From Wang Rui, "In the attached files I've added the Compute Shader support for OSG, as well as serializer updates and a new osgcomputeshaders example. My submission also include a setComputeGroups() function in Program for setting compute-shader work groups, and a bindToImageUnit() function in Texture for binding textures as image variables in shaders.
All code are tested on Windows 7 + NVIDIA GFX 570 with the latest GeForce 310.70 Driver (BETA), which could support OpenGL 4.3. Compute shader information can be found at "http://www.opengl.org/registry/specs/ARB/compute_shader.txt" "
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()=="<<shaderComponents.size()<<std::endl;
|
||||
|
||||
@@ -81,6 +82,9 @@ osg::Program* ShaderComposer::getOrCreateProgram(const ShaderComponents& shaderC
|
||||
case(Shader::FRAGMENT):
|
||||
fragmentShaders.push_back(shader);
|
||||
break;
|
||||
case(Shader::COMPUTE):
|
||||
computeShaders.push_back(shader);
|
||||
break;
|
||||
case(Shader::UNDEFINED):
|
||||
OSG_WARN<<"Warning: ShaderCompose::getOrCreateProgam(ShaderComponts) encounterd invalid Shader::Type."<<std::endl;
|
||||
break;
|
||||
@@ -105,6 +109,11 @@ osg::Program* ShaderComposer::getOrCreateProgram(const ShaderComponents& shaderC
|
||||
addShaderToProgram(program.get(), fragmentShaders);
|
||||
}
|
||||
|
||||
if (!computeShaders.empty())
|
||||
{
|
||||
addShaderToProgram(program.get(), computeShaders);
|
||||
}
|
||||
|
||||
// assign newly created program to map.
|
||||
_programMap[shaderComponents] = program;
|
||||
|
||||
|
||||
@@ -1226,6 +1226,16 @@ void Texture::setMaxAnisotropy(float anis)
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::bindToImageUnit(unsigned int unit, GLenum access, GLenum format, int level, bool layered, int layer)
|
||||
{
|
||||
_imageAttachment.unit = unit;
|
||||
_imageAttachment.level = level;
|
||||
_imageAttachment.layered = layered ? GL_TRUE : GL_FALSE;
|
||||
_imageAttachment.layer = layer;
|
||||
_imageAttachment.access = access;
|
||||
_imageAttachment.format = format;
|
||||
dirtyTextureParameters();
|
||||
}
|
||||
|
||||
/** Force a recompile on next apply() of associated OpenGL texture objects.*/
|
||||
void Texture::dirtyTextureObject()
|
||||
@@ -1741,6 +1751,19 @@ void Texture::applyTexParameters(GLenum target, State& state) const
|
||||
}
|
||||
}
|
||||
|
||||
// Apply image load/store attributes
|
||||
if (extensions->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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user