Merge branch 'feature_openxr_6dof' into feature_openxr_stereo

This commit is contained in:
Lubos committed 2022-08-17 17:08:12 +02:00
commit d570a194dd
77 files changed
+1040 -1353

No files matched your search

-17
View File
@@ -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 -6
View File
@@ -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
+27 -31
View File
@@ -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();
};
+13 -15
View File
@@ -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);
+3
View File
@@ -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);
+1 -1
View File
@@ -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;
-20
View File
@@ -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) {
+5
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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:
//
+3
View File
@@ -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),
+3
View File
@@ -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;
+5
View File
@@ -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
View File
@@ -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;
}
+2
View File
@@ -34,3 +34,5 @@ void __DisplaySetWasPaused();
void Register_sceDisplay_driver();
void __DisplayWaitForVblanks(const char* reason, int vblanks, bool callbacks = false);
void __DisplaySetFramerate(int value);
+1 -4
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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;
+53 -252
View File
@@ -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;
}
+83 -58
View File
@@ -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.
};
+164 -15
View File
@@ -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");
}
}
+2 -2
View File
@@ -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);
+7 -5
View File
@@ -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);
}
-60
View File
@@ -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() {
}
-9
View File
@@ -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_;
};
-3
View File
@@ -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);
+5 -4
View File
@@ -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));
}
+1
View File
@@ -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"
+4 -8
View File
@@ -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
-4
View File
@@ -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
+1 -6
View File
@@ -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
-6
View File
@@ -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_;
};
}
-7
View File
@@ -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
-6
View File
@@ -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;
-4
View File
@@ -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
-4
View File
@@ -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_;
};
};
-4
View File
@@ -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)?
}
}
-4
View File
@@ -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;
}
};
-4
View File
@@ -26,8 +26,6 @@
struct VirtualFramebuffer;
class DepalShaderCache;
namespace DX9 {
class FramebufferManagerDX9;
class ShaderManagerDX9;
@@ -78,5 +76,3 @@ private:
};
D3DFORMAT getClutDestFormat(GEPaletteFormat format);
};
+16 -14
View File
@@ -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;
+6 -19
View File
@@ -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) {
+2 -15
View File
@@ -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;
};
+1 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+3
View File
@@ -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;
+1 -4
View File
@@ -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;
-15
View File
@@ -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);
}
-6
View File
@@ -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);
+1 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4 -9
View File
@@ -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")) {
-185
View File
@@ -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;
}
-90
View File
@@ -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_;
};
-100
View File
@@ -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;
}
}
}
}
-70
View File
@@ -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
View File
@@ -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>
+1 -5
View File
@@ -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>
+2 -2
View File
@@ -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);
}
+310 -58
View File
@@ -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));
}
+42 -11
View File
@@ -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;
+26 -25
View File
@@ -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;
}
+1 -1
View File
@@ -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();
}
+4 -4
View File
@@ -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_);
+1
View File
@@ -31,6 +31,7 @@ enum class ContextMenuID {
GEDBG_STATE = 7,
GEDBG_PREVIEW = 8,
GEDBG_MATRIX = 9,
GEDBG_TABS = 10,
};
struct ContextPoint {
+1 -3
View File
@@ -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;
};
+3
View File
@@ -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)
+29
View File
@@ -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;
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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
}
+3
View File
@@ -1263,3 +1263,6 @@ ULES00897 = true
ULUS10194 = true
ULES00618 = true
# Silver Fall
ULES00808 = true
ULUS10270 = true
+25 -19
View File
@@ -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);
}
}
}