299 lines
10 KiB
C++
299 lines
10 KiB
C++
#include <string.h>
|
|
|
|
#include "base/logging.h"
|
|
#include "gfx/gl_common.h"
|
|
#include "gfx_es2/fbo.h"
|
|
#include "gfx/gl_common.h"
|
|
#include "gfx_es2/gl_state.h"
|
|
|
|
#if defined(USING_GLES2)
|
|
#define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
|
|
#define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
|
|
#define GL_RGBA8 GL_RGBA
|
|
#ifndef GL_DEPTH_COMPONENT24
|
|
#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
|
|
#endif
|
|
#ifndef GL_DEPTH24_STENCIL8_OES
|
|
#define GL_DEPTH24_STENCIL8_OES 0x88F0
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef IOS
|
|
extern void bindDefaultFBO();
|
|
#endif
|
|
|
|
struct FBO {
|
|
GLuint handle;
|
|
GLuint color_texture;
|
|
GLuint z_stencil_buffer; // Either this is set, or the two below.
|
|
GLuint z_buffer;
|
|
GLuint stencil_buffer;
|
|
|
|
int width;
|
|
int height;
|
|
FBOColorDepth colorDepth;
|
|
};
|
|
|
|
|
|
// On PC, we always use GL_DEPTH24_STENCIL8.
|
|
// On Android, we try to use what's available.
|
|
|
|
#ifndef USING_GLES2
|
|
FBO *fbo_ext_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
|
|
FBO *fbo = new FBO();
|
|
fbo->width = width;
|
|
fbo->height = height;
|
|
fbo->colorDepth = colorDepth;
|
|
|
|
// Color texture is same everywhere
|
|
glGenFramebuffersEXT(1, &fbo->handle);
|
|
glGenTextures(1, &fbo->color_texture);
|
|
|
|
// Create the surfaces.
|
|
glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
|
|
switch (colorDepth) {
|
|
case FBO_8888:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
break;
|
|
case FBO_4444:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
|
|
break;
|
|
case FBO_5551:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
|
|
break;
|
|
case FBO_565:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
|
|
break;
|
|
}
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
fbo->stencil_buffer = 0;
|
|
fbo->z_buffer = 0;
|
|
// 24-bit Z, 8-bit stencil
|
|
glGenRenderbuffersEXT(1, &fbo->z_stencil_buffer);
|
|
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
|
|
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, width, height);
|
|
//glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8, width, height);
|
|
|
|
// Bind it all together
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->color_texture, 0);
|
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
|
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->z_stencil_buffer);
|
|
|
|
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
|
switch(status) {
|
|
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
|
// ILOG("Framebuffer verified complete.");
|
|
break;
|
|
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
|
ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
|
|
break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
|
ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
|
|
break;
|
|
default:
|
|
FLOG("Other framebuffer error: %i", status);
|
|
break;
|
|
}
|
|
// Unbind state we don't need
|
|
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
return fbo;
|
|
}
|
|
#endif
|
|
|
|
FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) {
|
|
CheckGLExtensions();
|
|
|
|
#ifndef USING_GLES2
|
|
if(!gl_extensions.FBO_ARB)
|
|
return fbo_ext_create(width, height, num_color_textures, z_stencil, colorDepth);
|
|
#endif
|
|
|
|
FBO *fbo = new FBO();
|
|
fbo->width = width;
|
|
fbo->height = height;
|
|
fbo->colorDepth = colorDepth;
|
|
|
|
// Color texture is same everywhere
|
|
glGenFramebuffers(1, &fbo->handle);
|
|
glGenTextures(1, &fbo->color_texture);
|
|
|
|
// Create the surfaces.
|
|
glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// TODO: We could opt to only create 16-bit render targets on slow devices. For later.
|
|
switch (colorDepth) {
|
|
case FBO_8888:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
break;
|
|
case FBO_4444:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, NULL);
|
|
break;
|
|
case FBO_5551:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
|
|
break;
|
|
case FBO_565:
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
|
|
break;
|
|
}
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
#ifdef USING_GLES2
|
|
if (gl_extensions.OES_packed_depth_stencil) {
|
|
ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", width, height);
|
|
// Standard method
|
|
fbo->stencil_buffer = 0;
|
|
fbo->z_buffer = 0;
|
|
// 24-bit Z, 8-bit stencil combined
|
|
glGenRenderbuffers(1, &fbo->z_stencil_buffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
|
|
|
|
// Bind it all together
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
} else {
|
|
ILOG("Creating %i x %i FBO using separate stencil", width, height);
|
|
// TEGRA
|
|
fbo->z_stencil_buffer = 0;
|
|
// 16/24-bit Z, separate 8-bit stencil
|
|
glGenRenderbuffers(1, &fbo->z_buffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width, height);
|
|
|
|
// 8-bit stencil buffer
|
|
glGenRenderbuffers(1, &fbo->stencil_buffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->stencil_buffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
|
|
|
|
// Bind it all together
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer);
|
|
}
|
|
#else
|
|
fbo->stencil_buffer = 0;
|
|
fbo->z_buffer = 0;
|
|
// 24-bit Z, 8-bit stencil
|
|
glGenRenderbuffers(1, &fbo->z_stencil_buffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
|
|
|
// Bind it all together
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
|
#endif
|
|
|
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
switch(status) {
|
|
case GL_FRAMEBUFFER_COMPLETE:
|
|
// ILOG("Framebuffer verified complete.");
|
|
break;
|
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
|
ELOG("GL_FRAMEBUFFER_UNSUPPORTED");
|
|
break;
|
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
|
ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ");
|
|
break;
|
|
default:
|
|
FLOG("Other framebuffer error: %i", status);
|
|
break;
|
|
}
|
|
// Unbind state we don't need
|
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
return fbo;
|
|
}
|
|
|
|
void fbo_unbind() {
|
|
CheckGLExtensions();
|
|
|
|
if(gl_extensions.FBO_ARB){
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
}else{
|
|
#ifndef USING_GLES2
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
#endif
|
|
}
|
|
#ifdef IOS
|
|
bindDefaultFBO();
|
|
#endif
|
|
}
|
|
|
|
void fbo_bind_as_render_target(FBO *fbo) {
|
|
if(gl_extensions.FBO_ARB){
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
|
|
}else{
|
|
#ifndef USING_GLES2
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void fbo_bind_for_read(FBO *fbo) {
|
|
if(gl_extensions.FBO_ARB){
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle);
|
|
}else{
|
|
#ifndef USING_GLES2
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void fbo_bind_color_as_texture(FBO *fbo, int color) {
|
|
glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
|
|
}
|
|
|
|
void fbo_destroy(FBO *fbo) {
|
|
if(gl_extensions.FBO_ARB){
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
|
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
glDeleteFramebuffers(1, &fbo->handle);
|
|
glDeleteRenderbuffers(1, &fbo->z_stencil_buffer);
|
|
}else{
|
|
#ifndef USING_GLES2
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->handle);
|
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER_EXT, 0);
|
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
glDeleteFramebuffersEXT(1, &fbo->handle);
|
|
glDeleteRenderbuffersEXT(1, &fbo->z_stencil_buffer);
|
|
#endif
|
|
}
|
|
|
|
glDeleteTextures(1, &fbo->color_texture);
|
|
delete fbo;
|
|
}
|
|
|
|
void fbo_get_dimensions(FBO *fbo, int *w, int *h) {
|
|
*w = fbo->width;
|
|
*h = fbo->height;
|
|
}
|