[spirv] Add support for -fvk-bind-register (#1480)
format: -fvk-bind-register <type-number> <space> <binding> <set> Also created a short alias for it: -vkbr. This option gives the ultimate manual control of descriptor assignment. It requires: * All resources are annotated with :register() in the source code * -fvk-bind-register is specified for every resource It overrules all other mechanisms. It cannot be used together with -fvk-{u|b|s|t}-shift.
This commit is contained in:
Родитель
d82f291490
Коммит
05cda8da2a
|
@ -144,8 +144,35 @@ constructs when possible. If that is inadequate, we then consider attaching
|
|||
Descriptors
|
||||
~~~~~~~~~~~
|
||||
|
||||
To specify which Vulkan descriptor a particular resource binds to, use the
|
||||
``[[vk::binding(X[, Y])]]`` attribute.
|
||||
The compiler provides multiple mechanisms to specify which Vulkan descriptor
|
||||
a particular resource binds to.
|
||||
|
||||
In the source code, you can use the ``[[vk::binding(X[, Y])]]`` and
|
||||
``[[vk::counter_binding(X)]]`` attribute. The native ``:register()`` attribute
|
||||
is also respected.
|
||||
|
||||
On the command-line, you can use the ``-fvk-{b|s|t|u}-shift`` or
|
||||
``-fvk-bind-register`` option.
|
||||
|
||||
If you can modify the source code, the ``[[vk::binding(X[, Y])]]`` and
|
||||
``[[vk::counter_binding(X)]]`` attribute gives you find-grained control over
|
||||
descriptor assignment.
|
||||
|
||||
If you cannot modify the source code, you can use command-line options to change
|
||||
how ``:register()`` attribute is handled by the compiler. ``-fvk-bind-register``
|
||||
lets you to specify the descriptor for the source at a certain register.
|
||||
``-fvk-{b|s|t|u}-shift`` lets you to apply shifts to all register numbers
|
||||
of a certain register type. They cannot be used together, though.
|
||||
|
||||
Without attribute and command-line option, ``:register(xX, spaceY)`` will be
|
||||
mapped to binding ``X`` in descriptor set ``Y``. Note that register type ``x``
|
||||
is ignored, so this may cause overlap.
|
||||
|
||||
The more specific a mechanism is, the higher precedence it has, and command-line
|
||||
option has higher precedence over source code attribute.
|
||||
|
||||
For more details, see `HLSL register and Vulkan binding`_, `Vulkan specific
|
||||
attributes`_, and `Vulkan-specific options`_.
|
||||
|
||||
Subpass inputs
|
||||
~~~~~~~~~~~~~~
|
||||
|
@ -2829,6 +2856,12 @@ codegen for Vulkan:
|
|||
- ``-fvk-t-shift N M``, similar to ``-fvk-b-shift``, but for t-type registers.
|
||||
- ``-fvk-s-shift N M``, similar to ``-fvk-b-shift``, but for s-type registers.
|
||||
- ``-fvk-u-shift N M``, similar to ``-fvk-b-shift``, but for u-type registers.
|
||||
- ``-fvk-bind-register xX Y N M`` (short alias: ``-vkbr``): Binds the resouce
|
||||
at ``register(xX, spaceY)`` to descriptor set ``M`` and binding ``N``. This
|
||||
option cannot be used together with other binding assignment options.
|
||||
It requires all source code resources have ``:register()`` attribute and
|
||||
all registers have corresponding Vulkan descriptors specified using this
|
||||
option.
|
||||
- ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
|
||||
layout rules for resources.
|
||||
- ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
|
||||
|
|
|
@ -172,6 +172,7 @@ public:
|
|||
llvm::SmallVector<int32_t, 4> VkTShift; // OPT_fvk_t_shift
|
||||
llvm::SmallVector<int32_t, 4> VkSShift; // OPT_fvk_s_shift
|
||||
llvm::SmallVector<int32_t, 4> VkUShift; // OPT_fvk_u_shift
|
||||
std::vector<std::string> VkBindRegister; // OPT_fvk_bind_register
|
||||
llvm::SmallVector<llvm::StringRef, 4> SpvExtensions; // OPT_fspv_extension
|
||||
llvm::StringRef SpvTargetEnv; // OPT_fspv_target_env
|
||||
llvm::SmallVector<llvm::StringRef, 4> SpvOconfig; // OPT_Oconfig
|
||||
|
|
|
@ -246,6 +246,9 @@ 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_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>;
|
||||
def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
||||
HelpText<"Negate SV_Position.y before writing to stage output in VS/DS/GS to accommodate Vulkan's coordinate system">;
|
||||
def fvk_use_dx_position_w: Flag<["-"], "fvk-use-dx-position-w">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
|
||||
|
|
|
@ -206,6 +206,59 @@ static bool GetTargetVersionFromString(llvm::StringRef ref, unsigned *major, uns
|
|||
}
|
||||
}
|
||||
|
||||
// SPIRV Change Starts
|
||||
#ifdef ENABLE_SPIRV_CODEGEN
|
||||
/// Checks and collects the arguments for -fvk-{b|s|t|u}-shift into *shifts.
|
||||
static bool handleVkShiftArgs(const InputArgList &args, OptSpecifier id,
|
||||
const char *name,
|
||||
llvm::SmallVectorImpl<int32_t> *shifts,
|
||||
llvm::raw_ostream &errors) {
|
||||
const auto values = args.getAllArgValues(id);
|
||||
|
||||
if (values.empty())
|
||||
return true;
|
||||
|
||||
if (!args.hasArg(OPT_spirv)) {
|
||||
errors << "-fvk-" << name << "-shift requires -spirv";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!args.getLastArgValue(OPT_fvk_bind_register).empty()) {
|
||||
errors << "-fvk-" << name
|
||||
<< "-shift cannot be used together with -fvk-bind-register";
|
||||
return false;
|
||||
}
|
||||
|
||||
shifts->clear();
|
||||
bool setForAll = false;
|
||||
|
||||
for (const auto &val : values) {
|
||||
int32_t number = 0;
|
||||
if (val == "all") {
|
||||
number = -1;
|
||||
setForAll = true;
|
||||
} else {
|
||||
if (llvm::StringRef(val).getAsInteger(10, number)) {
|
||||
errors << "invalid -fvk-" << name << "-shift argument: " << val;
|
||||
return false;
|
||||
}
|
||||
if (number < 0) {
|
||||
errors << "negative -fvk-" << name << "-shift argument: " << val;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
shifts->push_back(number);
|
||||
}
|
||||
if (setForAll && shifts->size() > 2) {
|
||||
errors << "setting all sets via -fvk-" << name
|
||||
<< "-shift argument should be used alone";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
// SPIRV Change Ends
|
||||
|
||||
namespace hlsl {
|
||||
namespace options {
|
||||
|
||||
|
@ -511,51 +564,14 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
|||
opts.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
|
||||
opts.VkNoWarnIgnoredFeatures = Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false);
|
||||
|
||||
// Collects the arguments for -fvk-{b|s|t|u}-shift.
|
||||
const auto handleVkShiftArgs =
|
||||
[genSpirv, &Args, &errors](OptSpecifier id, const char *name,
|
||||
llvm::SmallVectorImpl<int32_t> *shifts) {
|
||||
const auto values = Args.getAllArgValues(id);
|
||||
|
||||
if (!genSpirv && !values.empty()) {
|
||||
errors << "-fvk-" << name << "-shift requires -spirv";
|
||||
return false;
|
||||
}
|
||||
|
||||
shifts->clear();
|
||||
bool setForAll = false;
|
||||
|
||||
for (const auto &val : values) {
|
||||
int32_t number = 0;
|
||||
if (val == "all") {
|
||||
number = -1;
|
||||
setForAll = true;
|
||||
} else {
|
||||
if (llvm::StringRef(val).getAsInteger(10, number)) {
|
||||
errors << "invalid -fvk-" << name << "-shift argument: " << val;
|
||||
return false;
|
||||
}
|
||||
if (number < 0) {
|
||||
errors << "negative -fvk-" << name << "-shift argument: " << val;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
shifts->push_back(number);
|
||||
}
|
||||
if (setForAll && shifts->size() > 2) {
|
||||
errors << "setting all sets via -fvk-" << name
|
||||
<< "-shift argument should be used alone";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!handleVkShiftArgs(OPT_fvk_b_shift, "b", &opts.VkBShift) ||
|
||||
!handleVkShiftArgs(OPT_fvk_t_shift, "t", &opts.VkTShift) ||
|
||||
!handleVkShiftArgs(OPT_fvk_s_shift, "s", &opts.VkSShift) ||
|
||||
!handleVkShiftArgs(OPT_fvk_u_shift, "u", &opts.VkUShift))
|
||||
if (!handleVkShiftArgs(Args, OPT_fvk_b_shift, "b", &opts.VkBShift, errors) ||
|
||||
!handleVkShiftArgs(Args, OPT_fvk_t_shift, "t", &opts.VkTShift, errors) ||
|
||||
!handleVkShiftArgs(Args, OPT_fvk_s_shift, "s", &opts.VkSShift, errors) ||
|
||||
!handleVkShiftArgs(Args, OPT_fvk_u_shift, "u", &opts.VkUShift, errors))
|
||||
return 1;
|
||||
|
||||
opts.VkBindRegister = Args.getAllArgValues(OPT_fvk_bind_register);
|
||||
|
||||
opts.VkStageIoOrder = Args.getLastArgValue(OPT_fvk_stage_io_order_EQ, "decl");
|
||||
if (opts.VkStageIoOrder != "alpha" && opts.VkStageIoOrder != "decl") {
|
||||
errors << "unknown Vulkan stage I/O location assignment order: "
|
||||
|
@ -598,16 +614,16 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
|
|||
!Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
|
||||
!Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
|
||||
!Args.getLastArgValue(OPT_Oconfig).empty() ||
|
||||
!Args.getLastArgValue(OPT_fvk_bind_register).empty() ||
|
||||
!Args.getLastArgValue(OPT_fvk_b_shift).empty() ||
|
||||
!Args.getLastArgValue(OPT_fvk_t_shift).empty() ||
|
||||
!Args.getLastArgValue(OPT_fvk_s_shift).empty() ||
|
||||
!Args.getLastArgValue(OPT_fvk_u_shift).empty()
|
||||
) {
|
||||
!Args.getLastArgValue(OPT_fvk_u_shift).empty()) {
|
||||
errors << "SPIR-V CodeGen not available. "
|
||||
"Please recompile with -DENABLE_SPIRV_CODEGEN=ON.";
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif // ENABLE_SPIRV_CODEGEN
|
||||
// SPIRV Change Ends
|
||||
|
||||
opts.Args = std::move(Args);
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#ifndef LLVM_CLANG_SPIRV_EMITSPIRVOPTIONS_H
|
||||
#define LLVM_CLANG_SPIRV_EMITSPIRVOPTIONS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
|
@ -45,6 +48,7 @@ struct EmitSPIRVOptions {
|
|||
llvm::SmallVector<int32_t, 4> tShift;
|
||||
llvm::SmallVector<int32_t, 4> sShift;
|
||||
llvm::SmallVector<int32_t, 4> uShift;
|
||||
std::vector<std::string> bindRegister;
|
||||
llvm::SmallVector<llvm::StringRef, 4> allowedExtensions;
|
||||
llvm::StringRef targetEnv;
|
||||
spirv::LayoutRule cBufferLayoutRule;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "clang/AST/HlslTypes.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "llvm/ADT/SmallBitVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -436,7 +437,8 @@ SpirvEvalInfo DeclResultIdMapper::createExternVar(const VarDecl *var) {
|
|||
const auto *bindingAttr = var->getAttr<VKBindingAttr>();
|
||||
const auto *counterBindingAttr = var->getAttr<VKCounterBindingAttr>();
|
||||
|
||||
resourceVars.emplace_back(id, regAttr, bindingAttr, counterBindingAttr);
|
||||
resourceVars.emplace_back(id, var->getLocation(), regAttr, bindingAttr,
|
||||
counterBindingAttr);
|
||||
|
||||
if (const auto *inputAttachment = var->getAttr<VKInputAttachmentIndexAttr>())
|
||||
theBuilder.decorateInputAttachmentIndex(id, inputAttachment->getIndex());
|
||||
|
@ -594,9 +596,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
|
|||
: spirvOptions.tBufferLayoutRule);
|
||||
astDecls[varDecl].indexInCTBuffer = index++;
|
||||
}
|
||||
resourceVars.emplace_back(bufferVar, getResourceBinding(decl),
|
||||
decl->getAttr<VKBindingAttr>(),
|
||||
decl->getAttr<VKCounterBindingAttr>());
|
||||
resourceVars.emplace_back(
|
||||
bufferVar, decl->getLocation(), getResourceBinding(decl),
|
||||
decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
|
||||
|
||||
return bufferVar;
|
||||
}
|
||||
|
@ -642,9 +644,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
|
|||
.setStorageClass(spv::StorageClass::Uniform)
|
||||
.setLayoutRule(context->isCBuffer() ? spirvOptions.cBufferLayoutRule
|
||||
: spirvOptions.tBufferLayoutRule);
|
||||
resourceVars.emplace_back(bufferVar, getResourceBinding(context),
|
||||
decl->getAttr<VKBindingAttr>(),
|
||||
decl->getAttr<VKCounterBindingAttr>());
|
||||
resourceVars.emplace_back(
|
||||
bufferVar, decl->getLocation(), getResourceBinding(context),
|
||||
decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
|
||||
|
||||
return bufferVar;
|
||||
}
|
||||
|
@ -679,7 +681,8 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
|
|||
context, /*arraySize*/ 0, ContextUsageKind::Globals, "type.$Globals",
|
||||
"$Globals");
|
||||
|
||||
resourceVars.emplace_back(globals, nullptr, nullptr, nullptr);
|
||||
resourceVars.emplace_back(globals, SourceLocation(), nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
uint32_t index = 0;
|
||||
for (const auto *decl : typeTranslator.collectDeclsInDeclContext(context))
|
||||
|
@ -793,7 +796,8 @@ void DeclResultIdMapper::createCounterVar(
|
|||
if (!isAlias) {
|
||||
// Non-alias counter variables should be put in to resourceVars so that
|
||||
// descriptors can be allocated for them.
|
||||
resourceVars.emplace_back(counterId, getResourceBinding(decl),
|
||||
resourceVars.emplace_back(counterId, decl->getLocation(),
|
||||
getResourceBinding(decl),
|
||||
decl->getAttr<VKBindingAttr>(),
|
||||
decl->getAttr<VKCounterBindingAttr>(), true);
|
||||
assert(declId);
|
||||
|
@ -1096,6 +1100,59 @@ private:
|
|||
uint32_t masterShift; /// Shift amount applies to all sets.
|
||||
llvm::DenseMap<int32_t, int32_t> perSetShift;
|
||||
};
|
||||
|
||||
/// A class for maintaining the mapping from source code register attributes to
|
||||
/// descriptor set and number settings.
|
||||
class RegisterBindingMapper {
|
||||
public:
|
||||
/// Takes in the relation between register attributes and descriptor settings.
|
||||
/// Each relation is represented by four strings:
|
||||
/// <register-type-number> <space> <descriptor-binding> <set>
|
||||
bool takeInRelation(const std::vector<std::string> &relation,
|
||||
std::string *error) {
|
||||
assert(relation.size() % 4 == 0);
|
||||
mapping.clear();
|
||||
|
||||
for (uint32_t i = 0; i < relation.size(); i += 4) {
|
||||
int32_t spaceNo = -1, setNo = -1, bindNo = -1;
|
||||
if (StringRef(relation[i + 1]).getAsInteger(10, spaceNo) || spaceNo < 0) {
|
||||
*error = "space number: " + relation[i + 1];
|
||||
return false;
|
||||
}
|
||||
if (StringRef(relation[i + 2]).getAsInteger(10, bindNo) || bindNo < 0) {
|
||||
*error = "binding number: " + relation[i + 2];
|
||||
return false;
|
||||
}
|
||||
if (StringRef(relation[i + 3]).getAsInteger(10, setNo) || setNo < 0) {
|
||||
*error = "set number: " + relation[i + 3];
|
||||
return false;
|
||||
}
|
||||
mapping[relation[i + 1] + relation[i]] = std::make_pair(setNo, bindNo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true and set the correct set and binding number if we can find a
|
||||
/// descriptor setting for the given register. False otherwise.
|
||||
bool getSetBinding(const hlsl::RegisterAssignment *regAttr, int *setNo,
|
||||
int *bindNo) const {
|
||||
std::ostringstream iss;
|
||||
iss << regAttr->RegisterSpace << regAttr->RegisterType
|
||||
<< regAttr->RegisterNumber;
|
||||
|
||||
auto found = mapping.find(iss.str());
|
||||
if (found != mapping.end()) {
|
||||
*setNo = found->second.first;
|
||||
*bindNo = found->second.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringMap<std::pair<int, int>> mapping;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool DeclResultIdMapper::decorateResourceBindings() {
|
||||
|
@ -1117,6 +1174,43 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|||
// - m2
|
||||
// - m3, mX * c2
|
||||
|
||||
// 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
|
||||
if (!spirvOptions.bindRegister.empty()) {
|
||||
RegisterBindingMapper bindingMapper;
|
||||
std::string error;
|
||||
|
||||
if (!bindingMapper.takeInRelation(spirvOptions.bindRegister, &error)) {
|
||||
emitError("invalid -fvk-bind-register %0", {}) << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &var : resourceVars)
|
||||
if (const auto *regAttr = var.getRegister()) {
|
||||
if (var.isCounter()) {
|
||||
emitError("-fvk-bind-register for RW/Append/Consume StructuredBuffer "
|
||||
"umimplemented",
|
||||
var.getSourceLocation());
|
||||
} else {
|
||||
int setNo = 0, bindNo = 0;
|
||||
if (!bindingMapper.getSetBinding(regAttr, &setNo, &bindNo)) {
|
||||
emitError("missing -fvk-bind-register for resource",
|
||||
var.getSourceLocation());
|
||||
return false;
|
||||
}
|
||||
theBuilder.decorateDSetBinding(var.getSpirvId(), setNo, bindNo);
|
||||
}
|
||||
} else {
|
||||
emitError(
|
||||
"-fvk-bind-register requires register annotations on all resources",
|
||||
var.getSourceLocation());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BindingSet bindingSet;
|
||||
|
||||
// Decorates the given varId of the given category with set number
|
||||
|
|
|
@ -112,13 +112,14 @@ private:
|
|||
|
||||
class ResourceVar {
|
||||
public:
|
||||
ResourceVar(uint32_t id, const hlsl::RegisterAssignment *r,
|
||||
const VKBindingAttr *b, const VKCounterBindingAttr *cb,
|
||||
bool counter = false)
|
||||
: varId(id), reg(r), binding(b), counterBinding(cb),
|
||||
ResourceVar(uint32_t id, SourceLocation loc,
|
||||
const hlsl::RegisterAssignment *r, const VKBindingAttr *b,
|
||||
const VKCounterBindingAttr *cb, bool counter = false)
|
||||
: varId(id), srcLoc(loc), reg(r), binding(b), counterBinding(cb),
|
||||
isCounterVar(counter) {}
|
||||
|
||||
uint32_t getSpirvId() const { return varId; }
|
||||
SourceLocation getSourceLocation() const { return srcLoc; }
|
||||
const hlsl::RegisterAssignment *getRegister() const { return reg; }
|
||||
const VKBindingAttr *getBinding() const { return binding; }
|
||||
bool isCounter() const { return isCounterVar; }
|
||||
|
@ -128,6 +129,7 @@ public:
|
|||
|
||||
private:
|
||||
uint32_t varId; ///< <result-id>
|
||||
SourceLocation srcLoc; ///< Source location
|
||||
const hlsl::RegisterAssignment *reg; ///< HLSL register assignment
|
||||
const VKBindingAttr *binding; ///< Vulkan binding assignment
|
||||
const VKCounterBindingAttr *counterBinding; ///< Vulkan counter binding
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register u10 2 10 1
|
||||
|
||||
struct S { float4 val; };
|
||||
RWStructuredBuffer<S> MyBuffer : register(u10, space2);
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyBuffer[0].val;
|
||||
}
|
||||
|
||||
// CHECK: :4:24: error: -fvk-bind-register for RW/Append/Consume StructuredBuffer umimplemented
|
|
@ -0,0 +1,13 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register t5 0 1 2 -vkbr s3 1 3 4
|
||||
|
||||
// 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);
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register s10 0 -10 0
|
||||
|
||||
Texture2D MyTexture;
|
||||
SamplerState MySampler;
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
||||
// CHECK: error: invalid -fvk-bind-register binding number: -10
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register s10 0 10 ff
|
||||
|
||||
Texture2D MyTexture;
|
||||
SamplerState MySampler;
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
||||
// CHECK: error: invalid -fvk-bind-register set number: ff
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register s10 5t 10 1
|
||||
|
||||
Texture2D MyTexture;
|
||||
SamplerState MySampler;
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
||||
// CHECK: error: invalid -fvk-bind-register space number: 5t
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register s10 0 10 0
|
||||
|
||||
Texture2D MyTexture;
|
||||
SamplerState MySampler;
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
||||
// CHECK: :3:11: error: -fvk-bind-register requires register annotations on all resources
|
|
@ -0,0 +1,10 @@
|
|||
// Run: %dxc -T ps_6_0 -E main -fvk-bind-register t5 1 10 1
|
||||
|
||||
Texture2D MyTexture : register(t5, space1);
|
||||
SamplerState MySampler : register(s0);
|
||||
|
||||
float4 main() : SV_Target {
|
||||
return MyTexture.Sample(MySampler, float2(0.1, 0.2));
|
||||
}
|
||||
|
||||
// CHECK: :4:14: error: missing -fvk-bind-register for resource
|
|
@ -525,6 +525,7 @@ public:
|
|||
spirvOpts.tShift = opts.VkTShift;
|
||||
spirvOpts.sShift = opts.VkSShift;
|
||||
spirvOpts.uShift = opts.VkUShift;
|
||||
spirvOpts.bindRegister = opts.VkBindRegister;
|
||||
spirvOpts.allowedExtensions = opts.SpvExtensions;
|
||||
spirvOpts.targetEnv = opts.SpvTargetEnv;
|
||||
spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
|
||||
|
|
|
@ -1409,12 +1409,33 @@ TEST_F(FileTest, VulkanRegisterBinding) {
|
|||
TEST_F(FileTest, VulkanRegisterBindingShift) {
|
||||
// Resource binding from :register() with shift specified via
|
||||
// command line option
|
||||
runFileTest("vk.binding.cl.hlsl");
|
||||
runFileTest("vk.binding.cl.shift.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBindingShiftAllSets) {
|
||||
// Resource binding from :register() with shift specified for all sets via
|
||||
// command line option
|
||||
runFileTest("vk.binding.cl.all-sets.hlsl");
|
||||
runFileTest("vk.binding.cl.shift.all-sets.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1Mapping) {
|
||||
runFileTest("vk.binding.cl.register.hlsl");
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingInvalidSpaceNo) {
|
||||
runFileTest("vk.binding.cl.register.invalid-space.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingInvalidSetNo) {
|
||||
runFileTest("vk.binding.cl.register.invalid-set.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingInvalidBindNo) {
|
||||
runFileTest("vk.binding.cl.register.invalid-bind.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingMissingAttr) {
|
||||
runFileTest("vk.binding.cl.register.missing-attr.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingMissingCLOption) {
|
||||
runFileTest("vk.binding.cl.register.missing-cl.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanRegisterBinding1to1MappingAssociatedCounter) {
|
||||
runFileTest("vk.binding.cl.register.counter.hlsl", Expect::Failure);
|
||||
}
|
||||
TEST_F(FileTest, VulkanStructuredBufferCounter) {
|
||||
// [[vk::counter_binding()]] for RWStructuredBuffer, AppendStructuredBuffer,
|
||||
|
|
Загрузка…
Ссылка в новой задаче