Browse Source

shader: Improvements to capability checking

rdb 5 years ago
parent
commit
70c1d64f84

+ 2 - 2
panda/src/display/graphicsStateGuardian.I

@@ -568,11 +568,11 @@ get_supports_sampler_objects() const {
 }
 
 /**
- * Returns true if this particular GSG supports arbfp1+arbvp1 or above.
+ * Returns true if this particular GSG supports vertex and fragment shaders.
  */
 INLINE bool GraphicsStateGuardian::
 get_supports_basic_shaders() const {
-  return _supports_basic_shaders;
+  return (_supported_shader_caps & ShaderModule::C_basic_shader) != 0;
 }
 
 /**

+ 1 - 2
panda/src/display/graphicsStateGuardian.cxx

@@ -240,7 +240,6 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_depth_stencil = false;
   _supports_shadow_filter = false;
   _supports_sampler_objects = false;
-  _supports_basic_shaders = false;
   _supports_glsl = false;
   _supports_hlsl = false;
   _supports_spir_v = false;
@@ -3548,7 +3547,7 @@ ensure_generated_shader(const RenderState *state) {
 
   if (shader_attrib->auto_shader()) {
     if (_shader_generator == nullptr) {
-      if (!_supports_basic_shaders) {
+      if (!get_supports_basic_shaders()) {
         return;
       }
       _shader_generator = new ShaderGenerator(this);

+ 0 - 1
panda/src/display/graphicsStateGuardian.h

@@ -621,7 +621,6 @@ protected:
   bool _supports_luminance_texture;
   bool _supports_shadow_filter;
   bool _supports_sampler_objects;
-  bool _supports_basic_shaders;
   bool _supports_glsl;
   bool _supports_hlsl;
   bool _supports_spir_v;

+ 9 - 9
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -395,13 +395,10 @@ extract_texture_data(Texture *tex) {
  */
 ShaderContext *DXGraphicsStateGuardian9::
 prepare_shader(Shader *se) {
-  PStatTimer timer(_prepare_shader_pcollector);
-
-  if (_supports_basic_shaders) {
-    return new DXShaderContext9(se, this);
-  }
+  nassertr(supports_basic_shaders(), nullptr);
 
-  return nullptr;
+  PStatTimer timer(_prepare_shader_pcollector);
+  return new DXShaderContext9(se, this);
 }
 
 /**
@@ -2283,11 +2280,14 @@ reset() {
 
   // 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;
+  if (_supports_hlsl) {
+    _supported_shader_caps = ShaderModule::C_basic_shader
+                           | ShaderModule::C_vertex_texture
+                           | ShaderModule::C_sampler_shadow
+                           | ShaderModule::C_integer
+                           | ShaderModule::C_texture_lod;
   }
 
   _vertex_shader_profile = (char *) D3DXGetVertexShaderProfile (_d3d_device);

+ 47 - 47
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1673,20 +1673,29 @@ reset() {
   }
 
   // Check for GLSL support.
-  _supported_shader_caps = 0;
 #if defined(OPENGLES_1)
   _supports_glsl = false;
+  _supported_shader_caps = 0;
 
 #elif defined(OPENGLES)
   _supports_glsl = true;
+  _supported_shader_caps =
+      ShaderModule::C_basic_shader |
+      ShaderModule::C_vertex_texture |
+      ShaderModule::C_sampler_shadow |
+      ShaderModule::C_invariant;
 
   if (is_at_least_gles_version(3, 0)) {
     _supported_shader_caps |=
+      ShaderModule::C_matrix_non_square |
       ShaderModule::C_integer |
+      ShaderModule::C_texture_lod |
       ShaderModule::C_texture_fetch |
+      ShaderModule::C_sampler_cube_shadow |
       ShaderModule::C_vertex_id |
       ShaderModule::C_round_even |
-      ShaderModule::C_instance_id;
+      ShaderModule::C_instance_id |
+      ShaderModule::C_bit_encoding;
   }
 
   if (is_at_least_gles_version(3, 1)) {
@@ -1698,11 +1707,16 @@ reset() {
 
   if (is_at_least_gles_version(3, 2)) {
     _supported_shader_caps |=
+      ShaderModule::C_double |
+      ShaderModule::C_cube_map_array |
+      ShaderModule::C_tessellation_shader |
       ShaderModule::C_sample_variables |
       ShaderModule::C_buffer_texture;
 
     if (has_extension("GL_EXT_geometry_shader")) {
-      _supported_shader_caps |= ShaderModule::C_geometry_shader;
+      _supported_shader_caps |=
+        ShaderModule::C_geometry_shader |
+        ShaderModule::C_primitive_id;
     }
     if (has_extension("GL_EXT_tessellation_shader")) {
       _supported_shader_caps |= ShaderModule::C_tessellation_shader;
@@ -1719,6 +1733,7 @@ reset() {
 
 #else
   _supports_glsl = (_glsl_version >= 100);
+  _supported_shader_caps = 0;
 
   // Test support for shader features.
   if (_supports_glsl) {
@@ -1730,35 +1745,44 @@ reset() {
     // 4.0 guarantees support for 4.00
     // 4.1 guarantees support for 4.10
     // 4.x guarantees support for 1.40-4.x0 (for x >= 2)
+    _supported_shader_caps |=
+      ShaderModule::C_basic_shader |
+      ShaderModule::C_vertex_texture |
+      ShaderModule::C_sampler_shadow;
 
-    if (_glsl_version >= 130) { // OpenGL 3.0
+    // OpenGL 2.1
+    if (_glsl_version >= 120) {
+      _supported_shader_caps |=
+        ShaderModule::C_invariant |
+        ShaderModule::C_matrix_non_square;
+    }
+
+    // OpenGL 3.0
+    if (_glsl_version >= 130) {
       _supported_shader_caps |=
         ShaderModule::C_integer |
+        ShaderModule::C_texture_lod |
         ShaderModule::C_texture_fetch |
-        ShaderModule::C_buffer_texture |
+        ShaderModule::C_sampler_cube_shadow |
         ShaderModule::C_vertex_id |
         ShaderModule::C_round_even;
     }
 
-    if (_glsl_version >= 140) { // OpenGL 3.1
+    // OpenGL 3.1
+    if (_glsl_version >= 140 || has_extension("GL_ARB_draw_instanced")) {
       _supported_shader_caps |= ShaderModule::C_instance_id;
     }
+    if (_glsl_version >= 140 || has_extension("GL_ARB_texture_buffer_object")) {
+      _supported_shader_caps |= ShaderModule::C_buffer_texture;
+    }
 
-    if (_glsl_version >= 150) { // OpenGL 3.2
+    // OpenGL 3.2
+    if (_glsl_version >= 150 || has_extension("GL_ARB_geometry_shader4")) {
       _supported_shader_caps |=
         ShaderModule::C_geometry_shader |
         ShaderModule::C_primitive_id;
       _supported_geom_rendering |= Geom::GR_adjacency;
     }
-    else {
-      if (has_extension("GL_ARB_draw_instanced")) {
-        _supported_shader_caps |= ShaderModule::C_instance_id;
-      }
-      if (has_extension("GL_ARB_geometry_shader4")) {
-        _supported_shader_caps |= ShaderModule::C_geometry_shader;
-        _supported_geom_rendering |= Geom::GR_adjacency;
-      }
-    }
 
     if (_glsl_version >= 330 || has_extension("GL_ARB_shader_bit_encoding")) {
       _supported_shader_caps |= ShaderModule::C_bit_encoding;
@@ -1842,8 +1866,6 @@ reset() {
   }
 #endif
 
-  _supports_basic_shaders = _supports_glsl;
-
 #ifndef OPENGLES_1
 #ifdef OPENGLES
   if (is_at_least_gles_version(3, 1)) {
@@ -1976,23 +1998,6 @@ reset() {
       _glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)
          get_extension_func("glPatchParameteri");
     }
-  } else if (_supports_basic_shaders) {
-    // We don't support GLSL, but we support ARB programs.
-    _glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)
-      get_extension_func("glDisableVertexAttribArrayARB");
-    _glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)
-      get_extension_func("glEnableVertexAttribArrayARB");
-
-    _glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)
-       get_extension_func("glVertexAttrib4fvARB");
-    _glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)
-       get_extension_func("glVertexAttrib4dvARB");
-    _glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
-       get_extension_func("glVertexAttribPointerARB");
-
-    _glBindFragDataLocation = nullptr;
-    _glVertexAttribIPointer = nullptr;
-    _glVertexAttribLPointer = nullptr;
   }
 #endif
 
@@ -6235,20 +6240,15 @@ prepare_shader(Shader *se) {
   PStatGPUTimer timer(this, se->get_prepare_shader_pcollector());
 
 #ifndef OPENGLES_1
-  if (_supports_glsl) {
-    push_group_marker(std::string("Prepare Shader ") + se->get_debug_name());
-    ShaderContext *result = new CLP(ShaderContext)(this, se);
-    pop_group_marker();
-
-    if (result->valid()) {
-      return result;
-    }
+  push_group_marker(std::string("Prepare Shader ") + se->get_debug_name());
+  ShaderContext *result = new CLP(ShaderContext)(this, se);
+  pop_group_marker();
 
-    delete result;
-  } else {
-    GLCAT.error()
-      << "Tried to load shader, but shaders are not supported.\n";
+  if (result->valid()) {
+    return result;
   }
+
+  delete result;
 #endif  // OPENGLES_1
 
   return nullptr;

+ 3 - 0
panda/src/gobj/shader.cxx

@@ -2819,6 +2819,9 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
     }
     out << std::endl;
 
+    // Insert nullptr so that we don't spam this error next time.
+    _contexts[prepared_objects] = nullptr;
+
     return nullptr;
   }
 

+ 24 - 3
panda/src/gobj/shaderModule.cxx

@@ -19,7 +19,7 @@ TypeHandle ShaderModule::_type_handle;
  *
  */
 ShaderModule::
-ShaderModule(Stage stage) : _stage(stage) {
+ShaderModule(Stage stage) : _stage(stage), _used_caps(C_basic_shader) {
   switch (stage) {
   case Stage::tess_control:
   case Stage::tess_evaluation:
@@ -123,14 +123,32 @@ format_stage(Stage stage) {
  */
 void ShaderModule::
 output_capabilities(std::ostream &out, int caps) {
+  if (caps & C_basic_shader) {
+    out << "basic_shader ";
+  }
+  if (caps & C_vertex_texture) {
+    out << "vertex_texture ";
+  }
+  if (caps & C_sampler_shadow) {
+    out << "sampler_shadow ";
+  }
+  if (caps & C_invariant) {
+    out << "invariant ";
+  }
+  if (caps & C_matrix_non_square) {
+    out << "matrix_non_square ";
+  }
   if (caps & C_integer) {
     out << "integer ";
   }
+  if (caps & C_texture_lod) {
+    out << "texture_lod ";
+  }
   if (caps & C_texture_fetch) {
     out << "texture_fetch ";
   }
-  if (caps & C_buffer_texture) {
-    out << "buffer_texture ";
+  if (caps & C_sampler_cube_shadow) {
+    out << "sampler_cube_shadow ";
   }
   if (caps & C_vertex_id) {
     out << "vertex_id ";
@@ -141,6 +159,9 @@ output_capabilities(std::ostream &out, int caps) {
   if (caps & C_instance_id) {
     out << "instance_id ";
   }
+  if (caps & C_buffer_texture) {
+    out << "buffer_texture ";
+  }
   if (caps & C_geometry_shader) {
     out << "geometry_shader ";
   }

+ 44 - 33
panda/src/gobj/shaderModule.h

@@ -97,45 +97,56 @@ public:
    * driver to check whether cross-compilation is possible, or whether certain
    * transformation steps may need to be applied.
    */
-  enum Capabilities {
-    // GLSL 1.30
-    C_integer = 1 << 0,
-    C_texture_fetch = 1 << 1, // texelFetch, textureSize, etc.
-    C_buffer_texture = 1 << 2,
-    C_vertex_id = 1 << 3,
-    C_round_even = 1 << 4,
-
-    // GLSL 1.40
-    C_instance_id = 1 << 5,
-
-    // GLSL 1.50
-    C_geometry_shader = 1 << 6,
-    C_primitive_id = 1 << 7,
+  enum Capabilities : uint64_t {
+    C_basic_shader = 1 << 0,
+    C_vertex_texture = 1 << 1,
+    C_sampler_shadow = 1 << 2, // 1D and 2D only
 
-    // GLSL 3.30 / ARB_shader_bit_encoding
-    C_bit_encoding = 1 << 8,
+    // GLSL 1.20
+    C_invariant = 1 << 3,
+    C_matrix_non_square = 1 << 4,
 
-    // GLSL 4.00
-    C_double = 1 << 9,
-    C_cube_map_array = 1 << 10,
-    C_tessellation_shader = 1 << 11,
-    C_sample_variables = 1 << 12,
-    C_extended_arithmetic = 1 << 13,
-    C_texture_query_lod = 1 << 14,
-
-    // GLSL 4.20
-    C_image_load_store = 1 << 15,
-
-    // GLSL 4.30
-    C_compute_shader = 1 << 16,
-    C_texture_query_levels = 1 << 17,
+    // GLSL 1.30
+    C_integer = 1 << 5,
+    C_texture_lod = 1 << 6, // textureLod, textureGrad, etc.
+    C_texture_fetch = 1 << 7, // texelFetch, textureSize, etc.
+    C_sampler_cube_shadow = 1 << 8,
+    C_vertex_id = 1 << 9,
+    C_round_even = 1 << 10, // roundEven function, also in SM 4.0
+
+    // GLSL 1.40 / SM 4.0
+    C_instance_id = 1 << 11,
+    C_buffer_texture = 1 << 12, // ES 3.20
+
+    // GLSL 1.50 / SM 4.0
+    C_geometry_shader = 1 << 13,
+    C_primitive_id = 1 << 14,
+
+    // GLSL 3.30 / ES 3.00 / SM 4.0
+    C_bit_encoding = 1 << 15,
+
+    // GLSL 4.00 / ES 3.20 / SM 5.0
+    C_texture_gather = 1 << 16,
+    C_double = 1 << 17,
+    C_cube_map_array = 1 << 18,
+    C_tessellation_shader = 1 << 19,
+    C_sample_variables = 1 << 20,
+    C_extended_arithmetic = 1 << 21,
+    C_texture_query_lod = 1 << 22, // not in ES
+
+    // GLSL 4.20 / ES 3.10 / SM 5.0
+    C_image_load_store = 1 << 23,
+
+    // GLSL 4.30 / ES 3.10 / SM 5.0
+    C_compute_shader = 1 << 24,
+    C_texture_query_levels = 1 << 25, // not in ES
 
     // GLSL 4.40 / ARB_enhanced_layouts
-    C_enhanced_layouts = 1 << 18,
+    C_enhanced_layouts = 1 << 26,
 
     // GLSL 4.50
-    C_derivative_control = 1 << 19,
-    C_texture_query_samples = 1 << 20,
+    C_derivative_control = 1 << 27,
+    C_texture_query_samples = 1 << 28,
   };
 
   static std::string format_stage(Stage stage);

+ 57 - 2
panda/src/shaderpipeline/shaderModuleSpirV.cxx

@@ -48,8 +48,8 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words) :
         const Definition &def = writer.get_definition(op.args[2]);
         nassertv(def._dtype == DT_ext_inst);
         if (def._name == "GLSL.std.450" && op.args[3] == 2) {
-          // We mark the use of the GLSL roundEven() function, which is not
-          // supported by HLSL and requires GLSL 1.30.
+          // We mark the use of the GLSL roundEven() function, which requires
+          // GLSL 1.30 or HLSL SM 4.0.
           _used_caps |= C_round_even;
         }
       }
@@ -74,6 +74,10 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words) :
         _used_caps |= C_double;
         break;
 
+      case spv::CapabilityImageGatherExtended:
+        _used_caps |= C_texture_gather;
+        break;
+
       case spv::CapabilityImageCubeArray:
         _used_caps |= C_cube_map_array;
         break;
@@ -172,6 +176,13 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words) :
         break;
       }
     }
+    else if (def._dtype == DT_type && def._type != nullptr) {
+      if (const ShaderType::Matrix *matrix_type = def._type->as_matrix()) {
+        if (matrix_type->get_num_rows() != matrix_type->get_num_columns()) {
+          _used_caps |= C_matrix_non_square;
+        }
+      }
+    }
   }
 
 #ifndef NDEBUG
@@ -189,17 +200,61 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words) :
   for (InstructionIterator it = _instructions.begin_functions(); it != _instructions.end(); ++it) {
     Instruction op = *it;
     switch (op.opcode) {
+    case spv::OpDecorate:
+      if ((spv::Decoration)op.args[1] == spv::DecorationInvariant) {
+        _used_caps |= C_invariant;
+      }
+      break;
+
     case spv::OpImageRead:
     case spv::OpImageWrite:
       _used_caps |= C_image_load_store;
       break;
 
+    case spv::OpImageSampleExplicitLod:
+    case spv::OpImageSampleProjExplicitLod:
+      _used_caps |= C_texture_lod;
+      // fall through
+    case spv::OpImageSampleImplicitLod:
+    case spv::OpImageSampleProjImplicitLod:
+      if (stage == Stage::vertex) {
+        _used_caps |= C_vertex_texture;
+      }
+      break;
+
+    case spv::OpImageSampleDrefExplicitLod:
+    case spv::OpImageSampleProjDrefExplicitLod:
+      _used_caps |= C_texture_lod;
+      // fall through
+    case spv::OpImageSampleDrefImplicitLod:
+    case spv::OpImageSampleProjDrefImplicitLod:
+      _used_caps |= C_sampler_shadow;
+
+      {
+        const Definition &sampler_def = writer.get_definition(op.args[2]);
+        if (sampler_def._type != nullptr) {
+          const ShaderType::SampledImage *sampler = sampler_def._type->as_sampled_image();
+          if (sampler != nullptr &&
+              sampler->get_texture_type() == Texture::TT_cube_map) {
+            _used_caps |= C_sampler_cube_shadow;
+          }
+        }
+      }
+      if (stage == Stage::vertex) {
+        _used_caps |= C_vertex_texture;
+      }
+      break;
+
     case spv::OpImageFetch:
     case spv::OpImageQuerySizeLod:
     case spv::OpImageQuerySize:
       _used_caps |= C_texture_fetch;
       break;
 
+    case spv::OpImageGather:
+      _used_caps |= C_texture_gather;
+      break;
+
     case spv::OpImageQueryLod:
       _used_caps |= C_texture_query_lod;
       break;