Reply To: float textures, cpu buffer support

Home Forums Syphon Syphon Development – Developer float textures, cpu buffer support Reply To: float textures, cpu buffer support

#5187
bangnoise
Keymaster

The exact way you do it depends on usage, and how much state you can preserve between calls, but here are the basics.

Setup

// Set-up: usually do this once and re-use these resources, however you may
// have to recreate them if the dimensions change

GLuint tex, fbo, pbo;
GLint prevFBO, prevReadFBO, prevDrawFBO;

// Store previous state
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &prevFBO);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &prevReadFBO);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &prevDrawFBO);

// Push attribs
glPushAttrib(GL_ALL_ATTRIB_BITS);

glEnable(GL_TEXTURE_RECTANGLE_ARB);

// Create the texture we draw into
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);		

// Create the FBO
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

// Test that binding works
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, tex, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
		// Deal with this error - you won't be able to draw into the FBO
}

// Restore state we're done with thus-far
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, prevFBO);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, prevReadFBO);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, prevDrawFBO);

// Save PBO state
GLint prevPBO;
glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &prevPBO);

// Create our PBO and request storage for it
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4, NULL, GL_DYNAMIC_READ);
if (glGetError() != GL_NO_ERROR)
{
		// Storage for the PBO couldn't be allocated, deal with it here
}

// Restore state
glBindBuffer(GL_PIXEL_PACK_BUFFER, prevPBO);
glPopAttrib();

Per-frame

// Save state as above, skipped for brevity
// ...

// The first thing we do is read data from the previous render-cycle
// This means the GPU has had a full frame's time to perform the download to PBO
// Skip this the first frame
if (thisIsNotTheFirstFrame)
{
	glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
	void *pixelData = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
	// Do something with the pixel data
}

// Now start the current frame downloading

// We have a SyphonImage from somewhere, e.g.
SyphonImage *image = [myClient newFrameImageForContext:cgl_ctx];

// Attach the FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, tex, 0);

// Set up required state
glViewport(0, 0,  width, height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

glOrtho(0.0, width,  0.0,  height, -1, 1);		

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

// Clear
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);

// Bind the texture
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, image.textureName);

// Configure texturing as we want it
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glColor4f(1.0, 1.0, 1.0, 1.0);

// Draw it
// These coords flip the texture vertically because often you'll want to do that
GLfloat texCoords[] =
{
	0.0, height,
	width, height,
	width, 0.0,
	0.0, 0.0
};

GLfloat verts[] =
{
	0.0, 0.0,
	width, 0.0,
	width, height,
	0.0, height
};

glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer(2, GL_FLOAT, 0, texCoords );
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, verts);
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );

// Now perform the download into the PBO

glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, tex);

// This is a minimal setup of pixel storage - if anything else might have touched it
// be more explicit
glPixelStorei(GL_PACK_ROW_LENGTH, width);

// Start the download to PBO
glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, (GLvoid *)0);

// Restore state, skipped for brevity, see set-up section
// ...