[spirv] Command line option for providing $Globals binding. (#2156)

This commit is contained in:
Ehsan 2019-05-01 18:28:14 -04:00 коммит произвёл GitHub
Родитель 6e8df18886
Коммит 5648e43f18
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 132 добавлений и 6 удалений

Просмотреть файл

@ -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
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
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
================
@ -3202,6 +3243,9 @@ codegen for Vulkan:
It requires all source code resources have ``:register()`` attribute and
all registers have corresponding Vulkan descriptors specified using this
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``
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">;
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">;
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]>,
HelpText<"Specify Vulkan descriptor set and binding for a specific 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> optConfig;
std::vector<std::string> bindRegister;
std::vector<std::string> bindGlobals;
// String representation of all command line options.
std::string clOptions;

Просмотреть файл

@ -682,6 +682,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
return 1;
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");
if (opts.SpirvOptions.stageIoOrder != "alpha" && opts.SpirvOptions.stageIoOrder != "decl") {
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_Oconfig).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_t_shift).empty() ||
!Args.getLastArgValue(OPT_fvk_s_shift).empty() ||

Просмотреть файл

@ -862,7 +862,8 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
"$Globals");
resourceVars.emplace_back(globals, SourceLocation(), nullptr, nullptr,
nullptr);
nullptr, /*isCounterVar*/ false,
/*isGlobalsCBuffer*/ true);
uint32_t index = 0;
for (const auto *decl : collectDeclsInDeclContext(context))
@ -1371,6 +1372,25 @@ bool DeclResultIdMapper::decorateResourceBindings() {
// - m2
// - 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
// * All resources are annoated with :register() in the source code
// * -fvk-bind-register is specified for every resource
@ -1398,6 +1418,9 @@ bool DeclResultIdMapper::decorateResourceBindings() {
}
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), setNo, bindNo);
}
} else if (bindGlobals && var.isGlobalsBuffer()) {
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), globalsSetNo,
globalsBindNo);
} else {
emitError(
"-fvk-bind-register requires register annotations on all resources",
@ -1498,9 +1521,20 @@ bool DeclResultIdMapper::decorateResourceBindings() {
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), set,
bindingSet.useNextBinding(set));
} else if (!reg) {
// Process m3
spvBuilder.decorateDSetBinding(var.getSpirvInstr(), 0,
bindingSet.useNextBinding(0));
// 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,
bindingSet.useNextBinding(0));
}
}
}
}

Просмотреть файл

@ -114,15 +114,17 @@ class ResourceVar {
public:
ResourceVar(SpirvVariable *var, SourceLocation loc,
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),
isCounterVar(counter) {}
isCounterVar(counter), isGlobalsCBuffer(globalsBuffer) {}
SpirvVariable *getSpirvInstr() const { return variable; }
SourceLocation getSourceLocation() const { return srcLoc; }
const hlsl::RegisterAssignment *getRegister() const { return reg; }
const VKBindingAttr *getBinding() const { return binding; }
bool isCounter() const { return isCounterVar; }
bool isGlobalsBuffer() const { return isGlobalsCBuffer; }
const VKCounterBindingAttr *getCounterBinding() const {
return counterBinding;
}
@ -134,6 +136,7 @@ private:
const VKBindingAttr *binding; ///< Vulkan binding assignment
const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding
bool isCounterVar; ///< Couter variable or not
bool isGlobalsCBuffer; ///< $Globals cbuffer or not
};
/// 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) {
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) {
runFileTest("vk.binding.cl.register.invalid-space.hlsl", Expect::Failure);
}