ppsspp/gfx_es2/fbo.cpp

181 lines
6.0 KiB
C++

#include <string.h>
#include "base/logging.h"
#include "gfx_es2/fbo.h"
#include "gfx/gl_common.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
#endif
// TODO: Breakout this GL extension checker in its own file.
struct GLExtensions {
bool OES_depth24;
bool OES_packed_depth_stencil;
bool OES_depth_texture;
};
GLExtensions gl_extensions;
void CheckExtensions() {
static bool done = false;
if (done)
return;
done = true;
memset(&gl_extensions, 0, sizeof(gl_extensions));
const char *extString = (const char *)glGetString(GL_EXTENSIONS);
gl_extensions.OES_packed_depth_stencil = strstr(extString, "GL_OES_packed_depth_stencil");
gl_extensions.OES_depth24 = strstr(extString, "GL_OES_depth24");
gl_extensions.OES_depth_texture = strstr(extString, "GL_OES_depth_texture");
}
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;
};
// On PC, we always use GL_DEPTH24_STENCIL8.
// On Android, we try to use what's available.
FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil) {
CheckExtensions();
FBO *fbo = new FBO();
fbo->width = width;
fbo->height = height;
// 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.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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 FBO using DEPTH24_STENCIL8");
// 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 FBO using separate stencil");
// TEGRA
fbo->z_stencil_buffer = 0;
// 16-bit Z, separate 8-bit stencil
glGenRenderbuffers(1, &fbo->z_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, 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() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void fbo_bind_as_render_target(FBO *fbo) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo->handle);
}
void fbo_bind_for_read(FBO *fbo) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle);
}
void fbo_bind_color_as_texture(FBO *fbo, int color) {
glBindTexture(GL_TEXTURE_2D, fbo->color_texture);
}
void fbo_destroy(FBO *fbo) {
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);
glDeleteTextures(1, &fbo->color_texture);
glDeleteRenderbuffers(1, &fbo->z_stencil_buffer);
}