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

Reply via email to