diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 90bec0ecfe..6dd922f1c1 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -100,8 +100,6 @@ public: } void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; - uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) override; - void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; void InvalidateCachedState() override; @@ -1709,21 +1707,6 @@ uint64_t D3D11DrawContext::GetNativeObject(NativeObject obj, void *srcObject) { } } -uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { - D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; - switch (channelBit) { - case FB_COLOR_BIT: return (uintptr_t)fb->colorTex; - case FB_DEPTH_BIT: return (uintptr_t)fb->depthStencilTex; - case FB_COLOR_BIT | FB_VIEW_BIT: return (uintptr_t)fb->colorRTView; - case FB_DEPTH_BIT | FB_VIEW_BIT: return (uintptr_t)fb->depthStencilRTView; - case FB_COLOR_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->colorFormat; - case FB_DEPTH_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->depthStencilFormat; - case FB_STENCIL_BIT | FB_FORMAT_BIT: return (uintptr_t)fb->depthStencilFormat; - default: - return 0; - } -} - void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; if (fb) { diff --git a/Common/GPU/D3D9/D3D9StateCache.cpp b/Common/GPU/D3D9/D3D9StateCache.cpp index 3388dd2486..b069d60296 100644 --- a/Common/GPU/D3D9/D3D9StateCache.cpp +++ b/Common/GPU/D3D9/D3D9StateCache.cpp @@ -2,12 +2,10 @@ #include "Common/GPU/D3D9/D3D9StateCache.h" -namespace DX9 { - DirectXState dxstate; -LPDIRECT3DDEVICE9 pD3Ddevice = nullptr; -LPDIRECT3DDEVICE9EX pD3DdeviceEx = nullptr; +LPDIRECT3DDEVICE9 pD3Ddevice9 = nullptr; +LPDIRECT3DDEVICE9EX pD3DdeviceEx9 = nullptr; int DirectXState::state_count = 0; @@ -62,6 +60,4 @@ void DirectXState::Restore() { texAddressW.restore(); count++; } -} // namespace DX9 - #endif // _MSC_VER diff --git a/Common/GPU/D3D9/D3D9StateCache.h b/Common/GPU/D3D9/D3D9StateCache.h index 09f3286222..ae2dbd0ff4 100644 --- a/Common/GPU/D3D9/D3D9StateCache.h +++ b/Common/GPU/D3D9/D3D9StateCache.h @@ -4,11 +4,9 @@ #include "Common/GPU/D3D9/D3D9ShaderCompiler.h" -namespace DX9 { - // TODO: Get rid of these somehow. -extern LPDIRECT3DDEVICE9 pD3Ddevice; -extern LPDIRECT3DDEVICE9EX pD3DdeviceEx; +extern LPDIRECT3DDEVICE9 pD3Ddevice9; +extern LPDIRECT3DDEVICE9EX pD3DdeviceEx9; class DirectXState { private: @@ -44,7 +42,7 @@ private: return _value; } void restore() { - pD3Ddevice->SetRenderState(cap, _value); + pD3Ddevice9->SetRenderState(cap, _value); } }; @@ -69,7 +67,7 @@ private: p1 = old; } void restore() { - pD3Ddevice->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state1, p1); } }; @@ -94,7 +92,7 @@ private: p1 = old; } void restore() { - pD3Ddevice->SetSamplerState(0, _state1, p1); + pD3Ddevice9->SetSamplerState(0, _state1, p1); } }; @@ -123,7 +121,7 @@ private: p1 = old; } void restore() { - pD3Ddevice->SetSamplerState(0, _state1, p1d); + pD3Ddevice9->SetSamplerState(0, _state1, p1d); } }; @@ -141,11 +139,11 @@ private: inline void set(DWORD newp1, DWORD newp2) { if (p1 != newp1) { p1 = newp1; - pD3Ddevice->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state1, p1); } if (p2 != newp2) { p2 = newp2; - pD3Ddevice->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state2, p2); } } void force(DWORD newp1, DWORD newp2) { @@ -156,8 +154,8 @@ private: p2 = old2; } void restore() { - pD3Ddevice->SetRenderState(_state1, p1); - pD3Ddevice->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state2, p2); } }; @@ -177,15 +175,15 @@ private: inline void set(DWORD newp1, DWORD newp2, DWORD newp3) { if (p1 != newp1) { p1 = newp1; - pD3Ddevice->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state1, p1); } if (p2 != newp2) { p2 = newp2; - pD3Ddevice->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state2, p2); } if (p3 != newp3) { p3 = newp3; - pD3Ddevice->SetRenderState(_state3, p3); + pD3Ddevice9->SetRenderState(_state3, p3); } } void force(DWORD newp1, DWORD newp2, DWORD newp3) { @@ -198,9 +196,9 @@ private: p3 = old3; } void restore() { - pD3Ddevice->SetRenderState(_state1, p1); - pD3Ddevice->SetRenderState(_state2, p2); - pD3Ddevice->SetRenderState(_state3, p3); + pD3Ddevice9->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state3, p3); } }; @@ -222,19 +220,19 @@ private: inline void set(DWORD newp1, DWORD newp2, DWORD newp3, DWORD newp4) { if (p1 != newp1) { p1 = newp1; - pD3Ddevice->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state1, p1); } if (p2 != newp2) { p2 = newp2; - pD3Ddevice->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state2, p2); } if (p3 != newp3) { p3 = newp3; - pD3Ddevice->SetRenderState(_state3, p3); + pD3Ddevice9->SetRenderState(_state3, p3); } if (p4 != newp4) { p4 = newp4; - pD3Ddevice->SetRenderState(_state4, p4); + pD3Ddevice9->SetRenderState(_state4, p4); } } void force(DWORD newp1, DWORD newp2, DWORD newp3, DWORD newp4) { @@ -249,10 +247,10 @@ private: p4 = old4; } void restore() { - pD3Ddevice->SetRenderState(_state1, p1); - pD3Ddevice->SetRenderState(_state2, p2); - pD3Ddevice->SetRenderState(_state3, p3); - pD3Ddevice->SetRenderState(_state3, p4); + pD3Ddevice9->SetRenderState(_state1, p1); + pD3Ddevice9->SetRenderState(_state2, p2); + pD3Ddevice9->SetRenderState(_state3, p3); + pD3Ddevice9->SetRenderState(_state3, p4); } }; @@ -284,7 +282,7 @@ private: c = old; } inline void restore() { - pD3Ddevice->SetRenderState(D3DRS_BLENDFACTOR, c); + pD3Ddevice9->SetRenderState(D3DRS_BLENDFACTOR, c); } }; @@ -318,7 +316,7 @@ private: } inline void restore() { - pD3Ddevice->SetViewport(&viewport); + pD3Ddevice9->SetViewport(&viewport); } }; @@ -340,7 +338,7 @@ private: } inline void restore() { - pD3Ddevice->SetScissorRect(&rect); + pD3Ddevice9->SetScissorRect(&rect); } }; @@ -412,5 +410,3 @@ struct GLExtensions { extern GLExtensions gl_extensions; void CheckGLExtensions(); - -}; diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 7b2fa934b0..938789479c 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -152,7 +152,6 @@ public: D3DCMPFUNC stencilCompareOp; void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) { - using namespace DX9; dxstate.depthTest.set(depthTestEnabled); if (depthTestEnabled) { dxstate.depthWrite.set(depthWriteEnabled); @@ -174,7 +173,6 @@ public: DWORD cullMode; // D3DCULL_* void Apply(LPDIRECT3DDEVICE9 device) { - using namespace DX9; dxstate.cullMode.set(cullMode); dxstate.scissorTest.enable(); } @@ -188,7 +186,6 @@ public: uint32_t colorMask; void Apply(LPDIRECT3DDEVICE9 device) { - using namespace DX9; dxstate.blend.set(enabled); dxstate.blendFunc.set(srcCol, dstCol, srcAlpha, dstAlpha); dxstate.blendEquation.set(eqCol, eqAlpha); @@ -202,7 +199,6 @@ public: D3DTEXTUREFILTERTYPE magFilt, minFilt, mipFilt; void Apply(LPDIRECT3DDEVICE9 device, int index) { - using namespace DX9; dxstate.texAddressU.set(wrapS); dxstate.texAddressV.set(wrapT); dxstate.texMagFilter.set(magFilt); @@ -259,17 +255,23 @@ class D3D9Pipeline : public Pipeline { public: D3D9Pipeline() {} ~D3D9Pipeline() { + if (vshader) { + vshader->Release(); + } + if (pshader) { + pshader->Release(); + } } - D3D9ShaderModule *vshader; - D3D9ShaderModule *pshader; + D3D9ShaderModule *vshader = nullptr; + D3D9ShaderModule *pshader = nullptr; - D3DPRIMITIVETYPE prim; + D3DPRIMITIVETYPE prim{}; AutoRef inputLayout; AutoRef depthStencil; AutoRef blend; AutoRef raster; - UniformBufferDesc dynamicUniforms; + UniformBufferDesc dynamicUniforms{}; void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask); }; @@ -683,7 +685,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID shaderLanguageDesc_.Init(HLSL_D3D9); - DX9::dxstate.Restore(); + dxstate.Restore(); } D3D9Context::~D3D9Context() { @@ -713,9 +715,11 @@ Pipeline *D3D9Context::CreateGraphicsPipeline(const PipelineDesc &desc) { } if (iter->GetStage() == ShaderStage::Fragment) { pipeline->pshader = static_cast(iter); + pipeline->pshader->AddRef(); } else if (iter->GetStage() == ShaderStage::Vertex) { pipeline->vshader = static_cast(iter); + pipeline->vshader->AddRef(); } } pipeline->prim = primToD3D9[(int)desc.prim]; @@ -1029,15 +1033,11 @@ void D3D9Context::Clear(int mask, uint32_t colorval, float depthVal, int stencil } void D3D9Context::SetScissorRect(int left, int top, int width, int height) { - using namespace DX9; - dxstate.scissorRect.set(left, top, left + width, top + height); dxstate.scissorTest.set(true); } void D3D9Context::SetViewports(int count, Viewport *viewports) { - using namespace DX9; - int x = (int)viewports[0].TopLeftX; int y = (int)viewports[0].TopLeftY; int w = (int)viewports[0].Width; @@ -1050,7 +1050,6 @@ void D3D9Context::SetBlendFactor(float color[4]) { uint32_t g = (uint32_t)(color[1] * 255.0f); uint32_t b = (uint32_t)(color[2] * 255.0f); uint32_t a = (uint32_t)(color[3] * 255.0f); - using namespace DX9; dxstate.blendColor.set(color); } @@ -1171,7 +1170,6 @@ D3D9Framebuffer::~D3D9Framebuffer() { } void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) { - using namespace DX9; if (fbo) { D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo; device_->SetRenderTarget(0, fb->surf); diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index d57a855ac7..900e2d1160 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -313,6 +313,9 @@ void ShaderWriter::EndVSMain(Slice varyings) { case HLSL_D3D11: case HLSL_D3D9: C(" VS_OUTPUT vs_out;\n"); + if (strlen(lang_.viewportYSign)) { + F(" gl_Position.y *= %s1.0;\n", lang_.viewportYSign); + } C(" vs_out.pos = gl_Position;\n"); for (auto &varying : varyings) { F(" vs_out.%s = %s;\n", varying.name, varying.name); diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 9d16f2bf9a..f07d4159f5 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -43,7 +43,7 @@ enum FSFlags { class ShaderWriter { public: - ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) { + ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions = nullptr, size_t num_gl_extensions = 0) : p_(buffer), lang_(lang), stage_(stage) { Preamble(gl_extensions, num_gl_extensions); } ShaderWriter(const ShaderWriter &) = delete; diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 3b0f0d10e6..72236d5e74 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -395,8 +395,6 @@ public: } void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override; - uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) override; - void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; void SetScissorRect(int left, int top, int width, int height) override; @@ -1580,24 +1578,6 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); } -uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { - if (!fbo) - return 0; - - VKFramebuffer *fb = (VKFramebuffer *)fbo; - VkImageView view = VK_NULL_HANDLE; - switch (channelBit) { - case FB_COLOR_BIT: - view = fb->GetFB()->color.imageView; - break; - case FB_DEPTH_BIT: - case FB_STENCIL_BIT: - view = fb->GetFB()->depth.imageView; - break; - } - return (uintptr_t)view; -} - void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { VKFramebuffer *fb = (VKFramebuffer *)fbo; if (fb) { diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index b5a2b89c2c..9dee5898fb 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -66,10 +66,15 @@ bool DataFormatIsDepthStencil(DataFormat fmt) { } } +RefCountedObject::~RefCountedObject() { + _dbg_assert_(refcount_ == 0xDEDEDE); +} bool RefCountedObject::Release() { if (refcount_ > 0 && refcount_ < 10000) { if (--refcount_ == 0) { + // Make it very obvious if we try to free this again. + refcount_ = 0xDEDEDE; delete this; return true; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index cbd5cafef1..264e240fa9 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -341,7 +341,9 @@ public: RefCountedObject() { refcount_ = 1; } - virtual ~RefCountedObject() {} + RefCountedObject(const RefCountedObject &other) = delete; + RefCountedObject& operator=(RefCountedObject const&) = delete; + virtual ~RefCountedObject(); void AddRef() { refcount_++; } bool Release(); @@ -605,12 +607,15 @@ public: virtual void SetErrorCallback(ErrorCallbackFn callback, void *userdata) {} // Partial pipeline state, used to create pipelines. (in practice, in d3d11 they'll use the native state objects directly). + // TODO: Possibly ditch these and just put the descs directly in PipelineDesc since only D3D11 benefits. virtual DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) = 0; virtual BlendState *CreateBlendState(const BlendStateDesc &desc) = 0; virtual SamplerState *CreateSamplerState(const SamplerStateDesc &desc) = 0; virtual RasterState *CreateRasterState(const RasterStateDesc &desc) = 0; // virtual ComputePipeline CreateComputePipeline(const ComputePipelineDesc &desc) = 0 virtual InputLayout *CreateInputLayout(const InputLayoutDesc &desc) = 0; + virtual ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const std::string &tag = "thin3d") = 0; + virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) = 0; // Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them. ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return vsPresets_[preset]; } @@ -623,9 +628,6 @@ public: // On some hardware, you might get a 24-bit depth buffer even though you only wanted a 16-bit one. virtual Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) = 0; - virtual ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const std::string &tag = "thin3d") = 0; - virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) = 0; - // Copies data from the CPU over into the buffer, at a specific offset. This does not change the size of the buffer and cannot write outside it. virtual void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) = 0; @@ -646,7 +648,7 @@ public: // binding must be < MAX_TEXTURE_SLOTS (0, 1 are okay if it's 2). virtual void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) = 0; - // deprecated + // deprecated, only used by D3D9 virtual uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) { return 0; } diff --git a/Common/Render/TextureAtlas.h b/Common/Render/TextureAtlas.h index 58a2b86c96..aed38e273f 100644 --- a/Common/Render/TextureAtlas.h +++ b/Common/Render/TextureAtlas.h @@ -3,7 +3,7 @@ #include #include -#define ATLAS_MAGIC ('A' + ('T' << 8) + ('L' << 16) | ('A' << 24)) +#define ATLAS_MAGIC ('A' | ('T' << 8) | ('L' << 16) | ('A' << 24)) // Metadata file structure v0: // diff --git a/Core/Config.cpp b/Core/Config.cpp index 98e59076e9..ff04296e57 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1167,6 +1167,9 @@ static ConfigSetting debuggerSettings[] = { ConfigSetting("GEWindowY", &g_Config.iGEWindowY, -1), ConfigSetting("GEWindowW", &g_Config.iGEWindowW, -1), ConfigSetting("GEWindowH", &g_Config.iGEWindowH, -1), + ConfigSetting("GEWindowTabsBL", &g_Config.uGETabsLeft, (uint32_t)0), + ConfigSetting("GEWindowTabsBR", &g_Config.uGETabsRight, (uint32_t)0), + ConfigSetting("GEWindowTabsTR", &g_Config.uGETabsTopRight, (uint32_t)0), ConfigSetting("ConsoleWindowX", &g_Config.iConsoleWindowX, -1), ConfigSetting("ConsoleWindowY", &g_Config.iConsoleWindowY, -1), ConfigSetting("FontWidth", &g_Config.iFontWidth, 8), diff --git a/Core/Config.h b/Core/Config.h index 3ac22964d8..60ec8eb96b 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -469,6 +469,9 @@ public: int iGEWindowY; int iGEWindowW; int iGEWindowH; + uint32_t uGETabsLeft; + uint32_t uGETabsRight; + uint32_t uGETabsTopRight; int iConsoleWindowX; int iConsoleWindowY; int iFontWidth; diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 6d40c6802e..3c9643d897 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -187,6 +187,9 @@ void __sceAudiocodecDoState(PointerWrap &p){ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-warning-option" #pragma clang diagnostic ignored "-Wsizeof-pointer-div" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsizeof-pointer-div" #endif DoArray(p, codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_)); DoArray(p, ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_)); @@ -197,6 +200,8 @@ void __sceAudiocodecDoState(PointerWrap &p){ } #ifdef __clang__ #pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop #endif delete[] codec_; delete[] ctxPtr_; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index e3a44e54d8..7db5998ff7 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -57,12 +57,6 @@ #include "GPU/Common/PostShader.h" #include "GPU/Debugger/Record.h" -#ifdef OPENXR -#define FRAMELIMIT 72 -#else -#define FRAMELIMIT 60 -#endif - struct FrameBufferState { u32 topaddr; GEBufferFormat fmt; @@ -110,8 +104,10 @@ static int height; static bool wasPaused; static bool flippedThisFrame; +static int framerate = 60; + // 1.001f to compensate for the classic 59.94 NTSC framerate that the PSP seems to have. -static const double timePerVblank = 1.001f / (float)FRAMELIMIT; +static double timePerVblank = 1.001f / (float)framerate; // Don't include this in the state, time increases regardless of state. static double curFrameTime; @@ -133,7 +129,7 @@ const double vblankMs = 0.7315; // These are guesses based on tests. const double vsyncStartMs = 0.5925; const double vsyncEndMs = 0.7265; -const double frameMs = 1001.0 / (double)FRAMELIMIT; +double frameMs = 1001.0 / (double)framerate; enum { PSP_DISPLAY_SETBUF_IMMEDIATE = 0, @@ -164,7 +160,7 @@ static void ScheduleLagSync(int over = 0) { if (lagSyncScheduled) { // Reset over if it became too high, such as after pausing or initial loading. // There's no real sense in it being more than 1/60th of a second. - if (over > 1000000 / FRAMELIMIT) { + if (over > 1000000 / framerate) { over = 0; } CoreTiming::ScheduleEvent(usToCycles(1000 + over), lagSyncEvent, 0); @@ -364,7 +360,7 @@ static int FrameTimingLimit() { return PSP_CoreParameter().analogFpsLimit; if (PSP_CoreParameter().fastForward) return 0; - return FRAMELIMIT; + return framerate; } static bool FrameTimingThrottled() { @@ -395,8 +391,8 @@ static void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) { return; float scaledTimestep = timestep; - if (fpsLimit > 0 && fpsLimit != FRAMELIMIT) { - scaledTimestep *= (float)FRAMELIMIT / fpsLimit; + if (fpsLimit > 0 && fpsLimit != framerate) { + scaledTimestep *= (float)framerate / fpsLimit; } if (lastFrameTime == 0.0 || wasPaused) { @@ -470,9 +466,9 @@ static void DoFrameIdleTiming() { float scaledVblank = timePerVblank; int fpsLimit = FrameTimingLimit(); - if (fpsLimit != 0 && fpsLimit != FRAMELIMIT) { + if (fpsLimit != 0 && fpsLimit != framerate) { // 0 is handled in FrameTimingThrottled(). - scaledVblank *= (float)FRAMELIMIT / fpsLimit; + scaledVblank *= (float)framerate / fpsLimit; } // If we have over at least a vblank of spare time, maintain at least 30fps in delay. @@ -592,7 +588,7 @@ void __DisplayFlip(int cyclesLate) { bool forceNoFlip = false; float refreshRate = System_GetPropertyFloat(SYSPROP_DISPLAY_REFRESH_RATE); // Avoid skipping on devices that have 58 or 59 FPS, except when alternate speed is set. - bool refreshRateNeedsSkip = FrameTimingLimit() != FRAMELIMIT && FrameTimingLimit() > refreshRate; + bool refreshRateNeedsSkip = FrameTimingLimit() != framerate && FrameTimingLimit() > refreshRate; // Alternative to frameskip fast-forward, where we draw everything. // Useful if skipping a frame breaks graphics or for checking drawing speed. if (fastForwardSkipFlip && (!FrameTimingThrottled() || refreshRateNeedsSkip)) { @@ -691,9 +687,9 @@ void hleLagSync(u64 userdata, int cyclesLate) { float scale = 1.0f; int fpsLimit = FrameTimingLimit(); - if (fpsLimit != 0 && fpsLimit != FRAMELIMIT) { + if (fpsLimit != 0 && fpsLimit != framerate) { // 0 is handled in FrameTimingThrottled(). - scale = (float)FRAMELIMIT / fpsLimit; + scale = (float)framerate / fpsLimit; } const double goal = lastLagSync + (scale / 1000.0f); @@ -851,7 +847,7 @@ u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) } // 1001 to account for NTSC timing (59.94 fps.) - u64 expected = msToCycles(1001) / FRAMELIMIT - LEEWAY_CYCLES_PER_FLIP; + u64 expected = msToCycles(1001) / framerate - LEEWAY_CYCLES_PER_FLIP; lastFlipCycles = now; nextFlipCycles = std::max(lastFlipCycles, nextFlipCycles) + expected; } @@ -1083,3 +1079,9 @@ void Register_sceDisplay() { void Register_sceDisplay_driver() { RegisterModule("sceDisplay_driver", ARRAY_SIZE(sceDisplay), sceDisplay); } + +void __DisplaySetFramerate(int value) { + framerate = value; + timePerVblank = 1.001f / (float)framerate; + frameMs = 1001.0 / (double)framerate; +} diff --git a/Core/HLE/sceDisplay.h b/Core/HLE/sceDisplay.h index bb134af815..b68133e8a2 100644 --- a/Core/HLE/sceDisplay.h +++ b/Core/HLE/sceDisplay.h @@ -34,3 +34,5 @@ void __DisplaySetWasPaused(); void Register_sceDisplay_driver(); void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks = false); + +void __DisplaySetFramerate(int value); diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index c35cc0e41f..0ec0b6c66c 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -264,7 +264,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config, c } void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + ShaderWriter writer(buffer, lang, ShaderStage::Fragment); writer.DeclareSamplers(samplers); writer.HighPrecisionFloat(); writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); @@ -289,9 +289,6 @@ void GenerateDepalVs(char *buffer, const ShaderLanguageDesc &lang) { writer.BeginVSMain(vsInputs, Slice::empty(), varyings); writer.C(" v_texcoord = a_texcoord0;\n"); writer.C(" gl_Position = vec4(a_position, 0.0, 1.0);\n"); - if (strlen(lang.viewportYSign)) { - writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); - } writer.EndVSMain(varyings); } diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 882da8590f..ccffd4e611 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -39,16 +39,14 @@ static const SamplerDef samplers[1] = { { "tex" }, }; -void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); +void GenerateDraw2DFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); writer.EndFSMain("outColor", FSFLAG_NONE); } -void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); +void GenerateDraw2DDepthFs(ShaderWriter &writer) { writer.DeclareSamplers(samplers); writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); @@ -56,120 +54,134 @@ void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) { writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); } -void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { - ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); - +void GenerateDraw2DVS(ShaderWriter &writer) { writer.BeginVSMain(inputs, Slice::empty(), varyings); writer.C(" v_texcoord = a_texcoord0;\n"); // yes, this should be right. Should be 2.0 in the far corners. writer.C(" gl_Position = vec4(a_position, 0.0, 1.0);\n"); - writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); writer.EndVSMain(varyings); } -// verts have positions in clip coordinates. -void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) { +void FramebufferManagerCommon::Ensure2DResources() { using namespace Draw; - if (!draw2DPipelineColor_) { - const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); - char *fsCode = new char[4000]; - char *fsDepthCode = new char[4000]; + if (!draw2DVs_) { char *vsCode = new char[4000]; - GenerateDraw2DFs(fsCode, shaderLanguageDesc); - GenerateDraw2DDepthFs(fsDepthCode, shaderLanguageDesc); - GenerateDraw2DVS(vsCode, shaderLanguageDesc); - - draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); + ShaderWriter writer(vsCode, shaderLanguageDesc, ShaderStage::Vertex); + GenerateDraw2DVS(writer); draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs"); - - _assert_(draw2DFs_ && draw2DVs_); - - if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { - draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs"); - _assert_(draw2DFsDepth_); - } else { - draw2DFsDepth_ = nullptr; - } - - InputLayoutDesc desc = { - { - { 16, false }, - }, - { - { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, - { 0, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 8 }, - }, - }; - InputLayout *inputLayout = draw_->CreateInputLayout(desc); - - BlendState *blendOff = draw_->CreateBlendState({ false, 0xF }); - BlendState *blendDiscard = draw_->CreateBlendState({ false, 0x0 }); - - DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(DepthStencilStateDesc{}); - RasterState *rasterNoCull = draw_->CreateRasterState({}); - - DepthStencilStateDesc dsWriteDesc{}; - dsWriteDesc.depthTestEnabled = true; - dsWriteDesc.depthWriteEnabled = true; - dsWriteDesc.depthCompare = Draw::Comparison::ALWAYS; - DepthStencilState *depthWriteAlways = draw_->CreateDepthStencilState(dsWriteDesc); - - PipelineDesc draw2DColorPipelineDesc{ - Primitive::TRIANGLE_STRIP, - { draw2DVs_, draw2DFs_ }, - inputLayout, noDepthStencil, blendOff, rasterNoCull, nullptr, - }; - - draw2DPipelineColor_ = draw_->CreateGraphicsPipeline(draw2DColorPipelineDesc); - - PipelineDesc draw2DDepthPipelineDesc{ - Primitive::TRIANGLE_STRIP, - { draw2DVs_, draw2DFsDepth_ }, - inputLayout, depthWriteAlways, blendDiscard, rasterNoCull, nullptr, - }; - - if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { - draw2DPipelineDepth_ = draw_->CreateGraphicsPipeline(draw2DDepthPipelineDesc); - _assert_(draw2DPipelineDepth_); - } else { - draw2DPipelineDepth_ = nullptr; - } - - delete[] fsCode; + _assert_(draw2DVs_); delete[] vsCode; + } - rasterNoCull->Release(); - blendOff->Release(); - blendDiscard->Release(); - noDepthStencil->Release(); - depthWriteAlways->Release(); - inputLayout->Release(); - + if (!draw2DSamplerLinear_) { SamplerStateDesc descLinear{}; descLinear.magFilter = TextureFilter::LINEAR; descLinear.minFilter = TextureFilter::LINEAR; descLinear.mipFilter = TextureFilter::LINEAR; descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE; descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE; - draw2DSamplerLinear_= draw_->CreateSamplerState(descLinear); + draw2DSamplerLinear_ = draw_->CreateSamplerState(descLinear); + } + if (!draw2DSamplerNearest_) { SamplerStateDesc descNearest{}; - descLinear.magFilter = TextureFilter::NEAREST; - descLinear.minFilter = TextureFilter::NEAREST; - descLinear.mipFilter = TextureFilter::NEAREST; - descLinear.wrapU = TextureAddressMode::CLAMP_TO_EDGE; - descLinear.wrapV = TextureAddressMode::CLAMP_TO_EDGE; + descNearest.magFilter = TextureFilter::NEAREST; + descNearest.minFilter = TextureFilter::NEAREST; + descNearest.mipFilter = TextureFilter::NEAREST; + descNearest.wrapU = TextureAddressMode::CLAMP_TO_EDGE; + descNearest.wrapV = TextureAddressMode::CLAMP_TO_EDGE; draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest); } +} - if (channel == RASTER_DEPTH && !draw2DPipelineDepth_) { - return; +Draw::Pipeline *FramebufferManagerCommon::Create2DPipeline(void (*generate)(ShaderWriter &)) { + using namespace Draw; + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + char *fsCode = new char[4000]; + ShaderWriter writer(fsCode, shaderLanguageDesc, ShaderStage::Fragment); + generate(writer); + + ShaderModule *fs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); + delete[] fsCode; + + _assert_(fs); + + // verts have positions in 2D clip coordinates. + static const InputLayoutDesc desc = { + { + { 16, false }, + }, + { + { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, + { 0, SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, 8 }, + }, + }; + InputLayout *inputLayout = draw_->CreateInputLayout(desc); + + BlendState *blendOff = draw_->CreateBlendState({ false, 0xF }); + BlendState *blendDiscard = draw_->CreateBlendState({ false, 0x0 }); + + DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(DepthStencilStateDesc{}); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + DepthStencilStateDesc dsWriteDesc{}; + dsWriteDesc.depthTestEnabled = true; + dsWriteDesc.depthWriteEnabled = true; + dsWriteDesc.depthCompare = Draw::Comparison::ALWAYS; + DepthStencilState *depthWriteAlways = draw_->CreateDepthStencilState(dsWriteDesc); + + PipelineDesc pipelineDesc{ + Primitive::TRIANGLE_STRIP, + { draw2DVs_, fs }, + inputLayout, noDepthStencil, blendOff, rasterNoCull, nullptr, + }; + + Draw::Pipeline *pipeline = draw_->CreateGraphicsPipeline(pipelineDesc); + + fs->Release(); + + rasterNoCull->Release(); + blendOff->Release(); + blendDiscard->Release(); + noDepthStencil->Release(); + depthWriteAlways->Release(); + inputLayout->Release(); + + return pipeline; +} + +void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) { + using namespace Draw; + + Ensure2DResources(); + + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + switch (channel) { + case RASTER_COLOR: + if (!draw2DPipelineColor_) { + draw2DPipelineColor_ = Create2DPipeline(&GenerateDraw2DFs); + } + draw_->BindPipeline(draw2DPipelineColor_); + break; + + case RASTER_DEPTH: + if (!draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { + // Can't do it + return; + } + if (!draw2DPipelineDepth_) { + draw2DPipelineDepth_ = Create2DPipeline(&GenerateDraw2DFs); + } + draw_->BindPipeline(draw2DPipelineDepth_); + break; } - draw_->BindPipeline(channel == RASTER_COLOR ? draw2DPipelineColor_ : draw2DPipelineDepth_); if (tex) { draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); } diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 0755988029..34e0f7ff90 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -266,7 +266,7 @@ bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vectorfb_address == addr) { - // Could check w too but whatever - if (match == nullptr || match->last_frame_render < v->last_frame_render) { + // Could check w too but whatever (actually, might very well make sense to do so, depending on context). + if (!match || v->last_frame_render > match->last_frame_render) { match = v; } } @@ -238,6 +232,9 @@ void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPU } params->isDrawing = !gstate.isModeClear() || !gstate.isClearModeColorMask() || !gstate.isClearModeAlphaMask(); params->isModeThrough = gstate.isModeThrough(); + const bool alphaBlending = gstate.isAlphaBlendEnabled(); + const bool logicOpBlending = gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_CLEAR && gstate.getLogicOp() != GE_LOGIC_COPY; + params->isBlending = alphaBlending || logicOpBlending; // Viewport-X1 and Y1 are not the upper left corner, but half the width/height. A bit confusing. float vpx = gstate.getViewportXScale(); @@ -272,7 +269,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // As there are no clear "framebuffer width" and "framebuffer height" registers, // we need to infer the size of the current framebuffer somehow. int drawing_width, drawing_height; - EstimateDrawingSize(params.fb_address, params.fmt, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, 4), drawing_width, drawing_height); + EstimateDrawingSize(params.fb_address, params.fmt, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, (u16)4), drawing_width, drawing_height); gstate_c.SetCurRTOffset(0, 0); bool vfbFormatChanged = false; @@ -321,7 +318,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->height = drawing_height; } break; - } else if (params.fb_address == v->z_address && params.fmt != GE_FORMAT_8888 && params.fb_stride == v->z_stride) { + } else if (params.fb_address == v->z_address && params.fmt != GE_FORMAT_8888 && params.fb_stride == v->z_stride && !params.isBlending) { // Looks like the game might be intending to use color to write directly to a Z buffer. // This is seen in Kuroyou 2. @@ -372,17 +369,11 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // Lookup in the depth tracking to find which VFB has the latest version of this Z buffer. // Then bind it in color-to-depth mode. // - // We are going to do this by having a special render mode where we take color and move to + // We do this by having a special render mode where we take color and move to // depth in the fragment shader, and set color writes to off. // - // We'll need a special fragment shader flag to convert color to depth. - - for (auto &depth : this->trackedDepthBuffers_) { - if (depth->z_address == params.fb_address && depth->z_stride == params.fb_stride) { - // Found the matching depth buffer. Use this vfb. - vfb = depth->vfb; - } - } + // We use a special fragment shader flag to convert color to depth. + vfb = GetLatestDepthBufferAt(params.fb_address /* !!! */, params.fb_stride); } gstate_c.SetFramebufferRenderMode(mode); @@ -450,14 +441,13 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // Looks up by z_address, so if one is found here and not have last pointers equal to this one, // there is another one. - TrackedDepthBuffer *prevDepth = GetOrCreateTrackedDepthBuffer(vfb); + VirtualFramebuffer *prevDepth = GetLatestDepthBufferAt(vfb->z_address, vfb->z_stride); // We might already want to copy depth, in case this is a temp buffer. See #7810. - if (prevDepth->vfb != vfb) { - if (!params.isClearingDepth && prevDepth->vfb) { - BlitFramebufferDepth(prevDepth->vfb, vfb); + if (prevDepth != vfb) { + if (!params.isClearingDepth && prevDepth) { + BlitFramebufferDepth(prevDepth, vfb); } - prevDepth->vfb = vfb; } SetColorUpdated(vfb, skipDrawReason); @@ -469,7 +459,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfbs_.push_back(vfb); currentRenderVfb_ = vfb; - if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) { + // Assume that if we're clearing right when switching to a new framebuffer, we don't need to upload. + if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects && params.isDrawing) { gpu->PerformMemoryUpload(params.fb_address, byteSize); // Alpha was already done by PerformMemoryUpload. PerformStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO | StencilUpload::IGNORE_ALPHA); @@ -526,6 +517,9 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame NotifyRenderFramebufferUpdated(vfb, vfbFormatChanged); } + vfb->colorBindSeq = GetBindSeqCount(); + vfb->depthBindSeq = GetBindSeqCount(); + gstate_c.curRTWidth = vfb->width; gstate_c.curRTHeight = vfb->height; gstate_c.curRTRenderWidth = vfb->renderWidth; @@ -551,13 +545,6 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) { if (prevPrevDisplayFramebuf_ == v) prevPrevDisplayFramebuf_ = nullptr; - // Remove any depth buffer tracking related to this vfb. - for (auto it = trackedDepthBuffers_.begin(); it != trackedDepthBuffers_.end(); it++) { - if ((*it)->vfb == v) { - (*it)->vfb = nullptr; // Mark for deletion in the next Decimate - } - } - delete v; } @@ -619,32 +606,16 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir dst->last_frame_depth_updated = gpuStats.numFlips; } -TrackedDepthBuffer *FramebufferManagerCommon::GetOrCreateTrackedDepthBuffer(VirtualFramebuffer *vfb) { - for (auto tracked : trackedDepthBuffers_) { - // Disable tracking if color of the new vfb is clashing with tracked depth. - if (vfb->fb_address == tracked->z_address) { - tracked->vfb = nullptr; // this is checked for. Cheaper than deleting. - continue; - } - - if (vfb->z_address == tracked->z_address) { - if (vfb->z_stride == tracked->z_stride) { - return tracked; - } else { - // Stride has changed, mark as bad. - tracked->vfb = nullptr; - } +VirtualFramebuffer *FramebufferManagerCommon::GetLatestDepthBufferAt(u32 z_address, u16 z_stride) { + int maxSeq = -1; + VirtualFramebuffer *latestDepth = nullptr; + for (auto vfb : vfbs_) { + if (vfb->z_address == z_address && vfb->z_stride == z_stride && vfb->depthBindSeq > maxSeq) { + maxSeq = vfb->depthBindSeq; + latestDepth = vfb; } } - - TrackedDepthBuffer *tracked = new TrackedDepthBuffer(); - tracked->vfb = vfb; - tracked->z_address = vfb->z_address; - tracked->z_stride = vfb->z_stride; - - trackedDepthBuffers_.push_back(tracked); - - return tracked; + return latestDepth; } void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) { @@ -685,168 +656,10 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer } } -// Can't easily dynamically create these strings, we just pass along the pointer. -static const char *reinterpretStrings[3][3] = { - { - "self_reinterpret_565", - "reinterpret_565_to_5551", - "reinterpret_565_to_4444", - }, - { - "reinterpret_5551_to_565", - "self_reinterpret_5551", - "reinterpret_5551_to_4444", - }, - { - "reinterpret_4444_to_565", - "reinterpret_4444_to_5551", - "self_reinterpret_4444", - }, -}; - -void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat) { - if (!useBufferedRendering_ || !vfb->fbo) { - return; - } - - _assert_(newFormat != oldFormat); - // The caller is responsible for updating the format. - _assert_(newFormat == vfb->format); - - ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage; - - // Copy image required for now, might get rid of this later. - bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && - (lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx) && - draw_->GetDeviceCaps().framebufferCopySupported; - - if (!doReinterpret) { - // Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil. - if (oldFormat == GE_FORMAT_565) { - // We have to bind here instead of clear, since it can be that no framebuffer is bound. - // The backend can sometimes directly optimize it to a clear. - - // Games that are marked as doing reinterpret just ignore this - better to keep the data than to clear. - // Fixes #13717. - if (!PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && !PSP_CoreParameter().compat.flags().BlueToAlpha) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret"); - // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. - // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. - gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE); - - if (currentRenderVfb_ != vfb) { - // In case ReinterpretFramebuffer was called from the texture manager. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After FakeReinterpret"); - } - } - } - return; - } - - // We only reinterpret between 16 - bit formats, for now. - if (!IsGeBufferFormat16BitColor(oldFormat) || !IsGeBufferFormat16BitColor(newFormat)) { - // 16->32 and 32->16 will require some more specialized shaders. - return; - } - - char *vsCode = nullptr; - char *fsCode = nullptr; - - if (!reinterpretVS_) { - vsCode = new char[4000]; - const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); - GenerateReinterpretVertexShader(vsCode, shaderLanguageDesc); - reinterpretVS_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "reinterpret_vs"); - _assert_(reinterpretVS_); - } - - if (!reinterpretSampler_) { - Draw::SamplerStateDesc samplerDesc{}; - samplerDesc.magFilter = Draw::TextureFilter::LINEAR; - samplerDesc.minFilter = Draw::TextureFilter::LINEAR; - reinterpretSampler_ = draw_->CreateSamplerState(samplerDesc); - } - - if (!reinterpretVBuf_) { - reinterpretVBuf_ = draw_->CreateBuffer(12 * 3, Draw::BufferUsageFlag::DYNAMIC | Draw::BufferUsageFlag::VERTEXDATA); - } - - // See if we need to create a new pipeline. - - Draw::Pipeline *pipeline = reinterpretFromTo_[(int)oldFormat][(int)newFormat]; - if (!pipeline) { - fsCode = new char[4000]; - const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); - GenerateReinterpretFragmentShader(fsCode, oldFormat, newFormat, shaderLanguageDesc); - Draw::ShaderModule *reinterpretFS = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "reinterpret_fs"); - _assert_(reinterpretFS); - - std::vector shaders; - shaders.push_back(reinterpretVS_); - shaders.push_back(reinterpretFS); - - using namespace Draw; - Draw::PipelineDesc desc{}; - // We use a "fullscreen triangle". - // TODO: clear the stencil buffer. Hard to actually initialize it with the new alpha, though possible - let's see if - // we need it. - DepthStencilState *depth = draw_->CreateDepthStencilState({ false, false, Comparison::LESS }); - BlendState *blendstateOff = draw_->CreateBlendState({ false, 0xF }); - RasterState *rasterNoCull = draw_->CreateRasterState({}); - - // No uniforms for these, only a single texture input. - PipelineDesc pipelineDesc{ Primitive::TRIANGLE_LIST, shaders, nullptr, depth, blendstateOff, rasterNoCull, nullptr }; - pipeline = draw_->CreateGraphicsPipeline(pipelineDesc); - _assert_(pipeline != nullptr); - reinterpretFromTo_[(int)oldFormat][(int)newFormat] = pipeline; - - depth->Release(); - blendstateOff->Release(); - rasterNoCull->Release(); - reinterpretFS->Release(); - } - - // Copy to a temp framebuffer. - Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight); - - // Ideally on Vulkan this should be using the original framebuffer as an input attachment, allowing it to read from - // itself while writing. - draw_->InvalidateCachedState(); - draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep"); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, reinterpretStrings[(int)oldFormat][(int)newFormat]); - draw_->BindPipeline(pipeline); - draw_->BindFramebufferAsTexture(temp, 0, Draw::FBChannel::FB_COLOR_BIT, 0); - draw_->BindSamplerStates(0, 1, &reinterpretSampler_); - draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); - Draw::Viewport vp = Draw::Viewport{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; - draw_->SetViewports(1, &vp); - // Vertex buffer not used - vertices generated in shader. - // TODO: Switch to a vertex buffer for GLES2/D3D9 compat. - draw_->BindVertexBuffers(0, 1, &reinterpretVBuf_, nullptr); - draw_->Draw(3, 0); - draw_->InvalidateCachedState(); - - // Unbind. - draw_->BindTexture(0, nullptr); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - - if (currentRenderVfb_ != vfb) { - // In case ReinterpretFramebuffer was called from the texture manager. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After reinterpret"); - } - delete[] vsCode; - delete[] fsCode; -} - void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height); - vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; - vfb->firstFrameSaved = true; + vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; } else { DownloadFramebufferOnSwitch(prevVfb); } @@ -854,14 +667,14 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe shaderManager_->DirtyLastShader(); // Copy depth between the framebuffers, if the z_address is the same (checked inside.) - TrackedDepthBuffer *prevDepth = GetOrCreateTrackedDepthBuffer(vfb); + VirtualFramebuffer * prevDepth = GetLatestDepthBufferAt(vfb->z_address, vfb->z_stride); // We might already want to copy depth, in case this is a temp buffer. See #7810. - if (prevDepth->vfb != vfb) { - if (!isClearingDepth && prevDepth->vfb) { - BlitFramebufferDepth(prevDepth->vfb, vfb); + if (prevDepth != vfb) { + if (!isClearingDepth && prevDepth) { + BlitFramebufferDepth(prevDepth, vfb); } - prevDepth->vfb = vfb; + prevDepth = vfb; } if (vfb->drawnFormat != vfb->format) { @@ -1179,14 +992,13 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu } void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb) { - if (vfb && vfb->safeWidth > 0 && vfb->safeHeight > 0 && !vfb->firstFrameSaved && !vfb->memoryUpdated) { + if (vfb && vfb->safeWidth > 0 && vfb->safeHeight > 0 && !(vfb->usageFlags & FB_USAGE_FIRST_FRAME_SAVED) && !vfb->memoryUpdated) { // Some games will draw to some memory once, and use it as a render-to-texture later. // To support this, we save the first frame to memory when we have a safe w/h. // Saving each frame would be slow. if (!g_Config.bDisableSlowFramebufEffects && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight); - vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; - vfb->firstFrameSaved = true; + vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->safeWidth = 0; vfb->safeHeight = 0; } @@ -1351,8 +1163,7 @@ void FramebufferManagerCommon::DecimateFBOs() { if (ShouldDownloadFramebuffer(vfb) && age == 0 && !vfb->memoryUpdated) { ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height); - vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; - vfb->firstFrameSaved = true; + vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; } // Let's also "decimate" the usageFlags. @@ -1387,16 +1198,6 @@ void FramebufferManagerCommon::DecimateFBOs() { bvfbs_.erase(bvfbs_.begin() + i--); } } - - // Also clean up the TrackedDepthBuffer array... - for (auto it = trackedDepthBuffers_.begin(); it != trackedDepthBuffers_.end();) { - if ((*it)->vfb == nullptr) { - delete *it; - it = trackedDepthBuffers_.erase(it); - } else { - it++; - } - } } // Requires width/height to be set already. @@ -1439,7 +1240,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } if (force1x && g_Config.iInternalResolution != 1) { - vfb->renderScaleFactor = 1.0f; + vfb->renderScaleFactor = 1; vfb->renderWidth = vfb->bufferWidth; vfb->renderHeight = vfb->bufferHeight; } else { @@ -1807,7 +1608,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram nvfb->height = vfb->height; nvfb->renderWidth = vfb->bufferWidth; nvfb->renderHeight = vfb->bufferHeight; - nvfb->renderScaleFactor = 1.0f; // For readbacks we resize to the original size, of course. + nvfb->renderScaleFactor = 1; // For readbacks we resize to the original size, of course. nvfb->bufferWidth = vfb->bufferWidth; nvfb->bufferHeight = vfb->bufferHeight; nvfb->format = vfb->format; @@ -2176,7 +1977,7 @@ void FramebufferManagerCommon::ShowScreenResolution() { // * Video file recording(would probably be great if it was async.) // * Screenshots(benefit slightly from async.) // * Save state screenshots(could probably be async but need to manage the stall.) -bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) { +bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxScaleFactor) { VirtualFramebuffer *vfb = currentRenderVfb_; if (!vfb) { vfb = GetVFBAt(fb_address); @@ -2195,9 +1996,9 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB Draw::Framebuffer *bound = nullptr; if (vfb->fbo) { - if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) { - w = vfb->width * maxRes; - h = vfb->height * maxRes; + if (maxScaleFactor > 0 && vfb->renderWidth > vfb->width * maxScaleFactor) { + w = vfb->width * maxScaleFactor; + h = vfb->height * maxScaleFactor; Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::COPY, w, h); VirtualFramebuffer tempVfb = *vfb; @@ -2206,7 +2007,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB tempVfb.bufferHeight = vfb->height; tempVfb.renderWidth = w; tempVfb.renderHeight = h; - tempVfb.renderScaleFactor = (float)maxRes; + tempVfb.renderScaleFactor = maxScaleFactor; BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0, "Blit_GetFramebuffer"); bound = tempFBO; @@ -2373,6 +2174,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, // We'll pseudo-blit framebuffers here to get a resized version of vfb. if (gameUsesSequentialCopies_) { // Ignore the x/y/etc., read the entire thing. + // TODO: What game did we need this for? x = 0; y = 0; w = vfb->width; @@ -2476,7 +2278,7 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) { } } -std::vector FramebufferManagerCommon::GetFramebufferList() { +std::vector FramebufferManagerCommon::GetFramebufferList() const { std::vector list; for (size_t i = 0; i < vfbs_.size(); ++i) { @@ -2504,6 +2306,9 @@ static void DoRelease(T *&obj) { void FramebufferManagerCommon::DeviceLost() { DestroyAllFBOs(); + + presentation_->DeviceLost(); + for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { DoRelease(reinterpretFromTo_[i][j]); @@ -2512,18 +2317,14 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(reinterpretVBuf_); DoRelease(reinterpretSampler_); DoRelease(reinterpretVS_); - DoRelease(stencilUploadFs_); - DoRelease(stencilUploadVs_); DoRelease(stencilUploadSampler_); DoRelease(stencilUploadPipeline_); - DoRelease(draw2DPipelineColor_); - DoRelease(draw2DPipelineDepth_); DoRelease(draw2DSamplerNearest_); DoRelease(draw2DSamplerLinear_); DoRelease(draw2DVs_); - DoRelease(draw2DFs_); - DoRelease(draw2DFsDepth_); - presentation_->DeviceLost(); + DoRelease(draw2DPipelineColor_); + DoRelease(draw2DPipelineDepth_); + draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 5277d6a03e..7952e83827 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -43,6 +43,7 @@ enum { FB_USAGE_DOWNLOAD = 16, FB_USAGE_DOWNLOAD_CLEAR = 32, FB_USAGE_BLUE_TO_ALPHA = 64, + FB_USAGE_FIRST_FRAME_SAVED = 128, }; enum { @@ -55,6 +56,7 @@ namespace Draw { } class VulkanFBO; +class ShaderWriter; // We have to track VFBs and depth buffers together, since bits are shared between the color alpha channel // and the stencil buffer on the PSP. @@ -62,48 +64,79 @@ class VulkanFBO; // when such a situation is detected. In order to reliably detect this, we separately track depth buffers, // and they know which color buffer they were used with last. struct VirtualFramebuffer { + Draw::Framebuffer *fbo; + u32 fb_address; u32 z_address; // If 0, it's a "RAM" framebuffer. - int fb_stride; - int z_stride; - - GEBufferFormat format; // virtual, in reality they are all RGBA8888 for better quality but we can reinterpret that as necessary + u16 fb_stride; + u16 z_stride; // width/height: The detected size of the current framebuffer, in original PSP pixels. u16 width; u16 height; // bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than or equal to width/height. - // Actual physical buffer is this size times the render resolution multiplier. + // In original PSP pixels - actual framebuffer is this size times the render resolution multiplier. // The buffer may be used to render a width or height from 0 to these values without being recreated. u16 bufferWidth; u16 bufferHeight; // renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions. - // The physical buffer may be larger than renderWidth/renderHeight. + // These are simply bufferWidth/Height * renderScaleFactor and are thus redundant. u16 renderWidth; u16 renderHeight; - float renderScaleFactor; - - u16 usageFlags; - - u16 newWidth; - u16 newHeight; - - int lastFrameNewSize; - - Draw::Framebuffer *fbo; - + // Attempt to keep track of a bounding rectangle of what's been actually drawn. Coarse, but might be smaller + // than width/height if framebuffer has been enlarged. In PSP pixels. u16 drawnWidth; u16 drawnHeight; - GEBufferFormat drawnFormat; + + // The dimensions at which we are confident that we can read back this buffer without stomping on irrelevant memory. u16 safeWidth; u16 safeHeight; + // The scale factor at which we are rendering (to achieve higher resolution). + u8 renderScaleFactor; + + // The original PSP format of the framebuffer. + // In reality they are all RGBA8888 for better quality but this is what the PSP thinks it is. This is necessary + // when we need to interpret the bits directly (depal or buffer aliasing). + GEBufferFormat format; + + // The configured buffer format at the time of the latest/current draw. This will change first, then + // if different we'll "reinterpret" the framebuffer to match 'format' as needed. + GEBufferFormat drawnFormat; + + u16 usageFlags; + + // These are used to track state to try to avoid buffer size shifting back and forth. + // You might think that doesn't happen since we mostly grow framebuffers, but we do resize down, + // if the size has shrunk for a while and the framebuffer is also larger than the stride. + // At this point, the "safe" size is probably a lie, and we have had various issues with readbacks, so this resizes down to avoid them. + // An example would be a game that always uses the address 0x00154000 for temp buffers, and uses it for a full-screen effect for 3 frames, then goes back to using it for character shadows or something much smaller. + u16 newWidth; + u16 newHeight; + + // The frame number at which this was last resized. + int lastFrameNewSize; + + // Tracking for downloads-to-CLUT. + u16 clutUpdatedBytes; + bool memoryUpdated; + + // TODO: Fold into usageFlags? bool dirtyAfterDisplay; bool reallyDirtyAfterDisplay; // takes frame skipping into account + // Global sequence numbers for the last time these were bound. + // Not based on frames at all. Can be used to determine new-ness of one framebuffer over another, + // can even be within a frame. + int colorBindSeq; + int depthBindSeq; + + // These are mainly used for garbage collection purposes and similar. + // Cannot be used to determine new-ness against a similar other buffer, since they are + // only at frame granularity. int last_frame_used; int last_frame_attached; int last_frame_render; @@ -112,33 +145,19 @@ struct VirtualFramebuffer { int last_frame_failed; int last_frame_depth_updated; int last_frame_depth_render; - u32 clutUpdatedBytes; - bool memoryUpdated; - bool firstFrameSaved; -}; - -struct TrackedDepthBuffer { - u32 z_address; - int z_stride; - - // Really need to make sure we're killing these TrackedDepthBuffer's off when the VirtualFrameBuffers die. - VirtualFramebuffer *vfb; - - // Could do full tracking of which framebuffers are used with this depth buffer, - // but probably not necessary. - // std::set> seen_fbs; }; struct FramebufferHeuristicParams { u32 fb_address; - int fb_stride; u32 z_address; - int z_stride; + u16 fb_stride; + u16 z_stride; GEBufferFormat fmt; bool isClearingDepth; bool isWritingDepth; bool isDrawing; bool isModeThrough; + bool isBlending; int viewportWidth; int viewportHeight; int regionWidth; @@ -248,7 +267,7 @@ public: } } void RebindFramebuffer(const char *tag); - std::vector GetFramebufferList(); + std::vector GetFramebufferList() const; void CopyDisplayToOutput(bool reallyDirty); @@ -269,31 +288,31 @@ public: void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes); void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride); - TrackedDepthBuffer *GetOrCreateTrackedDepthBuffer(VirtualFramebuffer *vfb); + VirtualFramebuffer *GetLatestDepthBufferAt(u32 z_address, u16 z_stride); void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); size_t NumVFBs() const { return vfbs_.size(); } - u32 PrevDisplayFramebufAddr() { + u32 PrevDisplayFramebufAddr() const { return prevDisplayFramebuf_ ? prevDisplayFramebuf_->fb_address : 0; } - u32 DisplayFramebufAddr() { + u32 DisplayFramebufAddr() const { return displayFramebuf_ ? displayFramebuf_->fb_address : 0; } - u32 DisplayFramebufStride() { + u32 DisplayFramebufStride() const { return displayFramebuf_ ? displayStride_ : 0; } - GEBufferFormat DisplayFramebufFormat() { + GEBufferFormat DisplayFramebufFormat() const { return displayFramebuf_ ? displayFormat_ : GE_FORMAT_INVALID; } - bool UseBufferedRendering() { + bool UseBufferedRendering() const { return useBufferedRendering_; } - bool MayIntersectFramebuffer(u32 start) { + bool MayIntersectFramebuffer(u32 start) const { // Clear the cache/kernel bits. start = start & 0x3FFFFFFF; // Most games only have two framebuffers at the start. @@ -306,9 +325,11 @@ public: VirtualFramebuffer *GetCurrentRenderVFB() const { return currentRenderVfb_; } - // TODO: Break out into some form of FBO manager - VirtualFramebuffer *GetVFBAt(u32 addr); - VirtualFramebuffer *GetDisplayVFB() { + + // This only checks for the color channel. + VirtualFramebuffer *GetVFBAt(u32 addr) const; + + VirtualFramebuffer *GetDisplayVFB() const { return GetVFBAt(displayFramebufPtr_); } @@ -348,7 +369,7 @@ public: virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer); virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer); - const std::vector &Framebuffers() { + const std::vector &Framebuffers() const { return vfbs_; } void ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat); @@ -360,6 +381,8 @@ protected: void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel); + void Ensure2DResources(); + Draw::Pipeline *Create2DPipeline(void (*generate)(ShaderWriter &)); bool UpdateSize(); @@ -408,6 +431,10 @@ protected: dstBuffer->reallyDirtyAfterDisplay = true; } + inline int GetBindSeqCount() { + return fbBindSeqCount_++; + } + PresentationCommon *presentation_ = nullptr; Draw::DrawContext *draw_ = nullptr; @@ -420,9 +447,11 @@ protected: u32 displayFramebufPtr_ = 0; u32 displayStride_ = 0; - GEBufferFormat displayFormat_; + GEBufferFormat displayFormat_ = GE_FORMAT_565; u32 prevDisplayFramebufPtr_ = 0; + int fbBindSeqCount_ = 0; + VirtualFramebuffer *displayFramebuf_ = nullptr; VirtualFramebuffer *prevDisplayFramebuf_ = nullptr; VirtualFramebuffer *prevPrevDisplayFramebuf_ = nullptr; @@ -440,16 +469,15 @@ protected: std::vector vfbs_; std::vector bvfbs_; // blitting framebuffers (for download) - std::vector trackedDepthBuffers_; - bool gameUsesSequentialCopies_ = false; // Sampled in BeginFrame/UpdateSize for safety. float renderWidth_ = 0.0f; float renderHeight_ = 0.0f; - float renderScaleFactor_ = 1.0f; - int pixelWidth_; - int pixelHeight_; + + int renderScaleFactor_ = 1; + int pixelWidth_ = 0; + int pixelHeight_ = 0; int bloomHack_ = 0; Draw::DataFormat preferredPixelsFormat_ = Draw::DataFormat::R8G8B8A8_UNORM; @@ -477,11 +505,9 @@ protected: Draw::SamplerState *reinterpretSampler_ = nullptr; Draw::Buffer *reinterpretVBuf_ = nullptr; - // Common implementation of stencil buffer upload. Also not 100% optimal, but not perforamnce + // Common implementation of stencil buffer upload. Also not 100% optimal, but not performance // critical either. Draw::Pipeline *stencilUploadPipeline_ = nullptr; - Draw::ShaderModule *stencilUploadVs_ = nullptr; - Draw::ShaderModule *stencilUploadFs_ = nullptr; Draw::SamplerState *stencilUploadSampler_ = nullptr; // Draw2D pipelines @@ -490,6 +516,5 @@ protected: Draw::SamplerState *draw2DSamplerLinear_ = nullptr; Draw::SamplerState *draw2DSamplerNearest_ = nullptr; Draw::ShaderModule *draw2DVs_ = nullptr; - Draw::ShaderModule *draw2DFs_ = nullptr; - Draw::ShaderModule *draw2DFsDepth_ = nullptr; + // The fragment shaders are "owned" by the pipelines since they're 1:1. }; diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index 71b0b24910..b453a4d3d6 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -4,7 +4,10 @@ #include "Common/GPU/ShaderWriter.h" #include "Common/Log.h" #include "Common/GPU/thin3d.h" +#include "Core/System.h" #include "GPU/Common/ReinterpretFramebuffer.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/TextureCacheCommon.h" static const VaryingDef varyings[1] = { { "vec2", "v_texcoord", Draw::SEM_TEXCOORD0, 0, "highp" }, @@ -17,12 +20,10 @@ static const SamplerDef samplers[1] = { // TODO: We could possibly have an option to preserve any extra color precision? But gonna start without it. // Requires full size integer math. It would be possible to make a floating point-only version with lots of // modulo and stuff, might do it one day. -bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) { - if (!lang.bitwiseOps) { - return false; - } +void GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) { + _assert_(lang.bitwiseOps); - ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + ShaderWriter writer(buffer, lang, ShaderStage::Fragment); writer.HighPrecisionFloat(); @@ -69,24 +70,172 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff } writer.EndFSMain("outColor", FSFLAG_NONE); - return true; } -bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang) { - if (!lang.bitwiseOps) { - return false; - } - ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); +void GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang) { + _assert_(lang.bitwiseOps); + ShaderWriter writer(buffer, lang, ShaderStage::Vertex); writer.BeginVSMain(Slice::empty(), Slice::empty(), varyings); writer.C(" float x = -1.0 + float((gl_VertexIndex & 1) << 2);\n"); writer.C(" float y = -1.0 + float((gl_VertexIndex & 2) << 1);\n"); writer.C(" v_texcoord = (vec2(x, y) + vec2(1.0, 1.0)) * 0.5;\n"); - if (strlen(lang.viewportYSign)) { - writer.F(" y *= %s1.0;\n", lang.viewportYSign); - } writer.C(" gl_Position = vec4(x, y, 0.0, 1.0);\n"); writer.EndVSMain(varyings); - return true; +} + + +// Can't easily dynamically create these strings, we just pass along the pointer. +static const char *reinterpretStrings[3][3] = { + { + "self_reinterpret_565", + "reinterpret_565_to_5551", + "reinterpret_565_to_4444", + }, + { + "reinterpret_5551_to_565", + "self_reinterpret_5551", + "reinterpret_5551_to_4444", + }, + { + "reinterpret_4444_to_565", + "reinterpret_4444_to_5551", + "self_reinterpret_4444", + }, +}; + +void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat) { + if (!useBufferedRendering_ || !vfb->fbo) { + return; + } + + _assert_(newFormat != oldFormat); + // The caller is responsible for updating the format. + _assert_(newFormat == vfb->format); + + ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage; + + // Copy image required for now, might get rid of this later. + bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && + (lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx) && + draw_->GetDeviceCaps().framebufferCopySupported; + + if (!doReinterpret) { + // Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil. + if (oldFormat == GE_FORMAT_565) { + // We have to bind here instead of clear, since it can be that no framebuffer is bound. + // The backend can sometimes directly optimize it to a clear. + + // Games that are marked as doing reinterpret just ignore this - better to keep the data than to clear. + // Fixes #13717. + if (!PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && !PSP_CoreParameter().compat.flags().BlueToAlpha) { + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret"); + // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. + // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. + gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE); + + if (currentRenderVfb_ != vfb) { + // In case ReinterpretFramebuffer was called from the texture manager. + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After FakeReinterpret"); + } + } + } + return; + } + + // We only reinterpret between 16 - bit formats, for now. + if (!IsGeBufferFormat16BitColor(oldFormat) || !IsGeBufferFormat16BitColor(newFormat)) { + // 16->32 and 32->16 will require some more specialized shaders. + return; + } + + if (!reinterpretVS_) { + char *vsCode = new char[4000]; + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + GenerateReinterpretVertexShader(vsCode, shaderLanguageDesc); + reinterpretVS_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "reinterpret_vs"); + _assert_(reinterpretVS_); + delete[] vsCode; + } + + if (!reinterpretSampler_) { + Draw::SamplerStateDesc samplerDesc{}; + samplerDesc.magFilter = Draw::TextureFilter::LINEAR; + samplerDesc.minFilter = Draw::TextureFilter::LINEAR; + reinterpretSampler_ = draw_->CreateSamplerState(samplerDesc); + } + + if (!reinterpretVBuf_) { + reinterpretVBuf_ = draw_->CreateBuffer(12 * 3, Draw::BufferUsageFlag::DYNAMIC | Draw::BufferUsageFlag::VERTEXDATA); + } + + // See if we need to create a new pipeline. + + Draw::Pipeline *pipeline = reinterpretFromTo_[(int)oldFormat][(int)newFormat]; + if (!pipeline) { + char *fsCode = new char[4000]; + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + GenerateReinterpretFragmentShader(fsCode, oldFormat, newFormat, shaderLanguageDesc); + Draw::ShaderModule *reinterpretFS = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "reinterpret_fs"); + _assert_(reinterpretFS); + delete[] fsCode; + + std::vector shaders; + shaders.push_back(reinterpretVS_); + shaders.push_back(reinterpretFS); + + using namespace Draw; + Draw::PipelineDesc desc{}; + // We use a "fullscreen triangle". + // TODO: clear the stencil buffer. Hard to actually initialize it with the new alpha, though possible - let's see if + // we need it. + DepthStencilState *depth = draw_->CreateDepthStencilState({ false, false, Comparison::LESS }); + BlendState *blendstateOff = draw_->CreateBlendState({ false, 0xF }); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + // No uniforms for these, only a single texture input. + PipelineDesc pipelineDesc{ Primitive::TRIANGLE_LIST, shaders, nullptr, depth, blendstateOff, rasterNoCull, nullptr }; + pipeline = draw_->CreateGraphicsPipeline(pipelineDesc); + _assert_(pipeline != nullptr); + reinterpretFromTo_[(int)oldFormat][(int)newFormat] = pipeline; + + depth->Release(); + blendstateOff->Release(); + rasterNoCull->Release(); + reinterpretFS->Release(); + } + + // Copy to a temp framebuffer. + Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight); + + // Ideally on Vulkan this should be using the original framebuffer as an input attachment, allowing it to read from + // itself while writing. + draw_->InvalidateCachedState(); + draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep"); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, reinterpretStrings[(int)oldFormat][(int)newFormat]); + draw_->BindPipeline(pipeline); + draw_->BindFramebufferAsTexture(temp, 0, Draw::FBChannel::FB_COLOR_BIT, 0); + draw_->BindSamplerStates(0, 1, &reinterpretSampler_); + draw_->SetScissorRect(0, 0, vfb->renderWidth, vfb->renderHeight); + Draw::Viewport vp = Draw::Viewport{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; + draw_->SetViewports(1, &vp); + // Vertex buffer not used - vertices generated in shader. + // TODO: Switch to a vertex buffer for GLES2/D3D9 compat. + draw_->BindVertexBuffers(0, 1, &reinterpretVBuf_, nullptr); + draw_->Draw(3, 0); + draw_->InvalidateCachedState(); + + // Unbind. + draw_->BindTexture(0, nullptr); + + shaderManager_->DirtyLastShader(); + textureCache_->ForgetLastTexture(); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + + if (currentRenderVfb_ != vfb) { + // In case ReinterpretFramebuffer was called from the texture manager. + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After reinterpret"); + } } diff --git a/GPU/Common/ReinterpretFramebuffer.h b/GPU/Common/ReinterpretFramebuffer.h index e45472a321..5819366887 100644 --- a/GPU/Common/ReinterpretFramebuffer.h +++ b/GPU/Common/ReinterpretFramebuffer.h @@ -4,8 +4,8 @@ #include "GPU/GPUCommon.h" #include "Common/GPU/ShaderWriter.h" -bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang); +void GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang); // Just a single one. Can probably be shared with a lot of similar use cases. // Generates the coordinates for a fullscreen triangle. -bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang); +void GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang); diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 950c84dd35..5cd0f9d795 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -123,7 +123,6 @@ void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners. } writer.C(" gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);\n"); - writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); writer.EndVSMain(varyings); } @@ -208,10 +207,10 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); GenerateStencilVs(vsCode, shaderLanguageDesc); - stencilUploadFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs"); - stencilUploadVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs"); + ShaderModule *stencilUploadFs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs"); + ShaderModule *stencilUploadVs = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs"); - _assert_(stencilUploadFs_ && stencilUploadVs_); + _assert_(stencilUploadFs && stencilUploadVs); InputLayoutDesc desc = { { @@ -235,7 +234,7 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU PipelineDesc stencilWriteDesc{ Primitive::TRIANGLE_LIST, - { stencilUploadVs_, stencilUploadFs_ }, + { stencilUploadVs, stencilUploadFs }, inputLayout, stencilWrite, blendOff, rasterNoCull, &stencilUBDesc, }; stencilUploadPipeline_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); @@ -249,6 +248,9 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU stencilWrite->Release(); inputLayout->Release(); + stencilUploadFs->Release(); + stencilUploadVs->Release(); + SamplerStateDesc descNearest{}; stencilUploadSampler_ = draw_->CreateSamplerState(descNearest); } diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 599e5718fa..f05bc499fe 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -20,74 +20,14 @@ #include #include "Common/Common.h" -#include "Common/Data/Convert/ColorConv.h" #include "Common/GPU/thin3d.h" -#include "Core/MemMap.h" -#include "Core/Config.h" -#include "Core/ConfigValues.h" -#include "Core/System.h" -#include "Core/Reporting.h" -#include "GPU/ge_constants.h" -#include "GPU/GPUState.h" -#include "GPU/Debugger/Stepping.h" #include "GPU/Common/FramebufferManagerCommon.h" #include "GPU/Common/PresentationCommon.h" -#include "GPU/Common/TextureDecoder.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" -#include "GPU/D3D11/ShaderManagerD3D11.h" -#include "GPU/D3D11/TextureCacheD3D11.h" -#include "GPU/D3D11/DrawEngineD3D11.h" - -#ifdef _M_SSE -#include -#endif FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) : FramebufferManagerCommon(draw) { - device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); - context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); - featureLevel_ = (D3D_FEATURE_LEVEL)draw->GetNativeObject(Draw::NativeObject::FEATURE_LEVEL); - presentation_->SetLanguage(HLSL_D3D11); preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM; } - -static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { - size_t x = 0; - -#ifdef _M_SSE - size_t sseSize = (c / 4) * 4; - const __m128i srcMask = _mm_set1_epi32(0x00FFFFFF); - const __m128i dstMask = _mm_set1_epi32(0xFF000000); - __m128i *dst = (__m128i *)dstp; - const __m128i *src = (const __m128i *)srcp; - - for (; x < sseSize; x += 4) { - const __m128i bits24 = _mm_and_si128(_mm_load_si128(src), srcMask); - const __m128i bits8 = _mm_and_si128(_mm_load_si128(dst), dstMask); - _mm_store_si128(dst, _mm_or_si128(bits24, bits8)); - dst++; - src++; - } -#endif - - // Copy the remaining pixels that didn't fit in SSE. - for (; x < c; ++x) { - memcpy(dstp + x, srcp + x, 3); - } -} - -// Nobody calls this yet. -void FramebufferManagerD3D11::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; - } - - const u32 z_address = vfb->z_address; - // TODO -} - -void FramebufferManagerD3D11::EndFrame() { -} diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 17ba33ec58..fc280e9de6 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -34,13 +34,4 @@ class ShaderManagerD3D11; class FramebufferManagerD3D11 : public FramebufferManagerCommon { public: FramebufferManagerD3D11(Draw::DrawContext *draw); - - void EndFrame(); - -private: - void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); - - ID3D11Device *device_; - ID3D11DeviceContext *context_; - D3D_FEATURE_LEVEL featureLevel_; }; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 23798640ee..ba41521fde 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -232,7 +232,6 @@ void GPU_D3D11::BeginFrame() { textureCacheD3D11_->StartFrame(); drawEngine_.BeginFrame(); - // fragmentTestCache_.Decimate(); shaderManagerD3D11_->DirtyLastShader(); @@ -255,9 +254,7 @@ void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) { context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF); framebufferManagerD3D11_->CopyDisplayToOutput(reallyDirty); - framebufferManagerD3D11_->EndFrame(); - // shaderManager_->EndFrame(); shaderManagerD3D11_->DirtyLastShader(); gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); diff --git a/GPU/Debugger/Playback.cpp b/GPU/Debugger/Playback.cpp index 8fa93e7d7c..aa34ce3ccf 100644 --- a/GPU/Debugger/Playback.cpp +++ b/GPU/Debugger/Playback.cpp @@ -367,6 +367,7 @@ bool DumpExecute::SubmitCmds(const void *p, u32 sz) { Memory::Write_U32((GE_CMD_JUMP << 24) | (execListBuf & 0x00FFFFFF), execListPos + 4); execListPos = execListBuf; + lastBase_ = execListBuf & 0xFF000000; // Don't continue until we've stalled. SyncStall(); @@ -450,9 +451,9 @@ void DumpExecute::Vertices(u32 ptr, u32 sz) { return; } - if (lastBase_ != (psp & 0x0FF000000)) { + if (lastBase_ != (psp & 0xFF000000)) { execListQueue.push_back((GE_CMD_BASE << 24) | ((psp >> 8) & 0x00FF0000)); - lastBase_ = psp & 0x0FF000000; + lastBase_ = psp & 0xFF000000; } execListQueue.push_back((GE_CMD_VADDR << 24) | (psp & 0x00FFFFFF)); } @@ -464,9 +465,9 @@ void DumpExecute::Indices(u32 ptr, u32 sz) { return; } - if (lastBase_ != (psp & 0x0FF000000)) { + if (lastBase_ != (psp & 0xFF000000)) { execListQueue.push_back((GE_CMD_BASE << 24) | ((psp >> 8) & 0x00FF0000)); - lastBase_ = psp & 0x0FF000000; + lastBase_ = psp & 0xFF000000; } execListQueue.push_back((GE_CMD_IADDR << 24) | (psp & 0x00FFFFFF)); } diff --git a/GPU/Debugger/Record.cpp b/GPU/Debugger/Record.cpp index 100e0dd3c4..0a15fb8f43 100644 --- a/GPU/Debugger/Record.cpp +++ b/GPU/Debugger/Record.cpp @@ -29,6 +29,7 @@ #include "Common/Thread/ParallelLoop.h" #include "Common/Log.h" #include "Common/StringUtils.h" +#include "Common/System/System.h" #include "Core/Core.h" #include "Core/ELF/ParamSFO.h" diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index d69c03da21..ffad2bd469 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -42,8 +42,6 @@ #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/GPU_DX9.h" -namespace DX9 { - static const D3DPRIMITIVETYPE d3d_prim[8] = { // Points, which are expanded to triangles. D3DPT_TRIANGLELIST, @@ -248,7 +246,7 @@ void DrawEngineDX9::MarkUnreliable(VertexArrayInfoDX9 *vai) { } void DrawEngineDX9::ClearTrackedVertexArrays() { - vai_.Iterate([&](uint32_t hash, DX9::VertexArrayInfoDX9 *vai) { + vai_.Iterate([&](uint32_t hash, VertexArrayInfoDX9 *vai) { delete vai; }); vai_.Clear(); @@ -264,7 +262,7 @@ void DrawEngineDX9::DecimateTrackedVertexArrays() { const int threshold = gpuStats.numFlips - VAI_KILL_AGE; const int unreliableThreshold = gpuStats.numFlips - VAI_UNRELIABLE_KILL_AGE; int unreliableLeft = VAI_UNRELIABLE_KILL_MAX; - vai_.Iterate([&](uint32_t hash, DX9::VertexArrayInfoDX9 *vai) { + vai_.Iterate([&](uint32_t hash, VertexArrayInfoDX9 *vai) { bool kill; if (vai->status == VertexArrayInfoDX9::VAI_UNRELIABLE) { // We limit killing unreliable so we don't rehash too often. @@ -524,7 +522,7 @@ rotateVBO: ApplyDrawState(prim); ApplyDrawStateLate(); - DX9::VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat); + VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat); IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); if (pHardwareVertexDecl) { @@ -616,7 +614,7 @@ rotateVBO: ApplyDrawStateLate(); - DX9::VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat); + VSShader *vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat); if (result.action == SW_DRAW_PRIMITIVES) { if (result.setStencil) { @@ -686,5 +684,3 @@ rotateVBO: void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) { // TODO } - -} // namespace diff --git a/GPU/Directx9/DrawEngineDX9.h b/GPU/Directx9/DrawEngineDX9.h index f0963beb91..616620a412 100644 --- a/GPU/Directx9/DrawEngineDX9.h +++ b/GPU/Directx9/DrawEngineDX9.h @@ -30,8 +30,6 @@ struct DecVtxFormat; struct UVScale; -namespace DX9 { - class VSShader; class ShaderManagerDX9; class TextureCacheDX9; @@ -175,5 +173,3 @@ private: int lastRenderStepId_ = -1; }; - -} // namespace diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index dab35117dc..610940584c 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -45,7 +45,7 @@ #include #endif -namespace DX9 { +// TODO: De-indent, the day we move all this readback stuff to GPU/Common FramebufferManagerDX9::FramebufferManagerDX9(Draw::DrawContext *draw) : FramebufferManagerCommon(draw) { @@ -223,9 +223,6 @@ namespace DX9 { } } - void FramebufferManagerDX9::EndFrame() { - } - void FramebufferManagerDX9::DecimateFBOs() { FramebufferManagerCommon::DecimateFBOs(); for (auto it = offscreenSurfaces_.begin(); it != offscreenSurfaces_.end(); ) { @@ -399,5 +396,3 @@ namespace DX9 { return success; } - -} // namespace DX9 diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 141f719310..4835ded4d1 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -28,8 +28,6 @@ #include "GPU/GPUCommon.h" #include "GPU/Common/FramebufferManagerCommon.h" -namespace DX9 { - class TextureCacheDX9; class DrawEngineDX9; class ShaderManagerDX9; @@ -41,8 +39,6 @@ public: void DestroyAllFBOs() override; - void EndFrame(); - bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; @@ -69,5 +65,3 @@ private: std::unordered_map offscreenSurfaces_; }; - -} diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index fe2cf594fd..c3f4476fcb 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -49,8 +49,6 @@ #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/sceGe.h" -namespace DX9 { - GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), drawEngine_(draw) { @@ -280,7 +278,6 @@ void GPU_DX9::ReapplyGfxState() { void GPU_DX9::BeginFrame() { textureCacheDX9_->StartFrame(); drawEngine_.BeginFrame(); - // fragmentTestCache_.Decimate(); GPUCommon::BeginFrame(); shaderManagerDX9_->DirtyShader(); @@ -300,9 +297,7 @@ void GPU_DX9::CopyDisplayToOutput(bool reallyDirty) { drawEngine_.Flush(); framebufferManagerDX9_->CopyDisplayToOutput(reallyDirty); - framebufferManagerDX9_->EndFrame(); - // shaderManager_->EndFrame(); shaderManagerDX9_->DirtyLastShader(); gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); @@ -396,5 +391,3 @@ std::string GPU_DX9::DebugGetShaderString(std::string id, DebugShaderType type, return shaderManagerDX9_->DebugGetShaderString(id, type, stringType); } } - -} // namespace DX9 diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 7c6100925a..349d2bd0a8 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -26,8 +26,6 @@ #include "GPU/Common/DepalettizeCommon.h" #include "GPU/Common/VertexDecoderCommon.h" -namespace DX9 { - class ShaderManagerDX9; class LinkedShaderDX9; class TextureCacheDX9; @@ -80,7 +78,3 @@ private: DrawEngineDX9 drawEngine_; ShaderManagerDX9 *shaderManagerDX9_; }; - -} // namespace DX9 - -typedef DX9::GPU_DX9 DIRECTX9_GPU; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 99be9bd2ee..7cae12bb53 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -49,8 +49,6 @@ using namespace Lin; -namespace DX9 { - PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : id_(id) { source_ = code; #ifdef SHADERLOG @@ -702,5 +700,3 @@ std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderTy return "N/A"; } } - -} // namespace diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 3c1e42d1fd..04cdf79544 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -27,8 +27,6 @@ #include "GPU/Common/ShaderId.h" #include "Common/Math/lin/matrix4x4.h" -namespace DX9 { - class PSShader; class VSShader; @@ -126,5 +124,3 @@ private: typedef std::map VSCache; VSCache vsCache_; }; - -}; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 018d3253ed..0de9c1774d 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -32,8 +32,6 @@ #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/FramebufferManagerDX9.h" -namespace DX9 { - static const D3DBLEND dxBlendFactorLookup[(size_t)BlendFactor::COUNT] = { D3DBLEND_ZERO, D3DBLEND_ONE, @@ -298,5 +296,3 @@ void DrawEngineDX9::ApplyDrawStateLate() { // 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)? } - -} diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 82ec19ceb6..1394183f1b 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -51,8 +51,6 @@ D3DFORMAT ToD3D9Format(Draw::DataFormat fmt) { } } -namespace DX9 { - #define INVALID_TEX (LPDIRECT3DTEXTURE9)(-1) static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { @@ -443,5 +441,3 @@ bool TextureCacheDX9::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) return success; } - -}; diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h index 925d28982a..47005cbd5c 100644 --- a/GPU/Directx9/TextureCacheDX9.h +++ b/GPU/Directx9/TextureCacheDX9.h @@ -26,8 +26,6 @@ struct VirtualFramebuffer; class DepalShaderCache; -namespace DX9 { - class FramebufferManagerDX9; class ShaderManagerDX9; @@ -78,5 +76,3 @@ private: }; D3DFORMAT getClutDestFormat(GEPaletteFormat format); - -}; diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index ef761de10f..e5bcc20bf9 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -84,7 +84,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int // 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)); + const int packWidth = std::min((int)vfb->z_stride, std::min(x + w, (int)vfb->width)); if (!convBuf_ || convBufSize_ < bufSize) { delete[] convBuf_; @@ -97,6 +97,8 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int const bool useColorPath = gl_extensions.IsGLES; bool format16Bit = false; + GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + if (useColorPath) { if (!depthDownloadProgram_) { std::string errorString; @@ -104,8 +106,8 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int 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")); + 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" }); @@ -116,9 +118,9 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int 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, false); + depthDownloadProgram_ = render->CreateProgram(shaders, semantics, queries, inits, false, false); for (auto iter : shaders) { - render_->DeleteShader(iter); + render->DeleteShader(iter); } if (!depthDownloadProgram_) { ERROR_LOG_REPORT(G3D, "Failed to compile depthDownloadProgram! This shouldn't happen.\n%s", errorString.c_str()); @@ -128,26 +130,26 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight); draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "PackDepthbuffer"); - render_->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); + render->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); // 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, GL_FALSE); - render_->BindProgram(depthDownloadProgram_); + render->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight }); + render->SetDepth(false, false, GL_ALWAYS); + render->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, 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); + 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); + 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); + 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); + render->SetUniformF(&u_depthDownloadTo8, 4, to8); draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); float u1 = 1.0f; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index f9e04803a7..9d1dc8d3dd 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -36,12 +36,10 @@ #include "GPU/Debugger/Stepping.h" #include "GPU/GLES/FramebufferManagerGLES.h" #include "GPU/GLES/TextureCacheGLES.h" -#include "GPU/GLES/DrawEngineGLES.h" #include "GPU/GLES/ShaderManagerGLES.h" -FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) : - FramebufferManagerCommon(draw), - render_(render) +FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw) : + FramebufferManagerCommon(draw) { needBackBufferYSwap_ = true; presentation_->SetLanguage(draw_->GetShaderLanguageDesc().shaderLanguage); @@ -51,10 +49,6 @@ FramebufferManagerGLES::~FramebufferManagerGLES() { delete[] convBuf_; } -void FramebufferManagerGLES::Init() { - FramebufferManagerCommon::Init(); -} - void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { _assert_msg_(nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer"); @@ -67,26 +61,19 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) } } -void FramebufferManagerGLES::EndFrame() { -} - void FramebufferManagerGLES::DeviceLost() { FramebufferManagerCommon::DeviceLost(); if (depthDownloadProgram_) { - render_->DeleteProgram(depthDownloadProgram_); + GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + render->DeleteProgram(depthDownloadProgram_); depthDownloadProgram_ = nullptr; } } -void FramebufferManagerGLES::DeviceRestore(Draw::DrawContext *draw) { - FramebufferManagerCommon::DeviceRestore(draw); - render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); -} - void FramebufferManagerGLES::Resized() { FramebufferManagerCommon::Resized(); - - render_->Resize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + render->Resize(PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); } bool FramebufferManagerGLES::GetOutputFramebuffer(GPUDebugBuffer &buffer) { diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index b859aefd9c..eb5354b60e 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -18,30 +18,21 @@ #pragma once #include "Common/GPU/thin3d.h" -// Keeps track of allocated FBOs. -// Also provides facilities for drawing and later converting raw -// pixel data. - #include "GPU/GPUCommon.h" #include "GPU/Common/FramebufferManagerCommon.h" -#include "Common/GPU/OpenGL/GLRenderManager.h" -struct GLSLProgram; class TextureCacheGLES; class DrawEngineGLES; class ShaderManagerGLES; +class GLRProgram; class FramebufferManagerGLES : public FramebufferManagerCommon { public: - FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render); + FramebufferManagerGLES(Draw::DrawContext *draw); ~FramebufferManagerGLES(); - virtual void Init() override; - void EndFrame(); void Resized() override; - void DeviceLost() override; - void DeviceRestore(Draw::DrawContext *draw) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; @@ -51,8 +42,6 @@ protected: private: void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); - GLRenderManager *render_; - u8 *convBuf_ = nullptr; u32 convBufSize_ = 0; @@ -61,6 +50,4 @@ private: int u_depthDownloadFactor = -1; int u_depthDownloadShift = -1; int u_depthDownloadTo8 = -1; - - DrawEngineGLES *drawEngineGL_ = nullptr; }; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index a18a9cb556..f774e4bebd 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -57,10 +57,8 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw) UpdateVsyncInterval(true); CheckGPUFeatures(); - GLRenderManager *render = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - shaderManagerGL_ = new ShaderManagerGLES(draw); - framebufferManagerGL_ = new FramebufferManagerGLES(draw, render); + framebufferManagerGL_ = new FramebufferManagerGLES(draw); framebufferManager_ = framebufferManagerGL_; textureCacheGL_ = new TextureCacheGLES(draw); textureCache_ = textureCacheGL_; @@ -375,7 +373,6 @@ void GPU_GLES::CopyDisplayToOutput(bool reallyDirty) { shaderManagerGL_->DirtyLastShader(); framebufferManagerGL_->CopyDisplayToOutput(reallyDirty); - framebufferManagerGL_->EndFrame(); } void GPU_GLES::FinishDeferred() { diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 958b2b08f1..ed6a553c7e 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -83,7 +83,7 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { break; case GPUCORE_DIRECTX9: #if PPSSPP_API(D3D9) - SetGPU(new DIRECTX9_GPU(ctx, draw)); + SetGPU(new GPU_DX9(ctx, draw)); break; #else return false; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 2996348b54..a0deb403aa 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2969,7 +2969,7 @@ bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false; } -std::vector GPUCommon::GetFramebufferList() { +std::vector GPUCommon::GetFramebufferList() const { return framebufferManager_->GetFramebufferList(); } diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 9a9db7b062..59298d8e92 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -230,11 +230,11 @@ public: const std::list& GetDisplayLists() override { return dlQueue; } - std::vector GetFramebufferList() override; + std::vector GetFramebufferList() const override; void ClearShaderCache() override {} void CleanupBeforeUI() override {} - s64 GetListTicks(int listid) override { + s64 GetListTicks(int listid) const override { if (listid >= 0 && listid < DisplayListMaxCount) { return dls[listid].waitTicks; } diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 1d2c74021a..832897f598 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -253,8 +253,8 @@ public: virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) = 0; virtual const std::list& GetDisplayLists() = 0; // TODO: Currently Qt only, needs to be cleaned up. - virtual std::vector GetFramebufferList() = 0; - virtual s64 GetListTicks(int listid) = 0; + virtual std::vector GetFramebufferList() const = 0; + virtual s64 GetListTicks(int listid) const = 0; // For debugging. The IDs returned are opaque, do not poke in them or display them in any way. virtual std::vector DebugGetShaderIDs(DebugShaderType type) = 0; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 3c22dc9f5b..b765df8404 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -813,6 +813,9 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector 0 && (gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { const u8 *inds = Memory::GetPointer(gstate_c.indexAddr); const u16_le *inds16 = (const u16_le *)inds; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index e50e6477ba..7be943ed63 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -531,10 +531,6 @@ void DrawEngineVulkan::DoFlush() { gpuStats.numFlushes++; - // TODO: Needs to be behind a check for changed render pass, at an appropriate time in this function. - // Similar issues as with the lastRenderStepId_ check. Will need a bit of a rethink. - lastPipeline_ = nullptr; - // If have a new render pass, dirty our dynamic state so it gets re-set. // We have to do this again after the last possible place in DoFlush that can cause a renderpass switch // like a shader blend blit or similar. But before we actually set the state! @@ -544,6 +540,7 @@ void DrawEngineVulkan::DoFlush() { gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); textureCache_->ForgetLastTexture(); lastRenderStepId_ = curRenderStepId; + lastPipeline_ = nullptr; } bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE; diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 1f3f258932..7748f24371 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -79,18 +79,3 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo SetDepthUpdated(); } } - -void FramebufferManagerVulkan::BeginFrameVulkan() { - BeginFrame(); -} - -void FramebufferManagerVulkan::EndFrame() { -} - -void FramebufferManagerVulkan::DeviceLost() { - FramebufferManagerCommon::DeviceLost(); -} - -void FramebufferManagerVulkan::DeviceRestore(Draw::DrawContext *draw) { - FramebufferManagerCommon::DeviceRestore(draw); -} diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index a303338320..0f5d7c4f53 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -36,12 +36,6 @@ public: FramebufferManagerVulkan(Draw::DrawContext *draw); ~FramebufferManagerVulkan(); - void BeginFrameVulkan(); // there's a BeginFrame in the base class, which this calls - void EndFrame(); - - void DeviceLost() override; - void DeviceRestore(Draw::DrawContext *draw) override; - // If within a render pass, this will just issue a regular clear. If beginning a new render pass, // do that. void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index a421e209c3..7d2dc8b5c0 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -317,7 +317,7 @@ void GPU_Vulkan::BeginHostFrame() { frame.push_->Reset(); frame.push_->Begin(vulkan); - framebufferManagerVulkan_->BeginFrameVulkan(); + framebufferManagerVulkan_->BeginFrame(); textureCacheVulkan_->SetPushBuffer(frameData_[curFrame].push_); shaderManagerVulkan_->DirtyShader(); @@ -339,7 +339,6 @@ void GPU_Vulkan::EndHostFrame() { frame.push_->End(); drawEngine_.EndFrame(); - framebufferManagerVulkan_->EndFrame(); textureCacheVulkan_->EndFrame(); draw_->InvalidateCachedState(); diff --git a/GPU/ge_constants.h b/GPU/ge_constants.h index 954934dcab..78363c3879 100644 --- a/GPU/ge_constants.h +++ b/GPU/ge_constants.h @@ -17,6 +17,8 @@ #pragma once +#include + enum GECommand { GE_CMD_NOP = 0, GE_CMD_VADDR = 0x1, @@ -276,8 +278,7 @@ enum GECommand { GE_CMD_NOP_FF = 0xFF, }; -enum GEBufferFormat -{ +enum GEBufferFormat : uint8_t { GE_FORMAT_565 = 0, GE_FORMAT_5551 = 1, GE_FORMAT_4444 = 2, diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index ec612d1182..da966cabae 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -388,6 +388,10 @@ int System_GetPropertyInt(SystemProperty prop) { return KEYBOARD_LAYOUT_QWERTZ; return KEYBOARD_LAYOUT_QWERTY; } + case SYSPROP_DISPLAY_XRES: + return g_DesktopWidth; + case SYSPROP_DISPLAY_YRES: + return g_DesktopHeight; default: return -1; } @@ -1240,7 +1244,7 @@ int main(int argc, char *argv[]) { #endif glslang::FinalizeProcess(); - printf("Leaving main"); + printf("Leaving main\n"); #ifdef HAVE_LIBNX socketExit(); #endif diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index ead36b0743..e4ed18b8f2 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -32,7 +32,6 @@ #include "XAudioSoundStream.h" #include "UWPHost.h" #include "UWPUtil.h" -#include "StorageFileLoader.h" #include "App.h" using namespace UWP; @@ -304,11 +303,6 @@ void PPSSPP_UWPMain::OnSuspend() { // TODO } -void PPSSPP_UWPMain::LoadStorageFile(StorageFile ^file) { - std::unique_ptr factory(new StorageFileLoaderFactory(file, IdentifiedFileType::PSP_ISO)); - RegisterFileLoaderFactory("override://", std::move(factory)); - NativeMessageReceived("boot", "override://file"); -} UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr resources) { std::vector adapterNames; @@ -457,13 +451,14 @@ void System_SendMessage(const char *command, const char *parameter) { picker->FileTypeFilter->Append(".iso"); // Can't load these this way currently, they require mounting the underlying folder. - // picker->FileTypeFilter->Append(".bin"); - // picker->FileTypeFilter->Append(".elf"); + picker->FileTypeFilter->Append(".bin"); + picker->FileTypeFilter->Append(".elf"); picker->SuggestedStartLocation = Pickers::PickerLocationId::DocumentsLibrary; create_task(picker->PickSingleFileAsync()).then([](StorageFile ^file){ if (file) { - g_main->LoadStorageFile(file); + std::string path = FromPlatformString(file->Path); + NativeMessageReceived("boot", path.c_str()); } }); } else if (!strcmp(command, "toggle_fullscreen")) { diff --git a/UWP/StorageFileLoader.cpp b/UWP/StorageFileLoader.cpp deleted file mode 100644 index 8e831a8787..0000000000 --- a/UWP/StorageFileLoader.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "pch.h" -#include "ppltasks.h" - -#include "Common/Log.h" -#include "Common/File/FileUtil.h" -#include "Common/File/Path.h" -#include "Common/File/DirListing.h" -#include "Common/Thread/ThreadUtil.h" -#include "StorageFileLoader.h" -#include "Common/Log.h" -#include "UWPUtil.h" - -using namespace Concurrency; -using namespace Windows::Storage; -using namespace Windows::Storage::Streams; - -// Not sure how necessary this one is. -static std::mutex initMutex; - -StorageFileLoader::StorageFileLoader(Windows::Storage::StorageFile ^file) { - active_ = false; - file_ = file; - path_ = Path(FromPlatformString(file_->Path)); - thread_.reset(new std::thread([this]() { this->threadfunc(); })); - - // Before we proceed, we need to block until the thread has found the size. - // Hacky way: - while (size_ < 0) { - Sleep(10); - } -} - -StorageFileLoader::~StorageFileLoader() { - { - std::unique_lock lock(mutex_); - active_ = false; - operationRequested_ = false; - cond_.notify_one(); - } - thread_->join(); -} - -void StorageFileLoader::threadfunc() { - SetCurrentThreadName("StorageFileLoader"); - - { - std::unique_lock lock(initMutex); - _assert_(!active_); - auto opentask = create_task(file_->OpenReadAsync()).then([this](IRandomAccessStreamWithContentType ^stream) { - stream_ = stream; - active_ = true; - }); - - try { - opentask.wait(); - } catch (const std::exception& e) { - operationFailed_ = true; - // TODO: What do we do? - const char *what = e.what(); - INFO_LOG(SYSTEM, "%s", what); - } catch (Platform::COMException ^e) { - - } - - auto sizetask = create_task(file_->GetBasicPropertiesAsync()).then([this](Windows::Storage::FileProperties::BasicProperties ^props) { - size_ = props->Size; - }); - try { - sizetask.wait(); - } catch (const std::exception& e) { - const char *what = e.what(); - INFO_LOG(SYSTEM, "%s", what); - } catch (Platform::COMException ^e) { - std::string what = FromPlatformString(e->ToString()); - INFO_LOG(SYSTEM, "%s", what.c_str()); - } - } - - std::unique_lock lock(mutex_); - while (active_) { - if (!operationRequested_) { - cond_.wait(lock); - } - if (operationRequested_) { - switch (operation_.type) { - case OpType::READ_AT: { - Streams::Buffer ^buf = ref new Streams::Buffer((unsigned int)operation_.size); - operationFailed_ = false; - stream_->Seek(operation_.offset); - auto task = create_task(stream_->ReadAsync(buf, (unsigned int)operation_.size, Streams::InputStreamOptions::None)); - Streams::IBuffer ^output = nullptr; - try { - task.wait(); - output = task.get(); - } catch (const std::exception& e) { - operationFailed_ = true; - const char *what = e.what(); - INFO_LOG(SYSTEM, "%s", what); - } - std::unique_lock lock(mutexResponse_); - operationRequested_ = false; - response_.buffer = output; - responseAvailable_ = true; - condResponse_.notify_one(); - break; - } - default: - operationRequested_ = false; - break; - } - } - } -} - -bool StorageFileLoader::Exists() { - return file_ != nullptr; -} - -bool StorageFileLoader::ExistsFast() { - return file_ != nullptr; -} - -bool StorageFileLoader::IsDirectory() { - return (file_->Attributes & Windows::Storage::FileAttributes::Directory) != Windows::Storage::FileAttributes::Normal; -} - -s64 StorageFileLoader::FileSize() { - EnsureOpen(); - if (size_ == -1) - __debugbreak(); // crude race condition detection - return size_; -} - -Path StorageFileLoader::GetPath() const { - return path_; -} - -void StorageFileLoader::EnsureOpen() { - while (size_ == -1) - Sleep(50); -} - -size_t StorageFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags) { - // We can't handle multiple of these at a time, so serialize the easy way. - std::unique_lock lock(operationMutex_); - - EnsureOpen(); - - _assert_(!operationRequested_); - _assert_(!responseAvailable_) - - { - std::unique_lock lock(mutex_); - operation_.type = OpType::READ_AT; - operation_.offset = absolutePos; - operation_.size = (int64_t)(bytes * count); - operationRequested_ = true; - cond_.notify_one(); - } - - // OK, now wait for response... - { - std::unique_lock responseLock(mutexResponse_); - while (!responseAvailable_) { - condResponse_.wait(responseLock); - } - // still under mutexResponse_ lock here. - responseAvailable_ = false; - if (operationFailed_) { - return 0; - } - - DataReader ^rd = DataReader::FromBuffer(response_.buffer); - size_t len = response_.buffer->Length; - Platform::Array ^bytearray = ref new Platform::Array((unsigned int)len); - rd->ReadBytes(bytearray); - memcpy(data, bytearray->Data, len); - response_.buffer = nullptr; - return len / bytes; - } -} - -FileLoader *StorageFileLoaderFactory::ConstructFileLoader(const Path &filename) { - return file_ ? new StorageFileLoader(file_) : nullptr; -} diff --git a/UWP/StorageFileLoader.h b/UWP/StorageFileLoader.h deleted file mode 100644 index 316ca4cc34..0000000000 --- a/UWP/StorageFileLoader.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include "pch.h" - -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "Common/File/Path.h" -#include "Core/Loaders.h" - -// This thing is a terrible abomination that wraps asynchronous file access behind a synchronous interface, -// completely defeating MS' design goals for StorageFile. But hey, you gotta do what you gotta do. -// This opens a stream attached to the passed-in file. Multiple of these can be created against one StorageFile. -class StorageFileLoader : public FileLoader { -public: - StorageFileLoader(Windows::Storage::StorageFile ^file); - ~StorageFileLoader(); - - bool Exists() override; - bool ExistsFast() override; - - bool IsDirectory() override; - s64 FileSize() override; - Path GetPath() const override; - - size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override; - -private: - void threadfunc(); - void EnsureOpen(); - - enum class OpType { - NONE, - READ_AT, - }; - - struct Operation { - OpType type; - int64_t offset; - int64_t size; - }; - - struct Response { - Windows::Storage::Streams::IBuffer ^buffer; - }; - - bool active_ = false; - int64_t size_ = -1; - std::unique_ptr thread_; - - Windows::Storage::StorageFile ^file_; - Windows::Storage::Streams::IRandomAccessStreamWithContentType ^stream_; - Path path_; - - std::mutex operationMutex_; - - bool operationRequested_ = false; - Operation operation_{ OpType::NONE, 0, 0 }; - std::condition_variable cond_; - std::mutex mutex_; - - bool operationFailed_ = false; - - bool responseAvailable_ = false; - Response response_; - std::condition_variable condResponse_; - std::mutex mutexResponse_; - - int64_t seekPos_ = 0; -}; - -class StorageFileLoaderFactory : public FileLoaderFactory { -public: - StorageFileLoaderFactory(Windows::Storage::StorageFile ^file, IdentifiedFileType fileType) : file_(file), fileType_(fileType) { } - FileLoader *ConstructFileLoader(const Path &filename) override; - -private: - Windows::Storage::StorageFile ^file_; - IdentifiedFileType fileType_; -}; - -// Similar to StorageFileLoader but for directory browsing. -class StorageDirectoryWrapper { -private: - std::thread thread_; -}; diff --git a/UWP/StorageFolderBrowser.cpp b/UWP/StorageFolderBrowser.cpp deleted file mode 100644 index 00f5275dbb..0000000000 --- a/UWP/StorageFolderBrowser.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "pch.h" -#include "ppltasks.h" - -#include "Common/Thread/ThreadUtil.h" - -#include "StorageFolderBrowser.h" -#include "UWPUtil.h" - -using namespace Concurrency; -using namespace Windows::Storage; -using namespace Windows::Storage::Streams; - -static std::mutex initMutex; - -StorageFolderBrowser::StorageFolderBrowser(Windows::Storage::StorageFolder ^folder) : folder_(folder) { - thread_.reset(new std::thread([this]() { this->threadfunc(); })); - - path_ = FromPlatformString(folder->Path); - displayName_ = FromPlatformString(folder->DisplayName); -} - -void StorageFolderBrowser::threadfunc() { - SetCurrentThreadName("StorageFileLoader"); - - initMutex.lock(); - - /* - auto opentask = create_task(folder_->GetItemsAsync()->OpenReadAsync()).then([this](IRandomAccessStreamWithContentType ^stream) { - stream_ = stream; - active_ = true; - }); - - try { - opentask.wait(); - } - catch (const std::exception& e) { - operationFailed_ = true; - // TODO: What do we do? - const char *what = e.what(); - ILOG("%s", what); - } - catch (Platform::COMException ^e) { - - } - - auto sizetask = create_task(file_->GetBasicPropertiesAsync()).then([this](Windows::Storage::FileProperties::BasicProperties ^props) { - size_ = props->Size; - }); - try { - sizetask.wait(); - } - catch (const std::exception& e) { - const char *what = e.what(); - ILOG("%s", what); - } - catch (Platform::COMException ^e) { - std::string what = FromPlatformString(e->ToString()); - ILOG("%s", what.c_str()); - } - */ - initMutex.unlock(); - - std::unique_lock lock(mutex_); - while (active_) { - if (!operationRequested_) { - cond_.wait(lock); - } - if (operationRequested_) { - switch (operation_.type) { - case OpType::LIST_DIRECTORY: { - - /* - Streams::Buffer ^buf = ref new Streams::Buffer(operation_.size); - operationFailed_ = false; - stream_->Seek(operation_.offset); - auto task = create_task(stream_->ReadAsync(buf, operation_.size, Streams::InputStreamOptions::None)); - Streams::IBuffer ^output = nullptr; - try { - task.wait(); - output = task.get(); - } - catch (const std::exception& e) { - operationFailed_ = true; - const char *what = e.what(); - ILOG("%s", what); - } - operationRequested_ = false; - std::unique_lock lock(mutexResponse_); - response_.buffer = output; - responseAvailable_ = true; - condResponse_.notify_one(); - break;*/ - } - default: - operationRequested_ = false; - break; - } - } - } -} diff --git a/UWP/StorageFolderBrowser.h b/UWP/StorageFolderBrowser.h deleted file mode 100644 index b349b4636e..0000000000 --- a/UWP/StorageFolderBrowser.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#pragma once - -#include "pch.h" - -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "Core/Loaders.h" - -// This thing is a terrible abomination that wraps asynchronous file access behind a synchronous interface, -// completely defeating MS' design goals for StorageFile. But hey, you gotta do what you gotta do. -// This opens a stream attached to the passed-in file. Multiple of these can be created against one StorageFile. - -class StorageFolderBrowser { -public: - StorageFolderBrowser(Windows::Storage::StorageFolder ^folder); - ~StorageFolderBrowser(); - - std::string GetPath() const { - return path_; - } - - std::string DisplayName() const { - return displayName_; - } - - -private: - void threadfunc(); - - enum class OpType { - NONE, - LIST_DIRECTORY, - CHANGE_FOLDER, - }; - - struct Operation { - OpType type; - }; - - struct Response { - }; - - std::string path_; - std::string displayName_; - - bool active_ = false; - std::unique_ptr thread_; - - Windows::Storage::StorageFolder ^folder_; - - bool operationRequested_ = false; - Operation operation_{ OpType::NONE }; - std::condition_variable cond_; - std::mutex mutex_; - - bool operationFailed_ = false; - - bool responseAvailable_ = false; - Response response_; - std::condition_variable condResponse_; - std::mutex mutexResponse_; - - int64_t seekPos_ = 0; -}; diff --git a/UWP/UWP.vcxproj b/UWP/UWP.vcxproj index 6426e6309b..3b7f8013d4 100644 --- a/UWP/UWP.vcxproj +++ b/UWP/UWP.vcxproj @@ -538,8 +538,6 @@ - - @@ -579,8 +577,6 @@ Create Create - - @@ -1778,4 +1774,4 @@ - + \ No newline at end of file diff --git a/UWP/UWP.vcxproj.filters b/UWP/UWP.vcxproj.filters index 209fd4951f..03611fcc46 100644 --- a/UWP/UWP.vcxproj.filters +++ b/UWP/UWP.vcxproj.filters @@ -61,10 +61,8 @@ - - @@ -74,11 +72,9 @@ - - @@ -381,4 +377,4 @@ Content - + \ No newline at end of file diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index 296851c630..6b521c4996 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -3,6 +3,7 @@ #include "Common/System/Display.h" #include "Windows/GEDebugger/CtrlDisplayListView.h" #include "Windows/GEDebugger/GEDebugger.h" +#include "Windows/MainWindow.h" #include "Windows/InputBox.h" #include "Windows/W32Util/ContextMenu.h" #include "Windows/main.h" @@ -149,8 +150,7 @@ void CtrlDisplayListView::redraw() GetClientRect(wnd, &rect); visibleRows = rect.bottom/rowHeight; - InvalidateRect(wnd, NULL, FALSE); - UpdateWindow(wnd); + RedrawWindow(wnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ALLCHILDREN); } diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 2a7c32713f..60ae3a0b3b 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -21,12 +21,18 @@ #include #include +#include +#include + #include "Common/Data/Convert/ColorConv.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Text/Parsers.h" #include "Common/StringUtils.h" +#include "Common/System/System.h" + #include "Core/Config.h" #include "Core/Screenshot.h" + #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/GEDebugger/SimpleGLWindow.h" #include "Windows/GEDebugger/CtrlDisplayListView.h" @@ -38,6 +44,7 @@ #include "Windows/InputBox.h" #include "Windows/MainWindow.h" #include "Windows/main.h" + #include "GPU/GPUInterface.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/GPUStateUtils.h" @@ -46,8 +53,6 @@ #include "GPU/Debugger/Debugger.h" #include "GPU/Debugger/Record.h" #include "GPU/Debugger/Stepping.h" -#include -#include using namespace GPUBreakpoints; using namespace GPUDebug; @@ -59,6 +64,60 @@ enum PrimaryDisplayType { PRIMARY_STENCILBUF, }; +enum class GEPanelIndex { + LEFT, + RIGHT, + TOPRIGHT, + COUNT, +}; + +static void *AddDisplayListTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, HINSTANCE inst, HWND parent) { + HWND wnd = tabs->AddTabWindow(L"CtrlDisplayListView", tab->name); + return CtrlDisplayListView::getFrom(wnd); +} + +static void RemoveDisplayListTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr) { + CtrlDisplayListView *view = (CtrlDisplayListView *)ptr; + DestroyWindow(view->GetHWND()); +} + +static void UpdateDisplayListTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr) { + CtrlDisplayListView *view = (CtrlDisplayListView *)ptr; + DisplayList list; + if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list)) { + view->setDisplayList(list); + } +} + +template +static void *AddStateTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, HINSTANCE inst, HWND parent) { + T *w = new T(inst, parent); + tabs->AddTabDialog(w, tab->name); + return w; +} + +static void RemoveStateTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr) { + Dialog *view = (Dialog *)ptr; + delete view; +} + +static void UpdateStateTab(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr) { + Dialog *view = (Dialog *)ptr; + view->Update(); +} + +static const std::vector defaultTabs = { + { L"Display List", GETabPosition::LEFT, GETabType::LIST_DISASM, {}, &AddDisplayListTab, &RemoveDisplayListTab, &UpdateDisplayListTab }, + { L"Flags", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Light", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Texture", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Settings", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Verts", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Matrices", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Lists", GETabPosition::LEFT, GETabType::LISTS, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, + { L"Watch", GETabPosition::LEFT, GETabType::WATCH, {}, &AddStateTab, &RemoveStateTab, &UpdateStateTab }, +}; + StepCountDlg::StepCountDlg(HINSTANCE _hInstance, HWND _hParent) : Dialog((LPCSTR)IDD_GEDBG_STEPCOUNT, _hInstance, _hParent) { DialogManager::AddDlg(this); @@ -141,14 +200,13 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) // up both the size and the aspect ratio RECT frameRect; HWND frameWnd = GetDlgItem(m_hDlg,IDC_GEDBG_FRAME); - GetWindowRect(frameWnd,&frameRect); MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&frameRect,2); MoveWindow(frameWnd,frameRect.left,frameRect.top,512,272,TRUE); - tabs = new TabControl(GetDlgItem(m_hDlg,IDC_GEDBG_MAINTAB)); - HWND wnd = tabs->AddTabWindow(L"CtrlDisplayListView",L"Display List"); - displayList = CtrlDisplayListView::getFrom(wnd); + tabs = new TabControl(GetDlgItem(m_hDlg, IDC_GEDBG_MAINTAB)); + tabsRight_ = new TabControl(GetDlgItem(m_hDlg, IDC_GEDBG_RIGHTTAB)); + tabsTR_ = new TabControl(GetDlgItem(m_hDlg, IDC_GEDBG_TOPRIGHTTAB)); fbTabs = new TabControl(GetDlgItem(m_hDlg, IDC_GEDBG_FBTABS)); fbTabs->SetMinTabWidth(50); @@ -158,31 +216,38 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) fbTabs->AddTab(NULL, L"Stencil"); fbTabs->ShowTab(0, true); - flags = new TabStateFlags(_hInstance, m_hDlg); - tabs->AddTabDialog(flags, L"Flags"); + tabStates_ = defaultTabs; + // Restore settings, if any set. + _assert_msg_(defaultTabs.size() <= 32, "Cannot have more than 32 tabs"); + if ((g_Config.uGETabsLeft | g_Config.uGETabsRight | g_Config.uGETabsTopRight) != 0) { + for (int i = 0; i < (int)tabStates_.size(); ++i) { + int mask = 1 << i; + tabStates_[i].pos = (GETabPosition)0; + if (g_Config.uGETabsLeft & mask) + tabStates_[i].pos |= GETabPosition::LEFT; + if (g_Config.uGETabsRight & mask) + tabStates_[i].pos |= GETabPosition::RIGHT; + if (g_Config.uGETabsTopRight & mask) + tabStates_[i].pos |= GETabPosition::TOPRIGHT; + // If this is a new tab, add it to left. + if (tabStates_[i].pos == (GETabPosition)0) { + tabStates_[i].pos |= GETabPosition::LEFT; + g_Config.uGETabsLeft |= 1 << i; + } + } + } else { + g_Config.uGETabsLeft = (1 << tabStates_.size()) - 1; + } + for (GEDebuggerTab &tabState : tabStates_) { + AddTab(&tabState, tabState.pos); + } - lighting = new TabStateLighting(_hInstance, m_hDlg); - tabs->AddTabDialog(lighting, L"Lighting"); - - textureState = new TabStateTexture(_hInstance, m_hDlg); - tabs->AddTabDialog(textureState, L"Texture"); - - settings = new TabStateSettings(_hInstance, m_hDlg); - tabs->AddTabDialog(settings, L"Settings"); - - vertices = new TabVertices(_hInstance, m_hDlg); - tabs->AddTabDialog(vertices, L"Vertices"); - - matrices = new TabMatrices(_hInstance, m_hDlg); - tabs->AddTabDialog(matrices, L"Matrices"); - - lists = new TabDisplayLists(_hInstance, m_hDlg); - tabs->AddTabDialog(lists, L"Lists"); - - watch = new TabStateWatch(_hInstance, m_hDlg); - tabs->AddTabDialog(watch, L"Watch"); - - tabs->ShowTab(0, true); + if (tabs->Count() > 0) + tabs->ShowTab(0, true); + if (tabsRight_->Count() > 0) + tabsRight_->ShowTab(0, true); + if (tabsTR_->Count() > 0) + tabsTR_->ShowTab(0, true); // set window position int x = g_Config.iGEWindowX == -1 ? windowRect.left : g_Config.iGEWindowX; @@ -198,15 +263,14 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) CGEDebugger::~CGEDebugger() { CleanupPrimPreview(); - delete flags; - delete lighting; - delete textureState; - delete settings; - delete vertices; - delete matrices; - delete lists; - delete watch; + + for (GEDebuggerTab &tabState : tabStates_) { + RemoveTab(&tabState, GETabPosition::ALL); + } + delete tabs; + delete tabsRight_; + delete tabsTR_; delete fbTabs; } @@ -353,26 +417,89 @@ void CGEDebugger::UpdatePreviews() { UpdatePrimPreview(primOp, 3); } - DisplayList list; - if (gpuDebug != nullptr && gpuDebug->GetCurrentDisplayList(list)) { - displayList->setDisplayList(list); - } - wchar_t primCounter[1024]{}; swprintf(primCounter, ARRAY_SIZE(primCounter), L"%d/%d", PrimsThisFrame(), PrimsLastFrame()); SetDlgItemText(m_hDlg, IDC_GEDBG_PRIMCOUNTER, primCounter); - flags->Update(); - lighting->Update(); - textureState->Update(); - settings->Update(); - vertices->Update(); - matrices->Update(); - lists->Update(); - watch->Update(); + for (GEDebuggerTab &tabState : tabStates_) { + UpdateTab(&tabState); + } + updating_ = false; } +void CGEDebugger::UpdateTab(GEDebuggerTab *tab) { + auto doUpdate = [&](GETabPosition pos, TabControl *t, GEPanelIndex index) { + if (tab->pos & pos) + tab->update(tab, t, pos, tab->state[(int)index].ptr); + }; + + doUpdate(GETabPosition::LEFT, tabs, GEPanelIndex::LEFT); + doUpdate(GETabPosition::RIGHT, tabsRight_, GEPanelIndex::RIGHT); + doUpdate(GETabPosition::TOPRIGHT, tabsTR_, GEPanelIndex::TOPRIGHT); +} + +void CGEDebugger::AddTab(GEDebuggerTab *tab, GETabPosition mask) { + auto doAdd = [&](GETabPosition pos, TabControl *t, GEPanelIndex pindex) { + int index = (int)pindex; + // On init, we still have nullptr, but already have pos, so we use that. + if ((mask & pos) && tab->state[index].ptr == nullptr) { + tab->state[index].index = t->Count(); + tab->state[index].ptr = tab->add(tab, t, pos, m_hInstance, m_hDlg); + tab->pos |= pos; + t->ShowTab(tab->state[index].index, true); + if (gpuDebug) + tab->update(tab, t, pos, tab->state[index].ptr); + } + }; + + doAdd(GETabPosition::LEFT, tabs, GEPanelIndex::LEFT); + doAdd(GETabPosition::RIGHT, tabsRight_, GEPanelIndex::RIGHT); + doAdd(GETabPosition::TOPRIGHT, tabsTR_, GEPanelIndex::TOPRIGHT); +} + +void CGEDebugger::RemoveTab(GEDebuggerTab *tab, GETabPosition mask) { + auto doRemove = [&](GETabPosition pos, TabControl *t, GEPanelIndex pindex) { + int index = (int)pindex; + if ((tab->pos & pos) && (mask & pos)) { + auto &state = tab->state[index]; + _assert_(state.ptr != nullptr); + t->RemoveTab(state.index); + for (auto &tabState : tabStates_) { + if (tabState.state[index].index > state.index) + --tabState.state[index].index; + } + + tab->remove(tab, t, pos, state.ptr); + tab->pos = GETabPosition((int)tab->pos & ~(int)pos); + state.ptr = nullptr; + state.index = -1; + } + }; + + doRemove(GETabPosition::LEFT, tabs, GEPanelIndex::LEFT); + doRemove(GETabPosition::RIGHT, tabsRight_, GEPanelIndex::RIGHT); + doRemove(GETabPosition::TOPRIGHT, tabsTR_, GEPanelIndex::TOPRIGHT); +} + +int CGEDebugger::HasTabIndex(GEDebuggerTab *tab, GETabPosition pos) { + int stateIndex = 0; + switch (pos) { + case GETabPosition::LEFT: stateIndex = (int)GEPanelIndex::LEFT; break; + case GETabPosition::RIGHT: stateIndex = (int)GEPanelIndex::RIGHT; break; + case GETabPosition::TOPRIGHT: stateIndex = (int)GEPanelIndex::TOPRIGHT; break; + default: _assert_msg_(false, "Invalid GE tab position"); break; + } + + if (tab->pos & pos) { + auto &state = tab->state[stateIndex]; + if (state.ptr == nullptr) + return -1; + return state.index; + } + return -1; +} + u32 CGEDebugger::TexturePreviewFlags(const GPUgstate &state) { if (state.isTextureAlphaUsed() && !forceOpaque_) { return SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_BEST_CENTER; @@ -696,16 +823,46 @@ void CGEDebugger::UpdateTextureLevel(int level) { } void CGEDebugger::UpdateSize(WORD width, WORD height) { - // only resize the tab for now + // only resize the tabs for now HWND tabControl = GetDlgItem(m_hDlg, IDC_GEDBG_MAINTAB); + HWND tabControlRight = GetDlgItem(m_hDlg, IDC_GEDBG_RIGHTTAB); + HWND tabControlTR = GetDlgItem(m_hDlg, IDC_GEDBG_TOPRIGHTTAB); RECT tabRect; GetWindowRect(tabControl,&tabRect); MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&tabRect,2); - tabRect.right = tabRect.left + (width-tabRect.left*2); // assume same gap on both sides - tabRect.bottom = tabRect.top + (height-tabRect.top-tabRect.left); // assume same gap on bottom too - MoveWindow(tabControl,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); + // Assume the same gap (tabRect.left) on all sides. + if (tabsRight_ && tabsRight_->Count() == 0) { + tabRect.right = tabRect.left + (width - tabRect.left * 2); + } else { + tabRect.right = tabRect.left + (width / 2 - tabRect.left * 2); + } + tabRect.bottom = tabRect.top + (height - tabRect.top - tabRect.left); + + RECT tabRectRight = tabRect; + if (tabs && tabsRight_ && tabs->Count() == 0 && tabsRight_->Count() != 0) { + tabRect.right = tabRect.left; + tabRect.bottom = tabRect.top; + } else { + tabRectRight.left += tabRect.right; + tabRectRight.right += tabRect.right + tabRect.left; + } + + RECT frameRect; + HWND frameWnd = GetDlgItem(m_hDlg, IDC_GEDBG_FRAME); + GetWindowRect(frameWnd, &frameRect); + MapWindowPoints(HWND_DESKTOP, m_hDlg, (LPPOINT)&frameRect, 2); + + RECT trRect = { frameRect.right + 10, frameRect.top, tabRectRight.right, tabRectRight.top }; + if (tabsTR_ && tabsTR_->Count() == 0) { + trRect.right = trRect.left; + trRect.bottom = trRect.top; + } + + MoveWindow(tabControl, tabRect.left, tabRect.top, tabRect.right - tabRect.left, tabRect.bottom - tabRect.top, TRUE); + MoveWindow(tabControlRight, tabRectRight.left, tabRectRight.top, tabRectRight.right - tabRectRight.left, tabRectRight.bottom - tabRectRight.top, TRUE); + MoveWindow(tabControlTR, trRect.left, trRect.top, trRect.right - trRect.left, trRect.bottom - trRect.top, TRUE); } void CGEDebugger::SavePosition() { @@ -774,8 +931,20 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_MAINTAB: tabs->HandleNotify(lParam); if (gpuDebug != nullptr) { - lists->Update(); + for (GEDebuggerTab &tabState : tabStates_) { + if (tabState.type == GETabType::LISTS) + UpdateTab(&tabState); + } } + CheckTabMessage(tabs, GETabPosition::LEFT, lParam); + break; + case IDC_GEDBG_RIGHTTAB: + tabsRight_->HandleNotify(lParam); + CheckTabMessage(tabsRight_, GETabPosition::RIGHT, lParam); + break; + case IDC_GEDBG_TOPRIGHTTAB: + tabsTR_->HandleNotify(lParam); + CheckTabMessage(tabsTR_, GETabPosition::TOPRIGHT, lParam); break; case IDC_GEDBG_FBTABS: fbTabs->HandleNotify(lParam); @@ -884,6 +1053,10 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { break; case IDC_GEDBG_RECORD: + GPURecord::SetCallback([](const Path &path) { + // Opens a Windows Explorer window with the file. + OpenDirectory(path.c_str()); + }); GPURecord::Activate(); break; @@ -957,14 +1130,93 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case WM_GEDBG_UPDATE_WATCH: // Just a notification to update. - if (watch) - watch->Update(); + for (GEDebuggerTab &tabState : tabStates_) { + if (tabState.type == GETabType::WATCH) + UpdateTab(&tabState); + } break; } return FALSE; } +void CGEDebugger::CheckTabMessage(TabControl *t, GETabPosition pos, LPARAM lParam) { + NMHDR *msg = (LPNMHDR)lParam; + if (msg->code != NM_RCLICK) + return; + + POINT cursorPos; + GetCursorPos(&cursorPos); + int tabIndex = t->HitTest(cursorPos); + if (tabIndex == -1) + return; + + // Find the tabState that was clicked on. + GEDebuggerTab *tab = nullptr; + int tabStateIndex = 0; + for (int i = 0; i < (int)tabStates_.size(); ++i) { + GEDebuggerTab &tabState = tabStates_[i]; + int foundIndex = HasTabIndex(&tabState, pos); + if (foundIndex == tabIndex) { + tab = &tabState; + tabStateIndex = i; + break; + } + } + // Shouldn't normally happen... maybe we added some other type of tab. + if (!tab) + return; + + int currentPanels = 0; + for (int i = 0; i < (int)GEPanelIndex::COUNT; ++i) { + if (tab->state[i].index != -1 && tab->state[i].ptr) + currentPanels++; + } + + HMENU subMenu = GetContextMenu(ContextMenuID::GEDBG_TABS); + static const int itemIDs[] = { ID_GEDBG_SHOWONLEFT, ID_GEDBG_SHOWONRIGHT, ID_GEDBG_SHOWONTOPRIGHT }; + for (int i = 0; i < (int)GEPanelIndex::COUNT; ++i) { + bool active = tab->state[i].index != -1 && tab->state[i].ptr; + bool disabled = active && currentPanels == 1; + CheckMenuItem(subMenu, itemIDs[i], active ? MF_CHECKED : MF_UNCHECKED); + EnableMenuItem(subMenu, itemIDs[i], disabled ? MF_GRAYED : MF_ENABLED); + } + + auto toggleState = [&](GEPanelIndex i, GETabPosition pos, uint32_t &configured) { + auto &state = tab->state[(int)i]; + bool removing = state.index != -1 && state.ptr; + if (removing) { + RemoveTab(tab, pos); + configured &= ~(1 << tabStateIndex); + } else { + AddTab(tab, pos); + configured |= 1 << tabStateIndex; + } + + RECT rc; + GetClientRect(m_hDlg, &rc); + UpdateSize(rc.right - rc.left, rc.bottom - rc.top); + }; + + switch (TriggerContextMenu(ContextMenuID::GEDBG_TABS, m_hDlg, ContextPoint::FromCursor())) { + case ID_GEDBG_SHOWONLEFT: + toggleState(GEPanelIndex::LEFT, GETabPosition::LEFT, g_Config.uGETabsLeft); + break; + + case ID_GEDBG_SHOWONRIGHT: + toggleState(GEPanelIndex::RIGHT, GETabPosition::RIGHT, g_Config.uGETabsRight); + break; + + case ID_GEDBG_SHOWONTOPRIGHT: + toggleState(GEPanelIndex::TOPRIGHT, GETabPosition::TOPRIGHT, g_Config.uGETabsTopRight); + break; + + default: + // Cancel, that's fine. + break; + } +} + void CGEDebugger::UpdateMenus() { CheckMenuItem(GetMenu(m_hDlg), IDC_GEDBG_FLUSHAUTO, MF_BYCOMMAND | (autoFlush_ ? MF_CHECKED : MF_UNCHECKED)); } diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index ebf9a2c0d7..c7d70dc3ee 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -44,6 +44,38 @@ class TabMatrices; class TabStateWatch; struct GPUgstate; +enum class GETabPosition { + LEFT = 1, + RIGHT = 2, + TOPRIGHT = 4, + ALL = 7, +}; +ENUM_CLASS_BITOPS(GETabPosition); + +enum class GETabType { + LIST_DISASM, + LISTS, + STATE, + WATCH, +}; + +struct GEDebuggerTab { + const wchar_t *name; + GETabPosition pos; + GETabType type; + struct { + union { + Dialog *dlg; + CtrlDisplayListView *displayList; + void *ptr; + }; + int index = -1; + } state[3]; + void *(*add)(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, HINSTANCE inst, HWND parent); + void (*remove)(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr); + void (*update)(GEDebuggerTab *tab, TabControl *tabs, GETabPosition pos, void *ptr); +}; + class StepCountDlg : public Dialog { public: StepCountDlg(HINSTANCE _hInstance, HWND _hParent); @@ -81,24 +113,23 @@ private: void PrimaryPreviewHover(int x, int y); void SecondPreviewHover(int x, int y); void PreviewExport(const GPUDebugBuffer *buffer); - void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); - void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); + static void DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); + static void DescribePixelRGBA(u32 pix, GPUDebugBufferFormat fmt, int x, int y, char desc[256]); void UpdateMenus(); + void UpdateTab(GEDebuggerTab *tab); + void AddTab(GEDebuggerTab *tab, GETabPosition mask); + void RemoveTab(GEDebuggerTab *tab, GETabPosition mask); + int HasTabIndex(GEDebuggerTab *tab, GETabPosition pos); + void CheckTabMessage(TabControl *t, GETabPosition pos, LPARAM lParam); u32 TexturePreviewFlags(const GPUgstate &state); - CtrlDisplayListView *displayList = nullptr; - TabDisplayLists *lists = nullptr; - TabStateFlags *flags = nullptr; - TabStateLighting *lighting = nullptr; - TabStateTexture *textureState = nullptr; - TabStateSettings *settings = nullptr; - TabVertices *vertices = nullptr; - TabMatrices *matrices = nullptr; SimpleGLWindow *primaryWindow = nullptr; SimpleGLWindow *secondWindow = nullptr; - TabStateWatch *watch = nullptr; + std::vector tabStates_; TabControl *tabs = nullptr; + TabControl *tabsRight_ = nullptr; + TabControl *tabsTR_ = nullptr; TabControl *fbTabs = nullptr; int textureLevel_ = 0; bool showClut_ = false; diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 486e6030b4..9d6735aabd 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -177,23 +177,25 @@ static const TabStateRow stateLightingRows[] = { }; static const TabStateRow stateTextureRows[] = { + { L"Texture L0 addr", GE_CMD_TEXADDR0, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH0 }, + { L"Texture L0 size", GE_CMD_TEXSIZE0, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE }, + { L"Tex format", GE_CMD_TEXFORMAT, CMD_FMT_TEXFMT, GE_CMD_TEXTUREMAPENABLE }, + { L"Tex CLUT", GE_CMD_CLUTADDR, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_CLUTADDRUPPER }, + { L"Tex CLUT format", GE_CMD_CLUTFORMAT, CMD_FMT_CLUTFMT, GE_CMD_TEXTUREMAPENABLE }, + { L"Tex U scale", GE_CMD_TEXSCALEU, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE }, { L"Tex V scale", GE_CMD_TEXSCALEV, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE }, { L"Tex U offset", GE_CMD_TEXOFFSETU, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE }, { L"Tex V offset", GE_CMD_TEXOFFSETV, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE }, { L"Tex mapping mode", GE_CMD_TEXMAPMODE, CMD_FMT_TEXMAPMODE, GE_CMD_TEXTUREMAPENABLE }, { L"Tex shade srcs", GE_CMD_TEXSHADELS, CMD_FMT_TEXSHADELS, GE_CMD_TEXTUREMAPENABLE }, + { L"Tex func", GE_CMD_TEXFUNC, CMD_FMT_TEXFUNC, GE_CMD_TEXTUREMAPENABLE }, + { L"Tex env color", GE_CMD_TEXENVCOLOR, CMD_FMT_HEX, GE_CMD_TEXTUREMAPENABLE }, { L"Tex mode", GE_CMD_TEXMODE, CMD_FMT_TEXMODE, GE_CMD_TEXTUREMAPENABLE }, - { L"Tex format", GE_CMD_TEXFORMAT, CMD_FMT_TEXFMT, GE_CMD_TEXTUREMAPENABLE }, { L"Tex filtering", GE_CMD_TEXFILTER, CMD_FMT_TEXFILTER, GE_CMD_TEXTUREMAPENABLE }, { L"Tex wrapping", GE_CMD_TEXWRAP, CMD_FMT_TEXWRAP, GE_CMD_TEXTUREMAPENABLE }, { L"Tex level/bias", GE_CMD_TEXLEVEL, CMD_FMT_TEXLEVEL, GE_CMD_TEXTUREMAPENABLE }, { L"Tex lod slope", GE_CMD_TEXLODSLOPE, CMD_FMT_FLOAT24, GE_CMD_TEXTUREMAPENABLE }, - { L"Tex func", GE_CMD_TEXFUNC, CMD_FMT_TEXFUNC, GE_CMD_TEXTUREMAPENABLE }, - { L"Tex env color", GE_CMD_TEXENVCOLOR, CMD_FMT_HEX, GE_CMD_TEXTUREMAPENABLE }, - { L"CLUT", GE_CMD_CLUTADDR, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_CLUTADDRUPPER }, - { L"CLUT format", GE_CMD_CLUTFORMAT, CMD_FMT_CLUTFMT, GE_CMD_TEXTUREMAPENABLE }, - { L"Texture L0 addr", GE_CMD_TEXADDR0, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH0 }, { L"Texture L1 addr", GE_CMD_TEXADDR1, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH1 }, { L"Texture L2 addr", GE_CMD_TEXADDR2, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH2 }, { L"Texture L3 addr", GE_CMD_TEXADDR3, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH3 }, @@ -201,7 +203,6 @@ static const TabStateRow stateTextureRows[] = { { L"Texture L5 addr", GE_CMD_TEXADDR5, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH5 }, { L"Texture L6 addr", GE_CMD_TEXADDR6, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH6 }, { L"Texture L7 addr", GE_CMD_TEXADDR7, CMD_FMT_PTRWIDTH, GE_CMD_TEXTUREMAPENABLE, GE_CMD_TEXBUFWIDTH7 }, - { L"Texture L0 size", GE_CMD_TEXSIZE0, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE }, { L"Texture L1 size", GE_CMD_TEXSIZE1, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE }, { L"Texture L2 size", GE_CMD_TEXSIZE2, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE }, { L"Texture L3 size", GE_CMD_TEXSIZE3, CMD_FMT_TEXSIZE, GE_CMD_TEXTUREMAPENABLE }, @@ -212,27 +213,34 @@ static const TabStateRow stateTextureRows[] = { }; static const TabStateRow stateSettingsRows[] = { - { L"Clear mode", GE_CMD_CLEARMODE, CMD_FMT_CLEARMODE }, { L"Framebuffer", GE_CMD_FRAMEBUFPTR, CMD_FMT_PTRWIDTH, 0, GE_CMD_FRAMEBUFWIDTH }, { L"Framebuffer format", GE_CMD_FRAMEBUFPIXFORMAT, CMD_FMT_TEXFMT }, { L"Depthbuffer", GE_CMD_ZBUFPTR, CMD_FMT_PTRWIDTH, 0, GE_CMD_ZBUFWIDTH }, + { L"Viewport Scale", GE_CMD_VIEWPORTXSCALE, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYSCALE, GE_CMD_VIEWPORTZSCALE }, + { L"Viewport Offset", GE_CMD_VIEWPORTXCENTER, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYCENTER, GE_CMD_VIEWPORTZCENTER }, + { L"Scissor", GE_CMD_SCISSOR1, CMD_FMT_XYXY, 0, GE_CMD_SCISSOR2 }, + { L"Region", GE_CMD_REGION1, CMD_FMT_XYXY, 0, GE_CMD_REGION2 }, + { L"Color test", GE_CMD_COLORTEST, CMD_FMT_COLORTEST, GE_CMD_COLORTESTENABLE, GE_CMD_COLORREF, GE_CMD_COLORTESTMASK }, + { L"Alpha test", GE_CMD_ALPHATEST, CMD_FMT_ALPHATEST, GE_CMD_ALPHATESTENABLE }, + { L"Clear mode", GE_CMD_CLEARMODE, CMD_FMT_CLEARMODE }, + { L"Stencil test", GE_CMD_STENCILTEST, CMD_FMT_STENCILTEST, GE_CMD_STENCILTESTENABLE }, + { L"Stencil test op", GE_CMD_STENCILOP, CMD_FMT_STENCILOP, GE_CMD_STENCILTESTENABLE }, + { L"Depth test", GE_CMD_ZTEST, CMD_FMT_ZTEST, GE_CMD_ZTESTENABLE }, + { L"RGB mask", GE_CMD_MASKRGB, CMD_FMT_HEX }, + { L"Stencil/alpha mask", GE_CMD_MASKALPHA, CMD_FMT_HEX }, + { L"Transfer src", GE_CMD_TRANSFERSRC, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERSRCW }, + { L"Transfer src pos", GE_CMD_TRANSFERSRCPOS, CMD_FMT_XY }, + { L"Transfer dst", GE_CMD_TRANSFERDST, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERDSTW }, + { L"Transfer dst pos", GE_CMD_TRANSFERDSTPOS, CMD_FMT_XY }, + { L"Transfer size", GE_CMD_TRANSFERSIZE, CMD_FMT_XY }, { L"Vertex type", GE_CMD_VERTEXTYPE, CMD_FMT_VERTEXTYPE }, { L"Offset addr", GE_CMD_OFFSETADDR, CMD_FMT_OFFSETADDR }, { L"Vertex addr", GE_CMD_VADDR, CMD_FMT_VADDR }, { L"Index addr", GE_CMD_IADDR, CMD_FMT_IADDR }, - { L"Region", GE_CMD_REGION1, CMD_FMT_XYXY, 0, GE_CMD_REGION2 }, - { L"Scissor", GE_CMD_SCISSOR1, CMD_FMT_XYXY, 0, GE_CMD_SCISSOR2 }, { L"Min Z", GE_CMD_MINZ, CMD_FMT_HEX }, { L"Max Z", GE_CMD_MAXZ, CMD_FMT_HEX }, - { L"Viewport Scale", GE_CMD_VIEWPORTXSCALE, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYSCALE, GE_CMD_VIEWPORTZSCALE }, - { L"Viewport Offset", GE_CMD_VIEWPORTXCENTER, CMD_FMT_XYZ, 0, GE_CMD_VIEWPORTYCENTER, GE_CMD_VIEWPORTZCENTER }, { L"Offset", GE_CMD_OFFSETX, CMD_FMT_F16_XY, 0, GE_CMD_OFFSETY }, { L"Cull mode", GE_CMD_CULL, CMD_FMT_CULL, GE_CMD_CULLFACEENABLE }, - { L"Color test", GE_CMD_COLORTEST, CMD_FMT_COLORTEST, GE_CMD_COLORTESTENABLE, GE_CMD_COLORREF, GE_CMD_COLORTESTMASK }, - { L"Alpha test", GE_CMD_ALPHATEST, CMD_FMT_ALPHATEST, GE_CMD_ALPHATESTENABLE }, - { L"Stencil test", GE_CMD_STENCILTEST, CMD_FMT_STENCILTEST, GE_CMD_STENCILTESTENABLE }, - { L"Stencil test op", GE_CMD_STENCILOP, CMD_FMT_STENCILOP, GE_CMD_STENCILTESTENABLE }, - { L"Depth test", GE_CMD_ZTEST, CMD_FMT_ZTEST, GE_CMD_ZTESTENABLE }, { L"Alpha blend mode", GE_CMD_BLENDMODE, CMD_FMT_BLENDMODE, GE_CMD_ALPHABLENDENABLE }, { L"Blend color A", GE_CMD_BLENDFIXEDA, CMD_FMT_HEX, GE_CMD_ALPHABLENDENABLE }, { L"Blend color B", GE_CMD_BLENDFIXEDB, CMD_FMT_HEX, GE_CMD_ALPHABLENDENABLE }, @@ -240,8 +248,6 @@ static const TabStateRow stateSettingsRows[] = { { L"Fog 1", GE_CMD_FOG1, CMD_FMT_FLOAT24, GE_CMD_FOGENABLE }, { L"Fog 2", GE_CMD_FOG2, CMD_FMT_FLOAT24, GE_CMD_FOGENABLE }, { L"Fog color", GE_CMD_FOGCOLOR, CMD_FMT_HEX, GE_CMD_FOGENABLE }, - { L"RGB mask", GE_CMD_MASKRGB, CMD_FMT_HEX }, - { L"Stencil/alpha mask", GE_CMD_MASKALPHA, CMD_FMT_HEX }, { L"Morph Weight 0", GE_CMD_MORPHWEIGHT0, CMD_FMT_FLOAT24 }, { L"Morph Weight 1", GE_CMD_MORPHWEIGHT1, CMD_FMT_FLOAT24 }, { L"Morph Weight 2", GE_CMD_MORPHWEIGHT2, CMD_FMT_FLOAT24 }, @@ -259,11 +265,6 @@ static const TabStateRow stateSettingsRows[] = { { L"Dither 1", GE_CMD_DITH1, CMD_FMT_HEX, GE_CMD_DITHERENABLE }, { L"Dither 2", GE_CMD_DITH2, CMD_FMT_HEX, GE_CMD_DITHERENABLE }, { L"Dither 3", GE_CMD_DITH3, CMD_FMT_HEX, GE_CMD_DITHERENABLE }, - { L"Transfer src", GE_CMD_TRANSFERSRC, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERSRCW }, - { L"Transfer src pos", GE_CMD_TRANSFERSRCPOS, CMD_FMT_XY }, - { L"Transfer dst", GE_CMD_TRANSFERDST, CMD_FMT_PTRWIDTH, 0, GE_CMD_TRANSFERDSTW }, - { L"Transfer dst pos", GE_CMD_TRANSFERDSTPOS, CMD_FMT_XY }, - { L"Transfer size", GE_CMD_TRANSFERSIZE, CMD_FMT_XY }, }; // TODO: Commands not present in the above lists (some because they don't have meaningful values...): @@ -1013,7 +1014,7 @@ void CtrlStateValues::OnRightClick(int row, int column, const POINT &point) { } bool CtrlStateValues::OnRowPrePaint(int row, LPNMLVCUSTOMDRAW msg) { - if (RowValuesChanged(row)) { + if (gpuDebug && RowValuesChanged(row)) { msg->clrText = RGB(255, 0, 0); return true; } diff --git a/Windows/GEDebugger/TabState.h b/Windows/GEDebugger/TabState.h index c60c849028..dbc1558fa0 100644 --- a/Windows/GEDebugger/TabState.h +++ b/Windows/GEDebugger/TabState.h @@ -57,7 +57,7 @@ public: TabStateValues(const TabStateRow *rows, int rowCount, LPCSTR dialogID, HINSTANCE _hInstance, HWND _hParent); ~TabStateValues(); - virtual void Update() { + void Update() override { values->Update(); } diff --git a/Windows/GPU/D3D9Context.cpp b/Windows/GPU/D3D9Context.cpp index 9367078a81..7c1f4868e9 100644 --- a/Windows/GPU/D3D9Context.cpp +++ b/Windows/GPU/D3D9Context.cpp @@ -160,8 +160,8 @@ bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { } device_->BeginScene(); - DX9::pD3Ddevice = device_; - DX9::pD3DdeviceEx = deviceEx_; + pD3Ddevice9 = device_; + pD3DdeviceEx9 = deviceEx_; if (deviceEx_ && IsWin7OrHigher()) { // TODO: This makes it slower? @@ -212,8 +212,8 @@ void D3D9Context::Shutdown() { device_->Release(); d3d_->Release(); UnloadD3DCompiler(); - DX9::pD3Ddevice = nullptr; - DX9::pD3DdeviceEx = nullptr; + pD3Ddevice9 = nullptr; + pD3DdeviceEx9 = nullptr; device_ = nullptr; hWnd_ = nullptr; FreeLibrary(hD3D9_); diff --git a/Windows/W32Util/ContextMenu.h b/Windows/W32Util/ContextMenu.h index f8fbe46488..9e52e2aa47 100644 --- a/Windows/W32Util/ContextMenu.h +++ b/Windows/W32Util/ContextMenu.h @@ -31,6 +31,7 @@ enum class ContextMenuID { GEDBG_STATE = 7, GEDBG_PREVIEW = 8, GEDBG_MATRIX = 9, + GEDBG_TABS = 10, }; struct ContextPoint { diff --git a/Windows/W32Util/DialogManager.h b/Windows/W32Util/DialogManager.h index fc943b3ddd..55497223ac 100644 --- a/Windows/W32Util/DialogManager.h +++ b/Windows/W32Util/DialogManager.h @@ -18,6 +18,7 @@ protected: virtual void Create(); void Destroy(); + HINSTANCE m_hInstance; HWND m_hParent; HWND m_hDlg; LPCSTR m_hResource; @@ -26,9 +27,6 @@ protected: virtual BOOL DlgProc(UINT message, WPARAM wParam, LPARAM lParam) = 0; static INT_PTR CALLBACK DlgProcStatic(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); - -private: - HINSTANCE m_hInstance; }; diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp index 37bdfd475e..657a0193d2 100644 --- a/Windows/W32Util/Misc.cpp +++ b/Windows/W32Util/Misc.cpp @@ -204,6 +204,7 @@ GenericListControl::GenericListControl(HWND hwnd, const GenericListViewDef& def) } GenericListControl::~GenericListControl() { + SetWindowLongPtr(handle, GWLP_USERDATA, (LONG_PTR)nullptr); // Don't destroy the image list, it's done automatically by the list view. } @@ -376,6 +377,8 @@ void GenericListControl::ResizeColumns() LRESULT CALLBACK GenericListControl::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { GenericListControl* list = (GenericListControl*) GetWindowLongPtr(hwnd,GWLP_USERDATA); + if (!list) + return FALSE; LRESULT returnValue; if (list->valid && list->WindowMessage(msg,wParam,lParam,returnValue) == true) diff --git a/Windows/W32Util/TabControl.cpp b/Windows/W32Util/TabControl.cpp index 2d315213df..d4556725b6 100644 --- a/Windows/W32Util/TabControl.cpp +++ b/Windows/W32Util/TabControl.cpp @@ -93,6 +93,27 @@ void TabControl::AddTab(HWND handle, const wchar_t* title) ShowTab(index); } +HWND TabControl::RemoveTab(int index) { + int prevIndex = CurrentTabIndex(); + if (currentTab >= index) + --currentTab; + + HWND prevHandle = tabs[index].pageHandle; + if (tabs.size() == 1) { + TabCtrl_DeleteAllItems(hwnd); + tabs.clear(); + currentTab = 0; + } else { + TabCtrl_DeleteItem(hwnd, index); + tabs.erase(tabs.begin() + index); + + if (prevIndex == index) + ShowTab(currentTab, true); + } + + return prevHandle; +} + int TabControl::AppendPageToControl(const wchar_t *title) { TCITEM tcItem; @@ -257,6 +278,14 @@ void TabControl::HandleNotify(LPARAM lParam) } } +int TabControl::HitTest(const POINT &screenPos) { + TCHITTESTINFO hitTest{}; + hitTest.pt = screenPos; + ScreenToClient(hwnd, &hitTest.pt); + + return TabCtrl_HitTest(hwnd, &hitTest); +} + void TabControl::OnResize() { RECT tabRect; diff --git a/Windows/W32Util/TabControl.h b/Windows/W32Util/TabControl.h index 7eb2360dcf..3d4b26f93e 100644 --- a/Windows/W32Util/TabControl.h +++ b/Windows/W32Util/TabControl.h @@ -11,9 +11,11 @@ class TabControl public: TabControl(HWND handle, bool noDisplayArea = false); void HandleNotify(LPARAM lParam); + int HitTest(const POINT &screenPos); HWND AddTabWindow(const wchar_t* className, const wchar_t* title, DWORD style = 0); void AddTabDialog(Dialog* dialog, const wchar_t* title); void AddTab(HWND hwnd, const wchar_t* title); + HWND RemoveTab(int index); void ShowTab(int index, bool setControlIndex = true); void ShowTab(HWND pageHandle); void NextTab(bool cycle); @@ -30,6 +32,10 @@ public: bool GetShowTabTitles() { return showTabTitles; } void SetMinTabWidth(int w); + int Count() { + return (int)tabs.size(); + } + private: static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); void OnResize(); diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index b306c1a7f5..e2f38fd8e6 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -196,7 +196,7 @@ BEGIN CONTROL "",IDC_DEBUG_BOTTOMTABS,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,1,338,513,93 END -IDD_GEDEBUGGER DIALOGEX 0, 0, 500, 400 +IDD_GEDEBUGGER DIALOGEX 0, 0, 490, 400 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME EXSTYLE WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW CAPTION "GE" @@ -212,7 +212,9 @@ BEGIN PUSHBUTTON "&Resume",IDC_GEDBG_RESUME,444,2,44,14 CONTROL "",IDC_GEDBG_TEX,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,10,20,128,128 CONTROL "",IDC_GEDBG_FRAME,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,148,20,256,136 - CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,10,216,480,180 + CONTROL "",IDC_GEDBG_TOPRIGHTTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,500,20,280,136 + CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,10,216,280,180 + CONTROL "",IDC_GEDBG_RIGHTTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,210,216,280,180 EDITTEXT IDC_GEDBG_FRAMEBUFADDR,148,192,200,12,ES_READONLY | NOT WS_BORDER EDITTEXT IDC_GEDBG_TEXADDR,10,152,128,12,ES_READONLY | NOT WS_BORDER CONTROL "Force opaque",IDC_GEDBG_FORCEOPAQUE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,164,60,12 @@ -790,6 +792,12 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Toggle Breakpoint", ID_DISASM_TOGGLEBREAKPOINT END + POPUP "getaboptions" + BEGIN + MENUITEM "Show in &Left Pane" ID_GEDBG_SHOWONLEFT + MENUITEM "Show in &Right Pane" ID_GEDBG_SHOWONRIGHT + MENUITEM "Show in &Top Right Pane" ID_GEDBG_SHOWONTOPRIGHT + END END #endif // English (United States) resources diff --git a/Windows/resource.h b/Windows/resource.h index 29879fdc57..eacb42760b 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -264,7 +264,6 @@ #define ID_OPTIONS_BUFLINEARFILTER 40152 #define ID_OPTIONS_BUFNEARESTFILTER 40153 #define ID_OPTIONS_DIRECT3D9 40154 -#define ID_OPTIONS_DIRECT3D11 40169 #define ID_OPTIONS_OPENGL 40155 #define ID_EMULATION_ROTATION_H 40156 #define ID_EMULATION_ROTATION_V 40157 @@ -326,6 +325,13 @@ #define IDC_GEDBG_FLUSHAUTO 40213 #define IDI_BREAKPOINT_SMALL 40214 #define IDC_GEDBG_SETPRIMFILTER 40215 +#define IDC_GEDBG_RIGHTTAB 40216 +#define ID_OPTIONS_DIRECT3D11 40217 +#define IDC_GEDBG_TOPRIGHTTAB 40218 +#define ID_GEDBG_SHOWONLEFT 40219 +#define ID_GEDBG_SHOWONRIGHT 40220 +#define ID_GEDBG_SHOWONTOPRIGHT 40221 + // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -338,7 +344,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 256 -#define _APS_NEXT_COMMAND_VALUE 40216 +#define _APS_NEXT_COMMAND_VALUE 40222 #define _APS_NEXT_CONTROL_VALUE 1202 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 23c6d56dc5..aaf9d290db 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -94,6 +94,7 @@ struct JNIEnv {}; #include "UI/GameInfoCache.h" #ifdef OPENXR +#include "Core/HLE/sceDisplay.h" #include "VR/VRBase.h" #include "VR/VRInput.h" #include "VR/VRRenderer.h" @@ -818,6 +819,8 @@ retry: java.AppVersion = gitVer.ToInteger(); strcpy(java.AppName, "PPSSPP"); VR_Init(java); + + __DisplaySetFramerate(72); #endif } diff --git a/assets/compat.ini b/assets/compat.ini index 005b5931e9..c6011605d7 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1263,3 +1263,6 @@ ULES00897 = true ULUS10194 = true ULES00618 = true +# Silver Fall +ULES00808 = true +ULUS10270 = true diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index 1a5d6b4164..19b0b0d2e9 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -181,19 +181,23 @@ bool TestReinterpretShaders() { bool failed = false; for (int k = 0; k < ARRAY_SIZE(languages); k++) { + printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); + ShaderLanguageDesc desc(languages[k]); - if (!GenerateReinterpretVertexShader(buffer, desc)) { - printf("Failed!\n%s\n", buffer); + + // These require bitwise operations. + if (!desc.bitwiseOps) { + continue; + } + + GenerateReinterpretVertexShader(buffer, desc); + std::string errorMessage; + if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { + printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; + return false; } else { - std::string errorMessage; - if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { - printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); - failed = true; - return false; - } else { - //printf("===\n%s\n===\n", buffer); - } + //printf("===\n%s\n===\n", buffer); } } @@ -201,23 +205,25 @@ bool TestReinterpretShaders() { printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); ShaderLanguageDesc desc(languages[k]); + + // These require bitwise operations. + if (!desc.bitwiseOps) { + continue; + } + std::string errorMessage; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i == j) continue; // useless shader! - if (!GenerateReinterpretFragmentShader(buffer, fmts[i], fmts[j], desc)) { - printf("Failed!\n%s\n", buffer); + GenerateReinterpretFragmentShader(buffer, fmts[i], fmts[j], desc); + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { + printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; + return false; } else { - if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { - printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str()); - failed = true; - return false; - } else { - printf("===\n%s\n===\n", buffer); - } + printf("===\n%s\n===\n", buffer); } } }