DX11 plugin: Do destination-alpha in a single pass. No more drawing the same geometry twice! SMG is faster now because it uses destination-alpha extensively. This uses dual-source color blending, a DirectX 10-level feature. The equivalent OpenGL function comes from the GL_ARB_blend_func_extended extension, which was made core in OpenGL 3.3.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6294 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
479eea6ad2
commit
cb453a0fb3
|
@ -22,7 +22,7 @@ static const char ID[4] = {'D', 'C', 'A', 'C'};
|
||||||
// Update this to the current SVN revision every time you change shader generation code.
|
// Update this to the current SVN revision every time you change shader generation code.
|
||||||
// We don't automatically get this from SVN_REV because that would mean regenerating the
|
// We don't automatically get this from SVN_REV because that would mean regenerating the
|
||||||
// shader cache for every revision, graphics-related or not, which is simply annoying.
|
// shader cache for every revision, graphics-related or not, which is simply annoying.
|
||||||
const int version = 6267;
|
const int version = 6294;
|
||||||
|
|
||||||
LinearDiskCache::LinearDiskCache()
|
LinearDiskCache::LinearDiskCache()
|
||||||
: file_(NULL), num_entries_(0) {
|
: file_(NULL), num_entries_(0) {
|
||||||
|
|
|
@ -521,7 +521,7 @@ const char *GeneratePixelShaderCode(bool dstAlphaEnable, API_TYPE ApiType,u32 co
|
||||||
if(ApiType != API_D3D11)
|
if(ApiType != API_D3D11)
|
||||||
WRITE(p, " out float4 ocol0 : COLOR0,%s\n in float4 rawpos : %s,\n",DepthTextureEnable ? "\n out float depth : DEPTH," : "", ApiType == API_OPENGL ? "WPOS" : "POSITION");
|
WRITE(p, " out float4 ocol0 : COLOR0,%s\n in float4 rawpos : %s,\n",DepthTextureEnable ? "\n out float depth : DEPTH," : "", ApiType == API_OPENGL ? "WPOS" : "POSITION");
|
||||||
else
|
else
|
||||||
WRITE(p, " out float4 ocol0 : SV_Target,%s\n in float4 rawpos : SV_Position,\n",DepthTextureEnable ? "\n out float depth : SV_Depth," : "");
|
WRITE(p, " out float4 ocol0 : SV_Target0,\n out float4 ocol1 : SV_Target1,%s\n in float4 rawpos : SV_Position,\n",DepthTextureEnable ? "\n out float depth : SV_Depth," : "");
|
||||||
|
|
||||||
WRITE(p, " in float4 colors_0 : COLOR0,\n");
|
WRITE(p, " in float4 colors_0 : COLOR0,\n");
|
||||||
WRITE(p, " in float4 colors_1 : COLOR1");
|
WRITE(p, " in float4 colors_1 : COLOR1");
|
||||||
|
@ -544,7 +544,8 @@ const char *GeneratePixelShaderCode(bool dstAlphaEnable, API_TYPE ApiType,u32 co
|
||||||
|
|
||||||
char* pmainstart = p;
|
char* pmainstart = p;
|
||||||
int Pretest = AlphaPreTest();
|
int Pretest = AlphaPreTest();
|
||||||
if (dstAlphaEnable && !DepthTextureEnable && Pretest >= 0)
|
// TODO: Re-enable the early discard on D3D11
|
||||||
|
if (dstAlphaEnable && !DepthTextureEnable && Pretest >= 0 && ApiType != API_D3D11)
|
||||||
{
|
{
|
||||||
if (!Pretest)
|
if (!Pretest)
|
||||||
{
|
{
|
||||||
|
@ -806,13 +807,24 @@ const char *GeneratePixelShaderCode(bool dstAlphaEnable, API_TYPE ApiType,u32 co
|
||||||
WRITE(p, "depth = zCoord;\n");
|
WRITE(p, "depth = zCoord;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dstAlphaEnable)
|
if (dstAlphaEnable && ApiType != API_D3D11)
|
||||||
WRITE(p, " ocol0 = float4(prev.rgb, "I_ALPHA"[0].a);\n");
|
WRITE(p, " ocol0 = float4(prev.rgb, "I_ALPHA"[0].a);\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteFog(p);
|
WriteFog(p);
|
||||||
WRITE(p, " ocol0 = prev;\n");
|
WRITE(p, " ocol0 = prev;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On D3D11, use dual-source color blending to perform dst alpha in a
|
||||||
|
// single pass
|
||||||
|
if (ApiType == API_D3D11)
|
||||||
|
{
|
||||||
|
// Colors will be blended against the alpha from ocol1...
|
||||||
|
WRITE(p, " ocol1 = ocol0;\n");
|
||||||
|
// ...and the alpha from ocol0 will be written to the framebuffer.
|
||||||
|
if (dstAlphaEnable)
|
||||||
|
WRITE(p, " ocol0.a = "I_ALPHA"[0].a;\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WRITE(p, "}\n");
|
WRITE(p, "}\n");
|
||||||
if (text[sizeof(text) - 1] != 0x7C)
|
if (text[sizeof(text) - 1] != 0x7C)
|
||||||
|
@ -1256,7 +1268,7 @@ static bool WriteAlphaTest(char *&p, API_TYPE ApiType)
|
||||||
int Pretest = AlphaPreTest();
|
int Pretest = AlphaPreTest();
|
||||||
if(Pretest >= 0)
|
if(Pretest >= 0)
|
||||||
{
|
{
|
||||||
return Pretest;
|
return Pretest != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using discard then return works the same in cg and dx9 but not in dx11
|
// using discard then return works the same in cg and dx9 but not in dx11
|
||||||
|
|
|
@ -34,6 +34,8 @@ EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(N
|
||||||
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC;
|
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_useDstAlpha = false;
|
||||||
|
|
||||||
memset(&blenddesc, 0, sizeof(blenddesc));
|
memset(&blenddesc, 0, sizeof(blenddesc));
|
||||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
blenddesc.AlphaToCoverageEnable = FALSE;
|
||||||
blenddesc.IndependentBlendEnable = FALSE;
|
blenddesc.IndependentBlendEnable = FALSE;
|
||||||
|
@ -70,7 +72,7 @@ EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(N
|
||||||
EmuGfxState::~EmuGfxState()
|
EmuGfxState::~EmuGfxState()
|
||||||
{
|
{
|
||||||
for (unsigned int k = 0;k < 8;k++)
|
for (unsigned int k = 0;k < 8;k++)
|
||||||
SAFE_RELEASE(shader_resources[k])
|
SAFE_RELEASE(shader_resources[k]);
|
||||||
|
|
||||||
SAFE_RELEASE(vsbytecode);
|
SAFE_RELEASE(vsbytecode);
|
||||||
SAFE_RELEASE(psbytecode);
|
SAFE_RELEASE(psbytecode);
|
||||||
|
@ -224,27 +226,6 @@ void EmuGfxState::ApplyState()
|
||||||
apply_called = true;
|
apply_called = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuGfxState::AlphaPass()
|
|
||||||
{
|
|
||||||
if (!apply_called) ERROR_LOG(VIDEO, "EmuGfxState::AlphaPass called without having called ApplyState before!")
|
|
||||||
else stateman->PopBlendState();
|
|
||||||
|
|
||||||
// pixel shader for alpha pass is different, so update it
|
|
||||||
context->PSSetShader(pixelshader, NULL, 0);
|
|
||||||
|
|
||||||
ID3D11BlendState* blstate;
|
|
||||||
D3D11_BLEND_DESC desc = blenddesc;
|
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
|
||||||
desc.RenderTarget[0].BlendEnable = FALSE;
|
|
||||||
HRESULT hr = device->CreateBlendState(&desc, &blstate);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState (created during alpha pass)");
|
|
||||||
stateman->PushBlendState(blstate);
|
|
||||||
blstate->Release();
|
|
||||||
|
|
||||||
stateman->Apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::Reset()
|
void EmuGfxState::Reset()
|
||||||
{
|
{
|
||||||
for (unsigned int k = 0;k < 8;k++)
|
for (unsigned int k = 0;k < 8;k++)
|
||||||
|
@ -274,29 +255,58 @@ void EmuGfxState::SetSrcBlend(D3D11_BLEND val)
|
||||||
{
|
{
|
||||||
// TODO: Check whether e.g. the dest color check is needed here
|
// TODO: Check whether e.g. the dest color check is needed here
|
||||||
blenddesc.RenderTarget[0].SrcBlend = val;
|
blenddesc.RenderTarget[0].SrcBlend = val;
|
||||||
|
if (m_useDstAlpha)
|
||||||
|
{
|
||||||
|
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
||||||
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
||||||
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
||||||
else blenddesc.RenderTarget[0].SrcBlendAlpha = val;
|
else blenddesc.RenderTarget[0].SrcBlendAlpha = val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuGfxState::SetDestBlend(D3D11_BLEND val)
|
void EmuGfxState::SetDestBlend(D3D11_BLEND val)
|
||||||
{
|
{
|
||||||
// TODO: Check whether e.g. the source color check is needed here
|
// TODO: Check whether e.g. the source color check is needed here
|
||||||
blenddesc.RenderTarget[0].DestBlend = val;
|
blenddesc.RenderTarget[0].DestBlend = val;
|
||||||
|
if (m_useDstAlpha)
|
||||||
|
{
|
||||||
|
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
||||||
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
||||||
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
||||||
else blenddesc.RenderTarget[0].DestBlendAlpha = val;
|
else blenddesc.RenderTarget[0].DestBlendAlpha = val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val)
|
void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val)
|
||||||
{
|
{
|
||||||
blenddesc.RenderTarget[0].BlendOp = val;
|
blenddesc.RenderTarget[0].BlendOp = val;
|
||||||
|
if (m_useDstAlpha)
|
||||||
|
{
|
||||||
|
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = val;
|
blenddesc.RenderTarget[0].BlendOpAlpha = val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuGfxState::SetDstAlpha(bool enable)
|
||||||
|
{
|
||||||
|
m_useDstAlpha = enable;
|
||||||
|
SetSrcBlend(blenddesc.RenderTarget[0].SrcBlend);
|
||||||
|
SetDestBlend(blenddesc.RenderTarget[0].DestBlend);
|
||||||
|
SetBlendOp(blenddesc.RenderTarget[0].BlendOp);
|
||||||
|
}
|
||||||
|
|
||||||
void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter)
|
void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,6 @@ public:
|
||||||
void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv);
|
void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv);
|
||||||
|
|
||||||
void ApplyState(); // apply current state
|
void ApplyState(); // apply current state
|
||||||
void AlphaPass(); // only modify the current state to enable the alpha pass
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
// blend state
|
// blend state
|
||||||
|
@ -49,6 +48,8 @@ public:
|
||||||
void SetDestBlend(D3D11_BLEND val);
|
void SetDestBlend(D3D11_BLEND val);
|
||||||
void SetBlendOp(D3D11_BLEND_OP val);
|
void SetBlendOp(D3D11_BLEND_OP val);
|
||||||
|
|
||||||
|
void SetDstAlpha(bool enable);
|
||||||
|
|
||||||
// sampler states
|
// sampler states
|
||||||
void SetSamplerFilter(DWORD stage, D3D11_FILTER filter);
|
void SetSamplerFilter(DWORD stage, D3D11_FILTER filter);
|
||||||
|
|
||||||
|
@ -80,6 +81,8 @@ private:
|
||||||
ID3D11ShaderResourceView* shader_resources[8];
|
ID3D11ShaderResourceView* shader_resources[8];
|
||||||
D3D11_BLEND_DESC blenddesc;
|
D3D11_BLEND_DESC blenddesc;
|
||||||
|
|
||||||
|
bool m_useDstAlpha;
|
||||||
|
|
||||||
bool apply_called;
|
bool apply_called;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,8 @@ static const D3D11_BLEND d3dSrcFactors[8] =
|
||||||
D3D11_BLEND_ONE,
|
D3D11_BLEND_ONE,
|
||||||
D3D11_BLEND_DEST_COLOR,
|
D3D11_BLEND_DEST_COLOR,
|
||||||
D3D11_BLEND_INV_DEST_COLOR,
|
D3D11_BLEND_INV_DEST_COLOR,
|
||||||
D3D11_BLEND_SRC_ALPHA,
|
D3D11_BLEND_SRC1_ALPHA,
|
||||||
D3D11_BLEND_INV_SRC_ALPHA,
|
D3D11_BLEND_INV_SRC1_ALPHA, // Use dual-source color blending for dst alpha
|
||||||
D3D11_BLEND_DEST_ALPHA,
|
D3D11_BLEND_DEST_ALPHA,
|
||||||
D3D11_BLEND_INV_DEST_ALPHA
|
D3D11_BLEND_INV_DEST_ALPHA
|
||||||
};
|
};
|
||||||
|
@ -102,8 +102,8 @@ static const D3D11_BLEND d3dDestFactors[8] =
|
||||||
D3D11_BLEND_ONE,
|
D3D11_BLEND_ONE,
|
||||||
D3D11_BLEND_SRC_COLOR,
|
D3D11_BLEND_SRC_COLOR,
|
||||||
D3D11_BLEND_INV_SRC_COLOR,
|
D3D11_BLEND_INV_SRC_COLOR,
|
||||||
D3D11_BLEND_SRC_ALPHA,
|
D3D11_BLEND_SRC1_ALPHA,
|
||||||
D3D11_BLEND_INV_SRC_ALPHA,
|
D3D11_BLEND_INV_SRC1_ALPHA, // Use dual-source color blending for dst alpha
|
||||||
D3D11_BLEND_DEST_ALPHA,
|
D3D11_BLEND_DEST_ALPHA,
|
||||||
D3D11_BLEND_INV_DEST_ALPHA
|
D3D11_BLEND_INV_DEST_ALPHA
|
||||||
};
|
};
|
||||||
|
|
|
@ -144,12 +144,9 @@ void VertexManager::LoadBuffers()
|
||||||
m_indexBufferCursor += iCount;
|
m_indexBufferCursor += iCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexManager::Draw(UINT stride, bool alphapass)
|
void VertexManager::Draw(UINT stride)
|
||||||
{
|
{
|
||||||
if (!alphapass)
|
|
||||||
D3D::gfxstate->ApplyState();
|
D3D::gfxstate->ApplyState();
|
||||||
else
|
|
||||||
D3D::gfxstate->AlphaPass();
|
|
||||||
|
|
||||||
D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &m_vertexDrawOffset);
|
D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &m_vertexDrawOffset);
|
||||||
D3D::context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0);
|
D3D::context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0);
|
||||||
|
@ -221,7 +218,12 @@ void VertexManager::vFlush()
|
||||||
VertexShaderManager::SetConstants();
|
VertexShaderManager::SetConstants();
|
||||||
PixelShaderManager::SetConstants();
|
PixelShaderManager::SetConstants();
|
||||||
|
|
||||||
if (!PixelShaderCache::SetShader(false,g_nativeVertexFmt->m_components))
|
bool useDstAlpha = bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
|
||||||
|
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||||
|
|
||||||
|
D3D::gfxstate->SetDstAlpha(useDstAlpha);
|
||||||
|
|
||||||
|
if (!PixelShaderCache::SetShader(useDstAlpha,g_nativeVertexFmt->m_components))
|
||||||
goto shader_fail;
|
goto shader_fail;
|
||||||
if (!VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
|
if (!VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
|
||||||
goto shader_fail;
|
goto shader_fail;
|
||||||
|
@ -230,18 +232,8 @@ void VertexManager::vFlush()
|
||||||
g_nativeVertexFmt->SetupVertexPointers();
|
g_nativeVertexFmt->SetupVertexPointers();
|
||||||
|
|
||||||
LoadBuffers();
|
LoadBuffers();
|
||||||
|
Draw(stride);
|
||||||
|
|
||||||
Draw(stride, false);
|
|
||||||
|
|
||||||
if (bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate)
|
|
||||||
{
|
|
||||||
DWORD write = 0;
|
|
||||||
if (!PixelShaderCache::SetShader(true,g_nativeVertexFmt->m_components))
|
|
||||||
goto shader_fail;
|
|
||||||
|
|
||||||
// update alpha only
|
|
||||||
Draw(stride, true);
|
|
||||||
}
|
|
||||||
D3D::gfxstate->Reset();
|
D3D::gfxstate->Reset();
|
||||||
|
|
||||||
shader_fail:
|
shader_fail:
|
||||||
|
|
|
@ -37,7 +37,7 @@ private:
|
||||||
void CreateDeviceObjects();
|
void CreateDeviceObjects();
|
||||||
void DestroyDeviceObjects();
|
void DestroyDeviceObjects();
|
||||||
void LoadBuffers();
|
void LoadBuffers();
|
||||||
void Draw(UINT stride, bool alphapass);
|
void Draw(UINT stride);
|
||||||
// temp
|
// temp
|
||||||
void vFlush();
|
void vFlush();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue