mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-26 19:58:36 +01:00
Merge branch 'feature_openxr_6dof' into feature_openxr_stereo
This commit is contained in:
commit
d570a194dd
77 files changed
+1040
-1353
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
@@ -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<D3D9InputLayout> inputLayout;
|
||||
AutoRef<D3D9DepthStencilState> depthStencil;
|
||||
AutoRef<D3D9BlendState> blend;
|
||||
AutoRef<D3D9RasterState> 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<D3D9ShaderModule *>(iter);
|
||||
pipeline->pshader->AddRef();
|
||||
}
|
||||
else if (iter->GetStage() == ShaderStage::Vertex) {
|
||||
pipeline->vshader = static_cast<D3D9ShaderModule *>(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);
|
||||
|
||||
@@ -313,6 +313,9 @@ void ShaderWriter::EndVSMain(Slice<VaryingDef> 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+7
-5
@@ -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;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#define ATLAS_MAGIC ('A' + ('T' << 8) + ('L' << 16) | ('A' << 24))
|
||||
#define ATLAS_MAGIC ('A' | ('T' << 8) | ('L' << 16) | ('A' << 24))
|
||||
|
||||
// Metadata file structure v0:
|
||||
//
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
+20
-18
@@ -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;
|
||||
}
|
||||
@@ -34,3 +34,5 @@ void __DisplaySetWasPaused();
|
||||
|
||||
void Register_sceDisplay_driver();
|
||||
void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks = false);
|
||||
|
||||
void __DisplaySetFramerate(int value);
|
||||
@@ -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<UniformDef>::empty(), varyings, FSFLAG_NONE);
|
||||
@@ -289,9 +289,6 @@ void GenerateDepalVs(char *buffer, const ShaderLanguageDesc &lang) {
|
||||
writer.BeginVSMain(vsInputs, Slice<UniformDef>::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);
|
||||
}
|
||||
|
||||
|
||||
+102
-90
@@ -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<UniformDef>::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<UniformDef>::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<UniformDef>::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);
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vector<GPUDebugV
|
||||
u16 indexLowerBound = 0;
|
||||
u16 indexUpperBound = count - 1;
|
||||
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr))
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr) || count == 0)
|
||||
return false;
|
||||
|
||||
bool savedVertexFullAlpha = gstate_c.vertexFullAlpha;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
FramebufferManagerCommon::FramebufferManagerCommon(Draw::DrawContext *draw)
|
||||
: draw_(draw), displayFormat_(GE_FORMAT_565) {
|
||||
: draw_(draw) {
|
||||
presentation_ = new PresentationCommon(draw);
|
||||
}
|
||||
|
||||
@@ -71,12 +71,6 @@ FramebufferManagerCommon::~FramebufferManagerCommon() {
|
||||
}
|
||||
bvfbs_.clear();
|
||||
|
||||
// Shouldn't be anything left here in theory, but just in case...
|
||||
for (auto trackedDepth : trackedDepthBuffers_) {
|
||||
delete trackedDepth;
|
||||
}
|
||||
trackedDepthBuffers_.clear();
|
||||
|
||||
delete presentation_;
|
||||
}
|
||||
|
||||
@@ -114,14 +108,14 @@ void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, G
|
||||
GPURecord::NotifyDisplay(framebuf, stride, format);
|
||||
}
|
||||
|
||||
VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) {
|
||||
VirtualFramebuffer *FramebufferManagerCommon::GetVFBAt(u32 addr) const {
|
||||
addr &= 0x3FFFFFFF;
|
||||
VirtualFramebuffer *match = nullptr;
|
||||
for (size_t i = 0; i < vfbs_.size(); ++i) {
|
||||
VirtualFramebuffer *v = vfbs_[i];
|
||||
if (v->fb_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<Draw::ShaderModule *> 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<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {
|
||||
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() const {
|
||||
std::vector<FramebufferInfo> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::pair<u32, u32>> 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<FramebufferInfo> GetFramebufferList();
|
||||
std::vector<FramebufferInfo> 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<VirtualFramebuffer *> &Framebuffers() {
|
||||
const std::vector<VirtualFramebuffer *> &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<VirtualFramebuffer *> vfbs_;
|
||||
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
|
||||
|
||||
std::vector<TrackedDepthBuffer *> 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.
|
||||
};
|
||||
@@ -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<InputDef>::empty(), Slice<UniformDef>::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<Draw::ShaderModule *> 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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -20,74 +20,14 @@
|
||||
#include <D3Dcompiler.h>
|
||||
|
||||
#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 <emmintrin.h>
|
||||
#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() {
|
||||
}
|
||||
@@ -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_;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -45,7 +45,7 @@
|
||||
#include <emmintrin.h>
|
||||
#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
|
||||
@@ -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<u64, OffscreenSurface> offscreenSurfaces_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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<VShaderID, VSShader *> VSCache;
|
||||
VSCache vsCache_;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -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)?
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -26,8 +26,6 @@
|
||||
struct VirtualFramebuffer;
|
||||
class DepalShaderCache;
|
||||
|
||||
namespace DX9 {
|
||||
|
||||
class FramebufferManagerDX9;
|
||||
class ShaderManagerDX9;
|
||||
|
||||
@@ -78,5 +76,3 @@ private:
|
||||
};
|
||||
|
||||
D3DFORMAT getClutDestFormat(GEPaletteFormat format);
|
||||
|
||||
};
|
||||
@@ -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<GLRShader *> 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<GLRProgram::Semantic> 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<GLRProgram::Initializer> 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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -2969,7 +2969,7 @@ bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) {
|
||||
return framebufferManager_ ? framebufferManager_->GetOutputFramebuffer(buffer) : false;
|
||||
}
|
||||
|
||||
std::vector<FramebufferInfo> GPUCommon::GetFramebufferList() {
|
||||
std::vector<FramebufferInfo> GPUCommon::GetFramebufferList() const {
|
||||
return framebufferManager_->GetFramebufferList();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -230,11 +230,11 @@ public:
|
||||
const std::list<int>& GetDisplayLists() override {
|
||||
return dlQueue;
|
||||
}
|
||||
std::vector<FramebufferInfo> GetFramebufferList() override;
|
||||
std::vector<FramebufferInfo> 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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -253,8 +253,8 @@ public:
|
||||
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) = 0;
|
||||
virtual const std::list<int>& GetDisplayLists() = 0;
|
||||
// TODO: Currently Qt only, needs to be cleaned up.
|
||||
virtual std::vector<FramebufferInfo> GetFramebufferList() = 0;
|
||||
virtual s64 GetListTicks(int listid) = 0;
|
||||
virtual std::vector<FramebufferInfo> 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<std::string> DebugGetShaderIDs(DebugShaderType type) = 0;
|
||||
|
||||
@@ -813,6 +813,9 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVert
|
||||
u16 indexLowerBound = 0;
|
||||
u16 indexUpperBound = count - 1;
|
||||
|
||||
if (!Memory::IsValidAddress(gstate_c.vertexAddr) || count == 0)
|
||||
return false;
|
||||
|
||||
if (count > 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
+3
-2
@@ -17,6 +17,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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,
|
||||
|
||||
+5
-1
@@ -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
|
||||
|
||||
@@ -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<FileLoaderFactory> factory(new StorageFileLoaderFactory(file, IdentifiedFileType::PSP_ISO));
|
||||
RegisterFileLoaderFactory("override://", std::move(factory));
|
||||
NativeMessageReceived("boot", "override://file");
|
||||
}
|
||||
|
||||
UWPGraphicsContext::UWPGraphicsContext(std::shared_ptr<DX::DeviceResources> resources) {
|
||||
std::vector<std::string> 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")) {
|
||||
|
||||
@@ -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<std::mutex> lock(mutex_);
|
||||
active_ = false;
|
||||
operationRequested_ = false;
|
||||
cond_.notify_one();
|
||||
}
|
||||
thread_->join();
|
||||
}
|
||||
|
||||
void StorageFileLoader::threadfunc() {
|
||||
SetCurrentThreadName("StorageFileLoader");
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(operationMutex_);
|
||||
|
||||
EnsureOpen();
|
||||
|
||||
_assert_(!operationRequested_);
|
||||
_assert_(!responseAvailable_)
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> 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<std::mutex> 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<uint8_t> ^bytearray = ref new Platform::Array<uint8_t>((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;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#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<std::thread> 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_;
|
||||
};
|
||||
@@ -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<std::mutex> 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<std::mutex> lock(mutexResponse_);
|
||||
response_.buffer = output;
|
||||
responseAvailable_ = true;
|
||||
condResponse_.notify_one();
|
||||
break;*/
|
||||
}
|
||||
default:
|
||||
operationRequested_ = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#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<std::thread> 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;
|
||||
};
|
||||
+1
-5
@@ -538,8 +538,6 @@
|
||||
<ClInclude Include="PPSSPP_UWPMain.h" />
|
||||
<ClInclude Include="Common\DirectXHelper.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="StorageFileLoader.h" />
|
||||
<ClInclude Include="StorageFolderBrowser.h" />
|
||||
<ClInclude Include="UWPHost.h" />
|
||||
<ClInclude Include="UWPUtil.h" />
|
||||
<ClInclude Include="XAudioSoundStream.h" />
|
||||
@@ -579,8 +577,6 @@
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='UWP Gold|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StorageFileLoader.cpp" />
|
||||
<ClCompile Include="StorageFolderBrowser.cpp" />
|
||||
<ClCompile Include="UWPHost.cpp" />
|
||||
<ClCompile Include="XAudioSoundStream.cpp" />
|
||||
</ItemGroup>
|
||||
@@ -1778,4 +1774,4 @@
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\MeshContentTask.targets" />
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ShaderGraphContentTask.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -61,10 +61,8 @@
|
||||
<ClCompile Include="XAudioSoundStream.cpp" />
|
||||
<ClCompile Include="PPSSPP_UWPMain.cpp" />
|
||||
<ClCompile Include="NKCodeFromWindowsSystem.cpp" />
|
||||
<ClCompile Include="StorageFileLoader.cpp" />
|
||||
<ClCompile Include="UWPHost.cpp" />
|
||||
<ClCompile Include="..\Windows\XinputDevice.cpp" />
|
||||
<ClCompile Include="StorageFolderBrowser.cpp" />
|
||||
<ClCompile Include="..\Windows\InputDevice.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -74,11 +72,9 @@
|
||||
<ClInclude Include="XAudioSoundStream.h" />
|
||||
<ClInclude Include="PPSSPP_UWPMain.h" />
|
||||
<ClInclude Include="NKCodeFromWindowsSystem.h" />
|
||||
<ClInclude Include="StorageFileLoader.h" />
|
||||
<ClInclude Include="UWPHost.h" />
|
||||
<ClInclude Include="..\Windows\XinputDevice.h" />
|
||||
<ClInclude Include="UWPUtil.h" />
|
||||
<ClInclude Include="StorageFolderBrowser.h" />
|
||||
<ClInclude Include="..\Windows\InputDevice.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -381,4 +377,4 @@
|
||||
<Filter>Content</Filter>
|
||||
</Font>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,12 +21,18 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
#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 <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
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 <typename T>
|
||||
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<GEDebuggerTab> defaultTabs = {
|
||||
{ L"Display List", GETabPosition::LEFT, GETabType::LIST_DISASM, {}, &AddDisplayListTab, &RemoveDisplayListTab, &UpdateDisplayListTab },
|
||||
{ L"Flags", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabStateFlags>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Light", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabStateLighting>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Texture", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabStateTexture>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Settings", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabStateSettings>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Verts", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabVertices>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Matrices", GETabPosition::LEFT, GETabType::STATE, {}, &AddStateTab<TabMatrices>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Lists", GETabPosition::LEFT, GETabType::LISTS, {}, &AddStateTab<TabDisplayLists>, &RemoveStateTab, &UpdateStateTab },
|
||||
{ L"Watch", GETabPosition::LEFT, GETabType::WATCH, {}, &AddStateTab<TabStateWatch>, &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));
|
||||
}
|
||||
@@ -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<GEDebuggerTab> tabStates_;
|
||||
TabControl *tabs = nullptr;
|
||||
TabControl *tabsRight_ = nullptr;
|
||||
TabControl *tabsTR_ = nullptr;
|
||||
TabControl *fbTabs = nullptr;
|
||||
int textureLevel_ = 0;
|
||||
bool showClut_ = false;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class ContextMenuID {
|
||||
GEDBG_STATE = 7,
|
||||
GEDBG_PREVIEW = 8,
|
||||
GEDBG_MATRIX = 9,
|
||||
GEDBG_TABS = 10,
|
||||
};
|
||||
|
||||
struct ContextPoint {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
+10
-2
@@ -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
|
||||
|
||||
+8
-2
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1263,3 +1263,6 @@ ULES00897 = true
|
||||
ULUS10194 = true
|
||||
ULES00618 = true
|
||||
|
||||
# Silver Fall
|
||||
ULES00808 = true
|
||||
ULUS10270 = true
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user