Dear all,
Some months ago I wrote a simple extension to support
GL_EXT_shader_image_load_store in the GL3 version of OSG.
What I've done is to provide a new StateAttribute which is called
ImageTextureBinding. This state attribute binds a texture to a shader
"image unit" identified by the number passed in the constructor. The
current interface is rather simple, providing the minimum set of
functions to make it usable.
The implementation does not worry about synchronization issues, being
the user who takes the responsibility of invoking glMemoryBarrier as needed.
In the diff file included I've also added suppport for symbolic names
for texture formats present in GL_ARB_texture_rg.
The example included shows the result of rasterizing 100 overlapping
screen-aligned quads while doing atomic increments of a single channel
integer texture at the raster positions. In my hardware (NVidia), it's
curious to see how the quad is decomposed in 2 triangles that overlap at
the diagonal. The example has a command line option (--early-test) to
show the difference between enabling early z-tests or not in the
fragment shader.
Please, feel free to make any comments or suggestions.
Best regards,
Juan
#include <cassert>
#include <iostream>
#include <osg/GLExtensions>
#include <osg/ImageTextureBinding>
#include <osg/State>
#include <osg/Texture>
using namespace osg;
ImageTextureBinding::ImageTextureBinding()
{}
ImageTextureBinding::~ImageTextureBinding()
{}
ImageTextureBinding::ImageTextureBinding(unsigned int index,
osg::Texture *texture,
Access access, int level,
bool layered, int layer) :
_index(index),
_texture(texture),
_format(_texture->getInternalFormat()),
_level(level),
_layered(layered ? GL_TRUE : GL_FALSE),
_layer(layer),
_access(access)
{
}
ImageTextureBinding::ImageTextureBinding(const ImageTextureBinding &itb,
const osg::CopyOp &op) :
_index(itb._index),
_texture(itb._texture),
_format(_texture->getInternalFormat()),
_level(itb._level),
_layered(itb._layered),
_layer(itb._layer),
_access(itb._access)
{}
int ImageTextureBinding::compare(const osg::StateAttribute& itb) const
{
COMPARE_StateAttribute_Types(ImageTextureBinding, itb)
COMPARE_StateAttribute_Parameter(_index)
COMPARE_StateAttribute_Parameter(_texture)
COMPARE_StateAttribute_Parameter(_format)
COMPARE_StateAttribute_Parameter(_level)
COMPARE_StateAttribute_Parameter(_layered)
COMPARE_StateAttribute_Parameter(_layer)
COMPARE_StateAttribute_Parameter(_access)
return 0;
}
void ImageTextureBinding::apply(osg::State &state) const
{
static void (*glBindImageTexture)(GLuint, GLuint, GLint, GLboolean,
GLint, GLenum, GLint) = 0;
if (glBindImageTexture == 0) {
osg::setGLExtensionFuncPtr(glBindImageTexture, "glBindImageTexture",
"glBindImageTextureEXT");
if (glBindImageTexture == 0) {
std::cerr << "Unsupported extension GL_EXT_shader_image_load_store"
<< std::endl;
abort();
}
}
if (_texture.get() != 0) {
unsigned int contextID = state.getContextID();
_texture->apply(state);
osg::Texture::TextureObject *to =
_texture->getTextureObject(contextID);
assert(to != 0);
glBindImageTexture(_index, to->id(), _level, _layered, _layer,
(GLenum) _access, _format);
if (state.getGlobalDefaultAttribute(getType(), _index)) {
ImageTextureBinding *default_itb = new ImageTextureBinding();
default_itb->_index = _index;
state.setGlobalDefaultAttribute(default_itb);
}
} else {
/* Any format is OK as long as it is a valid enum value. */
glBindImageTexture(_index, 0, 0, GL_FALSE, 0,
GL_READ_ONLY, GL_RGBA32F);
}
}
void ImageTextureBinding::setTexture(osg::Texture *texture)
{
_texture = texture;
_format = texture->getInternalFormat();
}
#ifndef OSG_IMAGETEXTUREBINDING
#define OSG_IMAGETEXTUREBINDING 1
#include <osg/StateAttribute>
namespace osg
{
class Texture;
class OSG_EXPORT ImageTextureBinding : public osg::StateAttribute
{
public:
enum Access {
READ_ONLY = GL_READ_ONLY,
WRITE_ONLY = GL_WRITE_ONLY,
READ_WRITE = GL_READ_WRITE
};
protected:
ImageTextureBinding();
~ImageTextureBinding();
public:
ImageTextureBinding(unsigned int index, osg::Texture *texture,
Access access = READ_WRITE,
int level = 0, bool layered = true, int layer = 0);
ImageTextureBinding(const ImageTextureBinding &itb,
const osg::CopyOp &op = osg::CopyOp::SHALLOW_COPY);
META_StateAttribute(osg, ImageTextureBinding, IMAGETEXTUREBINDING);
public:
// The member value is part of the key to this state attribute in
// the State class. Using the index target, we can seperately
// track the bindings for many different index targets.
virtual unsigned getMember() const
{
return _index;
}
virtual int compare(const osg::StateAttribute& itb) const;
virtual void apply(osg::State &state) const;
void setTexture(osg::Texture *texture);
osg::Texture *getTexture()
{
return _texture.get();
}
const osg::Texture *getTexture() const
{
return _texture.get();
}
void setBindingFormat(GLenum format)
{
_format = format;
}
protected:
unsigned int _index;
osg::ref_ptr<osg::Texture> _texture;
GLenum _format;
int _level;
GLboolean _layered;
int _layer;
Access _access;
};
}
#endif
Only in OpenSceneGraph-3.0.1.new/include/osg: ImageTextureBinding
diff -ru OpenSceneGraph-3.0.1/include/osg/StateAttribute
OpenSceneGraph-3.0.1.new/include/osg/StateAttribute
--- OpenSceneGraph-3.0.1/include/osg/StateAttribute 2010-11-29
18:43:27.000000000 +0100
+++ OpenSceneGraph-3.0.1.new/include/osg/StateAttribute 2011-10-14
12:29:20.000000000 +0200
@@ -187,7 +187,8 @@
OSGNVPARSE_PROGRAM_PARSER,
UNIFORMBUFFERBINDING,
- TRANSFORMFEEDBACKBUFFERBINDING
+ TRANSFORMFEEDBACKBUFFERBINDING,
+ IMAGETEXTUREBINDING
};
/** Simple pairing between an attribute type and the member within
that attribute type group.*/
diff -ru OpenSceneGraph-3.0.1/include/osg/Texture
OpenSceneGraph-3.0.1.new/include/osg/Texture
--- OpenSceneGraph-3.0.1/include/osg/Texture 2011-04-21 19:04:50.000000000
+0200
+++ OpenSceneGraph-3.0.1.new/include/osg/Texture 2011-10-14
12:28:53.000000000 +0200
@@ -302,6 +302,32 @@
#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E
#endif
+// Additioanl texture formats
http://www.opengl.org/registry/specs/ARB/texture_rg.txt
+#ifndef GL_ARB_texture_rg
+ #define GL_RG 0x8227
+ #define GL_RG_INTEGER 0x8228
+ #define GL_R8 0x8229
+ #define GL_R16 0x822A
+ #define GL_RG8 0x822B
+ #define GL_RG16 0x822C
+ #define GL_R16F 0x822D
+ #define GL_R32F 0x822E
+ #define GL_RG16F 0x822F
+ #define GL_RG32F 0x8230
+ #define GL_R8I 0x8231
+ #define GL_R8UI 0x8232
+ #define GL_R16I 0x8233
+ #define GL_R16UI 0x8234
+ #define GL_R32I 0x8235
+ #define GL_R32UI 0x8236
+ #define GL_RG8I 0x8237
+ #define GL_RG8UI 0x8238
+ #define GL_RG16I 0x8239
+ #define GL_RG16UI 0x823A
+ #define GL_RG32I 0x823B
+ #define GL_RG32UI 0x823C
+#endif
+
namespace osg {
diff -ru OpenSceneGraph-3.0.1/src/osg/CMakeLists.txt
OpenSceneGraph-3.0.1.new/src/osg/CMakeLists.txt
--- OpenSceneGraph-3.0.1/src/osg/CMakeLists.txt 2011-06-07 15:02:20.000000000
+0200
+++ OpenSceneGraph-3.0.1.new/src/osg/CMakeLists.txt 2011-10-14
12:27:36.000000000 +0200
@@ -84,6 +84,7 @@
${HEADER_PATH}/Group
${HEADER_PATH}/Hint
${HEADER_PATH}/Image
+ ${HEADER_PATH}/ImageTextureBinding
${HEADER_PATH}/ImageSequence
${HEADER_PATH}/ImageStream
${HEADER_PATH}/ImageUtils
@@ -260,6 +261,7 @@
Group.cpp
Hint.cpp
Image.cpp
+ ImageTextureBinding.cpp
ImageSequence.cpp
ImageStream.cpp
ImageUtils.cpp
Only in OpenSceneGraph-3.0.1.new/src/osg: ImageTextureBinding.cpp
diff -ru OpenSceneGraph-3.0.1/src/osg/Texture.cpp
OpenSceneGraph-3.0.1.new/src/osg/Texture.cpp
--- OpenSceneGraph-3.0.1/src/osg/Texture.cpp 2011-07-28 13:05:35.000000000
+0200
+++ OpenSceneGraph-3.0.1.new/src/osg/Texture.cpp 2011-10-14
13:04:57.000000000 +0200
@@ -1463,6 +1463,14 @@
case GL_RGB16UI_EXT:
case GL_RGB8UI_EXT:
+ case GL_RG32UI:
+ case GL_RG16UI:
+ case GL_RG8UI:
+
+ case GL_R32UI:
+ case GL_R16UI:
+ case GL_R8UI:
+
case GL_LUMINANCE32UI_EXT:
case GL_LUMINANCE16UI_EXT:
case GL_LUMINANCE8UI_EXT:
@@ -1485,6 +1493,14 @@
case GL_RGB16I_EXT:
case GL_RGB8I_EXT:
+ case GL_RG32I:
+ case GL_RG16I:
+ case GL_RG8I:
+
+ case GL_R32I:
+ case GL_R16I:
+ case GL_R8I:
+
case GL_LUMINANCE32I_EXT:
case GL_LUMINANCE16I_EXT:
case GL_LUMINANCE8I_EXT:
@@ -1505,6 +1521,12 @@
case GL_RGB32F_ARB:
case GL_RGB16F_ARB:
+ case GL_RG32F:
+ case GL_RG16F:
+
+ case GL_R32F:
+ case GL_R16F:
+
case GL_LUMINANCE32F_ARB:
case GL_LUMINANCE16F_ARB:
#include <assert.h>
#include <iostream>
#define GL_GLEXT_PROTOTYPES
#include <osg/GL>
#include <GL/glext.h>
#include <osg/ArgumentParser>
#include <osg/Geode>
#include <osg/ImageTextureBinding>
#include <osg/TextureRectangle>
#include <osgViewer/Viewer>
// This callback initializes an 1-channel integer texture with 0's
class SubloadCallback : public osg::TextureRectangle::SubloadCallback
{
public:
virtual void load(const osg::TextureRectangle &t, osg::State &s) const
{
size_t height = t.getTextureHeight();
size_t width = t.getTextureWidth();
std::vector<unsigned int> data(height * width * 4, 0);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, t.getInternalFormat(),
width, height, 0, GL_RGBA_INTEGER,
GL_UNSIGNED_INT, &data[0]);
}
virtual void subload(const osg::TextureRectangle &t, osg::State &s) const
{}
};
class DrawCallback : public osg::Drawable::DrawCallback
{
public:
void drawImplementation(osg::RenderInfo &renderInfo,
const osg::Drawable *drawable) const
{
drawable->drawImplementation(renderInfo);
// Wait until all writes are finished
glMemoryBarrierEXT(GL_ALL_BARRIER_BITS_EXT);
}
};
void readPixels(osg::State &state, osg::TextureRectangle *texture)
{
GLint previous;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &previous);
// Texture readback. This is not the most orthodox way, but it is compact
osg::ref_ptr<osg::FrameBufferObject> fbo = new osg::FrameBufferObject();
osg::FrameBufferAttachment buffer(texture);
fbo->setAttachment(osg::Camera::COLOR_BUFFER0, buffer);
fbo->apply(state);
osg::ref_ptr<osg::Image> image = new osg::Image();
image->readPixels(
0, 0, texture->getTextureWidth(), texture->getTextureHeight(),
GL_RED_INTEGER, GL_UNSIGNED_INT);
// Printing the 16x16 values of the texture
unsigned int *data = (unsigned int*)image->data();
for (int i = 0; i < 16; ++i) {
for (int j = 0; j < 16; ++j) {
std::cout << data[i * 16 + j] << ' ';
}
std::cout << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, previous);
}
int main(int argc, char *argv[])
{
osg::ArgumentParser args(&argc, argv);
osgViewer::Viewer viewer(args);
// Creating the geometry object with the quads
osg::Geometry *geometry = new osg::Geometry();
osg::Vec3Array *vertices = new osg::Vec3Array();
vertices->push_back(osg::Vec3(-1, -1, 0));
vertices->push_back(osg::Vec3(1, -1, 0));
vertices->push_back(osg::Vec3(1, 1, 0));
vertices->push_back(osg::Vec3(-1, 1, 0));
osg::DrawElementsUInt *indices =
new osg::DrawElementsUInt(GL_QUADS);
for (int i = 0; i < 100; ++i) {
indices->push_back(0);
indices->push_back(1);
indices->push_back(2);
indices->push_back(3);
}
geometry->setVertexArray(vertices);
geometry->addPrimitiveSet(indices);
osg::Geode *scene = new osg::Geode();
scene->addDrawable(geometry);
// Vertex and fragment shaders
osg::StateSet *stateSet = scene->getOrCreateStateSet();
osg::Program *program = new osg::Program();
osg::Shader *vert = new osg::Shader(osg::Shader::VERTEX);
vert->setShaderSource(
"#version 410\n"
"in vec3 osg_Vertex;"
"void main()"
"{"
" gl_Position = vec4(osg_Vertex, 1);"
"}");
osg::Shader *frag = new osg::Shader(osg::Shader::FRAGMENT);
std::string source =
"#version 410\n"
"#extension GL_ARB_shader_bit_encoding : enable\n"
"#extension GL_EXT_shader_image_load_store : enable\n"
"#extension GL_EXT_gpu_shader4 : enable\n"
"#extension GL_ARB_texture_rectangle : enable\n"
"out vec4 color;";
// Adding the layout declaration if early tests (z, alpha, ...) are
// enabled.
if (args.read("--early-tests"))
source +=
"layout(early_fragment_tests) in;";
source +=
"layout(size1x32) uniform uimage2DRect buffer;"
"void main()"
"{"
" imageAtomicAdd(buffer, ivec2(gl_FragCoord.xy), 1);"
" color = vec4(2);"
"}";
frag->setShaderSource(source);
program->addShader(vert);
program->addShader(frag);
stateSet->setAttributeAndModes(program);
int window_size = 16;
viewer.setUpViewInWindow(0, 0, window_size, window_size);
viewer.setSceneData(scene);
// Creating the target texture
osg::TextureRectangle *buffer;
buffer = new osg::TextureRectangle();
buffer->setTextureSize(window_size, window_size);
buffer->setInternalFormat(GL_R32UI);
buffer->setSourceFormat(GL_RED_INTEGER);
buffer->setSubloadCallback(new SubloadCallback());
osg::ImageTextureBinding *binding =
new osg::ImageTextureBinding(0, buffer,
osg::ImageTextureBinding::WRITE_ONLY);
geometry->getOrCreateStateSet()->setAttributeAndModes(binding);
geometry->getOrCreateStateSet()->setTextureAttribute(0, buffer);
// The draw callback is reponsible of calling glMemoryBarrierEXT
geometry->setDrawCallback(new DrawCallback());
viewer.realize();
// We use single threaded made to make sure that the no other thread is
// using GL after viewer.frame() returns.
viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
// Rendering a single frame
viewer.frame();
// Reading back the texture and printing the contents
osgViewer::ViewerBase::Contexts contexts;
viewer.getContexts(contexts);
contexts.front()->makeCurrent();
readPixels(*contexts.front()->getState(), buffer);
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org