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->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->getSize()) { my_buff = GLBufferTexturePtr(vms_new GLBufferTexture(GL_RGBA8, 4*w.value*h.value)); lfReportGLerrors(&error); my_buff->initialize(); lfReportGLerrors(&error); } /* * To each pixel, write a color based on pixel rank */ my_buff->bindToImageUnit(SMALL_BUFFER_WRITE_UNIT, GL_WRITE_ONLY); lfReportGLerrors(&error); sits->setSub("pixelRank"); lfReportGLerrors(&error); sits->renderWrapper(fullscreen_quad, ctx, time); lfReportGLerrors(&error); /* * Now show the image */ my_buff->bindToImageUnit(SMALL_BUFFER_READ_UNIT, GL_READ_ONLY); sits->setSub("readPixels"); lfReportGLerrors(&error); sits->renderWrapper(fullscreen_quad, ctx, time); lfReportGLerrors(&error); rend->EndFrame(time); //cap framerate at 100fps boost::this_thread::sleep(boost::posix_time::milliseconds(10)); }