问题
How can I draw a series of IOSurfaces to another then draw it to the screen? I've played around with some source from apple in the MultiGPU sample project, but the best I managed to do is draw a white screen or get tons of artifacts and crash the app.
I'm very new to openGL and I don't quite understand the binding of framebuffers and textures and how they interact with IOSurfaces.
This is what I have to create a texture from an IOSurface (directly from Apple's source)
// Create an IOSurface backed texture
// Create an FBO using the name of this texture and bind the texture to the color attachment of the FBO
- (GLuint)setupIOSurfaceTexture:(IOSurfaceRef)ioSurfaceBuffer {
GLuint name;
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA, 512, 512, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
ioSurfaceBuffer, 0);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate an FBO using the same name with the same texture bound to it as a render target.
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, name);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, name, 0);
if(!_depthBufferName) {
glGenRenderbuffersEXT(1, &_depthBufferName);
glRenderbufferStorageEXT(GL_TEXTURE_RECTANGLE_EXT, GL_DEPTH, 512, 512);
}
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_EXT, _depthBufferName);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return name;
}
And I have this piece of code to draw the surface to the screen. (Also from Apple's source)
// Fill the view with the IOSurface backed texture
- (void)textureFromCurrentIOSurface {
NSRect bounds = [self bounds];
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
// Render quad from our iosurface texture
glViewport(0, 0, (GLint)bounds.size.width, (GLint)bounds.size.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLfloat)bounds.size.width, 0.0f, (GLfloat)bounds.size.height, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, [[NSApp delegate] currentTextureName]); // Grab the texture from the delegate
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glTexEnvi(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(512.0f, 0.0f);
glVertex2f((GLfloat)bounds.size.width, 0.0f);
glTexCoord2f(512.0f, 512.0f);
glVertex2f((GLfloat)bounds.size.width, (GLfloat)bounds.size.height);
glTexCoord2f(0.0f, 512.0f);
glVertex2f(0.0f, (GLfloat)bounds.size.height);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE_EXT);
}
With a single IOSurface being draw to the screen this works fine. What am I missing to draw an IOSurface to another?
Assuming I have textures A, B, C, and D I want to:
-Draw A onto C in a specific region,
-Draw B onto C in a different region (may overlap A),
-Draw C to the screen.
回答1:
I solved the issue using the following code, however there are some minor issues with scaling the IOSurface before drawing.
- (void)renderIOSurface:(IOSurfaceRef)surface toBuffer:(GLuint)buffer atPoint:(CGPoint)point withSize:(CGSize)size {
CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
// Bind framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer);
glViewport(0, 0, TEXWIDE, TEXHIGH);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, TEXWIDE, 0.0, TEXHIGH, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLsizei sH = (GLsizei)IOSurfaceGetHeight(surface);
GLsizei sW = (GLsizei)IOSurfaceGetWidth(surface);
// Create texture
GLuint name;
glGenTextures(1, &name);
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA, sW, sH, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
//glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, name);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(point.x, point.y);
glTexCoord2f(sW, 0.0f);
glVertex2f(point.x + size.width, point.y);
glTexCoord2f(sW, sH);
glVertex2f(point.x + size.width, point.y + size.height);
glTexCoord2f(0.0f, sH);
glVertex2f(point.x, point.y + size.height);
glEnd();
//glDisable(GL_TEXTURE_RECTANGLE_EXT);
// Bindback to normal
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Delete the name texture
glDeleteTextures(1, &name);
// [[self openGLContext] flushBuffer];
// This flush is necessary to ensure proper behavior if the MT engine is enabled.
// glFlush();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
}
来源:https://stackoverflow.com/questions/14097015/draw-iosurfaces-to-another-iosurface