Skip to content

Commit e627275

Browse files
layers: GPL with VkPipelineRenderingCreateInfo madness (#11593)
1 parent 7209187 commit e627275

File tree

9 files changed

+335
-156
lines changed

9 files changed

+335
-156
lines changed

layers/core_checks/cc_pipeline_graphics.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3523,6 +3523,7 @@ bool CoreChecks::ValidateDrawPipelineRenderpass(const LastBound &last_bound_stat
35233523
bool skip = false;
35243524
const vvl::CommandBuffer &cb_state = last_bound_state.cb_state;
35253525

3526+
// Can use RenderPassState() here even GPL because we only need to check for compatible renderpasses
35263527
const auto &pipeline_rp_state = pipeline.RenderPassState();
35273528
// TODO: AMD extension codes are included here, but actual function entrypoints are not yet intercepted
35283529
if (rp_state.VkHandle() != pipeline_rp_state->VkHandle()) {
@@ -3546,6 +3547,7 @@ bool CoreChecks::ValidateDrawPipelineDynamicRenderpass(const LastBound &last_bou
35463547
bool skip = false;
35473548
const vvl::CommandBuffer &cb_state = last_bound_state.cb_state;
35483549

3550+
// Can use RenderPassState() here even GPL because we only need to check for it being null
35493551
const auto pipeline_rp_state = pipeline.RenderPassState();
35503552
ASSERT_AND_RETURN_SKIP(pipeline_rp_state);
35513553
if (pipeline_rp_state->VkHandle() != VK_NULL_HANDLE) {
@@ -3557,7 +3559,7 @@ bool CoreChecks::ValidateDrawPipelineDynamicRenderpass(const LastBound &last_bou
35573559
return skip;
35583560
}
35593561

3560-
const VkPipelineRenderingCreateInfo &pipeline_rendering_ci = *(pipeline_rp_state->dynamic_pipeline_rendering_create_info.ptr());
3562+
const VkPipelineRenderingCreateInfo& pipeline_rendering_ci = pipeline.GetRenderPassPipelineRenderingCreateInfo();
35613563
const auto rendering_view_mask = rp_state.GetDynamicRenderingViewMask();
35623564
// There is currently a 06031 VU that catches the viewMask at vkCmdExecuteCommands time, so seems like this is not suppose to be
35633565
// validated with inherited render passes

layers/state_tracker/cmd_buffer_state.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ static void InitDefaultRenderingAttachments(CommandBuffer::RenderingAttachment &
867867

868868
void CommandBuffer::RecordBeginRendering(const VkRenderingInfo &rendering_info, const Location &loc) {
869869
RecordCommand(loc);
870-
active_render_pass = std::make_shared<vvl::RenderPass>(&rendering_info, true);
870+
active_render_pass = std::make_shared<vvl::RenderPass>(rendering_info);
871871
render_area = rendering_info.renderArea;
872872
render_pass_queries.clear();
873873

layers/state_tracker/pipeline_state.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,11 @@ std::vector<std::shared_ptr<const vvl::PipelineLayout>> Pipeline::PipelineLayout
839839
return {merged_graphics_layout};
840840
}
841841

842+
// See DeviceState::PreCallValidateCreateGraphicsPipelines() why we need this awful function
843+
const VkPipelineRenderingCreateInfo& Pipeline::GetRenderPassPipelineRenderingCreateInfo() const {
844+
return *(rp_state->dynamic_pipeline_rendering_create_info.ptr());
845+
}
846+
842847
// Currently will return vvl::ShaderModule with no SPIR-V
843848
std::shared_ptr<const vvl::ShaderModule> Pipeline::GetGraphicsLibraryStateShader(VkShaderStageFlagBits state) const {
844849
switch (state) {

layers/state_tracker/pipeline_state.h

Lines changed: 26 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,19 @@ class Pipeline : public StateObject, public SubStateManager<PipelineSubState> {
243243

244244
// Used to know if the pipeline library is being created (as opposed to being linked)
245245
// Important as some pipeline checks need pipeline state that won't be there if the library is from linking
246-
// Many VUs say "the pipeline require" which means "not being linked in as a library"
246+
// Many VUs say "the pipeline requires" which means "not being linked in as a library"
247247
// If the VUs says "created with" then you should NOT use this function
248248
// TODO - This could probably just be a check to VkGraphicsPipelineLibraryCreateInfoEXT::flags
249249
bool OwnsLibState(const std::shared_ptr<PipelineLibraryState> lib_state) const {
250250
return lib_state && (&lib_state->parent == this);
251251
}
252252

253-
// This grabs the render pass at pipeline creation time, if you are inside a command buffer, use the vvl::RenderPass inside the
254-
// command buffer! (The render pass can be different as they just have to be compatible, see
255-
// vkspec.html#renderpass-compatibility)
253+
// If you are inside a command buffer, use the vvl::RenderPass inside the command buffer!!
254+
// - This grabs the render pass at pipeline creation time
255+
// - The render pass can be different as they just have to be compatible, see vkspec.html#renderpass-compatibility
256+
// - The issue is for something like VkPipelineRenderingCreateInfo we want executable version... so why this is ONLY suppose to
257+
// be used when we don't have the command buffer scope
256258
const std::shared_ptr<const vvl::RenderPass> RenderPassState() const {
257-
// TODO A render pass object is required for all of these library states. Which one should be used for an "executable
258-
// pipeline"?
259259
if (fragment_output_state && fragment_output_state->rp_state) {
260260
return fragment_output_state->rp_state;
261261
} else if (fragment_shader_state && fragment_shader_state->rp_state) {
@@ -266,6 +266,8 @@ class Pipeline : public StateObject, public SubStateManager<PipelineSubState> {
266266
return rp_state;
267267
}
268268

269+
const VkPipelineRenderingCreateInfo& GetRenderPassPipelineRenderingCreateInfo() const;
270+
269271
// A pipeline does not "require" state that is specified in a library.
270272
bool IsRenderPassStateRequired() const {
271273
return OwnsLibState(pre_raster_state) || OwnsLibState(fragment_shader_state) || OwnsLibState(fragment_output_state);
@@ -515,69 +517,31 @@ class Pipeline : public StateObject, public SubStateManager<PipelineSubState> {
515517
return EnablesRasterizationStates(create_info);
516518
}
517519

518-
template <typename CreateInfo>
519-
static bool ContainsLibraryState(const vvl::DeviceState &device_state, const CreateInfo &create_info,
520-
VkGraphicsPipelineLibraryFlagsEXT lib_flags) {
521-
constexpr VkGraphicsPipelineLibraryFlagsEXT null_lib = static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0);
522-
VkGraphicsPipelineLibraryFlagsEXT current_state = null_lib;
523-
524-
// Check linked libraries
525-
auto link_info = vku::FindStructInPNextChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
526-
if (link_info) {
527-
const auto libs = vvl::make_span(link_info->pLibraries, link_info->libraryCount);
528-
for (const auto handle : libs) {
529-
auto lib = device_state.Get<vvl::Pipeline>(handle);
530-
current_state |= lib->graphics_lib_type;
531-
}
532-
}
533-
534-
// Check if this is a graphics library
535-
auto lib_info = vku::FindStructInPNextChain<VkGraphicsPipelineLibraryCreateInfoEXT>(create_info.pNext);
536-
if (lib_info) {
537-
current_state |= lib_info->flags;
538-
}
539-
540-
if (!link_info && !lib_info) {
541-
// This is not a graphics pipeline library, and therefore contains all necessary state
542-
return true;
543-
}
544-
545-
return (current_state & lib_flags) != null_lib;
546-
}
547-
548-
// Version used at dispatch time for stateless VOs
549-
template <typename CreateInfo>
550-
static bool ContainsLibraryState(const CreateInfo &create_info, VkGraphicsPipelineLibraryFlagsEXT lib_flags) {
551-
constexpr VkGraphicsPipelineLibraryFlagsEXT null_lib = static_cast<VkGraphicsPipelineLibraryFlagsEXT>(0);
552-
VkGraphicsPipelineLibraryFlagsEXT current_state = null_lib;
553-
554-
auto link_info = vku::FindStructInPNextChain<VkPipelineLibraryCreateInfoKHR>(create_info.pNext);
555-
// Cannot check linked library state in stateless VO
556-
557-
// Check if this is a graphics library
558-
auto lib_info = vku::FindStructInPNextChain<VkGraphicsPipelineLibraryCreateInfoEXT>(create_info.pNext);
559-
if (lib_info) {
560-
current_state |= lib_info->flags;
561-
}
562-
563-
if (!link_info && !lib_info) {
564-
// This is not a graphics pipeline library, and therefore (should) contains all necessary state
565-
return true;
566-
}
567-
568-
return (current_state & lib_flags) != null_lib;
569-
}
570-
571520
// This is a helper that is meant to be used during safe_VkPipelineRenderingCreateInfo construction to determine whether or not
572521
// certain fields should be ignored based on graphics pipeline state
573522
static bool PnextRenderingInfoCustomCopy(const DeviceState &device_state, const VkGraphicsPipelineCreateInfo &graphics_info,
574523
VkBaseOutStructure *safe_struct, const VkBaseOutStructure *in_struct) {
575524
// "safe_struct" is assumed to be non-null as it should be the "this" member of calling class instance
576525
assert(safe_struct);
577526
if (safe_struct->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO) {
578-
const bool has_fo_state = Pipeline::ContainsLibraryState(
579-
device_state, graphics_info, VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT);
580-
if (!has_fo_state) {
527+
// If using normal, non-GPL pipline, this is simply true
528+
bool has_fragment_output_state = true;
529+
530+
{
531+
// Same as OwnsLibState() but when there is no vvl::Pipeline state
532+
auto lib_info = vku::FindStructInPNextChain<VkGraphicsPipelineLibraryCreateInfoEXT>(graphics_info.pNext);
533+
if (lib_info) {
534+
has_fragment_output_state =
535+
(lib_info->flags & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) != 0;
536+
} else if (auto link_info = vku::FindStructInPNextChain<VkPipelineLibraryCreateInfoKHR>(graphics_info.pNext)) {
537+
if (link_info->libraryCount != 0) {
538+
// We are linking in, so we now know this pipeline doesn't "own" FragmentOuptut
539+
has_fragment_output_state = false;
540+
}
541+
}
542+
}
543+
544+
if (!has_fragment_output_state) {
581545
// Clear out all pointers except for viewMask. Since viewMask is a scalar, it has already been copied at this point
582546
// in vku::safe_VkPipelineRenderingCreateInfo construction.
583547
auto pri = reinterpret_cast<vku::safe_VkPipelineRenderingCreateInfo *>(safe_struct);

layers/state_tracker/render_pass_state.cpp

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/* Copyright (c) 2015-2025 The Khronos Group Inc.
2-
* Copyright (c) 2015-2025 Valve Corporation
3-
* Copyright (c) 2015-2025 LunarG, Inc.
4-
* Copyright (C) 2015-2025 Google Inc.
1+
/* Copyright (c) 2015-2026 The Khronos Group Inc.
2+
* Copyright (c) 2015-2026 Valve Corporation
3+
* Copyright (c) 2015-2026 LunarG, Inc.
4+
* Copyright (C) 2015-2026 Google Inc.
55
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
66
*
77
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -255,10 +255,6 @@ static bool IsRenderPassMultiViewEnabled(const VkRenderPassCreateInfo2 &renderpa
255255
return is_multiview_enabled;
256256
}
257257

258-
static bool IsDynamicRenderingMultiviewEnabled(const VkRenderingInfo *rendering_info) {
259-
return rendering_info && rendering_info->viewMask != 0u;
260-
}
261-
262258
static void InitRenderPassState(vvl::RenderPass &render_pass) {
263259
auto create_info = render_pass.create_info.ptr();
264260

@@ -280,12 +276,11 @@ static void InitRenderPassState(vvl::RenderPass &render_pass) {
280276
namespace vvl {
281277

282278
// vkCreateRenderPass2
283-
RenderPass::RenderPass(VkRenderPass handle, VkRenderPassCreateInfo2 const *pCreateInfo)
279+
RenderPass::RenderPass(VkRenderPass handle, VkRenderPassCreateInfo2 const* pCreateInfo)
284280
: StateObject(handle, kVulkanObjectTypeRenderPass),
285281
create_info(pCreateInfo),
286282
use_dynamic_rendering(false),
287283
use_dynamic_rendering_inherited(false),
288-
rasterization_enabled(true),
289284
dynamic_rendering_color_attachment_count(0),
290285
has_multiview_enabled(IsRenderPassMultiViewEnabled(*create_info.ptr())) {
291286
InitRenderPassState(*this);
@@ -297,31 +292,25 @@ static vku::safe_VkRenderPassCreateInfo2 ConvertCreateInfo(const VkRenderPassCre
297292
}
298293

299294
// vkCreateRenderPass
300-
RenderPass::RenderPass(VkRenderPass handle, VkRenderPassCreateInfo const *pCreateInfo)
295+
RenderPass::RenderPass(VkRenderPass handle, VkRenderPassCreateInfo const* pCreateInfo)
301296
: StateObject(handle, kVulkanObjectTypeRenderPass),
302297
create_info(ConvertCreateInfo(*pCreateInfo)),
303298
use_dynamic_rendering(false),
304299
use_dynamic_rendering_inherited(false),
305-
rasterization_enabled(true),
306300
dynamic_rendering_color_attachment_count(0),
307301
has_multiview_enabled(IsRenderPassMultiViewEnabled(*create_info.ptr())) {
308302
InitRenderPassState(*this);
309303
}
310304

311-
const VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfo_default = {
312-
VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, nullptr, 0, 0, nullptr, VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED};
313-
314305
// vkCreateGraphicsPipelines (dynamic rendering state tied to pipeline state)
315-
RenderPass::RenderPass(VkPipelineRenderingCreateInfo const *pPipelineRenderingCreateInfo, bool rasterization_enabled)
306+
// (created in DeviceState::PreCallValidateCreateGraphicsPipelines)
307+
RenderPass::RenderPass(const VkPipelineRenderingCreateInfo& rendering_ci)
316308
: StateObject(static_cast<VkRenderPass>(VK_NULL_HANDLE), kVulkanObjectTypeRenderPass),
317309
use_dynamic_rendering(true),
318310
use_dynamic_rendering_inherited(false),
319-
rasterization_enabled(rasterization_enabled),
320-
dynamic_pipeline_rendering_create_info((pPipelineRenderingCreateInfo && rasterization_enabled)
321-
? pPipelineRenderingCreateInfo
322-
: &VkPipelineRenderingCreateInfo_default),
323-
dynamic_rendering_color_attachment_count(dynamic_pipeline_rendering_create_info.colorAttachmentCount),
324-
has_multiview_enabled(dynamic_pipeline_rendering_create_info.viewMask != 0) {}
311+
dynamic_pipeline_rendering_create_info(&rendering_ci),
312+
dynamic_rendering_color_attachment_count(rendering_ci.colorAttachmentCount),
313+
has_multiview_enabled(rendering_ci.viewMask != 0) {}
325314

326315
bool RenderPass::UsesColorAttachment(uint32_t subpass_num) const {
327316
bool result = false;
@@ -396,22 +385,19 @@ const VkMultisampledRenderToSingleSampledInfoEXT *RenderPass::GetMSRTSSInfo(uint
396385
}
397386

398387
// vkCmdBeginRendering
399-
RenderPass::RenderPass(VkRenderingInfo const *pRenderingInfo, bool rasterization_enabled)
388+
RenderPass::RenderPass(const VkRenderingInfo& rendering_info)
400389
: StateObject(static_cast<VkRenderPass>(VK_NULL_HANDLE), kVulkanObjectTypeRenderPass),
401390
use_dynamic_rendering(true),
402391
use_dynamic_rendering_inherited(false),
403-
rasterization_enabled(rasterization_enabled),
404-
dynamic_rendering_begin_rendering_info((pRenderingInfo && rasterization_enabled) ? pRenderingInfo : nullptr),
392+
dynamic_rendering_begin_rendering_info(&rendering_info),
405393
dynamic_rendering_color_attachment_count(dynamic_rendering_begin_rendering_info.colorAttachmentCount),
406-
has_multiview_enabled(
407-
IsDynamicRenderingMultiviewEnabled((pRenderingInfo && rasterization_enabled) ? pRenderingInfo : nullptr)) {}
394+
has_multiview_enabled(rendering_info.viewMask != 0u) {}
408395

409396
// vkBeginCommandBuffer (dynamic rendering in secondary command buffer)
410-
RenderPass::RenderPass(VkCommandBufferInheritanceRenderingInfo const *pInheritanceRenderingInfo)
397+
RenderPass::RenderPass(VkCommandBufferInheritanceRenderingInfo const* pInheritanceRenderingInfo)
411398
: StateObject(static_cast<VkRenderPass>(VK_NULL_HANDLE), kVulkanObjectTypeRenderPass),
412399
use_dynamic_rendering(false),
413400
use_dynamic_rendering_inherited(true),
414-
rasterization_enabled(true),
415401
inheritance_rendering_info(pInheritanceRenderingInfo),
416402
dynamic_rendering_color_attachment_count(inheritance_rendering_info.colorAttachmentCount),
417403
has_multiview_enabled(false) {}

layers/state_tracker/render_pass_state.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
/* Copyright (c) 2015-2025 The Khronos Group Inc.
2-
* Copyright (c) 2015-2025 Valve Corporation
3-
* Copyright (c) 2015-2025 LunarG, Inc.
4-
* Copyright (C) 2015-2025 Google Inc.
1+
/* Copyright (c) 2015-2026 The Khronos Group Inc.
2+
* Copyright (c) 2015-2026 Valve Corporation
3+
* Copyright (c) 2015-2026 LunarG, Inc.
4+
* Copyright (C) 2015-2026 Google Inc.
55
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
66
*
77
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -79,9 +79,9 @@ class RenderPass : public StateObject {
7979

8080
const bool use_dynamic_rendering;
8181
const bool use_dynamic_rendering_inherited;
82-
const bool rasterization_enabled;
8382

8483
const vku::safe_VkRenderingInfo dynamic_rendering_begin_rendering_info;
84+
// Note, this is not the exact VkPipelineRenderingCreateInfo passed in, instead it will handle fields being ignored
8585
const vku::safe_VkPipelineRenderingCreateInfo dynamic_pipeline_rendering_create_info;
8686
// when a secondary command buffer is recorded with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
8787
const vku::safe_VkCommandBufferInheritanceRenderingInfo inheritance_rendering_info;
@@ -112,12 +112,12 @@ class RenderPass : public StateObject {
112112
RenderPass(VkRenderPass handle, VkRenderPassCreateInfo2 const *pCreateInfo);
113113

114114
// vkCmdBeginRendering
115-
RenderPass(VkRenderingInfo const *pRenderingInfo, bool rasterization_enabled);
115+
explicit RenderPass(const VkRenderingInfo& rendering_info);
116116
// vkBeginCommandBuffer (dynamic rendering in secondary commadn buffer)
117117
explicit RenderPass(VkCommandBufferInheritanceRenderingInfo const *pInheritanceRenderingInfo);
118118

119119
// vkCreateGraphicsPipelines (dynamic rendering state tied to pipeline state)
120-
RenderPass(VkPipelineRenderingCreateInfo const *pPipelineRenderingCreateInfo, bool rasterization_enabled);
120+
explicit RenderPass(const VkPipelineRenderingCreateInfo& rendering_ci);
121121

122122
VkRenderPass VkHandle() const { return handle_.Cast<VkRenderPass>(); }
123123

0 commit comments

Comments
 (0)