Don't overlap storage with multiple inline UBO updates in one template

* Previously we were writing the inline UBO data to the same byte storage
  meaning the last update's data would write over all updates.
This commit is contained in:
baldurk
2024-12-09 15:03:35 +00:00
parent 0e406b0e4d
commit aa30ac2c10
5 changed files with 219 additions and 9 deletions
+2
View File
@@ -2949,6 +2949,8 @@ void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication
void *dst = application.inlineData.data() + inlineOffset;
memcpy(dst, src, inlineWrite.dataSize);
inlineWrite.pData = dst;
inlineOffset += inlineWrite.dataSize;
inlineOffset = AlignUp4(inlineOffset);
write.pNext = &inlineWrite;
write.descriptorCount = entry.descriptorCount;
+7 -9
View File
@@ -742,16 +742,14 @@ float4 main() : SV_Target0
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
{
VkWriteDescriptorSetInlineUniformBlockEXT inlineUpdate = {};
inlineUpdate.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
inlineUpdate.pData = &inlinedata;
inlineUpdate.dataSize = sizeof(inlinedata);
vkh::updateDescriptorSets(
device, {
vkh::WriteDescriptorSet(
descset, 1, inlineUpdate,
vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))),
});
device,
{
vkh::WriteDescriptorSet(
descset, 1,
vkh::WriteDescriptorSetInlineUniformBlockEXT(&inlinedata, sizeof(inlinedata)),
vkh::DescriptorBufferInfo(cb.buffer, bindOffset * sizeof(Vec4f))),
});
}
else
{
+13
View File
@@ -922,6 +922,19 @@ struct DescriptorImageInfo : public VkDescriptorImageInfo
}
};
struct WriteDescriptorSetInlineUniformBlockEXT : public VkWriteDescriptorSetInlineUniformBlockEXT
{
WriteDescriptorSetInlineUniformBlockEXT(void *data, uint32_t size)
{
sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
pNext = NULL;
this->pData = data;
this->dataSize = size;
}
operator const VkWriteDescriptorSetInlineUniformBlockEXT *() const { return this; }
};
struct WriteDescriptorSet : public VkWriteDescriptorSet
{
WriteDescriptorSet(VkDescriptorSet dstSet, uint32_t dstBinding, uint32_t dstArrayElement,
+147
View File
@@ -104,6 +104,28 @@ void main()
Color = ubos[7].data;
}
)EOSHADER";
const std::string inlineubopixel = R"EOSHADER(
#version 450 core
layout(location = 0, index = 0) out vec4 Color;
layout(binding=0) uniform ubo_block1
{
vec4 col;
} ubo1;
layout(binding=1) uniform ubo_block2
{
vec4 col;
} ubo2;
void main()
{
Color = ubo1.col + ubo2.col;
}
)EOSHADER";
const std::string refpixel = R"EOSHADER(
@@ -263,6 +285,7 @@ void main()
void Prepare(int argc, char **argv)
{
optDevExts.push_back(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
optDevExts.push_back(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME);
optDevExts.push_back(VK_EXT_TOOLING_INFO_EXTENSION_NAME);
optDevExts.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
optDevExts.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
@@ -363,6 +386,17 @@ void main()
dyn.pNext = (void *)devInfoNext;
devInfoNext = &dyn;
}
static VkPhysicalDeviceInlineUniformBlockFeaturesEXT inlineFeats = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
};
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
{
inlineFeats.inlineUniformBlock = VK_TRUE;
inlineFeats.pNext = (void *)devInfoNext;
devInfoNext = &inlineFeats;
}
}
int main()
@@ -566,6 +600,27 @@ void main()
VkPipelineLayout dynamicarraylayout =
createPipelineLayout(vkh::PipelineLayoutCreateInfo({dynamicarraysetlayout}));
VkDescriptorSetLayout inlineubosetlayout = VK_NULL_HANDLE;
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
{
inlineubosetlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({
{0, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 16, VK_SHADER_STAGE_FRAGMENT_BIT},
{1, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 16, VK_SHADER_STAGE_FRAGMENT_BIT},
}));
}
else
{
// dummy, won't be tested
inlineubosetlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
}));
}
VkPipelineLayout inlineubolayout =
createPipelineLayout(vkh::PipelineLayoutCreateInfo({inlineubosetlayout}));
VkDescriptorSet descset2 = allocateDescriptorSet(setlayout2);
VkDescriptorSetLayout asm_setlayout =
@@ -682,6 +737,15 @@ void main()
VkPipeline dynarraypipe = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.layout = inlineubolayout;
pipeCreateInfo.stages = {
CompileShaderModule(VKDefaultVertex, ShaderLang::glsl, ShaderStage::vert, "main"),
CompileShaderModule(inlineubopixel, ShaderLang::glsl, ShaderStage::frag, "main"),
};
VkPipeline inlineubopipe = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.stages = {
CompileShaderModule(VKDefaultVertex, ShaderLang::glsl, ShaderStage::vert, "main"),
CompileShaderModule(pixel2, ShaderLang::glsl, ShaderStage::frag, "main"),
@@ -1201,6 +1265,53 @@ void main()
vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &refpushtempl);
}
Vec4f inlinetemplData[2] = {
Vec4f(1.0f, 0.0f, 0.0f, 0.0f),
Vec4f(0.0f, 0.0f, 1.0f, 1.0f),
};
VkDescriptorUpdateTemplateKHR inlinetempl = VK_NULL_HANDLE;
VkDescriptorSet inlineuboset = allocateDescriptorSet(inlineubosetlayout);
VkDescriptorSet inlineuboset_templ = allocateDescriptorSet(inlineubosetlayout);
VkDescriptorSet inlineuboset_templ_dyn = allocateDescriptorSet(inlineubosetlayout);
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
{
vkh::updateDescriptorSets(
device, {
vkh::WriteDescriptorSet(inlineuboset, 0,
vkh::WriteDescriptorSetInlineUniformBlockEXT(
&inlinetemplData[0], sizeof(Vec4f)),
vkh::DescriptorBufferInfo(validBuffer)),
vkh::WriteDescriptorSet(inlineuboset, 1,
vkh::WriteDescriptorSetInlineUniformBlockEXT(
&inlinetemplData[1], sizeof(Vec4f)),
vkh::DescriptorBufferInfo(validBuffer)),
});
if(KHR_descriptor_update_template)
{
std::vector<VkDescriptorUpdateTemplateEntryKHR> entries = {
{0, 0, sizeof(Vec4f), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, 0, sizeof(Vec4f) * 2},
{1, 0, sizeof(Vec4f), VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, sizeof(Vec4f),
sizeof(Vec4f) * 2},
};
VkDescriptorUpdateTemplateCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR;
createInfo.descriptorUpdateEntryCount = (uint32_t)entries.size();
createInfo.pDescriptorUpdateEntries = entries.data();
createInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR;
createInfo.descriptorSetLayout = setlayout;
createInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &inlinetempl);
vkUpdateDescriptorSetWithTemplateKHR(device, inlineuboset_templ, inlinetempl,
&inlinetemplData);
}
}
// check that stale views in descriptors don't cause problems if the handle is re-used
VkImageView view1, view2;
@@ -1619,6 +1730,10 @@ void main()
if(KHR_descriptor_update_template)
vkUpdateDescriptorSetWithTemplateKHR(device, reftempldescset, reftempl, &reftempldata);
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME) && KHR_descriptor_update_template)
vkUpdateDescriptorSetWithTemplateKHR(device, inlineuboset_templ_dyn, inlinetempl,
&inlinetemplData);
VkCommandBuffer cmd = GetCommandBuffer();
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
@@ -1800,6 +1915,33 @@ void main()
setMarker(cmd, "Dynamic Array Draw");
vkCmdDraw(cmd, 3, 1, 0, 0);
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
{
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0,
{inlineuboset}, {});
setMarker(cmd, "Inline UBO Draw");
vkCmdDraw(cmd, 3, 1, 0, 0);
if(KHR_descriptor_update_template)
{
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0,
{inlineuboset_templ}, {});
setMarker(cmd, "Inline UBO + Templ Draw");
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubopipe);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, inlineubolayout, 0,
{inlineuboset_templ_dyn}, {});
setMarker(cmd, "Inline UBO + Templ Dyn Draw");
vkCmdDraw(cmd, 3, 1, 0, 0);
}
}
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout2, 0, {descset2}, {});
@@ -1881,8 +2023,13 @@ void main()
}
if(KHR_descriptor_update_template)
{
vkDestroyDescriptorUpdateTemplateKHR(device, reftempl, NULL);
if(hasExt(VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME))
vkDestroyDescriptorUpdateTemplateKHR(device, inlinetempl, NULL);
}
return 0;
}
};
@@ -217,6 +217,56 @@ class VK_Parameter_Zoo(rdtest.TestCase):
rdtest.log.success("ASM Draw is as expected")
inline_ubo_actions = [
self.find_action("Inline UBO Draw"),
self.find_action("Inline UBO + Templ Draw"),
self.find_action("Inline UBO + Templ Dyn Draw"),
]
action = self.find_action("Inline UBO Draw")
for action in inline_ubo_actions:
if action is None:
continue
rdtest.log.print(f"Checking {action.customName}")
self.controller.SetFrameEvent(action.next.eventId, False)
self.check_triangle(fore=[1.0, 0.0, 1.0, 1.0])
stage = rd.ShaderStage.Pixel
pipe = self.controller.GetPipelineState()
ubo1 = pipe.GetConstantBlock(stage, 0, 0).descriptor
ubo2 = pipe.GetConstantBlock(stage, 1, 0).descriptor
ubo1_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(),
pipe.GetShader(
stage), stage,
pipe.GetShaderEntryPoint(
stage), 0,
ubo1.resource, ubo1.byteOffset, ubo1.byteSize)
ubo2_vars = self.controller.GetCBufferVariableContents(pipe.GetGraphicsPipelineObject(),
pipe.GetShader(
stage), stage,
pipe.GetShaderEntryPoint(
stage), 1,
ubo2.resource, ubo2.byteOffset, ubo2.byteSize)
if len(ubo1_vars) != 1 or ubo1_vars[0].name != "col":
raise rdtest.TestFailureException("Didn't find ubo1 col variable")
if len(ubo2_vars) != 1 or ubo2_vars[0].name != "col":
raise rdtest.TestFailureException("Didn't find ubo2 col variable")
if ubo1_vars[0].value.f32v[0:4] != (1.0, 0.0, 0.0, 0.0):
raise rdtest.TestFailureException(f"ubo1 col value incorrect: {ubo1_vars[0].value.f32v[0:4]}")
if ubo2_vars[0].value.f32v[0:4] != (0.0, 0.0, 1.0, 1.0):
raise rdtest.TestFailureException(f"ubo2 col value incorrect: {ubo2_vars[0].value.f32v[0:4]}")
rdtest.log.success(f"{action.customName} is as expected")
action = self.find_action("Immutable Draw")
self.check(action is not None)