@@ -329,6 +329,10 @@ struct GLSLLegalizationContext
329
329
330
330
IRBuilder* builder;
331
331
IRBuilder* getBuilder () { return builder; }
332
+
333
+ // For ray tracing shaders, we need to consolidate all parameters into a single structure
334
+ Dictionary<IRFunc*, IRInst*> rayTracingConsolidatedVars;
335
+ Dictionary<IRFunc*, List<IRParam*>> rayTracingProcessedParams;
332
336
};
333
337
334
338
// This examines the passed type and determines the GLSL mesh shader indices
@@ -2302,7 +2306,7 @@ IRInst* materializeValue(IRBuilder* builder, ScalarizedVal const& val)
2302
2306
}
2303
2307
}
2304
2308
2305
- void legalizeRayTracingEntryPointParameterForGLSL (
2309
+ static void handleSingleParam (
2306
2310
GLSLLegalizationContext* context,
2307
2311
IRFunc* func,
2308
2312
IRParam* pp,
@@ -2311,49 +2315,156 @@ void legalizeRayTracingEntryPointParameterForGLSL(
2311
2315
auto builder = context->getBuilder ();
2312
2316
auto paramType = pp->getDataType ();
2313
2317
2314
- // The parameter might be either an `in` parameter,
2315
- // or an `out` or `in out` parameter, and in those
2316
- // latter cases its IR-level type will include a
2317
- // wrapping "pointer-like" type (e.g., `Out<Float>`
2318
- // instead of just `Float`).
2319
- //
2320
- // Because global shader parameters are read-only
2321
- // in the same way function types are, we can take
2322
- // care of that detail here just by allocating a
2323
- // global shader parameter with exactly the type
2324
- // of the original function parameter.
2325
- //
2326
2318
auto globalParam = addGlobalParam (builder->getModule (), paramType);
2327
2319
builder->addLayoutDecoration (globalParam, paramLayout);
2328
2320
moveValueBefore (globalParam, builder->getFunc ());
2329
2321
pp->replaceUsesWith (globalParam);
2330
-
2331
- // Because linkage between ray-tracing shaders is
2332
- // based on the type of incoming/outgoing payload
2333
- // and attribute parameters, it would be an error to
2334
- // eliminate the global parameter *even if* it is
2335
- // not actually used inside the entry point.
2336
- //
2337
- // We attach a decoration to the entry point that
2338
- // makes note of the dependency, so that steps
2339
- // like dead code elimination cannot get rid of
2340
- // the parameter.
2341
- //
2342
- // TODO: We could consider using a structure like
2343
- // this for *all* of the entry point parameters
2344
- // that get moved to the global scope, since SPIR-V
2345
- // ends up requiring such information on an `OpEntryPoint`.
2346
- //
2347
- // As a further alternative, we could decide to
2348
- // keep entry point varying input/outtput attached
2349
- // to the parameter list through all of the Slang IR
2350
- // steps, and only declare it as global variables at
2351
- // the last minute when emitting a GLSL `main` or
2352
- // SPIR-V for an entry point.
2353
- //
2354
2322
builder->addDependsOnDecoration (func, globalParam);
2355
2323
}
2356
2324
2325
+ static void consolidateParameters (
2326
+ GLSLLegalizationContext* context,
2327
+ IRFunc* func,
2328
+ List<IRParam*>& params)
2329
+ {
2330
+ auto builder = context->getBuilder ();
2331
+
2332
+ // Create a struct type to hold all parameters
2333
+ IRInst* consolidatedVar = nullptr ;
2334
+ auto structType = builder->createStructType ();
2335
+
2336
+ // Inside the structure, add fields for each parameter
2337
+ for (auto _param : params)
2338
+ {
2339
+ auto _paramType = _param->getDataType ();
2340
+ IRType* valueType = _paramType;
2341
+
2342
+ if (as<IROutType>(_paramType))
2343
+ valueType = as<IROutType>(_paramType)->getValueType ();
2344
+ else if (auto inOutType = as<IRInOutType>(_paramType))
2345
+ valueType = inOutType->getValueType ();
2346
+
2347
+ auto key = builder->createStructKey ();
2348
+ builder->addNameHintDecoration (key, UnownedStringSlice (" field" ));
2349
+ auto field = builder->createStructField (structType, key, valueType);
2350
+ field->removeFromParent ();
2351
+ field->insertAtEnd (structType);
2352
+ }
2353
+
2354
+ // Create a global variable to hold the consolidated struct
2355
+ consolidatedVar = builder->createGlobalVar (structType);
2356
+ auto ptrType = builder->getPtrType (kIROp_PtrType , structType, AddressSpace::IncomingRayPayload);
2357
+ consolidatedVar->setFullType (ptrType);
2358
+ consolidatedVar->moveToEnd ();
2359
+
2360
+ // Add the ray payload decoration and assign location 0.
2361
+ builder->addVulkanRayPayloadDecoration (consolidatedVar, 0 );
2362
+
2363
+ // Store the consolidated variable for this function
2364
+ context->rayTracingConsolidatedVars [func] = consolidatedVar;
2365
+
2366
+ // Replace each parameter with a field in the consolidated struct
2367
+ for (Index i = 0 ; i < params.getCount (); ++i)
2368
+ {
2369
+ auto _param = params[i];
2370
+
2371
+ // Find the i-th field
2372
+ IRStructField* targetField = nullptr ;
2373
+ Index fieldIndex = 0 ;
2374
+ for (auto field : structType->getFields ())
2375
+ {
2376
+ if (fieldIndex == i)
2377
+ {
2378
+ targetField = field;
2379
+ break ;
2380
+ }
2381
+ fieldIndex++;
2382
+ }
2383
+ SLANG_ASSERT (targetField);
2384
+
2385
+ // Create the field address with the correct type
2386
+ auto _paramType = _param->getDataType ();
2387
+ auto fieldType = targetField->getFieldType ();
2388
+
2389
+ // If the parameter is an out/inout type, we need to create a pointer type
2390
+ IRType* fieldPtrType = nullptr ;
2391
+ if (as<IROutType>(_paramType))
2392
+ {
2393
+ fieldPtrType = builder->getPtrType (kIROp_OutType , fieldType);
2394
+ }
2395
+ else if (as<IRInOutType>(_paramType))
2396
+ {
2397
+ fieldPtrType = builder->getPtrType (kIROp_InOutType , fieldType);
2398
+ }
2399
+
2400
+ auto fieldAddr =
2401
+ builder->emitFieldAddress (fieldPtrType, consolidatedVar, targetField->getKey ());
2402
+
2403
+ // Replace parameter uses with field address
2404
+ _param->replaceUsesWith (fieldAddr);
2405
+ }
2406
+ }
2407
+
2408
+ static void handleMultipleParams (GLSLLegalizationContext* context, IRFunc* func, IRParam* pp)
2409
+ {
2410
+ auto firstBlock = func->getFirstBlock ();
2411
+
2412
+ // Now we run the consolidation step, but if we've already
2413
+ // processed this parameter, skip it.
2414
+ List<IRParam*>* processedParams = nullptr ;
2415
+ if (auto foundList = context->rayTracingProcessedParams .tryGetValue (func))
2416
+ {
2417
+ processedParams = foundList;
2418
+ if (processedParams->contains (pp))
2419
+ return ;
2420
+ }
2421
+ else
2422
+ {
2423
+ context->rayTracingProcessedParams [func] = List<IRParam*>();
2424
+ processedParams = &context->rayTracingProcessedParams [func];
2425
+ }
2426
+
2427
+ // Collect all parameters that need to be consolidated
2428
+ List<IRParam*> params;
2429
+ List<IRVarLayout*> paramLayouts;
2430
+
2431
+ for (auto _param = firstBlock->getFirstParam (); _param; _param = _param->getNextParam ())
2432
+ {
2433
+ auto pLayoutDecoration = _param->findDecoration <IRLayoutDecoration>();
2434
+ SLANG_ASSERT (pLayoutDecoration);
2435
+ auto pLayout = as<IRVarLayout>(pLayoutDecoration->getLayout ());
2436
+ SLANG_ASSERT (pLayout);
2437
+
2438
+ // Only include parameters that haven't been processed yet
2439
+ auto _paramType = _param->getDataType ();
2440
+ bool needsConsolidation = (as<IROutType>(_paramType) || as<IRInOutType>(_paramType));
2441
+ if (!processedParams->contains (_param) && needsConsolidation)
2442
+ {
2443
+ params.add (_param);
2444
+ paramLayouts.add (pLayout);
2445
+ processedParams->add (_param);
2446
+ }
2447
+ }
2448
+
2449
+ consolidateParameters (context, func, params);
2450
+ }
2451
+
2452
+ void legalizeRayTracingEntryPointParameterForGLSL (
2453
+ GLSLLegalizationContext* context,
2454
+ IRFunc* func,
2455
+ IRParam* pp,
2456
+ IRVarLayout* paramLayout,
2457
+ bool hasSingleOutOrInOutParam)
2458
+ {
2459
+ if (hasSingleOutOrInOutParam)
2460
+ {
2461
+ handleSingleParam (context, func, pp, paramLayout);
2462
+ return ;
2463
+ }
2464
+
2465
+ handleMultipleParams (context, func, pp);
2466
+ }
2467
+
2357
2468
static void legalizeMeshPayloadInputParam (
2358
2469
GLSLLegalizationContext* context,
2359
2470
CodeGenContext* codeGenContext,
@@ -3041,7 +3152,6 @@ void legalizeEntryPointParameterForGLSL(
3041
3152
}
3042
3153
}
3043
3154
3044
-
3045
3155
// We need to create a global variable that will replace the parameter.
3046
3156
// It seems superficially obvious that the variable should have
3047
3157
// the same type as the parameter.
@@ -3198,7 +3308,28 @@ void legalizeEntryPointParameterForGLSL(
3198
3308
case Stage::Intersection:
3199
3309
case Stage::Miss:
3200
3310
case Stage::RayGeneration:
3201
- legalizeRayTracingEntryPointParameterForGLSL (context, func, pp, paramLayout);
3311
+ {
3312
+ // Count the number of inout or out parameters
3313
+ int inoutOrOutParamCount = 0 ;
3314
+ auto firstBlock = func->getFirstBlock ();
3315
+ for (auto _param = firstBlock->getFirstParam (); _param; _param = _param->getNextParam ())
3316
+ {
3317
+ auto _paramType = _param->getDataType ();
3318
+ if (as<IROutType>(_paramType) || as<IRInOutType>(_paramType))
3319
+ {
3320
+ inoutOrOutParamCount++;
3321
+ }
3322
+ }
3323
+
3324
+ // If we have just one inout or out param, we don't need consolidation.
3325
+ bool hasSingleOutOrInOutParam = inoutOrOutParamCount <= 1 ;
3326
+ legalizeRayTracingEntryPointParameterForGLSL (
3327
+ context,
3328
+ func,
3329
+ pp,
3330
+ paramLayout,
3331
+ hasSingleOutOrInOutParam);
3332
+ }
3202
3333
return ;
3203
3334
}
3204
3335
0 commit comments