Browse Source

Extremely experimental support for GL_ARB_shader_image_load_store

rdb 11 years ago
parent
commit
e4747ebf50

+ 30 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1584,7 +1584,36 @@ reset() {
     GLP(GetFloatv)(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
     _max_anisotropy = (PN_stdfloat)max_anisotropy;
     _supports_anisotropy = true;
-  } 
+  }
+
+  // Check availability of image read/write functionality in shaders.
+  _max_image_units = 0;
+  if (is_at_least_gl_version(4, 2) || has_extension("GL_ARB_shader_image_load_store")) {
+    _glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)
+      get_extension_func(GLPREFIX_QUOTED, "BindImageTexture");
+
+    GLP(GetIntegerv)(GL_MAX_IMAGE_UNITS, &_max_image_units);
+
+  } else if (has_extension("GL_EXT_shader_image_load_store")) {
+    _glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)
+      get_extension_func(GLPREFIX_QUOTED, "BindImageTextureEXT");
+
+    GLP(GetIntegerv)(GL_MAX_IMAGE_UNITS_EXT, &_max_image_units);
+  }
+
+  // Check availability of multi-bind functions.
+  _supports_multi_bind = false;
+  if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_multi_bind")) {
+    _glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)
+      get_extension_func(GLPREFIX_QUOTED, "BindImageTextures");
+
+    if (_glBindImageTextures != NULL) {
+      _supports_multi_bind = true;
+    } else {
+      GLCAT.warning()
+        << "ARB_multi_bind advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
+    }
+  }
 
   report_my_gl_errors();
 

+ 6 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -170,6 +170,8 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size,
 typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
 typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
 #endif  // OPENGLES
 #endif  // __EDG__
 
@@ -522,6 +524,8 @@ protected:
   int _num_active_texture_stages;
   PN_stdfloat _max_anisotropy;
   bool _supports_anisotropy;
+  GLint _max_image_units;
+  bool _supports_multi_bind;
 
 #ifdef OPENGLES
   bool _supports_depth24;
@@ -687,6 +691,8 @@ public:
   PFNGLPATCHPARAMETERIPROC _glPatchParameteri;
   PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced;
   PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
+  PFNGLBINDIMAGETEXTUREPROC _glBindImageTexture;
+  PFNGLBINDIMAGETEXTURESPROC _glBindImageTextures;
 #endif  // OPENGLES
 
   GLenum _edge_clamp;

+ 71 - 1
panda/src/glstuff/glShaderContext_src.cxx

@@ -290,9 +290,11 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
         return;
       }
     }
+    gsg->_glUseProgram(_glsl_program);
+
     // Analyze the uniforms and put them in _glsl_parameter_map
     if (_glsl_parameter_map.size() == 0) {
-      int seqno = 0, texunitno = 0;
+      int seqno = 0, texunitno = 0, imgunitno = 0;
       string noprefix;
       GLint param_count, param_maxlength, param_size;
       GLenum param_type;
@@ -653,6 +655,28 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
               case GL_INT_VEC4:
                 GLCAT.warning() << "Panda does not support passing integers to shaders (yet)!\n";
                 continue;
+#ifndef OPENGLES
+              case GL_IMAGE_1D_EXT:
+              case GL_IMAGE_2D_EXT:
+              case GL_IMAGE_3D_EXT:
+              case GL_IMAGE_CUBE_EXT:
+              case GL_IMAGE_2D_ARRAY_EXT:
+              case GL_INT_IMAGE_1D_EXT:
+              case GL_INT_IMAGE_2D_EXT:
+              case GL_INT_IMAGE_3D_EXT:
+              case GL_INT_IMAGE_CUBE_EXT:
+              case GL_INT_IMAGE_2D_ARRAY_EXT:
+              case GL_UNSIGNED_INT_IMAGE_1D_EXT:
+              case GL_UNSIGNED_INT_IMAGE_2D_EXT:
+              case GL_UNSIGNED_INT_IMAGE_3D_EXT:
+              case GL_UNSIGNED_INT_IMAGE_CUBE_EXT:
+              case GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT:
+                // This won't really change at runtime, so we might as well
+                // bind once and then forget about it.
+                gsg->_glUniform1i(p, imgunitno++);
+                _glsl_img_inputs.push_back(InternalName::make(param_name));
+                continue;
+#endif
               default:
                 GLCAT.warning() << "Ignoring unrecognized GLSL parameter type!\n";
             }
@@ -793,6 +817,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
         s->_var_spec.push_back(bind);
       }
     }
+    gsg->_glUseProgram(0);
   }
 
   gsg->report_my_gl_errors();
@@ -1465,6 +1490,51 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
     }
   }
 
+  // Now bind all the 'image units'; a bit of an esoteric OpenGL feature right now.
+  int num_image_units = min(_glsl_img_inputs.size(), (size_t)gsg->_max_image_units);
+
+  if (num_image_units > 0 && _shader->get_language() == Shader::SL_GLSL) {
+    GLuint *multi_img = NULL;
+    // If we support multi-bind, prepare an array.
+    if (gsg->_supports_multi_bind && num_image_units > 1) {
+      multi_img = new GLuint[num_image_units];
+    }
+
+    for (int i = 0; i < num_image_units; ++i) {
+      const InternalName *name = _glsl_img_inputs[i];
+      Texture *tex = gsg->_target_shader->get_shader_input_texture(name);
+
+      GLuint gl_tex = 0;
+      if (tex != NULL) {
+        int view = gsg->get_current_tex_view_offset();
+
+        CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, gsg->_prepared_objects, gsg));
+        if (gtc != (TextureContext*)NULL) {
+          gl_tex = gtc->_index;
+        }
+      }
+
+      if (multi_img != NULL) {
+        // Put in array so we can multi-bind later.
+        multi_img[i] = gl_tex;
+
+      } else {
+        // We don't support multi-bind, so bind now in the same way that multi-bind would have done it.
+        if (gl_tex == 0) {
+          gsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
+        } else {
+          GLint internal_format = gsg->get_internal_image_format(tex);
+          gsg->_glBindImageTexture(i, gl_tex, 0, GL_TRUE, 0, GL_READ_WRITE, internal_format);
+        }
+      }
+    }
+
+    if (multi_img != NULL) {
+      gsg->_glBindImageTextures(0, num_image_units, multi_img);
+      delete[] multi_img;
+    }
+  }
+
 #if defined(HAVE_CG) && !defined(OPENGLES)
   cg_report_errors();
 #endif

+ 2 - 0
panda/src/glstuff/glShaderContext_src.h

@@ -77,6 +77,8 @@ private:
 
   pvector <GLint> _glsl_parameter_map;
 
+  pvector<CPT(InternalName)> _glsl_img_inputs;
+
   int _stage_offset;
   // Avoid using this! It merely exists so the
   // destructor has access to the extension functions.