Remove D3D9 support, to make future changes easier

This commit is contained in:
Henrik Rydgård 2025-02-05 11:27:22 -06:00
parent 2309226a08
commit 2d59bb8d9a
59 changed files with 56 additions and 5661 deletions

View file

@ -496,9 +496,6 @@
<ClInclude Include="File\VFS\VFS.h" />
<ClInclude Include="File\VFS\ZipFileReader.h" />
<ClInclude Include="GPU\D3D11\D3D11Loader.h" />
<ClInclude Include="GPU\D3D9\D3DCompilerLoader.h" />
<ClInclude Include="GPU\D3D9\D3D9ShaderCompiler.h" />
<ClInclude Include="GPU\D3D9\D3D9StateCache.h" />
<ClInclude Include="GPU\DataFormat.h" />
<ClInclude Include="GPU\GPUBackendCommon.h" />
<ClInclude Include="GPU\MiscTypes.h" />
@ -991,10 +988,6 @@
<ClCompile Include="File\VFS\ZipFileReader.cpp" />
<ClCompile Include="GPU\D3D11\D3D11Loader.cpp" />
<ClCompile Include="GPU\D3D11\thin3d_d3d11.cpp" />
<ClCompile Include="GPU\D3D9\D3DCompilerLoader.cpp" />
<ClCompile Include="GPU\D3D9\D3D9ShaderCompiler.cpp" />
<ClCompile Include="GPU\D3D9\D3D9StateCache.cpp" />
<ClCompile Include="GPU\D3D9\thin3d_d3d9.cpp" />
<ClCompile Include="GPU\GPUBackendCommon.cpp" />
<ClCompile Include="GPU\OpenGL\DataFormatGL.cpp" />
<ClCompile Include="GPU\OpenGL\gl3stub.c" />

View file

@ -250,15 +250,6 @@
<ClInclude Include="UI\ViewGroup.h">
<Filter>UI</Filter>
</ClInclude>
<ClInclude Include="GPU\D3D9\D3DCompilerLoader.h">
<Filter>GPU\D3D9</Filter>
</ClInclude>
<ClInclude Include="GPU\D3D9\D3D9ShaderCompiler.h">
<Filter>GPU\D3D9</Filter>
</ClInclude>
<ClInclude Include="GPU\D3D9\D3D9StateCache.h">
<Filter>GPU\D3D9</Filter>
</ClInclude>
<ClInclude Include="GPU\D3D11\D3D11Loader.h">
<Filter>GPU\D3D11</Filter>
</ClInclude>
@ -911,21 +902,9 @@
<ClCompile Include="UI\ViewGroup.cpp">
<Filter>UI</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D9\thin3d_d3d9.cpp">
<Filter>GPU\D3D9</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D11\thin3d_d3d11.cpp">
<Filter>GPU\D3D11</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D9\D3DCompilerLoader.cpp">
<Filter>GPU\D3D9</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D9\D3D9ShaderCompiler.cpp">
<Filter>GPU\D3D9</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D9\D3D9StateCache.cpp">
<Filter>GPU\D3D9</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D11\D3D11Loader.cpp">
<Filter>GPU\D3D11</Filter>
</ClCompile>
@ -1368,9 +1347,6 @@
<Filter Include="GPU">
<UniqueIdentifier>{3b448d70-d5c6-4732-96f0-29f3e101bfe8}</UniqueIdentifier>
</Filter>
<Filter Include="GPU\D3D9">
<UniqueIdentifier>{a1745de8-f61a-4f11-b715-705a8812862e}</UniqueIdentifier>
</Filter>
<Filter Include="GPU\D3D11">
<UniqueIdentifier>{8241d0c2-78c8-4fc6-9543-69042ec5eb54}</UniqueIdentifier>
</Filter>

View file

@ -1650,7 +1650,6 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x
break;
case Aspect::NO_BIT:
case Aspect::STENCIL_BIT:
case Aspect::SURFACE_BIT:
case Aspect::VIEW_BIT:
case Aspect::FORMAT_BIT:
break;
@ -1833,7 +1832,6 @@ bool D3D11DrawContext::CopyFramebufferToMemory(Framebuffer *src, Aspect channelB
}
break;
case Aspect::NO_BIT:
case Aspect::SURFACE_BIT:
case Aspect::VIEW_BIT:
case Aspect::FORMAT_BIT:
break;

View file

@ -1,70 +0,0 @@
#include "ppsspp_config.h"
#ifdef _WIN32
#include "Common/CommonWindows.h"
#include "Common/GPU/D3D9/D3DCompilerLoader.h"
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
#include "Common/CommonFuncs.h"
#include "Common/SysError.h"
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include <wrl/client.h>
using namespace Microsoft::WRL;
HRESULT CompileShaderToByteCodeD3D9(const char *code, const char *target, std::string *errorMessage, ID3DBlob **ppShaderCode) {
ComPtr<ID3DBlob> pErrorMsg;
// Compile pixel shader.
HRESULT hr = dyn_D3DCompile(code,
(UINT)strlen(code),
nullptr,
nullptr,
nullptr,
"main",
target,
0,
0,
ppShaderCode,
&pErrorMsg);
if (pErrorMsg) {
*errorMessage = std::string((CHAR *)pErrorMsg->GetBufferPointer());
OutputDebugStringUTF8(LineNumberString(std::string(code)).c_str());
OutputDebugStringUTF8(errorMessage->c_str());
} else if (FAILED(hr)) {
*errorMessage = GetStringErrorMsg(hr);
} else {
errorMessage->clear();
}
return hr;
}
bool CompilePixelShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPIXELSHADER9 *pShader, std::string *errorMessage) {
ComPtr<ID3DBlob> pShaderCode;
HRESULT hr = CompileShaderToByteCodeD3D9(code, "ps_3_0", errorMessage, &pShaderCode);
if (SUCCEEDED(hr)) {
// Create pixel shader.
device->CreatePixelShader((DWORD*)pShaderCode->GetBufferPointer(), pShader);
return true;
} else {
return false;
}
}
bool CompileVertexShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DVERTEXSHADER9 *pShader, std::string *errorMessage) {
ComPtr<ID3DBlob> pShaderCode;
HRESULT hr = CompileShaderToByteCodeD3D9(code, "vs_3_0", errorMessage, &pShaderCode);
if (SUCCEEDED(hr)) {
// Create vertex shader.
device->CreateVertexShader((DWORD*)pShaderCode->GetBufferPointer(), pShader);
return true;
} else {
return false;
}
}
#endif

View file

@ -1,13 +0,0 @@
#pragma once
#include "Common/CommonWindows.h"
#include "Common/GPU/D3D9/D3DCompilerLoader.h"
#include <initguid.h>
#include <string>
#include <d3d9.h>
HRESULT CompileShaderToByteCodeD3D9(const char *code, const char *target, std::string *errorMessage, LPD3DBLOB *pShaderCode);
bool CompilePixelShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DPIXELSHADER9 *pShader, std::string *errorMessage);
bool CompileVertexShaderD3D9(LPDIRECT3DDEVICE9 device, const char *code, LPDIRECT3DVERTEXSHADER9 *pShader, std::string *errorMessage);

View file

@ -1,64 +0,0 @@
#ifdef _WIN32
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include <wrl/client.h>
DirectXState dxstate;
Microsoft::WRL::ComPtr<IDirect3DDevice9> pD3Ddevice9;
Microsoft::WRL::ComPtr<IDirect3DDevice9Ex> pD3DdeviceEx9;
int DirectXState::state_count = 0;
void DirectXState::Initialize() {
if (initialized)
return;
Restore();
initialized = true;
}
void DirectXState::Restore() {
int count = 0;
blend.restore(); count++;
blendSeparate.restore(); count++;
blendEquation.restore(); count++;
blendFunc.restore(); count++;
blendColor.restore(); count++;
scissorTest.restore(); count++;
scissorRect.restore(); count++;
cullMode.restore(); count++;
shadeMode.restore(); count++;
depthTest.restore(); count++;
depthFunc.restore(); count++;
depthWrite.restore(); count++;
colorMask.restore(); count++;
viewport.restore(); count++;
alphaTest.restore(); count++;
alphaTestFunc.restore(); count++;
alphaTestRef.restore(); count++;
stencilTest.restore(); count++;
stencilOp.restore(); count++;
stencilFunc.restore(); count++;
stencilWriteMask.restore(); count++;
texMinFilter.restore(); count++;
texMagFilter.restore(); count++;
texMipFilter.restore(); count++;
texMipLodBias.restore(); count++;
texMaxMipLevel.restore(); count++;
texAddressU.restore(); count++;
texAddressV.restore(); count++;
texAddressW.restore(); count++;
}
#endif // _MSC_VER

View file

@ -1,402 +0,0 @@
#pragma once
#include <cstring>
#include <wrl/client.h>
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
// TODO: Get rid of these somehow.
extern Microsoft::WRL::ComPtr<IDirect3DDevice9> pD3Ddevice9;
extern Microsoft::WRL::ComPtr<IDirect3DDevice9Ex> pD3DdeviceEx9;
class DirectXState {
private:
template<D3DRENDERSTATETYPE cap, bool init>
class BoolState {
bool _value;
public:
BoolState() : _value(init) {
DirectXState::state_count++;
}
inline void set(bool value) {
if (_value != value) {
_value = value;
restore();
}
}
void force(bool value) {
bool old = _value;
set(value);
_value = old;
}
inline void enable() {
set(true);
}
inline void disable() {
set(false);
}
operator bool() const {
return isset();
}
inline bool isset() {
return _value;
}
void restore() {
pD3Ddevice9->SetRenderState(cap, _value);
}
};
template<D3DRENDERSTATETYPE state1, DWORD p1def>
class DxState1 {
D3DRENDERSTATETYPE _state1;
DWORD p1;
public:
DxState1() : _state1(state1), p1(p1def) {
DirectXState::state_count++;
}
inline void set(DWORD newp1) {
if (p1 != newp1) {
p1 = newp1;
restore();
}
}
void force(DWORD newp1) {
DWORD old = p1;
set(newp1);
p1 = old;
}
void restore() {
pD3Ddevice9->SetRenderState(_state1, p1);
}
};
template<D3DSAMPLERSTATETYPE state1, DWORD p1def>
class DxSampler0State1 {
D3DSAMPLERSTATETYPE _state1;
DWORD p1;
public:
DxSampler0State1() : _state1(state1), p1(p1def) {
DirectXState::state_count++;
}
inline void set(DWORD newp1) {
if (p1 != newp1) {
p1 = newp1;
restore();
}
}
void force(DWORD newp1) {
DWORD old = p1;
set(newp1);
p1 = old;
}
void restore() {
pD3Ddevice9->SetSamplerState(0, _state1, p1);
}
};
// Can't have FLOAT template parameters...
template<D3DSAMPLERSTATETYPE state1, DWORD p1def>
class DxSampler0State1Float {
D3DSAMPLERSTATETYPE _state1;
union {
FLOAT p1;
DWORD p1d;
};
public:
DxSampler0State1Float() : _state1(state1), p1d(p1def) {
DirectXState::state_count++;
}
inline void set(FLOAT newp1) {
if (p1 != newp1) {
p1 = newp1;
restore();
}
}
void force(FLOAT newp1) {
FLOAT old = p1;
set(newp1);
p1 = old;
}
void restore() {
pD3Ddevice9->SetSamplerState(0, _state1, p1d);
}
};
template<D3DRENDERSTATETYPE state1, DWORD p1def, D3DRENDERSTATETYPE state2, DWORD p2def>
class DxState2 {
D3DRENDERSTATETYPE _state1;
D3DRENDERSTATETYPE _state2;
DWORD p1;
DWORD p2;
public:
DxState2() : _state1(state1),_state2(state2), p1(p1def), p2(p2def) {
DirectXState::state_count++;
}
inline void set(DWORD newp1, DWORD newp2) {
if (p1 != newp1) {
p1 = newp1;
pD3Ddevice9->SetRenderState(_state1, p1);
}
if (p2 != newp2) {
p2 = newp2;
pD3Ddevice9->SetRenderState(_state2, p2);
}
}
void force(DWORD newp1, DWORD newp2) {
DWORD old1 = p1;
DWORD old2 = p2;
set(newp1, newp2);
p1 = old1;
p2 = old2;
}
void restore() {
pD3Ddevice9->SetRenderState(_state1, p1);
pD3Ddevice9->SetRenderState(_state2, p2);
}
};
template<D3DRENDERSTATETYPE state1, DWORD p1def, D3DRENDERSTATETYPE state2, DWORD p2def, D3DRENDERSTATETYPE state3, DWORD p3def>
class DxState3 {
D3DRENDERSTATETYPE _state1;
D3DRENDERSTATETYPE _state2;
D3DRENDERSTATETYPE _state3;
DWORD p1;
DWORD p2;
DWORD p3;
public:
DxState3() : _state1(state1),_state2(state2), _state3(state3),
p1(p1def), p2(p2def), p3(p3def) {
}
inline void set(DWORD newp1, DWORD newp2, DWORD newp3) {
if (p1 != newp1) {
p1 = newp1;
pD3Ddevice9->SetRenderState(_state1, p1);
}
if (p2 != newp2) {
p2 = newp2;
pD3Ddevice9->SetRenderState(_state2, p2);
}
if (p3 != newp3) {
p3 = newp3;
pD3Ddevice9->SetRenderState(_state3, p3);
}
}
void force(DWORD newp1, DWORD newp2, DWORD newp3) {
DWORD old1 = p1;
DWORD old2 = p2;
DWORD old3 = p3;
set(newp1, newp2, newp3);
p1 = old1;
p2 = old2;
p3 = old3;
}
void restore() {
pD3Ddevice9->SetRenderState(_state1, p1);
pD3Ddevice9->SetRenderState(_state2, p2);
pD3Ddevice9->SetRenderState(_state3, p3);
}
};
template<D3DRENDERSTATETYPE state1, DWORD p1def, D3DRENDERSTATETYPE state2, DWORD p2def, D3DRENDERSTATETYPE state3, DWORD p3def, D3DRENDERSTATETYPE state4, DWORD p4def>
class DxState4 {
D3DRENDERSTATETYPE _state1;
D3DRENDERSTATETYPE _state2;
D3DRENDERSTATETYPE _state3;
D3DRENDERSTATETYPE _state4;
DWORD p1;
DWORD p2;
DWORD p3;
DWORD p4;
public:
DxState4() : _state1(state1), _state2(state2), _state3(state3), _state4(state4),
p1(p1def), p2(p2def), p3(p3def), p4(p4def) {
}
inline void set(DWORD newp1, DWORD newp2, DWORD newp3, DWORD newp4) {
if (p1 != newp1) {
p1 = newp1;
pD3Ddevice9->SetRenderState(_state1, p1);
}
if (p2 != newp2) {
p2 = newp2;
pD3Ddevice9->SetRenderState(_state2, p2);
}
if (p3 != newp3) {
p3 = newp3;
pD3Ddevice9->SetRenderState(_state3, p3);
}
if (p4 != newp4) {
p4 = newp4;
pD3Ddevice9->SetRenderState(_state4, p4);
}
}
void force(DWORD newp1, DWORD newp2, DWORD newp3, DWORD newp4) {
DWORD old1 = p1;
DWORD old2 = p2;
DWORD old3 = p3;
DWORD old4 = p4;
set(newp1, newp2, newp3, newp4);
p1 = old1;
p2 = old2;
p3 = old3;
p4 = old4;
}
void restore() {
pD3Ddevice9->SetRenderState(_state1, p1);
pD3Ddevice9->SetRenderState(_state2, p2);
pD3Ddevice9->SetRenderState(_state3, p3);
pD3Ddevice9->SetRenderState(_state4, p4);
}
};
class SavedBlendFactor {
DWORD c;
public:
SavedBlendFactor() {
c = 0xFFFFFFFF;
DirectXState::state_count++;
}
inline void set(const float v[4]) {
DWORD newc = D3DCOLOR_COLORVALUE(v[0], v[1], v[2], v[3]);
if (c != newc) {
c = newc;
restore();
}
}
void setDWORD(DWORD newc) {
newc = ((newc >> 8) & 0xff) | (newc & 0xff00ff00) | ((newc << 16) & 0xff0000); // ARGB -> ABGR fix
if (c != newc) {
c = newc;
restore();
}
}
void force(const float v[4]) {
DWORD old = c;
set(v);
c = old;
}
inline void restore() {
pD3Ddevice9->SetRenderState(D3DRS_BLENDFACTOR, c);
}
};
class StateVp {
D3DVIEWPORT9 viewport;
public:
StateVp() {
memset(&viewport, 0, sizeof(viewport));
// It's an error if w/h is zero, so let's start with something that can work.
viewport.Width = 1;
viewport.Height = 1;
}
inline void set(int x, int y, int w, int h, float n = 0.f, float f = 1.f) {
D3DVIEWPORT9 newviewport;
newviewport.X = x;
newviewport.Y = y;
newviewport.Width = w;
newviewport.Height = h;
newviewport.MinZ = n;
newviewport.MaxZ = f;
if (memcmp(&viewport, &newviewport, sizeof(viewport)) != 0) {
viewport = newviewport;
restore();
}
}
void force(int x, int y, int w, int h, float n = 0.f, float f = 1.f) {
D3DVIEWPORT9 old = viewport;
set(x, y, w, h, n, f);
viewport = old;
}
inline void restore() {
pD3Ddevice9->SetViewport(&viewport);
}
};
class StateScissor {
RECT rect;
public:
inline void set(int x1, int y1, int x2, int y2) {
RECT newrect = {x1, y1, x2, y2};
if (memcmp(&rect, &newrect, sizeof(rect))) {
rect = newrect;
restore();
}
}
void force(int x1, int y1, int x2, int y2) {
RECT old = rect;
set(x1, y1, x2, y2);
rect = old;
}
inline void restore() {
pD3Ddevice9->SetScissorRect(&rect);
}
};
bool initialized;
public:
static int state_count;
DirectXState() : initialized(false) {}
void Initialize();
void Restore();
// When adding a state here, don't forget to add it to DirectxState::Restore() too
BoolState<D3DRS_ALPHABLENDENABLE, false> blend;
BoolState<D3DRS_SEPARATEALPHABLENDENABLE, false> blendSeparate;
DxState4<D3DRS_SRCBLEND, D3DBLEND_SRCALPHA, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA, D3DRS_SRCBLENDALPHA, D3DBLEND_ONE, D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO> blendFunc;
DxState2<D3DRS_BLENDOP, D3DBLENDOP_ADD, D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD> blendEquation;
SavedBlendFactor blendColor;
BoolState<D3DRS_SCISSORTESTENABLE, false> scissorTest;
DxState1<D3DRS_CULLMODE, D3DCULL_NONE> cullMode;
DxState1<D3DRS_SHADEMODE, D3DSHADE_GOURAUD> shadeMode;
DxState1<D3DRS_CLIPPLANEENABLE, 0> clipPlaneEnable;
BoolState<D3DRS_ZENABLE, false> depthTest;
DxState1<D3DRS_ALPHAFUNC, D3DCMP_ALWAYS> alphaTestFunc;
DxState1<D3DRS_ALPHAREF, 0> alphaTestRef;
BoolState<D3DRS_ALPHATESTENABLE, false> alphaTest;
DxState1<D3DRS_ZFUNC, D3DCMP_LESSEQUAL> depthFunc;
DxState1<D3DRS_ZWRITEENABLE, TRUE> depthWrite;
DxState1<D3DRS_COLORWRITEENABLE, 0xF> colorMask;
StateVp viewport;
StateScissor scissorRect;
BoolState<D3DRS_STENCILENABLE, false> stencilTest;
DxState3<D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP, D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP, D3DRS_STENCILPASS, D3DSTENCILOP_KEEP> stencilOp;
DxState1<D3DRS_STENCILFUNC, D3DCMP_ALWAYS> stencilFunc;
DxState1<D3DRS_STENCILREF, 0> stencilRef;
DxState1<D3DRS_STENCILWRITEMASK, 0xFFFFFFFF> stencilWriteMask;
DxState1<D3DRS_STENCILMASK, 0xFFFFFFFF> stencilCompareMask;
DxSampler0State1<D3DSAMP_MINFILTER, D3DTEXF_POINT> texMinFilter;
DxSampler0State1<D3DSAMP_MAGFILTER, D3DTEXF_POINT> texMagFilter;
DxSampler0State1<D3DSAMP_MIPFILTER, D3DTEXF_NONE> texMipFilter;
DxSampler0State1Float<D3DSAMP_MIPMAPLODBIAS, 0> texMipLodBias;
DxSampler0State1<D3DSAMP_MAXMIPLEVEL, 0> texMaxMipLevel;
DxSampler0State1<D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP> texAddressU;
DxSampler0State1<D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP> texAddressV;
DxSampler0State1<D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP> texAddressW;
};
#undef STATE1
#undef STATE2
extern DirectXState dxstate;

View file

@ -1,56 +0,0 @@
#include "ppsspp_config.h"
#include "Common/CommonWindows.h"
#include <D3Dcompiler.h>
#include "Common/Log.h"
#include "Common/GPU/D3D9/D3DCompilerLoader.h"
static HMODULE g_D3DCompileModule;
extern pD3DCompile ptr_D3DCompile;
static int d3dcompiler_version = 47;
bool LoadD3DCompilerDynamic() {
g_D3DCompileModule = LoadLibrary(D3DCOMPILER_DLL);
#if PPSSPP_ARCH(X86)
// Workaround for distributing both 32-bit and 64-bit versions of the DLL.
if (!g_D3DCompileModule) {
g_D3DCompileModule = LoadLibrary(L"D3dcompiler_47.x86.dll");
}
#endif
if (!g_D3DCompileModule) {
g_D3DCompileModule = LoadLibrary(L"D3dcompiler_42.dll");
d3dcompiler_version = 42;
}
if (!g_D3DCompileModule) {
return false;
} else {
ptr_D3DCompile = (pD3DCompile)GetProcAddress(g_D3DCompileModule, "D3DCompile");
return true;
}
}
int GetD3DCompilerVersion() {
return d3dcompiler_version;
}
bool UnloadD3DCompiler() {
if (!g_D3DCompileModule)
return false;
FreeLibrary(g_D3DCompileModule);
g_D3DCompileModule = nullptr;
return true;
}
HRESULT dyn_D3DCompile(LPCSTR pSrcData, UINT SrcDataSize, LPCSTR pFileName, CONST D3D_SHADER_MACRO* pDefines,
LPD3DINCLUDE pInclude, LPCSTR pEntrypoint, LPCSTR pTarget,
UINT Flags1, UINT Flags2, LPD3DBLOB* ppShader, LPD3DBLOB* ppErrorMsgs)
{
_assert_(g_D3DCompileModule != nullptr);
return ptr_D3DCompile(pSrcData, SrcDataSize, pFileName, pDefines, pInclude, pEntrypoint, pTarget, Flags1, Flags2, ppShader, ppErrorMsgs);
}

View file

@ -1,15 +0,0 @@
#pragma once
#include "ppsspp_config.h"
#include "Common/CommonWindows.h"
#include <D3Dcompiler.h>
bool LoadD3DCompilerDynamic();
HRESULT dyn_D3DCompile(LPCSTR pSrcData, UINT SrcDataSize, LPCSTR pFileName, CONST D3D_SHADER_MACRO* pDefines,
LPD3DINCLUDE pInclude, LPCSTR pEntrypoint, LPCSTR pTarget,
UINT Flags1, UINT Flags2, LPD3DBLOB* ppShader, LPD3DBLOB* ppErrorMsgs);
bool UnloadD3DCompiler();
int GetD3DCompilerVersion();

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,6 @@ const char *ShaderLanguageAsString(ShaderLanguage lang) {
case GLSL_1xx: return "GLSL 1.x";
case GLSL_3xx: return "GLSL 3.x";
case GLSL_VULKAN: return "GLSL-VK";
case HLSL_D3D9: return "HLSL-D3D9";
case HLSL_D3D11: return "HLSL-D3D11";
default: return "(combination)";
}
@ -88,22 +87,17 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) {
coefsFromBuffers = true;
vertexIndex = true;
break;
case HLSL_D3D9:
case HLSL_D3D11:
if (lang == HLSL_D3D11) {
fragColor0 = "outfragment.target";
fragColor1 = "outfragment.target1";
vertexIndex = true; // if declared as a semantic input
} else {
fragColor0 = "outfragment.target";
}
fragColor0 = "outfragment.target";
fragColor1 = "outfragment.target1";
vertexIndex = true; // if declared as a semantic input
varying_fs = "in";
varying_vs = "out";
attribute = "in";
bitwiseOps = lang == HLSL_D3D11;
framebufferFetchExtension = nullptr;
gles = false;
glslES30 = true; // Hm, D3D9 too?
glslES30 = true;
glslVersionNumber = 0;
lastFragData = nullptr;
texture = "texture";

View file

@ -17,7 +17,6 @@ enum ShaderLanguage {
GLSL_1xx = 1,
GLSL_3xx = 2,
GLSL_VULKAN = 4,
HLSL_D3D9 = 8,
HLSL_D3D11 = 16,
};

View file

@ -102,22 +102,13 @@ layout (std140, set = 0, binding = 0) uniform Data {
};
)";
static const char * const d3d9RegisterDecl = R"(
float4 gl_HalfPixel : register(c0);
float2 u_texelDelta : register(c1);
float2 u_pixelDelta : register(c2);
float4 u_time : register(c3);
float4 u_timeDelta : register(c4);
float4 u_setting : register(c5);
float u_video : register(c6);
)";
// SPIRV-Cross' HLSL output has some deficiencies we need to work around.
// Also we need to rip out single uniforms and replace them with blocks.
// Should probably do it in the source shader instead and then back translate to old style GLSL, but
// SPIRV-Cross currently won't compile with the Android NDK so I can't be bothered.
std::string Postprocess(std::string code, ShaderLanguage lang, ShaderStage stage) {
if (lang != HLSL_D3D11 && lang != HLSL_D3D9)
if (lang != HLSL_D3D11)
return code;
std::stringstream out;
@ -125,18 +116,11 @@ std::string Postprocess(std::string code, ShaderLanguage lang, ShaderStage stage
// Output the uniform buffer.
if (lang == HLSL_D3D11)
out << cbufferDecl;
else if (lang == HLSL_D3D9)
out << d3d9RegisterDecl;
// Alright, now let's go through it line by line and zap the single uniforms.
std::string line;
std::stringstream instream(code);
while (std::getline(instream, line)) {
int num;
if (lang == HLSL_D3D9 && sscanf(line.c_str(), "uniform sampler2D sampler%d;", &num) == 1) {
out << "sampler2D sampler" << num << " : register(s" << num << ");\n";
continue;
}
if (line.find("uniform float") != std::string::npos) {
continue;
}
@ -272,19 +256,6 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, const ShaderLan
switch (destLang) {
#ifdef _WIN32
case HLSL_D3D9:
{
spirv_cross::CompilerHLSL hlsl(spirv);
spirv_cross::CompilerHLSL::Options options{};
options.shader_model = 30;
spirv_cross::CompilerGLSL::Options options_common{};
options_common.vertex.fixup_clipspace = true;
hlsl.set_hlsl_options(options);
hlsl.set_common_options(options_common);
std::string raw = hlsl.compile();
*dest = Postprocess(raw, destLang, stage);
return true;
}
case HLSL_D3D11:
{
spirv_cross::CompilerHLSL hlsl(spirv);

View file

@ -136,18 +136,13 @@ void ShaderWriter::Preamble(Slice<const char *> extensions) {
}
break;
case HLSL_D3D11:
case HLSL_D3D9:
switch (stage_) {
case ShaderStage::Vertex:
W(hlsl_preamble_vs);
break;
case ShaderStage::Fragment:
W(hlsl_preamble_fs);
if (lang_.shaderLanguage == HLSL_D3D9) {
W(hlsl_d3d9_preamble_fs);
} else {
W(hlsl_d3d11_preamble_fs);
}
W(hlsl_d3d11_preamble_fs);
break;
case ShaderStage::Geometry:
W(hlsl_preamble_gs);
@ -205,7 +200,6 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniform
_assert_(this->stage_ == ShaderStage::Vertex);
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
case HLSL_D3D9:
{
C("struct VS_OUTPUT {\n");
for (auto &varying : varyings) {
@ -215,9 +209,7 @@ void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniform
C("};\n");
C("VS_OUTPUT main( "); // 2 spaces for the rewind
if (lang_.shaderLanguage == HLSL_D3D11) {
C("uint gl_VertexIndex : SV_VertexID, ");
}
C("uint gl_VertexIndex : SV_VertexID, ");
// List the inputs.
for (auto &input : inputs) {
F("in %s %s : %s, ", input.type, input.name, semanticNames[input.semantic]);
@ -293,32 +285,6 @@ void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> var
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
C(" float gl_FragDepth;\n");
}
break;
case HLSL_D3D9:
C("struct PS_OUT {\n");
C(" vec4 target : SV_Target0;\n");
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
C(" float depth : DEPTH;\n");
}
C("};\n");
for (auto &uniform : uniforms) {
F(" %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index);
}
// Let's do the varyings as parameters to main, no struct.
C("PS_OUT main(");
for (auto &varying : varyings) {
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
}
// Erase the last comma
Rewind(2);
F(") {\n");
C(" PS_OUT ps_out;\n");
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
C(" float gl_FragDepth;\n");
}
break;
case GLSL_VULKAN:
for (auto &varying : varyings) {
@ -391,7 +357,6 @@ void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
_assert_(this->stage_ == ShaderStage::Vertex);
switch (lang_.shaderLanguage) {
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);
@ -413,7 +378,6 @@ void ShaderWriter::EndFSMain(const char *vec4_color_variable) {
_assert_(this->stage_ == ShaderStage::Fragment);
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
case HLSL_D3D9:
F(" ps_out.target = %s;\n", vec4_color_variable);
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
C(" ps_out.depth = gl_FragDepth;\n");
@ -448,7 +412,6 @@ void ShaderWriter::LowPrecisionFloat() {
void ShaderWriter::ConstFloat(const char *name, float value) {
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
case HLSL_D3D9:
F("static const float %s = %f;\n", name, value);
break;
default:
@ -474,9 +437,6 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) {
case HLSL_D3D11:
F("Texture2D<float4> %s : register(t%d);\n", def.name, def.binding);
break;
case HLSL_D3D9:
F("sampler %s: register(s%d);\n", def.name, def.binding);
break;
case GLSL_VULKAN:
// texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1.
if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) {
@ -508,9 +468,6 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv
case HLSL_D3D11:
F("%s.Sample(%sSamp, %s)", sampName, sampName, uv);
break;
case HLSL_D3D9:
F("tex2D(%s, %s)", sampName, uv);
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
@ -531,10 +488,6 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch
case HLSL_D3D11:
F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY);
break;
case HLSL_D3D9:
// Not supported, we do a normal sample here to not crash or something
F("tex2D(%s, %s)", sampName, uv);
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
@ -555,10 +508,6 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv,
case HLSL_D3D11:
F("%s.Load(ivec3(%s, %d))", sampName, uv, level);
break;
case HLSL_D3D9:
// Not supported, we return a bad value
C("float4(1.0, 0.0, 1.0, 1.0)");
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
@ -575,9 +524,6 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv,
ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *texName) {
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
case HLSL_D3D9:
F(" float2 %s; %s.GetDimensions(%s.x, %s.y);", szVariable, texName, szVariable, szVariable);
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
F("vec2 %s = textureSize(%s, 0);", szVariable, texName);

View file

@ -183,13 +183,6 @@ static const std::vector<ShaderSource> fsTexCol = {
"uniform sampler2D Sampler0;\n"
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n"
},
{ShaderLanguage::HLSL_D3D9,
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"sampler2D Sampler0 : register(s0);\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
" return input.color * tex2D(Sampler0, input.uv);\n"
"}\n"
},
{ShaderLanguage::HLSL_D3D11,
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"SamplerState samp : register(s0);\n"
@ -227,13 +220,6 @@ static const std::vector<ShaderSource> fsTexColRBSwizzle = {
"uniform sampler2D Sampler0;\n"
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0).zyxw * oColor0; }\n"
},
{ShaderLanguage::HLSL_D3D9,
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"sampler2D Sampler0 : register(s0);\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
" return input.color * tex2D(Sampler0, input.uv).zyxw;\n"
"}\n"
},
{ShaderLanguage::HLSL_D3D11,
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"SamplerState samp : register(s0);\n"
@ -268,12 +254,6 @@ static const std::vector<ShaderSource> fsCol = {
"varying vec4 oColor0;\n"
"void main() { gl_FragColor = oColor0; }\n"
},
{ ShaderLanguage::HLSL_D3D9,
"struct PS_INPUT { float4 color : COLOR0; };\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
" return input.color;\n"
"}\n"
},
{ ShaderLanguage::HLSL_D3D11,
"struct PS_INPUT { float4 color : COLOR0; };\n"
"float4 main(PS_INPUT input) : SV_Target {\n"
@ -309,18 +289,6 @@ static const std::vector<ShaderSource> vsCol = {
" oColor0 = Color0;\n"
"}"
},
{ ShaderLanguage::HLSL_D3D9,
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj : register(c0);\n"
"float2 TintSaturation : register(c4);\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
" output.Color0 = input.Color0;\n"
" return output;\n"
"}\n"
},
{ ShaderLanguage::HLSL_D3D11,
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Color0 : COLOR0; float4 Position : SV_Position; };\n"
@ -416,37 +384,6 @@ void main() {
oColor0 = vec4(hsv2rgb(hsv), Color0.w);
oTexCoord0 = TexCoord0;
})",
},
{ ShaderLanguage::HLSL_D3D9,
R"(
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
float4x4 WorldViewProj : register(c0);
float2 TintSaturation : register(c4);
float3 rgb2hsv(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
float3 hsv2rgb(float3 c) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
VS_OUTPUT main(VS_INPUT input) {
VS_OUTPUT output;
float3 hsv = rgb2hsv(input.Color0.xyz);
hsv.x += TintSaturation.x;
hsv.y *= TintSaturation.y;
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
output.Position = mul(float4(input.Position, 1.0), WorldViewProj);
output.Texcoord0 = input.Texcoord0;
return output;
}
)"
},
{ ShaderLanguage::HLSL_D3D11,
R"(

View file

@ -89,8 +89,6 @@ std::string GPUBackendToString(GPUBackend backend) {
switch (backend) {
case GPUBackend::OPENGL:
return "OPENGL";
case GPUBackend::DIRECT3D9:
return "DIRECT3D9";
case GPUBackend::DIRECT3D11:
return "DIRECT3D11";
case GPUBackend::VULKAN:
@ -103,8 +101,6 @@ std::string GPUBackendToString(GPUBackend backend) {
GPUBackend GPUBackendFromString(std::string_view backend) {
if (!equalsNoCase(backend, "OPENGL") || backend == "0")
return GPUBackend::OPENGL;
if (!equalsNoCase(backend, "DIRECT3D9") || backend == "1")
return GPUBackend::DIRECT3D9;
if (!equalsNoCase(backend, "DIRECT3D11") || backend == "2")
return GPUBackend::DIRECT3D11;
if (!equalsNoCase(backend, "VULKAN") || backend == "3")
@ -537,11 +533,6 @@ int Config::NextValidBackend() {
return (int)GPUBackend::OPENGL;
}
#endif
#if PPSSPP_API(D3D9)
if (!failed.count(GPUBackend::DIRECT3D9)) {
return (int)GPUBackend::DIRECT3D9;
}
#endif
// They've all failed. Let them try the default - or on Android, OpenGL.
sFailedGPUBackends += ",ALL";
@ -578,7 +569,7 @@ bool Config::IsBackendEnabled(GPUBackend backend) {
if (backend == GPUBackend::DIRECT3D11 && !IsVistaOrHigher())
return false;
#else
if (backend == GPUBackend::DIRECT3D11 || backend == GPUBackend::DIRECT3D9)
if (backend == GPUBackend::DIRECT3D11)
return false;
#endif
@ -1268,6 +1259,10 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
}
}
if (iGPUBackend == 1) { // d3d9, no longer supported
iGPUBackend = 2; // d3d11
}
if (iMaxRecent > 0) {
private_->ResetRecentIsosThread();
std::lock_guard<std::mutex> guard(private_->recentIsosLock);

View file

@ -97,7 +97,6 @@ enum class ScreenshotMode {
// Software is not among these because it will have one of these perform the blit to display.
enum class GPUBackend {
OPENGL = 0,
DIRECT3D9 = 1,
DIRECT3D11 = 2,
VULKAN = 3,
};

View file

@ -24,11 +24,10 @@
#include "Core/Loaders.h"
enum GPUCore {
GPUCORE_GLES,
GPUCORE_SOFTWARE,
GPUCORE_DIRECTX9,
GPUCORE_DIRECTX11,
GPUCORE_VULKAN,
GPUCORE_GLES = 0,
GPUCORE_SOFTWARE = 1,
GPUCORE_DIRECTX11 = 3,
GPUCORE_VULKAN = 4,
};
enum class FPSLimit {

View file

@ -182,10 +182,7 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) {
case GE_FORMAT_CLUT8:
if (shift == 0 && mask == 0xFF) {
// Easy peasy.
if (writer.Lang().shaderLanguage == HLSL_D3D9)
snprintf(lookupMethod, sizeof(lookupMethod), "index.a");
else
snprintf(lookupMethod, sizeof(lookupMethod), "index.r");
snprintf(lookupMethod, sizeof(lookupMethod), "index.r");
formatOK = true;
} else {
// Deal with this if we find it.
@ -318,10 +315,6 @@ void GenerateDepalShaderFloat(ShaderWriter &writer, const DepalConfig &config) {
// Offset by half a texel (plus clutBase) to turn NEAREST filtering into FLOOR.
// Technically, the clutBase should be |'d, not added, but that's hard with floats.
float texel_offset = ((float)config.startPos + 0.5f) / texturePixels;
if (writer.Lang().shaderLanguage == HLSL_D3D9) {
// Seems to need a half-pixel offset fix? Might mean it was rendered wrong...
texel_offset += 0.5f / texturePixels;
}
writer.F(" float coord = (%s * %f) + %f;\n", lookupMethod, index_multiplier, texel_offset);
writer.C(" vec4 outColor = ").SampleTexture2D("pal", "vec2(coord, 0.0)").C(";\n");
}
@ -366,7 +359,6 @@ void GenerateDepalFs(ShaderWriter &writer, const DepalConfig &config) {
GenerateDepalSmoothed(writer, config);
} else {
switch (writer.Lang().shaderLanguage) {
case HLSL_D3D9:
case GLSL_1xx:
GenerateDepalShaderFloat(writer, config);
break;

View file

@ -238,51 +238,8 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) {
WRITE(p, "layout (location = 0, index = 1) out vec4 fragColor1;\n");
}
} else if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
if (compat.shaderLanguage == HLSL_D3D9) {
if (doTexture)
WRITE(p, "sampler tex : register(s0);\n");
if (readFramebufferTex) {
WRITE(p, "vec2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE);
WRITE(p, "sampler fbotex : register(s1);\n");
}
if (replaceBlend > REPLACE_BLEND_STANDARD) {
if (replaceBlendFuncA >= GE_SRCBLEND_FIXA) {
WRITE(p, "float3 u_blendFixA : register(c%i);\n", CONST_PS_BLENDFIXA);
}
if (replaceBlendFuncB >= GE_DSTBLEND_FIXB) {
WRITE(p, "float3 u_blendFixB : register(c%i);\n", CONST_PS_BLENDFIXB);
}
}
if (needShaderTexClamp && doTexture) {
WRITE(p, "vec4 u_texclamp : register(c%i);\n", CONST_PS_TEXCLAMP);
WRITE(p, "vec2 u_texclampoff : register(c%i);\n", CONST_PS_TEXCLAMPOFF);
}
if (enableAlphaTest || enableColorTest) {
WRITE(p, "vec4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF);
WRITE(p, "vec4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK);
}
if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) {
WRITE(p, "float u_stencilReplaceValue : register(c%i);\n", CONST_PS_STENCILREPLACE);
}
if (doTexture) {
if (texFunc == GE_TEXFUNC_BLEND) {
WRITE(p, "float3 u_texenv : register(c%i);\n", CONST_PS_TEXENV);
}
if (ubershader) {
WRITE(p, "float2 u_texNoAlphaMul : register(c%i);\n", CONST_PS_TEX_NO_ALPHA_MUL);
}
}
if (enableFog) {
WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR);
}
if (texture3D) {
WRITE(p, "float u_mipBias : register(c%i);\n", CONST_PS_MIPBIAS);
}
} else {
} else if (compat.shaderLanguage == HLSL_D3D11) {
{
WRITE(p, "SamplerState texSamp : register(s0);\n");
if (texture3D) {
WRITE(p, "Texture3D<vec4> tex : register(t0);\n");
@ -334,8 +291,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (needFragCoord) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " vec4 pixelPos : SV_POSITION;\n");
} else if (compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, " vec4 pixelPos : VPOS;\n"); // VPOS is only supported for Shader Model 3.0, but we can probably forget about D3D9 SM2.0 at this point...
}
}
WRITE(p, "};\n");
@ -352,13 +307,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
WRITE(p, " float depth : SV_Depth;\n");
}
WRITE(p, "};\n");
} else if (compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, "struct PS_OUT {\n");
WRITE(p, " vec4 target : COLOR;\n");
if (writeDepth) {
WRITE(p, " float depth : DEPTH;\n");
}
WRITE(p, "};\n");
}
} else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
if ((shaderDepalMode != ShaderDepalMode::OFF || colorWriteMask) && gl_extensions.IsGLES) {
@ -545,17 +493,11 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (writeDepth) {
WRITE(p, " float gl_FragDepth;\n");
}
} else if (compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, "PS_OUT main( PS_IN In ) {\n");
WRITE(p, " PS_OUT outfragment;\n");
if (needFragCoord) {
WRITE(p, " vec4 gl_FragCoord = In.pixelPos;\n");
}
} else {
WRITE(p, "void main() {\n");
}
if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " vec4 v_color0 = In.v_color0;\n");
if (lmode) {
WRITE(p, " vec3 v_color1 = In.v_color1;\n");
@ -572,8 +514,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (readFramebufferTex) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " vec4 destColor = fbotex.Load(int3((int)gl_FragCoord.x, (int)gl_FragCoord.y, 0));\n");
} else if (compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, " vec4 destColor = tex2D(fbotex, gl_FragCoord.xy * u_fbotexSize.xy);\n", compat.texture);
} else if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, " lowp vec4 destColor = %s(fbotex, ivec3(gl_FragCoord.x, gl_FragCoord.y, %s), 0);\n", compat.texelFetch, useStereo ? "float(gl_ViewIndex)" : "0");
} else if (!compat.texelFetch) {
@ -663,20 +603,6 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
WRITE(p, " vec4 t = tex.Sample(texSamp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
}
}
} else if (compat.shaderLanguage == HLSL_D3D9) {
if (texture3D) {
if (doTextureProjection) {
WRITE(p, " vec4 t = tex3Dproj(tex, vec4(v_texcoord.x, v_texcoord.y, u_mipBias, v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : "");
} else {
WRITE(p, " vec4 t = tex3D(tex, vec3(%s.x, %s.y, u_mipBias))%s;\n", texcoord, texcoord, bgraTexture ? ".bgra" : "");
}
} else {
if (doTextureProjection) {
WRITE(p, " vec4 t = tex2Dproj(tex, vec4(v_texcoord.x, v_texcoord.y, 0.0, v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : "");
} else {
WRITE(p, " vec4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : "");
}
}
} else {
// Note that here we're relying on the filter to be linear. We would have to otherwise to do two samples and manually filter in Z.
// Let's add that if we run into a case...
@ -1012,11 +938,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
const char *test = colorTestFuncs[colorTestFunc];
if (test[0] != '#') {
// TODO: Unify these paths better.
if (compat.shaderLanguage == HLSL_D3D9) {
// TODO: Use a texture to lookup bitwise ops instead?
WRITE(p, " vec3 colortest = roundAndScaleTo255v(v.rgb);\n");
WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b)) %s\n", test, test, test, discardStatement);
} else if (compat.bitwiseOps) {
if (compat.bitwiseOps) {
WRITE(p, " uint v_uint = roundAndScaleTo8x4(v.rgb);\n");
WRITE(p, " uint v_masked = v_uint & u_alphacolormask;\n");
WRITE(p, " uint colorTestRef = (u_alphacolorref & u_alphacolormask) & 0xFFFFFFu;\n");
@ -1264,7 +1186,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n");
}
if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
if (compat.shaderLanguage == HLSL_D3D11) {
if (writeDepth) {
WRITE(p, " outfragment.depth = gl_FragDepth;\n");
}

View file

@ -1531,7 +1531,7 @@ bool FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, int
flags |= OutputFlags::BACKBUFFER_FLIPPED;
}
// CopyToOutput reverses these, probably to match "up".
if (GetGPUBackend() == GPUBackend::DIRECT3D9 || GetGPUBackend() == GPUBackend::DIRECT3D11) {
if (GetGPUBackend() == GPUBackend::DIRECT3D11) {
flags |= OutputFlags::POSITION_FLIPPED;
}
@ -1698,7 +1698,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
flags |= OutputFlags::BACKBUFFER_FLIPPED;
}
// DrawActiveTexture reverses these, probably to match "up".
if (GetGPUBackend() == GPUBackend::DIRECT3D9 || GetGPUBackend() == GPUBackend::DIRECT3D11) {
if (GetGPUBackend() == GPUBackend::DIRECT3D11) {
flags |= OutputFlags::POSITION_FLIPPED;
}

View file

@ -493,7 +493,7 @@ Draw::Pipeline *PresentationCommon::CreatePipeline(std::vector<Draw::ShaderModul
Semantic pos = SEM_POSITION;
Semantic tc = SEM_TEXCOORD0;
// Shader translation marks these both as "TEXCOORDs" on HLSL...
if (postShader && (lang_ == HLSL_D3D11 || lang_ == HLSL_D3D9)) {
if (postShader && lang_ == HLSL_D3D11) {
pos = SEM_TEXCOORD0;
tc = SEM_TEXCOORD1;
}
@ -681,12 +681,6 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u
FRect rc;
CalculateDisplayOutputRect(&rc, 480.0f, 272.0f, frame, uvRotation);
if (GetGPUBackend() == GPUBackend::DIRECT3D9) {
rc.x -= 0.5f;
// This is plus because the top is larger y.
rc.y += 0.5f;
}
// To make buffer updates easier, we use one array of verts.
int postVertsOffset = (int)sizeof(Vertex) * 4;

View file

@ -2252,9 +2252,6 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer
!(texFormat == GE_TFMT_CLUT8 && framebuffer->fb_format == GE_FORMAT_5551); // socom
switch (draw_->GetShaderLanguageDesc().shaderLanguage) {
case ShaderLanguage::HLSL_D3D9:
useShaderDepal = false;
break;
case ShaderLanguage::GLSL_1xx:
// Force off for now, in case <= GLSL 1.20 or GLES 2, which don't support switch-case.
useShaderDepal = false;

View file

@ -203,7 +203,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
*errorString = "Invalid flags - tess requires normal.";
return false;
}
if (compat.shaderLanguage == HLSL_D3D9 || compat.texelFetch == nullptr) {
if (compat.texelFetch == nullptr) {
*errorString = "Tess not supported on this shader language version";
return false;
}
@ -288,83 +288,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "layout (location = 3) out highp float v_fogdepth;\n");
WRITE(p, "invariant gl_Position;\n");
} else if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
} else if (compat.shaderLanguage == HLSL_D3D11) {
// Note: These two share some code after this hellishly large if/else.
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr);
WRITE(p, "cbuffer lights: register(b1) {\n%s};\n", ub_vs_lightsStr);
WRITE(p, "cbuffer bones : register(b2) {\n%s};\n", ub_vs_bonesStr);
} else {
WRITE(p, "#pragma warning( disable : 3571 )\n");
if (isModeThrough) {
WRITE(p, "mat4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH);
} else if (useHWTransform) {
WRITE(p, "mat4 u_proj : register(c%i);\n", CONST_VS_PROJ);
} else {
WRITE(p, "float u_rotation : register(c%i);\n", CONST_VS_ROTATION);
}
if (useHWTransform)
WRITE(p, "vec2 u_fogcoef : register(c%i);\n", CONST_VS_FOGCOEF);
if (useHWTransform || !hasColor)
WRITE(p, "vec4 u_matambientalpha : register(c%i);\n", CONST_VS_MATAMBIENTALPHA); // matambient + matalpha
if (useHWTransform) {
WRITE(p, "mat3x4 u_world : register(c%i);\n", CONST_VS_WORLD);
WRITE(p, "mat3x4 u_view : register(c%i);\n", CONST_VS_VIEW);
if (doTextureTransform)
WRITE(p, "mat3x4 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX);
if (enableBones) {
#ifdef USE_BONE_ARRAY
WRITE(p, "mat3x4 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0);
#else
for (int i = 0; i < numBoneWeights; i++) {
WRITE(p, "mat3x4 u_bone%i : register(c%i);\n", i, CONST_VS_BONE0 + i * 3);
}
#endif
}
WRITE(p, "vec4 u_uvscaleoffset : register(c%i);\n", CONST_VS_UVSCALEOFFSET);
// No need for light ubershader support here, D3D9 doesn't do it.
for (int i = 0; i < 4; i++) {
if (doLight[i] != LIGHT_OFF) {
// This is needed for shade mapping
WRITE(p, "vec3 u_lightpos%i : register(c%i);\n", i, CONST_VS_LIGHTPOS + i);
}
if (doLight[i] == LIGHT_FULL) {
GELightType type = static_cast<GELightType>(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2));
GELightComputation comp = static_cast<GELightComputation>(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2));
if (type != GE_LIGHTTYPE_DIRECTIONAL)
WRITE(p, "vec3 u_lightatt%i : register(c%i);\n", i, CONST_VS_LIGHTATT + i);
if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) {
WRITE(p, "vec3 u_lightdir%i : register(c%i);\n", i, CONST_VS_LIGHTDIR + i);
WRITE(p, "vec4 u_lightangle_spotCoef%i : register(c%i);\n", i, CONST_VS_LIGHTANGLE_SPOTCOEF + i);
}
WRITE(p, "vec3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i);
WRITE(p, "vec3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i);
if (comp == GE_LIGHTCOMP_BOTH) {
WRITE(p, "vec3 u_lightspecular%i : register(c%i);\n", i, CONST_VS_LIGHTSPECULAR + i);
}
}
}
if (enableLighting) {
WRITE(p, "vec4 u_ambient : register(c%i);\n", CONST_VS_AMBIENT);
if ((matUpdate & 2) == 0 || !hasColor)
WRITE(p, "vec3 u_matdiffuse : register(c%i);\n", CONST_VS_MATDIFFUSE);
// if ((matUpdate & 4) == 0)
WRITE(p, "vec4 u_matspecular : register(c%i);\n", CONST_VS_MATSPECULAR); // Specular coef is contained in alpha
WRITE(p, "vec3 u_matemissive : register(c%i);\n", CONST_VS_MATEMISSIVE);
}
}
if (!isModeThrough) {
WRITE(p, "vec4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
WRITE(p, "vec4 u_cullRangeMin : register(c%i);\n", CONST_VS_CULLRANGEMIN);
WRITE(p, "vec4 u_cullRangeMax : register(c%i);\n", CONST_VS_CULLRANGEMAX);
}
}
WRITE(p, "cbuffer base : register(b0) {\n%s};\n", ub_baseStr);
WRITE(p, "cbuffer lights: register(b1) {\n%s};\n", ub_vs_lightsStr);
WRITE(p, "cbuffer bones : register(b2) {\n%s};\n", ub_vs_bonesStr);
// And the "varyings".
if (useHWTransform) {
@ -417,9 +345,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
WRITE(p, " float v_fogdepth : TEXCOORD1;\n");
if (compat.shaderLanguage == HLSL_D3D9) {
WRITE(p, " vec4 gl_Position : POSITION;\n");
} else {
{
WRITE(p, " vec4 gl_Position : SV_Position;\n");
bool clipRange = vertexRangeCulling && gstate_c.Use(GPU_USE_CLIP_DISTANCE);
if (clipClampedDepth && clipRange) {
@ -647,8 +573,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "};\n");
WRITE(p, "StructuredBuffer<TessWeight> tess_weights_u : register(t1);\n");
WRITE(p, "StructuredBuffer<TessWeight> tess_weights_v : register(t2);\n");
} else if (compat.shaderLanguage == HLSL_D3D9) {
}
const char *init[3] = { "0.0, 0.0", "0.0, 0.0, 0.0", "0.0, 0.0, 0.0, 0.0" };
@ -669,7 +593,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n");
WRITE(p, " return mat4(u * v[0], u * v[1], u * v[2], u * v[3]);\n");
WRITE(p, "}\n");
} else if (compat.shaderLanguage == HLSL_D3D9 || compat.shaderLanguage == HLSL_D3D11) {
} else if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "mat4 outerProduct(vec4 u, vec4 v) {\n");
WRITE(p, " return mul((float4x1)v, (float1x4)u);\n");
WRITE(p, "}\n");
@ -683,7 +607,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " vec3 nrm;\n");
WRITE(p, "};\n");
if (compat.shaderLanguage == HLSL_D3D9 || compat.shaderLanguage == HLSL_D3D11) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "void tessellate(in VS_IN In, out Tess tess) {\n");
WRITE(p, " vec3 position = In.position;\n");
WRITE(p, " vec3 normal = In.normal;\n");
@ -770,7 +694,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (ShaderLanguageIsOpenGL(compat.shaderLanguage) || compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "void main() {\n");
} else if (compat.shaderLanguage == HLSL_D3D9 || compat.shaderLanguage == HLSL_D3D11) {
} else if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, "VS_OUT main(VS_IN In) {\n");
WRITE(p, " VS_OUT Out;\n");
if (hasTexcoord) {
@ -851,7 +775,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (doBezier || doSpline) {
// Hardware tessellation
WRITE(p, " Tess tess;\n");
if (compat.shaderLanguage == HLSL_D3D9 || compat.shaderLanguage == HLSL_D3D11) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " tessellate(In, tess);\n");
} else {
WRITE(p, " tessellate(tess);\n");
@ -1362,7 +1286,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
compat.vsOutPrefix, compat.vsOutPrefix, compat.vsOutPrefix);
}
if (compat.shaderLanguage == HLSL_D3D11 || compat.shaderLanguage == HLSL_D3D9) {
if (compat.shaderLanguage == HLSL_D3D11) {
WRITE(p, " return Out;\n");
}
WRITE(p, "}\n");

View file

@ -1,430 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <wrl/client.h>
#include "Common/Log.h"
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/TransformCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/SoftwareTransformCommon.h"
#include "GPU/Directx9/TextureCacheDX9.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
using Microsoft::WRL::ComPtr;
static const D3DPRIMITIVETYPE d3d_prim[8] = {
// Points, which are expanded to triangles.
D3DPT_TRIANGLELIST,
// Lines and line strips, which are also expanded to triangles.
D3DPT_TRIANGLELIST,
D3DPT_TRIANGLELIST,
D3DPT_TRIANGLELIST,
D3DPT_TRIANGLESTRIP,
D3DPT_TRIANGLEFAN,
// Rectangles, which are expanded to triangles.
D3DPT_TRIANGLELIST,
};
static const int D3DPRIMITIVEVERTEXCOUNT[8][2] = {
{0, 0}, // invalid
{1, 0}, // 1 = D3DPT_POINTLIST,
{2, 0}, // 2 = D3DPT_LINELIST,
{2, 1}, // 3 = D3DPT_LINESTRIP,
{3, 0}, // 4 = D3DPT_TRIANGLELIST,
{1, 2}, // 5 = D3DPT_TRIANGLESTRIP,
{1, 2}, // 6 = D3DPT_TRIANGLEFAN,
};
inline int D3DPrimCount(D3DPRIMITIVETYPE prim, int size) {
return (size / D3DPRIMITIVEVERTEXCOUNT[prim][0]) - D3DPRIMITIVEVERTEXCOUNT[prim][1];
}
enum {
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
};
static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {
{ 0, offsetof(TransformedVertex, pos), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, offsetof(TransformedVertex, uv), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, offsetof(TransformedVertex, color0), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, offsetof(TransformedVertex, color1), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
{ 0, offsetof(TransformedVertex, fog), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
D3DDECL_END()
};
DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vertexDeclMap_(64) {
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
decOptions_.expandAllWeightsToFloat = true;
decOptions_.expand8BitNormalsToFloat = true;
InitDeviceObjects();
tessDataTransferDX9 = new TessellationDataTransferDX9();
tessDataTransfer = tessDataTransferDX9;
device_->CreateVertexDeclaration(TransformedVertexElements, &transformedVertexDecl_);
}
DrawEngineDX9::~DrawEngineDX9() {
DestroyDeviceObjects();
vertexDeclMap_.Clear();
delete tessDataTransferDX9;
}
void DrawEngineDX9::InitDeviceObjects() {
draw_->SetInvalidationCallback(std::bind(&DrawEngineDX9::Invalidate, this, std::placeholders::_1));
}
void DrawEngineDX9::DestroyDeviceObjects() {
if (draw_) {
draw_->SetInvalidationCallback(InvalidationCallback());
}
}
struct DeclTypeInfo {
u32 type;
const char * name;
};
static const DeclTypeInfo VComp[] = {
{ 0, "NULL" }, // DEC_NONE,
{ D3DDECLTYPE_FLOAT1, "D3DDECLTYPE_FLOAT1 " }, // DEC_FLOAT_1,
{ D3DDECLTYPE_FLOAT2, "D3DDECLTYPE_FLOAT2 " }, // DEC_FLOAT_2,
{ D3DDECLTYPE_FLOAT3, "D3DDECLTYPE_FLOAT3 " }, // DEC_FLOAT_3,
{ D3DDECLTYPE_FLOAT4, "D3DDECLTYPE_FLOAT4 " }, // DEC_FLOAT_4,
{ 0, "UNUSED" }, // DEC_S8_3,
{ D3DDECLTYPE_SHORT4N, "D3DDECLTYPE_SHORT4N " }, // DEC_S16_3,
{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_1,
{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_2,
{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_3,
{ D3DDECLTYPE_UBYTE4N, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_4,
{0, "UNUSED_DEC_U16_1" }, // DEC_U16_1,
{0, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
};
static void VertexAttribSetup(D3DVERTEXELEMENT9 * VertexElement, u8 fmt, u8 offset, u8 usage, u8 usage_index = 0) {
memset(VertexElement, 0, sizeof(D3DVERTEXELEMENT9));
VertexElement->Offset = offset;
VertexElement->Type = VComp[fmt].type;
VertexElement->Usage = usage;
VertexElement->UsageIndex = usage_index;
}
HRESULT DrawEngineDX9::SetupDecFmtForDraw(const DecVtxFormat &decFmt, u32 pspFmt, IDirect3DVertexDeclaration9 **ppVertextDeclaration) {
ComPtr<IDirect3DVertexDeclaration9> vertexDeclCached;
if (vertexDeclMap_.Get(pspFmt, &vertexDeclCached)) {
*ppVertextDeclaration = vertexDeclCached.Detach();
return S_OK;
} else {
D3DVERTEXELEMENT9 VertexElements[8];
D3DVERTEXELEMENT9 *VertexElement = &VertexElements[0];
// Vertices Elements orders
// WEIGHT
if (decFmt.w0fmt != 0) {
VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, D3DDECLUSAGE_TEXCOORD, 1);
VertexElement++;
}
if (decFmt.w1fmt != 0) {
VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, D3DDECLUSAGE_TEXCOORD, 2);
VertexElement++;
}
// TC
if (decFmt.uvfmt != 0) {
VertexAttribSetup(VertexElement, decFmt.uvfmt, decFmt.uvoff, D3DDECLUSAGE_TEXCOORD, 0);
VertexElement++;
}
// COLOR
if (decFmt.c0fmt != 0) {
VertexAttribSetup(VertexElement, decFmt.c0fmt, decFmt.c0off, D3DDECLUSAGE_COLOR, 0);
VertexElement++;
}
// Never used ?
if (decFmt.c1fmt != 0) {
VertexAttribSetup(VertexElement, decFmt.c1fmt, decFmt.c1off, D3DDECLUSAGE_COLOR, 1);
VertexElement++;
}
// NORMAL
if (decFmt.nrmfmt != 0) {
VertexAttribSetup(VertexElement, decFmt.nrmfmt, decFmt.nrmoff, D3DDECLUSAGE_NORMAL, 0);
VertexElement++;
}
// POSITION
// Always
VertexAttribSetup(VertexElement, DecVtxFormat::PosFmt(), decFmt.posoff, D3DDECLUSAGE_POSITION, 0);
VertexElement++;
// End
D3DVERTEXELEMENT9 end = D3DDECL_END();
memcpy(VertexElement, &end, sizeof(D3DVERTEXELEMENT9));
// Create declaration
ComPtr<IDirect3DVertexDeclaration9> pHardwareVertexDecl;
HRESULT hr = device_->CreateVertexDeclaration( VertexElements, &pHardwareVertexDecl );
if (FAILED(hr)) {
ERROR_LOG(Log::G3D, "Failed to create vertex declaration!");
}
// Add it to map
vertexDeclMap_.Insert(pspFmt, pHardwareVertexDecl);
*ppVertextDeclaration = pHardwareVertexDecl.Detach();
return hr;
}
}
static uint32_t SwapRB(uint32_t c) {
return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000);
}
void DrawEngineDX9::BeginFrame() {
DrawEngineCommon::BeginFrame();
lastRenderStepId_ = -1;
}
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
void DrawEngineDX9::Invalidate(InvalidationCallbackFlags flags) {
if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
}
}
void DrawEngineDX9::Flush() {
if (!numDrawVerts_) {
return;
}
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();
gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
textureNeedsApply = true;
} else if (gstate.getTextureAddress(0) == (gstate.getFrameBufRawAddress() | 0x04000000)) {
// This catches the case of clearing a texture. (#10957)
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
}
GEPrimitiveType prim = prevPrim_;
// Always use software for flat shading to fix the provoking index.
bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE;
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
if (useHWTransform) {
LPDIRECT3DVERTEXBUFFER9 vb_ = nullptr;
LPDIRECT3DINDEXBUFFER9 ib_ = nullptr;
int vertexCount;
int maxIndex;
bool useElements;
DecodeVerts(dec_, decoded_);
DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false);
gpuStats.numUncachedVertsDrawn += vertexCount;
_dbg_assert_((int)prim > 0);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
} else {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
}
if (textureNeedsApply) {
textureCache_->ApplyTexture();
}
ApplyDrawState(prim);
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(true, useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, applySkinInDecode_, pipelineState_);
ComPtr<IDirect3DVertexDeclaration9> pHardwareVertexDecl;
SetupDecFmtForDraw(dec_->GetDecVtxFmt(), dec_->VertexType(), &pHardwareVertexDecl);
if (pHardwareVertexDecl) {
device_->SetVertexDeclaration(pHardwareVertexDecl.Get());
if (vb_ == NULL) {
if (useElements) {
device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], vertexCount), decIndex_, D3DFMT_INDEX16, decoded_, dec_->GetDecVtxFmt().stride);
} else {
device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], vertexCount), decoded_, dec_->GetDecVtxFmt().stride);
}
} else {
device_->SetStreamSource(0, vb_, 0, dec_->GetDecVtxFmt().stride);
if (useElements) {
device_->SetIndices(ib_);
device_->DrawIndexedPrimitive(d3d_prim[prim], 0, 0, numDecodedVerts_, 0, D3DPrimCount(d3d_prim[prim], vertexCount));
} else {
device_->DrawPrimitive(d3d_prim[prim], 0, D3DPrimCount(d3d_prim[prim], vertexCount));
}
}
}
if (useDepthRaster_) {
DepthRasterTransform(prim, dec_, dec_->VertexType(), vertexCount);
}
} else {
VertexDecoder *swDec = dec_;
if (swDec->nweights != 0) {
u32 withSkinning = lastVType_ | (1 << 26);
if (withSkinning != lastVType_) {
swDec = GetVertexDecoder(withSkinning);
}
}
DecodeVerts(swDec, decoded_);
int vertexCount = DecodeInds();
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);
} else {
gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);
}
gpuStats.numUncachedVertsDrawn += vertexCount;
prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim);
VERBOSE_LOG(Log::G3D, "Flush prim %i SW! %i verts in one go", prim, vertexCount);
u16 *inds = decIndex_;
SoftwareTransformResult result{};
SoftwareTransformParams params{};
params.decoded = decoded_;
params.transformed = transformed_;
params.transformedExpanded = transformedExpanded_;
params.fbman = framebufferManager_;
params.texCache = textureCache_;
params.allowClear = true;
params.allowSeparateAlphaClear = false;
params.flippedY = false;
params.usesHalfZ = true;
if (gstate.getShadeMode() == GE_SHADE_FLAT) {
// We need to rotate the index buffer to simulate a different provoking vertex.
// We do this before line expansion etc.
int indexCount = RemainingIndices(inds);
IndexBufferProvokingLastToFirst(prim, inds, vertexCount);
}
// We need correct viewport values in gstate_c already.
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
ViewportAndScissor vpAndScissor;
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
UpdateCachedViewportState(vpAndScissor);
}
// At this point, rect and line primitives are still preserved as such. So, it's the best time to do software depth raster.
// We could piggyback on the viewport transform below, but it gets complicated since it's different per-backend. Which we really
// should clean up one day...
if (useDepthRaster_) {
DepthRasterPredecoded(prim, decoded_, numDecodedVerts_, swDec, vertexCount);
}
int maxIndex = numDecodedVerts_;
SoftwareTransform swTransform(params);
// Half pixel offset hack.
float xOffset = -1.0f / gstate_c.curRTRenderWidth;
float yOffset = 1.0f / gstate_c.curRTRenderHeight;
const Lin::Vec3 trans(gstate_c.vpXOffset + xOffset, -gstate_c.vpYOffset + yOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale);
swTransform.Transform(prim, swDec->VertexType(), swDec->GetDecVtxFmt(), numDecodedVerts_, &result);
// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
result.action = SW_NOT_READY;
if (textureNeedsApply) {
gstate_c.pixelMapped = result.pixelMapped;
textureCache_->ApplyTexture();
gstate_c.pixelMapped = false;
}
ApplyDrawState(prim);
if (result.action == SW_NOT_READY)
swTransform.BuildDrawingParams(prim, vertexCount, swDec->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result);
if (result.setSafeSize)
framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);
ApplyDrawStateLate();
VSShader *vshader = shaderManager_->ApplyShader(false, false, swDec, decOptions_.expandAllWeightsToFloat, true, pipelineState_);
if (result.action == SW_DRAW_INDEXED) {
if (result.setStencil) {
dxstate.stencilFunc.set(D3DCMP_ALWAYS);
dxstate.stencilRef.set(result.stencilValue);
dxstate.stencilCompareMask.set(255);
}
// TODO: Add a post-transform cache here for multi-RECTANGLES only.
// Might help for text drawing.
device_->SetVertexDeclaration(transformedVertexDecl_.Get());
device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, numDecodedVerts_, D3DPrimCount(d3d_prim[prim], result.drawNumTrans), inds, D3DFMT_INDEX16, result.drawBuffer, sizeof(TransformedVertex));
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
float clearDepth = result.depth;
int mask = gstate.isClearModeColorMask() ? D3DCLEAR_TARGET : 0;
if (gstate.isClearModeAlphaMask()) mask |= D3DCLEAR_STENCIL;
if (gstate.isClearModeDepthMask()) mask |= D3DCLEAR_ZBUFFER;
device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24);
if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate_c.framebufFormat == GE_FORMAT_565)) {
int scissorX1 = gstate.getScissorX1();
int scissorY1 = gstate.getScissorY1();
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);
}
}
}
ResetAfterDrawInline();
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
gpuCommon_->NotifyFlush();
}
void TessellationDataTransferDX9::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {
// TODO
}

View file

@ -1,106 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <d3d9.h>
#include <wrl/client.h>
#include "Common/Data/Collections/Hashmaps.h"
#include "GPU/GPUState.h"
#include "GPU/Common/DrawEngineCommon.h"
#include "GPU/MiscTypes.h"
struct DecVtxFormat;
struct UVScale;
class VSShader;
class ShaderManagerDX9;
class TextureCacheDX9;
class FramebufferManagerDX9;
class TessellationDataTransferDX9 : public TessellationDataTransfer {
public:
TessellationDataTransferDX9() {}
~TessellationDataTransferDX9() {}
void SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) override;
};
// Handles transform, lighting and drawing.
class DrawEngineDX9 : public DrawEngineCommon {
public:
DrawEngineDX9(Draw::DrawContext *draw);
~DrawEngineDX9();
void DeviceLost() override { draw_ = nullptr; }
void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
void SetShaderManager(ShaderManagerDX9 *shaderManager) {
shaderManager_ = shaderManager;
}
void SetTextureCache(TextureCacheDX9 *textureCache) {
textureCache_ = textureCache;
}
void SetFramebufferManager(FramebufferManagerDX9 *fbManager) {
framebufferManager_ = fbManager;
}
void InitDeviceObjects();
void DestroyDeviceObjects();
void BeginFrame() override;
// So that this can be inlined
void Flush() override;
void FinishDeferred() {
DecodeVerts(dec_, decoded_);
}
protected:
// Not currently supported.
bool UpdateUseHWTessellation(bool enable) const override { return false; }
private:
void Invalidate(InvalidationCallbackFlags flags);
void ApplyDrawState(int prim);
void ApplyDrawStateLate();
HRESULT SetupDecFmtForDraw(const DecVtxFormat &decFmt, u32 pspFmt, IDirect3DVertexDeclaration9 **ppVertexDeclaration);
LPDIRECT3DDEVICE9 device_ = nullptr;
Draw::DrawContext *draw_;
DenseHashMap<u32, Microsoft::WRL::ComPtr<IDirect3DVertexDeclaration9>> vertexDeclMap_;
// SimpleVertex
Microsoft::WRL::ComPtr<IDirect3DVertexDeclaration9> transformedVertexDecl_;
// Other
ShaderManagerDX9 *shaderManager_ = nullptr;
TextureCacheDX9 *textureCache_ = nullptr;
FramebufferManagerDX9 *framebufferManager_ = nullptr;
// Hardware tessellation
TessellationDataTransferDX9 *tessDataTransferDX9;
FBOTexState fboTexBindState_ = FBO_TEX_NONE;
int lastRenderStepId_ = -1;
bool fboTexNeedsBind_ = false;
};

View file

@ -1,77 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <d3d9.h>
#include "Common/Common.h"
#include "Common/GPU/thin3d.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Common/PresentationCommon.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
FramebufferManagerDX9::FramebufferManagerDX9(Draw::DrawContext *draw)
: FramebufferManagerCommon(draw) {
presentation_->SetLanguage(HLSL_D3D9);
preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM;
}
bool FramebufferManagerDX9::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) {
// Don't yet support stretched readbacks here.
if (destW != w || destH != h) {
return false;
}
// We always read the depth buffer in 24_8 format.
LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)draw_->GetFramebufferAPITexture(fbo, Draw::Aspect::DEPTH_BIT, 0);
if (!tex)
return false;
// This is separate from the thin3d way because it applies DepthScaleFactors.
D3DSURFACE_DESC desc;
D3DLOCKED_RECT locked;
tex->GetLevelDesc(0, &desc);
RECT rect = {(LONG)x, (LONG)y, (LONG)w, (LONG)h};
HRESULT hr = tex->LockRect(0, &locked, &rect, D3DLOCK_READONLY);
if (!SUCCEEDED(hr))
return false;
const u32 *packed = (const u32 *)locked.pBits;
u16 *depth = (u16 *)pixels;
DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags());
// TODO: Optimize.
for (int yp = 0; yp < h; ++yp) {
for (int xp = 0; xp < w; ++xp) {
const int offset = (yp + y) * pixelsStride + x + xp;
float scaled = depthScale.DecodeToU16((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f));
if (scaled <= 0.0f) {
depth[offset] = 0;
} else if (scaled >= 65535.0f) {
depth[offset] = 65535;
} else {
depth[offset] = (int)scaled;
}
}
}
tex->UnlockRect(0);
return true;
}

View file

@ -1,30 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "GPU/GPUCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
class FramebufferManagerDX9 : public FramebufferManagerCommon {
public:
FramebufferManagerDX9(Draw::DrawContext *draw);
protected:
// TODO: The non-color path of FramebufferManagerCommon::ReadbackDepthbufferSync seems to work just as well.
bool ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) override;
};

View file

@ -1,151 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <string>
#include "Common/Serialize/Serializer.h"
#include "Common/GraphicsContext.h"
#include "Common/System/OSD.h"
#include "Common/Profiler/Profiler.h"
#include "Common/Data/Text/I18n.h"
#include "Core/Config.h"
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "GPU/GPUState.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/GPU_DX9.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Directx9/TextureCacheDX9.h"
GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
: GPUCommonHW(gfxCtx, draw),
drawEngine_(draw) {
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
deviceEx_ = (LPDIRECT3DDEVICE9EX)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX);
shaderManagerDX9_ = new ShaderManagerDX9(draw, device_);
framebufferManagerDX9_ = new FramebufferManagerDX9(draw);
framebufferManager_ = framebufferManagerDX9_;
textureCacheDX9_ = new TextureCacheDX9(draw, framebufferManager_->GetDraw2D());
textureCache_ = textureCacheDX9_;
drawEngineCommon_ = &drawEngine_;
shaderManager_ = shaderManagerDX9_;
drawEngine_.SetGPUCommon(this);
drawEngine_.SetShaderManager(shaderManagerDX9_);
drawEngine_.SetTextureCache(textureCacheDX9_);
drawEngine_.SetFramebufferManager(framebufferManagerDX9_);
drawEngine_.Init();
framebufferManagerDX9_->SetTextureCache(textureCacheDX9_);
framebufferManagerDX9_->SetShaderManager(shaderManagerDX9_);
framebufferManagerDX9_->SetDrawEngine(&drawEngine_);
framebufferManagerDX9_->Init(msaaLevel_);
textureCacheDX9_->SetFramebufferManager(framebufferManagerDX9_);
textureCacheDX9_->SetShaderManager(shaderManagerDX9_);
// Sanity check gstate
if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
ERROR_LOG(Log::G3D, "gstate has drifted out of sync!");
}
// No need to flush before the tex scale/offset commands if we are baking
// the tex scale/offset into the vertices anyway.
UpdateCmdInfo();
gstate_c.SetUseFlags(CheckGPUFeatures());
BuildReportingInfo();
// Some of our defaults are different from hw defaults, let's assert them.
// We restore each frame anyway, but here is convenient for tests.
dxstate.Restore();
textureCache_->NotifyConfigChanged();
if (g_Config.bHardwareTessellation) {
// Disable hardware tessellation bacause DX9 is still unsupported.
ERROR_LOG(Log::G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
// TODO: Badly formulated
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported"));
}
}
u32 GPU_DX9::CheckGPUFeatures() const {
u32 features = GPUCommonHW::CheckGPUFeatures();
features |= GPU_USE_16BIT_FORMATS;
features |= GPU_USE_TEXTURE_LOD_CONTROL;
// Accurate depth is required because the Direct3D API does not support inverse Z.
// So we cannot incorrectly use the viewport transform as the depth range on Direct3D.
features |= GPU_USE_ACCURATE_DEPTH;
return CheckGPUFeaturesLate(features);
}
void GPU_DX9::DeviceLost() {
GPUCommonHW::DeviceLost();
}
void GPU_DX9::DeviceRestore(Draw::DrawContext *draw) {
GPUCommonHW::DeviceRestore(draw);
}
void GPU_DX9::ReapplyGfxState() {
dxstate.Restore();
GPUCommonHW::ReapplyGfxState();
}
void GPU_DX9::BeginHostFrame() {
GPUCommonHW::BeginHostFrame();
textureCache_->StartFrame();
drawEngine_.BeginFrame();
shaderManagerDX9_->DirtyLastShader();
framebufferManager_->BeginFrame();
if (gstate_c.useFlagsChanged) {
// TODO: It'd be better to recompile them in the background, probably?
// This most likely means that saw equal depth changed.
WARN_LOG(Log::G3D, "Shader use flags changed, clearing all shaders and depth buffers");
shaderManager_->ClearShaders();
framebufferManager_->ClearAllDepthBuffers();
gstate_c.useFlagsChanged = false;
}
}
void GPU_DX9::FinishDeferred() {
// This finishes reading any vertex data that is pending.
drawEngine_.FinishDeferred();
}
void GPU_DX9::GetStats(char *buffer, size_t bufsize) {
size_t offset = FormatGPUStatsCommon(buffer, bufsize);
buffer += offset;
bufsize -= offset;
if ((int)bufsize < 0)
return;
snprintf(buffer, bufsize,
"Vertex, Fragment shaders loaded: %i, %i\n",
shaderManagerDX9_->GetNumVertexShaders(),
shaderManagerDX9_->GetNumFragmentShaders()
);
}

View file

@ -1,59 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <string>
#include <vector>
#include "Common/GPU/thin3d.h"
#include "GPU/GPUCommonHW.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Common/TextureShaderCommon.h"
#include "GPU/Common/VertexDecoderCommon.h"
class ShaderManagerDX9;
class LinkedShaderDX9;
class TextureCacheDX9;
class FramebufferManagerDX9;
class GPU_DX9 : public GPUCommonHW {
public:
GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
u32 CheckGPUFeatures() const override;
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;
void ReapplyGfxState() override;
void GetStats(char *buffer, size_t bufsize) override;
protected:
void FinishDeferred() override;
private:
void BeginHostFrame() override;
LPDIRECT3DDEVICE9 device_;
LPDIRECT3DDEVICE9EX deviceEx_;
FramebufferManagerDX9 *framebufferManagerDX9_;
TextureCacheDX9 *textureCacheDX9_;
DrawEngineDX9 drawEngine_;
ShaderManagerDX9 *shaderManagerDX9_;
};

View file

@ -1,706 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#ifdef _WIN32
//#define SHADERLOG
#endif
#include <cmath>
#include <map>
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Math/lin/matrix4x4.h"
#include "Common/Math/math_util.h"
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
#include "Common/GPU/thin3d.h"
#include "Common/System/OSD.h"
#include "Common/System/Display.h"
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/LogReporting.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "GPU/Math3D.h"
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Common/ShaderUniforms.h"
#include "GPU/Common/FragmentShaderGenerator.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/DrawEngineDX9.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
using namespace Lin;
PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : id_(id) {
source_ = code;
#ifdef SHADERLOG
OutputDebugString(ConvertUTF8ToWString(code).c_str());
#endif
bool success;
std::string errorMessage;
success = CompilePixelShaderD3D9(device, code, &shader, &errorMessage);
if (!errorMessage.empty()) {
if (success) {
ERROR_LOG(Log::G3D, "Warnings in shader compilation!");
} else {
ERROR_LOG(Log::G3D, "Error in shader compilation!");
}
ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());
ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str());
OutputDebugStringUTF8("Messages:\n");
OutputDebugStringUTF8(errorMessage.c_str());
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
}
if (!success) {
failed_ = true;
shader = nullptr;
return;
} else {
VERBOSE_LOG(Log::G3D, "Compiled pixel shader:\n%s\n", (const char *)code);
}
}
PSShader::~PSShader() {
}
std::string PSShader::GetShaderString(DebugShaderStringType type) const {
switch (type) {
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return FragmentShaderDesc(id_);
default:
return "N/A";
}
}
VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, bool useHWTransform) : useHWTransform_(useHWTransform), id_(id) {
source_ = code;
#ifdef SHADERLOG
OutputDebugString(ConvertUTF8ToWString(code).c_str());
#endif
bool success;
std::string errorMessage;
success = CompileVertexShaderD3D9(device, code, &shader, &errorMessage);
if (!errorMessage.empty()) {
if (success) {
ERROR_LOG(Log::G3D, "Warnings in shader compilation!");
} else {
ERROR_LOG(Log::G3D, "Error in shader compilation!");
}
ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());
ERROR_LOG(Log::G3D, "Shader source:\n%s", code);
OutputDebugStringUTF8("Messages:\n");
OutputDebugStringUTF8(errorMessage.c_str());
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
}
if (!success) {
failed_ = true;
shader = nullptr;
return;
} else {
VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code);
}
}
VSShader::~VSShader() {
}
std::string VSShader::GetShaderString(DebugShaderStringType type) const {
switch (type) {
case SHADER_STRING_SOURCE_CODE:
return source_;
case SHADER_STRING_SHORT_DESC:
return VertexShaderDesc(id_);
default:
return "N/A";
}
}
void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {
float f[4];
Uint8x3ToFloat4(f, color);
device_->SetPixelShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha) {
const float col[4] = {
(float)((color & 0xFF)),
(float)((color & 0xFF00) >> 8),
(float)((color & 0xFF0000) >> 16),
(float)alpha,
};
device_->SetPixelShaderConstantF(creg, col, 1);
}
void ShaderManagerDX9::PSSetFloat(int creg, float value) {
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
device_->SetPixelShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::PSSetFloatArray(int creg, const float *value, int count) {
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
for (int i = 0; i < count; i++) {
f[i] = value[i];
}
device_->SetPixelShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetFloat(int creg, float value) {
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
device_->SetVertexShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetFloatArray(int creg, const float *value, int count) {
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
for (int i = 0; i < count; i++) {
f[i] = value[i];
}
device_->SetVertexShaderConstantF(creg, f, 1);
}
// Utility
void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) {
float f[4];
Uint8x3ToFloat4(f, color);
device_->SetVertexShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) {
device_->SetVertexShaderConstantF(creg, data, 1);
}
void ShaderManagerDX9::VSSetFloat24Uniform3(int creg, const u32 data[3]) {
float f[4];
ExpandFloat24x3ToFloat4(f, data);
device_->SetVertexShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetFloat24Uniform3Normalized(int creg, const u32 data[3]) {
float f[4];
ExpandFloat24x3ToFloat4AndNormalize(f, data);
device_->SetVertexShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetColorUniform3Alpha(int creg, u32 color, u8 alpha) {
float f[4];
Uint8x3ToFloat4_AlphaUint8(f, color, alpha);
device_->SetVertexShaderConstantF(creg, f, 1);
}
void ShaderManagerDX9::VSSetColorUniform3ExtraFloat(int creg, u32 color, float extra) {
const float col[4] = {
((color & 0xFF)) / 255.0f,
((color & 0xFF00) >> 8) / 255.0f,
((color & 0xFF0000) >> 16) / 255.0f,
extra
};
device_->SetVertexShaderConstantF(creg, col, 1);
}
void ShaderManagerDX9::VSSetMatrix4x3_3(int creg, const float *m4x3) {
float m3x4[12];
ConvertMatrix4x3To3x4Transposed(m3x4, m4x3);
device_->SetVertexShaderConstantF(creg, m3x4, 3);
}
void ShaderManagerDX9::VSSetMatrix(int creg, const float* pMatrix) {
device_->SetVertexShaderConstantF(creg, pMatrix, 4);
}
// Depth in ogl is between -1;1 we need between 0;1 and optionally reverse it
static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY) {
// Half pixel offset hack
float xoff = 1.0f / gstate_c.curRTRenderWidth;
if (invertedX) {
xoff = -gstate_c.vpXOffset - xoff;
} else {
xoff = gstate_c.vpXOffset - xoff;
}
float yoff = -1.0f / gstate_c.curRTRenderHeight;
if (invertedY) {
yoff = -gstate_c.vpYOffset - yoff;
} else {
yoff = gstate_c.vpYOffset - yoff;
}
const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f);
const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
in.translateAndScale(trans, scale);
}
static void ConvertProjMatrixToD3DThrough(Matrix4x4 &in) {
float xoff = -1.0f / gstate_c.curRTRenderWidth;
float yoff = 1.0f / gstate_c.curRTRenderHeight;
in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
}
const uint64_t psUniforms = DIRTY_TEXENV | DIRTY_TEX_ALPHA_MUL | DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FOGCOLOR | DIRTY_STENCILREPLACEVALUE | DIRTY_SHADERBLEND | DIRTY_TEXCLAMP | DIRTY_MIPBIAS;
void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {
if (dirtyUniforms & DIRTY_TEXENV) {
PSSetColorUniform3(CONST_PS_TEXENV, gstate.texenvcolor);
}
if (dirtyUniforms & DIRTY_ALPHACOLORREF) {
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
}
if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORMASK, gstate.colortestmask, gstate.getAlphaTestMask());
}
if (dirtyUniforms & DIRTY_FOGCOLOR) {
PSSetColorUniform3(CONST_PS_FOGCOLOR, gstate.fogcolor);
}
if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {
PSSetFloat(CONST_PS_STENCILREPLACE, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
}
if (dirtyUniforms & DIRTY_TEX_ALPHA_MUL) {
bool doTextureAlpha = gstate.isTextureAlphaUsed();
if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) {
doTextureAlpha = false;
}
// NOTE: Reversed value, more efficient in shader.
float noAlphaMul[2] = { doTextureAlpha ? 0.0f : 1.0f, gstate.isColorDoublingEnabled() ? 2.0f : 1.0f };
PSSetFloatArray(CONST_PS_TEX_NO_ALPHA_MUL, noAlphaMul, 2);
}
if (dirtyUniforms & DIRTY_SHADERBLEND) {
PSSetColorUniform3(CONST_PS_BLENDFIXA, gstate.getFixA());
PSSetColorUniform3(CONST_PS_BLENDFIXB, gstate.getFixB());
const float fbotexSize[2] = {
1.0f / (float)gstate_c.curRTRenderWidth,
1.0f / (float)gstate_c.curRTRenderHeight,
};
PSSetFloatArray(CONST_PS_FBOTEXSIZE, fbotexSize, 2);
}
if (dirtyUniforms & DIRTY_TEXCLAMP) {
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
const int w = gstate.getTextureWidth(0);
const int h = gstate.getTextureHeight(0);
const float widthFactor = (float)w * invW;
const float heightFactor = (float)h * invH;
// First wrap xy, then half texel xy (for clamp.)
const float texclamp[4] = {
widthFactor,
heightFactor,
invW * 0.5f,
invH * 0.5f,
};
const float texclampoff[2] = {
gstate_c.curTextureXOffset * invW,
gstate_c.curTextureYOffset * invH,
};
PSSetFloatArray(CONST_PS_TEXCLAMP, texclamp, 4);
PSSetFloatArray(CONST_PS_TEXCLAMPOFF, texclampoff, 2);
}
if (dirtyUniforms & DIRTY_MIPBIAS) {
float mipBias = (float)gstate.getTexLevelOffset16() * (1.0 / 16.0f);
// NOTE: This equation needs some adjustment in D3D9. Can't get it to look completely smooth :(
mipBias = (mipBias + 0.25f) / (float)(gstate.getTextureMaxLevel() + 1);
PSSetFloatArray(CONST_PS_MIPBIAS, &mipBias, 1);
}
}
const uint64_t vsUniforms = DIRTY_PROJMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX |
DIRTY_FOGCOEF | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |
DIRTY_AMBIENT | DIRTY_MATAMBIENTALPHA | DIRTY_MATSPECULAR | DIRTY_MATDIFFUSE | DIRTY_MATEMISSIVE | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3;
void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
// Update any dirty uniforms before we draw
if (dirtyUniforms & DIRTY_PROJMATRIX) {
Matrix4x4 flippedMatrix;
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
const bool invertedY = gstate_c.vpHeight < 0;
if (!invertedY) {
flippedMatrix[1] = -flippedMatrix[1];
flippedMatrix[5] = -flippedMatrix[5];
flippedMatrix[9] = -flippedMatrix[9];
flippedMatrix[13] = -flippedMatrix[13];
}
const bool invertedX = gstate_c.vpWidth < 0;
if (invertedX) {
flippedMatrix[0] = -flippedMatrix[0];
flippedMatrix[4] = -flippedMatrix[4];
flippedMatrix[8] = -flippedMatrix[8];
flippedMatrix[12] = -flippedMatrix[12];
}
ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY);
VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr());
VSSetFloat(CONST_VS_ROTATION, 0); // We don't use this on any platform in D3D9.
}
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
Matrix4x4 proj_through;
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);
ConvertProjMatrixToD3DThrough(proj_through);
VSSetMatrix(CONST_VS_PROJ_THROUGH, proj_through.getReadPtr());
}
// Transform
if (dirtyUniforms & DIRTY_WORLDMATRIX) {
VSSetMatrix4x3_3(CONST_VS_WORLD, gstate.worldMatrix);
}
if (dirtyUniforms & DIRTY_VIEWMATRIX) {
VSSetMatrix4x3_3(CONST_VS_VIEW, gstate.viewMatrix);
}
if (dirtyUniforms & DIRTY_TEXMATRIX) {
VSSetMatrix4x3_3(CONST_VS_TEXMTX, gstate.tgenMatrix);
}
if (dirtyUniforms & DIRTY_FOGCOEF) {
float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
if (my_isnanorinf(fogcoef[0])) {
// Not really sure what a sensible value might be, but let's try 64k.
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
}
if (my_isnanorinf(fogcoef[1])) {
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
}
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
}
// TODO: Could even set all bones in one go if they're all dirty.
#ifdef USE_BONE_ARRAY
if (u_bone != 0) {
float allBones[8 * 16];
bool allDirty = true;
for (int i = 0; i < numBones; i++) {
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);
} else {
allDirty = false;
}
}
if (allDirty) {
// Set them all with one call
//glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);
} else {
// Set them one by one. Could try to coalesce two in a row etc but too lazy.
for (int i = 0; i < numBones; i++) {
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
//glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);
}
}
}
}
#else
for (int i = 0; i < 8; i++) {
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
VSSetMatrix4x3_3(CONST_VS_BONE0 + 3 * i, gstate.boneMatrix + 12 * i);
}
}
#endif
// Texturing
if (dirtyUniforms & DIRTY_UVSCALEOFFSET) {
float widthFactor = 1.0f;
float heightFactor = 1.0f;
if (gstate_c.textureIsFramebuffer) {
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
const int w = gstate.getTextureWidth(0);
const int h = gstate.getTextureHeight(0);
widthFactor = (float)w * invW;
heightFactor = (float)h * invH;
}
float uvscaleoff[4];
uvscaleoff[0] = widthFactor;
uvscaleoff[1] = heightFactor;
uvscaleoff[2] = 0.0f;
uvscaleoff[3] = 0.0f;
VSSetFloatArray(CONST_VS_UVSCALEOFFSET, uvscaleoff, 4);
}
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
// Depth is [0, 1] mapping to [minz, maxz], not too hard.
float vpZScale = gstate.getViewportZScale();
float vpZCenter = gstate.getViewportZCenter();
// These are just the reverse of the formulas in GPUStateUtils.
float halfActualZRange = InfToZero(gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f);
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
float viewZScale = halfActualZRange * 2.0f;
float viewZCenter = minz;
float reverseScale = InfToZero(gstate_c.vpDepthScale != 0.0f ? 2.0f * (1.0f / gstate_c.vpDepthScale) : 0.0f);
float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;
float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
if (draw_->GetDeviceCaps().clipPlanesSupported >= 1) {
float clip[4] = { 0.0f, 0.0f, reverseScale, 1.0f - reverseTranslate * reverseScale };
// Well, not a uniform, but we treat it as one like other backends.
device_->SetClipPlane(0, clip);
}
}
if (dirtyUniforms & DIRTY_CULLRANGE) {
float minValues[4], maxValues[4];
CalcCullRange(minValues, maxValues, false, false);
VSSetFloatUniform4(CONST_VS_CULLRANGEMIN, minValues);
VSSetFloatUniform4(CONST_VS_CULLRANGEMAX, maxValues);
}
// Lighting
if (dirtyUniforms & DIRTY_AMBIENT) {
VSSetColorUniform3Alpha(CONST_VS_AMBIENT, gstate.ambientcolor, gstate.getAmbientA());
}
if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {
VSSetColorUniform3Alpha(CONST_VS_MATAMBIENTALPHA, gstate.materialambient, gstate.getMaterialAmbientA());
}
if (dirtyUniforms & DIRTY_MATDIFFUSE) {
VSSetColorUniform3(CONST_VS_MATDIFFUSE, gstate.materialdiffuse);
}
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
VSSetColorUniform3(CONST_VS_MATEMISSIVE, gstate.materialemissive);
}
if (dirtyUniforms & DIRTY_MATSPECULAR) {
VSSetColorUniform3ExtraFloat(CONST_VS_MATSPECULAR, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
}
for (int i = 0; i < 4; i++) {
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
if (gstate.isDirectionalLight(i)) {
VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);
} else {
VSSetFloat24Uniform3(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);
}
VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTDIR + i, &gstate.ldir[i * 3]);
VSSetFloat24Uniform3(CONST_VS_LIGHTATT + i, &gstate.latt[i * 3]);
float angle_spotCoef[4] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };
VSSetFloatUniform4(CONST_VS_LIGHTANGLE_SPOTCOEF + i, angle_spotCoef);
VSSetColorUniform3(CONST_VS_LIGHTAMBIENT + i, gstate.lcolor[i * 3]);
VSSetColorUniform3(CONST_VS_LIGHTDIFFUSE + i, gstate.lcolor[i * 3 + 1]);
VSSetColorUniform3(CONST_VS_LIGHTSPECULAR + i, gstate.lcolor[i * 3 + 2]);
}
}
}
ShaderManagerDX9::ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device)
: ShaderManagerCommon(draw), device_(device) {
codeBuffer_ = new char[32768];
}
ShaderManagerDX9::~ShaderManagerDX9() {
delete [] codeBuffer_;
}
void ShaderManagerDX9::Clear() {
for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) {
delete iter->second;
}
for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) {
delete iter->second;
}
fsCache_.clear();
vsCache_.clear();
DirtyLastShader();
}
void ShaderManagerDX9::ClearShaders() {
Clear();
}
void ShaderManagerDX9::DirtyLastShader() {
// Forget the last shader ID
lastFSID_.set_invalid();
lastVSID_.set_invalid();
lastVShader_ = nullptr;
lastPShader_ = nullptr;
// TODO: Probably not necessary to dirty uniforms here on DX9.
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
VShaderID VSID;
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
} else {
VSID = lastVSID_;
}
FShaderID FSID;
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());
} else {
FSID = lastFSID_;
}
// Just update uniforms if this is the same shader as last time.
if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
if (dirtyUniforms) {
if (dirtyUniforms & psUniforms)
PSUpdateUniforms(dirtyUniforms);
if (dirtyUniforms & vsUniforms)
VSUpdateUniforms(dirtyUniforms);
gstate_c.CleanUniforms();
}
return lastVShader_; // Already all set.
}
VSCache::iterator vsIter = vsCache_.find(VSID);
VSShader *vs = nullptr;
if (vsIter == vsCache_.end()) {
// Vertex shader not in cache. Let's compile it.
std::string genErrorString;
uint32_t attrMask;
uint64_t uniformMask;
VertexShaderFlags flags;
if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) {
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
}
if (!vs || vs->Failed()) {
if (!vs) {
// TODO: Report this?
ERROR_LOG(Log::G3D, "Shader generation failed, falling back to software transform");
} else {
ERROR_LOG(Log::G3D, "Shader compilation failed, falling back to software transform");
}
if (!g_Config.bHideSlowWarnings) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f);
}
delete vs;
ComputeVertexShaderID(&VSID, decoder, false, false, weightsAsFloat, useSkinInDecode);
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match
// next time and we'll do this over and over...
// Can still work with software transform.
uint32_t attrMask;
uint64_t uniformMask;
bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);
_assert_(success);
vs = new VSShader(device_, VSID, codeBuffer_, false);
}
vsCache_[VSID] = vs;
} else {
vs = vsIter->second;
}
lastVSID_ = VSID;
FSCache::iterator fsIter = fsCache_.find(FSID);
PSShader *fs;
if (fsIter == fsCache_.end()) {
// Fragment shader not in cache. Let's compile it.
std::string errorString;
uint64_t uniformMask;
FragmentShaderFlags flags;
bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString);
// We're supposed to handle all possible cases.
_assert_(success);
fs = new PSShader(device_, FSID, codeBuffer_);
fsCache_[FSID] = fs;
} else {
fs = fsIter->second;
}
lastFSID_ = FSID;
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
if (dirtyUniforms) {
if (dirtyUniforms & psUniforms)
PSUpdateUniforms(dirtyUniforms);
if (dirtyUniforms & vsUniforms)
VSUpdateUniforms(dirtyUniforms);
gstate_c.CleanUniforms();
}
device_->SetPixelShader(fs->shader.Get());
device_->SetVertexShader(vs->shader.Get());
lastPShader_ = fs;
lastVShader_ = vs;
return vs;
}
std::vector<std::string> ShaderManagerDX9::DebugGetShaderIDs(DebugShaderType type) {
std::string id;
std::vector<std::string> ids;
switch (type) {
case SHADER_TYPE_VERTEX:
for (auto iter : vsCache_) {
iter.first.ToString(&id);
ids.push_back(id);
}
break;
case SHADER_TYPE_FRAGMENT:
for (auto iter : fsCache_) {
iter.first.ToString(&id);
ids.push_back(id);
}
break;
case SHADER_TYPE_GEOMETRY:
case SHADER_TYPE_PIPELINE:
case SHADER_TYPE_SAMPLER:
case SHADER_TYPE_TEXTURE:
case SHADER_TYPE_VERTEXLOADER:
break;
}
return ids;
}
std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
ShaderID shaderId;
shaderId.FromString(id);
switch (type) {
case SHADER_TYPE_VERTEX:
{
auto iter = vsCache_.find(VShaderID(shaderId));
if (iter == vsCache_.end()) {
return "";
}
return iter->second->GetShaderString(stringType);
}
case SHADER_TYPE_FRAGMENT:
{
auto iter = fsCache_.find(FShaderID(shaderId));
if (iter == fsCache_.end()) {
return "";
}
return iter->second->GetShaderString(stringType);
}
default:
return "N/A";
}
}

View file

@ -1,131 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <map>
#include <cstdint>
#include <d3d9.h>
#include <wrl/client.h>
#include "Common/CommonTypes.h"
#include "GPU/Common/VertexShaderGenerator.h"
#include "GPU/Common/FragmentShaderGenerator.h"
#include "GPU/Common/ShaderCommon.h"
#include "GPU/Common/ShaderId.h"
#include "Common/Math/lin/matrix4x4.h"
class PSShader;
class VSShader;
// Real public interface
class PSShader {
public:
PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code);
~PSShader();
const std::string &source() const { return source_; }
bool Failed() const { return failed_; }
std::string GetShaderString(DebugShaderStringType type) const;
Microsoft::WRL::ComPtr<IDirect3DPixelShader9> shader;
protected:
std::string source_;
bool failed_ = false;
FShaderID id_;
};
class VSShader {
public:
VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, bool useHWTransform);
~VSShader();
const std::string &source() const { return source_; }
bool Failed() const { return failed_; }
bool UseHWTransform() const { return useHWTransform_; }
std::string GetShaderString(DebugShaderStringType type) const;
Microsoft::WRL::ComPtr<IDirect3DVertexShader9> shader;
protected:
std::string source_;
bool failed_ = false;
bool useHWTransform_;
VShaderID id_;
};
class ShaderManagerDX9 : public ShaderManagerCommon {
public:
ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device);
~ShaderManagerDX9();
void ClearShaders() override;
VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState);
void DirtyLastShader() override;
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
void DeviceLost() override { draw_ = nullptr; }
void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type) override;
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) override;
private:
void PSUpdateUniforms(u64 dirtyUniforms);
void VSUpdateUniforms(u64 dirtyUniforms);
inline void PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha);
inline void PSSetColorUniform3(int creg, u32 color);
inline void PSSetFloat(int creg, float value);
inline void PSSetFloatArray(int creg, const float *value, int count);
void VSSetMatrix4x3_3(int creg, const float *m4x3);
inline void VSSetColorUniform3(int creg, u32 color);
inline void VSSetColorUniform3ExtraFloat(int creg, u32 color, float extra);
inline void VSSetColorUniform3Alpha(int creg, u32 color, u8 alpha);
void VSSetMatrix(int creg, const float* pMatrix);
void VSSetFloat(int creg, float value);
void VSSetFloatArray(int creg, const float *value, int count);
void VSSetFloat24Uniform3(int creg, const u32 data[3]);
void VSSetFloat24Uniform3Normalized(int creg, const u32 data[3]);
void VSSetFloatUniform4(int creg, const float data[4]);
void Clear();
LPDIRECT3DDEVICE9 device_;
FShaderID lastFSID_;
VShaderID lastVSID_;
char *codeBuffer_;
VSShader *lastVShader_ = nullptr;
PSShader *lastPShader_ = nullptr;
typedef std::map<FShaderID, PSShader *> FSCache;
FSCache fsCache_;
typedef std::map<VShaderID, VSShader *> VSCache;
VSCache vsCache_;
};

View file

@ -1,302 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Profiler/Profiler.h"
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "Core/System.h"
#include "Core/Config.h"
#include "GPU/Math3D.h"
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Directx9/GPU_DX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "GPU/Directx9/TextureCacheDX9.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
static const D3DBLEND dxBlendFactorLookup[(size_t)BlendFactor::COUNT] = {
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA,
D3DBLEND_BLENDFACTOR,
D3DBLEND_INVBLENDFACTOR,
D3DBLEND_BLENDFACTOR,
D3DBLEND_INVBLENDFACTOR,
#if 0 // TODO: Requires D3D9Ex
D3DBLEND_SRCCOLOR2,
D3DBLEND_INVSRCCOLOR2,
D3DBLEND_SRCCOLOR2,
D3DBLEND_INVSRCCOLOR2,
#else
D3DBLEND_FORCE_DWORD,
D3DBLEND_FORCE_DWORD,
#endif
D3DBLEND_FORCE_DWORD,
};
static const D3DBLENDOP dxBlendEqLookup[(size_t)BlendEq::COUNT] = {
D3DBLENDOP_ADD,
D3DBLENDOP_SUBTRACT,
D3DBLENDOP_REVSUBTRACT,
D3DBLENDOP_MIN,
D3DBLENDOP_MAX,
};
static const D3DCULL cullingMode[] = {
D3DCULL_CW,
D3DCULL_CCW,
};
static const D3DCMPFUNC ztests[] = {
D3DCMP_NEVER, D3DCMP_ALWAYS, D3DCMP_EQUAL, D3DCMP_NOTEQUAL,
D3DCMP_LESS, D3DCMP_LESSEQUAL, D3DCMP_GREATER, D3DCMP_GREATEREQUAL,
};
static const D3DSTENCILOP stencilOps[] = {
D3DSTENCILOP_KEEP,
D3DSTENCILOP_ZERO,
D3DSTENCILOP_REPLACE,
D3DSTENCILOP_INVERT,
D3DSTENCILOP_INCRSAT,
D3DSTENCILOP_DECRSAT,
D3DSTENCILOP_KEEP, // reserved
D3DSTENCILOP_KEEP, // reserved
};
void DrawEngineDX9::ApplyDrawState(int prim) {
if (!gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
// nothing to do
return;
}
// At this point, we know if the vertices are full alpha or not.
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
if (!gstate.isModeClear()) {
textureCache_->ApplyTexture();
if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) {
// Note that this is positions, not UVs, that we need the copy from.
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY, 0);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
fboTexBound_ = true;
fboTexBindState_ = FBO_TEX_NONE;
}
// TODO: Test texture?
}
bool useBufferedRendering = framebufferManager_->UseBufferedRendering();
if (gstate_c.IsDirty(DIRTY_BLEND_STATE)) {
if (gstate.isModeClear()) {
dxstate.blend.disable();
// Color Mask
u32 mask = 0;
if (gstate.isClearModeColorMask()) {
mask |= 7;
}
if (gstate.isClearModeAlphaMask()) {
mask |= 8;
}
dxstate.colorMask.set(mask);
} else {
pipelineState_.Convert(draw_->GetShaderLanguageDesc().bitwiseOps);
GenericMaskState &maskState = pipelineState_.maskState;
GenericBlendState &blendState = pipelineState_.blendState;
// We ignore the logicState on D3D since there's no support, the emulation of it is blend-and-shader only.
if (pipelineState_.FramebufferRead()) {
ApplyFramebufferRead(&fboTexBindState_);
// The shader takes over the responsibility for blending, so recompute.
ApplyStencilReplaceAndLogicOpIgnoreBlend(blendState.replaceAlphaWithStencil, blendState);
if (fboTexBindState_ == FBO_TEX_COPY_BIND_TEX) {
// Note that this is positions, not UVs, that we need the copy from.
framebufferManager_->BindFramebufferAsColorTexture(1, framebufferManager_->GetCurrentRenderVFB(), BINDFBCOLOR_MAY_COPY | BINDFBCOLOR_UNCACHED, Draw::ALL_LAYERS);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
fboTexBound_ = true;
fboTexBindState_ = FBO_TEX_NONE;
dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE;
gstate_c.Dirty(DIRTY_BLEND_STATE);
} else if (fboTexBindState_ == FBO_TEX_READ_FRAMEBUFFER) {
// Not supported.
fboTexBindState_ = FBO_TEX_NONE;
}
dirtyRequiresRecheck_ |= DIRTY_FRAGMENTSHADER_STATE;
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
} else {
if (fboTexBound_) {
dirtyRequiresRecheck_ |= DIRTY_FRAGMENTSHADER_STATE;
gstate_c.Dirty(DIRTY_FRAGMENTSHADER_STATE);
fboTexBound_ = false;
}
}
if (blendState.blendEnabled) {
dxstate.blend.enable();
dxstate.blendSeparate.enable();
dxstate.blendEquation.set(dxBlendEqLookup[(size_t)blendState.eqColor], dxBlendEqLookup[(size_t)blendState.eqAlpha]);
dxstate.blendFunc.set(
dxBlendFactorLookup[(size_t)blendState.srcColor], dxBlendFactorLookup[(size_t)blendState.dstColor],
dxBlendFactorLookup[(size_t)blendState.srcAlpha], dxBlendFactorLookup[(size_t)blendState.dstAlpha]);
if (blendState.dirtyShaderBlendFixValues) {
dirtyRequiresRecheck_ |= DIRTY_SHADERBLEND;
gstate_c.Dirty(DIRTY_SHADERBLEND);
}
if (blendState.useBlendColor) {
dxstate.blendColor.setDWORD(blendState.blendColor);
}
} else {
dxstate.blend.disable();
}
dxstate.colorMask.set(maskState.channelMask);
}
}
if (gstate_c.IsDirty(DIRTY_RASTER_STATE)) {
bool wantCull = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && prim > GE_PRIM_LINE_STRIP && gstate.isCullEnabled();
if (wantCull) {
if (gstate.getCullMode() == 1) {
dxstate.cullMode.set(D3DCULL_CCW);
} else {
dxstate.cullMode.set(D3DCULL_CW);
}
} else {
dxstate.cullMode.set(D3DCULL_NONE);
}
if (gstate.isModeClear()) {
// Well, probably doesn't matter...
dxstate.shadeMode.set(D3DSHADE_GOURAUD);
} else {
dxstate.shadeMode.set(gstate.getShadeMode() == GE_SHADE_GOURAUD ? D3DSHADE_GOURAUD : D3DSHADE_FLAT);
}
// We use fixed-function user clipping on D3D9, where available, for negative Z clipping.
if (draw_->GetDeviceCaps().clipPlanesSupported >= 1) {
bool wantClip = !gstate.isModeThrough() && gstate_c.submitType == SubmitType::DRAW;
dxstate.clipPlaneEnable.set(wantClip ? 1 : 0);
}
}
if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) {
GenericStencilFuncState stencilState;
ConvertStencilFuncState(stencilState);
// Set Stencil/Depth
if (gstate.isModeClear()) {
// Depth Test
dxstate.depthTest.enable();
dxstate.depthFunc.set(D3DCMP_ALWAYS);
dxstate.depthWrite.set(gstate.isClearModeDepthMask());
// Stencil Test
bool alphaMask = gstate.isClearModeAlphaMask();
if (alphaMask) {
dxstate.stencilTest.enable();
dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE);
dxstate.stencilFunc.set(D3DCMP_ALWAYS);
dxstate.stencilRef.set(0xFF);
dxstate.stencilCompareMask.set(0xFF);
dxstate.stencilWriteMask.set(stencilState.writeMask);
} else {
dxstate.stencilTest.disable();
}
} else {
// Depth Test
if (!IsDepthTestEffectivelyDisabled()) {
dxstate.depthTest.enable();
dxstate.depthFunc.set(ztests[gstate.getDepthTestFunction()]);
dxstate.depthWrite.set(gstate.isDepthWriteEnabled());
UpdateEverUsedEqualDepth(gstate.getDepthTestFunction());
} else {
dxstate.depthTest.disable();
}
// Stencil Test
if (stencilState.enabled) {
dxstate.stencilTest.enable();
dxstate.stencilFunc.set(ztests[stencilState.testFunc]);
dxstate.stencilRef.set(stencilState.testRef);
dxstate.stencilCompareMask.set(stencilState.testMask);
dxstate.stencilOp.set(stencilOps[stencilState.sFail], stencilOps[stencilState.zFail], stencilOps[stencilState.zPass]);
dxstate.stencilWriteMask.set(stencilState.writeMask);
// Nasty special case for Spongebob and similar where it tries to write zeros to alpha/stencil during
// depth-fail. We can't write to alpha then because the pixel is killed. However, we can invert the depth
// test and modify the alpha function...
if (SpongebobDepthInverseConditions(stencilState)) {
dxstate.blend.set(true);
dxstate.blendEquation.set(D3DBLENDOP_ADD, D3DBLENDOP_ADD);
dxstate.blendFunc.set(D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ZERO);
dxstate.colorMask.set(8);
dxstate.depthFunc.set(D3DCMP_LESS);
dxstate.stencilFunc.set(D3DCMP_ALWAYS);
// Invert
dxstate.stencilOp.set(D3DSTENCILOP_ZERO, D3DSTENCILOP_KEEP, D3DSTENCILOP_ZERO);
dirtyRequiresRecheck_ |= DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE;
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE);
}
} else {
dxstate.stencilTest.disable();
}
}
}
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
ViewportAndScissor vpAndScissor;
ConvertViewportAndScissor(useBufferedRendering,
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
UpdateCachedViewportState(vpAndScissor);
dxstate.scissorTest.enable();
dxstate.scissorRect.set(vpAndScissor.scissorX, vpAndScissor.scissorY, vpAndScissor.scissorX + vpAndScissor.scissorW, vpAndScissor.scissorY + vpAndScissor.scissorH);
float depthMin = vpAndScissor.depthRangeMin;
float depthMax = vpAndScissor.depthRangeMax;
dxstate.viewport.set(vpAndScissor.viewportX, vpAndScissor.viewportY, vpAndScissor.viewportW, vpAndScissor.viewportH, depthMin, depthMax);
}
gstate_c.Clean(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_BLEND_STATE);
gstate_c.Dirty(dirtyRequiresRecheck_);
dirtyRequiresRecheck_ = 0;
}
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)?
}

View file

@ -1,442 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <algorithm>
#include <cstring>
#include <wrl/client.h>
#include "Common/TimeUtil.h"
#include "Core/MemMap.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Directx9/TextureCacheDX9.h"
#include "GPU/Directx9/FramebufferManagerDX9.h"
#include "GPU/Directx9/ShaderManagerDX9.h"
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "GPU/Common/TextureShaderCommon.h"
#include "GPU/Common/FramebufferManagerCommon.h"
#include "GPU/Common/TextureDecoder.h"
#include "Core/Config.h"
#include "ext/xxhash.h"
#include "Common/Math/math_util.h"
// NOTE: In the D3D backends, we flip R and B in the shaders, so while these look wrong, they're OK.
using Microsoft::WRL::ComPtr;
Draw::DataFormat FromD3D9Format(u32 fmt) {
switch (fmt) {
case D3DFMT_A4R4G4B4: return Draw::DataFormat::B4G4R4A4_UNORM_PACK16;
case D3DFMT_A1R5G5B5: return Draw::DataFormat::A1R5G5B5_UNORM_PACK16;
case D3DFMT_R5G6B5: return Draw::DataFormat::R5G6B5_UNORM_PACK16;
case D3DFMT_A8: return Draw::DataFormat::R8_UNORM;
case D3DFMT_A8R8G8B8: default: return Draw::DataFormat::R8G8B8A8_UNORM;
}
}
D3DFORMAT ToD3D9Format(Draw::DataFormat fmt) {
switch (fmt) {
case Draw::DataFormat::BC1_RGBA_UNORM_BLOCK: return D3DFMT_DXT1;
case Draw::DataFormat::BC2_UNORM_BLOCK: return D3DFMT_DXT3;
case Draw::DataFormat::BC3_UNORM_BLOCK: return D3DFMT_DXT5;
case Draw::DataFormat::R8G8B8A8_UNORM: return D3DFMT_A8R8G8B8;
default: _dbg_assert_(false); return D3DFMT_A8R8G8B8;
}
}
#define INVALID_TEX (LPDIRECT3DTEXTURE9)(-1)
static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
TextureCacheDX9::TextureCacheDX9(Draw::DrawContext *draw, Draw2D *draw2D)
: TextureCacheCommon(draw, draw2D) {
lastBoundTexture = INVALID_TEX;
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
deviceEx_ = (LPDIRECT3DDEVICE9EX)draw->GetNativeObject(Draw::NativeObject::DEVICE_EX);
D3DCAPS9 pCaps;
ZeroMemory(&pCaps, sizeof(pCaps));
HRESULT result = 0;
if (deviceEx_) {
result = deviceEx_->GetDeviceCaps(&pCaps);
} else {
result = device_->GetDeviceCaps(&pCaps);
}
if (FAILED(result)) {
WARN_LOG(Log::G3D, "Failed to get the device caps!");
maxAnisotropyLevel = 16;
} else {
maxAnisotropyLevel = pCaps.MaxAnisotropy;
}
nextTexture_ = nullptr;
device_->CreateVertexDeclaration(g_FramebufferVertexElements, &pFramebufferVertexDecl);
}
TextureCacheDX9::~TextureCacheDX9() {
Clear(true);
}
void TextureCacheDX9::SetFramebufferManager(FramebufferManagerDX9 *fbManager) {
framebufferManager_ = fbManager;
}
void TextureCacheDX9::ReleaseTexture(TexCacheEntry *entry, bool delete_them) {
LPDIRECT3DBASETEXTURE9 &texture = DxTex(entry);
if (texture) {
texture->Release();
texture = nullptr;
}
}
void TextureCacheDX9::ForgetLastTexture() {
lastBoundTexture = INVALID_TEX;
}
static D3DFORMAT getClutDestFormat(GEPaletteFormat format) {
switch (format) {
case GE_CMODE_16BIT_ABGR4444:
return D3DFMT_A4R4G4B4;
case GE_CMODE_16BIT_ABGR5551:
return D3DFMT_A1R5G5B5;
case GE_CMODE_16BIT_BGR5650:
return D3DFMT_R5G6B5;
case GE_CMODE_32BIT_ABGR8888:
return D3DFMT_A8R8G8B8;
}
// Should never be here !
return D3DFMT_A8R8G8B8;
}
void TextureCacheDX9::ApplySamplingParams(const SamplerCacheKey &key) {
D3DTEXTUREFILTERTYPE minFilt = (false ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR);
dxstate.texMinFilter.set(key.minFilt ? minFilt : D3DTEXF_POINT);
dxstate.texMipFilter.set(key.mipFilt ? D3DTEXF_LINEAR : D3DTEXF_POINT);
dxstate.texMagFilter.set(key.magFilt ? D3DTEXF_LINEAR : D3DTEXF_POINT);
// DX9 mip levels are .. odd. The "max level" sets the LARGEST mip to use.
// We can enforce only the top mip level by setting a massive negative lod bias.
if (!key.mipEnable) {
dxstate.texMaxMipLevel.set(0);
dxstate.texMipLodBias.set(-100.0f);
} else {
dxstate.texMipLodBias.set((float)key.lodBias / 256.0f);
dxstate.texMaxMipLevel.set(key.minLevel / 256);
}
dxstate.texAddressU.set(key.sClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP);
dxstate.texAddressV.set(key.tClamp ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP);
}
void TextureCacheDX9::StartFrame() {
TextureCacheCommon::StartFrame();
if (gstate_c.Use(GPU_USE_ANISOTROPY)) {
// Just take the opportunity to set the global aniso level here, once per frame.
DWORD aniso = 1 << g_Config.iAnisotropyLevel;
DWORD anisotropyLevel = aniso > maxAnisotropyLevel ? maxAnisotropyLevel : aniso;
device_->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, anisotropyLevel);
}
}
void TextureCacheDX9::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) {
const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16));
// Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier.
// If not, we're going to hash random data, which hopefully doesn't cause a performance issue.
//
// TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data.
// clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash
// unrelated old entries for small palettes.
// Adding clutBaseBytes may just be mitigating this for some usage patterns.
const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_);
if (replacer_.Enabled())
clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888);
else
clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF;
clutBuf_ = clutBufRaw_;
// Special optimization: fonts typically draw clut4 with just alpha values in a single color.
clutAlphaLinear_ = false;
clutAlphaLinearColor_ = 0;
if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) {
const u16_le *clut = GetCurrentClut<u16_le>();
clutAlphaLinear_ = true;
clutAlphaLinearColor_ = clut[15] & 0x0FFF;
for (int i = 0; i < 16; ++i) {
u16 step = clutAlphaLinearColor_ | (i << 12);
if (clut[i] != step) {
clutAlphaLinear_ = false;
break;
}
}
}
clutLastFormat_ = gstate.clutformat;
}
void TextureCacheDX9::BindTexture(TexCacheEntry *entry) {
if (!entry) {
device_->SetTexture(0, nullptr);
return;
}
IDirect3DBaseTexture9 *texture = DxTex(entry);
if (texture != lastBoundTexture) {
device_->SetTexture(0, texture);
lastBoundTexture = texture;
}
int maxLevel = (entry->status & TexCacheEntry::STATUS_NO_MIPS) ? 0 : entry->maxLevel;
SamplerCacheKey samplerKey = GetSamplingParams(maxLevel, entry);
ApplySamplingParams(samplerKey);
}
void TextureCacheDX9::Unbind() {
device_->SetTexture(0, nullptr);
ForgetLastTexture();
}
void TextureCacheDX9::BindAsClutTexture(Draw::Texture *tex, bool smooth) {
LPDIRECT3DBASETEXTURE9 clutTexture = (LPDIRECT3DBASETEXTURE9)draw_->GetNativeObject(Draw::NativeObject::TEXTURE_VIEW, tex);
device_->SetTexture(1, clutTexture);
device_->SetSamplerState(1, D3DSAMP_MINFILTER, smooth ? D3DTEXF_LINEAR : D3DTEXF_POINT);
device_->SetSamplerState(1, D3DSAMP_MAGFILTER, smooth ? D3DTEXF_LINEAR : D3DTEXF_POINT);
device_->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
}
void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry) {
BuildTexturePlan plan;
if (!PrepareBuildTexture(plan, entry)) {
// We're screwed?
return;
}
D3DFORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
if (plan.doReplace) {
dstFmt = ToD3D9Format(plan.replaced->Format());
} else if (plan.scaleFactor > 1 || plan.saveTexture) {
dstFmt = D3DFMT_A8R8G8B8;
} else if (plan.decodeToClut8) {
dstFmt = D3DFMT_A8;
}
int levels;
LPDIRECT3DBASETEXTURE9 &texture = DxTex(entry);
D3DPOOL pool = D3DPOOL_DEFAULT;
int usage = D3DUSAGE_DYNAMIC;
int tw;
int th;
plan.GetMipSize(0, &tw, &th);
HRESULT hr;
if (plan.depth == 1) {
// We don't yet have mip generation, so clamp the number of levels to the ones we can load directly.
levels = std::min(plan.levelsToCreate, plan.levelsToLoad);
LPDIRECT3DTEXTURE9 tex;
hr = device_->CreateTexture(tw, th, levels, usage, dstFmt, pool, &tex, nullptr);
texture = tex;
} else {
LPDIRECT3DVOLUMETEXTURE9 tex;
hr = device_->CreateVolumeTexture(tw, th, plan.depth, 1, usage, dstFmt, pool, &tex, nullptr);
texture = tex;
levels = 1;
}
if (FAILED(hr)) {
INFO_LOG(Log::G3D, "Failed to create D3D texture: %dx%d", tw, th);
ReleaseTexture(entry, true);
return;
}
if (!texture) {
// What to do here?
return;
}
if (plan.depth == 1) {
// Regular loop.
for (int i = 0; i < levels; i++) {
int dstLevel = i;
HRESULT result;
uint32_t lockFlag = dstLevel == 0 ? D3DLOCK_DISCARD : 0; // Can only discard the top level
D3DLOCKED_RECT rect{};
result = ((LPDIRECT3DTEXTURE9)texture)->LockRect(dstLevel, &rect, NULL, lockFlag);
if (FAILED(result)) {
ERROR_LOG(Log::G3D, "Failed to lock D3D 2D texture at level %d: %dx%d", i, plan.w, plan.h);
return;
}
uint8_t *data = (uint8_t *)rect.pBits;
int stride = rect.Pitch;
LoadTextureLevel(*entry, data, 0, stride, plan, (i == 0) ? plan.baseLevelSrc : i, FromD3D9Format(dstFmt), TexDecodeFlags{});
((LPDIRECT3DTEXTURE9)texture)->UnlockRect(dstLevel);
}
} else {
// 3D loop.
D3DLOCKED_BOX box;
HRESULT result = ((LPDIRECT3DVOLUMETEXTURE9)texture)->LockBox(0, &box, nullptr, D3DLOCK_DISCARD);
if (FAILED(result)) {
ERROR_LOG(Log::G3D, "Failed to lock D3D 2D texture: %dx%dx%d", plan.w, plan.h, plan.depth);
return;
}
uint8_t *data = (uint8_t *)box.pBits;
int stride = box.RowPitch;
for (int i = 0; i < plan.depth; i++) {
LoadTextureLevel(*entry, data, 0, stride, plan, (i == 0) ? plan.baseLevelSrc : i, FromD3D9Format(dstFmt), TexDecodeFlags{});
data += box.SlicePitch;
}
((LPDIRECT3DVOLUMETEXTURE9)texture)->UnlockBox(0);
}
// Signal that we support depth textures so use it as one.
if (plan.depth > 1) {
entry->status |= TexCacheEntry::STATUS_3D;
}
if (plan.doReplace) {
entry->SetAlphaStatus(TexCacheEntry::TexStatus(plan.replaced->AlphaStatus()));
if (!Draw::DataFormatIsBlockCompressed(plan.replaced->Format(), nullptr)) {
entry->status |= TexCacheEntry::STATUS_BGRA;
}
} else {
entry->status |= TexCacheEntry::STATUS_BGRA;
}
}
D3DFORMAT TextureCacheDX9::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const {
switch (format) {
case GE_TFMT_CLUT4:
case GE_TFMT_CLUT8:
case GE_TFMT_CLUT16:
case GE_TFMT_CLUT32:
return getClutDestFormat(clutFormat);
case GE_TFMT_4444:
return D3DFMT_A4R4G4B4;
case GE_TFMT_5551:
return D3DFMT_A1R5G5B5;
case GE_TFMT_5650:
return D3DFMT_R5G6B5;
case GE_TFMT_8888:
case GE_TFMT_DXT1:
case GE_TFMT_DXT3:
case GE_TFMT_DXT5:
default:
return D3DFMT_A8R8G8B8;
}
}
bool TextureCacheDX9::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) {
SetTexture();
if (!nextTexture_) {
return GetCurrentFramebufferTextureDebug(buffer, isFramebuffer);
}
ApplyTexture();
ComPtr<IDirect3DBaseTexture9> baseTex;
ComPtr<IDirect3DTexture9> tex;
ComPtr<IDirect3DSurface9> offscreen;
HRESULT hr;
bool success = false;
hr = device_->GetTexture(0, &baseTex);
if (SUCCEEDED(hr) && baseTex != NULL) {
hr = baseTex.As(&tex);
if (SUCCEEDED(hr)) {
D3DSURFACE_DESC desc;
D3DLOCKED_RECT locked;
tex->GetLevelDesc(level, &desc);
RECT rect = { 0, 0, (LONG)desc.Width, (LONG)desc.Height };
hr = tex->LockRect(level, &locked, &rect, D3DLOCK_READONLY);
// If it fails, this means it's a render-to-texture, so we have to get creative.
if (FAILED(hr)) {
ComPtr<IDirect3DSurface9> renderTarget;
hr = tex->GetSurfaceLevel(level, &renderTarget);
if (renderTarget && SUCCEEDED(hr)) {
hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, NULL);
if (SUCCEEDED(hr)) {
hr = device_->GetRenderTargetData(renderTarget.Get(), offscreen.Get());
if (SUCCEEDED(hr)) {
hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY);
}
}
}
*isFramebuffer = true;
} else {
*isFramebuffer = false;
}
if (SUCCEEDED(hr)) {
GPUDebugBufferFormat fmt;
int pixelSize;
switch (desc.Format) {
case D3DFMT_A1R5G5B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_5551 : GPU_DBG_FORMAT_5551_BGRA;
pixelSize = 2;
break;
case D3DFMT_A4R4G4B4:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_4444 : GPU_DBG_FORMAT_4444_BGRA;
pixelSize = 2;
break;
case D3DFMT_R5G6B5:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_565 : GPU_DBG_FORMAT_565_BGRA;
pixelSize = 2;
break;
case D3DFMT_A8R8G8B8:
fmt = gstate_c.bgraTexture ? GPU_DBG_FORMAT_8888 : GPU_DBG_FORMAT_8888_BGRA;
pixelSize = 4;
break;
default:
fmt = GPU_DBG_FORMAT_INVALID;
break;
}
if (fmt != GPU_DBG_FORMAT_INVALID) {
buffer.Allocate(locked.Pitch / pixelSize, desc.Height, fmt, false);
memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height);
success = true;
} else {
success = false;
}
if (offscreen) {
offscreen->UnlockRect();
} else {
tex->UnlockRect(level);
}
}
}
}
return success;
}
void *TextureCacheDX9::GetNativeTextureView(const TexCacheEntry *entry, bool flat) const {
LPDIRECT3DBASETEXTURE9 tex = DxTex(entry);
return (void *)tex;
}

View file

@ -1,79 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <d3d9.h>
#include <wrl/client.h>
#include "GPU/GPU.h"
#include "GPU/GPUCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
struct VirtualFramebuffer;
class TextureShaderCache;
class FramebufferManagerDX9;
class ShaderManagerDX9;
class TextureCacheDX9 : public TextureCacheCommon {
public:
TextureCacheDX9(Draw::DrawContext *draw, Draw2D *draw2D);
~TextureCacheDX9();
void StartFrame() override;
void SetFramebufferManager(FramebufferManagerDX9 *fbManager);
void ForgetLastTexture() override;
bool GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level, bool *isFramebuffer) override;
void DeviceLost() override { draw_ = nullptr; }
void DeviceRestore(Draw::DrawContext *draw) override { draw_ = draw; }
protected:
void BindTexture(TexCacheEntry *entry) override;
void Unbind() override;
void ReleaseTexture(TexCacheEntry *entry, bool delete_them) override;
void BindAsClutTexture(Draw::Texture *tex, bool smooth) override;
void *GetNativeTextureView(const TexCacheEntry *entry, bool flat) const override;
private:
void ApplySamplingParams(const SamplerCacheKey &key) override;
D3DFORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const;
void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override;
void BuildTexture(TexCacheEntry *const entry) override;
static LPDIRECT3DBASETEXTURE9 &DxTex(const TexCacheEntry *entry) {
return *(LPDIRECT3DBASETEXTURE9 *)&entry->texturePtr;
}
Microsoft::WRL::ComPtr<IDirect3DDevice9> device_;
Microsoft::WRL::ComPtr<IDirect3DDevice9Ex> deviceEx_;
Microsoft::WRL::ComPtr<IDirect3DVertexDeclaration9> pFramebufferVertexDecl;
IDirect3DBaseTexture9 *lastBoundTexture = nullptr;
float maxAnisotropyLevel;
FramebufferManagerDX9 *framebufferManagerDX9_;
};
static D3DFORMAT getClutDestFormat(GEPaletteFormat format);

View file

@ -31,10 +31,6 @@
#include "GPU/Vulkan/GPU_Vulkan.h"
#include "GPU/Software/SoftGpu.h"
#if PPSSPP_API(D3D9)
#include "GPU/Directx9/GPU_DX9.h"
#endif
#if PPSSPP_API(D3D11)
#include "GPU/D3D11/GPU_D3D11.h"
#endif
@ -86,13 +82,6 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) {
case GPUCORE_SOFTWARE:
SetGPU(new SoftGPU(ctx, draw));
break;
case GPUCORE_DIRECTX9:
#if PPSSPP_API(D3D9)
SetGPU(new GPU_DX9(ctx, draw));
break;
#else
return false;
#endif
case GPUCORE_DIRECTX11:
#if PPSSPP_API(D3D11)
SetGPU(new GPU_D3D11(ctx, draw));

View file

@ -389,11 +389,6 @@
<ClInclude Include="Debugger\RecordFormat.h" />
<ClInclude Include="Debugger\State.h" />
<ClInclude Include="Debugger\Stepping.h" />
<ClInclude Include="Directx9\FramebufferManagerDX9.h" />
<ClInclude Include="Directx9\GPU_DX9.h" />
<ClInclude Include="Directx9\ShaderManagerDX9.h" />
<ClInclude Include="Directx9\TextureCacheDX9.h" />
<ClInclude Include="Directx9\DrawEngineDX9.h" />
<ClInclude Include="ge_constants.h" />
<ClInclude Include="GeDisasm.h" />
<ClInclude Include="GLES\FragmentTestCacheGLES.h">
@ -538,12 +533,6 @@
<ClCompile Include="Debugger\Record.cpp" />
<ClCompile Include="Debugger\State.cpp" />
<ClCompile Include="Debugger\Stepping.cpp" />
<ClCompile Include="Directx9\FramebufferManagerDX9.cpp" />
<ClCompile Include="Directx9\GPU_DX9.cpp" />
<ClCompile Include="Directx9\ShaderManagerDX9.cpp" />
<ClCompile Include="Directx9\StateMappingDX9.cpp" />
<ClCompile Include="Directx9\TextureCacheDX9.cpp" />
<ClCompile Include="Directx9\DrawEngineDX9.cpp" />
<ClCompile Include="GeDisasm.cpp" />
<ClCompile Include="GeConstants.cpp" />
<ClCompile Include="GLES\FragmentTestCacheGLES.cpp">
@ -693,4 +682,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -10,9 +10,6 @@
<Filter Include="Common">
<UniqueIdentifier>{21783292-4dd7-447b-af93-356cd2eaa4d6}</UniqueIdentifier>
</Filter>
<Filter Include="DirectX9">
<UniqueIdentifier>{88629970-4774-4122-b031-2128244b795c}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger">
<UniqueIdentifier>{0cbddc00-4aa3-41d0-bed2-a454d37f838e}</UniqueIdentifier>
</Filter>
@ -60,18 +57,6 @@
<ClInclude Include="GLES\DrawEngineGLES.h">
<Filter>GLES</Filter>
</ClInclude>
<ClInclude Include="Directx9\GPU_DX9.h">
<Filter>DirectX9</Filter>
</ClInclude>
<ClInclude Include="Directx9\DrawEngineDX9.h">
<Filter>DirectX9</Filter>
</ClInclude>
<ClInclude Include="Directx9\TextureCacheDX9.h">
<Filter>DirectX9</Filter>
</ClInclude>
<ClInclude Include="Directx9\ShaderManagerDX9.h">
<Filter>DirectX9</Filter>
</ClInclude>
<ClInclude Include="Common\IndexGenerator.h">
<Filter>Common</Filter>
</ClInclude>
@ -225,9 +210,6 @@
<ClInclude Include="Common\FramebufferManagerCommon.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Directx9\FramebufferManagerDX9.h">
<Filter>DirectX9</Filter>
</ClInclude>
<ClInclude Include="ge_constants.h">
<Filter>Common</Filter>
</ClInclude>
@ -314,21 +296,6 @@
<ClCompile Include="GLES\DrawEngineGLES.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="Directx9\GPU_DX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Directx9\DrawEngineDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Directx9\TextureCacheDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Directx9\StateMappingDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Directx9\ShaderManagerDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="Common\IndexGenerator.cpp">
<Filter>Common</Filter>
</ClCompile>
@ -491,9 +458,6 @@
<ClCompile Include="Common\FramebufferManagerCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Directx9\FramebufferManagerDX9.cpp">
<Filter>DirectX9</Filter>
</ClCompile>
<ClCompile Include="GeConstants.cpp">
<Filter>Common</Filter>
</ClCompile>

View file

@ -634,7 +634,6 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
case GPUBackend::OPENGL:
outputFlags |= OutputFlags::BACKBUFFER_FLIPPED;
break;
case GPUBackend::DIRECT3D9:
case GPUBackend::DIRECT3D11:
outputFlags |= OutputFlags::POSITION_FLIPPED;
break;

View file

@ -619,11 +619,6 @@ void SystemInfoScreen::CreateDeviceInfoTab(UI::LinearLayout *deviceSpecs) {
if (GetGPUBackend() != GPUBackend::VULKAN) {
gpuInfo->Add(new InfoItem(si->T("Driver Version"), System_GetProperty(SYSPROP_GPUDRIVER_VERSION)));
}
#if !PPSSPP_PLATFORM(UWP)
if (GetGPUBackend() == GPUBackend::DIRECT3D9) {
gpuInfo->Add(new InfoItem(si->T("D3DCompiler Version"), StringFromFormat("%d", GetD3DCompilerVersion())));
}
#endif
#endif
if (GetGPUBackend() == GPUBackend::OPENGL) {
gpuInfo->Add(new InfoItem(si->T("Core Context"), gl_extensions.IsCoreContext ? di->T("Active") : di->T("Inactive")));
@ -1277,14 +1272,13 @@ void TouchTestScreen::CreateViews() {
root_->Add(theTwo);
#if !PPSSPP_PLATFORM(UWP)
static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" };
static const char *renderingBackend[] = { "OpenGL", "(n/a)", "Direct3D 11", "Vulkan" };
PopupMultiChoice *renderingBackendChoice = root_->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), I18NCat::GRAPHICS, screenManager()));
renderingBackendChoice->OnChoice.Handle(this, &TouchTestScreen::OnRenderingBackend);
if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL);
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9))
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9);
renderingBackendChoice->HideChoice(1); // previously D3D9
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11);
if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))

View file

@ -329,9 +329,6 @@ void EmuScreen::bootGame(const Path &filename) {
coreParam.gpuCore = GPUCORE_GLES;
break;
#endif
case GPUBackend::DIRECT3D9:
coreParam.gpuCore = GPUCORE_DIRECTX9;
break;
case GPUBackend::VULKAN:
coreParam.gpuCore = GPUCORE_VULKAN;
break;

View file

@ -299,15 +299,11 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
#if !PPSSPP_PLATFORM(UWP)
static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" };
PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), I18NCat::GRAPHICS, screenManager()));
if (g_Config.iGPUBackend != (int)GPUBackend::DIRECT3D9 && !draw->GetDeviceCaps().supportsD3D9) {
renderingBackendChoice->HideChoice(1);
}
renderingBackendChoice->HideChoice(1);
renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend);
if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL);
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9))
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9);
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11);
if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))

View file

@ -30,7 +30,6 @@
#include "Windows/GPU/WindowsGLContext.h"
#endif
#include "Windows/GPU/WindowsVulkanContext.h"
#include "Windows/GPU/D3D9Context.h"
#include "Windows/GPU/D3D11Context.h"
enum class EmuThreadState {
@ -173,9 +172,6 @@ bool CreateGraphicsBackend(std::string *error_message, GraphicsContext **ctx) {
graphicsContext = new WindowsGLContext();
break;
#endif
case (int)GPUBackend::DIRECT3D9:
graphicsContext = new D3D9Context();
break;
case (int)GPUBackend::DIRECT3D11:
graphicsContext = new D3D11Context();
break;
@ -267,19 +263,15 @@ void MainThreadFunc() {
const char *defaultErrorOpenGL = "Failed initializing graphics. Try upgrading your graphics drivers.\n\nWould you like to try switching to DirectX 9?\n\nError message:";
const char *defaultErrorDirect3D9 = "Failed initializing graphics. Try upgrading your graphics drivers and directx 9 runtime.\n\nWould you like to try switching to OpenGL?\n\nError message:";
std::string_view genericError;
GPUBackend nextBackend = GPUBackend::DIRECT3D9;
GPUBackend nextBackend = GPUBackend::VULKAN;
switch (g_Config.iGPUBackend) {
case (int)GPUBackend::DIRECT3D9:
nextBackend = GPUBackend::OPENGL;
genericError = err->T("GenericDirect3D9Error", defaultErrorDirect3D9);
break;
case (int)GPUBackend::VULKAN:
nextBackend = GPUBackend::OPENGL;
genericError = err->T("GenericVulkanError", defaultErrorVulkan);
break;
case (int)GPUBackend::OPENGL:
default:
nextBackend = GPUBackend::DIRECT3D9;
nextBackend = GPUBackend::DIRECT3D11;
genericError = err->T("GenericOpenGLError", defaultErrorOpenGL);
break;
}
@ -296,11 +288,6 @@ void MainThreadFunc() {
g_Config.Save("save_graphics_fallback");
W32Util::ExitAndRestart();
} else {
if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D9) {
// Allow the user to download the DX9 runtime.
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.microsoft.com/en-us/download/details.aspx?id=34429");
}
}
// No safe way out without graphics.

View file

@ -104,13 +104,13 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
}
if (FAILED(hr)) {
const char *defaultError = "Your GPU does not appear to support Direct3D 11.\n\nWould you like to try again using Direct3D 9 instead?";
const char *defaultError = "Your GPU does not appear to support Direct3D 11.\n\nWould you like to try again using OpenGL instead?";
auto err = GetI18NCategory(I18NCat::ERRORS);
std::wstring error;
if (result == LoadD3D11Error::FAIL_NO_COMPILER) {
error = ConvertUTF8ToWString(err->T("D3D11CompilerMissing", "D3DCompiler_47.dll not found. Please install. Or press Yes to try again using Direct3D9 instead."));
error = ConvertUTF8ToWString(err->T("D3D11CompilerMissing", "D3DCompiler_47.dll not found. Please install. Or press Yes to try again using OpenGL instead."));
} else if (result == LoadD3D11Error::FAIL_NO_D3D11) {
error = ConvertUTF8ToWString(err->T("D3D11Missing", "Your operating system version does not include D3D11. Please run Windows Update.\n\nPress Yes to try again using Direct3D9 instead."));
}
@ -119,8 +119,8 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
std::wstring title = ConvertUTF8ToWString(err->T("D3D11InitializationError", "Direct3D 11 initialization error"));
bool yes = IDYES == MessageBox(hWnd_, error.c_str(), title.c_str(), MB_ICONERROR | MB_YESNO);
if (yes) {
// Change the config to D3D9 and restart.
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
// Change the config to OpenGL and restart.
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
g_Config.sFailedGPUBackends.clear();
g_Config.Save("save_d3d9_fallback");

View file

@ -1,197 +0,0 @@
#include "ppsspp_config.h"
#include "Common/CommonWindows.h"
#include <d3d9.h>
#include "Common/GPU/D3D9/D3D9StateCache.h"
#include "Common/System/Display.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Log.h"
#include "Common/OSVersion.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/System.h"
#include "Common/OSVersion.h"
#include "Windows/GPU/D3D9Context.h"
#include "Windows/W32Util/Misc.h"
#include "Common/GPU/thin3d.h"
#include "Common/GPU/thin3d_create.h"
#include "Common/GPU/D3D9/D3DCompilerLoader.h"
typedef HRESULT (__stdcall *DIRECT3DCREATE9EX)(UINT, IDirect3D9Ex**);
bool D3D9Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
bool windowed = true;
hWnd_ = wnd;
// D3D9 has no need for display rotation.
g_display.rotation = DisplayRotation::ROTATE_0;
g_display.rot_matrix.setIdentity();
DIRECT3DCREATE9EX g_pfnCreate9ex;
hD3D9_ = LoadLibrary(TEXT("d3d9.dll"));
if (!hD3D9_) {
ERROR_LOG(Log::G3D, "Missing d3d9.dll");
*error_message = "D3D9.dll missing - try reinstalling DirectX.";
return false;
}
bool result = LoadD3DCompilerDynamic();
if (!result) {
*error_message = "D3DCompiler not found! Try reinstalling DirectX.";
return false;
}
g_pfnCreate9ex = (DIRECT3DCREATE9EX)GetProcAddress(hD3D9_, "Direct3DCreate9Ex");
has9Ex_ = (g_pfnCreate9ex != NULL) && IsVistaOrHigher();
if (has9Ex_) {
HRESULT result = g_pfnCreate9ex(D3D_SDK_VERSION, &d3dEx_);
d3d_ = d3dEx_;
if (FAILED(result)) {
FreeLibrary(hD3D9_);
*error_message = "D3D9Ex available but context creation failed. Try reinstalling DirectX.";
return false;
}
} else {
d3d_ = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d_) {
FreeLibrary(hD3D9_);
*error_message = "Failed to create D3D9 context. Try reinstalling DirectX.";
return false;
}
}
adapterId_ = D3DADAPTER_DEFAULT;
D3DCAPS9 d3dCaps;
D3DDISPLAYMODE d3ddm;
if (FAILED(d3d_->GetAdapterDisplayMode(adapterId_, &d3ddm))) {
*error_message = "GetAdapterDisplayMode failed";
d3d_ = nullptr;
return false;
}
if (FAILED(d3d_->GetDeviceCaps(adapterId_, D3DDEVTYPE_HAL, &d3dCaps))) {
*error_message = "GetDeviceCaps failed (?)";
d3d_ = nullptr;
return false;
}
HRESULT hr;
if (FAILED(hr = d3d_->CheckDeviceFormat(adapterId_,
D3DDEVTYPE_HAL,
d3ddm.Format,
D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE,
D3DFMT_D24S8))) {
if (hr == D3DERR_NOTAVAILABLE) {
*error_message = "D24S8 depth/stencil not available";
d3d_ = nullptr;
return false;
}
}
DWORD dwBehaviorFlags = D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE;
if (d3dCaps.VertexProcessingCaps != 0)
dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
int xres, yres;
W32Util::GetWindowRes(hWnd_, &xres, &yres);
presentParams_ = {};
presentParams_.BackBufferWidth = xres;
presentParams_.BackBufferHeight = yres;
presentParams_.BackBufferFormat = d3ddm.Format;
presentParams_.MultiSampleType = D3DMULTISAMPLE_NONE;
presentParams_.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParams_.Windowed = windowed;
presentParams_.hDeviceWindow = wnd;
presentParams_.EnableAutoDepthStencil = true;
presentParams_.AutoDepthStencilFormat = D3DFMT_D24S8;
presentParams_.PresentationInterval = swapInterval_ == 1 ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
if (has9Ex_) {
if (windowed && IsWin7OrHigher()) {
// This "new" flip mode should give higher performance but doesn't.
//pp.BackBufferCount = 2;
//pp.SwapEffect = D3DSWAPEFFECT_FLIPEX;
}
hr = d3dEx_->CreateDeviceEx(adapterId_, D3DDEVTYPE_HAL, wnd, dwBehaviorFlags, &presentParams_, NULL, &deviceEx_);
device_ = deviceEx_;
} else {
hr = d3d_->CreateDevice(adapterId_, D3DDEVTYPE_HAL, wnd, dwBehaviorFlags, &presentParams_, &device_);
}
if (FAILED(hr)) {
*error_message = "Failed to create D3D device";
d3d_ = nullptr;
return false;
}
device_->BeginScene();
pD3Ddevice9 = device_;
pD3DdeviceEx9 = deviceEx_;
if (deviceEx_ && IsWin7OrHigher()) {
// TODO: This makes it slower?
//deviceEx->SetMaximumFrameLatency(1);
}
draw_ = Draw::T3DCreateDX9Context(d3d_.Get(), d3dEx_.Get(), adapterId_, device_.Get(), deviceEx_.Get());
SetGPUBackend(GPUBackend::DIRECT3D9);
if (!draw_->CreatePresets()) {
// Shader compiler not installed? Return an error so we can fall back to GL.
device_ = nullptr;
d3d_ = nullptr;
*error_message = "DirectX9 runtime not correctly installed. Please install.";
return false;
}
if (draw_)
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr);
return true;
}
void D3D9Context::Resize() {
// This should only be called from the emu thread.
int xres, yres;
W32Util::GetWindowRes(hWnd_, &xres, &yres);
uint32_t newInterval = swapInterval_ == 1 ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
bool w_changed = presentParams_.BackBufferWidth != xres;
bool h_changed = presentParams_.BackBufferHeight != yres;
bool i_changed = presentParams_.PresentationInterval != newInterval;
if (device_ && (w_changed || h_changed || i_changed)) {
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
presentParams_.BackBufferWidth = xres;
presentParams_.BackBufferHeight = yres;
presentParams_.PresentationInterval = newInterval;
HRESULT hr = device_->Reset(&presentParams_);
if (FAILED(hr)) {
// Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015.
_assert_msg_(false, "Unable to reset D3D9 device");
}
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, 0, 0, nullptr);
}
}
void D3D9Context::Shutdown() {
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, 0, 0, nullptr);
delete draw_;
draw_ = nullptr;
device_->EndScene();
device_ = nullptr;
d3d_ = nullptr;
UnloadD3DCompiler();
pD3Ddevice9 = nullptr;
pD3DdeviceEx9 = nullptr;
device_ = nullptr;
hWnd_ = nullptr;
FreeLibrary(hD3D9_);
hD3D9_ = nullptr;
}

View file

@ -1,57 +0,0 @@
// Copyright (c) 2015- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// Modelled on OpenD3DBase. Might make a cleaner interface later.
#pragma once
#include "Common/CommonWindows.h"
#include "Windows/GPU/WindowsGraphicsContext.h"
#include <d3d9.h>
#include <wrl/client.h>
namespace Draw {
class DrawContext;
}
class D3D9Context : public WindowsGraphicsContext {
public:
D3D9Context() : draw_(nullptr), has9Ex_(false), d3d_(nullptr), d3dEx_(nullptr), adapterId_(-1), device_(nullptr), deviceEx_(nullptr), hDC_(nullptr), hWnd_(nullptr), hD3D9_(nullptr), presentParams_{} {
}
bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override;
void Shutdown() override;
void Resize() override;
Draw::DrawContext *GetDrawContext() override { return draw_; }
private:
Draw::DrawContext *draw_;
bool has9Ex_;
Microsoft::WRL::ComPtr<IDirect3D9> d3d_;
Microsoft::WRL::ComPtr<IDirect3D9Ex> d3dEx_;
int adapterId_;
Microsoft::WRL::ComPtr<IDirect3DDevice9> device_;
Microsoft::WRL::ComPtr<IDirect3DDevice9Ex> deviceEx_;
HDC hDC_; // Private GDI Device Context
HWND hWnd_; // Holds Our Window Handle
HMODULE hD3D9_;
D3DPRESENT_PARAMETERS presentParams_;
int swapInterval_ = 0;
};

View file

@ -270,10 +270,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
if (yes) {
// Change the config to D3D and restart.
const char *d3d9Or11 = "Direct3D 9? (Or no for Direct3D 11)";
std::wstring whichD3D9 = ConvertUTF8ToWString(err->T("D3D9or11", d3d9Or11));
bool d3d9 = IDYES == MessageBox(hWnd_, whichD3D9.c_str(), title.c_str(), MB_YESNO);
g_Config.iGPUBackend = d3d9 ? (int)GPUBackend::DIRECT3D9 : (int)GPUBackend::DIRECT3D11;
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
g_Config.sFailedGPUBackends.clear();
g_Config.Save("save_d3d11_fallback");

View file

@ -280,7 +280,6 @@ namespace MainWindow {
// Skip window size 1x-4x..
TranslateMenuItem(menu, ID_OPTIONS_BACKEND_MENU);
TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D11);
TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D9);
TranslateMenuItem(menu, ID_OPTIONS_OPENGL);
TranslateMenuItem(menu, ID_OPTIONS_VULKAN);
@ -688,12 +687,6 @@ namespace MainWindow {
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
break;
case ID_OPTIONS_DIRECT3D9:
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
g_Config.Save("gpu_choice");
RestartApp();
break;
case ID_OPTIONS_DIRECT3D11:
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
g_Config.Save("gpu_choice");
@ -1187,48 +1180,31 @@ namespace MainWindow {
CheckMenuItem(menu, savestateSlot[i], MF_BYCOMMAND | ((i == g_Config.iCurrentStateSlot) ? MF_CHECKED : MF_UNCHECKED));
}
bool allowD3D9 = g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9);
bool allowD3D11 = g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11);
bool allowOpenGL = g_Config.IsBackendEnabled(GPUBackend::OPENGL);
bool allowVulkan = g_Config.IsBackendEnabled(GPUBackend::VULKAN);
switch (GetGPUBackend()) {
case GPUBackend::DIRECT3D9:
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_CHECKED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
break;
case GPUBackend::OPENGL:
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_CHECKED);
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
break;
case GPUBackend::VULKAN:
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_GRAYED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_CHECKED);
break;
case GPUBackend::DIRECT3D11:
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D9, allowD3D9 ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D9, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_CHECKED);
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);

View file

@ -842,7 +842,6 @@
<ClCompile Include="CaptureDevice.cpp" />
<ClCompile Include="Debugger\WatchItemWindow.cpp" />
<ClCompile Include="GPU\D3D11Context.cpp" />
<ClCompile Include="GPU\D3D9Context.cpp" />
<ClCompile Include="Debugger\BreakpointWindow.cpp" />
<ClCompile Include="Debugger\EditSymbolsWindow.cpp" />
<ClCompile Include="Debugger\CtrlDisAsmView.cpp" />
@ -1400,7 +1399,6 @@
<ClInclude Include="CaptureDevice.h" />
<ClInclude Include="Debugger\WatchItemWindow.h" />
<ClInclude Include="GPU\D3D11Context.h" />
<ClInclude Include="GPU\D3D9Context.h" />
<ClInclude Include="Debugger\BreakpointWindow.h" />
<ClInclude Include="Debugger\EditSymbolsWindow.h" />
<ClInclude Include="Debugger\CtrlDisAsmView.h" />
@ -1764,4 +1762,4 @@
<UserProperties RESOURCE_FILE="DaSh.rc" />
</VisualStudio>
</ProjectExtensions>
</Project>
</Project>

View file

@ -175,9 +175,6 @@
<ClCompile Include="MainWindow.cpp">
<Filter>Windows\UI</Filter>
</ClCompile>
<ClCompile Include="GPU\D3D9Context.cpp">
<Filter>Windows\System</Filter>
</ClCompile>
<ClCompile Include="GPU\WindowsGLContext.cpp">
<Filter>Windows\System</Filter>
</ClCompile>
@ -390,9 +387,6 @@
<ClInclude Include="MainWindow.h">
<Filter>Windows\UI</Filter>
</ClInclude>
<ClInclude Include="GPU\D3D9Context.h">
<Filter>Windows\System</Filter>
</ClInclude>
<ClInclude Include="GPU\WindowsGLContext.h">
<Filter>Windows\System</Filter>
</ClInclude>
@ -592,12 +586,6 @@
<Filter>Resource Files</Filter>
</None>
<None Include="..\README.md" />
<None Include="aboutbox.rc">
<Filter>Resource Files</Filter>
</None>
<None Include="version.rc">
<Filter>Resource Files</Filter>
</None>
<None Include="..\assets\knownfuncs.ini">
<Filter>Resource Files</Filter>
</None>
@ -856,4 +844,4 @@
<Filter>Other Platforms\SDL</Filter>
</Text>
</ItemGroup>
</Project>
</Project>

View file

@ -1019,14 +1019,11 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
if (wideArgs[i].find(gpuBackend) != std::wstring::npos && wideArgs[i].size() > gpuBackend.size()) {
const std::wstring restOfOption = wideArgs[i].substr(gpuBackend.size());
// Force software rendering off, as picking directx9 or gles implies HW acceleration.
// Force software rendering off, as picking gles implies HW acceleration.
// Once software rendering supports Direct3D9/11, we can add more options for software,
// such as "software-gles", "software-d3d9", and "software-d3d11", or something similar.
// For now, software rendering force-activates OpenGL.
if (restOfOption == L"directx9") {
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
g_Config.bSoftwareRendering = false;
} else if (restOfOption == L"directx11") {
if (restOfOption == L"directx11") {
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
g_Config.bSoftwareRendering = false;
} else if (restOfOption == L"gles") {

View file

@ -624,7 +624,6 @@ BEGIN
POPUP "Backend", ID_OPTIONS_BACKEND_MENU
BEGIN
MENUITEM "Direct3D9", ID_OPTIONS_DIRECT3D9
MENUITEM "Direct3D11", ID_OPTIONS_DIRECT3D11
MENUITEM "OpenGL", ID_OPTIONS_OPENGL
MENUITEM "Vulkan", ID_OPTIONS_VULKAN

View file

@ -272,7 +272,6 @@
#define ID_DEBUG_SAVESYMFILE 40151
#define ID_OPTIONS_BUFLINEARFILTER 40152
#define ID_OPTIONS_BUFNEARESTFILTER 40153
#define ID_OPTIONS_DIRECT3D9 40154
#define ID_OPTIONS_OPENGL 40155
#define ID_EMULATION_ROTATION_H 40156
#define ID_EMULATION_ROTATION_V 40157

View file

@ -402,8 +402,6 @@ int main(int argc, const char* argv[])
// There used to be a separate "null" rendering core - just use software.
else if (!strcasecmp(gpuName, "software") || !strcasecmp(gpuName, "null"))
gpuCore = GPUCORE_SOFTWARE;
else if (!strcasecmp(gpuName, "directx9"))
gpuCore = GPUCORE_DIRECTX9;
else if (!strcasecmp(gpuName, "directx11"))
gpuCore = GPUCORE_DIRECTX11;
else if (!strcasecmp(gpuName, "vulkan"))

View file

@ -455,7 +455,6 @@
</ClCompile>
<ClCompile Include="..\Windows\CaptureDevice.cpp" />
<ClCompile Include="..\Windows\GPU\D3D11Context.cpp" />
<ClCompile Include="..\Windows\GPU\D3D9Context.cpp" />
<ClCompile Include="..\Windows\GPU\WindowsGLContext.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</ExcludedFromBuild>
@ -530,4 +529,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -4,9 +4,6 @@
<ClCompile Include="Headless.cpp" />
<ClCompile Include="Compare.cpp" />
<ClCompile Include="..\ext\glew\glew.c" />
<ClCompile Include="..\Windows\GPU\D3D9Context.cpp">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\Windows\GPU\WindowsGLContext.cpp">
<Filter>Windows</Filter>
</ClCompile>

View file

@ -37,7 +37,6 @@
#if PPSSPP_API(ANY_GL)
#include "Windows/GPU/WindowsGLContext.h"
#endif
#include "Windows/GPU/D3D9Context.h"
#include "Windows/GPU/D3D11Context.h"
#include "Windows/GPU/WindowsVulkanContext.h"
@ -91,10 +90,6 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
needRenderThread = true;
break;
#endif
case GPUCORE_DIRECTX9:
graphicsContext = new D3D9Context();
break;
case GPUCORE_DIRECTX11:
graphicsContext = new D3D11Context();
break;
@ -102,6 +97,9 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte
case GPUCORE_VULKAN:
graphicsContext = new WindowsVulkanContext();
break;
default:
_assert_(false);
break;
}
if (graphicsContext->Init(NULL, hWnd, error_message)) {
@ -165,11 +163,4 @@ void WindowsHeadlessHost::ShutdownGraphics() {
hWnd = NULL;
}
void WindowsHeadlessHost::SwapBuffers() {
if (gpuCore_ == GPUCORE_DIRECTX9) {
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void WindowsHeadlessHost::SwapBuffers() {}

View file

@ -126,9 +126,5 @@
#endif
#if PPSSPP_PLATFORM(WINDOWS)
#if !PPSSPP_PLATFORM(UWP)
#define PPSSPP_API_D3D9 1
#endif
#define PPSSPP_API_D3D11 1
#endif

View file

@ -21,9 +21,6 @@
#include <wrl/client.h>
#include "GPU/D3D11/D3D11Util.h"
#include "GPU/D3D11/D3D11Loader.h"
#include "GPU/D3D9/D3DCompilerLoader.h"
#include "GPU/D3D9/D3D9ShaderCompiler.h"
#endif
static constexpr size_t CODE_BUFFER_SIZE = 32768;
@ -50,11 +47,6 @@ bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx);
return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString);
}
case ShaderLanguage::HLSL_D3D9:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9);
return GenerateFragmentShader(id, buffer, compat, bugs, &uniformMask, &flags, errorString);
}
case ShaderLanguage::HLSL_D3D11:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11);
@ -88,11 +80,6 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString);
}
case ShaderLanguage::HLSL_D3D9:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, &flags, errorString);
}
case ShaderLanguage::HLSL_D3D11:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11);
@ -157,18 +144,6 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stag
auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), programType, 0);
return !output.empty();
}
case ShaderLanguage::HLSL_D3D9:
{
const char *programType = nullptr;
switch (stage) {
case ShaderStage::Vertex: programType = "vs_3_0"; break;
case ShaderStage::Fragment: programType = "ps_3_0"; break;
default: return false;
}
Microsoft::WRL::ComPtr<ID3DBlob> blob;
HRESULT hr = CompileShaderToByteCodeD3D9(buffer, programType, errorMessage, &blob);
return SUCCEEDED(hr);
}
#endif
case ShaderLanguage::GLSL_VULKAN:
@ -211,7 +186,6 @@ void PrintDiff(const char *a, const char *b) {
const char *ShaderLanguageToString(ShaderLanguage lang) {
switch (lang) {
case HLSL_D3D11: return "HLSL_D3D11";
case HLSL_D3D9: return "HLSL_D3D9";
case GLSL_VULKAN: return "GLSL_VULKAN";
case GLSL_1xx: return "GLSL_1xx";
case GLSL_3xx: return "GLSL_3xx";
@ -275,7 +249,6 @@ bool TestStencilShaders() {
ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D9,
ShaderLanguage::HLSL_D3D11,
#endif
ShaderLanguage::GLSL_VULKAN,
@ -331,7 +304,6 @@ bool TestDepalShaders() {
ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D9,
ShaderLanguage::HLSL_D3D11,
#endif
ShaderLanguage::GLSL_VULKAN,
@ -380,7 +352,6 @@ bool TestDepalShaders() {
const ShaderLanguage languages[] = {
#if PPSSPP_PLATFORM(WINDOWS)
ShaderLanguage::HLSL_D3D9,
ShaderLanguage::HLSL_D3D11,
#endif
ShaderLanguage::GLSL_VULKAN,
@ -619,7 +590,6 @@ bool TestShaderGenerators() {
#if PPSSPP_PLATFORM(WINDOWS)
LoadD3D11();
init_glslang();
LoadD3DCompilerDynamic();
#else
init_glslang();
#endif