diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 55f38f74a..0041c2730 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -180,6 +180,7 @@ IF(DYNAMIC_OPENSCENEGRAPH) ADD_SUBDIRECTORY(osgphotoalbum) ADD_SUBDIRECTORY(osgtessellate) ADD_SUBDIRECTORY(osgtessellationshaders) + ADD_SUBDIRECTORY(osgcomputeshaders) ADD_SUBDIRECTORY(osgpdf) diff --git a/examples/osgcomputeshaders/CMakeLists.txt b/examples/osgcomputeshaders/CMakeLists.txt new file mode 100644 index 000000000..b5456e846 --- /dev/null +++ b/examples/osgcomputeshaders/CMakeLists.txt @@ -0,0 +1,2 @@ +SET(TARGET_SRC osgcomputeshaders.cpp) +SETUP_EXAMPLE(osgcomputeshaders) diff --git a/examples/osgcomputeshaders/osgcomputeshaders.cpp b/examples/osgcomputeshaders/osgcomputeshaders.cpp new file mode 100644 index 000000000..26dfd5671 --- /dev/null +++ b/examples/osgcomputeshaders/osgcomputeshaders.cpp @@ -0,0 +1,92 @@ +/* -*-c++-*- OpenSceneGraph example, osgcomputeshaders. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +// Written by Wang Rui +// This example can work only if GL version is 4.3 or greater + +#include +#include +#include +#include +#include +#include +#include + +static char* computeSrc = { + "#version 430\n" + "uniform float osg_FrameTime;\n" + "uniform image2D targetTex;\n" + "layout (local_size_x = 16, local_size_y = 16) in;\n" + "void main() {\n" + " ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\n" + " float coeffcient = 0.5*sin(float(gl_WorkGroupID.x + gl_WorkGroupID.y)*0.1 + osg_FrameTime);\n" + " coeffcient *= length(vec2(ivec2(gl_LocalInvocationID.xy) - ivec2(8)) / vec2(8.0));\n" + " imageStore(targetTex, storePos, vec4(1.0-coeffcient, 0.0, 0.0, 0.0));\n" + "}\n" +}; + +int main( int argc, char** argv ) +{ + osg::ArgumentParser arguments( &argc, argv ); + + // Create the texture as both the output of compute shader and the input of a normal quad + osg::ref_ptr tex2D = new osg::Texture2D; + tex2D->setTextureSize( 512, 512 ); + tex2D->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR ); + tex2D->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR ); + tex2D->setInternalFormat( GL_R32F ); + tex2D->setSourceFormat( GL_RED ); + tex2D->setSourceType( GL_FLOAT ); + tex2D->bindToImageUnit( 0, osg::Texture::WRITE_ONLY ); // So we can use 'image2D' in the compute shader + + // The compute shader can't work with other kinds of shaders + // It also requires the work group numbers. Setting them to 0 will disable the compute shader + osg::ref_ptr computeProg = new osg::Program; + computeProg->setComputeGroups( 512/16, 512/16, 1 ); + computeProg->addShader( new osg::Shader(osg::Shader::COMPUTE, computeSrc) ); + + // Create a node for outputting to the texture. + // It is OK to have just an empty node here, but seems inbuilt uniforms like osg_FrameTime won't work then. + // TODO: maybe we can have a custom drawable which also will implement glMemoryBarrier? + osg::Node* sourceNode = osgDB::readNodeFile("axes.osgt"); + if ( !sourceNode ) sourceNode = new osg::Node; + sourceNode->setDataVariance( osg::Object::DYNAMIC ); + sourceNode->getOrCreateStateSet()->setAttributeAndModes( computeProg.get() ); + sourceNode->getOrCreateStateSet()->addUniform( new osg::Uniform("targetTex", (int)0) ); + sourceNode->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex2D.get() ); + + // Display the texture on a quad. We will also be able to operate on the data if reading back to CPU side + osg::Geometry* geom = osg::createTexturedQuadGeometry( + osg::Vec3(), osg::Vec3(1.0f,0.0f,0.0f), osg::Vec3(0.0f,0.0f,1.0f) ); + osg::ref_ptr quad = new osg::Geode; + quad->addDrawable( geom ); + quad->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + quad->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex2D.get() ); + + // Create the scene graph and start the viewer + osg::ref_ptr scene = new osg::Group; + scene->addChild( sourceNode ); + scene->addChild( quad.get() ); + + osgViewer::Viewer viewer; + viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); + viewer.addEventHandler( new osgViewer::StatsHandler ); + viewer.addEventHandler( new osgViewer::WindowSizeHandler ); + viewer.setSceneData( scene.get() ); + return viewer.run(); +} diff --git a/include/osg/GL2Extensions b/include/osg/GL2Extensions index 5efbb236c..4e5fa1651 100644 --- a/include/osg/GL2Extensions +++ b/include/osg/GL2Extensions @@ -442,6 +442,28 @@ typedef char GLchar; #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #endif +// ARB_compute_shader +#ifndef GL_ARB_compute_shader +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_LOCAL_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_LOCAL_WORK_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#endif + #ifndef GL_ARB_depth_clamp #define GL_DEPTH_CLAMP 0x864F #endif @@ -689,6 +711,8 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced // ARB_shader_atomic_counters void glGetActiveAtomicCounterBufferiv( GLuint program, GLuint bufferIndex, GLenum pname, GLint* params ) const; + // ARB_compute_shader + void glDispatchCompute( GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ ) const; protected: ~GL2Extensions() {} @@ -855,6 +879,7 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced typedef void (GL_APIENTRY * UniformMatrix3x4dvProc)( GLint location, GLsizei count, GLboolean transpose, const GLdouble* value ); typedef void (GL_APIENTRY * UniformMatrix4x3dvProc)( GLint location, GLsizei count, GLboolean transpose, const GLdouble* value ); typedef void (GL_APIENTRY * GetActiveAtomicCounterBufferivProc)( GLuint program, GLuint bufferIndex, GLenum pname, GLint* params ); + typedef void (GL_APIENTRY * DispatchComputeProc)( GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ ); BlendEquationSeparateProc _glBlendEquationSeparate; DrawBuffersProc _glDrawBuffers; @@ -1020,6 +1045,9 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced // ARB_shader_atomic_counters GetActiveAtomicCounterBufferivProc _glGetActiveAtomicCounterBufferiv; + + // ARB_compute_shader + DispatchComputeProc _glDispatchCompute; }; } diff --git a/include/osg/Program b/include/osg/Program index 00e846643..ad68b2ae5 100644 --- a/include/osg/Program +++ b/include/osg/Program @@ -101,6 +101,10 @@ class OSG_EXPORT Program : public osg::StateAttribute void setParameterfv( GLenum pname, const GLfloat* value ); const GLfloat* getParameterfv( GLenum pname ) const; + + /** Set/get compute shader work groups */ + void setComputeGroups( GLint numGroupsX, GLint numGroupsY, GLint numGroupsZ ); + void getComputeGroups( GLint& numGroupsX, GLint& numGroupsY, GLint& numGroupsZ ) const; /** Add an attribute location binding. */ void addBindAttribLocation( const std::string& name, GLuint index ); @@ -388,6 +392,11 @@ class OSG_EXPORT Program : public osg::StateAttribute // todo add tessellation default level //GLfloat _patchDefaultInnerLevel[2]; //GLfloat _patchDefaultOuterLevel[4]; + + /** Parameter maintained with glDispatchCompute */ + GLint _numGroupsX; + GLint _numGroupsY; + GLint _numGroupsZ; private: Program& operator=(const Program&); // disallowed diff --git a/include/osg/Shader b/include/osg/Shader index bc0db16bb..2aa461643 100644 --- a/include/osg/Shader +++ b/include/osg/Shader @@ -92,6 +92,7 @@ class OSG_EXPORT Shader : public osg::Object TESSEVALUATION = GL_TESS_EVALUATION_SHADER, GEOMETRY = GL_GEOMETRY_SHADER_EXT, FRAGMENT = GL_FRAGMENT_SHADER, + COMPUTE = GL_COMPUTE_SHADER, UNDEFINED = -1 }; diff --git a/include/osg/Texture b/include/osg/Texture index a7a09670d..8dbb18704 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -302,7 +302,6 @@ #define GL_RGBA_INTEGER_MODE_EXT 0x8D9E #endif - #ifndef GL_ARB_texture_rg #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 @@ -328,12 +327,77 @@ #define GL_RG32UI 0x823C #endif +#ifndef GL_ARB_shader_image_load_store + #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 + #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 + #define GL_UNIFORM_BARRIER_BIT 0x00000004 + #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 + #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 + #define GL_COMMAND_BARRIER_BIT 0x00000040 + #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 + #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 + #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 + #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 + #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 + #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 + #define GL_ALL_BARRIER_BITS 0xFFFFFFFF + #define GL_MAX_IMAGE_UNITS 0x8F38 + #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 + #define GL_IMAGE_BINDING_NAME 0x8F3A + #define GL_IMAGE_BINDING_LEVEL 0x8F3B + #define GL_IMAGE_BINDING_LAYERED 0x8F3C + #define GL_IMAGE_BINDING_LAYER 0x8F3D + #define GL_IMAGE_BINDING_ACCESS 0x8F3E + #define GL_IMAGE_1D 0x904C + #define GL_IMAGE_2D 0x904D + #define GL_IMAGE_3D 0x904E + #define GL_IMAGE_2D_RECT 0x904F + #define GL_IMAGE_CUBE 0x9050 + #define GL_IMAGE_BUFFER 0x9051 + #define GL_IMAGE_1D_ARRAY 0x9052 + #define GL_IMAGE_2D_ARRAY 0x9053 + #define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 + #define GL_IMAGE_2D_MULTISAMPLE 0x9055 + #define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 + #define GL_INT_IMAGE_1D 0x9057 + #define GL_INT_IMAGE_2D 0x9058 + #define GL_INT_IMAGE_3D 0x9059 + #define GL_INT_IMAGE_2D_RECT 0x905A + #define GL_INT_IMAGE_CUBE 0x905B + #define GL_INT_IMAGE_BUFFER 0x905C + #define GL_INT_IMAGE_1D_ARRAY 0x905D + #define GL_INT_IMAGE_2D_ARRAY 0x905E + #define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F + #define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 + #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 + #define GL_UNSIGNED_INT_IMAGE_1D 0x9062 + #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 + #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 + #define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 + #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 + #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 + #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 + #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 + #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A + #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B + #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C + #define GL_MAX_IMAGE_SAMPLES 0x906D + #define GL_IMAGE_BINDING_FORMAT 0x906E + #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 + #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 + #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 + #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA + #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB + #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC + #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD + #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE + #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#endif + #ifndef GL_ARB_half_float_pixel #define GL_HALF_FLOAT 0x140B #endif - - namespace osg { @@ -590,6 +654,37 @@ class OSG_EXPORT Texture : public osg::StateAttribute * min filter is used. */ void allocateMipmapLevels(); + /** Encapsulates texture image load/store attributes */ + struct ImageAttachment + { + GLuint unit; + GLint level; + GLboolean layered; + GLint layer; + GLenum access; + GLenum format; + + ImageAttachment() + : unit(0), level(0), layered(GL_FALSE), layer(0), access(0), format(0) {} + }; + + /** Type of access that will be performed on the texture image. */ + enum ImageAccess + { + NOT_USED = 0, + READ_ONLY = GL_READ_ONLY_ARB, + WRITE_ONLY = GL_WRITE_ONLY_ARB, + READ_WRITE = GL_READ_WRITE_ARB + }; + + /** Bind texture to an image unit (available only if GL version is 4.2 or greater) + * The format parameter for the image unit need not exactly match the texture internal format, + * but if it is set to 0, the texture internal format will be used. + * See http://www.opengl.org/registry/specs/ARB/shader_image_load_store.txt */ + void bindToImageUnit(unsigned int unit, GLenum access, GLenum format=0, int level=0, bool layered=false, int layer=0); + + ImageAttachment& getImageAttachment() { return _imageAttachment; } + const ImageAttachment& getImageAttachment() const { return _imageAttachment; } /** Sets GL_TEXTURE_COMPARE_MODE_ARB to GL_COMPARE_R_TO_TEXTURE_ARB * See http://oss.sgi.com/projects/ogl-sample/registry/ARB/shadow.txt. */ @@ -746,6 +841,8 @@ class OSG_EXPORT Texture : public osg::StateAttribute void setTextureIntegerSupported(bool flag) { _isTextureIntegerEXTSupported=flag; } bool isTextureIntegerSupported() const { return _isTextureIntegerEXTSupported; } + bool isBindImageTextureSupported() const { return _glBindImageTexture!=0; } + void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const { _glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); @@ -776,6 +873,12 @@ class OSG_EXPORT Texture : public osg::StateAttribute _glTexParameterIuiv(target, pname, data); } + // ARB_shader_image_load_store + void glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) const + { + _glBindImageTexture(unit, texture, level, layered, layer, access, format); + } + protected: ~Extensions() {} @@ -786,6 +889,7 @@ class OSG_EXPORT Texture : public osg::StateAttribute typedef void (GL_APIENTRY * TexImage2DMultisample)(GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (GL_APIENTRY * TexParameterIivProc)(GLenum target, GLenum pname, const GLint* data); typedef void (GL_APIENTRY * TexParameterIuivProc)(GLenum target, GLenum pname, const GLuint* data); + typedef void (GL_APIENTRY * BindImageTextureProc)( GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format ); CompressedTexImage2DArbProc _glCompressedTexImage2D; CompressedTexSubImage2DArbProc _glCompressedTexSubImage2D; @@ -794,6 +898,8 @@ class OSG_EXPORT Texture : public osg::StateAttribute TexParameterIivProc _glTexParameterIiv; TexParameterIuivProc _glTexParameterIuiv; + // ARB_shader_image_load_store + BindImageTextureProc _glBindImageTexture; bool _isMultiTexturingSupported; bool _isTextureFilterAnisotropicSupported; @@ -938,6 +1044,8 @@ class OSG_EXPORT Texture : public osg::StateAttribute ShadowTextureMode _shadow_texture_mode; float _shadow_ambient; + ImageAttachment _imageAttachment; + public: struct OSG_EXPORT TextureProfile diff --git a/src/osg/GL2Extensions.cpp b/src/osg/GL2Extensions.cpp index a24a80eb3..0143b19ea 100644 --- a/src/osg/GL2Extensions.cpp +++ b/src/osg/GL2Extensions.cpp @@ -214,6 +214,9 @@ GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced() // ARB_shader_atomic_counters _glGetActiveAtomicCounterBufferiv = rhs._glGetActiveAtomicCounterBufferiv; + + // ARB_compute_shader + _glDispatchCompute = rhs._glDispatchCompute; } @@ -399,6 +402,9 @@ void GL2Extensions::lowestCommonDenominator(const GL2Extensions& rhs) // ARB_shader_atomic_counters if(!rhs._glGetActiveAtomicCounterBufferiv) _glGetActiveAtomicCounterBufferiv = 0; + + // ARB_compute_shder + if(!rhs._glDispatchCompute) _glDispatchCompute = 0; } @@ -589,6 +595,9 @@ void GL2Extensions::setupGL2Extensions(unsigned int contextID) // ARB_shader_atomic_counters _glGetActiveAtomicCounterBufferiv= 0; + // ARB_compute_shader + _glDispatchCompute= 0; + return; } @@ -794,6 +803,9 @@ void GL2Extensions::setupGL2Extensions(unsigned int contextID) // ARB_shader_atomic_counters setGLExtensionFuncPtr(_glGetActiveAtomicCounterBufferiv, "glGetActiveAtomicCounterBufferiv" ); + + // ARB_compute_shader + setGLExtensionFuncPtr(_glDispatchCompute, "glDispatchCompute" ); } @@ -2826,6 +2838,18 @@ void GL2Extensions::glGetActiveAtomicCounterBufferiv( GLuint program, GLuint buf } } +void GL2Extensions::glDispatchCompute( GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ ) const +{ + if (_glDispatchCompute) + { + _glDispatchCompute( numGroupsX, numGroupsY, numGroupsZ ); + } + else + { + NotSupported( "glDispatchCompute" ); + } +} + /////////////////////////////////////////////////////////////////////////// // C++-friendly convenience methods diff --git a/src/osg/Program.cpp b/src/osg/Program.cpp index e23498239..612c34ad6 100644 --- a/src/osg/Program.cpp +++ b/src/osg/Program.cpp @@ -137,7 +137,8 @@ void Program::ProgramBinary::assign(unsigned int size, const unsigned char* data Program::Program() : _geometryVerticesOut(1), _geometryInputType(GL_TRIANGLES), _geometryOutputType(GL_TRIANGLE_STRIP), - _patchVertices(3) + _patchVertices(3), + _numGroupsX(0), _numGroupsY(0), _numGroupsZ(0) { } @@ -167,6 +168,10 @@ Program::Program(const Program& rhs, const osg::CopyOp& copyop): _geometryOutputType = rhs._geometryOutputType; _patchVertices = rhs._patchVertices; + + _numGroupsX = rhs._numGroupsX; + _numGroupsY = rhs._numGroupsY; + _numGroupsZ = rhs._numGroupsZ; } @@ -203,6 +208,15 @@ int Program::compare(const osg::StateAttribute& sa) const if( _patchVertices < rhs._patchVertices ) return -1; if( rhs._patchVertices < _patchVertices ) return 1; + + if( _numGroupsX < rhs._numGroupsX ) return -1; + if( rhs._numGroupsX < _numGroupsX ) return 1; + + if( _numGroupsY < rhs._numGroupsY ) return -1; + if( rhs._numGroupsY < _numGroupsY ) return 1; + + if( _numGroupsZ < rhs._numGroupsZ ) return -1; + if( rhs._numGroupsZ < _numGroupsZ ) return 1; ShaderList::const_iterator litr=_shaderList.begin(); ShaderList::const_iterator ritr=rhs._shaderList.begin(); @@ -397,6 +411,19 @@ GLint Program::getParameter( GLenum pname ) const return 0; } +void Program::setComputeGroups( GLint numGroupsX, GLint numGroupsY, GLint numGroupsZ ) +{ + _numGroupsX = numGroupsX; + _numGroupsY = numGroupsY; + _numGroupsZ = numGroupsZ; +} + +void Program::getComputeGroups( GLint& numGroupsX, GLint& numGroupsY, GLint& numGroupsZ ) const +{ + numGroupsX = _numGroupsX; + numGroupsY = _numGroupsY; + numGroupsZ = _numGroupsZ; +} void Program::addBindAttribLocation( const std::string& name, GLuint index ) { @@ -930,4 +957,8 @@ Program::ProgramBinary* Program::PerContextProgram::compileProgramBinary(osg::St void Program::PerContextProgram::useProgram() const { _extensions->glUseProgram( _glProgramHandle ); + if ( _program->_numGroupsX>0 && _program->_numGroupsY>0 && _program->_numGroupsZ>0 ) + { + _extensions->glDispatchCompute( _program->_numGroupsX, _program->_numGroupsY, _program->_numGroupsZ ); + } } diff --git a/src/osg/Shader.cpp b/src/osg/Shader.cpp index f1da48a12..5b5fc8fb8 100644 --- a/src/osg/Shader.cpp +++ b/src/osg/Shader.cpp @@ -330,6 +330,7 @@ const char* Shader::getTypename() const case TESSEVALUATION: return "TESSEVALUATION"; case GEOMETRY: return "GEOMETRY"; case FRAGMENT: return "FRAGMENT"; + case COMPUTE: return "COMPUTE"; default: return "UNDEFINED"; } } @@ -342,6 +343,7 @@ Shader::Type Shader::getTypeId( const std::string& tname ) if( tname == "TESSEVALUATION") return TESSEVALUATION; if( tname == "GEOMETRY" ) return GEOMETRY; if( tname == "FRAGMENT" ) return FRAGMENT; + if( tname == "COMPUTE" ) return COMPUTE; return UNDEFINED; } diff --git a/src/osg/ShaderComposer.cpp b/src/osg/ShaderComposer.cpp index 3389bd2ff..5035da105 100644 --- a/src/osg/ShaderComposer.cpp +++ b/src/osg/ShaderComposer.cpp @@ -52,6 +52,7 @@ osg::Program* ShaderComposer::getOrCreateProgram(const ShaderComponents& shaderC Shaders tessEvaluationShaders; Shaders geometryShaders; Shaders fragmentShaders; + Shaders computeShaders; OSG_NOTICE<<"ShaderComposer::getOrCreateProgram(shaderComponents.size()=="<isBindImageTextureSupported() && _imageAttachment.access!=0) + { + TextureObject* tobj = getTextureObject(contextID); + if (tobj) + { + extensions->glBindImageTexture( + _imageAttachment.unit, tobj->id(), _imageAttachment.level, + _imageAttachment.layered, _imageAttachment.layer, _imageAttachment.access, + _imageAttachment.format!=0 ? _imageAttachment.format : _internalFormat); + } + } + getTextureParameterDirty(state.getContextID()) = false; } @@ -2590,6 +2613,8 @@ Texture::Extensions::Extensions(unsigned int contextID) if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT"); if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT"); + setGLExtensionFuncPtr(_glBindImageTexture, "glBindImageTexture", "glBindImageTextureARB"); + _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f ); } diff --git a/src/osgPlugins/glsl/ReaderWriterGLSL.cpp b/src/osgPlugins/glsl/ReaderWriterGLSL.cpp index d84af38b6..8a34e61a0 100644 --- a/src/osgPlugins/glsl/ReaderWriterGLSL.cpp +++ b/src/osgPlugins/glsl/ReaderWriterGLSL.cpp @@ -23,6 +23,7 @@ class ReaderWriterGLSL : public osgDB::ReaderWriter supportsExtension("glsl","OpenGL Shader Language format"); supportsExtension("tctrl","OpenGL Shader Language format"); supportsExtension("teval","OpenGL Shader Language format"); + supportsExtension("compute","OpenGL Shader Language format"); } virtual const char* className() const { return "GLSL Shader Reader"; } @@ -100,6 +101,7 @@ class ReaderWriterGLSL : public osgDB::ReaderWriter if (options->getOptionString().find("geometry")!=std::string::npos) shader->setType(osg::Shader::GEOMETRY); if (options->getOptionString().find("tesscontrol")!=std::string::npos) shader->setType(osg::Shader::TESSCONTROL); if (options->getOptionString().find("tessevaluation")!=std::string::npos) shader->setType(osg::Shader::TESSEVALUATION); + if (options->getOptionString().find("compute")!=std::string::npos) shader->setType(osg::Shader::COMPUTE); } // return valid shader @@ -129,6 +131,7 @@ class ReaderWriterGLSL : public osgDB::ReaderWriter if (ext == "geom") shader->setType(osg::Shader::GEOMETRY); if (ext == "tctrl") shader->setType(osg::Shader::TESSCONTROL); if (ext == "teval") shader->setType(osg::Shader::TESSEVALUATION); + if (ext == "compute") shader->setType(osg::Shader::COMPUTE); } } return rr; diff --git a/src/osgWrappers/serializers/osg/Program.cpp b/src/osgWrappers/serializers/osg/Program.cpp index 9548512d4..9f0e7d639 100644 --- a/src/osgWrappers/serializers/osg/Program.cpp +++ b/src/osgWrappers/serializers/osg/Program.cpp @@ -77,6 +77,30 @@ static bool writeShaders( osgDB::OutputStream& os, const osg::Program& attr ) return true; } +// _numGroupsX/Y/Z +static bool checkComputeGroups( const osg::Program& attr ) +{ + GLint numX = 0, numY = 0, numZ = 0; + attr.getComputeGroups( numX, numY, numZ ); + return numX>0 && numY>0 && numZ>0; +} + +static bool readComputeGroups( osgDB::InputStream& is, osg::Program& attr ) +{ + GLint numX = 0, numY = 0, numZ = 0; + is >> numX >> numY >> numZ; + attr.setComputeGroups( numX, numY, numZ ); + return true; +} + +static bool writeComputeGroups( osgDB::OutputStream& os, const osg::Program& attr ) +{ + GLint numX = 0, numY = 0, numZ = 0; + attr.getComputeGroups( numX, numY, numZ ); + os << numX << numY << numZ << std::endl; + return true; +} + REGISTER_OBJECT_WRAPPER( Program, new osg::Program, osg::Program, @@ -88,4 +112,8 @@ REGISTER_OBJECT_WRAPPER( Program, ADD_USER_SERIALIZER( GeometryVerticesOut ); // _geometryVerticesOut ADD_USER_SERIALIZER( GeometryInputType ); // _geometryInputType ADD_USER_SERIALIZER( GeometryOutputType ); // _geometryOutputType + { + UPDATE_TO_VERSION_SCOPED( 95 ) + ADD_USER_SERIALIZER( ComputeGroups ); // _numGroupsX/Y/Z + } } diff --git a/src/osgWrappers/serializers/osg/Shader.cpp b/src/osgWrappers/serializers/osg/Shader.cpp index 468f44ae7..026d8261c 100644 --- a/src/osgWrappers/serializers/osg/Shader.cpp +++ b/src/osgWrappers/serializers/osg/Shader.cpp @@ -55,6 +55,7 @@ REGISTER_OBJECT_WRAPPER( Shader, ADD_ENUM_VALUE( TESSEVALUATION ); ADD_ENUM_VALUE( FRAGMENT ); ADD_ENUM_VALUE( GEOMETRY ); + ADD_ENUM_VALUE( COMPUTE ); ADD_ENUM_VALUE( UNDEFINED ); END_ENUM_SERIALIZER(); // _type diff --git a/src/osgWrappers/serializers/osg/Texture.cpp b/src/osgWrappers/serializers/osg/Texture.cpp index 9d15a16f7..bd1b9b9ca 100644 --- a/src/osgWrappers/serializers/osg/Texture.cpp +++ b/src/osgWrappers/serializers/osg/Texture.cpp @@ -70,6 +70,30 @@ static bool writeInternalFormat( osgDB::OutputStream& os, const osg::Texture& te return true; } +// _imageAttachment +static bool checkImageAttachment( const osg::Texture& attr ) +{ + return attr.getImageAttachment().access!=0; +} + +static bool readImageAttachment( osgDB::InputStream& is, osg::Texture& attr ) +{ + osg::Texture::ImageAttachment attachment; + is >> attachment.unit >> attachment.level >> attachment.layered + >> attachment.layer >> attachment.access >> attachment.format; + attr.bindToImageUnit( attachment.unit, attachment.access, attachment.format, + attachment.level, attachment.layered!=GL_FALSE, attachment.layer ); + return true; +} + +static bool writeImageAttachment( osgDB::OutputStream& os, const osg::Texture& attr ) +{ + const osg::Texture::ImageAttachment& attachment = attr.getImageAttachment(); + os << attachment.unit << attachment.level << attachment.layered + << attachment.layer << attachment.access << attachment.format << std::endl; + return true; +} + REGISTER_OBJECT_WRAPPER( Texture, /*new osg::Texture*/NULL, osg::Texture, @@ -127,4 +151,9 @@ REGISTER_OBJECT_WRAPPER( Texture, END_ENUM_SERIALIZER(); // _shadow_texture_mode ADD_FLOAT_SERIALIZER( ShadowAmbient, 0.0f ); // _shadow_ambient + + { + UPDATE_TO_VERSION_SCOPED( 95 ) + ADD_USER_SERIALIZER( ImageAttachment ); // _imageAttachment + } }