Having trouble with imageBuffers

I’m in the middle of implementing linked-list transparency, and so I wrote a simple test program as a proof of concept for using texture buffers. Unfortunately, I’m having trouble getting it to work properly.

What the code is supposed to do is generate a 2D color gradient and display it on the screen. It does this with two separate shader invocations: in the first invocation, the fragment shader writes a color to the texture buffer that varies with gl_FragCoord.xy; the buffer location written to is gl_FragCoord.x + (gl_FragCoord.y * viewport_width). The second shader invocation merely reads from the same buffer and writes out to the framebuffer.

What I end up seeing instead is a small, horizontal line of pixels at the bottom-left of the screen - only a tiny section at the beginning of the buffer is being properly written (or read?). Through some finagling with the shader code, I found that the line is 64 pixels long. If I try to read the buffer into main memory to inspect it, I end up with a region of memory containing some data that appears more or less random.

I’ve been trying to figure out what’s going wrong for quite a while now, so if anyone has encountered a similar problem before or has further suggestions for debugging, I’d be most grateful.

System specs:
Ubuntu Linux 11.04 64-bit
Radeon HD 5450
Catalyst v12.6

This is the shader I am using. The first invocation writes the pixel rank to a bufferTexture object (w_buffer). That object is then bound to r_buffer, and the second invocation reads from it and draws those pixels to the screen.

#version 420

#include <gtest/SmallImage.h>

layout(binding = SMALL_IMAGE_READ_UNIT, rgba8) readonly uniform image2D r_image;

layout(binding = SMALL_IMAGE_WRITE_UNIT, rgba8) writeonly uniform image2D w_image;

layout(binding = SMALL_BUFFER_READ_UNIT, rgba8) readonly uniform imageBuffer r_buffer;

layout(binding = SMALL_BUFFER_WRITE_UNIT, rgba8) writeonly uniform imageBuffer w_buffer;

subroutine void actual_main(void);
subroutine uniform actual_main exec;

subroutine vec4 imageReader(ivec2 coords);
subroutine uniform imageReader imRd;

subroutine void imageWriter(ivec2 coords, vec4 value);
subroutine uniform imageWriter imWt;

uniform uint viewport_height;
uniform uint viewport_width;

//NOTE: bottom-left pixel is at (0,0)
layout(pixel_center_integer) in vec4 gl_FragCoord;

smooth in vec2 texture_coords;
out vec4 out_color;

/*

  • Subroutines that abstract image acess away from buffer/2d format
    */

//image2d
subroutine(imageReader) vec4 read2D(ivec2 coords)
{
return imageLoad(r_image, coords);
}

subroutine(imageWriter) void write2D(ivec2 coords, vec4 color)
{
imageStore(w_image, coords, color);
}

//buffers
int pixelToBufferCoords(ivec2 coords)
{
return coords.x + (coords.y * int(viewport_width));
}

subroutine(imageReader) vec4 readBuffer(ivec2 coords)
{
return imageLoad(r_buffer, pixelToBufferCoords(coords));
}

subroutine(imageWriter) void writeBuffer(ivec2 coords, vec4 color)
{
imageStore(w_buffer, pixelToBufferCoords(coords), color);
}

/*

  • Subroutines set for test functionality
    */
    subroutine(actual_main) void loadImageOrigin(void)
    {
    vec4 loaded = imRd(ivec2(int(gl_FragCoord.x),
    int(gl_FragCoord.y)));
    out_color = vec4(1.0,0.0,0.0,1.0);/loaded.r,
    loaded.g,
    gl_FragCoord.y/1200.0,
    1);
    /
    }

subroutine(actual_main) void pixelRank(void)
{
vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f);
color.r = gl_FragCoord.x/viewport_width);
color.b = gl_FragCoord.y/viewport_height);
color.g = 1.0f;
imWt(ivec2(int(gl_FragCoord.x),
int(gl_FragCoord.y)),
color);
}

subroutine(actual_main) void readPixels(void)
{
vec4 loaded = imRd(ivec2(int(gl_FragCoord.x),
int(gl_FragCoord.y)));
out_color = vec4(loaded.r,
loaded.g,
loaded.b,
1.0);
}

void main(void)
{
exec();
}

This is my draw-loop. ReportGLErrors is just a macro that records any openGLerrors to disk.

WHILE_YNTEST(handler,nameWriter)
{
float64 time = (float64) timer.GetTime();

  rend-&gt;InitFrame(time);

  /*
   * Refresh the texture if the viewport has changed size
   */
  Height h = getViewportHeight();
  Width w = getViewportWidth();
  if(4*h.value*w.value != my_buff-&gt;getSize())  {
    my_buff = GLBufferTexturePtr(vms_new GLBufferTexture(GL_RGBA8,
                                                         4*w.value*h.value));
    lfReportGLerrors(&error);

    my_buff-&gt;initialize();
    lfReportGLerrors(&error);
  }

  /* 
   * To each pixel, write a color based on pixel rank
   */
  my_buff-&gt;bindToImageUnit(SMALL_BUFFER_WRITE_UNIT, GL_WRITE_ONLY);
  lfReportGLerrors(&error);

  sits-&gt;setSub("pixelRank");
  lfReportGLerrors(&error);
  sits-&gt;renderWrapper(fullscreen_quad, ctx, time);
  lfReportGLerrors(&error);
 
  /* 
   * Now show the image
   */    
  my_buff-&gt;bindToImageUnit(SMALL_BUFFER_READ_UNIT, GL_READ_ONLY);

  sits-&gt;setSub("readPixels");
  lfReportGLerrors(&error);
  sits-&gt;renderWrapper(fullscreen_quad, ctx, time);
  lfReportGLerrors(&error);

  rend-&gt;EndFrame(time);

  //cap framerate at 100fps
  boost::this_thread::sleep(boost::posix_time::milliseconds(10));   
}

just out of curiosity, do u set viewport_width uniform?

Yup. And I know that it’s the correct value, because when I set the imageRead/Write subroutines to use an image2D instead of an imageBuffer, I get a smooth gradient along the X-axis that goes from no red to all red.