fix(render3d): Vulkan exposure, foliage depth and meadow alpha
Three things the first Vulkan frames on the RTX 3070 Ti showed against OpenGL on the same PC: - Exposure: the adaptation pass reads the HDR scene's smallest mip, and a render target made without pixels had one level, so exposure came from a single texel. A target asked for mipmaps now grows a full chain (level 0 kept), and passes draw through level-0 views keyed by the image's generation. - Foliage: the depth prepass and the lit pass (depth EQUAL) are different variants. Vulkan vertex stages now declare an invariant gl_Position so both land on the same depth. - Alpha to coverage is enabled only on a multisampled pass. OpenGL ignores it without MSAA; Vulkan with one sample dropped every fragment under half alpha. vk_resources also checks a big-endian 16-bit RGB upload (a normal map). VKRES OK; ludic-dev test 140 passed; the PC's Vulkan frame is validation-clean; OpenGL frames byte-identical at the five viewpoints with 59 self-tests passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
072f9a848e
commit
a674c9b372
33 changed files with 70 additions and 7 deletions
|
|
@ -290,7 +290,9 @@ function gvk_pipeline(p: int, m: Mesh, st: GvkState, n_color: int, color_fmt: in
|
|||
Vk.zero(ms, VkPipelineMultisampleStateCreateInfo_sizeof)
|
||||
Vk.put_i32(ms, VkPipelineMultisampleStateCreateInfo_sType, VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO)
|
||||
Vk.put_i32(ms, VkPipelineMultisampleStateCreateInfo_rasterizationSamples, samples)
|
||||
Vk.put_i32(ms, VkPipelineMultisampleStateCreateInfo_alphaToCoverageEnable, st.a2c)
|
||||
# OpenGL ignores alpha to coverage without a multisampled target; Vulkan with one sample would
|
||||
# instead drop every fragment under half alpha, which erased the meadow's flowers
|
||||
if samples > 1 { Vk.put_i32(ms, VkPipelineMultisampleStateCreateInfo_alphaToCoverageEnable, st.a2c) }
|
||||
let ds = bytes(VkPipelineDepthStencilStateCreateInfo_sizeof)
|
||||
Vk.zero(ds, VkPipelineDepthStencilStateCreateInfo_sizeof)
|
||||
Vk.put_i32(ds, VkPipelineDepthStencilStateCreateInfo_sType, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO)
|
||||
|
|
@ -607,10 +609,12 @@ function gvk_frame_cb() -> pointer {
|
|||
return gvk_cb
|
||||
}
|
||||
|
||||
# a view of one layer of an array image, for a cascade drawn into on its own
|
||||
# The view a pass draws into: level 0 only (an attachment view has exactly one level, and a target
|
||||
# the exposure measure mipmaps has several), and one layer of an array image for a cascade drawn
|
||||
# on its own. Keyed by the image's generation, so a replaced image never reuses a stale view.
|
||||
function gvk_view_of(tex: int, layer1: int) -> long {
|
||||
if layer1 == 0 { return gvk_tex_view[tex] }
|
||||
let key = `{tex}:{layer1}`
|
||||
if layer1 == 0 and gvk_tex_levels[tex] <= 1 and gvk_tex_layers[tex] <= 1 { return gvk_tex_view[tex] }
|
||||
let key = `{tex}:{gvk_tex_gen[tex]}:{layer1}`
|
||||
if gvk_layer_views == null { gvk_layer_views = new []string; gvk_layer_view = new []long }
|
||||
for i in 0 .. len(gvk_layer_views) { if gvk_layer_views[i] == key { return gvk_layer_view[i] } }
|
||||
let depth = gvk_tex_vkfmt[tex] == VK_FORMAT_D32_SFLOAT
|
||||
|
|
@ -623,7 +627,7 @@ function gvk_view_of(tex: int, layer1: int) -> long {
|
|||
let sr = VkImageViewCreateInfo_subresourceRange
|
||||
if depth { Vk.put_i32(vci, sr + VkImageSubresourceRange_aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) } else { Vk.put_i32(vci, sr + VkImageSubresourceRange_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT) }
|
||||
Vk.put_i32(vci, sr + VkImageSubresourceRange_levelCount, 1)
|
||||
Vk.put_i32(vci, sr + VkImageSubresourceRange_baseArrayLayer, layer1 - 1)
|
||||
if layer1 > 0 { Vk.put_i32(vci, sr + VkImageSubresourceRange_baseArrayLayer, layer1 - 1) }
|
||||
Vk.put_i32(vci, sr + VkImageSubresourceRange_layerCount, 1)
|
||||
let out = bytes(8)
|
||||
let zero: long = 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue