Prechádzať zdrojové kódy

[spirv] Support Vulkan 1.2: change operands of OpEntryPoint (#2728)

This commit adds a new DXC option -fspv-target-env=vulkan1.2
that set the target environment of SPIR-V as SPIR-V 1.5.
It specifies all global variables in operands of OpEntryPoint when
the version of SPIR-V is SPIR-V 1.5.
Jaebaek Seo 5 rokov pred
rodič
commit
98bd16c50d

+ 2 - 0
tools/clang/include/clang/SPIRV/SpirvModule.h

@@ -129,6 +129,8 @@ public:
   // Adds the given OpModuleProcessed to the module.
   void addModuleProcessed(SpirvModuleProcessed *);
 
+  llvm::ArrayRef<SpirvVariable *> getVariables() const { return variables; }
+
 private:
   // Use a set for storing capabilities. This will ensure there are no duplicate
   // capabilities. Although the set stores pointers, the provided

+ 10 - 2
tools/clang/lib/SPIRV/EmitVisitor.cpp

@@ -80,6 +80,15 @@ bool isOpLineLegalForOp(spv::Op op) {
   }
 }
 
+// Returns SPIR-V version that will be used in SPIR-V header section.
+uint32_t getHeaderVersion(llvm::StringRef env) {
+  if (env == "vulkan1.1")
+    return 0x00010300u;
+  if (env == "vulkan1.2")
+    return 0x00010500u;
+  return 0x00010000u;
+}
+
 constexpr uint32_t kGeneratorNumber = 14;
 constexpr uint32_t kToolVersion = 0;
 
@@ -274,8 +283,7 @@ void EmitVisitor::finalizeInstruction() {
 
 std::vector<uint32_t> EmitVisitor::takeBinary() {
   std::vector<uint32_t> result;
-  Header header(takeNextId(),
-                spvOptions.targetEnv == "vulkan1.1" ? 0x00010300u : 0x00010000);
+  Header header(takeNextId(), getHeaderVersion(spvOptions.targetEnv));
   auto headerBinary = header.takeBinary();
   result.insert(result.end(), headerBinary.begin(), headerBinary.end());
   result.insert(result.end(), preambleBinary.begin(), preambleBinary.end());

+ 10 - 7
tools/clang/lib/SPIRV/FeatureManager.cpp

@@ -33,9 +33,11 @@ FeatureManager::FeatureManager(DiagnosticsEngine &de,
     targetEnv = SPV_ENV_VULKAN_1_0;
   else if (opts.targetEnv == "vulkan1.1")
     targetEnv = SPV_ENV_VULKAN_1_1;
+  else if (opts.targetEnv == "vulkan1.2")
+    targetEnv = SPV_ENV_VULKAN_1_2;
   else {
     emitError("unknown SPIR-V target environment '%0'", {}) << opts.targetEnv;
-    emitNote("allowed options are:\n vulkan1.0\n vulkan1.1", {});
+    emitNote("allowed options are:\n vulkan1.0\n vulkan1.1\n vulkan1.2", {});
   }
 }
 
@@ -81,8 +83,9 @@ bool FeatureManager::requestExtension(Extension ext, llvm::StringRef target,
 bool FeatureManager::requestTargetEnv(spv_target_env requestedEnv,
                                       llvm::StringRef target,
                                       SourceLocation srcLoc) {
-  if (targetEnv == SPV_ENV_VULKAN_1_0 && requestedEnv == SPV_ENV_VULKAN_1_1) {
-    emitError("Vulkan 1.1 is required for %0 but not permitted to use", srcLoc)
+  if (targetEnv < requestedEnv) {
+    emitError("%0 is required for %1 but not permitted to use", srcLoc)
+        << (requestedEnv == SPV_ENV_VULKAN_1_2 ? "Vulkan 1.2" : "Vulkan 1.1")
         << target;
     emitNote("please specify your target environment via command line option "
              "-fspv-target-env=",
@@ -190,9 +193,9 @@ std::string FeatureManager::getKnownExtensions(const char *delimiter,
 
 bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
   bool required = true;
-  if (targetEnv == SPV_ENV_VULKAN_1_1) {
-    // The following extensions are incorporated into Vulkan 1.1, and are
-    // therefore not required to be emitted for that target environment.
+  if (targetEnv >= SPV_ENV_VULKAN_1_1) {
+    // The following extensions are incorporated into Vulkan 1.1 or above, and
+    // are therefore not required to be emitted for that target environment.
     // TODO: Also add the following extensions  if we start to support them.
     // * SPV_KHR_storage_buffer_storage_class
     // * SPV_KHR_variable_pointers
@@ -204,7 +207,7 @@ bool FeatureManager::isExtensionRequiredForTargetEnv(Extension ext) {
       required = false;
       break;
     default:
-      // Only 1.1 extensions can be suppressed.
+      // Only 1.1 or above extensions can be suppressed.
       required = true;
     }
   }

+ 10 - 7
tools/clang/lib/SPIRV/SpirvEmitter.cpp

@@ -195,8 +195,8 @@ bool spirvToolsOptimize(spv_target_env env, std::vector<uint32_t> *mod,
 }
 
 bool spirvToolsValidate(spv_target_env env, const SpirvCodeGenOptions &opts,
-                        bool beforeHlslLegalization,
-                        std::vector<uint32_t> *mod, std::string *messages) {
+                        bool beforeHlslLegalization, std::vector<uint32_t> *mod,
+                        std::string *messages) {
   spvtools::SpirvTools tools(env);
 
   tools.SetMessageConsumer(
@@ -554,7 +554,8 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci)
                                              spvContext.getMinorVersion(),
                                              fileNames, source);
 
-  if (spirvOptions.debugInfoTool && spirvOptions.targetEnv == "vulkan1.1") {
+  if (spirvOptions.debugInfoTool &&
+      spirvOptions.targetEnv.compare("vulkan1.1") >= 0) {
     // Emit OpModuleProcessed to indicate the commit information.
     std::string commitHash =
         std::string("dxc-commit-hash: ") + clang::getGitCommitHash();
@@ -628,10 +629,12 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) {
     // TODO: assign specific StageVars w.r.t. to entry point
     const FunctionInfo *entryInfo = workQueue[i];
     assert(entryInfo->isEntryFunction);
-    spvBuilder.addEntryPoint(getSpirvShaderStage(entryInfo->shaderModelKind),
-                             entryInfo->entryFunction,
-                             entryInfo->funcDecl->getName(),
-                             declIdMapper.collectStageVars());
+    spvBuilder.addEntryPoint(
+        getSpirvShaderStage(entryInfo->shaderModelKind),
+        entryInfo->entryFunction, entryInfo->funcDecl->getName(),
+        targetEnv == SPV_ENV_VULKAN_1_2
+            ? spvBuilder.getModule()->getVariables()
+            : llvm::ArrayRef<SpirvVariable *>(declIdMapper.collectStageVars()));
   }
 
   // Add Location decorations to stage input/output variables.

+ 38 - 0
tools/clang/test/CodeGenSPIRV/vk.1p2.entry-point.hlsl

@@ -0,0 +1,38 @@
+// Run: %dxc -T ps_6_0 -E main -fspv-target-env=vulkan1.2
+
+// CHECK: OpEntryPoint Fragment %main "main"
+// CHECK-SAME: %_Globals %gSampler %gTex %MyCBuffer %gCBuffer %gSPInput %gRWBuffer %out_var_SV_Target
+
+int gScalar;
+SamplerState gSampler;
+float2 gVec;
+Texture2D gTex;
+float2x3 gMat1;
+row_major float2x3 gMat2;
+row_major float2x3 gArray[2];
+
+struct S {
+  float f;
+};
+
+S gStruct;
+
+cbuffer MyCBuffer {
+  float4 CBData[16];
+};
+
+ConstantBuffer<S> gCBuffer;
+
+typedef SamplerState SamplerStateType;
+
+struct {
+  float2 f;
+} gAnonStruct;
+
+[[vk::input_attachment_index(0)]] SubpassInput gSPInput;
+
+RWBuffer<float4> gRWBuffer[4];
+
+float4 main() : SV_Target {
+  return gScalar + gMat2[0][0] + gStruct.f;
+}

+ 6 - 0
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -2192,4 +2192,10 @@ TEST_F(FileTest, MeshShadingNVAmplificationError4) {
   runFileTest("meshshading.nv.error3.amplification.hlsl", Expect::Failure);
 }
 
+// Test OpEntryPoint in the Vulkan1.2 target environment
+TEST_F(FileTest, Vk1p2EntryPoint) {
+  useVulkan1p2();
+  runFileTest("vk.1p2.entry-point.hlsl");
+}
+
 } // namespace

+ 1 - 0
tools/clang/unittests/SPIRV/FileTestFixture.h

@@ -32,6 +32,7 @@ public:
         glLayout(false), dxLayout(false) {}
 
   void useVulkan1p1() { targetEnv = SPV_ENV_VULKAN_1_1; }
+  void useVulkan1p2() { targetEnv = SPV_ENV_VULKAN_1_2; }
   void setBeforeHLSLLegalization() { beforeHLSLLegalization = true; }
   void setGlLayout() { glLayout = true; }
   void setDxLayout() { dxLayout = true; }