From e4747ebf5054bed250cf59d1d454babb548dee56 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 15 Jun 2014 12:57:58 +0000 Subject: [PATCH] Extremely experimental support for GL_ARB_shader_image_load_store --- .../glstuff/glGraphicsStateGuardian_src.cxx | 31 +++++++- .../src/glstuff/glGraphicsStateGuardian_src.h | 6 ++ panda/src/glstuff/glShaderContext_src.cxx | 72 ++++++++++++++++++- panda/src/glstuff/glShaderContext_src.h | 2 + 4 files changed, 109 insertions(+), 2 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index aadc09e121..3cd634a977 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/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(); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index bba06db847..b5ce1a61bd 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/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; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index e9da393fd4..47869cd1d4 100755 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/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 diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index cb5d1a0065..cfc1007673 100755 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -77,6 +77,8 @@ private: pvector _glsl_parameter_map; + pvector _glsl_img_inputs; + int _stage_offset; // Avoid using this! It merely exists so the // destructor has access to the extension functions.