|
@@ -158,21 +158,18 @@ uint32_t DeclResultIdMapper::createExternVar(const VarDecl *var) {
|
|
const uint32_t id = theBuilder.addModuleVar(varType, storageClass,
|
|
const uint32_t id = theBuilder.addModuleVar(varType, storageClass,
|
|
var->getName(), llvm::None);
|
|
var->getName(), llvm::None);
|
|
astDecls[var] = {id, storageClass, rule};
|
|
astDecls[var] = {id, storageClass, rule};
|
|
- resourceVars.emplace_back(id, getResourceCategory(var->getType()),
|
|
|
|
- getResourceBinding(var),
|
|
|
|
- var->getAttr<VKBindingAttr>());
|
|
|
|
|
|
|
|
- if (isACSBuffer) {
|
|
|
|
- // For {Append|Consume}StructuredBuffer, we need to create another variable
|
|
|
|
- // for its associated counter.
|
|
|
|
- const uint32_t counterType = typeTranslator.getACSBufferCounter();
|
|
|
|
- const std::string counterName = "counter.var." + var->getName().str();
|
|
|
|
- const uint32_t counterId =
|
|
|
|
- theBuilder.addModuleVar(counterType, storageClass, counterName);
|
|
|
|
|
|
+ const auto *regAttr = getResourceBinding(var);
|
|
|
|
+ const auto *bindingAttr = var->getAttr<VKBindingAttr>();
|
|
|
|
+ const auto *counterBindingAttr = var->getAttr<VKCounterBindingAttr>();
|
|
|
|
+
|
|
|
|
+ resourceVars.emplace_back(id, getResourceCategory(var->getType()), regAttr,
|
|
|
|
+ bindingAttr, counterBindingAttr);
|
|
|
|
|
|
- resourceVars.emplace_back(counterId, ResourceVar::Category::Other, nullptr,
|
|
|
|
- nullptr);
|
|
|
|
- counterVars[var] = counterId;
|
|
|
|
|
|
+ if (isACSBuffer) {
|
|
|
|
+ // For {Append|Consume}StructuredBuffer, we need to always create another
|
|
|
|
+ // variable for its associated counter.
|
|
|
|
+ createCounterVar(var);
|
|
}
|
|
}
|
|
|
|
|
|
return id;
|
|
return id;
|
|
@@ -237,9 +234,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) {
|
|
astDecls[varDecl] = {bufferVar, spv::StorageClass::Uniform,
|
|
astDecls[varDecl] = {bufferVar, spv::StorageClass::Uniform,
|
|
LayoutRule::GLSLStd140, index++};
|
|
LayoutRule::GLSLStd140, index++};
|
|
}
|
|
}
|
|
- resourceVars.emplace_back(bufferVar, ResourceVar::Category::Other,
|
|
|
|
- getResourceBinding(decl),
|
|
|
|
- decl->getAttr<VKBindingAttr>());
|
|
|
|
|
|
+ resourceVars.emplace_back(
|
|
|
|
+ bufferVar, ResourceVar::Category::Other, getResourceBinding(decl),
|
|
|
|
+ decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
|
|
|
|
|
|
return bufferVar;
|
|
return bufferVar;
|
|
}
|
|
}
|
|
@@ -260,9 +257,9 @@ uint32_t DeclResultIdMapper::createCTBuffer(const VarDecl *decl) {
|
|
// TODO: std140 rules may not suit tbuffers.
|
|
// TODO: std140 rules may not suit tbuffers.
|
|
astDecls[decl] = {bufferVar, spv::StorageClass::Uniform,
|
|
astDecls[decl] = {bufferVar, spv::StorageClass::Uniform,
|
|
LayoutRule::GLSLStd140};
|
|
LayoutRule::GLSLStd140};
|
|
- resourceVars.emplace_back(bufferVar, ResourceVar::Category::Other,
|
|
|
|
- getResourceBinding(context),
|
|
|
|
- decl->getAttr<VKBindingAttr>());
|
|
|
|
|
|
+ resourceVars.emplace_back(
|
|
|
|
+ bufferVar, ResourceVar::Category::Other, getResourceBinding(context),
|
|
|
|
+ decl->getAttr<VKBindingAttr>(), decl->getAttr<VKCounterBindingAttr>());
|
|
|
|
|
|
return bufferVar;
|
|
return bufferVar;
|
|
}
|
|
}
|
|
@@ -277,11 +274,25 @@ uint32_t DeclResultIdMapper::getOrRegisterFnResultId(const FunctionDecl *fn) {
|
|
return id;
|
|
return id;
|
|
}
|
|
}
|
|
|
|
|
|
-uint32_t DeclResultIdMapper::getCounterId(const VarDecl *decl) {
|
|
|
|
|
|
+uint32_t DeclResultIdMapper::getOrCreateCounterId(const ValueDecl *decl) {
|
|
const auto counter = counterVars.find(decl);
|
|
const auto counter = counterVars.find(decl);
|
|
if (counter != counterVars.end())
|
|
if (counter != counterVars.end())
|
|
return counter->second;
|
|
return counter->second;
|
|
- return 0;
|
|
|
|
|
|
+ return createCounterVar(decl);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+uint32_t DeclResultIdMapper::createCounterVar(const ValueDecl *decl) {
|
|
|
|
+ const auto *info = getDeclSpirvInfo(decl);
|
|
|
|
+ const uint32_t counterType = typeTranslator.getACSBufferCounter();
|
|
|
|
+ const std::string counterName = "counter.var." + decl->getName().str();
|
|
|
|
+ const uint32_t counterId =
|
|
|
|
+ theBuilder.addModuleVar(counterType, info->storageClass, counterName);
|
|
|
|
+
|
|
|
|
+ resourceVars.emplace_back(counterId, ResourceVar::Category::Other,
|
|
|
|
+ getResourceBinding(decl),
|
|
|
|
+ decl->getAttr<VKBindingAttr>(),
|
|
|
|
+ decl->getAttr<VKCounterBindingAttr>(), true);
|
|
|
|
+ return counterVars[decl] = counterId;
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<uint32_t> DeclResultIdMapper::collectStageVars() const {
|
|
std::vector<uint32_t> DeclResultIdMapper::collectStageVars() const {
|
|
@@ -328,8 +339,6 @@ private:
|
|
/// set and binding number.
|
|
/// set and binding number.
|
|
class BindingSet {
|
|
class BindingSet {
|
|
public:
|
|
public:
|
|
- BindingSet() : nextBinding(0) {}
|
|
|
|
-
|
|
|
|
/// Tries to use the given set and binding number. Returns true if possible,
|
|
/// Tries to use the given set and binding number. Returns true if possible,
|
|
/// false otherwise.
|
|
/// false otherwise.
|
|
bool tryToUseBinding(uint32_t binding, uint32_t set,
|
|
bool tryToUseBinding(uint32_t binding, uint32_t set,
|
|
@@ -337,26 +346,28 @@ public:
|
|
const auto cat = static_cast<uint32_t>(category);
|
|
const auto cat = static_cast<uint32_t>(category);
|
|
// Note that we will create the entry for binding in bindings[set] here.
|
|
// Note that we will create the entry for binding in bindings[set] here.
|
|
// But that should not have bad effects since it defaults to zero.
|
|
// But that should not have bad effects since it defaults to zero.
|
|
- if ((bindings[set][binding] & cat) == 0) {
|
|
|
|
- bindings[set][binding] |= cat;
|
|
|
|
|
|
+ if ((usedBindings[set][binding] & cat) == 0) {
|
|
|
|
+ usedBindings[set][binding] |= cat;
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/// Uses the next avaiable binding number in set 0.
|
|
/// Uses the next avaiable binding number in set 0.
|
|
- uint32_t useNextBinding(ResourceVar::Category category) {
|
|
|
|
- auto &set0bindings = bindings[0];
|
|
|
|
- while (set0bindings.count(nextBinding))
|
|
|
|
- nextBinding++;
|
|
|
|
- set0bindings[nextBinding] = static_cast<uint32_t>(category);
|
|
|
|
- return nextBinding++;
|
|
|
|
|
|
+ uint32_t useNextBinding(uint32_t set, ResourceVar::Category category) {
|
|
|
|
+ auto &binding = usedBindings[set];
|
|
|
|
+ auto &next = nextBindings[set];
|
|
|
|
+ while (binding.count(next))
|
|
|
|
+ ++next;
|
|
|
|
+ binding[next] = static_cast<uint32_t>(category);
|
|
|
|
+ return next++;
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
private:
|
|
///< set number -> (binding number -> resource category)
|
|
///< set number -> (binding number -> resource category)
|
|
- llvm::DenseMap<uint32_t, llvm::DenseMap<uint32_t, uint32_t>> bindings;
|
|
|
|
- uint32_t nextBinding; ///< Next available binding number in set 0
|
|
|
|
|
|
+ llvm::DenseMap<uint32_t, llvm::DenseMap<uint32_t, uint32_t>> usedBindings;
|
|
|
|
+ ///< set number -> next available binding number
|
|
|
|
+ llvm::DenseMap<uint32_t, uint32_t> nextBindings;
|
|
};
|
|
};
|
|
} // namespace
|
|
} // namespace
|
|
|
|
|
|
@@ -511,35 +522,74 @@ private:
|
|
}
|
|
}
|
|
|
|
|
|
bool DeclResultIdMapper::decorateResourceBindings() {
|
|
bool DeclResultIdMapper::decorateResourceBindings() {
|
|
|
|
+ // For normal resource, we support 3 approaches of setting binding numbers:
|
|
|
|
+ // - m1: [[vk::binding(...)]]
|
|
|
|
+ // - m2: :register(...)
|
|
|
|
+ // - m3: None
|
|
|
|
+ //
|
|
|
|
+ // For associated counters, we support 2 approaches:
|
|
|
|
+ // - c1: [[vk::counter_binding(...)]
|
|
|
|
+ // - c2: None
|
|
|
|
+ //
|
|
|
|
+ // In combination, we need to handle 9 cases:
|
|
|
|
+ // - 3 cases for nomral resoures (m1, m2, m3)
|
|
|
|
+ // - 6 cases for associated counters (mX * cY)
|
|
|
|
+ //
|
|
|
|
+ // In the following order:
|
|
|
|
+ // - m1, mX * c1
|
|
|
|
+ // - m2
|
|
|
|
+ // - m3, mX * c2
|
|
|
|
+
|
|
BindingSet bindingSet;
|
|
BindingSet bindingSet;
|
|
bool noError = true;
|
|
bool noError = true;
|
|
|
|
|
|
- // Process variables with [[vk::binding(...)]] binding assignment
|
|
|
|
- for (const auto &var : resourceVars)
|
|
|
|
- if (const auto *vkBinding = var.getBinding()) {
|
|
|
|
- const auto cat = var.getCategory();
|
|
|
|
- const auto set = vkBinding->getSet();
|
|
|
|
- const auto binding = vkBinding->getBinding();
|
|
|
|
|
|
+ // Tries to decorate the given varId of the given category with set number
|
|
|
|
+ // setNo, binding number bindingNo. Emits error on failure.
|
|
|
|
+ const auto tryToDecorate = [this, &bindingSet, &noError](
|
|
|
|
+ const uint32_t varId, const uint32_t setNo, const uint32_t bindingNo,
|
|
|
|
+ const ResourceVar::Category cat, SourceLocation loc) {
|
|
|
|
+ if (bindingSet.tryToUseBinding(bindingNo, setNo, cat)) {
|
|
|
|
+ theBuilder.decorateDSetBinding(varId, setNo, bindingNo);
|
|
|
|
+ } else {
|
|
|
|
+ emitError("resource binding #%0 in descriptor set #%1 already assigned",
|
|
|
|
+ loc)
|
|
|
|
+ << bindingNo << setNo;
|
|
|
|
+ noError = false;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
- if (bindingSet.tryToUseBinding(binding, set, cat)) {
|
|
|
|
- theBuilder.decorateDSetBinding(var.getSpirvId(), set, binding);
|
|
|
|
- } else {
|
|
|
|
- emitError("resource binding #%0 in descriptor set #%1 already assigned",
|
|
|
|
- vkBinding->getLocation())
|
|
|
|
- << binding << set;
|
|
|
|
- noError = false;
|
|
|
|
|
|
+ for (const auto &var : resourceVars) {
|
|
|
|
+ if (var.isCounter()) {
|
|
|
|
+ if (const auto *vkCBinding = var.getCounterBinding()) {
|
|
|
|
+ // Process mX * c1
|
|
|
|
+ uint32_t set = 0;
|
|
|
|
+ if (const auto *vkBinding = var.getBinding())
|
|
|
|
+ set = vkBinding->getSet();
|
|
|
|
+ if (const auto *reg = var.getRegister())
|
|
|
|
+ set = reg->RegisterSpace;
|
|
|
|
+
|
|
|
|
+ tryToDecorate(var.getSpirvId(), set, vkCBinding->getBinding(),
|
|
|
|
+ var.getCategory(), vkCBinding->getLocation());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (const auto *vkBinding = var.getBinding()) {
|
|
|
|
+ // Process m1
|
|
|
|
+ tryToDecorate(var.getSpirvId(), vkBinding->getSet(),
|
|
|
|
+ vkBinding->getBinding(), var.getCategory(),
|
|
|
|
+ vkBinding->getLocation());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
BindingShiftMapper bShiftMapper(spirvOptions.bShift);
|
|
BindingShiftMapper bShiftMapper(spirvOptions.bShift);
|
|
BindingShiftMapper tShiftMapper(spirvOptions.tShift);
|
|
BindingShiftMapper tShiftMapper(spirvOptions.tShift);
|
|
BindingShiftMapper sShiftMapper(spirvOptions.sShift);
|
|
BindingShiftMapper sShiftMapper(spirvOptions.sShift);
|
|
BindingShiftMapper uShiftMapper(spirvOptions.uShift);
|
|
BindingShiftMapper uShiftMapper(spirvOptions.uShift);
|
|
|
|
|
|
- // Process variables with register(...) binding assignment
|
|
|
|
|
|
+ // Process m2
|
|
for (const auto &var : resourceVars)
|
|
for (const auto &var : resourceVars)
|
|
- if (const auto *reg = var.getRegister())
|
|
|
|
- if (!var.getBinding()) {
|
|
|
|
|
|
+ if (!var.isCounter() && !var.getBinding())
|
|
|
|
+ if (const auto *reg = var.getRegister()) {
|
|
const uint32_t set = reg->RegisterSpace;
|
|
const uint32_t set = reg->RegisterSpace;
|
|
uint32_t binding = reg->RegisterNumber;
|
|
uint32_t binding = reg->RegisterNumber;
|
|
switch (reg->RegisterType) {
|
|
switch (reg->RegisterType) {
|
|
@@ -562,24 +612,30 @@ bool DeclResultIdMapper::decorateResourceBindings() {
|
|
llvm_unreachable("unknown register type found");
|
|
llvm_unreachable("unknown register type found");
|
|
}
|
|
}
|
|
|
|
|
|
- const auto cat = var.getCategory();
|
|
|
|
-
|
|
|
|
- if (bindingSet.tryToUseBinding(binding, set, cat)) {
|
|
|
|
- theBuilder.decorateDSetBinding(var.getSpirvId(), set, binding);
|
|
|
|
- } else {
|
|
|
|
- emitError(
|
|
|
|
- "resource binding #%0 in descriptor set #%1 already assigned",
|
|
|
|
- reg->Loc)
|
|
|
|
- << binding << set;
|
|
|
|
- noError = false;
|
|
|
|
- }
|
|
|
|
|
|
+ tryToDecorate(var.getSpirvId(), set, binding, var.getCategory(),
|
|
|
|
+ reg->Loc);
|
|
}
|
|
}
|
|
|
|
|
|
- // Process variables with no binding assignment
|
|
|
|
- for (const auto &var : resourceVars)
|
|
|
|
- if (!var.getBinding() && !var.getRegister())
|
|
|
|
- theBuilder.decorateDSetBinding(
|
|
|
|
- var.getSpirvId(), 0, bindingSet.useNextBinding(var.getCategory()));
|
|
|
|
|
|
+ for (const auto &var : resourceVars) {
|
|
|
|
+ const auto cat = var.getCategory();
|
|
|
|
+ if (var.isCounter()) {
|
|
|
|
+ if (!var.getCounterBinding()) {
|
|
|
|
+ // Process mX * c2
|
|
|
|
+ uint32_t set = 0;
|
|
|
|
+ if (const auto *vkBinding = var.getBinding())
|
|
|
|
+ set = vkBinding->getSet();
|
|
|
|
+ else if (const auto *reg = var.getRegister())
|
|
|
|
+ set = reg->RegisterSpace;
|
|
|
|
+
|
|
|
|
+ theBuilder.decorateDSetBinding(var.getSpirvId(), set,
|
|
|
|
+ bindingSet.useNextBinding(set, cat));
|
|
|
|
+ }
|
|
|
|
+ } else if (!var.getBinding() && !var.getRegister()) {
|
|
|
|
+ // Process m3
|
|
|
|
+ theBuilder.decorateDSetBinding(var.getSpirvId(), 0,
|
|
|
|
+ bindingSet.useNextBinding(0, cat));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
return noError;
|
|
return noError;
|
|
}
|
|
}
|