@@ -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,174 @@ 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 = builder->emitFieldAddress (
2401
+ fieldPtrType,
2402
+ consolidatedVar,
2403
+ targetField->getKey ());
2404
+
2405
+ // Replace parameter uses with field address
2406
+ _param->replaceUsesWith (fieldAddr);
2407
+ }
2408
+ }
2409
+
2410
+ static void handleMultipleParams (
2411
+ GLSLLegalizationContext* context,
2412
+ IRFunc* func,
2413
+ IRParam* pp)
2414
+ {
2415
+ auto firstBlock = func->getFirstBlock ();
2416
+
2417
+ // Now we run the consolidation step, but if we've already
2418
+ // processed this parameter, skip it.
2419
+ List<IRParam*>* processedParams = nullptr ;
2420
+ if (auto foundList = context->rayTracingProcessedParams .tryGetValue (func))
2421
+ {
2422
+ processedParams = foundList;
2423
+ if (processedParams->contains (pp))
2424
+ return ;
2425
+ }
2426
+ else
2427
+ {
2428
+ context->rayTracingProcessedParams [func] = List<IRParam*>();
2429
+ processedParams = &context->rayTracingProcessedParams [func];
2430
+ }
2431
+
2432
+ // Collect all parameters that need to be consolidated
2433
+ List<IRParam*> params;
2434
+ List<IRVarLayout*> paramLayouts;
2435
+
2436
+ for (auto _param = firstBlock->getFirstParam (); _param; _param = _param->getNextParam ())
2437
+ {
2438
+ auto pLayoutDecoration = _param->findDecoration <IRLayoutDecoration>();
2439
+ SLANG_ASSERT (pLayoutDecoration);
2440
+ auto pLayout = as<IRVarLayout>(pLayoutDecoration->getLayout ());
2441
+ SLANG_ASSERT (pLayout);
2442
+
2443
+ // Only include parameters that haven't been processed yet
2444
+ auto _paramType = _param->getDataType ();
2445
+ bool needsConsolidation = (as<IROutType>(_paramType) || as<IRInOutType>(_paramType));
2446
+ if (!processedParams->contains (_param) && needsConsolidation)
2447
+ {
2448
+ params.add (_param);
2449
+ paramLayouts.add (pLayout);
2450
+ processedParams->add (_param);
2451
+ }
2452
+ }
2453
+
2454
+ consolidateParameters (context, func, params);
2455
+ }
2456
+
2457
+ void legalizeRayTracingEntryPointParameterForGLSL (
2458
+ GLSLLegalizationContext* context,
2459
+ IRFunc* func,
2460
+ IRParam* pp,
2461
+ IRVarLayout* paramLayout)
2462
+ {
2463
+ auto firstBlock = func->getFirstBlock ();
2464
+
2465
+ // Count the number of inout or out parameters
2466
+ int inoutOrOutParamCount = 0 ;
2467
+ for (auto _param = firstBlock->getFirstParam (); _param; _param = _param->getNextParam ())
2468
+ {
2469
+ auto _paramType = _param->getDataType ();
2470
+ if (as<IROutType>(_paramType) || as<IRInOutType>(_paramType))
2471
+ {
2472
+ inoutOrOutParamCount++;
2473
+ }
2474
+ }
2475
+
2476
+ // If we have just one inout or out param, we don't need consolidation.
2477
+ if (inoutOrOutParamCount <= 1 )
2478
+ {
2479
+ handleSingleParam (context, func, pp, paramLayout);
2480
+ return ;
2481
+ }
2482
+
2483
+ handleMultipleParams (context, func, pp);
2484
+ }
2485
+
2357
2486
static void legalizeMeshPayloadInputParam (
2358
2487
GLSLLegalizationContext* context,
2359
2488
CodeGenContext* codeGenContext,
0 commit comments