Browse Source

shaderpipeline: SPIR-V refactoring, optimizer, support Cg via glslang

rdb 5 years ago
parent
commit
b506ce13de

+ 3 - 2
makepanda/makepanda.py

@@ -799,6 +799,7 @@ if (COMPILER=="GCC"):
     SmartPkgEnable("JPEG",      "",          ("jpeg"), "jpeglib.h")
     SmartPkgEnable("PNG",       "libpng",    ("png"), "png.h", tool = "libpng-config")
     SmartPkgEnable("GLSLANG",   "",          ("glslang", "SPIRV", "OSDependent", "OGLCompiler", "HLSL"), "glslang/Public/ShaderLang.h")
+    SmartPkgEnable("SPIRV-TOOLS", "",        ("SPIRV-Tools-opt"), "spirv-tools/optimizer.hpp")
 
     # Copy freetype libraries to be specified after harfbuzz libraries as well,
     # because there's a circular dependency between the two libraries.
@@ -3719,7 +3720,7 @@ PyTargetAdd('p3display_ext_composite.obj', opts=OPTS, input='p3display_ext_compo
 # DIRECTORY: panda/src/shaderpipeline/
 #
 
-OPTS=['DIR:panda/src/shaderpipeline', 'BUILDING:PANDA', 'GLSLANG']
+OPTS=['DIR:panda/src/shaderpipeline', 'BUILDING:PANDA', 'GLSLANG', 'SPIRV-TOOLS']
 TargetAdd('p3shaderpipeline_composite1.obj', opts=OPTS, input='p3shaderpipeline_composite1.cxx')
 
 OPTS=['DIR:panda/src/shaderpipeline']
@@ -3909,7 +3910,7 @@ TargetAdd('libp3dxml.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dxml', 'SRCDIR:p
 OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ',
     'TIFF', 'OPENEXR', 'ZLIB', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
     'SQUISH', 'NVIDIACG', 'VORBIS', 'OPUS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI',
-    'SETUPAPI', 'IOKIT', 'GLSLANG']
+    'SETUPAPI', 'IOKIT', 'GLSLANG', 'SPIRV-TOOLS']
 
 TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
 

+ 8 - 8
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -558,7 +558,7 @@ issue_parameters(int altered) {
       void *data = ptr_data->_ptr;
 
       switch (ptr_data->_type) {
-      case Shader::SPT_float:
+      case ShaderType::ST_float:
         if (spec._info._type->as_array() != nullptr) {
           switch (spec._dim[1]) {
           case 1: cgGLSetParameterArray1f(p, 0, spec._dim[0], (float *)data); continue;
@@ -582,7 +582,7 @@ issue_parameters(int altered) {
         }
         break;
 
-      case Shader::SPT_double:
+      case ShaderType::ST_double:
         if (spec._info._type->as_array() != nullptr) {
           switch (spec._dim[1]) {
           case 1: cgGLSetParameterArray1d(p, 0, spec._dim[0], (double *)data); continue;
@@ -606,8 +606,8 @@ issue_parameters(int altered) {
         }
         break;
 
-      case Shader::SPT_int:
-      case Shader::SPT_uint:
+      case ShaderType::ST_int:
+      case ShaderType::ST_uint:
         switch (spec._dim[1]) {
         case 1: cgSetParameter1iv(p, (int *)data); continue;
         case 2: cgSetParameter2iv(p, (int *)data); continue;
@@ -838,11 +838,11 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
-          } else if (bind._numeric_type == Shader::SPT_float ||
+          } else if (bind._scalar_type == ShaderType::ST_float ||
                      numeric_type == GeomEnums::NT_float32) {
             _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
-          } else if (bind._numeric_type == Shader::SPT_double) {
+          } else if (bind._scalar_type == ShaderType::ST_double) {
             _glgsg->_glVertexAttribLPointer(p, num_values, type,
                                             stride, client_pointer);
           } else {
@@ -904,9 +904,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           // So, we work around this by just binding something silly to 0.
           // This breaks flat colors, but it's better than invisible objects?
           _glgsg->enable_vertex_attrib_array(0);
-          if (bind._numeric_type == Shader::SPT_float) {
+          if (bind._scalar_type == ShaderType::ST_float) {
             _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
-          } else if (bind._numeric_type == Shader::SPT_double) {
+          } else if (bind._scalar_type == ShaderType::ST_double) {
             _glgsg->_glVertexAttribLPointer(0, 4, GL_DOUBLE, 0, 0);
           } else {
             _glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);

+ 9 - 43
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -6278,54 +6278,20 @@ prepare_shader(Shader *se) {
   PStatGPUTimer timer(this, se->get_prepare_shader_pcollector());
 
 #ifndef OPENGLES_1
-  ShaderContext *result = nullptr;
-
-  switch (se->get_language()) {
-  case Shader::SL_GLSL:
-    if (_supports_glsl) {
-      push_group_marker(std::string("Prepare Shader ") + se->get_debug_name());
-      result = new CLP(ShaderContext)(this, se);
-      pop_group_marker();
-      break;
-    } else {
-      GLCAT.error()
-        << "Tried to load GLSL shader, but GLSL shaders not supported.\n";
-      return nullptr;
-    }
+  if (_supports_glsl) {
+    push_group_marker(std::string("Prepare Shader ") + se->get_debug_name());
+    ShaderContext *result = new CLP(ShaderContext)(this, se);
+    pop_group_marker();
 
-  case Shader::SL_Cg:
-#if defined(HAVE_CG) && !defined(OPENGLES)
-    if (_supports_basic_shaders) {
-      push_group_marker(std::string("Prepare Shader ") + se->get_debug_name());
-      result = new CLP(CgShaderContext)(this, se);
-      pop_group_marker();
-      break;
-    } else {
-      GLCAT.error()
-        << "Tried to load Cg shader, but basic shaders not supported.\n";
-      return nullptr;
+    if (result->valid()) {
+      return result;
     }
-#elif defined(OPENGLES)
-    GLCAT.error()
-      << "Tried to load Cg shader, but Cg support is not available for OpenGL ES.\n";
-    return nullptr;
-#else
-    GLCAT.error()
-      << "Tried to load Cg shader, but Cg support not compiled in.\n";
-    return nullptr;
-#endif
 
-  default:
+    delete result;
+  } else {
     GLCAT.error()
-      << "Tried to load shader with unsupported shader language!\n";
-    return nullptr;
+      << "Tried to load shader, but shaders are not supported.\n";
   }
-
-  if (result->valid()) {
-    return result;
-  }
-
-  delete result;
 #endif  // OPENGLES_1
 
   return nullptr;

+ 100 - 82
panda/src/glstuff/glShaderContext_src.cxx

@@ -56,7 +56,7 @@ TypeHandle CLP(ShaderContext)::_type_handle;
  */
 bool CLP(ShaderContext)::
 parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_type, GLint param_size, Shader *objShader) {
-  Shader::ShaderArgInfo p;
+  /*Shader::ShaderArgInfo p;
   p._id = arg_id;
 
   string basename(arg_id._name);
@@ -250,7 +250,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t
     }
 
     return true;
-  }
+  }*/
   return false;
 }
 
@@ -270,8 +270,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
   _frame_number = -1;
   _validated = !gl_validate_shaders;
 
-  nassertv(s->get_language() == Shader::SL_GLSL);
-
   // We compile and analyze the shader here, instead of in shader.cxx, to
   // avoid gobj getting a dependency on GL stuff.
   if (!compile_and_link()) {
@@ -315,7 +313,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
     // Do we have a p3d_Color attribute?
     for (auto it = s->_var_spec.begin(); it != s->_var_spec.end(); ++it) {
       Shader::ShaderVarSpec &spec = *it;
-      if (spec._id._name == "p3d_Color") {
+      if (spec._name == InternalName::get_color()) {
         _color_attrib_index = spec._id._seqno;
         break;
       }
@@ -1472,25 +1470,33 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_UNSIGNED_INT_VEC4: {
         Shader::ShaderPtrSpec bind;
         bind._id = arg_id;
+        bind._dim[0] = 1;
+        bind._dim[1] = 1;
         switch (param_type) {
           case GL_BOOL:
           case GL_INT:
           case GL_UNSIGNED_INT:
-          case GL_FLOAT:      bind._dim[1] = 1; break;
+          case GL_FLOAT:      bind._dim[2] = 1; break;
           case GL_BOOL_VEC2:
           case GL_INT_VEC2:
           case GL_UNSIGNED_INT_VEC2:
-          case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
+          case GL_FLOAT_VEC2: bind._dim[2] = 2; break;
           case GL_BOOL_VEC3:
           case GL_INT_VEC3:
           case GL_UNSIGNED_INT_VEC3:
-          case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
+          case GL_FLOAT_VEC3: bind._dim[2] = 3; break;
           case GL_BOOL_VEC4:
           case GL_INT_VEC4:
           case GL_UNSIGNED_INT_VEC4:
-          case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
-          case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
-          case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
+          case GL_FLOAT_VEC4: bind._dim[2] = 4; break;
+          case GL_FLOAT_MAT3:
+            bind._dim[1] = 3;
+            bind._dim[2] = 3;
+            break;
+          case GL_FLOAT_MAT4:
+            bind._dim[1] = 4;
+            bind._dim[2] = 4;
+            break;
         }
         switch (param_type) {
         case GL_BOOL:
@@ -1501,13 +1507,13 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         case GL_UNSIGNED_INT_VEC2:
         case GL_UNSIGNED_INT_VEC3:
         case GL_UNSIGNED_INT_VEC4:
-          bind._type = Shader::SPT_uint;
+          bind._type = ShaderType::ST_uint;
           break;
         case GL_INT:
         case GL_INT_VEC2:
         case GL_INT_VEC3:
         case GL_INT_VEC4:
-          bind._type = Shader::SPT_int;
+          bind._type = ShaderType::ST_int;
           break;
         case GL_FLOAT:
         case GL_FLOAT_VEC2:
@@ -1515,11 +1521,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
         case GL_FLOAT_VEC4:
         case GL_FLOAT_MAT3:
         case GL_FLOAT_MAT4:
-          bind._type = Shader::SPT_float;
+          bind._type = ShaderType::ST_float;
           break;
         }
         bind._arg = InternalName::make(param_name);
-        bind._dim[0] = 1;
         bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
         bind._dep[1] = Shader::SSD_NONE;
         _shader->_ptr_spec.push_back(bind);
@@ -1594,21 +1599,33 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
     case GL_FLOAT_MAT4: {
       Shader::ShaderPtrSpec bind;
       bind._id = arg_id;
+      bind._dim[0] = param_size;
+      bind._dim[1] = 1;
       switch (param_type) {
         case GL_BOOL:
         case GL_INT:
-        case GL_FLOAT:      bind._dim[1] = 1; break;
+        case GL_UNSIGNED_INT:
+        case GL_FLOAT:      bind._dim[2] = 1; break;
         case GL_BOOL_VEC2:
         case GL_INT_VEC2:
-        case GL_FLOAT_VEC2: bind._dim[1] = 2; break;
+        case GL_UNSIGNED_INT_VEC2:
+        case GL_FLOAT_VEC2: bind._dim[2] = 2; break;
         case GL_BOOL_VEC3:
         case GL_INT_VEC3:
-        case GL_FLOAT_VEC3: bind._dim[1] = 3; break;
+        case GL_UNSIGNED_INT_VEC3:
+        case GL_FLOAT_VEC3: bind._dim[2] = 3; break;
         case GL_BOOL_VEC4:
         case GL_INT_VEC4:
-        case GL_FLOAT_VEC4: bind._dim[1] = 4; break;
-        case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
-        case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
+        case GL_UNSIGNED_INT_VEC4:
+        case GL_FLOAT_VEC4: bind._dim[2] = 4; break;
+        case GL_FLOAT_MAT3:
+          bind._dim[1] = 3;
+          bind._dim[2] = 3;
+          break;
+        case GL_FLOAT_MAT4:
+          bind._dim[1] = 4;
+          bind._dim[2] = 4;
+          break;
       }
       switch (param_type) {
       case GL_BOOL:
@@ -1619,13 +1636,13 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_UNSIGNED_INT_VEC2:
       case GL_UNSIGNED_INT_VEC3:
       case GL_UNSIGNED_INT_VEC4:
-        bind._type = Shader::SPT_uint;
+        bind._type = ShaderType::ST_uint;
         break;
       case GL_INT:
       case GL_INT_VEC2:
       case GL_INT_VEC3:
       case GL_INT_VEC4:
-        bind._type = Shader::SPT_int;
+        bind._type = ShaderType::ST_int;
         break;
       case GL_FLOAT:
       case GL_FLOAT_VEC2:
@@ -1633,11 +1650,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
       case GL_FLOAT_VEC4:
       case GL_FLOAT_MAT3:
       case GL_FLOAT_MAT4:
-        bind._type = Shader::SPT_float;
+        bind._type = ShaderType::ST_float;
         break;
       }
       bind._arg = InternalName::make(param_name);
-      bind._dim[0] = param_size;
       bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame;
       bind._dep[1] = Shader::SSD_NONE;
       _shader->_ptr_spec.push_back(bind);
@@ -1659,116 +1675,116 @@ get_param_type(GLenum param_type) {
     return ShaderType::float_type;
 
   case GL_FLOAT_VEC2:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::float_type, 2));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_float, 2));
 
   case GL_FLOAT_VEC3:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::float_type, 3));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_float, 3));
 
   case GL_FLOAT_VEC4:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::float_type, 4));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_float, 4));
 
   case GL_FLOAT_MAT2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 2, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 2, 2));
 
   case GL_FLOAT_MAT3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 3, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 3, 3));
 
   case GL_FLOAT_MAT4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 4, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 4, 4));
 
   case GL_FLOAT_MAT2x3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 2, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 2, 3));
 
   case GL_FLOAT_MAT2x4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 2, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 2, 4));
 
   case GL_FLOAT_MAT3x2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 3, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 3, 2));
 
   case GL_FLOAT_MAT3x4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 3, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 3, 4));
 
   case GL_FLOAT_MAT4x2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 4, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 4, 2));
 
   case GL_FLOAT_MAT4x3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::float_type, 4, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_float, 4, 3));
 
   case GL_INT:
     return ShaderType::int_type;
 
   case GL_INT_VEC2:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::int_type, 2));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_int, 2));
 
   case GL_INT_VEC3:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::int_type, 3));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_int, 3));
 
   case GL_INT_VEC4:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::int_type, 4));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_int, 4));
 
   case GL_BOOL:
     return ShaderType::bool_type;
 
   case GL_BOOL_VEC2:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::bool_type, 2));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_bool, 2));
 
   case GL_BOOL_VEC3:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::bool_type, 3));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_bool, 3));
 
   case GL_BOOL_VEC4:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::bool_type, 4));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_bool, 4));
 
   case GL_UNSIGNED_INT:
     return ShaderType::uint_type;
 
   case GL_UNSIGNED_INT_VEC2:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::uint_type, 2));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_uint, 2));
 
   case GL_UNSIGNED_INT_VEC3:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::uint_type, 3));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_uint, 3));
 
   case GL_UNSIGNED_INT_VEC4:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::uint_type, 4));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_uint, 4));
 
 #ifndef OPENGLES
   case GL_DOUBLE:
     return ShaderType::double_type;
 
   case GL_DOUBLE_VEC2:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::double_type, 2));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_double, 2));
 
   case GL_DOUBLE_VEC3:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::double_type, 3));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_double, 3));
 
   case GL_DOUBLE_VEC4:
-    return ShaderType::register_type(ShaderType::Vector(ShaderType::double_type, 4));
+    return ShaderType::register_type(ShaderType::Vector(ShaderType::ST_double, 4));
 
   case GL_DOUBLE_MAT2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 2, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 2, 2));
 
   case GL_DOUBLE_MAT3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 3, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 3, 3));
 
   case GL_DOUBLE_MAT4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 4, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 4, 4));
 
   case GL_DOUBLE_MAT2x3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 2, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 2, 3));
 
   case GL_DOUBLE_MAT2x4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 2, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 2, 4));
 
   case GL_DOUBLE_MAT3x2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 3, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 3, 2));
 
   case GL_DOUBLE_MAT3x4:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 3, 4));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 3, 4));
 
   case GL_DOUBLE_MAT4x2:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 4, 2));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 4, 2));
 
   case GL_DOUBLE_MAT4x3:
-    return ShaderType::register_type(ShaderType::Matrix(ShaderType::double_type, 4, 3));
+    return ShaderType::register_type(ShaderType::Matrix(ShaderType::ST_double, 4, 3));
 #endif
 
 #ifndef OPENGLES
@@ -2168,39 +2184,41 @@ issue_parameters(int altered) {
 
       nassertd(spec._dim[1] > 0) continue;
 
+      uint32_t dim = spec._dim[1] * spec._dim[2];
       GLint p = spec._id._seqno;
-      int array_size = min(spec._dim[0], (int)ptr_data._size / spec._dim[1]);
+      int array_size = min(spec._dim[0], (uint32_t)(ptr_data._size / dim));
       switch (spec._type) {
-      case Shader::SPT_float:
+      case ShaderType::ST_bool:
+      case ShaderType::ST_float:
         {
           float *data = nullptr;
 
           switch (ptr_data._type) {
-          case Shader::SPT_int:
+          case ShaderType::ST_int:
             // Convert int data to float data.
-            data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
-            for (int i = 0; i < (array_size * spec._dim[1]); ++i) {
+            data = (float*) alloca(sizeof(float) * array_size * dim);
+            for (int i = 0; i < (array_size * dim); ++i) {
               data[i] = (float)(((int*)ptr_data._ptr)[i]);
             }
             break;
 
-          case Shader::SPT_uint:
+          case ShaderType::ST_uint:
             // Convert unsigned int data to float data.
-            data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
-            for (int i = 0; i < (array_size * spec._dim[1]); ++i) {
+            data = (float*) alloca(sizeof(float) * array_size * dim);
+            for (int i = 0; i < (array_size * dim); ++i) {
               data[i] = (float)(((unsigned int*)ptr_data._ptr)[i]);
             }
             break;
 
-          case Shader::SPT_double:
+          case ShaderType::ST_double:
             // Downgrade double data to float data.
-            data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]);
-            for (int i = 0; i < (array_size * spec._dim[1]); ++i) {
+            data = (float*) alloca(sizeof(float) * array_size * dim);
+            for (int i = 0; i < (array_size * dim); ++i) {
               data[i] = (float)(((double*)ptr_data._ptr)[i]);
             }
             break;
 
-          case Shader::SPT_float:
+          case ShaderType::ST_float:
             data = (float*)ptr_data._ptr;
             break;
 
@@ -2208,7 +2226,7 @@ issue_parameters(int altered) {
             nassertd(false) continue;
           }
 
-          switch (spec._dim[1]) {
+          switch (dim) {
           case 1: _glgsg->_glUniform1fv(p, array_size, (float*)data); continue;
           case 2: _glgsg->_glUniform2fv(p, array_size, (float*)data); continue;
           case 3: _glgsg->_glUniform3fv(p, array_size, (float*)data); continue;
@@ -2220,9 +2238,9 @@ issue_parameters(int altered) {
         }
         break;
 
-      case Shader::SPT_int:
-        if (ptr_data._type != Shader::SPT_int &&
-            ptr_data._type != Shader::SPT_uint) {
+      case ShaderType::ST_int:
+        if (ptr_data._type != ShaderType::ST_int &&
+            ptr_data._type != ShaderType::ST_uint) {
           GLCAT.error()
             << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
 
@@ -2232,7 +2250,7 @@ issue_parameters(int altered) {
           spec._dep[1] = 0;
 
         } else {
-          switch (spec._dim[1]) {
+          switch (spec._dim[1] * spec._dim[2]) {
           case 1: _glgsg->_glUniform1iv(p, array_size, (int*)ptr_data._ptr); continue;
           case 2: _glgsg->_glUniform2iv(p, array_size, (int*)ptr_data._ptr); continue;
           case 3: _glgsg->_glUniform3iv(p, array_size, (int*)ptr_data._ptr); continue;
@@ -2242,9 +2260,9 @@ issue_parameters(int altered) {
         }
         break;
 
-      case Shader::SPT_uint:
-        if (ptr_data._type != Shader::SPT_uint &&
-            ptr_data._type != Shader::SPT_int) {
+      case ShaderType::ST_uint:
+        if (ptr_data._type != ShaderType::ST_uint &&
+            ptr_data._type != ShaderType::ST_int) {
           GLCAT.error()
             << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n";
 
@@ -2254,7 +2272,7 @@ issue_parameters(int altered) {
           spec._dep[1] = 0;
 
         } else {
-          switch (spec._dim[1]) {
+          switch (spec._dim[1] * spec._dim[2]) {
           case 1: _glgsg->_glUniform1uiv(p, array_size, (GLuint *)ptr_data._ptr); continue;
           case 2: _glgsg->_glUniform2uiv(p, array_size, (GLuint *)ptr_data._ptr); continue;
           case 3: _glgsg->_glUniform3uiv(p, array_size, (GLuint *)ptr_data._ptr); continue;
@@ -2264,7 +2282,7 @@ issue_parameters(int altered) {
         }
         break;
 
-      case Shader::SPT_double:
+      case ShaderType::ST_double:
         GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
 
         // Deactivate it to make sure the user doesn't get flooded with this
@@ -2537,11 +2555,11 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
             // It requires us to pass GL_TRUE for normalized.
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
-          } else if (bind._numeric_type == Shader::SPT_float ||
+          } else if (bind._scalar_type == ShaderType::ST_float ||
                      numeric_type == GeomEnums::NT_float32) {
             _glgsg->_glVertexAttribPointer(p, num_values, type,
                                            normalized, stride, client_pointer);
-          } else if (bind._numeric_type == Shader::SPT_double) {
+          } else if (bind._scalar_type == ShaderType::ST_double) {
             _glgsg->_glVertexAttribLPointer(p, num_values, type,
                                             stride, client_pointer);
           } else {

+ 39 - 38
panda/src/gobj/shader.I

@@ -244,7 +244,7 @@ operator == (const ShaderCaps &other) const {
 INLINE Shader::ShaderPtrData::
 ShaderPtrData() :
   _ptr(nullptr),
-  _type(SPT_unknown),
+  _type(ScalarType::ST_unknown),
   _updated(true),
   _size(0)
 {
@@ -257,7 +257,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_float &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size())
 {
@@ -270,7 +270,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LMatrix4f &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size() * 16)
 {
@@ -283,7 +283,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LMatrix3f &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size() * 9)
 {
@@ -296,7 +296,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase4f &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size() * 4)
 {
@@ -309,7 +309,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase3f &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size() * 3)
 {
@@ -322,7 +322,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase2f &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(ptr.size() * 2)
 {
@@ -333,7 +333,7 @@ ShaderPtrData(const PTA_LVecBase2f &ptr):
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase4f &vec) :
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(4)
 {
@@ -349,7 +349,7 @@ ShaderPtrData(const LVecBase4f &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase3f &vec) :
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(3)
 {
@@ -365,7 +365,7 @@ ShaderPtrData(const LVecBase3f &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase2f &vec) :
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(2)
 {
@@ -381,7 +381,7 @@ ShaderPtrData(const LVecBase2f &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LMatrix4f &mat) :
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(16)
 {
@@ -397,7 +397,7 @@ ShaderPtrData(const LMatrix4f &mat) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LMatrix3f &mat) :
-  _type(SPT_float),
+  _type(ScalarType::ST_float),
   _updated(true),
   _size(9)
 {
@@ -415,7 +415,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_double &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size())
 {
@@ -428,7 +428,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LMatrix4d &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size() * 16)
 {
@@ -441,7 +441,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LMatrix3d &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size() * 9)
 {
@@ -454,7 +454,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase4d &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size() * 4)
 {
@@ -467,7 +467,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase3d &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size() * 3)
 {
@@ -480,7 +480,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase2d &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(ptr.size() * 2)
 {
@@ -491,7 +491,7 @@ ShaderPtrData(const PTA_LVecBase2d &ptr):
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase4d &vec) :
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(4)
 {
@@ -507,7 +507,7 @@ ShaderPtrData(const LVecBase4d &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase3d &vec) :
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(3)
 {
@@ -523,7 +523,7 @@ ShaderPtrData(const LVecBase3d &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase2d &vec) :
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(2)
 {
@@ -539,7 +539,7 @@ ShaderPtrData(const LVecBase2d &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LMatrix4d &mat) :
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(16)
 {
@@ -555,7 +555,7 @@ ShaderPtrData(const LMatrix4d &mat) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LMatrix3d &mat) :
-  _type(SPT_double),
+  _type(ScalarType::ST_double),
   _updated(true),
   _size(9)
 {
@@ -573,7 +573,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_int &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(ptr.size())
 {
@@ -586,7 +586,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase4i &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(ptr.size() * 4)
 {
@@ -599,7 +599,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase3i &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(ptr.size() * 3)
 {
@@ -612,7 +612,7 @@ INLINE Shader::ShaderPtrData::
 ShaderPtrData(const PTA_LVecBase2i &ptr):
   _pta(ptr.v0()),
   _ptr(ptr.p()),
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(ptr.size() * 2)
 {
@@ -623,7 +623,7 @@ ShaderPtrData(const PTA_LVecBase2i &ptr):
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase4i &vec) :
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(4)
 {
@@ -639,7 +639,7 @@ ShaderPtrData(const LVecBase4i &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase3i &vec) :
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(3)
 {
@@ -655,7 +655,7 @@ ShaderPtrData(const LVecBase3i &vec) :
  */
 INLINE Shader::ShaderPtrData::
 ShaderPtrData(const LVecBase2i &vec) :
-  _type(SPT_int),
+  _type(ScalarType::ST_int),
   _updated(true),
   _size(2)
 {
@@ -675,18 +675,19 @@ write_datagram(Datagram &dg) const {
   dg.add_uint8(_type);
   dg.add_uint32((uint32_t)_size);
 
-  if (_type == SPT_double) {
+  if (_type == ScalarType::ST_double) {
     const double *data = (const double *) _ptr;
     for (size_t i = 0; i < _size; ++i) {
       dg.add_float64(data[i]);
     }
-
-  } else if (_type == SPT_float) {
+  }
+  else if (_type == ScalarType::ST_float) {
     const float *data = (const float *) _ptr;
     for (size_t i = 0; i < _size; ++i) {
       dg.add_float32(data[i]);
     }
-  } else if (_type == SPT_int) {
+  }
+  else if (_type == ScalarType::ST_int) {
     const int *data = (const int *) _ptr;
     for (size_t i = 0; i < _size; ++i) {
       dg.add_int32(data[i]);
@@ -699,10 +700,10 @@ write_datagram(Datagram &dg) const {
  */
 INLINE void Shader::ShaderPtrData::
 read_datagram(DatagramIterator &scan) {
-  _type = (ShaderPtrType) scan.get_uint8();
+  _type = (::ShaderType::ScalarType) scan.get_uint8();
   _size = scan.get_uint32();
 
-  if (_type == SPT_double) {
+  if (_type == ScalarType::ST_double) {
     PTA_double pta = PTA_double::empty_array(_size);
     for (size_t i = 0; i < _size; ++i) {
       pta[i] = scan.get_float64();
@@ -710,7 +711,7 @@ read_datagram(DatagramIterator &scan) {
     _pta = pta.v0();
     _ptr = pta.p();
 
-  } else if (_type == SPT_float) {
+  } else if (_type == ScalarType::ST_float) {
     PTA_float pta = PTA_float::empty_array(_size);
     for (size_t i = 0; i < _size; ++i) {
       pta[i] = scan.get_float32();
@@ -718,7 +719,7 @@ read_datagram(DatagramIterator &scan) {
     _pta = pta.v0();
     _ptr = pta.p();
 
-  } else if (_type == SPT_int) {
+  } else if (_type == ScalarType::ST_int) {
     PTA_int pta = PTA_int::empty_array(_size);
     for (size_t i = 0; i < _size; ++i) {
       pta[i] = scan.get_int32();

File diff suppressed because it is too large
+ 2043 - 2084
panda/src/gobj/shader.cxx


+ 24 - 26
panda/src/gobj/shader.h

@@ -56,6 +56,7 @@ class ShaderCompiler;
 class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
 PUBLISHED:
   using Stage = ShaderModule::Stage;
+  using ScalarType = ShaderType::ScalarType;
 
   enum ShaderLanguage {
     SL_none,
@@ -298,17 +299,16 @@ public:
   };
 
   enum ShaderPtrType {
-    SPT_float,
-    SPT_double,
-    SPT_int,
-    SPT_uint,
-    SPT_unknown
+    SPT_float = ScalarType::ST_float,
+    SPT_double = ScalarType::ST_double,
+    SPT_int = ScalarType::ST_int,
+    SPT_uint = ScalarType::ST_uint,
+    SPT_unknown = ScalarType::ST_unknown,
   };
 
   struct ShaderArgInfo {
-    ShaderArgId       _id;
+    ShaderArgId _id;
     const ::ShaderType *_type;
-    ShaderPtrType     _numeric_type;
   };
 
   // Container structure for data of parameters ShaderPtrSpec.
@@ -318,7 +318,7 @@ public:
 
   public:
     void *_ptr;
-    ShaderPtrType _type;
+    ScalarType _type;
     bool _updated;
     size_t _size; //number of elements vec3[4]=12
 
@@ -408,16 +408,16 @@ public:
     PT(InternalName)  _name;
     int               _append_uv;
     int               _elements;
-    ShaderPtrType     _numeric_type;
+    ScalarType        _scalar_type;
   };
 
   struct ShaderPtrSpec {
     ShaderArgId       _id;
-    int               _dim[3]; //n_elements,rows,cols
+    uint32_t          _dim[3]; //n_elements,rows,cols
     int               _dep[2];
     CPT(InternalName) _arg;
     ShaderArgInfo     _info;
-    ShaderPtrType     _type;
+    ScalarType        _type;
   };
 
   class EXPCL_PANDA_GOBJ ShaderCaps {
@@ -467,23 +467,21 @@ public:
     std::string _compute;
   };
 
-public:
-  void cp_report_error(ShaderArgInfo &arg, const std::string &msg);
-  bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len);
-  bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
-  bool cp_parse_eol(ShaderArgInfo &arg,
-                    vector_string &pieces, int &next);
-  bool cp_parse_delimiter(ShaderArgInfo &arg,
-                          vector_string &pieces, int &next);
-  std::string cp_parse_non_delimiter(vector_string &pieces, int &next);
-  bool cp_parse_coord_sys(ShaderArgInfo &arg,
-                          vector_string &pieces, int &next,
-                          ShaderMatSpec &spec, bool fromflag);
+protected:
+  bool report_parameter_error(const InternalName *name, const ::ShaderType *type, const char *msg);
+  bool expect_num_words(const InternalName *name, const ::ShaderType *type, size_t len);
+  bool expect_float_vector(const InternalName *name, const ::ShaderType *type, int lo, int hi);
+  bool expect_float_matrix(const InternalName *name, const ::ShaderType *type, int lo, int hi);
+  bool expect_coordinate_system(const InternalName *name, const ::ShaderType *type,
+                                vector_string &pieces, int &next,
+                                ShaderMatSpec &spec, bool fromflag);
   int cp_dependency(ShaderMatInput inp);
+
+public:
   void cp_add_mat_spec(ShaderMatSpec &spec);
   size_t cp_get_mat_cache_size() const;
 
-  bool compile_parameter(ShaderArgInfo &p);
+  bool compile_parameter(ShaderArgId &p);
 
   void clear_parameters();
 
@@ -497,7 +495,7 @@ public:
 
 private:
 #ifdef HAVE_CG
-  const ::ShaderType *cg_scalar_type(int type);
+  ScalarType cg_scalar_type(int type);
   const ::ShaderType *cg_parameter_type(CGparameter p);
 
   CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
@@ -588,7 +586,7 @@ private:
 public:
   bool link();
   bool bind_vertex_input(const InternalName *name, const ::ShaderType *type, int location);
-  bool bind_parameter(const InternalName *name, const ::ShaderType *type, int location);
+  bool bind_parameter(CPT_InternalName name, const ::ShaderType *type, int location);
 
   bool check_modified() const;
   ShaderCompiler *get_compiler(ShaderLanguage lang) const;

+ 20 - 20
panda/src/gobj/shaderType.I

@@ -48,38 +48,38 @@ compare_to(const ShaderType &other) const {
  * Constructs a scalar type.
  */
 INLINE ShaderType::Scalar::
-Scalar(GeomEnums::NumericType numeric_type) : _numeric_type(numeric_type) {
+Scalar(ScalarType scalar_type) : _scalar_type(scalar_type) {
 }
 
 /**
  * Returns the base numeric type.
  */
-INLINE GeomEnums::NumericType ShaderType::Scalar::
-get_numeric_type() const {
-  return _numeric_type;
+INLINE ShaderType::ScalarType ShaderType::Scalar::
+get_scalar_type() const {
+  return _scalar_type;
 }
 
 /**
  * Constructs a vector from a scalar type and number of elements.
  */
 INLINE ShaderType::Vector::
-Vector(const ShaderType *base_type, size_t num_elements) :
-  _base_type(base_type),
+Vector(ScalarType scalar_type, uint32_t num_elements) :
+  _scalar_type(scalar_type),
   _num_elements(num_elements) {
 }
 
 /**
  * Returns the scalar type that this vector consists of.
  */
-INLINE const ShaderType *ShaderType::Vector::
-get_base_type() const {
-  return _base_type;
+INLINE ShaderType::ScalarType ShaderType::Vector::
+get_scalar_type() const {
+  return _scalar_type;
 }
 
 /**
  * Returns the number of elements in this vector.
  */
-INLINE size_t ShaderType::Vector::
+INLINE uint32_t ShaderType::Vector::
 get_num_elements() const {
   return _num_elements;
 }
@@ -88,8 +88,8 @@ get_num_elements() const {
  * Constructs a matrix type from a scalar type, a number of rows and columns.
  */
 INLINE ShaderType::Matrix::
-Matrix(const ShaderType *base_type, size_t num_rows, size_t num_columns) :
-  _base_type(base_type),
+Matrix(ScalarType scalar_type, uint32_t num_rows, uint32_t num_columns) :
+  _scalar_type(scalar_type),
   _num_rows(num_rows),
   _num_columns(num_columns) {
 }
@@ -97,15 +97,15 @@ Matrix(const ShaderType *base_type, size_t num_rows, size_t num_columns) :
 /**
  * Returns the scalar type that this matrix consists of.
  */
-INLINE const ShaderType *ShaderType::Matrix::
-get_base_type() const {
-  return _base_type;
+INLINE ShaderType::ScalarType ShaderType::Matrix::
+get_scalar_type() const {
+  return _scalar_type;
 }
 
 /**
  * Returns the number of rows in this matrix type.
  */
-INLINE size_t ShaderType::Matrix::
+INLINE uint32_t ShaderType::Matrix::
 get_num_rows() const {
   return _num_rows;
 }
@@ -113,7 +113,7 @@ get_num_rows() const {
 /**
  * Returns the number of columns in this matrix type.
  */
-INLINE size_t ShaderType::Matrix::
+INLINE uint32_t ShaderType::Matrix::
 get_num_columns() const {
   return _num_columns;
 }
@@ -138,7 +138,7 @@ get_member(size_t i) const {
  * Adds a member to this struct.
  */
 INLINE void ShaderType::Struct::
-add_member(const ShaderType *type, CPT(InternalName) name) {
+add_member(const ShaderType *type, std::string name) {
   Member member;
   member.type = type;
   member.name = std::move(name);
@@ -149,7 +149,7 @@ add_member(const ShaderType *type, CPT(InternalName) name) {
  * Constructs an array type from a base type and number of elements.
  */
 INLINE ShaderType::Array::
-Array(const ShaderType *element_type, size_t num_elements) :
+Array(const ShaderType *element_type, uint32_t num_elements) :
   _element_type(element_type),
   _num_elements(num_elements) {
 }
@@ -165,7 +165,7 @@ get_element_type() const {
 /**
  * Returns the number of elements in this array.
  */
-INLINE size_t ShaderType::Array::
+INLINE uint32_t ShaderType::Array::
 get_num_elements() const {
   return _num_elements;
 }

+ 110 - 26
panda/src/gobj/shaderType.cxx

@@ -25,6 +25,7 @@ TypeHandle ShaderType::Matrix::_type_handle;
 TypeHandle ShaderType::Struct::_type_handle;
 TypeHandle ShaderType::Array::_type_handle;
 TypeHandle ShaderType::Image::_type_handle;
+TypeHandle ShaderType::Sampler::_type_handle;
 TypeHandle ShaderType::SampledImage::_type_handle;
 
 const ShaderType::Scalar *ShaderType::bool_type;
@@ -32,6 +33,7 @@ const ShaderType::Scalar *ShaderType::int_type;
 const ShaderType::Scalar *ShaderType::uint_type;
 const ShaderType::Scalar *ShaderType::float_type;
 const ShaderType::Scalar *ShaderType::double_type;
+const ShaderType::Sampler *ShaderType::sampler_type;
 
 /**
  *
@@ -52,33 +54,53 @@ init_type() {
   ::register_type(Struct::_type_handle, "ShaderType::Struct", _type_handle);
   ::register_type(Array::_type_handle, "ShaderType::Array", _type_handle);
   ::register_type(Image::_type_handle, "ShaderType::Image", _type_handle);
+  ::register_type(Sampler::_type_handle, "ShaderType::Sampler", _type_handle);
   ::register_type(SampledImage::_type_handle, "ShaderType::SampledImage", _type_handle);
-  //::register_type(Sampler::_type_handle, "ShaderType::Sampler", _type_handle);
 
-  bool_type = nullptr;
-  int_type = ShaderType::register_type(ShaderType::Scalar(GeomEnums::NT_int32));
-  uint_type = ShaderType::register_type(ShaderType::Scalar(GeomEnums::NT_uint32));
-  float_type = ShaderType::register_type(ShaderType::Scalar(GeomEnums::NT_float32));
-  double_type = ShaderType::register_type(ShaderType::Scalar(GeomEnums::NT_float64));
+  bool_type = ShaderType::register_type(ShaderType::Scalar(ST_bool));
+  int_type = ShaderType::register_type(ShaderType::Scalar(ST_int));
+  uint_type = ShaderType::register_type(ShaderType::Scalar(ST_uint));
+  float_type = ShaderType::register_type(ShaderType::Scalar(ST_float));
+  double_type = ShaderType::register_type(ShaderType::Scalar(ST_double));
+
+  sampler_type = ShaderType::register_type(ShaderType::Sampler());
+}
+
+/**
+ * Outputs a string description of the ScalarType to the stream.
+ */
+std::ostream &operator << (std::ostream &out, ShaderType::ScalarType scalar_type) {
+  static const char *names[] = {"unknown", "float", "double", "int", "uint", "bool"};
+  const char *name;
+  if ((size_t)scalar_type < sizeof(names) / sizeof(names[0])) {
+    name = names[(size_t)scalar_type];
+  } else {
+    name = "**invalid**";
+  }
+  return out << name;
 }
 
 #ifndef CPPPARSER
+/**
+ * If this is an array, vector or matrix of a scalar type, extracts the
+ * dimensions.
+ */
+bool ShaderType::Scalar::
+as_scalar_type(ScalarType &type, uint32_t &num_elements,
+               uint32_t &num_rows, uint32_t &num_columns) const {
+  type = _scalar_type;
+  num_elements = 1;
+  num_rows = 1;
+  num_columns = 1;
+  return true;
+}
+
 /**
  *
  */
 void ShaderType::Scalar::
 output(std::ostream &out) const {
-  if (this == bool_type) {
-    out << "bool";
-  } else if (this == int_type) {
-    out << "int";
-  } else if (this == uint_type) {
-    out << "uint";
-  } else if (this == float_type) {
-    out << "float";
-  } else {
-    out << "unknown";
-  }
+  out << _scalar_type;
 }
 
 /**
@@ -88,8 +110,22 @@ output(std::ostream &out) const {
 int ShaderType::Scalar::
 compare_to_impl(const ShaderType &other) const {
   const Scalar &other_scalar = (const Scalar &)other;
-  return (_numeric_type > other_scalar._numeric_type)
-       - (_numeric_type < other_scalar._numeric_type);
+  return (_scalar_type > other_scalar._scalar_type)
+       - (_scalar_type < other_scalar._scalar_type);
+}
+
+/**
+ * If this is an array, vector or matrix of a scalar type, extracts the
+ * dimensions.
+ */
+bool ShaderType::Vector::
+as_scalar_type(ScalarType &type, uint32_t &num_elements,
+               uint32_t &num_rows, uint32_t &num_columns) const {
+  type = _scalar_type;
+  num_elements = 1;
+  num_rows = 1;
+  num_columns = _num_elements;
+  return true;
 }
 
 /**
@@ -97,7 +133,7 @@ compare_to_impl(const ShaderType &other) const {
  */
 void ShaderType::Vector::
 output(std::ostream &out) const {
-  out << *_base_type << _num_elements;
+  out << _scalar_type << _num_elements;
 }
 
 /**
@@ -107,19 +143,33 @@ output(std::ostream &out) const {
 int ShaderType::Vector::
 compare_to_impl(const ShaderType &other) const {
   const Vector &other_vector = (const Vector &)other;
-  if (_base_type != other_vector._base_type) {
-    return _base_type < other_vector._base_type ? -1 : 1;
+  if (_scalar_type != other_vector._scalar_type) {
+    return _scalar_type < other_vector._scalar_type ? -1 : 1;
   }
   return (_num_elements > other_vector._num_elements)
        - (_num_elements < other_vector._num_elements);
 }
 
+/**
+ * If this is an array, vector or matrix of a scalar type, extracts the
+ * dimensions.
+ */
+bool ShaderType::Matrix::
+as_scalar_type(ScalarType &type, uint32_t &num_elements,
+               uint32_t &num_rows, uint32_t &num_columns) const {
+  type = _scalar_type;
+  num_elements = 1;
+  num_rows = _num_rows;
+  num_columns = _num_columns;
+  return true;
+}
+
 /**
  *
  */
 void ShaderType::Matrix::
 output(std::ostream &out) const {
-  out << *_base_type << _num_rows << "x" << _num_columns;
+  out << _scalar_type << _num_rows << "x" << _num_columns;
 }
 
 /**
@@ -129,8 +179,8 @@ output(std::ostream &out) const {
 int ShaderType::Matrix::
 compare_to_impl(const ShaderType &other) const {
   const Matrix &other_matrix = (const Matrix &)other;
-  if (_base_type != other_matrix._base_type) {
-    return _base_type < other_matrix._base_type ? -1 : 1;
+  if (_scalar_type != other_matrix._scalar_type) {
+    return _scalar_type < other_matrix._scalar_type ? -1 : 1;
   }
   if (_num_rows != other_matrix._num_rows) {
     return _num_rows < other_matrix._num_rows ? -1 : 1;
@@ -149,7 +199,7 @@ output(std::ostream &out) const {
     if (member.type != nullptr) {
       out << *member.type << ' ';
     }
-    out << *member.name << "; ";
+    out << member.name << "; ";
   }
   out << '}';
 }
@@ -193,6 +243,22 @@ get_num_parameter_locations() const {
   return total;
 }
 
+/**
+ * If this is an array, vector or matrix of a scalar type, extracts the
+ * dimensions.
+ */
+bool ShaderType::Array::
+as_scalar_type(ScalarType &type, uint32_t &num_elements,
+               uint32_t &num_rows, uint32_t &num_columns) const {
+  if (_element_type != nullptr &&
+      _element_type->as_scalar_type(type, num_elements, num_rows, num_columns) &&
+      num_elements == 1) {
+    num_elements = _num_elements;
+    return true;
+  }
+  return false;
+}
+
 /**
  *
  */
@@ -243,6 +309,24 @@ compare_to_impl(const ShaderType &other) const {
        - (_texture_type < other_image._texture_type);
 }
 
+/**
+ *
+ */
+void ShaderType::Sampler::
+output(std::ostream &out) const {
+  out << "sampler";
+}
+
+/**
+ * Private implementation of compare_to, only called for types with the same
+ * TypeHandle.
+ */
+int ShaderType::Sampler::
+compare_to_impl(const ShaderType &other) const {
+  // All samplers are the same type.
+  return true;
+}
+
 /**
  *
  */

+ 86 - 29
panda/src/gobj/shaderType.h

@@ -36,6 +36,15 @@ public:
 
   virtual int get_num_parameter_locations() const { return 1; }
 
+  enum ScalarType {
+    ST_unknown,
+    ST_float,
+    ST_double,
+    ST_int,
+    ST_uint,
+    ST_bool,
+  };
+
 private:
   typedef pset<const ShaderType *, indirect_compare_to<const ShaderType *> > Registry;
   static Registry *_registered_types;
@@ -56,8 +65,14 @@ PUBLISHED:
   static const ShaderType::Scalar *uint_type;
   static const ShaderType::Scalar *float_type;
   static const ShaderType::Scalar *double_type;
+  static const ShaderType::Sampler *sampler_type;
 
 public:
+  virtual bool as_scalar_type(ScalarType &type,
+                              uint32_t &num_elements,
+                              uint32_t &num_rows,
+                              uint32_t &num_columns) const { return false; }
+
   virtual const Scalar *as_scalar() const { return nullptr; }
   virtual const Vector *as_vector() const { return nullptr; }
   virtual const Matrix *as_matrix() const { return nullptr; }
@@ -84,6 +99,8 @@ private:
   static TypeHandle _type_handle;
 };
 
+std::ostream &operator << (std::ostream &out, ShaderType::ScalarType scalar_type);
+
 INLINE std::ostream &operator << (std::ostream &out, const ShaderType &stype) {
   stype.output(out);
   return out;
@@ -93,18 +110,21 @@ INLINE std::ostream &operator << (std::ostream &out, const ShaderType &stype) {
  * A numeric scalar type, like int or float.
  */
 class EXPCL_PANDA_GOBJ ShaderType::Scalar final : public ShaderType {
-private:
-  INLINE Scalar(GeomEnums::NumericType numeric_type);
+public:
+  INLINE Scalar(ScalarType scalar_type);
 
-  INLINE GeomEnums::NumericType get_numeric_type() const;
-
-  virtual void output(std::ostream &out) const override;
-  virtual int compare_to_impl(const ShaderType &other) const override;
+  INLINE ScalarType get_scalar_type() const;
+  virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
+                              uint32_t &num_rows, uint32_t &num_columns) const override;
 
   const Scalar *as_scalar() const override { return this; }
 
+  virtual void output(std::ostream &out) const override;
+
 private:
-  GeomEnums::NumericType _numeric_type;
+  virtual int compare_to_impl(const ShaderType &other) const override;
+
+  const ScalarType _scalar_type;
 
 public:
   static TypeHandle get_class_type() {
@@ -125,21 +145,24 @@ private:
  */
 class EXPCL_PANDA_GOBJ ShaderType::Vector final : public ShaderType {
 public:
-  INLINE Vector(const ShaderType *base_type, size_t num_elements);
+  INLINE Vector(ScalarType scalar_type, uint32_t num_elements);
   Vector(const Vector &copy) = default;
 
-  INLINE const ShaderType *get_base_type() const;
-  INLINE size_t get_num_elements() const;
+  INLINE ScalarType get_scalar_type() const;
+  INLINE uint32_t get_num_elements() const;
 
-  virtual void output(std::ostream &out) const override;
-  virtual int compare_to_impl(const ShaderType &other) const override;
+  virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
+                              uint32_t &num_rows, uint32_t &num_columns) const override;
 
-public:
   const Vector *as_vector() const override { return this; }
 
+  virtual void output(std::ostream &out) const override;
+
 private:
-  const ShaderType *_base_type;
-  size_t _num_elements;
+  virtual int compare_to_impl(const ShaderType &other) const override;
+
+  const ScalarType _scalar_type;
+  const uint32_t _num_elements;
 
 public:
   static TypeHandle get_class_type() {
@@ -160,21 +183,25 @@ private:
  */
 class EXPCL_PANDA_GOBJ ShaderType::Matrix final : public ShaderType {
 public:
-  INLINE Matrix(const ShaderType *base_type, size_t num_rows, size_t num_columns);
+  INLINE Matrix(ScalarType scalar_type, uint32_t num_rows, uint32_t num_columns);
 
-  INLINE const ShaderType *get_base_type() const;
-  INLINE size_t get_num_rows() const;
-  INLINE size_t get_num_columns() const;
+  INLINE ScalarType get_scalar_type() const;
+  INLINE uint32_t get_num_rows() const;
+  INLINE uint32_t get_num_columns() const;
 
-  virtual void output(std::ostream &out) const override;
-  virtual int compare_to_impl(const ShaderType &other) const override;
+  virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
+                              uint32_t &num_rows, uint32_t &num_columns) const override;
 
   const Matrix *as_matrix() const override { return this; }
 
+  virtual void output(std::ostream &out) const override;
+
 private:
-  const ShaderType *_base_type;
-  size_t _num_rows;
-  size_t _num_columns;
+  virtual int compare_to_impl(const ShaderType &other) const override;
+
+  const ScalarType _scalar_type;
+  const uint32_t _num_rows;
+  const uint32_t _num_columns;
 
 public:
   static TypeHandle get_class_type() {
@@ -199,7 +226,7 @@ public:
 
   INLINE size_t get_num_members() const;
   INLINE const Member &get_member(size_t i) const;
-  INLINE void add_member(const ShaderType *type, CPT(InternalName) name);
+  INLINE void add_member(const ShaderType *type, std::string name);
 
   virtual void output(std::ostream &out) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
@@ -213,7 +240,7 @@ PUBLISHED:
 
   struct Member {
     const ShaderType *type;
-    CPT(InternalName) name;
+    std::string name;
   };
 
 private:
@@ -238,10 +265,13 @@ private:
  */
 class EXPCL_PANDA_GOBJ ShaderType::Array final : public ShaderType {
 public:
-  INLINE Array(const ShaderType *element_type, size_t num_elements);
+  INLINE Array(const ShaderType *element_type, uint32_t num_elements);
 
   INLINE const ShaderType *get_element_type() const;
-  INLINE size_t get_num_elements() const;
+  INLINE uint32_t get_num_elements() const;
+
+  virtual bool as_scalar_type(ScalarType &type, uint32_t &num_elements,
+                              uint32_t &num_rows, uint32_t &num_columns) const override;
 
   virtual void output(std::ostream &out) const override;
   virtual int compare_to_impl(const ShaderType &other) const override;
@@ -256,7 +286,7 @@ PUBLISHED:
 
 private:
   const ShaderType *_element_type;
-  size_t _num_elements;
+  uint32_t _num_elements;
 
 public:
   static TypeHandle get_class_type() {
@@ -319,6 +349,33 @@ private:
   friend class ShaderType;
 };
 
+/**
+ * Sampler state.
+ */
+class EXPCL_PANDA_GOBJ ShaderType::Sampler final : public ShaderType {
+private:
+  Sampler() = default;
+
+public:
+  virtual void output(std::ostream &out) const override;
+  virtual int compare_to_impl(const ShaderType &other) const override;
+
+  const Sampler *as_sampler() const override { return this; }
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  virtual TypeHandle get_type() const override {
+    return get_class_type();
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class ShaderType;
+};
+
 /**
  * Sampled image type.
  */

+ 7 - 7
panda/src/pgraph/shaderAttrib.cxx

@@ -355,13 +355,13 @@ get_shader_input_vector(const InternalName *id) const {
       const Shader::ShaderPtrData &ptr = p.get_ptr();
 
       switch (ptr._type) {
-      case Shader::SPT_float:
+      case ShaderType::ST_float:
         {
           LVector4f vectorf;
           memcpy(&vectorf[0], ptr._ptr, sizeof(float) * ptr._size);
           return LCAST(PN_stdfloat, vectorf);
         }
-      case Shader::SPT_double:
+      case ShaderType::ST_double:
         {
           LVector4d vectord;
           memcpy(&vectord[0], ptr._ptr, sizeof(double) * ptr._size);
@@ -442,19 +442,19 @@ get_shader_input_ptr(const InternalName *id, Shader::ShaderPtrData &data) const
         if (param->is_of_type(ParamVecBase4f::get_class_type())) {
           data._ptr = (void *)((const ParamVecBase4f *)param)->get_value().get_data();
           data._size = 4;
-          data._type = Shader::SPT_float;
+          data._type = ShaderType::ST_float;
           return true;
         }
         else if (param->is_of_type(ParamVecBase4i::get_class_type())) {
           data._ptr = (void *)((const ParamVecBase4i *)param)->get_value().get_data();
           data._size = 4;
-          data._type = Shader::SPT_int;
+          data._type = ShaderType::ST_int;
           return true;
         }
         else if (param->is_of_type(ParamVecBase4d::get_class_type())) {
           data._ptr = (void *)((const ParamVecBase4d *)param)->get_value().get_data();
           data._size = 4;
-          data._type = Shader::SPT_float;
+          data._type = ShaderType::ST_float;
           return true;
         }
       }
@@ -538,13 +538,13 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const {
       const Shader::ShaderPtrData &ptr = p.get_ptr();
 
       switch (ptr._type) {
-        case Shader::SPT_float: {
+        case ShaderType::ST_float: {
           LMatrix4f matrixf;
           memcpy(&matrixf(0, 0), ptr._ptr, sizeof(float) * 16);
           matrix = LCAST(PN_stdfloat, matrixf);
           return matrix;
         }
-        case Shader::SPT_double: {
+        case ShaderType::ST_double: {
           LMatrix4d matrixd;
           memcpy(&matrixd(0, 0), ptr._ptr, sizeof(double) * 16);
           matrix = LCAST(PN_stdfloat, matrixd);

+ 2 - 1
panda/src/shaderpipeline/config_shaderpipeline.cxx

@@ -46,6 +46,7 @@ init_libshaderpipeline() {
   }
   initialized = true;
 
+  ShaderCompilerGlslang::init_type();
   ShaderModule::init_type();
   ShaderModuleSpirV::init_type();
   ShaderModuleGlsl::init_type();
@@ -53,5 +54,5 @@ init_libshaderpipeline() {
   ShaderCompilerRegistry *reg = ShaderCompilerRegistry::get_global_ptr();
   reg->register_compiler(new ShaderCompilerGlslang());
   reg->register_compiler(new ShaderCompilerGlslPreProc());
-  reg->register_compiler(new ShaderCompilerCg());
+  //reg->register_compiler(new ShaderCompilerCg());
 }

+ 78 - 8
panda/src/shaderpipeline/shaderCompilerGlslang.cxx

@@ -16,13 +16,13 @@
 #include "config_shaderpipeline.h"
 #include "virtualFile.h"
 
+#ifndef CPPPARSER
 #include <glslang/Public/ShaderLang.h>
 #include <glslang/Include/ResourceLimits.h>
 #include <glslang/SPIRV/GlslangToSpv.h>
 
-#include "dcast.h"
+#include <spirv-tools/optimizer.hpp>
 
-#ifndef CPPPARSER
 const TBuiltInResource resource_limits = {
   /* .MaxLights = */ 32,
   /* .MaxClipPlanes = */ 6,
@@ -116,6 +116,7 @@ const TBuiltInResource resource_limits = {
   /* .maxTaskWorkGroupSizeY_NV = */ 1,
   /* .maxTaskWorkGroupSizeZ_NV = */ 1,
   /* .maxMeshViewCountNV = */ 4,
+  /* .maxDualSourceDrawBuffersEXT = */ 1,
 
   /* .limits = */ {
       /* .nonInductiveForLoops = */ 1,
@@ -209,6 +210,34 @@ public:
 private:
   BamCacheRecord *_record = nullptr;
 };
+
+/**
+ * Message consumer for SPIRV-Tools.
+ */
+static void
+log_message(spv_message_level_t level, const char *, const spv_position_t &, const char *msg) {
+  NotifySeverity severity;
+  switch (level) {
+  case SPV_MSG_FATAL:
+  case SPV_MSG_INTERNAL_ERROR:
+    severity = NS_fatal;
+    break;
+  case SPV_MSG_ERROR:
+    severity = NS_error;
+    break;
+  case SPV_MSG_WARNING:
+    severity = NS_warning;
+    break;
+  case SPV_MSG_INFO:
+    severity = NS_info;
+    break;
+  case SPV_MSG_DEBUG:
+    severity = NS_debug;
+    break;
+  }
+  shader_cat.out(severity) << msg << std::endl;
+}
+
 #endif  // CPPPARSER
 
 TypeHandle ShaderCompilerGlslang::_type_handle;
@@ -234,7 +263,8 @@ get_name() const {
 ShaderLanguages ShaderCompilerGlslang::
 get_languages() const {
   return {
-    Shader::SL_GLSL
+    Shader::SL_GLSL,
+    Shader::SL_Cg,
   };
 }
 
@@ -261,12 +291,39 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
   const int length = (int)code.size();
   const char *fname = filename.c_str();
 
+  EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgDebugInfo);
+
   glslang::TShader *shader = new glslang::TShader((EShLanguage)stage);
   shader->setStringsWithLengthsAndNames(&string, &length, &fname, 1);
-  //shader->setEntryPoint("main");
-  //shader->setSourceEntryPoint("main");
+  shader->setEntryPoint("main");
+
+  // If it's marked as a Cg shader, we compile it with the HLSL front-end.
+  bool is_hlsl = false;
+  if (code.size() >= 5 && strncmp((const char *)&code[0], "//Cg\n", 5) == 0) {
+    shader->setEnvInput(glslang::EShSource::EShSourceHlsl, (EShLanguage)stage, glslang::EShClient::EShClientOpenGL, 120);
+    switch (stage) {
+    case ShaderModule::Stage::vertex:
+      shader->setSourceEntryPoint("vshader");
+      break;
+    case ShaderModule::Stage::geometry:
+      shader->setSourceEntryPoint("gshader");
+      break;
+    case ShaderModule::Stage::fragment:
+      shader->setSourceEntryPoint("fshader");
+      break;
+    }
+
+    shader->setPreamble(
+      "#define f1tex2D(x, y) (tex2D(x, y).r)\n"
+      "#define sampler2DShadow sampler2D\n"
+      "#define shadow2D(s, tc) (float4(tex2D(s, tc) > tc.z))\n"
+      "#define shadow2DProj(s, tc) (float4(tex2Dproj(s, tc) > tc.z / tc.w))\n"
+    );
+    is_hlsl = true;
+    messages = (EShMessages)(messages | EShMsgHlslDX9Compatible | EShMsgHlslLegalization);
+  }
   //shader->setEnvInput(glslang::EShSource::EShSourceGlsl, (EShLanguage)stage, glslang::EShClient::EShClientVulkan, 430);
-  //shader->setEnvClient(glslang::EShClient::EShClientVulkan, glslang::EShTargetVulkan_1_1);
+  shader->setEnvClient(glslang::EShClient::EShClientOpenGL, glslang::EShTargetOpenGL_450);
   shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
 
   // Have the compilers assign bindings to everything--even if we will end up
@@ -280,7 +337,7 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
   shader->setAutoMapLocations(true);
 
   Includer includer(record);
-  if (!shader->parse(&resource_limits, 110, false, (EShMessages)(EShMsgDefault | EShMsgDebugInfo), includer)) {
+  if (!shader->parse(&resource_limits, 110, false, messages, includer)) {
     std::cerr << "failed to parse " << filename << ":\n";
     std::cerr << shader->getInfoLog() << "\n";
     std::cerr << shader->getInfoDebugLog() << "\n";
@@ -310,5 +367,18 @@ compile_now(ShaderModule::Stage stage, std::istream &in,
       glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
   }*/
 
-  return new ShaderModuleSpirV(stage, spirv.data(), spirv.size());
+  spvtools::Optimizer opt(SPV_ENV_UNIVERSAL_1_0);
+  opt.SetMessageConsumer(log_message);
+  opt.RegisterPerformancePasses();
+
+  if (is_hlsl) {
+    opt.RegisterLegalizationPasses();
+  }
+
+  std::vector<uint32_t> optimized;
+  if (!opt.Run(spirv.data(), spirv.size(), &optimized)) {
+    return nullptr;
+  }
+
+  return new ShaderModuleSpirV(stage, optimized.data(), optimized.size());
 }

+ 189 - 0
panda/src/shaderpipeline/shaderModuleSpirV.I

@@ -0,0 +1,189 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file shaderModuleSpirV.I
+ * @author rdb
+ * @date 2020-06-01
+ */
+
+/**
+ * Returns a pointer to the raw words.
+ */
+const uint32_t *ShaderModuleSpirV::
+get_data() const {
+  return _instructions.get_data();
+}
+
+/**
+ * Returns the number of words in the module.
+ */
+size_t ShaderModuleSpirV::
+get_data_size() const {
+  return _instructions.get_data_size();
+}
+
+/**
+ * Iterator dereference operator.
+ */
+INLINE ShaderModuleSpirV::Instruction ShaderModuleSpirV::InstructionIterator::
+operator *() {
+  return Instruction {
+    (SpvOp)(_words[0] & SpvOpCodeMask),
+    (_words[0] >> SpvWordCountShift) - 1,
+    _words + 1,
+  };
+}
+
+/**
+ * Advances to the next instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator &ShaderModuleSpirV::InstructionIterator::
+operator ++() {
+  uint16_t wcount = _words[0] >> SpvWordCountShift;
+  _words += wcount;
+  nassertr(wcount > 0, *this);
+  return *this;
+}
+
+/**
+ * Returns true if these iterators point to the same instruction.
+ */
+INLINE bool ShaderModuleSpirV::InstructionIterator::
+operator ==(const InstructionIterator &other) const {
+  return _words == other._words;
+}
+
+/**
+ * Returns false if these iterators point to the same instruction.
+ */
+INLINE bool ShaderModuleSpirV::InstructionIterator::
+operator !=(const InstructionIterator &other) const {
+  return _words != other._words;
+}
+
+/**
+ * Constructs an iterator from the given word pointer.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator::
+InstructionIterator(uint32_t *words) : _words(words) {
+}
+
+/**
+ * Initializes the instruction stream from an existing module.
+ */
+INLINE ShaderModuleSpirV::InstructionStream::
+InstructionStream(const uint32_t *words, size_t num_words) :
+  _words(words, words + num_words) {
+  // We must have at least a valid header.
+  nassertv(num_words >= 5);
+}
+
+/**
+ * Returns an iterator to the beginning of the instruction stream.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+begin() {
+  return iterator(&_words[5]);
+}
+
+/**
+ * Returns an iterator past the end of the instruction stream.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+end() {
+  return iterator(&_words[0] + _words.size());
+}
+
+/**
+ * Inserts a new instruction before the given other one.  Invalidates existing
+ * iterators, but returns a new one pointing to the location of the inserted
+ * instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+insert(iterator &it, SpvOp opcode, std::initializer_list<uint32_t > args) {
+  return insert(it, opcode, args.begin(), args.size());
+}
+
+/**
+ * Inserts a new instruction before the given other one.  Invalidates existing
+ * iterators, but returns a new one pointing to the location of the inserted
+ * instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+insert(iterator &it, SpvOp opcode, const uint32_t *args, uint16_t nargs) {
+  ptrdiff_t offset = it._words - &_words[0];
+
+  // If this triggers, you used an invalid iterator.
+  assert(offset >= 0 && offset <= _words.size());
+
+  _words.insert(_words.begin() + offset, ((nargs + 1) << SpvWordCountShift) | opcode);
+  _words.insert(_words.begin() + offset + 1, args, args + nargs);
+
+  return iterator(&_words[offset]);
+}
+
+/**
+ * Erases the given instruction.  Invalidates iterators at or after the
+ * insertion point, but returns a new iterator pointing to the next element.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+erase(iterator &it) {
+  ptrdiff_t offset = it._words - &_words[0];
+
+  // If this triggers, you used an invalid iterator.
+  assert(offset >= 0 && offset <= _words.size());
+
+  uint16_t wcount = _words[offset] >> SpvWordCountShift;
+  _words.erase(_words.begin() + offset, _words.begin() + offset + wcount);
+
+  return iterator(&_words[offset]);
+}
+
+/**
+ * Erases the given argument of the given instruction.
+ */
+INLINE ShaderModuleSpirV::InstructionIterator ShaderModuleSpirV::InstructionStream::
+erase_arg(iterator &it, uint16_t arg) {
+  ptrdiff_t offset = it._words - &_words[0];
+
+  // If this triggers, you used an invalid iterator.
+  assert(offset >= 0 && offset <= _words.size());
+
+  uint16_t wcount = _words[offset] >> SpvWordCountShift;
+  nassertr(arg < wcount - 1, it);
+
+  SpvOp op = (SpvOp)(_words[offset] & SpvOpCodeMask);
+  _words[offset] = op | ((wcount - 1) << SpvWordCountShift);
+  _words.erase(_words.begin() + offset + 1 + arg);
+
+  return iterator(&_words[offset]);
+}
+
+/**
+ * Returns a pointer to the raw words of the instruction stream.
+ */
+const uint32_t *ShaderModuleSpirV::InstructionStream::
+get_data() const {
+  return &_words[0];
+}
+
+/**
+ * Returns the number of words in the instruction stream.
+ */
+size_t ShaderModuleSpirV::InstructionStream::
+get_data_size() const {
+  return _words.size();
+}
+
+/**
+ * Allocates a new identifier.
+ */
+INLINE uint32_t ShaderModuleSpirV::InstructionStream::
+allocate_id() {
+  return _words[3]++;
+}

+ 231 - 67
panda/src/shaderpipeline/shaderModuleSpirV.cxx

@@ -29,7 +29,7 @@ TypeHandle ShaderModuleSpirV::_type_handle;
 ShaderModuleSpirV::
 ShaderModuleSpirV(Stage stage, const uint32_t *words, size_t size) :
   ShaderModule(stage),
-  _words(words, words + size)
+  _instructions(words, size)
 {
   Definitions defs;
   if (!parse(defs)) {
@@ -38,10 +38,19 @@ ShaderModuleSpirV(Stage stage, const uint32_t *words, size_t size) :
     return;
   }
 
+  // Check if there is a $Global uniform block.  This is generated by the HLSL
+  // front-end of glslang.  If so, unwrap it back down to individual uniforms.
+  for (uint32_t id = 0; id < defs.size(); ++id) {
+    Definition &def = defs[id];
+    if (def._dtype == DT_type && def._name == "$Global") {
+      unwrap_uniform_block(defs, id);
+    }
+  }
+
   // Add in location decorations for any inputs that are missing it.
   assign_locations(defs);
 
-  // Identify the inputs and outputs.
+  // Identify the inputs, outputs and uniform parameters.
   for (uint32_t id = 0; id < defs.size(); ++id) {
     Definition &def = defs[id];
     if (def._dtype == DT_variable && def._builtin == SpvBuiltInMax) {
@@ -157,16 +166,14 @@ remap_parameter_locations(pmap<int, int> &locations) {
  */
 bool ShaderModuleSpirV::
 parse(Definitions &defs) {
-  const uint32_t *words = (const uint32_t *)_words.data();
-  const size_t length = _words.size();
-  const uint32_t *end = words + length;
-
-  if (length < 5) {
+  if (get_data_size() < 5) {
     shader_cat.error()
       << "Invalid SPIR-V file: too short.\n";
     return false;
   }
 
+  // Validate the header.
+  const uint32_t *words = (const uint32_t *)get_data();
   if (*words++ != SpvMagicNumber) {
     shader_cat.error()
       << "Invalid SPIR-V file: wrong magic number.\n";
@@ -180,15 +187,10 @@ parse(Definitions &defs) {
 
   defs = Definitions(bound);
 
-  while (words < end) {
-    uint16_t wcount = words[0] >> SpvWordCountShift;
-    SpvOp opcode = (SpvOp)(words[0] & SpvOpCodeMask);
-    nassertr(wcount > 0, false);
-
-    if (!parse_instruction(defs, opcode, words + 1, wcount - 1)) {
+  for (Instruction op : _instructions) {
+    if (!parse_instruction(defs, op.opcode, op.args, op.nargs)) {
       return false;
     }
-    words += wcount;
   }
 
   return true;
@@ -247,6 +249,10 @@ parse_instruction(Definitions &defs, SpvOp opcode, const uint32_t *args, size_t
     defs[args[0]].set_type(nullptr);
     break;
 
+  case SpvOpTypeBool:
+    defs[args[0]].set_type(ShaderType::bool_type);
+    break;
+
   case SpvOpTypeInt:
     {
       if (args[2]) {
@@ -265,10 +271,11 @@ parse_instruction(Definitions &defs, SpvOp opcode, const uint32_t *args, size_t
 
   case SpvOpTypeVector:
     {
-      const ShaderType *component_type = defs[args[1]]._type;
+      const ShaderType::Scalar *element_type;
+      DCAST_INTO_R(element_type, defs[args[1]]._type, false);
       uint32_t component_count = args[2];
       defs[args[0]].set_type(ShaderType::register_type(
-        ShaderType::Vector(component_type, component_count)));
+        ShaderType::Vector(element_type->get_scalar_type(), component_count)));
     }
     break;
 
@@ -276,10 +283,9 @@ parse_instruction(Definitions &defs, SpvOp opcode, const uint32_t *args, size_t
     {
       const ShaderType::Vector *column_type;
       DCAST_INTO_R(column_type, defs[args[1]]._type, false);
-      uint32_t column_count = args[2];
-      //TODO: handle asymmetric matrices
+      uint32_t num_rows = args[2];
       defs[args[0]].set_type(ShaderType::register_type(
-        ShaderType::Matrix(column_type->get_base_type(), column_count, column_count)));
+        ShaderType::Matrix(column_type->get_scalar_type(), column_type->get_num_elements(), num_rows)));
     }
     break;
 
@@ -364,7 +370,7 @@ parse_instruction(Definitions &defs, SpvOp opcode, const uint32_t *args, size_t
 
   case SpvOpTypeSampler:
     // A sampler that's not bound to a particular image.
-    //defs[args[0]].set_type(SAT_sampler);
+    defs[args[0]].set_type(ShaderType::sampler_type);
     break;
 
   case SpvOpTypeSampledImage:
@@ -391,7 +397,7 @@ parse_instruction(Definitions &defs, SpvOp opcode, const uint32_t *args, size_t
       for (size_t i = 0; i < nargs - 1; ++i) {
         type.add_member(
           defs[args[i + 1]]._type,
-          InternalName::make(defs[args[0]]._member_names[i])
+          defs[args[0]]._member_names[i]
         );
       }
       defs[args[0]].set_type(ShaderType::register_type(std::move(type)));
@@ -450,7 +456,10 @@ assign_locations(Definitions &defs) {
   for (const Definition &def : defs) {
     if (def._dtype == DT_variable) {
       if (def._location < 0) {
-        if (def._builtin == SpvBuiltInMax) {
+        if (def._builtin == SpvBuiltInMax &&
+            (def._storage_class == SpvStorageClassInput ||
+             def._storage_class == SpvStorageClassOutput ||
+             def._storage_class == SpvStorageClassUniformConstant)) {
           // A non-built-in variable definition without a location.
           has_unassigned_locations = true;
         }
@@ -473,13 +482,11 @@ assign_locations(Definitions &defs) {
 
   // Find the end of the annotation block, so that we know where to insert the
   // new locations.
-  size_t i = 5;
-  for (; i < _words.size();) {
-    uint16_t wcount = _words[i] >> SpvWordCountShift;
-    SpvOp opcode = (SpvOp)(_words[i] & SpvOpCodeMask);
-    nassertv(wcount > 0);
-
-    if (opcode != SpvOpCapability &&
+  InstructionIterator it;
+  for (it = _instructions.begin(); it != _instructions.end(); ++it) {
+    SpvOp opcode = (*it).opcode;
+    if (opcode != SpvOpNop &&
+        opcode != SpvOpCapability &&
         opcode != SpvOpExtension &&
         opcode != SpvOpExtInstImport &&
         opcode != SpvOpMemoryModel &&
@@ -499,8 +506,6 @@ assign_locations(Definitions &defs) {
         opcode != SpvOpDecorationGroup) {
       break;
     }
-
-    i += wcount;
   }
 
   // Now insert decorations for every unassigned variable.
@@ -550,7 +555,7 @@ assign_locations(Definitions &defs) {
           location = uniform_locations.get_next_higher_different_bit(next_bit);
           assert(location >= 0);
         }
-        uniform_locations.set_bit(location);
+        uniform_locations.set_range(location, num_locations);
 
         if (shader_cat.is_debug()) {
           if (num_locations == 1) {
@@ -568,13 +573,9 @@ assign_locations(Definitions &defs) {
       }
 
       def._location = location;
-      _words.insert(_words.begin() + i, {
-        (4 << SpvWordCountShift) | SpvOpDecorate,
-        id,
-        SpvDecorationLocation,
-        (uint32_t)location,
-      });
-      i += 4;
+      it = _instructions.insert(it,
+        SpvOpDecorate, {id, SpvDecorationLocation, (uint32_t)location});
+      ++it;
     }
   }
 }
@@ -587,29 +588,18 @@ assign_locations(Definitions &defs) {
  */
 void ShaderModuleSpirV::
 remap_locations(SpvStorageClass storage_class, const pmap<int, int> &locations) {
-  uint32_t *words = (uint32_t *)_words.data();
-  const size_t length = _words.size();
-  const uint32_t *end = words + length;
-
   pmap<uint32_t, uint32_t *> decorations;
 
-  // Skip header
-  words += 5;
-
-  while (words < end) {
-    uint16_t wcount = words[0] >> SpvWordCountShift;
-    SpvOp opcode = (SpvOp)(words[0] & SpvOpCodeMask);
-    nassertv(wcount > 0);
-
-    if (opcode == SpvOpDecorate) {
+  for (Instruction op : _instructions) {
+    if (op.opcode == SpvOpDecorate) {
       // Store the location of this decoration in the bytecode.
-      if ((SpvDecoration)words[2] == SpvDecorationLocation && wcount >= 4) {
-        decorations[words[1]] = &words[3];
+      if ((SpvDecoration)op.args[1] == SpvDecorationLocation && op.nargs >= 3) {
+        decorations[op.args[0]] = &op.args[2];
       }
     }
-    else if (opcode == SpvOpVariable && (SpvStorageClass)words[3] == storage_class) {
+    else if (op.opcode == SpvOpVariable && (SpvStorageClass)op.args[2] == storage_class) {
       // Found a variable, did we store the location for its decoration?
-      pmap<uint32_t, uint32_t *>::const_iterator it = decorations.find(words[2]);
+      pmap<uint32_t, uint32_t *>::const_iterator it = decorations.find(op.args[1]);
       if (it != decorations.end()) {
         // Yes, do we have a remapping for it?
         pmap<int, int>::const_iterator it2 = locations.find((int)*(it->second));
@@ -619,8 +609,175 @@ remap_locations(SpvStorageClass storage_class, const pmap<int, int> &locations)
         }
       }
     }
+  }
+}
 
-    words += wcount;
+/**
+ * Converts the variables in the uniform block with the given ID to regular
+ * variables.
+ */
+void ShaderModuleSpirV::
+unwrap_uniform_block(Definitions &defs, uint32_t type_id) {
+  const ShaderType::Struct *struct_type;
+  DCAST_INTO_V(struct_type, defs[type_id]._type);
+
+  pset<uint32_t> deleted_ids;
+  pmap<uint32_t, uint32_t> deleted_access_chains;
+
+  pvector<uint32_t> member_ids(struct_type->get_num_members());
+
+  InstructionIterator it = _instructions.begin();
+  while (it != _instructions.end()) {
+    Instruction op = *it;
+
+    switch (op.opcode) {
+    case SpvOpName:
+    case SpvOpMemberName:
+    case SpvOpDecorate:
+    case SpvOpMemberDecorate:
+      // Delete decorations on the struct type.
+      if (op.nargs >= 1 && op.args[0] == type_id) {
+        it = _instructions.erase(it);
+        continue;
+      }
+      break;
+
+    case SpvOpTypeStruct:
+      // Delete the struct definition itself.
+      if (op.nargs >= 1 && op.args[0] == type_id) {
+        it = _instructions.erase(it);
+        continue;
+      }
+      break;
+
+    case SpvOpTypePointer:
+      if (op.nargs >= 3 && op.args[2] == type_id) {
+        // Remember this pointer.
+        deleted_ids.insert(op.args[0]);
+
+        //if ((SpvStorageClass)op.args[1] == SpvStorageClassUniform) {
+        //  // Change storage class to UniformConstant.
+        //  op.args[1] = SpvStorageClassUniformConstant;
+        //  defs[op.args[0]]._storage_class = SpvStorageClassUniformConstant;
+        //}
+
+        it = _instructions.erase(it);
+        continue;
+      }
+      break;
+
+    case SpvOpVariable:
+      if (op.nargs >= 3 && deleted_ids.count(op.args[0])) {
+        // Delete this variable entirely, and replace it instead with individual
+        // variable definitions for all its members.
+        deleted_ids.insert(op.args[1]);
+        it = _instructions.erase(it);
+
+        for (size_t mi = 0; mi < struct_type->get_num_members(); ++mi) {
+          const ShaderType::Struct::Member &member = struct_type->get_member(mi);
+
+          // Find type identifier.
+          uint32_t type_id = 0;
+          for (uint32_t id = 0; id < defs.size(); ++id) {
+            if (defs[id]._type == member.type && defs[id]._dtype == DT_type) {
+              type_id = id;
+            }
+          }
+
+          // Create a type pointer for it.
+          nassertv(type_id > 0);
+
+          // Create an OpTypePointer instruction.
+          uint32_t type_pointer_id = _instructions.allocate_id();
+
+          it = _instructions.insert(it, SpvOpTypePointer, {
+            type_pointer_id,
+            SpvStorageClassUniformConstant,
+            type_id,
+          });
+          ++it;
+
+          defs.push_back(Definition());
+          defs[type_pointer_id].set_type_pointer(SpvStorageClassUniformConstant, member.type);
+
+          // Insert a new variable for this struct member.
+          uint32_t variable_id = _instructions.allocate_id();
+          it = _instructions.insert(it, SpvOpVariable, {
+            type_pointer_id,
+            variable_id,
+            SpvStorageClassUniformConstant,
+          });
+          ++it;
+
+          defs.push_back(Definition());
+          defs[variable_id]._name = member.name;
+          defs[variable_id].set_variable(member.type, SpvStorageClassUniformConstant);
+
+          member_ids[mi] = variable_id;
+        }
+        continue;
+      }
+      break;
+
+    case SpvOpAccessChain:
+    case SpvOpInBoundsAccessChain:
+      if (deleted_ids.count(op.args[2])) {
+        uint32_t index = defs[op.args[3]]._constant;
+        if (op.nargs > 4) {
+          // Just unwrap the first index.
+          op.args[2] = member_ids[index];
+          it = _instructions.erase_arg(it, 3);
+        } else {
+          // Delete the access chain entirely.
+          deleted_access_chains[op.args[1]] = member_ids[index];
+          it = _instructions.erase(it);
+          continue;
+        }
+      }
+      break;
+
+    case SpvOpLoad:
+      // Shouldn't be loading the struct directly.
+      nassertv(!deleted_ids.count(op.args[2]));
+
+      if (deleted_access_chains.count(op.args[2])) {
+        op.args[2] = deleted_access_chains[op.args[2]];
+      }
+      break;
+
+    case SpvOpCopyMemory:
+      // Shouldn't be copying the struct directly.
+      nassertv(!deleted_ids.count(op.args[1]));
+
+      if (deleted_access_chains.count(op.args[1])) {
+        op.args[1] = deleted_access_chains[op.args[1]];
+      }
+      break;
+
+    default:
+      break;
+    }
+
+    ++it;
+  }
+
+  // Go over it again now that we know the deleted IDs, to remove any
+  // decorations on them.
+  if (deleted_ids.empty()) {
+    return;
+  }
+
+  it = _instructions.begin();
+  while (it != _instructions.end()) {
+    Instruction op = *it;
+
+    if ((op.opcode == SpvOpName || op.opcode == SpvOpDecorate || op.opcode == SpvOpMemberName || op.opcode == SpvOpMemberDecorate) &&
+        op.nargs >= 2 && deleted_ids.count(op.args[0])) {
+      _instructions.erase(it);
+      continue;
+    }
+
+    ++it;
   }
 }
 
@@ -629,24 +786,29 @@ remap_locations(SpvStorageClass storage_class, const pmap<int, int> &locations)
  */
 void ShaderModuleSpirV::
 strip() {
-  pvector<uint32_t> old_words;
-  old_words.swap(_words);
+  _instructions = _instructions.strip();
+}
 
-  const uint32_t *words = (const uint32_t *)old_words.data();
-  const size_t length = old_words.size();
+/**
+ * Returns a stripped copy of the instruction stream.
+ */
+ShaderModuleSpirV::InstructionStream ShaderModuleSpirV::InstructionStream::
+strip() const {
+  const uint32_t *words = (const uint32_t *)_words.data();
+  const size_t length = _words.size();
   const uint32_t *end = words + length;
 
-  // Copy header.
-  _words.insert(_words.end(), words, words + 5);
-  words += 5;
+  // Create a new instruction stream, in which we copy the header for now.
+  InstructionStream copy(words, 5);
 
   // Copy all non-debug instructions to the new vector.
   while (words < end) {
     uint16_t wcount = words[0] >> SpvWordCountShift;
     SpvOp opcode = (SpvOp)(words[0] & SpvOpCodeMask);
-    nassertv(wcount > 0);
+    nassertr(wcount > 0, copy);
 
-    if (opcode != SpvOpSourceContinued &&
+    if (opcode != SpvOpNop &&
+        opcode != SpvOpSourceContinued &&
         opcode != SpvOpSource &&
         opcode != SpvOpSourceExtension &&
         opcode != SpvOpName &&
@@ -656,10 +818,12 @@ strip() {
         opcode != SpvOpNoLine &&
         opcode != SpvOpModuleProcessed) {
 
-      _words.insert(_words.end(), words, words + wcount);
+      copy._words.insert(copy._words.end(), words, words + wcount);
     }
     words += wcount;
   }
+
+  return copy;
 }
 
 /**

+ 58 - 7
panda/src/shaderpipeline/shaderModuleSpirV.h

@@ -31,12 +31,8 @@ public:
 
   virtual PT(CopyOnWriteObject) make_cow_copy() override;
 
-  const uint32_t *get_data() const {
-    return &_words[0];
-  }
-  size_t get_data_size() const {
-    return _words.size();
-  }
+  INLINE const uint32_t *get_data() const;
+  INLINE size_t get_data_size() const;
 
   virtual bool link_inputs(const ShaderModule *previous) override;
   virtual void remap_parameter_locations(pmap<int, int> &remap) override;
@@ -44,7 +40,59 @@ public:
   virtual std::string get_ir() const override;
 
 protected:
-  pvector<uint32_t> _words;
+  class InstructionStream;
+
+  struct Instruction {
+    const SpvOp opcode;
+    const uint32_t nargs;
+    uint32_t *args;
+  };
+
+  class InstructionIterator {
+  public:
+    constexpr InstructionIterator() = default;
+
+    INLINE Instruction operator *();
+    INLINE InstructionIterator &operator ++();
+    INLINE bool operator ==(const InstructionIterator &other) const;
+    INLINE bool operator !=(const InstructionIterator &other) const;
+
+  private:
+    INLINE InstructionIterator(uint32_t *words);
+
+    uint32_t *_words = nullptr;
+
+    friend class InstructionStream;
+  };
+
+  /**
+   * A container that allows conveniently iterating over the instructions.
+   */
+  class InstructionStream {
+  public:
+    typedef InstructionIterator iterator;
+
+    INLINE InstructionStream(const uint32_t *words, size_t size);
+
+    InstructionStream strip() const;
+
+    INLINE iterator begin();
+    INLINE iterator end();
+    INLINE iterator insert(iterator &it, SpvOp opcode, std::initializer_list<uint32_t > args);
+    INLINE iterator insert(iterator &it, SpvOp opcode, const uint32_t *args, uint16_t nargs);
+    INLINE iterator erase(iterator &it);
+    INLINE iterator erase_arg(iterator &it, uint16_t arg);
+
+    INLINE const uint32_t *get_data() const;
+    INLINE size_t get_data_size() const;
+
+    INLINE uint32_t allocate_id();
+
+  private:
+    pvector<uint32_t> _words;
+  };
+
+  InstructionStream _instructions;
 
   enum DefinitionType {
     DT_none,
@@ -88,6 +136,7 @@ private:
   void assign_locations(Definitions &defs);
   void remap_locations(SpvStorageClass storage_class, const pmap<int, int> &locations);
 
+  void unwrap_uniform_block(Definitions &defs, uint32_t type_id);
   void strip();
 
 public:
@@ -111,4 +160,6 @@ private:
   static TypeHandle _type_handle;
 };
 
+#include "shaderModuleSpirV.I"
+
 #endif

Some files were not shown because too many files changed in this diff