Browse Source

dxgsg9: Further improvements to DX9 shader pipeline support

rdb 5 years ago
parent
commit
1e4b0e7c4f

+ 7 - 1
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -2281,9 +2281,15 @@ reset() {
   _pixel_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.PixelShaderVersion);
   _pixel_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.PixelShaderVersion);
 
-  _supports_hlsl = (_pixel_shader_version_major != 0);
+  // We require at least shader model 3.
+  _supports_hlsl = (_pixel_shader_version_major >= 3);
   _supports_basic_shaders = _supports_hlsl;
 
+  _supported_shader_caps = 0;
+  if (_supports_basic_shaders) {
+    _supported_shader_caps = ShaderModule::C_integer;
+  }
+
   _vertex_shader_profile = (char *) D3DXGetVertexShaderProfile (_d3d_device);
   _pixel_shader_profile = (char *) D3DXGetPixelShaderProfile (_d3d_device);
 

+ 99 - 93
panda/src/dxgsg9/dxShaderContext9.cxx

@@ -81,16 +81,6 @@ compile_module(const ShaderModule *module, DWORD *&data) {
       << spv->get_source_filename() << "\n";
   }
 
-  // Create a mapping from locations to parameter index.  This makes
-  // reflection a little easier later on.
-  pmap<int, unsigned int> params_by_location;
-  for (size_t i = 0; i < module->get_num_parameters(); ++i) {
-    const ShaderModule::Variable &var = module->get_parameter(i);
-    if (var.has_location()) {
-      params_by_location[var.get_location()] = (unsigned int)i;
-    }
-  }
-
   spirv_cross::CompilerHLSL compiler(std::vector<uint32_t>(spv->get_data(), spv->get_data() + spv->get_data_size()));
   spirv_cross::CompilerHLSL::Options options;
   options.shader_model = 30;
@@ -131,6 +121,16 @@ compile_module(const ShaderModule *module, DWORD *&data) {
     }
   }
 
+  // Create a mapping from locations to parameter index.  This makes
+  // reflection a little easier later on.
+  pmap<int, unsigned int> params_by_location;
+  for (size_t i = 0; i < module->get_num_parameters(); ++i) {
+    const ShaderModule::Variable &var = module->get_parameter(i);
+    if (var.has_location()) {
+      params_by_location[var.get_location()] = (unsigned int)i;
+    }
+  }
+
   // Tell spirv-cross to rename the constants to "p#", where # is the index of
   // the original parameter.  This makes it easier to map the compiled
   // constants back to the original parameters later on.
@@ -180,15 +180,33 @@ compile_module(const ShaderModule *module, DWORD *&data) {
     nassertr(shader != nullptr, false);
     data = (DWORD *)shader->GetBufferPointer();
 
+#ifndef NDEBUG
+    if (dxgsg9_cat.is_debug()) {
+      std::ostream &out = dxgsg9_cat.debug()
+        << "Disassembly of compiled " << profile << " module:\n";
+      LPD3DXBUFFER dis;
+      if (SUCCEEDED(D3DXDisassembleShader(data, FALSE, NULL, &dis))) {
+        out << (char *)dis->GetBufferPointer();
+        dis->Release();
+      }
+    }
+#endif
+
+    if (errors != nullptr) {
+      errors->Release();
+    }
+
     return query_constants(module, data);
   }
   else {
     dxgsg9_cat.error()
-      << "Failed to compile " << module->get_stage() << " shader (" << DXGetErrorString(result) << "):\n";
+      << "Failed to compile " << module->get_stage() << " shader ("
+      << DXGetErrorString(result) << "):\n";
 
     if (errors != nullptr) {
       std::string messages((const char *)errors->GetBufferPointer(), errors->GetBufferSize());
       dxgsg9_cat.error(false) << messages << "\n";
+      errors->Release();
     }
     return false;
   }
@@ -219,6 +237,8 @@ query_constants(const ShaderModule *module, DWORD *data) {
     }
   }
 
+  Shader::Stage stage = module->get_stage();
+
   for (DWORD ci = 0; ci < table->Constants; ++ci) {
     D3DXSHADER_CONSTANTINFO &constant = constants[ci];
     D3DXSHADER_TYPEINFO *type = (D3DXSHADER_TYPEINFO *)(offset + constant.TypeInfo);
@@ -227,15 +247,13 @@ query_constants(const ShaderModule *module, DWORD *data) {
     // parameter index.
     const char *name = (const char *)(offset + constant.Name);
     if (name[0] != 'p') {
-      if (module->get_stage() == Shader::Stage::vertex &&
-          strcmp(name, "gl_HalfPixel") == 0) {
+      if (stage == Shader::Stage::vertex && strcmp(name, "gl_HalfPixel") == 0) {
         // This is a special input generated by spirv-cross.
         _half_pixel_register = constant.RegisterIndex;
         continue;
       }
       dxgsg9_cat.warning()
-        << "Ignoring unknown " << module->get_stage()
-        << " shader constant " << name << "\n";
+        << "Ignoring unknown " << stage << " shader constant " << name << "\n";
       continue;
     }
     int index = atoi(name + 1);
@@ -256,99 +274,87 @@ query_constants(const ShaderModule *module, DWORD *data) {
       num_elements = array_type->get_num_elements();
     }
 
-    if (type->Class == D3DXPC_STRUCT) {
-      const ShaderType::Struct *struct_type = element_type->as_struct();
-      nassertr(struct_type != nullptr, false);
+    int reg_set = constant.RegisterSet;
+    int reg_idx = constant.RegisterIndex;
+    int reg_end = reg_idx + constant.RegisterCount;
+    if (!r_query_constants(stage, offset, *type, loc, reg_set, reg_idx, reg_end)) {
+      return false;
+    }
 
 #ifndef NDEBUG
-      if (dxgsg9_cat.is_debug()) {
-        const char sets[] = {'b', 'i', 'c', 's'};
+    if (dxgsg9_cat.is_debug()) {
+      const char sets[] = {'b', 'i', 'c', 's'};
+      if (type->Class == D3DXPC_STRUCT) {
         dxgsg9_cat.debug()
           << "  struct " << name << "[" << type->Elements << "] (" << *var.name
           << "@" << loc << ") at register " << sets[constant.RegisterSet]
           << constant.RegisterIndex;
-
-        if (constant.RegisterCount > 1) {
-          dxgsg9_cat.debug(false)
-            << ".." << (constant.RegisterIndex + constant.RegisterCount - 1);
-        }
-        dxgsg9_cat.debug(false) << std::endl;
-      }
-#endif
-
-      D3DXSHADER_STRUCTMEMBERINFO *members = (D3DXSHADER_STRUCTMEMBERINFO *)(offset + type->StructMemberInfo);
-      int reg_index = constant.RegisterIndex;
-
-      for (WORD ei = 0; ei < type->Elements; ++ei) {
-        for (DWORD mi = 0; mi < type->StructMembers; ++mi) {
-          D3DXSHADER_TYPEINFO *type = (D3DXSHADER_TYPEINFO *)(offset + members[mi].TypeInfo);
-          const char *name = (char *)(offset + members[mi].Name);
-
-          if (type->StructMembers > 0) {
-            dxgsg9_cat.error()
-              << "Nested structs are not currently supported.\n";
-            return false;
-          }
-
-          ConstantRegister &reg = _register_map[(size_t)loc];
-          reg.set = (D3DXREGISTER_SET)constant.RegisterSet;
-          reg.count = std::max(reg.count, (UINT)(type->Elements * type->Rows));
-          switch (module->get_stage()) {
-          case ShaderModule::Stage::vertex:
-            reg.vreg = reg_index;
-            break;
-          case ShaderModule::Stage::fragment:
-            reg.freg = reg_index;
-            break;
-          default:
-            reg.count = 0;
-            break;
-          }
-
-          reg_index += type->Elements * type->Rows;
-          loc += type->Elements;
-        }
-      }
-    } else {
-      // Non-aggregate type.  Note that arrays of arrays are not supported.
-      nassertr(!element_type->is_aggregate_type(), false);
-
-      // Note that RegisterCount may be lower than Rows * Elements if the
-      // optimizer decided that eg. the last row of a matrix is not used!
-
-      ConstantRegister &reg = _register_map[(size_t)loc];
-      reg.set = (D3DXREGISTER_SET)constant.RegisterSet;
-      reg.count = std::max(reg.count, (UINT)constant.RegisterCount);
-      switch (module->get_stage()) {
-      case ShaderModule::Stage::vertex:
-        reg.vreg = constant.RegisterIndex;
-        break;
-      case ShaderModule::Stage::fragment:
-        reg.freg = constant.RegisterIndex;
-        break;
-      default:
-        reg.count = 0;
-        break;
-      }
-
-#ifndef NDEBUG
-      if (dxgsg9_cat.is_debug()) {
+      } else {
         const char *types[] = {"void", "bool", "int", "float", "string", "texture", "texture1D", "texture2D", "texture3D", "textureCUBE", "sampler", "sampler1D", "sampler2D", "sampler3D", "samplerCUBE"};
-        const char sets[] = {'b', 'i', 'c', 's'};
         dxgsg9_cat.debug()
           << "  " << ((type->Type <= D3DXPT_SAMPLERCUBE) ? types[type->Type] : "unknown")
           << " " << name << "[" << type->Elements << "] (" << *var.name
           << "@" << loc << ") at register " << sets[constant.RegisterSet]
           << constant.RegisterIndex;
+      }
+      if (constant.RegisterCount > 1) {
+        dxgsg9_cat.debug(false)
+          << ".." << (constant.RegisterIndex + constant.RegisterCount - 1);
+      }
+      dxgsg9_cat.debug(false) << std::endl;
+    }
+#endif
+  }
+
+  return true;
+}
 
-        if (constant.RegisterCount > 1) {
-          dxgsg9_cat.debug(false)
-            << ".." << (constant.RegisterIndex + constant.RegisterCount - 1);
+/**
+ * Recursive method used by query_constants.
+ */
+bool DXShaderContext9::
+r_query_constants(Shader::Stage stage, BYTE *offset, D3DXSHADER_TYPEINFO &typeinfo,
+                  int &loc, int reg_set, int &reg_idx, int reg_end) {
+  if (typeinfo.Class == D3DXPC_STRUCT) {
+    //const ShaderType::Struct *struct_type = element_type->as_struct();
+    //nassertr(struct_type != nullptr, false);
+    D3DXSHADER_STRUCTMEMBERINFO *members = (D3DXSHADER_STRUCTMEMBERINFO *)(offset + typeinfo.StructMemberInfo);
+
+    for (WORD ei = 0; ei < typeinfo.Elements && reg_idx < reg_end; ++ei) {
+      for (DWORD mi = 0; mi < typeinfo.StructMembers && reg_idx < reg_end; ++mi) {
+        D3DXSHADER_TYPEINFO *typeinfo = (D3DXSHADER_TYPEINFO *)(offset + members[mi].TypeInfo);
+
+        if (!r_query_constants(stage, offset, *typeinfo, loc, reg_set, reg_idx, reg_end)) {
+          return false;
         }
-        dxgsg9_cat.debug(false) << std::endl;
       }
-#endif
     }
+  } else {
+    // Non-aggregate type.  Note that arrays of arrays are not supported.
+    //nassertr(!element_type->is_aggregate_type(), false);
+
+    // Note that RegisterCount may be lower than Rows * Elements if the
+    // optimizer decided that eg. the last row of a matrix is not used!
+
+    nassertr((size_t)loc < _register_map.size(), false);
+
+    ConstantRegister &reg = _register_map[(size_t)loc];
+    reg.set = (D3DXREGISTER_SET)reg_set;
+    reg.count = std::max(reg.count, (UINT)(reg_end - reg_idx));
+    switch (stage) {
+    case ShaderModule::Stage::vertex:
+      reg.vreg = reg_idx;
+      break;
+    case ShaderModule::Stage::fragment:
+      reg.freg = reg_idx;
+      break;
+    default:
+      reg.count = 0;
+      break;
+    }
+
+    loc += typeinfo.Elements;
+    reg_idx += typeinfo.Elements * typeinfo.Rows;
   }
 
   return true;
@@ -547,7 +553,7 @@ issue_parameters(GSG *gsg, int altered) {
           // error.
           reg.count = -1;
         }
-        if (num_cols == 4) {
+        else if (num_cols == 4) {
           // Straight passthrough, hooray!
           void *data = ptr_data._ptr;
           if (reg.vreg >= 0) {

+ 6 - 29
panda/src/dxgsg9/dxShaderContext9.h

@@ -24,36 +24,9 @@
 class VertexElementArray;
 class DXGraphicsStateGuardian9;
 
-// Caution: adding HLSL support is going to be tricky, as the parsing needs to
-// be done in the cull thread, which cannot use the DX API.  - Josh
-//
-//
-// typedef struct
-// {
-//   int vertex_shader;
-//   int total_constant_descriptions;
-//   D3DXCONSTANT_DESC *constant_description_array;
-// }
-// DX_PARAMETER;
-//
-// typedef struct
-// {
-//   int state;
-//   union
-//   {
-//     DIRECT_3D_VERTEX_SHADER direct_3d_vertex_shader;
-//     DIRECT_3D_PIXEL_SHADER direct_3d_pixel_shader;
-//   };
-//   LPD3DXCONSTANTTABLE constant_table;
-//   D3DXCONSTANTTABLE_DESC constant_table_description;
-//
-//   int total_semantics;
-//   D3DXSEMANTIC *semantic_array;
-// }
-// DIRECT_3D_SHADER;
-
 /**
- * xyz
+ * Shader back-end for DX9.  We only support SPIR-V shaders, which are
+ * transpiled to HLSL by spirv-cross, then compiled using D3DXCompileShader.
  */
 class EXPCL_PANDADX DXShaderContext9 : public ShaderContext {
 public:
@@ -78,6 +51,10 @@ public:
   LPDIRECT3DVERTEXDECLARATION9 get_vertex_declaration(GSG *gsg, const GeomVertexFormat *format);
 
 private:
+  bool r_query_constants(Shader::Stage stage, BYTE *offset,
+                         D3DXSHADER_TYPEINFO &typeinfo, int &loc,
+                         int reg_set, int &reg_idx, int reg_end);
+
   IDirect3DVertexShader9 *_vertex_shader = nullptr;
   IDirect3DPixelShader9 *_pixel_shader = nullptr;