From 51f467a7b3a23e63e9230346b6aa6502ba347022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 12 Dec 2017 15:04:46 +0100 Subject: [PATCH] Kill off the GL state cache --- CMakeLists.txt | 2 - GPU/GLES/DepalettizeShaderGLES.cpp | 1 - GPU/GLES/DrawEngineGLES.cpp | 8 +- GPU/GLES/DrawEngineGLES.h | 2 +- GPU/GLES/FragmentTestCacheGLES.h | 1 - GPU/GLES/FramebufferManagerGLES.cpp | 1 + GPU/GLES/GPU_GLES.cpp | 18 -- GPU/GLES/ShaderManagerGLES.cpp | 2 +- GPU/GLES/StateMappingGLES.cpp | 21 +-- GPU/GLES/StencilBufferGLES.cpp | 19 +- GPU/GLES/TextureCacheGLES.cpp | 5 +- Qt/Debugger/debugger_memorytex.cpp | 1 - ext/native/Android.mk | 1 - ext/native/gfx/GLStateCache.cpp | 52 ----- ext/native/gfx/GLStateCache.h | 283 ---------------------------- ext/native/native.vcxproj | 2 - ext/native/native.vcxproj.filters | 8 +- ext/native/thin3d/GLQueueRunner.cpp | 49 +++-- ext/native/thin3d/GLQueueRunner.h | 21 ++- ext/native/thin3d/GLRenderManager.h | 39 ++-- ext/native/thin3d/thin3d.h | 2 +- ext/native/thin3d/thin3d_gl.cpp | 9 +- 22 files changed, 110 insertions(+), 437 deletions(-) delete mode 100644 ext/native/gfx/GLStateCache.cpp delete mode 100644 ext/native/gfx/GLStateCache.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a1ae75c2d..b60032d8f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -887,8 +887,6 @@ add_library(native STATIC ext/native/file/vfs.h ext/native/file/zip_read.cpp ext/native/file/zip_read.h - ext/native/gfx/GLStateCache.cpp - ext/native/gfx/GLStateCache.h ext/native/gfx/gl_common.h ext/native/gfx/gl_debug_log.cpp ext/native/gfx/gl_debug_log.h diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 7e56ce8525..b4eff02b9d 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -23,7 +23,6 @@ #include "Core/Reporting.h" #include "DepalettizeShaderGLES.h" #include "GPU/GLES/TextureCacheGLES.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/Common/DepalettizeShaderCommon.h" #ifdef _WIN32 diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index aacc8f7f31..e61f7df9d0 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -83,7 +83,6 @@ #include "GPU/Common/SplineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SoftwareTransformCommon.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/FragmentTestCacheGLES.h" #include "GPU/GLES/StateMappingGLES.h" #include "GPU/GLES/TextureCacheGLES.h" @@ -585,7 +584,7 @@ rotateVBO: gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255); } - ApplyDrawStateLate(); + ApplyDrawStateLate(false, 0); LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, lastVType_, prim); GLRInputLayout *inputLayout = SetupDecFmtForDraw(program, dec_->GetDecVtxFmt()); @@ -646,14 +645,11 @@ rotateVBO: prim, vertexCount, dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); - ApplyDrawStateLate(); + ApplyDrawStateLate(result.setStencil, result.stencilValue); LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, lastVType_, prim); if (result.action == SW_DRAW_PRIMITIVES) { - if (result.setStencil) { - glstate.stencilFunc.set(GL_ALWAYS, result.stencilValue, 255); - } const int vertexSize = sizeof(transformed[0]); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 9fd2a6080d..ea75d346e6 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -165,7 +165,7 @@ private: void DoFlush(); void ApplyDrawState(int prim); - void ApplyDrawStateLate(); + void ApplyDrawStateLate(bool setStencil, int stencilValue); void ResetShaderBlending(); GLRInputLayout *SetupDecFmtForDraw(LinkedShader *program, const DecVtxFormat &decFmt); diff --git a/GPU/GLES/FragmentTestCacheGLES.h b/GPU/GLES/FragmentTestCacheGLES.h index 95eecb23cb..2b044614a3 100644 --- a/GPU/GLES/FragmentTestCacheGLES.h +++ b/GPU/GLES/FragmentTestCacheGLES.h @@ -19,7 +19,6 @@ #include #include "Common/CommonTypes.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/TextureCacheGLES.h" #include "GPU/ge_constants.h" diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 52c2d4390f..1fbb7044a0 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -1058,6 +1058,7 @@ void FramebufferManagerGLES::DestroyAllFBOs() { void FramebufferManagerGLES::Resized() { FramebufferManagerCommon::Resized(); + render_->Resize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); if (UpdateSize()) { DestroyAllFBOs(); } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index be88cda194..7887292baa 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -36,7 +36,6 @@ #include "GPU/GeDisasm.h" #include "GPU/Common/FramebufferCommon.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/GPU_GLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" @@ -160,9 +159,6 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) // Update again after init to be sure of any silly driver problems. UpdateVsyncInterval(true); - // Some of our defaults are different from hw defaults, let's assert them. - // We restore each frame anyway, but here is convenient for tests. - glstate.Restore(); textureCacheGL_->NotifyConfigChanged(); // Load shader cache. @@ -431,14 +427,6 @@ void GPU_GLES::Reinitialize() { } void GPU_GLES::InitClear() { - bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE; - if (useNonBufferedRendering) { - glstate.depthWrite.set(GL_TRUE); - glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); } void GPU_GLES::BeginHostFrame() { @@ -497,7 +485,6 @@ void GPU_GLES::UpdateCmdInfo() { } void GPU_GLES::ReapplyGfxState() { - glstate.Restore(); GPUCommon::ReapplyGfxState(); } @@ -557,9 +544,6 @@ void GPU_GLES::CopyDisplayToOutput() { shaderManagerGL_->DirtyLastShader(); - glstate.depthWrite.set(GL_TRUE); - glstate.colorMask.set(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - framebufferManagerGL_->CopyDisplayToOutput(); framebufferManagerGL_->EndFrame(); @@ -768,8 +752,6 @@ void GPU_GLES::ClearShaderCache() { void GPU_GLES::CleanupBeforeUI() { // Clear any enabled vertex arrays. shaderManagerGL_->DirtyLastShader(); - glstate.arrayBuffer.bind(0); - glstate.elementArrayBuffer.bind(0); } void GPU_GLES::DoState(PointerWrap &p) { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 08b9072feb..22d21f50d6 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -26,6 +26,7 @@ #include "base/logging.h" #include "base/timeutil.h" #include "gfx/gl_debug_log.h" +#include "gfx_es2/gpu_features.h" #include "thin3d/GLRenderManager.h" #include "i18n/i18n.h" #include "math/math_util.h" @@ -39,7 +40,6 @@ #include "GPU/Math3D.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/DrawEngineGLES.h" #include "FramebufferManagerGLES.h" diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 54acebcb1c..bb5af37045 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -32,7 +32,6 @@ #include "Core/Config.h" #include "Core/Reporting.h" #include "GPU/GLES/GPU_GLES.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/ShaderManagerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" @@ -169,12 +168,6 @@ void DrawEngineGLES::ApplyDrawState(int prim) { bool colorMask = gstate.isClearModeColorMask(); bool alphaMask = gstate.isClearModeAlphaMask(); renderManager->SetNoBlendAndMask((colorMask ? 7 : 0) | (alphaMask ? 8 : 0)); -#ifndef USING_GLES2 - if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { - // Logic Ops - glstate.colorLogicOp.disable(); - } -#endif } else { // Do the large chunks of state conversion. We might be able to hide these two behind a dirty-flag each, // to avoid recomputing heavy stuff unnecessarily every draw call. @@ -280,7 +273,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) { if (gstate.isClearModeDepthMask()) { framebufferManager_->SetDepthUpdated(); } - renderManager->SetStencil(gstate.isClearModeAlphaMask() && enableStencilTest, GL_ALWAYS, GL_REPLACE, GL_REPLACE, GL_REPLACE, 0xFF, 0xFF, 0xFF); + renderManager->SetStencilFunc(gstate.isClearModeAlphaMask() && enableStencilTest, GL_ALWAYS, 0xFF, 0xFF); + renderManager->SetStencilOp(0xFF, GL_REPLACE, GL_REPLACE, GL_REPLACE); renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS); } else { // Depth Test @@ -293,9 +287,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) { ConvertStencilFuncState(stencilState); // Stencil Test if (stencilState.enabled) { - renderManager->SetStencil(stencilState.enabled, compareOps[stencilState.testFunc], - stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass], - stencilState.writeMask, stencilState.testMask, stencilState.testRef); + renderManager->SetStencilFunc(stencilState.enabled, compareOps[stencilState.testFunc], stencilState.testRef, stencilState.testMask); + renderManager->SetStencilOp(stencilState.writeMask, stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]); } else { renderManager->SetStencilDisabled(); } @@ -332,7 +325,11 @@ void DrawEngineGLES::ApplyDrawState(int prim) { } } -void DrawEngineGLES::ApplyDrawStateLate() { +void DrawEngineGLES::ApplyDrawStateLate(bool setStencil, int stencilValue) { + if (setStencil) { + render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, stencilValue, 255); + } + // At this point, we know if the vertices are full alpha or not. // TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? if (!gstate.isModeClear()) { diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 15da119330..1cd17c8c38 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -17,7 +17,6 @@ #include "gfx_es2/glsl_program.h" #include "Core/Reporting.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/Common/StencilCommon.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" @@ -111,12 +110,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe } // Let's not bother with the shader if it's just zero. - glstate.scissorTest.disable(); - glstate.colorMask.set(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glClearColor(0, 0, 0, 0); - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - + render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); return true; } @@ -150,8 +144,6 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe DisableState(); render_->SetNoBlendAndMask(0x8); - glstate.stencilTest.enable(); - glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE); bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT); @@ -178,7 +170,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe textureCacheGL_->ForgetLastTexture(); render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT); - render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, 0xFF, 0xFF, 0xFF); + render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, 0xFF, 0xFF); for (int i = 1; i < values; i += i) { if (!(usedBits & i)) { @@ -186,18 +178,17 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe continue; } if (dstBuffer->format == GE_FORMAT_4444) { - render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, (i << 4) | i, 0xFF, 0xFF); + render_->SetStencilOp((i << 4) | i, GL_KEEP, GL_KEEP, GL_KEEP); render_->SetUniformF1(&u_stencilValue, i * (16.0f / 255.0f)); } else if (dstBuffer->format == GE_FORMAT_5551) { - glstate.stencilMask.set(0xFF); + render_->SetStencilOp(0xFF, GL_KEEP, GL_KEEP, GL_KEEP); render_->SetUniformF1(&u_stencilValue, i * (128.0f / 255.0f)); } else { - render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, i, 0xFF, 0xFF); + render_->SetStencilOp(i, GL_KEEP, GL_KEEP, GL_KEEP); render_->SetUniformF1(&u_stencilValue, i * (1.0f / 255.0f)); } DrawActiveTexture(0, 0, dstBuffer->width, dstBuffer->height, dstBuffer->bufferWidth, dstBuffer->bufferHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); } - render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, 0xFF, 0xFF, 0xFF); if (useBlit) { draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST); diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 307b208342..9747dad92f 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -32,7 +32,6 @@ #include "Core/Reporting.h" #include "GPU/ge_constants.h" #include "GPU/GPUState.h" -#include "ext/native/gfx/GLStateCache.h" #include "GPU/GLES/TextureCacheGLES.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/FragmentShaderGeneratorGLES.h" @@ -523,6 +522,10 @@ GLenum ToGLESFormat(ReplacedTextureFormat fmt) { void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry, bool replaceImages) { entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK; + // Never replace images in-place - there's no such thing, drivers have to fake it anyway, at least if + // the image has been in use within the last frame or two. + replaceImages = false; + // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); diff --git a/Qt/Debugger/debugger_memorytex.cpp b/Qt/Debugger/debugger_memorytex.cpp index 51af9915c5..f077daaaf7 100644 --- a/Qt/Debugger/debugger_memorytex.cpp +++ b/Qt/Debugger/debugger_memorytex.cpp @@ -1,5 +1,4 @@ #include "debugger_memorytex.h" -#include "gfx/GLStateCache.h" #include "gfx/gl_common.h" #include "ui_debugger_memorytex.h" #include "Core/MemMap.h" diff --git a/ext/native/Android.mk b/ext/native/Android.mk index 5656512d81..fd0e69181f 100644 --- a/ext/native/Android.mk +++ b/ext/native/Android.mk @@ -75,7 +75,6 @@ LOCAL_SRC_FILES :=\ gfx_es2/draw_buffer.cpp.arm \ gfx_es2/draw_text.cpp.arm \ gfx_es2/draw_text_android.cpp.arm \ - gfx/GLStateCache.cpp.arm \ gfx/gl_debug_log.cpp \ gfx/texture_atlas.cpp \ image/zim_load.cpp \ diff --git a/ext/native/gfx/GLStateCache.cpp b/ext/native/gfx/GLStateCache.cpp deleted file mode 100644 index b4edffc1aa..0000000000 --- a/ext/native/gfx/GLStateCache.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include - -#include "base/logging.h" - -#include "gfx/GLStateCache.h" - -OpenGLState glstate; - -int OpenGLState::state_count = 0; - -void OpenGLState::Restore() { - int count = 0; - - blend.restore(); count++; - blendEquationSeparate.restore(); count++; - blendFuncSeparate.restore(); count++; - blendColor.restore(); count++; - - scissorTest.restore(); count++; - scissorRect.restore(); count++; - - cullFace.restore(); count++; - cullFaceMode.restore(); count++; - frontFace.restore(); count++; - - depthTest.restore(); count++; - depthRange.restore(); count++; - depthFunc.restore(); count++; - depthWrite.restore(); count++; - - colorMask.restore(); count++; - viewport.restore(); count++; - - stencilTest.restore(); count++; - stencilOp.restore(); count++; - stencilFunc.restore(); count++; - stencilMask.restore(); count++; - - dither.restore(); count++; - -#if !defined(USING_GLES2) - colorLogicOp.restore(); count++; - logicOp.restore(); count++; -#endif - - arrayBuffer.restore(); count++; - elementArrayBuffer.restore(); count++; - - if (count != state_count) { - FLOG("OpenGLState::Restore is missing some states"); - } -} diff --git a/ext/native/gfx/GLStateCache.h b/ext/native/gfx/GLStateCache.h deleted file mode 100644 index e46133709f..0000000000 --- a/ext/native/gfx/GLStateCache.h +++ /dev/null @@ -1,283 +0,0 @@ -#pragma once - -#include -#include // for memcmp - -#include "gfx/gl_common.h" -#include "gfx_es2/gpu_features.h" - -// OpenGL state cache. -// Probably only really worth it in rendering cores on weak mobile hardware. -class OpenGLState { -private: - template - class BoolState { - private: - bool v; - public: - BoolState() : v(init) { - OpenGLState::state_count++; - } - - inline void set(bool value) { - if (value != v) { - v = value; - restore(); - } - } - inline void force(bool value) { - bool old = v; - set(value); - v = old; - } - inline void enable() { - set(true); - } - inline void disable() { - set(false); - } - operator bool() const { - return isset(); - } - inline bool isset() { - return v; - } - void restore() { - if (v) - glEnable(cap); - else - glDisable(cap); - } - }; - -#define STATE1(func, p1type, p1def) \ - class SavedState1_##func { \ - p1type p1; \ - public: \ - SavedState1_##func() : p1(p1def) { \ - OpenGLState::state_count++; \ - } \ - void set(p1type newp1) { \ - if (newp1 != p1) { \ - p1 = newp1; \ - restore(); \ - } \ - } \ - void force(p1type newp1) { \ - p1type old = p1; \ - set(newp1); \ - p1 = old; \ - } \ - inline void restore() { \ - func(p1); \ - } \ - } - -#define STATE2(func, p1type, p2type, p1def, p2def) \ - class SavedState2_##func { \ - p1type p1; \ - p2type p2; \ - public: \ - SavedState2_##func() : p1(p1def), p2(p2def) { \ - OpenGLState::state_count++; \ - } \ - inline void set(p1type newp1, p2type newp2) { \ - if (newp1 != p1 || newp2 != p2) { \ - p1 = newp1; \ - p2 = newp2; \ - restore(); \ - } \ - } \ - void force(p1type newp1, p2type newp2) { \ - p1type old1 = p1; \ - p2type old2 = p2; \ - set(newp1, newp2); \ - p1 = old1; \ - p2 = old2; \ - } \ - inline void restore() { \ - func(p1, p2); \ - } \ - } - -#define STATE3(func, p1type, p2type, p3type, p1def, p2def, p3def) \ - class SavedState3_##func { \ - p1type p1; \ - p2type p2; \ - p3type p3; \ - public: \ - SavedState3_##func() : p1(p1def), p2(p2def), p3(p3def) { \ - OpenGLState::state_count++; \ - } \ - inline void set(p1type newp1, p2type newp2, p3type newp3) { \ - if (newp1 != p1 || newp2 != p2 || newp3 != p3) { \ - p1 = newp1; \ - p2 = newp2; \ - p3 = newp3; \ - restore(); \ - } \ - } \ - void force(p1type newp1, p2type newp2, p3type newp3) { \ - p1type old1 = p1; \ - p2type old2 = p2; \ - p3type old3 = p3; \ - set(newp1, newp2, newp3); \ - p1 = old1; \ - p2 = old2; \ - p3 = old3; \ - } \ - inline void restore() { \ - func(p1, p2, p3); \ - } \ - } - - #define STATE4(func, p1type, p2type, p3type, p4type, p1def, p2def, p3def, p4def) \ - class SavedState4_##func { \ - p1type p1; \ - p2type p2; \ - p3type p3; \ - p4type p4; \ - public: \ - SavedState4_##func() : p1(p1def), p2(p2def), p3(p3def), p4(p4def) { \ - OpenGLState::state_count++; \ - } \ - inline void set(p1type newp1, p2type newp2, p3type newp3, p4type newp4) { \ - if (newp1 != p1 || newp2 != p2 || newp3 != p3 || newp4 != p4) { \ - p1 = newp1; \ - p2 = newp2; \ - p3 = newp3; \ - p4 = newp4; \ - restore(); \ - } \ - } \ - void force(p1type newp1, p2type newp2, p3type newp3, p4type newp4) { \ - p1type old1 = p1; \ - p2type old2 = p2; \ - p3type old3 = p3; \ - p4type old4 = p4; \ - set(newp1, newp2, newp3, newp4); \ - p1 = old1; \ - p2 = old2; \ - p3 = old3; \ - p4 = old4; \ - } \ - inline void restore() { \ - func(p1, p2, p3, p4); \ - } \ - } - -#define STATEFLOAT4(func, def) \ - class SavedState4_##func { \ - float p[4]; \ - public: \ - SavedState4_##func() { \ - for (int i = 0; i < 4; i++) {p[i] = def;} \ - OpenGLState::state_count++; \ - } \ - inline void set(const float v[4]) { \ - if (memcmp(p, v, sizeof(float) * 4)) { \ - memcpy(p, v, sizeof(float) * 4); \ - restore(); \ - } \ - } \ - void force(const float v[4]) { \ - float old[4]; \ - memcpy(old, p, sizeof(float) * 4); \ - set(v); \ - memcpy(p, old, sizeof(float) * 4); \ - } \ - inline void restore() { \ - func(p[0], p[1], p[2], p[3]); \ - } \ - } - -#define STATEBIND(func, target) \ - class SavedBind_##func_##target { \ - GLuint val_; \ - public: \ - SavedBind_##func_##target() { \ - val_ = 0; \ - OpenGLState::state_count++; \ - } \ - inline void bind(GLuint val) { \ - if (val_ != val) { \ - val_ = val; \ - restore(); \ - } \ - } \ - inline void force(GLuint val) { \ - GLuint old = val_; \ - bind(val); \ - val_ = old; \ - } \ - inline void unbind() { \ - bind(0); \ - } \ - inline void restore() { \ - func(target, val_); \ - } \ - } - -public: - static int state_count; - OpenGLState() {} - void Restore(); - - // When adding a state here, don't forget to add it to OpenGLState::Restore() too - - // Blending - BoolState blend; - STATE4(glBlendFuncSeparate, GLenum, GLenum, GLenum, GLenum, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) blendFuncSeparate; - - // On OpenGL ES, using minmax blend requires glBlendEquationEXT (in theory at least but I don't think it's true in practice) - STATE2(glBlendEquationSeparate, GLenum, GLenum, GL_FUNC_ADD, GL_FUNC_ADD) blendEquationSeparate; - STATEFLOAT4(glBlendColor, 1.0f) blendColor; - - // Logic Ops. Not available on OpenGL ES at all. -#if !defined(USING_GLES2) - BoolState colorLogicOp; - STATE1(glLogicOp, GLenum, GL_COPY) logicOp; -#endif - - // Dither - BoolState dither; - - // Cull Face - BoolState cullFace; - STATE1(glCullFace, GLenum, GL_FRONT) cullFaceMode; - STATE1(glFrontFace, GLenum, GL_CCW) frontFace; - - // Depth Test - BoolState depthTest; -#if defined(USING_GLES2) - STATE2(glDepthRangef, float, float, 0.f, 1.f) depthRange; -#else - STATE2(glDepthRange, double, double, 0.0, 1.0) depthRange; -#endif - STATE1(glDepthFunc, GLenum, GL_LESS) depthFunc; - STATE1(glDepthMask, GLboolean, GL_TRUE) depthWrite; - - // Color Mask - STATE4(glColorMask, bool, bool, bool, bool, true, true, true, true) colorMask; - - // Viewport - STATE4(glViewport, GLint, GLint, GLsizei, GLsizei, 0, 0, 128, 128) viewport; - - // Scissor Test - BoolState scissorTest; - STATE4(glScissor, GLint, GLint, GLsizei, GLsizei, 0, 0, 128, 128) scissorRect; - - // Stencil Test - BoolState stencilTest; - STATE3(glStencilOp, GLenum, GLenum, GLenum, GL_KEEP, GL_KEEP, GL_KEEP) stencilOp; - STATE3(glStencilFunc, GLenum, GLint, GLuint, GL_ALWAYS, 0, 0xFF) stencilFunc; - STATE1(glStencilMask, GLuint, 0xFF) stencilMask; - - STATEBIND(glBindBuffer, GL_ARRAY_BUFFER) arrayBuffer; - STATEBIND(glBindBuffer, GL_ELEMENT_ARRAY_BUFFER) elementArrayBuffer; -}; - -#undef STATE1 -#undef STATE2 - -extern OpenGLState glstate; diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 3f520beb66..a9929e396a 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -232,7 +232,6 @@ - @@ -693,7 +692,6 @@ - diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index d452261752..7336d62265 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -302,9 +302,6 @@ gfx - - gfx - thin3d @@ -775,9 +772,6 @@ gfx - - gfx - thin3d @@ -883,4 +877,4 @@ {06c6305a-a646-485b-85b9-645a24dd6553} - + \ No newline at end of file diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 42b25e040f..cf886b25ef 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -279,13 +279,24 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { glBlendColor(c.blendColor.color[0], c.blendColor.color[1], c.blendColor.color[2], c.blendColor.color[3]); break; case GLRRenderCommand::VIEWPORT: + { + float y = c.viewport.vp.y; + if (!curFramebuffer_) + y = curFBHeight_ - y - c.viewport.vp.h; + // TODO: Support FP viewports through glViewportArrays - glViewport((GLint)c.viewport.vp.x, (GLint)c.viewport.vp.y, (GLsizei)c.viewport.vp.w, (GLsizei)c.viewport.vp.h); + glViewport((GLint)c.viewport.vp.x, (GLint)y, (GLsizei)c.viewport.vp.w, (GLsizei)c.viewport.vp.h); glDepthRange(c.viewport.vp.minZ, c.viewport.vp.maxZ); break; + } case GLRRenderCommand::SCISSOR: - glScissor(c.scissor.rc.x, c.scissor.rc.y, c.scissor.rc.w, c.scissor.rc.h); + { + int y = c.scissor.rc.y; + if (!curFramebuffer_) + y = curFBHeight_ - y - c.scissor.rc.h; + glScissor(c.scissor.rc.x, y, c.scissor.rc.w, c.scissor.rc.h); break; + } case GLRRenderCommand::UNIFORM4F: { int loc = c.uniform4.loc ? *c.uniform4.loc : -1; @@ -345,24 +356,30 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { } break; } - case GLRRenderCommand::STENCIL: - if (c.stencil.enabled) { + case GLRRenderCommand::STENCILFUNC: + if (c.stencilFunc.enabled) { glEnable(GL_STENCIL_TEST); - glStencilFunc(c.stencil.func, c.stencil.ref, c.stencil.compareMask); - glStencilOp(c.stencil.sFail, c.stencil.zFail, c.stencil.pass); - glStencilMask(c.stencil.writeMask); } else { glDisable(GL_STENCIL_TEST); } + glStencilFunc(c.stencilFunc.func, c.stencilFunc.ref, c.stencilFunc.compareMask); + break; + case GLRRenderCommand::STENCILOP: + glStencilOp(c.stencilOp.sFail, c.stencilOp.zFail, c.stencilOp.pass); + glStencilMask(c.stencilOp.writeMask); break; case GLRRenderCommand::BINDTEXTURE: { - GLint target = c.texture.slot; - if (target != activeTexture) { - glActiveTexture(GL_TEXTURE0 + target); - activeTexture = target; + GLint slot = c.texture.slot; + if (slot != activeTexture) { + glActiveTexture(GL_TEXTURE0 + slot); + activeTexture = slot; + } + if (c.texture.texture) { + glBindTexture(c.texture.texture->target, c.texture.texture->texture); + } else { + glBindTexture(GL_TEXTURE_2D, 0); // ? } - glBindTexture(c.texture.texture->target, c.texture.texture->texture); break; } case GLRRenderCommand::BINDPROGRAM: @@ -518,7 +535,13 @@ void GLQueueRunner::PerformReadbackImage(const GLRStep &pass) { } void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) { - + if (pass.render.framebuffer) { + curFBWidth_ = pass.render.framebuffer->width; + curFBHeight_ = pass.render.framebuffer->height; + } else { + curFBWidth_ = targetWidth_; + curFBHeight_ = targetHeight_; + } } void GLQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h index f6ddf68ef9..f26d995d5e 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/ext/native/thin3d/GLQueueRunner.h @@ -28,7 +28,8 @@ class GLRInputLayout; enum class GLRRenderCommand : uint8_t { DEPTH, - STENCIL, + STENCILFUNC, + STENCILOP, BLEND, BLENDCOLOR, UNIFORM4I, @@ -77,13 +78,15 @@ struct GLRRenderData { struct { GLboolean enabled; GLenum func; - uint8_t writeMask; - uint8_t compareMask; uint8_t ref; + uint8_t compareMask; + } stencilFunc; + struct { GLenum sFail; GLenum zFail; GLenum pass; - } stencil; + uint8_t writeMask; + } stencilOp; // also write mask struct { GLenum mode; // primitive GLint buffer; @@ -299,6 +302,10 @@ public: void CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); + void Resize(int width, int height) { + targetWidth_ = width; + targetHeight_ = height; + } private: void PerformBindFramebufferAsRenderTarget(const GLRStep &pass); void PerformRenderPass(const GLRStep &pass); @@ -318,8 +325,10 @@ private: GLuint globalVAO_; GLint curFramebuffer_ = 0; - int curFBWidth_; - int curFBHeight_; + int curFBWidth_ = 0; + int curFBHeight_ = 0; + int targetWidth_ = 0; + int targetHeight_ = 0; // Readback buffer. Currently we only support synchronous readback, so we only really need one. // We size it generously. diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 19c82ee043..1e20c17827 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -456,25 +456,31 @@ public: curRenderStep_->commands.push_back(data); } - void SetStencil(bool enabled, GLenum func, GLenum sFail, GLenum zFail, GLenum pass, uint8_t writeMask, uint8_t compareMask, uint8_t refValue) { + void SetStencilFunc(bool enabled, GLenum func, uint8_t refValue, uint8_t compareMask) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); - GLRRenderData data{ GLRRenderCommand::STENCIL }; - data.stencil.enabled = enabled; - data.stencil.func = func; - data.stencil.sFail = sFail; - data.stencil.zFail = zFail; - data.stencil.pass = pass; - data.stencil.writeMask = writeMask; - data.stencil.compareMask = compareMask; - data.stencil.ref = refValue; + GLRRenderData data{ GLRRenderCommand::STENCILFUNC }; + data.stencilFunc.enabled = enabled; + data.stencilFunc.func = func; + data.stencilFunc.ref = refValue; + data.stencilFunc.compareMask = compareMask; + curRenderStep_->commands.push_back(data); + } + + void SetStencilOp(uint8_t writeMask, GLenum sFail, GLenum zFail, GLenum pass) { + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); + GLRRenderData data{ GLRRenderCommand::STENCILOP }; + data.stencilOp.writeMask = writeMask; + data.stencilOp.sFail = sFail; + data.stencilOp.zFail = zFail; + data.stencilOp.pass = pass; curRenderStep_->commands.push_back(data); } void SetStencilDisabled() { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data; - data.cmd = GLRRenderCommand::STENCIL; - data.stencil.enabled = false; + data.cmd = GLRRenderCommand::STENCILFUNC; + data.stencilFunc.enabled = false; curRenderStep_->commands.push_back(data); } @@ -546,6 +552,12 @@ public: return curFrame_; } + void Resize(int width, int height) { + targetWidth_ = width; + targetHeight_ = height; + queueRunner_.Resize(width, height); + } + private: void BeginSubmitFrame(int frame); void EndSubmitFrame(int frame); @@ -601,6 +613,9 @@ private: bool useThread_ = false; int curFrame_ = 0; + + int targetWidth_ = 0; + int targetHeight_ = 0; }; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 6bbc0d50e8..3427773c24 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -633,7 +633,7 @@ public: virtual void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) = 0; // Necessary to correctly flip scissor rectangles etc for OpenGL. - void SetTargetSize(int w, int h) { + virtual void SetTargetSize(int w, int h) { targetWidth_ = w; targetHeight_ = h; } diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 751e839e22..cc0fb5299c 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -11,7 +11,6 @@ #include "thin3d/thin3d.h" #include "gfx/gl_common.h" #include "gfx/gl_debug_log.h" -#include "gfx/GLStateCache.h" #include "gfx_es2/gpu_features.h" #include "thin3d/GLRenderManager.h" @@ -207,7 +206,8 @@ public: void Apply(GLRenderManager *render) { render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp); - render->SetStencil(stencilEnabled, stencilCompareOp, stencilFail, stencilZFail, stencilPass, stencilWriteMask, stencilCompareMask, stencilReference); + render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilReference, stencilCompareMask); + render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass); } }; @@ -345,6 +345,11 @@ public: OpenGLContext(); virtual ~OpenGLContext(); + void SetTargetSize(int w, int h) override { + DrawContext::SetTargetSize(w, h); + renderManager_.Resize(w, h); + } + const DeviceCaps &GetDeviceCaps() const override { return caps_; }