[spirv] Command line option for providing $Globals binding. (#2156)
This commit is contained in:
Родитель
6e8df18886
Коммит
5648e43f18
|
@ -1502,7 +1502,48 @@ If we compile with ``-fvk-t-shift 10 0 -fvk-t-shift 20 1``:
|
||||||
- ``sampler1`` will take binding 1 in set #0, since that's the next available
|
- ``sampler1`` will take binding 1 in set #0, since that's the next available
|
||||||
binding number in set #0.
|
binding number in set #0.
|
||||||
|
|
||||||
|
HLSL global variables and Vulkan binding
|
||||||
|
----------------------------------------
|
||||||
|
As mentioned above, all global externally-visible non-resource-type stand-alone
|
||||||
|
variables will be collected into a cbuffer named ``$Globals``. By default,
|
||||||
|
the ``$Globals`` cbuffer is placed in descriptor set #0, and the binding number
|
||||||
|
would be the next available binding number in that set. Meaning, the binding number
|
||||||
|
depends on where the very first global variable is in the code.
|
||||||
|
|
||||||
|
Example 1:
|
||||||
|
|
||||||
.. code:: hlsl
|
.. code:: hlsl
|
||||||
|
|
||||||
|
float4 someColors;
|
||||||
|
// $Globals cbuffer placed at DescriptorSet #0, Binding #0
|
||||||
|
Texture2D<float4> texture1;
|
||||||
|
// texture1 placed at DescriptorSet #0, Binding #1
|
||||||
|
|
||||||
|
Example 2:
|
||||||
|
|
||||||
|
.. code:: hlsl
|
||||||
|
|
||||||
|
Texture2D<float4> texture1;
|
||||||
|
// texture1 placed at DescriptorSet #0, Binding #0
|
||||||
|
float4 someColors;
|
||||||
|
// $Globals cbuffer placed at DescriptorSet #0, Binding #1
|
||||||
|
|
||||||
|
In order provide more control over the descriptor set and binding number of the
|
||||||
|
``$Globals`` cbuffer, you can use the ``-fvk-bind-globals B S`` command line
|
||||||
|
option, which will place this cbuffer at descriptor set ``S``, and binding number ``B``.
|
||||||
|
|
||||||
|
Example 3: (compiled with ``-fvk-bind-globals 2 1``)
|
||||||
|
|
||||||
|
.. code:: hlsl
|
||||||
|
|
||||||
|
Texture2D<float4> texture1;
|
||||||
|
// texture1 placed at DescriptorSet #0, Binding #0
|
||||||
|
float4 someColors;
|
||||||
|
// $Globals cbuffer placed at DescriptorSet #1, Binding #2
|
||||||
|
|
||||||
|
Note that if the developer chooses to use this command line option, it is their
|
||||||
|
responsibility to provide proper numbers and avoid binding overlaps.
|
||||||
|
|
||||||
HLSL Expressions
|
HLSL Expressions
|
||||||
================
|
================
|
||||||
|
|
||||||
|
@ -3202,6 +3243,9 @@ codegen for Vulkan:
|
||||||
It requires all source code resources have ``:register()`` attribute and
|
It requires all source code resources have ``:register()`` attribute and
|
||||||
all registers have corresponding Vulkan descriptors specified using this
|
all registers have corresponding Vulkan descriptors specified using this
|
||||||
option.
|
option.
|
||||||
|
- ``-fvk-bind-globals N M``: Places the ``$Globals`` cbuffer at
|
||||||
|
descriptor set #M and binding #N. See `HLSL global variables and Vulkan binding`_
|
||||||
|
for explanation and examples.
|
||||||
- ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
|
- ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
|
||||||
layout rules for resources.
|
layout rules for resources.
|
||||||
- ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
|
- ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
|
||||||
|
|
|
@ -256,6 +256,8 @@ def fvk_s_shift : MultiArg<["-"], "fvk-s-shift", 2>, MetaVarName<"<shift> <space
|
||||||
HelpText<"Specify Vulkan binding number shift for s-type register">;
|
HelpText<"Specify Vulkan binding number shift for s-type register">;
|
||||||
def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
||||||
HelpText<"Specify Vulkan binding number shift for u-type register">;
|
HelpText<"Specify Vulkan binding number shift for u-type register">;
|
||||||
|
def fvk_bind_globals : MultiArg<["-"], "fvk-bind-globals", 2>, MetaVarName<"<binding> <set>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
||||||
|
HelpText<"Specify Vulkan binding number and set number for the $Globals cbuffer">;
|
||||||
def fvk_bind_register : MultiArg<["-"], "fvk-bind-register", 4>, MetaVarName<"<type-number> <space> <binding> <set>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
def fvk_bind_register : MultiArg<["-"], "fvk-bind-register", 4>, MetaVarName<"<type-number> <space> <binding> <set>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
||||||
HelpText<"Specify Vulkan descriptor set and binding for a specific register">;
|
HelpText<"Specify Vulkan descriptor set and binding for a specific register">;
|
||||||
def vkbr : MultiArg<["-"], "vkbr", 4>, Flags<[CoreOption, DriverOption]>, Alias<fvk_bind_register>;
|
def vkbr : MultiArg<["-"], "vkbr", 4>, Flags<[CoreOption, DriverOption]>, Alias<fvk_bind_register>;
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct SpirvCodeGenOptions {
|
||||||
llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
|
llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
|
||||||
llvm::SmallVector<llvm::StringRef, 4> optConfig;
|
llvm::SmallVector<llvm::StringRef, 4> optConfig;
|
||||||
std::vector<std::string> bindRegister;
|
std::vector<std::string> bindRegister;
|
||||||
|
std::vector<std::string> bindGlobals;
|
||||||
|
|
||||||
// String representation of all command line options.
|
// String representation of all command line options.
|
||||||
std::string clOptions;
|
std::string clOptions;
|
||||||
|
|
|
@ -682,6 +682,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
opts.SpirvOptions.bindRegister = Args.getAllArgValues(OPT_fvk_bind_register);
|
opts.SpirvOptions.bindRegister = Args.getAllArgValues(OPT_fvk_bind_register);
|
||||||
|
opts.SpirvOptions.bindGlobals = Args.getAllArgValues(OPT_fvk_bind_globals);
|
||||||
opts.SpirvOptions.stageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
|
opts.SpirvOptions.stageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
|
||||||
if (opts.SpirvOptions.stageIoOrder != "alpha" && opts.SpirvOptions.stageIoOrder != "decl") {
|
if (opts.SpirvOptions.stageIoOrder != "alpha" && opts.SpirvOptions.stageIoOrder != "decl") {
|
||||||
errors << "unknown Vulkan stage I/O location assignment order: "
|
errors << "unknown Vulkan stage I/O location assignment order: "
|
||||||
|
@ -756,6 +757,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
||||||
!Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
|
!Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
|
||||||
!Args.getLastArgValue(OPT_Oconfig).empty() ||
|
!Args.getLastArgValue(OPT_Oconfig).empty() ||
|
||||||
!Args.getLastArgValue(OPT_fvk_bind_register).empty() ||
|
!Args.getLastArgValue(OPT_fvk_bind_register).empty() ||
|
||||||
|
!Args.getLastArgValue(OPT_fvk_bind_globals).empty() ||
|
||||||
!Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
|
!Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
|
||||||
!Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
|
!Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
|
||||||
!Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
|
!Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
|
||||||
|
|
|
@ -862,7 +862,8 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
|
||||||
"$Globals");
|
"$Globals");
|
||||||
|
|
||||||
resourceVars.emplace_back(globals, SourceLocation(), nullptr, nullptr,
|
resourceVars.emplace_back(globals, SourceLocation(), nullptr, nullptr,
|
||||||
nullptr);
|
nullptr, /*isCounterVar*/ false,
|
||||||
|
/*isGlobalsCBuffer*/ true);
|
||||||
|
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
for (const auto *decl : collectDeclsInDeclContext(context))
|
for (const auto *decl : collectDeclsInDeclContext(context))
|
||||||
|
@ -1371,6 +1372,25 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
||||||
// - m2
|
// - m2
|
||||||
// - m3, m4, mX * c2
|
// - m3, m4, mX * c2
|
||||||
|
|
||||||
|
const bool bindGlobals = !spirvOptions.bindGlobals.empty();
|
||||||
|
int32_t globalsBindNo = -1, globalsSetNo = -1;
|
||||||
|
if (bindGlobals) {
|
||||||
|
assert(spirvOptions.bindGlobals.size() == 2);
|
||||||
|
if (StringRef(spirvOptions.bindGlobals[0])
|
||||||
|
.getAsInteger(10, globalsBindNo) ||
|
||||||
|
globalsBindNo < 0) {
|
||||||
|
emitError("invalid -fvk-bind-globals binding number: %0", {})
|
||||||
|
<< spirvOptions.bindGlobals[0];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (StringRef(spirvOptions.bindGlobals[1]).getAsInteger(10, globalsSetNo) ||
|
||||||
|
globalsSetNo < 0) {
|
||||||
|
emitError("invalid -fvk-bind-globals set number: %0", {})
|
||||||
|
<< spirvOptions.bindGlobals[1];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Special handling of -fvk-bind-register, which requires
|
// Special handling of -fvk-bind-register, which requires
|
||||||
// * All resources are annoated with :register() in the source code
|
// * All resources are annoated with :register() in the source code
|
||||||
// * -fvk-bind-register is specified for every resource
|
// * -fvk-bind-register is specified for every resource
|
||||||
|
@ -1398,6 +1418,9 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
||||||
}
|
}
|
||||||
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), setNo, bindNo);
|
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), setNo, bindNo);
|
||||||
}
|
}
|
||||||
|
} else if (bindGlobals && var.isGlobalsBuffer()) {
|
||||||
|
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), globalsSetNo,
|
||||||
|
globalsBindNo);
|
||||||
} else {
|
} else {
|
||||||
emitError(
|
emitError(
|
||||||
"-fvk-bind-register requires register annotations on all resources",
|
"-fvk-bind-register requires register annotations on all resources",
|
||||||
|
@ -1498,12 +1521,23 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
||||||
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), set,
|
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), set,
|
||||||
bindingSet.useNextBinding(set));
|
bindingSet.useNextBinding(set));
|
||||||
} else if (!reg) {
|
} else if (!reg) {
|
||||||
// Process m3
|
// Process m3 (no 'vk::binding' and no ':register' assignment)
|
||||||
|
|
||||||
|
// There is a special case for the $Globals cbuffer. The $Globals buffer
|
||||||
|
// doesn't have either 'vk::binding' or ':register', but the user may
|
||||||
|
// ask for a specific binding for it via command line options.
|
||||||
|
if (bindGlobals && var.isGlobalsBuffer()) {
|
||||||
|
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), globalsSetNo,
|
||||||
|
globalsBindNo);
|
||||||
|
}
|
||||||
|
// The normal case
|
||||||
|
else {
|
||||||
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), 0,
|
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), 0,
|
||||||
bindingSet.useNextBinding(0));
|
bindingSet.useNextBinding(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,15 +114,17 @@ class ResourceVar {
|
||||||
public:
|
public:
|
||||||
ResourceVar(SpirvVariable *var, SourceLocation loc,
|
ResourceVar(SpirvVariable *var, SourceLocation loc,
|
||||||
const hlsl::RegisterAssignment *r, const VKBindingAttr *b,
|
const hlsl::RegisterAssignment *r, const VKBindingAttr *b,
|
||||||
const VKCounterBindingAttr *cb, bool counter = false)
|
const VKCounterBindingAttr *cb, bool counter = false,
|
||||||
|
bool globalsBuffer = false)
|
||||||
: variable(var), srcLoc(loc), reg(r), binding(b), counterBinding(cb),
|
: variable(var), srcLoc(loc), reg(r), binding(b), counterBinding(cb),
|
||||||
isCounterVar(counter) {}
|
isCounterVar(counter), isGlobalsCBuffer(globalsBuffer) {}
|
||||||
|
|
||||||
SpirvVariable *getSpirvInstr() const { return variable; }
|
SpirvVariable *getSpirvInstr() const { return variable; }
|
||||||
SourceLocation getSourceLocation() const { return srcLoc; }
|
SourceLocation getSourceLocation() const { return srcLoc; }
|
||||||
const hlsl::RegisterAssignment *getRegister() const { return reg; }
|
const hlsl::RegisterAssignment *getRegister() const { return reg; }
|
||||||
const VKBindingAttr *getBinding() const { return binding; }
|
const VKBindingAttr *getBinding() const { return binding; }
|
||||||
bool isCounter() const { return isCounterVar; }
|
bool isCounter() const { return isCounterVar; }
|
||||||
|
bool isGlobalsBuffer() const { return isGlobalsCBuffer; }
|
||||||
const VKCounterBindingAttr *getCounterBinding() const {
|
const VKCounterBindingAttr *getCounterBinding() const {
|
||||||
return counterBinding;
|
return counterBinding;
|
||||||
}
|
}
|
||||||
|
@ -134,6 +136,7 @@ private:
|
||||||
const VKBindingAttr *binding; ///< Vulkan binding assignment
|
const VKBindingAttr *binding; ///< Vulkan binding assignment
|
||||||
const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding
|
const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding
|
||||||
bool isCounterVar; ///< Couter variable or not
|
bool isCounterVar; ///< Couter variable or not
|
||||||
|
bool isGlobalsCBuffer; ///< $Globals cbuffer or not
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A (instruction-pointer, is-alias-or-not) pair for counter variables
|
/// A (instruction-pointer, is-alias-or-not) pair for counter variables
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Run: %dxc -T ps_6_0 -E main -fvk-bind-globals 1 2
|
||||||
|
|
||||||
|
// CHECK: OpDecorate %_Globals DescriptorSet 2
|
||||||
|
// CHECK: OpDecorate %_Globals Binding 1
|
||||||
|
|
||||||
|
int globalInteger;
|
||||||
|
float4 globalFloat4;
|
||||||
|
|
||||||
|
float4 main() : SV_Target {
|
||||||
|
return (globalInteger + globalFloat4.z).xxxx;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register t5 0 1 2 -vkbr s3 1 3 4 -fvk-bind-globals 7 8
|
||||||
|
|
||||||
|
// CHECK: OpDecorate %MyTexture DescriptorSet 2
|
||||||
|
// CHECK: OpDecorate %MyTexture Binding 1
|
||||||
|
Texture2D MyTexture : register(t5);
|
||||||
|
// CHECK: OpDecorate %MySampler DescriptorSet 4
|
||||||
|
// CHECK: OpDecorate %MySampler Binding 3
|
||||||
|
SamplerState MySampler : register(s3, space1);
|
||||||
|
|
||||||
|
// CHECK: OpDecorate %_Globals DescriptorSet 8
|
||||||
|
// CHECK: OpDecorate %_Globals Binding 7
|
||||||
|
int globalInteger;
|
||||||
|
float4 globalFloat4;
|
||||||
|
|
||||||
|
float4 main() : SV_Target {
|
||||||
|
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||||
|
}
|
||||||
|
|
|
@ -1523,6 +1523,16 @@ TEST_F(FileTest, VulkanRegisterBindingShiftAllSets) {
|
||||||
TEST_F(FileTest, VulkanRegisterBinding1to1Mapping) {
|
TEST_F(FileTest, VulkanRegisterBinding1to1Mapping) {
|
||||||
runFileTest("vk.binding.cl.register.hlsl");
|
runFileTest("vk.binding.cl.register.hlsl");
|
||||||
}
|
}
|
||||||
|
TEST_F(FileTest, VulkanGlobalsBinding) {
|
||||||
|
// Binding the $Globals buffer to a specific set/binding via command line
|
||||||
|
// option.
|
||||||
|
runFileTest("vk.binding.cl.globals.hlsl");
|
||||||
|
}
|
||||||
|
TEST_F(FileTest, VulkanGlobalsBindingRegisterBinding) {
|
||||||
|
// Using command line option for specifying both the 1-1 register mapping as
|
||||||
|
// well as $Globals binding.
|
||||||
|
runFileTest("vk.binding.cl.register-and-globals.hlsl");
|
||||||
|
}
|
||||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingInvalidSpaceNo) {
|
TEST_F(FileTest, VulkanRegisterBinding1to1MappingInvalidSpaceNo) {
|
||||||
runFileTest("vk.binding.cl.register.invalid-space.hlsl", Expect::Failure);
|
runFileTest("vk.binding.cl.register.invalid-space.hlsl", Expect::Failure);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче