4040namespace Diligent
4141{
4242
43+ namespace SPIRVToolsInternal
44+ {
45+
46+ // Forward declarations
47+
48+ void SpvOptimizerMessageConsumer (
49+ spv_message_level_t level,
50+ const char * /* source */ ,
51+ const spv_position_t & /* position */ ,
52+ const char * message);
53+
54+ spv_target_env SpvTargetEnvFromSPIRV (const std::vector<uint32_t >& SPIRV);
55+
56+ } // namespace SPIRVToolsInternal
57+
4358namespace
4459{
4560
@@ -161,6 +176,14 @@ class ConvertUBOToPushConstantPass : public spvtools::opt::Pass
161176 // Get the pointee type ID
162177 uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand (1 );
163178
179+ // Verify that the pointee type has the Block decoration, which is required for UBOs.
180+ // This ensures we don't accidentally convert a non-UBO uniform variable.
181+ if (!HasBlockDecoration (pointee_type_id))
182+ {
183+ // The struct type doesn't have Block decoration, not a valid UBO
184+ return Status::SuccessWithoutChange;
185+ }
186+
164187 // Create or find a pointer type with PushConstant storage class
165188 spvtools::opt::analysis::TypeManager* type_mgr = context ()->get_type_mgr ();
166189 uint32_t new_ptr_type_id =
@@ -172,39 +195,11 @@ class ConvertUBOToPushConstantPass : public spvtools::opt::Pass
172195 return Status::Failure;
173196 }
174197
175- // Ensure the new pointer type is defined before the variable
176- // FindPointerToType may have created it at the end, we need to move it
177- spvtools::opt::Instruction* new_ptr_type_inst = get_def_use_mgr ()->GetDef (new_ptr_type_id);
178- if (new_ptr_type_inst != nullptr )
179- {
180- // Find the pointee type instruction to insert after it
181- spvtools::opt::Instruction* pointee_type_inst = get_def_use_mgr ()->GetDef (pointee_type_id);
182-
183- // Check if new_ptr_type_inst is after target_var in the types_values list
184- bool needs_move = false ;
185- for (auto & inst : context ()->types_values ())
186- {
187- if (&inst == target_var)
188- {
189- // Found target_var first, so new_ptr_type_inst is after it
190- needs_move = true ;
191- break ;
192- }
193- if (&inst == new_ptr_type_inst)
194- {
195- // Found new_ptr_type_inst first, it's in the right position
196- needs_move = false ;
197- break ;
198- }
199- }
200-
201- if (needs_move && pointee_type_inst != nullptr )
202- {
203- // Move the new pointer type to right after the pointee type
204- // InsertAfter will automatically remove it from its current position
205- new_ptr_type_inst->InsertAfter (pointee_type_inst);
206- }
207- }
198+ // Note: We don't need to manually reorder the pointer type instruction.
199+ // SPIR-V does not require types to appear in any specific relative order,
200+ // as long as they are valid type declarations. FindPointerToType handles
201+ // type creation correctly, and the SPIRV-Tools framework manages instruction
202+ // ordering appropriately.
208203
209204 // Update the variable's type to the new pointer type
210205 target_var->SetResultType (new_ptr_type_id);
@@ -289,6 +284,8 @@ class ConvertUBOToPushConstantPass : public spvtools::opt::Pass
289284 }
290285
291286 // Handle instructions that produce pointer results
287+ // This switch covers the common pointer-producing opcodes.
288+ // Reference: SPIRV-Tools fix_storage_class.cpp
292289 switch (inst->opcode ())
293290 {
294291 case spv::Op::OpAccessChain:
@@ -311,14 +308,28 @@ class ConvertUBOToPushConstantPass : public spvtools::opt::Pass
311308 }
312309 return true ;
313310
311+ case spv::Op::OpFunctionCall:
312+ // We cannot be sure of the actual connection between the storage class
313+ // of the parameter and the storage class of the result, so we should not
314+ // do anything. If the result type needs to be fixed, the function call
315+ // should be inlined first.
316+ return false ;
317+
314318 case spv::Op::OpLoad:
315319 case spv::Op::OpStore:
316320 case spv::Op::OpCopyMemory:
317321 case spv::Op::OpCopyMemorySized:
318- // These don't produce pointer results that need updating
322+ case spv::Op::OpImageTexelPointer:
323+ case spv::Op::OpBitcast:
324+ case spv::Op::OpVariable:
325+ // These don't produce pointer results that need updating,
326+ // or the result type is independent of the operand's storage class.
319327 return false ;
320328
321329 default :
330+ // Unexpected pointer-producing instruction. This may indicate
331+ // a new SPIR-V extension or pattern not yet handled.
332+ UNEXPECTED (" Unexpected instruction with pointer result type: opcode " , static_cast <uint32_t >(inst->opcode ()));
322333 return false ;
323334 }
324335 }
@@ -373,6 +384,18 @@ class ConvertUBOToPushConstantPass : public spvtools::opt::Pass
373384 return pointer_storage_class == storage_class;
374385 }
375386
387+ // Checks if a type has the Block decoration, which identifies it as a UBO struct type.
388+ bool HasBlockDecoration (uint32_t type_id)
389+ {
390+ bool has_block = false ;
391+ get_decoration_mgr ()->ForEachDecoration (
392+ type_id, static_cast <uint32_t >(spv::Decoration::Block),
393+ [&has_block](const spvtools::opt::Instruction&) {
394+ has_block = true ;
395+ });
396+ return has_block;
397+ }
398+
376399 std::string m_BlockName;
377400};
378401
@@ -382,6 +405,8 @@ std::vector<uint32_t> ConvertUBOToPushConstants(
382405 const std::vector<uint32_t >& SPIRV,
383406 const std::string& BlockName)
384407{
408+ using namespace SPIRVToolsInternal ;
409+
385410 spv_target_env TargetEnv = SpvTargetEnvFromSPIRV (SPIRV);
386411
387412 spvtools::Optimizer optimizer (TargetEnv);
0 commit comments