mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-14 10:09:32 +01:00
Start moving the framebuffer stuff over to the render manager
This commit is contained in:
1 parent
7e3e652963
commit
062608ad78
7 files changed
+443
-475
No files matched your search
@@ -8,6 +8,12 @@
|
||||
|
||||
#define TEXCACHE_NAME_CACHE_SIZE 16
|
||||
|
||||
// Workaround for Retroarch. Simply declare
|
||||
// extern GLuint g_defaultFBO;
|
||||
// and set is as appropriate. Can adjust the variables in ext/native/base/display.h as
|
||||
// appropriate.
|
||||
GLuint g_defaultFBO = 0;
|
||||
|
||||
void GLQueueRunner::CreateDeviceObjects() {
|
||||
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyLevel_);
|
||||
glGenVertexArrays(1, &globalVAO_);
|
||||
@@ -156,7 +162,7 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps) {
|
||||
}
|
||||
case GLRInitStepType::CREATE_FRAMEBUFFER:
|
||||
{
|
||||
// TODO
|
||||
InitCreateFramebuffer(step);
|
||||
break;
|
||||
}
|
||||
case GLRInitStepType::TEXTURE_SUBDATA:
|
||||
@@ -180,6 +186,114 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps) {
|
||||
}
|
||||
}
|
||||
|
||||
void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) {
|
||||
GLRFramebuffer *fbo = step.create_framebuffer.framebuffer;
|
||||
|
||||
#ifndef USING_GLES2
|
||||
if (!gl_extensions.ARB_framebuffer_object && gl_extensions.EXT_framebuffer_object) {
|
||||
fbo_ext_create(step);
|
||||
} else if (!gl_extensions.ARB_framebuffer_object) {
|
||||
return;
|
||||
}
|
||||
// If GLES2, we have basic FBO support and can just proceed.
|
||||
#endif
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
// 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);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo->width, fbo->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);
|
||||
|
||||
if (gl_extensions.IsGLES) {
|
||||
if (gl_extensions.OES_packed_depth_stencil) {
|
||||
ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8", fbo->width, fbo->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, fbo->width, fbo->height);
|
||||
|
||||
// Bind it all together
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
} else {
|
||||
ILOG("Creating %i x %i FBO using separate stencil", fbo->width, fbo->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);
|
||||
// Don't forget to make sure fbo_standard_z_depth() matches.
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, fbo->width, fbo->height);
|
||||
|
||||
// 8-bit stencil buffer
|
||||
glGenRenderbuffers(1, &fbo->stencil_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fbo->stencil_buffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fbo->width, fbo->height);
|
||||
|
||||
// Bind it all together
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer);
|
||||
glFramebufferRenderbuffer(GL_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, fbo->width, fbo->height);
|
||||
|
||||
// Bind it all together
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->z_stencil_buffer);
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
|
||||
currentDrawHandle_ = fbo->handle;
|
||||
currentReadHandle_ = fbo->handle;
|
||||
}
|
||||
|
||||
void GLQueueRunner::RunSteps(const std::vector<GLRStep *> &steps) {
|
||||
for (int i = 0; i < steps.size(); i++) {
|
||||
const GLRStep &step = *steps[i];
|
||||
@@ -213,6 +327,25 @@ void GLQueueRunner::LogSteps(const std::vector<GLRStep *> &steps) {
|
||||
|
||||
|
||||
void GLQueueRunner::PerformBlit(const GLRStep &step) {
|
||||
/*
|
||||
// Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing
|
||||
// in ES 2.0 that actually separate them anyway of course, so doesn't matter.
|
||||
fbo_bind_fb_target(false, dst->handle);
|
||||
fbo_bind_fb_target(true, src->handle);
|
||||
if (gl_extensions.GLES3 || gl_extensions.ARB_framebuffer_object) {
|
||||
glBlitFramebuffer(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, aspect, linearFilter == FB_BLIT_LINEAR ? GL_LINEAR : GL_NEAREST);
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
#if defined(USING_GLES2) && defined(__ANDROID__) // We only support this extension on Android, it's not even available on PC.
|
||||
return true;
|
||||
} else if (gl_extensions.NV_framebuffer_blit) {
|
||||
glBlitFramebufferNV(srcX1, srcY1, srcX2, srcY2, dstX1, dstY1, dstX2, dstY2, aspect, linearFilter == FB_BLIT_LINEAR ? GL_LINEAR : GL_NEAREST);
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
#endif // defined(USING_GLES2) && defined(__ANDROID__)
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
@@ -236,6 +369,9 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
|
||||
int attrMask = 0;
|
||||
|
||||
// TODO: We can implement state-filtering locally in this function, to mimic the old gl state tracker,
|
||||
// to avoid redundant calls. Might be worth it?
|
||||
|
||||
auto &commands = step.commands;
|
||||
for (const auto &c : commands) {
|
||||
switch (c.cmd) {
|
||||
@@ -445,6 +581,13 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c.textureSampler.anisotropy);
|
||||
}
|
||||
break;
|
||||
case GLRRenderCommand::TEXTURELOD:
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, c.textureLod.minLod);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, c.textureLod.maxLod);
|
||||
#ifndef USING_GLES2
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, c.textureLod.lodBias);
|
||||
#endif
|
||||
break;
|
||||
case GLRRenderCommand::RASTER:
|
||||
if (c.raster.cullEnable) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
@@ -498,13 +641,16 @@ void GLQueueRunner::PerformCopy(const GLRStep &step) {
|
||||
|
||||
switch (step.copy.aspectMask) {
|
||||
case GL_COLOR_BUFFER_BIT:
|
||||
srcTex = src->color.texture;
|
||||
dstTex = dst->color.texture;
|
||||
srcTex = src->color_texture;
|
||||
dstTex = dst->color_texture;
|
||||
break;
|
||||
case GL_DEPTH_BUFFER_BIT:
|
||||
_assert_msg_(G3D, false, "Depth copies not yet supported - soon");
|
||||
target = GL_RENDERBUFFER;
|
||||
/*
|
||||
srcTex = src->depth.texture;
|
||||
dstTex = src->depth.texture;
|
||||
*/
|
||||
break;
|
||||
}
|
||||
#if defined(USING_GLES2)
|
||||
@@ -546,6 +692,59 @@ void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) {
|
||||
curFBWidth_ = targetWidth_;
|
||||
curFBHeight_ = targetHeight_;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
curFB_ = (OpenGLFramebuffer *)fbo;
|
||||
if (fbo) {
|
||||
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
|
||||
// Without FBO_ARB / GLES3, this will collide with bind_for_read, but there's nothing
|
||||
// in ES 2.0 that actually separate them anyway of course, so doesn't matter.
|
||||
fbo_bind_fb_target(false, fb->handle);
|
||||
// Always restore viewport after render target binding. Works around driver bugs.
|
||||
glstate.viewport.restore();
|
||||
} else {
|
||||
fbo_unbind();
|
||||
}
|
||||
int clearFlags = 0;
|
||||
if (rp.color == RPAction::CLEAR) {
|
||||
float fc[4]{};
|
||||
if (rp.clearColor) {
|
||||
Uint8x4ToFloat4(fc, rp.clearColor);
|
||||
}
|
||||
glClearColor(fc[0], fc[1], fc[2], fc[3]);
|
||||
clearFlags |= GL_COLOR_BUFFER_BIT;
|
||||
glstate.colorMask.force(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
}
|
||||
if (rp.depth == RPAction::CLEAR) {
|
||||
#ifdef USING_GLES2
|
||||
glClearDepthf(rp.clearDepth);
|
||||
#else
|
||||
glClearDepth(rp.clearDepth);
|
||||
#endif
|
||||
glClearStencil(rp.clearStencil);
|
||||
clearFlags |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
glstate.depthWrite.force(GL_TRUE);
|
||||
glstate.stencilFunc.force(GL_ALWAYS, 0, 0);
|
||||
glstate.stencilMask.force(0xFF);
|
||||
}
|
||||
if (clearFlags) {
|
||||
glstate.scissorTest.force(false);
|
||||
glClear(clearFlags);
|
||||
glstate.scissorTest.restore();
|
||||
}
|
||||
if (rp.color == RPAction::CLEAR) {
|
||||
glstate.colorMask.restore();
|
||||
}
|
||||
if (rp.depth == RPAction::CLEAR) {
|
||||
glstate.depthWrite.restore();
|
||||
glstate.stencilFunc.restore();
|
||||
glstate.stencilMask.restore();
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void GLQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) {
|
||||
@@ -562,3 +761,157 @@ GLuint GLQueueRunner::AllocTextureName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
// On PC, we always use GL_DEPTH24_STENCIL8.
|
||||
// On Android, we try to use what's available.
|
||||
|
||||
#ifndef USING_GLES2
|
||||
void GLQueueRunner::fbo_ext_create(const GLRInitStep &step) {
|
||||
GLRFramebuffer *fbo = step.create_framebuffer.framebuffer;
|
||||
|
||||
// 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);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo->width, fbo->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);
|
||||
|
||||
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, fbo->width, fbo->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);
|
||||
|
||||
currentDrawHandle_ = fbo->handle;
|
||||
currentReadHandle_ = fbo->handle;
|
||||
}
|
||||
#endif
|
||||
|
||||
GLenum GLQueueRunner::fbo_get_fb_target(bool read, GLuint **cached) {
|
||||
bool supportsBlit = gl_extensions.ARB_framebuffer_object;
|
||||
if (gl_extensions.IsGLES) {
|
||||
supportsBlit = (gl_extensions.GLES3 || gl_extensions.NV_framebuffer_blit);
|
||||
}
|
||||
|
||||
// Note: GL_FRAMEBUFFER_EXT and GL_FRAMEBUFFER have the same value, same with _NV.
|
||||
if (supportsBlit) {
|
||||
if (read) {
|
||||
*cached = ¤tReadHandle_;
|
||||
return GL_READ_FRAMEBUFFER;
|
||||
} else {
|
||||
*cached = ¤tDrawHandle_;
|
||||
return GL_DRAW_FRAMEBUFFER;
|
||||
}
|
||||
} else {
|
||||
*cached = ¤tDrawHandle_;
|
||||
return GL_FRAMEBUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
void GLQueueRunner::fbo_bind_fb_target(bool read, GLuint name) {
|
||||
GLuint *cached;
|
||||
GLenum target = fbo_get_fb_target(read, &cached);
|
||||
if (*cached != name) {
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
|
||||
glBindFramebuffer(target, name);
|
||||
} else {
|
||||
#ifndef USING_GLES2
|
||||
glBindFramebufferEXT(target, name);
|
||||
#endif
|
||||
}
|
||||
*cached = name;
|
||||
}
|
||||
}
|
||||
|
||||
void GLQueueRunner::fbo_unbind() {
|
||||
#ifndef USING_GLES2
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
|
||||
} else if (gl_extensions.EXT_framebuffer_object) {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_defaultFBO);
|
||||
}
|
||||
#else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
|
||||
#endif
|
||||
|
||||
#ifdef IOS
|
||||
bindDefaultFBO();
|
||||
#endif
|
||||
|
||||
currentDrawHandle_ = 0;
|
||||
currentReadHandle_ = 0;
|
||||
}
|
||||
|
||||
GLRFramebuffer::~GLRFramebuffer() {
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) {
|
||||
if (handle) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, handle);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, g_defaultFBO);
|
||||
glDeleteFramebuffers(1, &handle);
|
||||
}
|
||||
if (z_stencil_buffer)
|
||||
glDeleteRenderbuffers(1, &z_stencil_buffer);
|
||||
if (z_buffer)
|
||||
glDeleteRenderbuffers(1, &z_buffer);
|
||||
if (stencil_buffer)
|
||||
glDeleteRenderbuffers(1, &stencil_buffer);
|
||||
} else if (gl_extensions.EXT_framebuffer_object) {
|
||||
#ifndef USING_GLES2
|
||||
if (handle) {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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, g_defaultFBO);
|
||||
glDeleteFramebuffersEXT(1, &handle);
|
||||
}
|
||||
if (z_stencil_buffer)
|
||||
glDeleteRenderbuffers(1, &z_stencil_buffer);
|
||||
if (z_buffer)
|
||||
glDeleteRenderbuffers(1, &z_buffer);
|
||||
if (stencil_buffer)
|
||||
glDeleteRenderbuffers(1, &stencil_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
glDeleteTextures(1, &color_texture);
|
||||
}
|
||||
Reference in new issue
Block a user