diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b236c69e44d..6e65121389c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1221,6 +1221,7 @@ endif() set(GPU_GLES GPU/GLES/DepalettizeShaderGLES.cpp GPU/GLES/DepalettizeShaderGLES.h + GPU/GLES/DepthBufferGLES.cpp GPU/GLES/GPU_GLES.cpp GPU/GLES/GPU_GLES.h GPU/GLES/FragmentShaderGeneratorGLES.cpp diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp new file mode 100644 index 000000000000..3f9c6cde18ce --- /dev/null +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -0,0 +1,198 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include "gfx_es2/gpu_features.h" +#include "Core/ConfigValues.h" +#include "Core/Reporting.h" +#include "GPU/Common/GPUStateUtils.h" +#include "GPU/GLES/DrawEngineGLES.h" +#include "GPU/GLES/FramebufferManagerGLES.h" +#include "GPU/GLES/ShaderManagerGLES.h" +#include "GPU/GLES/TextureCacheGLES.h" + +static const char *depth_dl_fs = R"( +#ifdef GL_ES +#if GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#endif +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +varying vec2 v_texcoord0; +uniform vec2 u_depthFactor; +uniform vec4 u_depthShift; +uniform vec4 u_depthTo8; +uniform sampler2D tex; +void main() { + float depth = texture2D(tex, v_texcoord0).r; + // At this point, clamped maps [0, 1] to [0, 65535]. + float clamped = clamp((depth + u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0); + + vec4 enc = u_depthShift * clamped; + enc = floor(mod(enc, 256.0)) * u_depthTo8; + enc = enc * u_depthTo8; + // Let's ignore the bits outside 16 bit precision. + gl_FragColor = enc.yzww; +} +)"; + +static const char *depth_vs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec4 a_position; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_texcoord0; + gl_Position = a_position; +} +)"; + +void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { + if (!vfb->fbo) { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); + return; + } + + // Pixel size always 4 here because we always request float + const u32 bufSize = vfb->z_stride * (h - y) * 4; + const u32 z_address = vfb->z_address; + const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width)); + + if (!convBuf_ || convBufSize_ < bufSize) { + delete[] convBuf_; + convBuf_ = new u8[bufSize]; + convBufSize_ = bufSize; + } + + DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + // TODO: On desktop, we can just directly download, but for now testing. + const bool useColorPath = true; // gl_extensions.IsGLES; + bool format16Bit = false; + + if (useColorPath) { + if (!depthDownloadProgram_) { + std::string errorString; + static std::string vs_code, fs_code; + vs_code = ApplyGLSLPrelude(depth_vs, GL_VERTEX_SHADER); + fs_code = ApplyGLSLPrelude(depth_dl_fs, GL_FRAGMENT_SHADER); + std::vector shaders; + shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vs_code, "depth_dl")); + shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fs_code, "depth_dl")); + std::vector semantics; + semantics.push_back({ 0, "a_position" }); + semantics.push_back({ 1, "a_texcoord0" }); + std::vector queries; + queries.push_back({ &u_depthDownloadTex, "tex" }); + queries.push_back({ &u_depthDownloadFactor, "u_depthFactor" }); + queries.push_back({ &u_depthDownloadShift, "u_depthShift" }); + queries.push_back({ &u_depthDownloadTo8, "u_depthTo8" }); + std::vector inits; + inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE }); + depthDownloadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false); + for (auto iter : shaders) { + render_->DeleteShader(iter); + } + if (!depthDownloadProgram_) { + ERROR_LOG_REPORT(G3D, "Failed to compile depthDownloadProgram! This shouldn't happen.\n%s", errorString.c_str()); + } + } + + shaderManagerGL_->DirtyLastShader(); + auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight, Draw::FBO_8888); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); + render_->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); + textureCacheGL_->ForgetLastTexture(); + + // We must bind the program after starting the render pass, and set the color mask after clearing. + render_->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight }); + render_->SetDepth(false, false, GL_ALWAYS); + render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE); + render_->BindProgram(depthDownloadProgram_); + + if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + float factors[] = { 0.0f, 1.0f }; + render_->SetUniformF(&u_depthDownloadFactor, 2, factors); + } else { + const float factor = DepthSliceFactor(); + float factors[] = { -0.5f * (factor - 1.0f) * (1.0f / factor), factor }; + render_->SetUniformF(&u_depthDownloadFactor, 2, factors); + } + float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f }; + render_->SetUniformF(&u_depthDownloadShift, 4, shifts); + float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; + render_->SetUniformF(&u_depthDownloadTo8, 4, to8); + + draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); + float u1 = 1.0f; + float v1 = 1.0f; + DrawActiveTexture(x, y, w, h, vfb->renderWidth, vfb->renderHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); + + draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride); + // TODO: Use 4444 so we can copy lines directly? + format16Bit = true; + } else { + draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); + format16Bit = false; + } + + int dstByteOffset = y * vfb->z_stride * sizeof(u16); + u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); + u32_le *packed32 = (u32_le *)convBuf_; + GLfloat *packedf = (GLfloat *)convBuf_; + + int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; + if (format16Bit) { + for (int yp = 0; yp < h; ++yp) { + int row_offset = vfb->z_stride * yp; + for (int xp = 0; xp < packWidth; ++xp) { + const int i = row_offset + xp; + depth[i] = packed32[i] & 0xFFFF; + } + } + } else { + for (int yp = 0; yp < h; ++yp) { + int row_offset = vfb->z_stride * yp; + for (int xp = 0; xp < packWidth; ++xp) { + const int i = row_offset + xp; + float scaled = FromScaledDepth(packedf[i]); + if (scaled <= 0.0f) { + depth[i] = 0; + } else if (scaled >= 65535.0f) { + depth[i] = 65535; + } else { + depth[i] = (int)scaled; + } + } + } + } + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); +} diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 46f69b60505d..57c92fe7f92f 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -326,6 +326,10 @@ void FramebufferManagerGLES::DestroyDeviceObjects() { render_->DeleteProgram(stencilUploadProgram_); stencilUploadProgram_ = nullptr; } + if (depthDownloadProgram_) { + render_->DeleteProgram(depthDownloadProgram_); + depthDownloadProgram_ = nullptr; + } } FramebufferManagerGLES::~FramebufferManagerGLES() { @@ -652,48 +656,6 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); } -void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { - if (!vfb->fbo) { - ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); - return; - } - - // Pixel size always 4 here because we always request float - const u32 bufSize = vfb->z_stride * (h - y) * 4; - const u32 z_address = (0x04000000) | vfb->z_address; - const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width)); - - if (!convBuf_ || convBufSize_ < bufSize) { - delete [] convBuf_; - convBuf_ = new u8[bufSize]; - convBufSize_ = bufSize; - } - - DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); - - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride); - - int dstByteOffset = y * vfb->z_stride * sizeof(u16); - u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); - GLfloat *packed = (GLfloat *)convBuf_; - - int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; - for (int yp = 0; yp < h; ++yp) { - int row_offset = vfb->z_stride * yp; - for (int xp = 0; xp < packWidth; ++xp) { - const int i = row_offset + xp; - float scaled = FromScaledDepth(packed[i]); - if (scaled <= 0.0f) { - depth[i] = 0; - } else if (scaled >= 65535.0f) { - depth[i] = 65535; - } else { - depth[i] = (int)scaled; - } - } - } -} - void FramebufferManagerGLES::EndFrame() { } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 8c0be0ac1e32..aa6486c8221a 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -103,6 +103,12 @@ class FramebufferManagerGLES : public FramebufferManagerCommon { int u_stencilUploadTex = -1; int u_stencilValue = -1; int u_postShaderTex = -1; + + GLRProgram *depthDownloadProgram_ = nullptr; + int u_depthDownloadTex = -1; + int u_depthDownloadFactor = -1; + int u_depthDownloadShift = -1; + int u_depthDownloadTo8 = -1; // Cached uniform locs int u_draw2d_tex = -1; diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index f512b5bffa49..2f421c44f58c 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -20,6 +20,7 @@ #include "Core/ConfigValues.h" #include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" +#include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" @@ -143,7 +144,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe queries.push_back({ &u_stencilUploadTex, "tex" }); queries.push_back({ &u_stencilValue, "u_stencilValue" }); std::vector inits; - inits.push_back({ &u_stencilUploadTex, 0, 0 }); + inits.push_back({ &u_stencilUploadTex, 0, TEX_SLOT_PSP_TEXTURE }); stencilUploadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false); for (auto iter : shaders) { render_->DeleteShader(iter); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index c3f2a1aa10af..13264c837c09 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -339,6 +339,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 1710c3f7907e..76b0113d10ab 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -548,5 +548,8 @@ Debugger + + GLES + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 1ed3b4eb69f7..7e5d2829d6b3 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -247,6 +247,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Debugger/Stepping.cpp \ $(SRC)/GPU/GLES/FramebufferManagerGLES.cpp \ $(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \ + $(SRC)/GPU/GLES/DepthBufferGLES.cpp.arm \ $(SRC)/GPU/GLES/GPU_GLES.cpp.arm \ $(SRC)/GPU/GLES/StencilBufferGLES.cpp.arm \ $(SRC)/GPU/GLES/TextureCacheGLES.cpp.arm \ diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 02bfc979b117..cf4dd780ddda 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -249,6 +249,7 @@ void GLQueueRunner::RunInitSteps(const std::vector &steps, bool ski switch (init.type) { case 0: glUniform1i(uniform, init.value); + break; } } } @@ -388,31 +389,69 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { #endif CHECK_GL_ERROR_IF_DEBUG(); + auto initFBOTexture = [&](GLRTexture &tex, GLint internalFormat, GLenum format, GLenum type, bool linear) { + glGenTextures(1, &tex.texture); + tex.target = GL_TEXTURE_2D; + tex.maxLod = 0.0f; + + // Create the surfaces. + glBindTexture(GL_TEXTURE_2D, tex.texture); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, fbo->width, fbo->height, 0, format, type, nullptr); + + tex.wrapS = GL_CLAMP_TO_EDGE; + tex.wrapT = GL_CLAMP_TO_EDGE; + tex.magFilter = linear ? GL_LINEAR : GL_NEAREST; + tex.minFilter = linear ? GL_LINEAR : GL_NEAREST; + tex.canWrap = isPowerOf2(fbo->width) && isPowerOf2(fbo->height); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex.wrapS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex.wrapT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex.magFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex.minFilter); + if (!gl_extensions.IsGLES || gl_extensions.GLES3) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + } + }; + // Color texture is same everywhere glGenFramebuffers(1, &fbo->handle); - glGenTextures(1, &fbo->color_texture.texture); - fbo->color_texture.target = GL_TEXTURE_2D; - fbo->color_texture.maxLod = 0.0f; + initFBOTexture(fbo->color_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true); - // Create the surfaces. - glBindTexture(GL_TEXTURE_2D, fbo->color_texture.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbo->width, fbo->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); +retry_depth: + if (!fbo->z_stencil_) { + ILOG("Creating %i x %i FBO using no depth", fbo->width, fbo->height); - fbo->color_texture.wrapS = GL_CLAMP_TO_EDGE; - fbo->color_texture.wrapT = GL_CLAMP_TO_EDGE; - fbo->color_texture.magFilter = GL_LINEAR; - fbo->color_texture.minFilter = GL_LINEAR; - fbo->color_texture.canWrap = isPowerOf2(fbo->width) && isPowerOf2(fbo->height); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, fbo->color_texture.wrapS); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, fbo->color_texture.wrapT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, fbo->color_texture.magFilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, fbo->color_texture.minFilter); - if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - } + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; - if (gl_extensions.IsGLES) { - if (gl_extensions.OES_packed_depth_stencil) { + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + } else if (gl_extensions.IsGLES) { + if (gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3)) { + ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; + + if (gl_extensions.GLES3) { + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + } else { + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + } + + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + if (gl_extensions.GLES3) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + } else { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); + } + } else 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; @@ -448,6 +487,18 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo->z_buffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbo->stencil_buffer); } + } else if (gl_extensions.VersionGEThan(3, 0)) { + ILOG("Creating %i x %i FBO using DEPTH24_STENCIL8 texture", fbo->width, fbo->height); + fbo->z_stencil_buffer = 0; + fbo->stencil_buffer = 0; + fbo->z_buffer = 0; + + initFBOTexture(fbo->z_stencil_texture, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false); + + // Bind it all together + glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->color_texture.texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, fbo->z_stencil_texture.texture, 0); } else { fbo->stencil_buffer = 0; fbo->z_buffer = 0; @@ -464,6 +515,13 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE && !fbo->z_buffer) { + CHECK_GL_ERROR_IF_DEBUG(); + // Uh oh, maybe we need a z/stencil. Platforms sometimes, right? + fbo->z_stencil_ = true; + goto retry_depth; + } + switch (status) { case GL_FRAMEBUFFER_COMPLETE: // ILOG("Framebuffer verified complete."); @@ -472,7 +530,7 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { ELOG("GL_FRAMEBUFFER_UNSUPPORTED"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT "); + ELOG("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); break; default: FLOG("Other framebuffer error: %i", status); @@ -894,10 +952,14 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } if (c.bind_fb_texture.aspect == GL_COLOR_BUFFER_BIT) { if (curTex[slot] != &c.bind_fb_texture.framebuffer->color_texture) - glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture); + glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->color_texture.texture); curTex[slot] = &c.bind_fb_texture.framebuffer->color_texture; + } else if (c.bind_fb_texture.aspect == GL_DEPTH_BUFFER_BIT) { + if (curTex[slot] != &c.bind_fb_texture.framebuffer->z_stencil_texture) + glBindTexture(GL_TEXTURE_2D, c.bind_fb_texture.framebuffer->z_stencil_texture.texture); + curTex[slot] = &c.bind_fb_texture.framebuffer->z_stencil_texture; } else { - // TODO: Depth texturing? + // TODO: Stencil texturing? curTex[slot] = nullptr; } CHECK_GL_ERROR_IF_DEBUG(); @@ -1458,36 +1520,30 @@ GLRFramebuffer::~GLRFramebuffer() { return; CHECK_GL_ERROR_IF_DEBUG(); - if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) { - if (handle) { + if (handle) { + if (gl_extensions.ARB_framebuffer_object || gl_extensions.IsGLES) { 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) { + } else if (gl_extensions.EXT_framebuffer_object) { 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 + } } + + // These can only be set when supported. + if (z_stencil_buffer) + glDeleteRenderbuffers(1, &z_stencil_buffer); + if (z_buffer) + glDeleteRenderbuffers(1, &z_buffer); + if (stencil_buffer) + glDeleteRenderbuffers(1, &stencil_buffer); CHECK_GL_ERROR_IF_DEBUG(); } diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index 56317029f45c..bc9defccadc2 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -61,10 +61,12 @@ void GLDeleter::Perform(GLRenderManager *renderManager, bool skipGLCalls) { inputLayouts.clear(); for (auto framebuffer : framebuffers) { if (skipGLCalls) { + framebuffer->handle = 0; + framebuffer->color_texture.texture = 0; + framebuffer->z_stencil_buffer = 0; + framebuffer->z_stencil_texture.texture = 0; framebuffer->z_buffer = 0; framebuffer->stencil_buffer = 0; - framebuffer->z_stencil_buffer = 0; - framebuffer->handle = 0; } delete framebuffer; } diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 9cc4ca4f7d7d..719ad156e6ac 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -52,7 +52,9 @@ class GLRFramebuffer { GLuint handle = 0; GLRTexture color_texture; - GLuint z_stencil_buffer = 0; // Either this is set, or the two below. + // Either z_stencil_texture, z_stencil_buffer, or (z_buffer and stencil_buffer) are set. + GLuint z_stencil_buffer = 0; + GLRTexture z_stencil_texture; GLuint z_buffer = 0; GLuint stencil_buffer = 0; diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 7baa2c897bb1..1d3b805e7cfc 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -188,6 +188,7 @@ SOURCES_CXX += \ $(GPUDIR)/Software/Lighting.cpp \ $(GPUDIR)/Software/Rasterizer.cpp \ $(GPUDIR)/GLES/DepalettizeShaderGLES.cpp \ + $(GPUDIR)/GLES/DepthBufferGLES.cpp \ $(GPUDIR)/GLES/VertexShaderGeneratorGLES.cpp \ $(GPUDIR)/GLES/DrawEngineGLES.cpp \ $(GPUDIR)/GLES/GPU_GLES.cpp \