Skip to content

Commit c9d9424

Browse files
author
Tim Foley
authored
Parameter block work (shader-slang#276)
* Don't auto-enable IR use for compute tests The `COMPARE_COMPUTE` and `COMPARE_RENDER_COMPUTE` test fixtures were set up to always enable the `-use-ir` flag on Slang, which precludes having any tests that confirm functionality on the old non-IR path (which is still required by our main customer). This change adds the `-xslang -use-ir` flags explicitly to any compute test cases that left them out, and makes the fixture no longer add it by default. * Continue building out parameter block support The initial front-end logic for parameter blocks was already added, but they are still missing a bunch of functionality. This change addresses some of the known issues: - Bug fix: don't try to emit HLSL `register` bindings for variables that consume whole register spaces/sets - Overhaul type layout logic so that it can make decisions based on a given code generation target (currently passed in as a `TargetRequest`), which allows us to decide whether or not a parameter block should get its own register set on a per-target basis. - Always use a register space/set for Vulkan - Never use a register space/set for HLSL SM 5.0 and lower - By default, don't use register spaces/sets for HLSL output - Add a command-line flag and some "target flags" to enable register-space usage for D3D targets - Hackily add initial support for parameter blocks in the AST-to-AST path - This just blindly lowers `ParameterBlock<T>` to `T`, which shouldn't quite work - A more complete overhaul will probably need to wait until the AST-to-AST legalization is changed to use the `LegalType`s from the IR legalization pass. - Add a compute-based test case to actually run code using parameter blocks - This file runs test cases both with and without the IR
1 parent c9368fe commit c9d9424

22 files changed

+625
-266
lines changed

slang.h

+25-3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ extern "C"
135135
SLANG_COMPILE_FLAG_NO_MANGLING = 1 << 3,
136136
};
137137

138+
/*!
139+
@brief Flags to control code generation behavior of a compilation target */
140+
typedef unsigned int SlangTargetFlags;
141+
enum
142+
{
143+
/* When compiling for a D3D Shader Model 5.1 or higher target, allocate
144+
distinct register spaces for parameter blocks. */
145+
SLANG_TARGET_FLAG_PARAMETER_BLOCKS_USE_REGISTER_SPACES = 1 << 4,
146+
};
147+
138148
/*!
139149
@brief Options to control emission of `#line` directives
140150
*/
@@ -249,10 +259,20 @@ extern "C"
249259
/*!
250260
@brief Add a code-generation target to be used.
251261
*/
252-
SLANG_API void spAddCodeGenTarget(
262+
SLANG_API int spAddCodeGenTarget(
253263
SlangCompileRequest* request,
254264
SlangCompileTarget target);
255265

266+
SLANG_API void spSetTargetProfile(
267+
SlangCompileRequest* request,
268+
int targetIndex,
269+
SlangProfileID profile);
270+
271+
SLANG_API void spSetTargetFlags(
272+
SlangCompileRequest* request,
273+
int targetIndex,
274+
SlangTargetFlags flags);
275+
256276
/*!
257277
@brief Set the container format to be used for binary output.
258278
*/
@@ -564,7 +584,9 @@ extern "C"
564584
SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
565585
SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT,
566586
SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER,
567-
SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK,
587+
588+
// HLSL register `space`, Vulkan GLSL `set`
589+
SLANG_PARAMETER_CATEGORY_REGISTER_SPACE,
568590

569591
//
570592
SLANG_PARAMETER_CATEGORY_COUNT,
@@ -825,7 +847,7 @@ namespace slang
825847
DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
826848
SpecializationConstant = SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT,
827849
PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER,
828-
ParameterBlock = SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK,
850+
RegisterSpace = SLANG_PARAMETER_CATEGORY_REGISTER_SPACE,
829851
};
830852

831853
struct TypeLayoutReflection

source/slang/compiler.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ namespace Slang
176176
class TargetRequest : public RefObject
177177
{
178178
public:
179-
CompileRequest* compileRequest;
180-
CodeGenTarget target;
179+
CompileRequest* compileRequest;
180+
CodeGenTarget target;
181+
SlangTargetFlags targetFlags = 0;
182+
Slang::Profile targetProfile = Slang::Profile::Unknown;
181183

182184
// The resulting reflection layout information
183185
RefPtr<ProgramLayout> layout;

source/slang/emit.cpp

+65-56
Original file line numberDiff line numberDiff line change
@@ -3425,75 +3425,84 @@ struct EmitVisitor
34253425
// Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`)
34263426
char const* uniformSemanticSpelling = "register")
34273427
{
3428-
if( info.kind == LayoutResourceKind::Uniform )
3428+
switch(info.kind)
34293429
{
3430-
size_t offset = info.index;
3430+
case LayoutResourceKind::Uniform:
3431+
{
3432+
size_t offset = info.index;
34313433

3432-
// The HLSL `c` register space is logically grouped in 16-byte registers,
3433-
// while we try to traffic in byte offsets. That means we need to pick
3434-
// a register number, based on the starting offset in 16-byte register
3435-
// units, and then a "component" within that register, based on 4-byte
3436-
// offsets from there. We cannot support more fine-grained offsets than that.
3434+
// The HLSL `c` register space is logically grouped in 16-byte registers,
3435+
// while we try to traffic in byte offsets. That means we need to pick
3436+
// a register number, based on the starting offset in 16-byte register
3437+
// units, and then a "component" within that register, based on 4-byte
3438+
// offsets from there. We cannot support more fine-grained offsets than that.
34373439

3438-
Emit(": ");
3439-
Emit(uniformSemanticSpelling);
3440-
Emit("(c");
3440+
Emit(": ");
3441+
Emit(uniformSemanticSpelling);
3442+
Emit("(c");
34413443

3442-
// Size of a logical `c` register in bytes
3443-
auto registerSize = 16;
3444+
// Size of a logical `c` register in bytes
3445+
auto registerSize = 16;
34443446

3445-
// Size of each component of a logical `c` register, in bytes
3446-
auto componentSize = 4;
3447+
// Size of each component of a logical `c` register, in bytes
3448+
auto componentSize = 4;
34473449

3448-
size_t startRegister = offset / registerSize;
3449-
Emit(int(startRegister));
3450+
size_t startRegister = offset / registerSize;
3451+
Emit(int(startRegister));
34503452

3451-
size_t byteOffsetInRegister = offset % registerSize;
3453+
size_t byteOffsetInRegister = offset % registerSize;
34523454

3453-
// If this field doesn't start on an even register boundary,
3454-
// then we need to emit additional information to pick the
3455-
// right component to start from
3456-
if (byteOffsetInRegister != 0)
3457-
{
3458-
// The value had better occupy a whole number of components.
3459-
SLANG_RELEASE_ASSERT(byteOffsetInRegister % componentSize == 0);
3455+
// If this field doesn't start on an even register boundary,
3456+
// then we need to emit additional information to pick the
3457+
// right component to start from
3458+
if (byteOffsetInRegister != 0)
3459+
{
3460+
// The value had better occupy a whole number of components.
3461+
SLANG_RELEASE_ASSERT(byteOffsetInRegister % componentSize == 0);
34603462

3461-
size_t startComponent = byteOffsetInRegister / componentSize;
3463+
size_t startComponent = byteOffsetInRegister / componentSize;
34623464

3463-
static const char* kComponentNames[] = {"x", "y", "z", "w"};
3464-
Emit(".");
3465-
Emit(kComponentNames[startComponent]);
3466-
}
3467-
Emit(")");
3468-
}
3469-
else
3470-
{
3471-
Emit(": register(");
3472-
switch( info.kind )
3473-
{
3474-
case LayoutResourceKind::ConstantBuffer:
3475-
Emit("b");
3476-
break;
3477-
case LayoutResourceKind::ShaderResource:
3478-
Emit("t");
3479-
break;
3480-
case LayoutResourceKind::UnorderedAccess:
3481-
Emit("u");
3482-
break;
3483-
case LayoutResourceKind::SamplerState:
3484-
Emit("s");
3485-
break;
3486-
default:
3487-
SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled HLSL register type");
3488-
break;
3465+
static const char* kComponentNames[] = {"x", "y", "z", "w"};
3466+
Emit(".");
3467+
Emit(kComponentNames[startComponent]);
3468+
}
3469+
Emit(")");
34893470
}
3490-
Emit(info.index);
3491-
if(info.space)
3471+
break;
3472+
3473+
case LayoutResourceKind::RegisterSpace:
3474+
// ignore
3475+
break;
3476+
3477+
default:
34923478
{
3493-
Emit(", space");
3494-
Emit(info.space);
3479+
Emit(": register(");
3480+
switch( info.kind )
3481+
{
3482+
case LayoutResourceKind::ConstantBuffer:
3483+
Emit("b");
3484+
break;
3485+
case LayoutResourceKind::ShaderResource:
3486+
Emit("t");
3487+
break;
3488+
case LayoutResourceKind::UnorderedAccess:
3489+
Emit("u");
3490+
break;
3491+
case LayoutResourceKind::SamplerState:
3492+
Emit("s");
3493+
break;
3494+
default:
3495+
SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unhandled HLSL register type");
3496+
break;
3497+
}
3498+
Emit(info.index);
3499+
if(info.space)
3500+
{
3501+
Emit(", space");
3502+
Emit(info.space);
3503+
}
3504+
Emit(")");
34953505
}
3496-
Emit(")");
34973506
}
34983507
}
34993508

source/slang/ir-legalize-types.cpp

+4-12
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,13 @@ static LegalVal declareSimpleVar(
660660
// those to all the nested resource infos.
661661
for (auto vv = varChain; vv; vv = vv->next)
662662
{
663-
auto parentSpaceInfo = vv->varLayout->findOrAddResourceInfo(LayoutResourceKind::ParameterBlock);
663+
auto parentSpaceInfo = vv->varLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace);
664664
if (!parentSpaceInfo)
665665
continue;
666666

667667
for (auto& rr : varLayout->resourceInfos)
668668
{
669-
if (rr.kind == LayoutResourceKind::ParameterBlock)
669+
if (rr.kind == LayoutResourceKind::RegisterSpace)
670670
{
671671
rr.index += parentSpaceInfo->index;
672672
}
@@ -827,21 +827,13 @@ static void legalizeGlobalVar(
827827
RefPtr<VarLayout> varLayout = findVarLayout(irGlobalVar);
828828
RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
829829

830-
// If we've decided to do implicit deref on the type,
831-
// then go ahead and declare a value of the pointed-to type.
832-
LegalType maybeSimpleType = legalValueType;
833-
while (maybeSimpleType.flavor == LegalType::Flavor::implicitDeref)
834-
{
835-
maybeSimpleType = maybeSimpleType.getImplicitDeref()->valueType;
836-
}
837-
838-
switch (maybeSimpleType.flavor)
830+
switch (legalValueType.flavor)
839831
{
840832
case LegalType::Flavor::simple:
841833
// Easy case: the type is usable as-is, and we
842834
// should just do that.
843835
irGlobalVar->type = context->session->getPtrType(
844-
maybeSimpleType.getSimple());
836+
legalValueType.getSimple());
845837
break;
846838

847839
default:

source/slang/lower.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,20 @@ struct LoweringVisitor
797797
lowerType(type->valueType));
798798
}
799799

800+
RefPtr<Type> visitParameterBlockType(ParameterBlockType* type)
801+
{
802+
// TODO: When doing AST-to-AST lowering, we want to lower
803+
// a `ParameterBlock<T>` just like a `ConstantBuffer<T>`.
804+
//
805+
// HACK: for now we will try to simply lower the type
806+
// directly to its stated element type, and see how
807+
// that works.
808+
809+
return lowerType(type->getElementType());
810+
// return getSession()->getConstantBufferType(
811+
// lowerType(type->getElementType());
812+
}
813+
800814
RefPtr<Type> transformSyntaxField(Type* type)
801815
{
802816
return lowerType(type);

source/slang/options.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct OptionsParser
8080
int profileOptionCount = 0;
8181

8282
SlangCompileFlags flags = 0;
83+
SlangTargetFlags targetFlags = 0;
8384

8485
struct RawOutputPath
8586
{
@@ -279,6 +280,10 @@ struct OptionsParser
279280
{
280281
requestImpl->shouldSkipCodegen = true;
281282
}
283+
else if(argStr == "-parameter-blocks-use-register-spaces" )
284+
{
285+
targetFlags |= SLANG_TARGET_FLAG_PARAMETER_BLOCKS_USE_REGISTER_SPACES;
286+
}
282287
else if (argStr == "-backend" || argStr == "-target")
283288
{
284289
String name = tryReadCommandLineArgument(arg, &argCursor, argEnd);
@@ -729,6 +734,13 @@ struct OptionsParser
729734
}
730735
}
731736

737+
// If the user specifed and per-compilation-target flags, make sure
738+
// to apply them here.
739+
if(targetFlags)
740+
{
741+
spSetTargetFlags(compileRequest, 0, targetFlags);
742+
}
743+
732744
// Next, we want to make sure that entry points get attached to the appropriate translation
733745
// unit that will provide them.
734746
{

0 commit comments

Comments
 (0)