DX11: Support thick lines and large points with geometry shaders. Lines still aren't drawn with correct thickness, see Twilight Princess map. But the map corners are drawn with correct shadow "blobs" for the first time!

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7340 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Nolan Check 2011-03-14 09:38:29 +00:00
parent 8fedc3db38
commit 7c536b8f15
19 changed files with 1982 additions and 720 deletions

View File

@ -73,6 +73,37 @@ static char text[16384];
#define WRITE p+=sprintf #define WRITE p+=sprintf
char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type)
{
WRITE(p, "struct VS_OUTPUT {\n");
WRITE(p, " float4 pos : POSITION;\n");
WRITE(p, " float4 colors_0 : COLOR0;\n");
WRITE(p, " float4 colors_1 : COLOR1;\n");
if (xfregs.numTexGen.numTexGens < 7) {
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i);
WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens);
if(g_ActiveConfig.bEnablePixelLigting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1);
} else {
// clip position is in w of first 4 texcoords
if(g_ActiveConfig.bEnablePixelLigting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
{
for (int i = 0; i < 8; ++i)
WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i);
}
else
{
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i);
}
}
WRITE(p, "};\n");
return p;
}
const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type)
{ {
setlocale(LC_NUMERIC, "C"); // Reset locale for compilation setlocale(LC_NUMERIC, "C"); // Reset locale for compilation
@ -102,31 +133,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type)
"typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n"
); );
WRITE(p, "struct VS_OUTPUT {\n"); p = GenerateVSOutputStruct(p, components, api_type);
WRITE(p, " float4 pos : POSITION;\n");
WRITE(p, " float4 colors_0 : COLOR0;\n");
WRITE(p, " float4 colors_1 : COLOR1;\n");
if (xfregs.numTexGen.numTexGens < 7) {
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
WRITE(p, " float3 tex%d : TEXCOORD%d;\n", i, i);
WRITE(p, " float4 clipPos : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens);
if(g_ActiveConfig.bEnablePixelLigting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
WRITE(p, " float4 Normal : TEXCOORD%d;\n", xfregs.numTexGen.numTexGens + 1);
} else {
// clip position is in w of first 4 texcoords
if(g_ActiveConfig.bEnablePixelLigting && g_ActiveConfig.backend_info.bSupportsPixelLighting)
{
for (int i = 0; i < 8; ++i)
WRITE(p, " float4 tex%d : TEXCOORD%d;\n", i, i);
}
else
{
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
WRITE(p, " float%d tex%d : TEXCOORD%d;\n", i < 4 ? 4 : 3 , i, i);
}
}
WRITE(p, "};\n");
// uniforms // uniforms

View File

@ -103,6 +103,7 @@ public:
// components is included in the uid. // components is included in the uid.
char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE api_type);
const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type); const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type);
void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components); void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components);

View File

@ -197,9 +197,11 @@
<ClCompile Include="Src\D3DUtil.cpp" /> <ClCompile Include="Src\D3DUtil.cpp" />
<ClCompile Include="Src\FramebufferManager.cpp" /> <ClCompile Include="Src\FramebufferManager.cpp" />
<ClCompile Include="Src\GfxState.cpp" /> <ClCompile Include="Src\GfxState.cpp" />
<ClCompile Include="Src\LineGeometryShader.cpp" />
<ClCompile Include="Src\main.cpp" /> <ClCompile Include="Src\main.cpp" />
<ClCompile Include="Src\NativeVertexFormat.cpp" /> <ClCompile Include="Src\NativeVertexFormat.cpp" />
<ClCompile Include="Src\PixelShaderCache.cpp" /> <ClCompile Include="Src\PixelShaderCache.cpp" />
<ClCompile Include="Src\PointGeometryShader.cpp" />
<ClCompile Include="Src\PSTextureEncoder.cpp" /> <ClCompile Include="Src\PSTextureEncoder.cpp" />
<ClCompile Include="Src\Render.cpp" /> <ClCompile Include="Src\Render.cpp" />
<ClCompile Include="Src\stdafx.cpp"> <ClCompile Include="Src\stdafx.cpp">
@ -225,8 +227,10 @@
<ClInclude Include="Src\FramebufferManager.h" /> <ClInclude Include="Src\FramebufferManager.h" />
<ClInclude Include="Src\GfxState.h" /> <ClInclude Include="Src\GfxState.h" />
<ClInclude Include="Src\Globals.h" /> <ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\LineGeometryShader.h" />
<ClInclude Include="Src\main.h" /> <ClInclude Include="Src\main.h" />
<ClInclude Include="Src\PixelShaderCache.h" /> <ClInclude Include="Src\PixelShaderCache.h" />
<ClInclude Include="Src\PointGeometryShader.h" />
<ClInclude Include="Src\PSTextureEncoder.h" /> <ClInclude Include="Src\PSTextureEncoder.h" />
<ClInclude Include="Src\Render.h" /> <ClInclude Include="Src\Render.h" />
<ClInclude Include="Src\stdafx.h" /> <ClInclude Include="Src\stdafx.h" />

View File

@ -51,6 +51,12 @@
<ClCompile Include="Src\Television.cpp"> <ClCompile Include="Src\Television.cpp">
<Filter>Render</Filter> <Filter>Render</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Src\LineGeometryShader.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PointGeometryShader.cpp">
<Filter>Render</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Src\Globals.h" /> <ClInclude Include="Src\Globals.h" />
@ -105,6 +111,12 @@
<ClInclude Include="Src\Television.h"> <ClInclude Include="Src\Television.h">
<Filter>Render</Filter> <Filter>Render</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Src\LineGeometryShader.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PointGeometryShader.h">
<Filter>Render</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="D3D"> <Filter Include="D3D">

View File

@ -415,7 +415,6 @@ void Close()
UnloadDXGI(); UnloadDXGI();
} }
/* just returning the 4_0 ones here */
const char* VertexShaderVersionString() const char* VertexShaderVersionString()
{ {
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0"; if(featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0";
@ -423,6 +422,13 @@ const char* VertexShaderVersionString()
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0"; else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0";
} }
const char* GeometryShaderVersionString()
{
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "gs_5_0";
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "gs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "gs_4_0";
}
const char* PixelShaderVersionString() const char* PixelShaderVersionString()
{ {
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0"; if(featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0";

View File

@ -64,6 +64,7 @@ unsigned int GetBackBufferWidth();
unsigned int GetBackBufferHeight(); unsigned int GetBackBufferHeight();
D3DTexture2D* &GetBackBuffer(); D3DTexture2D* &GetBackBuffer();
const char* PixelShaderVersionString(); const char* PixelShaderVersionString();
const char* GeometryShaderVersionString();
const char* VertexShaderVersionString(); const char* VertexShaderVersionString();
bool BGRATexturesSupported(); bool BGRATexturesSupported();

View File

@ -82,6 +82,61 @@ bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
// bytecode->shader
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len)
{
ID3D11GeometryShader* g_shader;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, NULL, &g_shader);
if (FAILED(hr))
{
PanicAlert("CreateGeometryShaderFromByteCode failed from %p (size %d) at %s %d\n", bytecode, len, __FILE__, __LINE__);
g_shader = NULL;
}
return g_shader;
}
// code->bytecode
bool CompileGeometryShader(const char* code, unsigned int len, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = NULL;
ID3D10Blob* errorBuffer = NULL;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
#else
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
#endif
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, pDefines, NULL, "main", D3D::GeometryShaderVersionString(),
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
if (g_ActiveConfig.bShowShaderErrors)
{
std::string msg = (char*)errorBuffer->GetBufferPointer();
msg += "\n\n";
msg += code;
MessageBoxA(0, msg.c_str(), "Error compiling geometry shader", MB_ICONERROR);
}
*blob = NULL;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader // bytecode->shader
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len) ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len)
{ {
@ -138,7 +193,8 @@ bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob,
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len) ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
unsigned int len)
{ {
D3DBlob* blob = NULL; D3DBlob* blob = NULL;
if (CompileVertexShader(code, len, &blob)) if (CompileVertexShader(code, len, &blob))
@ -151,7 +207,22 @@ ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int
return NULL; return NULL;
} }
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len) ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
unsigned int len, const D3D_SHADER_MACRO* pDefines)
{
D3DBlob* blob = NULL;
if (CompileGeometryShader(code, len, &blob, pDefines))
{
ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob);
blob->Release();
return g_shader;
}
PanicAlert("Failed to compile and create geometry shader from %p (size %d) at %s %d\n", code, len, __FILE__, __LINE__);
return NULL;
}
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
unsigned int len)
{ {
D3DBlob* blob = NULL; D3DBlob* blob = NULL;
CompilePixelShader(code, len, &blob); CompilePixelShader(code, len, &blob);

View File

@ -29,20 +29,38 @@ namespace DX11
namespace D3D namespace D3D
{ {
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len); ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len); ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
// The returned bytecode buffers should be Release()d. // The returned bytecode buffers should be Release()d.
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob); bool CompileVertexShader(const char* code, unsigned int len,
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL); D3DBlob** blob);
bool CompileGeometryShader(const char* code, unsigned int len,
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
bool CompilePixelShader(const char* code, unsigned int len,
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
// Utility functions // Utility functions
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len); ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len); unsigned int len);
ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
unsigned int len, const D3D_SHADER_MACRO* pDefines = NULL);
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
unsigned int len);
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); } inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); } { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) { return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); } inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); } { return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
{ return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
{ return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); }
inline ID3D11GeometryShader* CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = NULL)
{ return CompileAndCreateGeometryShader((const char*)code->Data(), code->Size(), pDefines); }
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
{ return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
} }
} // namespace DX11 } // namespace DX11

View File

@ -0,0 +1,452 @@
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "LineGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
union LineGSParams
{
struct
{
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
};
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[16]; // Pad to the next multiple of 16 bytes
};
static const char LINE_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu line geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match LineGSParams above
"{\n"
"float LineWidth;\n"
"float TexOffset;\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
// Pretend input[0] is on the bottom and input[1] is on top.
// We generate vertices to the left and right.
// Correct w coordinate so screen-space math will work
"VS_OUTPUT l0 = input[0];\n"
"l0.pos /= l0.pos.w;\n"
"VS_OUTPUT r0 = l0;\n"
"VS_OUTPUT l1 = input[1];\n"
"l1.pos /= l1.pos.w;\n"
"VS_OUTPUT r1 = l1;\n"
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
// use the correct line caps. Instead, the line caps are vertical or
// horizontal depending the slope of the line.
"float2 offset;\n"
"float2 to = input[1].pos.xy - input[0].pos.xy;\n"
// FIXME: What does real hardware do when line is at a 45-degree angle?
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
"if (abs(to.y) > abs(to.x)) {\n"
// Line is more tall. Extend geometry left and right.
// Lerp Params.LineWidth/2 from [0..640] to [-1..1]
"offset = float2(Params.LineWidth/640, 0);\n"
"} else {\n"
// Line is more wide. Extend geometry up and down.
// Lerp Params.LineWidth/2 from [0..528] to [1..-1]
"offset = float2(0, -Params.LineWidth/528);\n"
"}\n"
"l0.pos.xy -= offset;\n"
"r0.pos.xy += offset;\n"
"l1.pos.xy -= offset;\n"
"r1.pos.xy += offset;\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex
"#if NUM_TEXCOORDS >= 1\n"
"r0.tex0.x += Params.TexOffset;\n"
"r1.tex0.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"r0.tex1.x += Params.TexOffset;\n"
"r1.tex1.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"r0.tex2.x += Params.TexOffset;\n"
"r1.tex2.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"r0.tex3.x += Params.TexOffset;\n"
"r1.tex3.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"r0.tex4.x += Params.TexOffset;\n"
"r1.tex4.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"r0.tex5.x += Params.TexOffset;\n"
"r1.tex5.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"r0.tex6.x += Params.TexOffset;\n"
"r1.tex6.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"r0.tex7.x += Params.TexOffset;\n"
"r1.tex7.x += Params.TexOffset;\n"
"#endif\n"
"outStream.Append(l0);\n"
"outStream.Append(r0);\n"
"outStream.Append(l1);\n"
"outStream.Append(r1);\n"
"}\n"
;
LineGeometryShader::LineGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void LineGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
m_ready = true;
}
void LineGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool LineGeometryShader::SetShader(u32 components, float lineWidth, float texOffset)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char code[16384];
char* p = code;
p = GenerateVSOutputStruct(p, components, API_D3D11);
p += sprintf(p, "\n%s", LINE_GS_COMMON);
std::stringstream numTexCoordsStr;
numTexCoordsStr << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
LineGSParams params = { 0 };
params.LineWidth = lineWidth;
params.TexOffset = texOffset;
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, &params, 0, 0);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "LineGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
union LineGSParams
{
struct
{
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
};
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[16]; // Pad to the next multiple of 16 bytes
};
static const char LINE_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu line geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match LineGSParams above
"{\n"
"float LineWidth;\n"
"float TexOffset;\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
// Pretend input[0] is on the bottom and input[1] is on top.
// We generate vertices to the left and right.
// Correct w coordinate so screen-space math will work
"VS_OUTPUT l0 = input[0];\n"
"l0.pos /= l0.pos.w;\n"
"VS_OUTPUT r0 = l0;\n"
"VS_OUTPUT l1 = input[1];\n"
"l1.pos /= l1.pos.w;\n"
"VS_OUTPUT r1 = l1;\n"
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
// use the correct line caps. Instead, the line caps are vertical or
// horizontal depending the slope of the line.
"float2 offset;\n"
"float2 to = input[1].pos.xy - input[0].pos.xy;\n"
// FIXME: What does real hardware do when line is at a 45-degree angle?
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
"if (abs(to.y) > abs(to.x)) {\n"
// Line is more tall. Extend geometry left and right.
// Lerp Params.LineWidth/2 from [0..640] to [-1..1]
"offset = float2(Params.LineWidth/640, 0);\n"
"} else {\n"
// Line is more wide. Extend geometry up and down.
// Lerp Params.LineWidth/2 from [0..528] to [1..-1]
"offset = float2(0, -Params.LineWidth/528);\n"
"}\n"
"l0.pos.xy -= offset;\n"
"r0.pos.xy += offset;\n"
"l1.pos.xy -= offset;\n"
"r1.pos.xy += offset;\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex
"#if NUM_TEXCOORDS >= 1\n"
"r0.tex0.x += Params.TexOffset;\n"
"r1.tex0.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"r0.tex1.x += Params.TexOffset;\n"
"r1.tex1.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"r0.tex2.x += Params.TexOffset;\n"
"r1.tex2.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"r0.tex3.x += Params.TexOffset;\n"
"r1.tex3.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"r0.tex4.x += Params.TexOffset;\n"
"r1.tex4.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"r0.tex5.x += Params.TexOffset;\n"
"r1.tex5.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"r0.tex6.x += Params.TexOffset;\n"
"r1.tex6.x += Params.TexOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"r0.tex7.x += Params.TexOffset;\n"
"r1.tex7.x += Params.TexOffset;\n"
"#endif\n"
"outStream.Append(l0);\n"
"outStream.Append(r0);\n"
"outStream.Append(l1);\n"
"outStream.Append(r1);\n"
"}\n"
;
LineGeometryShader::LineGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void LineGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
m_ready = true;
}
void LineGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool LineGeometryShader::SetShader(u32 components, float lineWidth, float texOffset)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char code[16384];
char* p = code;
p = GenerateVSOutputStruct(p, components, API_D3D11);
p += sprintf(p, "\n%s", LINE_GS_COMMON);
std::stringstream numTexCoordsStr;
numTexCoordsStr << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
LineGSParams params = { 0 };
params.LineWidth = lineWidth;
params.TexOffset = texOffset;
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, &params, 0, 0);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}

View File

@ -0,0 +1,114 @@
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _LINEGEOMETRYSHADER_H
#define _LINEGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of line geometry shaders, one for each
// vertex format.
class LineGeometryShader
{
public:
LineGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float lineWidth, float texOffset);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _LINEGEOMETRYSHADER_H
#define _LINEGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of line geometry shaders, one for each
// vertex format.
class LineGeometryShader
{
public:
LineGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float lineWidth, float texOffset);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif

View File

@ -1265,10 +1265,8 @@ bool PSTextureEncoder::SetStaticShader(unsigned int dstFormat, unsigned int srcF
HRESULT hr = D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), NULL, &newShader); HRESULT hr = D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), NULL, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
m_staticShaders[key] = newShader; it = m_staticShaders.insert(std::make_pair(key, newShader)).first;
bytecode->Release(); bytecode->Release();
it = m_staticShaders.find(key);
} }
if (it != m_staticShaders.end()) if (it != m_staticShaders.end())

View File

@ -0,0 +1,434 @@
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "PointGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
union PointGSParams
{
struct
{
FLOAT PointSize; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
};
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[16]; // Pad to the next multiple of 16 bytes
};
static const char POINT_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu point geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match PointGSParams above
"{\n"
"float PointSize;\n"
"float TexOffset;\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
// Correct w coordinate so screen-space math will work
"VS_OUTPUT ptLL = input[0];\n"
"ptLL.pos /= ptLL.pos.w;\n"
"VS_OUTPUT ptLR = ptLL;\n"
"VS_OUTPUT ptUL = ptLL;\n"
"VS_OUTPUT ptUR = ptLL;\n"
// Distance from center to upper right vertex
"float2 offset = float2(Params.PointSize/640, -Params.PointSize/528);\n"
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
"ptLR.pos.xy += float2(1,-1) * offset;\n"
"ptUL.pos.xy += float2(-1,1) * offset;\n"
"ptUR.pos.xy += offset;\n"
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex
"#if NUM_TEXCOORDS >= 1\n"
"ptLL.tex0.xy += float2(0,1) * texOffset;\n"
"ptLR.tex0.xy += texOffset;\n"
"ptUR.tex0.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"ptLL.tex1.xy += float2(0,1) * texOffset;\n"
"ptLR.tex1.xy += texOffset;\n"
"ptUR.tex1.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"ptLL.tex2.xy += float2(0,1) * texOffset;\n"
"ptLR.tex2.xy += texOffset;\n"
"ptUR.tex2.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"ptLL.tex3.xy += float2(0,1) * texOffset;\n"
"ptLR.tex3.xy += texOffset;\n"
"ptUR.tex3.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"ptLL.tex4.xy += float2(0,1) * texOffset;\n"
"ptLR.tex4.xy += texOffset;\n"
"ptUR.tex4.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"ptLL.tex5.xy += float2(0,1) * texOffset;\n"
"ptLR.tex5.xy += texOffset;\n"
"ptUR.tex5.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"ptLL.tex6.xy += float2(0,1) * texOffset;\n"
"ptLR.tex6.xy += texOffset;\n"
"ptUR.tex6.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"ptLL.tex7.xy += float2(0,1) * texOffset;\n"
"ptLR.tex7.xy += texOffset;\n"
"ptUR.tex7.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"outStream.Append(ptLL);\n"
"outStream.Append(ptLR);\n"
"outStream.Append(ptUL);\n"
"outStream.Append(ptUR);\n"
"}\n"
;
PointGeometryShader::PointGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void PointGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
m_ready = true;
}
void PointGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool PointGeometryShader::SetShader(u32 components, float pointSize, float texOffset)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char code[16384];
char* p = code;
p = GenerateVSOutputStruct(p, components, API_D3D11);
p += sprintf(p, "\n%s", POINT_GS_COMMON);
std::stringstream numTexCoordsStr;
numTexCoordsStr << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
PointGSParams params = { 0 };
params.PointSize = pointSize;
params.TexOffset = texOffset;
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, &params, 0, 0);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "PointGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
union PointGSParams
{
struct
{
FLOAT PointSize; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
};
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[16]; // Pad to the next multiple of 16 bytes
};
static const char POINT_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu point geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match PointGSParams above
"{\n"
"float PointSize;\n"
"float TexOffset;\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
// Correct w coordinate so screen-space math will work
"VS_OUTPUT ptLL = input[0];\n"
"ptLL.pos /= ptLL.pos.w;\n"
"VS_OUTPUT ptLR = ptLL;\n"
"VS_OUTPUT ptUL = ptLL;\n"
"VS_OUTPUT ptUR = ptLL;\n"
// Distance from center to upper right vertex
"float2 offset = float2(Params.PointSize/640, -Params.PointSize/528);\n"
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
"ptLR.pos.xy += float2(1,-1) * offset;\n"
"ptUL.pos.xy += float2(-1,1) * offset;\n"
"ptUR.pos.xy += offset;\n"
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex
"#if NUM_TEXCOORDS >= 1\n"
"ptLL.tex0.xy += float2(0,1) * texOffset;\n"
"ptLR.tex0.xy += texOffset;\n"
"ptUR.tex0.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"ptLL.tex1.xy += float2(0,1) * texOffset;\n"
"ptLR.tex1.xy += texOffset;\n"
"ptUR.tex1.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"ptLL.tex2.xy += float2(0,1) * texOffset;\n"
"ptLR.tex2.xy += texOffset;\n"
"ptUR.tex2.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"ptLL.tex3.xy += float2(0,1) * texOffset;\n"
"ptLR.tex3.xy += texOffset;\n"
"ptUR.tex3.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"ptLL.tex4.xy += float2(0,1) * texOffset;\n"
"ptLR.tex4.xy += texOffset;\n"
"ptUR.tex4.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"ptLL.tex5.xy += float2(0,1) * texOffset;\n"
"ptLR.tex5.xy += texOffset;\n"
"ptUR.tex5.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"ptLL.tex6.xy += float2(0,1) * texOffset;\n"
"ptLR.tex6.xy += texOffset;\n"
"ptUR.tex6.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"ptLL.tex7.xy += float2(0,1) * texOffset;\n"
"ptLR.tex7.xy += texOffset;\n"
"ptUR.tex7.xy += float2(1,0) * texOffset;\n"
"#endif\n"
"outStream.Append(ptLL);\n"
"outStream.Append(ptLR);\n"
"outStream.Append(ptUL);\n"
"outStream.Append(ptUR);\n"
"}\n"
;
PointGeometryShader::PointGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void PointGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
m_ready = true;
}
void PointGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool PointGeometryShader::SetShader(u32 components, float pointSize, float texOffset)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char code[16384];
char* p = code;
p = GenerateVSOutputStruct(p, components, API_D3D11);
p += sprintf(p, "\n%s", POINT_GS_COMMON);
std::stringstream numTexCoordsStr;
numTexCoordsStr << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
PointGSParams params = { 0 };
params.PointSize = pointSize;
params.TexOffset = texOffset;
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, &params, 0, 0);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}

View File

@ -0,0 +1,114 @@
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _POINTGEOMETRYSHADER_H
#define _POINTGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of point geometry shaders, one for each
// vertex format.
class PointGeometryShader
{
public:
PointGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float pointSize, float texOffset);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif
// Copyright (C) 2003 Dolphin 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.
// 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 SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _POINTGEOMETRYSHADER_H
#define _POINTGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of point geometry shaders, one for each
// vertex format.
class PointGeometryShader
{
public:
PointGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float pointSize, float texOffset);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif

View File

@ -1,154 +1,154 @@
// Copyright (C) 2003 Dolphin Project. // Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0. // the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include "Television.h" #include "Television.h"
#include "VideoConfig.h" #include "VideoConfig.h"
#include "D3DBase.h" #include "D3DBase.h"
#include "D3DShader.h" #include "D3DShader.h"
#include "D3DUtil.h" #include "D3DUtil.h"
#include "VertexShaderCache.h" #include "VertexShaderCache.h"
#include "HW/Memmap.h" #include "HW/Memmap.h"
namespace DX11 namespace DX11
{ {
static const char YUYV_DECODER_PS[] = static const char YUYV_DECODER_PS[] =
"// dolphin-emu YUYV decoder pixel shader\n" "// dolphin-emu YUYV decoder pixel shader\n"
"Texture2D Tex0 : register(t0);\n" "Texture2D Tex0 : register(t0);\n"
"sampler Samp0 : register(s0);\n" "sampler Samp0 : register(s0);\n"
"static const float3x3 YCBCR_TO_RGB = float3x3(\n" "static const float3x3 YCBCR_TO_RGB = float3x3(\n"
"1.164, 0.000, 1.596,\n" "1.164, 0.000, 1.596,\n"
"1.164, -0.392, -0.813,\n" "1.164, -0.392, -0.813,\n"
"1.164, 2.017, 0.000\n" "1.164, 2.017, 0.000\n"
");\n" ");\n"
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n" "void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
"{\n" "{\n"
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n" "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color // GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
// primaries, compressed to the range Y in 16..235, U and V in 16..240. // primaries, compressed to the range Y in 16..235, U and V in 16..240.
// We want to convert it to RGB format with sRGB color primaries, with // We want to convert it to RGB format with sRGB color primaries, with
// range 0..255. // range 0..255.
// Recover RGB components // Recover RGB components
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n" "float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n" "float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
// If we were really obsessed with accuracy, we would correct for the // If we were really obsessed with accuracy, we would correct for the
// differing color primaries between BT.601 and sRGB. However, this may not // differing color primaries between BT.601 and sRGB. However, this may not
// be worth the trouble because: // be worth the trouble because:
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL. // - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
// - sRGB's color primaries are actually an intermediate between BT.601's // - sRGB's color primaries are actually an intermediate between BT.601's
// NTSC and PAL primaries. // NTSC and PAL primaries.
// - If users even noticed any difference at all, they would be confused by // - If users even noticed any difference at all, they would be confused by
// the slightly-different colors in the NTSC and PAL versions of the same // the slightly-different colors in the NTSC and PAL versions of the same
// game. // game.
// - Even the game designers probably don't pay close attention to this // - Even the game designers probably don't pay close attention to this
// stuff. // stuff.
// Still, instructions on how to do it can be found at // Still, instructions on how to do it can be found at
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20> // <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
"ocol0 = float4(rgb_601, 1);\n" "ocol0 = float4(rgb_601, 1);\n"
"}\n" "}\n"
; ;
Television::Television() Television::Television()
: m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL) : m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL)
{ } { }
void Television::Init() void Television::Init()
{ {
HRESULT hr; HRESULT hr;
// Create YUYV texture for real XFB mode // Create YUYV texture for real XFB mode
// This texture format is designed for YUYV data. // This texture format is designed for YUYV data.
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC( D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1); DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_yuyvTexture); hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_yuyvTexture);
CHECK(SUCCEEDED(hr), "create tv yuyv texture"); CHECK(SUCCEEDED(hr), "create tv yuyv texture");
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture"); D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
// Create shader resource view for YUYV texture // Create shader resource view for YUYV texture
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC( D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
DXGI_FORMAT_G8R8_G8B8_UNORM); DXGI_FORMAT_G8R8_G8B8_UNORM);
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV); hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv"); CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv"); D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
// Create YUYV-decoding pixel shader // Create YUYV-decoding pixel shader
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS)); m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS));
CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader"); CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader");
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader"); D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
} }
void Television::Shutdown() void Television::Shutdown()
{ {
SAFE_RELEASE(m_pShader); SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_yuyvTextureSRV); SAFE_RELEASE(m_yuyvTextureSRV);
SAFE_RELEASE(m_yuyvTexture); SAFE_RELEASE(m_yuyvTexture);
} }
void Television::Submit(u32 xfbAddr, u32 width, u32 height) void Television::Submit(u32 xfbAddr, u32 width, u32 height)
{ {
m_curAddr = xfbAddr; m_curAddr = xfbAddr;
m_curWidth = width; m_curWidth = width;
m_curHeight = height; m_curHeight = height;
// Load data from GameCube RAM to YUYV texture // Load data from GameCube RAM to YUYV texture
u8* yuyvSrc = Memory::GetPointer(xfbAddr); u8* yuyvSrc = Memory::GetPointer(xfbAddr);
D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1); D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1);
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height); D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height);
} }
void Television::Render() void Television::Render()
{ {
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB) if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
{ {
// Use real XFB mode // Use real XFB mode
// TODO: If this is the lower field, render at a vertical offset of 1 // TODO: If this is the lower field, render at a vertical offset of 1
// line down. We could even consider implementing a deinterlacing // line down. We could even consider implementing a deinterlacing
// algorithm. // algorithm.
MathUtil::Rectangle<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight)); MathUtil::Rectangle<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
MathUtil::Rectangle<float> destRc(-1.f, 1.f, 1.f, -1.f); MathUtil::Rectangle<float> destRc(-1.f, 1.f, 1.f, -1.f);
D3D::drawShadedTexSubQuad( D3D::drawShadedTexSubQuad(
m_yuyvTextureSRV, &sourceRc, m_yuyvTextureSRV, &sourceRc,
MAX_XFB_WIDTH, MAX_XFB_HEIGHT, MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
&destRc, &destRc,
m_pShader, m_pShader,
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout()); VertexShaderCache::GetSimpleInputLayout());
} }
else if (g_ActiveConfig.bUseXFB) else if (g_ActiveConfig.bUseXFB)
{ {
// Use virtual XFB mode // Use virtual XFB mode
// TODO: Eventually, Television should render the Virtual XFB mode // TODO: Eventually, Television should render the Virtual XFB mode
// display as well. // display as well.
} }
} }
} }

View File

@ -1,65 +1,65 @@
// Copyright (C) 2003 Dolphin Project. // Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0. // the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#ifndef _TELEVISION_H #ifndef _TELEVISION_H
#define _TELEVISION_H #define _TELEVISION_H
#include "VideoCommon.h" #include "VideoCommon.h"
struct ID3D11Texture2D; struct ID3D11Texture2D;
struct ID3D11ShaderResourceView; struct ID3D11ShaderResourceView;
struct ID3D11PixelShader; struct ID3D11PixelShader;
namespace DX11 namespace DX11
{ {
class Television class Television
{ {
public: public:
Television(); Television();
void Init(); void Init();
void Shutdown(); void Shutdown();
// Submit video data to be drawn. This will change the current state of the // Submit video data to be drawn. This will change the current state of the
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB // TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
// may be virtualized when rendering so the RAM may not actually be read. // may be virtualized when rendering so the RAM may not actually be read.
void Submit(u32 xfbAddr, u32 width, u32 height); void Submit(u32 xfbAddr, u32 width, u32 height);
// Render the current state of the TV. // Render the current state of the TV.
void Render(); void Render();
private: private:
// Properties of last Submit call // Properties of last Submit call
u32 m_curAddr; u32 m_curAddr;
u32 m_curWidth; u32 m_curWidth;
u32 m_curHeight; u32 m_curHeight;
// Used for real XFB mode // Used for real XFB mode
ID3D11Texture2D* m_yuyvTexture; ID3D11Texture2D* m_yuyvTexture;
ID3D11ShaderResourceView* m_yuyvTextureSRV; ID3D11ShaderResourceView* m_yuyvTextureSRV;
ID3D11PixelShader* m_pShader; ID3D11PixelShader* m_pShader;
}; };
} }
#endif #endif

View File

@ -64,10 +64,16 @@ void VertexManager::CreateDeviceObjects()
m_triangleDrawIndex = 0; m_triangleDrawIndex = 0;
m_lineDrawIndex = 0; m_lineDrawIndex = 0;
m_pointDrawIndex = 0; m_pointDrawIndex = 0;
m_lineShader.Init();
m_pointShader.Init();
} }
void VertexManager::DestroyDeviceObjects() void VertexManager::DestroyDeviceObjects()
{ {
m_pointShader.Shutdown();
m_lineShader.Shutdown();
SAFE_RELEASE(m_vertexBuffer); SAFE_RELEASE(m_vertexBuffer);
SAFE_RELEASE(m_indexBuffer); SAFE_RELEASE(m_indexBuffer);
} }
@ -126,6 +132,10 @@ void VertexManager::LoadBuffers()
m_indexBufferCursor += iCount; m_indexBufferCursor += iCount;
} }
static const float LINE_PT_TEX_OFFSETS[8] = {
0.f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.f, 1.f, 1.f
};
void VertexManager::Draw(UINT stride) void VertexManager::Draw(UINT stride)
{ {
D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &m_vertexDrawOffset); D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &m_vertexDrawOffset);
@ -139,15 +149,31 @@ void VertexManager::Draw(UINT stride)
} }
if (IndexGenerator::GetNumLines() > 0) if (IndexGenerator::GetNumLines() > 0)
{ {
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); float lineWidth = float(bpmem.lineptwidth.linesize) / 6.f;
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_lineDrawIndex, 0); float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
if (m_lineShader.SetShader(g_nativeVertexFmt->m_components, lineWidth, texOffset))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_lineDrawIndex, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
}
} }
if (IndexGenerator::GetNumPoints() > 0) if (IndexGenerator::GetNumPoints() > 0)
{ {
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); float pointSize = float(bpmem.lineptwidth.pointsize) / 6.f;
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_pointDrawIndex, 0); float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
if (m_pointShader.SetShader(g_nativeVertexFmt->m_components, pointSize, texOffset))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_pointDrawIndex, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
}
} }
} }

View File

@ -19,7 +19,8 @@
#define _VERTEXMANAGER_H #define _VERTEXMANAGER_H
#include "VertexManagerBase.h" #include "VertexManagerBase.h"
#include "LineGeometryShader.h"
#include "PointGeometryShader.h"
namespace DX11 namespace DX11
{ {
@ -48,6 +49,9 @@ private:
UINT m_pointDrawIndex; UINT m_pointDrawIndex;
ID3D11Buffer* m_indexBuffer; ID3D11Buffer* m_indexBuffer;
ID3D11Buffer* m_vertexBuffer; ID3D11Buffer* m_vertexBuffer;
LineGeometryShader m_lineShader;
PointGeometryShader m_pointShader;
}; };
} // namespace } // namespace

View File

@ -1,387 +1,387 @@
// Copyright (C) 2003 Dolphin Project. // Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0. // the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include "XFBEncoder.h" #include "XFBEncoder.h"
#include "D3DBase.h" #include "D3DBase.h"
#include "D3DBlob.h" #include "D3DBlob.h"
#include "D3DShader.h" #include "D3DShader.h"
#include "Render.h" #include "Render.h"
#include "GfxState.h" #include "GfxState.h"
#include "FramebufferManager.h" #include "FramebufferManager.h"
namespace DX11 namespace DX11
{ {
union XFBEncodeParams union XFBEncodeParams
{ {
struct struct
{ {
FLOAT Width; // Width and height of encoded XFB in luma pixels FLOAT Width; // Width and height of encoded XFB in luma pixels
FLOAT Height; FLOAT Height;
FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
FLOAT TexTop; FLOAT TexTop;
FLOAT TexRight; FLOAT TexRight;
FLOAT TexBottom; FLOAT TexBottom;
FLOAT Gamma; FLOAT Gamma;
}; };
// Constant buffers must be a multiple of 16 bytes in size // Constant buffers must be a multiple of 16 bytes in size
u8 pad[32]; // Pad to the next multiple of 16 u8 pad[32]; // Pad to the next multiple of 16
}; };
static const char XFB_ENCODE_VS[] = static const char XFB_ENCODE_VS[] =
"// dolphin-emu XFB encoder vertex shader\n" "// dolphin-emu XFB encoder vertex shader\n"
"cbuffer cbParams : register(b0)\n" "cbuffer cbParams : register(b0)\n"
"{\n" "{\n"
"struct\n" // Should match XFBEncodeParams above "struct\n" // Should match XFBEncodeParams above
"{\n" "{\n"
"float Width;\n" "float Width;\n"
"float Height;\n" "float Height;\n"
"float TexLeft;\n" "float TexLeft;\n"
"float TexTop;\n" "float TexTop;\n"
"float TexRight;\n" "float TexRight;\n"
"float TexBottom;\n" "float TexBottom;\n"
"float Gamma;\n" "float Gamma;\n"
"} Params;\n" "} Params;\n"
"}\n" "}\n"
"struct Output\n" "struct Output\n"
"{\n" "{\n"
"float4 Pos : SV_Position;\n" "float4 Pos : SV_Position;\n"
"float2 Coord : ENCODECOORD;\n" "float2 Coord : ENCODECOORD;\n"
"};\n" "};\n"
"Output main(in float2 Pos : POSITION)\n" "Output main(in float2 Pos : POSITION)\n"
"{\n" "{\n"
"Output result;\n" "Output result;\n"
"result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n" "result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n"
"result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n" "result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n"
"return result;\n" "return result;\n"
"}\n" "}\n"
; ;
static const char XFB_ENCODE_PS[] = static const char XFB_ENCODE_PS[] =
"// dolphin-emu XFB encoder pixel shader\n" "// dolphin-emu XFB encoder pixel shader\n"
"cbuffer cbParams : register(b0)\n" "cbuffer cbParams : register(b0)\n"
"{\n" "{\n"
"struct\n" // Should match XFBEncodeParams above "struct\n" // Should match XFBEncodeParams above
"{\n" "{\n"
"float Width;\n" "float Width;\n"
"float Height;\n" "float Height;\n"
"float TexLeft;\n" "float TexLeft;\n"
"float TexTop;\n" "float TexTop;\n"
"float TexRight;\n" "float TexRight;\n"
"float TexBottom;\n" "float TexBottom;\n"
"float Gamma;\n" "float Gamma;\n"
"} Params;\n" "} Params;\n"
"}\n" "}\n"
"Texture2D EFBTexture : register(t0);\n" "Texture2D EFBTexture : register(t0);\n"
"sampler EFBSampler : register(s0);\n" "sampler EFBSampler : register(s0);\n"
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion> // <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
"static const float3x4 RGB_TO_YCBCR = float3x4(\n" "static const float3x4 RGB_TO_YCBCR = float3x4(\n"
"0.257, 0.504, 0.098, 16.0/255.0,\n" "0.257, 0.504, 0.098, 16.0/255.0,\n"
"-0.148, -0.291, 0.439, 128.0/255.0,\n" "-0.148, -0.291, 0.439, 128.0/255.0,\n"
"0.439, -0.368, -0.071, 128.0/255.0\n" "0.439, -0.368, -0.071, 128.0/255.0\n"
");\n" ");\n"
"float3 SampleEFB(float2 coord)\n" "float3 SampleEFB(float2 coord)\n"
"{\n" "{\n"
"float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n" "float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n"
"return EFBTexture.Sample(EFBSampler, texCoord).rgb;\n" "return EFBTexture.Sample(EFBSampler, texCoord).rgb;\n"
"}\n" "}\n"
"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n" "void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
"{\n" "{\n"
"float2 baseCoord = Coord * float2(2,1);\n" "float2 baseCoord = Coord * float2(2,1);\n"
// FIXME: Shall we apply gamma here, or apply it below to the Y components? // FIXME: Shall we apply gamma here, or apply it below to the Y components?
// Be careful if you apply it to Y! The Y components are in the range (16..235) / 255. // Be careful if you apply it to Y! The Y components are in the range (16..235) / 255.
"float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
"float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
"float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
"float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n" "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
"float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n" "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n"
"float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n" "float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n"
// The Y components correspond to two EFB pixels, while the U and V are // The Y components correspond to two EFB pixels, while the U and V are
// made from a blend of three EFB pixels. // made from a blend of three EFB pixels.
"float y0 = yuvM.r;\n" "float y0 = yuvM.r;\n"
"float y1 = yuvR.r;\n" "float y1 = yuvR.r;\n"
"float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n" "float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n"
"float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n" "float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n"
"ocol0 = float4(y0, u0, y1, v0);\n" "ocol0 = float4(y0, u0, y1, v0);\n"
"}\n" "}\n"
; ;
static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = { static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 } { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
}; };
static const struct QuadVertex static const struct QuadVertex
{ {
float posX; float posX;
float posY; float posY;
} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; } QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
XFBEncoder::XFBEncoder() XFBEncoder::XFBEncoder()
: m_out(NULL), m_outRTV(NULL), m_outStage(NULL), m_encodeParams(NULL), : m_out(NULL), m_outRTV(NULL), m_outStage(NULL), m_encodeParams(NULL),
m_quad(NULL), m_vShader(NULL), m_quadLayout(NULL), m_pShader(NULL), m_quad(NULL), m_vShader(NULL), m_quadLayout(NULL), m_pShader(NULL),
m_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL), m_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL),
m_xfbEncodeRastState(NULL), m_efbSampler(NULL) m_xfbEncodeRastState(NULL), m_efbSampler(NULL)
{ } { }
void XFBEncoder::Init() void XFBEncoder::Init()
{ {
HRESULT hr; HRESULT hr;
// Create output texture // Create output texture
// The pixel shader can generate one YUYV entry per pixel. One YUYV entry // The pixel shader can generate one YUYV entry per pixel. One YUYV entry
// is created for every two EFB pixels. // is created for every two EFB pixels.
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC( D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
D3D11_BIND_RENDER_TARGET); D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out); hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture"); CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
D3D::SetDebugObjectName(m_out, "xfb encoder output texture"); D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
// Create output render target view // Create output render target view
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out, D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM); D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv"); CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv"); D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
// Create output staging buffer // Create output staging buffer
t2dd.Usage = D3D11_USAGE_STAGING; t2dd.Usage = D3D11_USAGE_STAGING;
t2dd.BindFlags = 0; t2dd.BindFlags = 0;
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage); hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage);
CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer"); CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer"); D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
// Create constant buffer for uploading params to shaders // Create constant buffer for uploading params to shaders
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
D3D11_BIND_CONSTANT_BUFFER); D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams); hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams);
CHECK(SUCCEEDED(hr), "create xfb encode params buffer"); CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer"); D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
// Create vertex quad // Create vertex quad
bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
D3D11_USAGE_IMMUTABLE); D3D11_USAGE_IMMUTABLE);
D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 }; D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad); hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer"); CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer"); D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
// Create vertex shader // Create vertex shader
D3DBlob* bytecode = NULL; D3DBlob* bytecode = NULL;
if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode)) if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode))
{ {
ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile"); ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
return; return;
} }
hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader); hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader);
CHECK(SUCCEEDED(hr), "create xfb encode vertex shader"); CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader"); D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
// Create input layout for vertex quad using bytecode from vertex shader // Create input layout for vertex quad using bytecode from vertex shader
hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC, hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC), sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
bytecode->Data(), bytecode->Size(), &m_quadLayout); bytecode->Data(), bytecode->Size(), &m_quadLayout);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout"); CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout"); D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
bytecode->Release(); bytecode->Release();
// Create pixel shader // Create pixel shader
m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS)); m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS));
if (!m_pShader) if (!m_pShader)
{ {
ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile"); ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
return; return;
} }
D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader"); D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
// Create blend state // Create blend state
D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState); hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
CHECK(SUCCEEDED(hr), "create xfb encode blend state"); CHECK(SUCCEEDED(hr), "create xfb encode blend state");
D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state"); D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
// Create depth state // Create depth state
D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
dsd.DepthEnable = FALSE; dsd.DepthEnable = FALSE;
hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState); hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
CHECK(SUCCEEDED(hr), "create xfb encode depth state"); CHECK(SUCCEEDED(hr), "create xfb encode depth state");
D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state"); D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
// Create rasterizer state // Create rasterizer state
D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
rd.CullMode = D3D11_CULL_NONE; rd.CullMode = D3D11_CULL_NONE;
rd.DepthClipEnable = FALSE; rd.DepthClipEnable = FALSE;
hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState); hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state"); CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state"); D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
// Create EFB texture sampler // Create EFB texture sampler
D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
// FIXME: Should we really use point sampling here? // FIXME: Should we really use point sampling here?
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler); hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
CHECK(SUCCEEDED(hr), "create xfb encode texture sampler"); CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler"); D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
} }
void XFBEncoder::Shutdown() void XFBEncoder::Shutdown()
{ {
SAFE_RELEASE(m_efbSampler); SAFE_RELEASE(m_efbSampler);
SAFE_RELEASE(m_xfbEncodeRastState); SAFE_RELEASE(m_xfbEncodeRastState);
SAFE_RELEASE(m_xfbEncodeDepthState); SAFE_RELEASE(m_xfbEncodeDepthState);
SAFE_RELEASE(m_xfbEncodeBlendState); SAFE_RELEASE(m_xfbEncodeBlendState);
SAFE_RELEASE(m_pShader); SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_quadLayout); SAFE_RELEASE(m_quadLayout);
SAFE_RELEASE(m_vShader); SAFE_RELEASE(m_vShader);
SAFE_RELEASE(m_quad); SAFE_RELEASE(m_quad);
SAFE_RELEASE(m_encodeParams); SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage); SAFE_RELEASE(m_outStage);
SAFE_RELEASE(m_outRTV); SAFE_RELEASE(m_outRTV);
SAFE_RELEASE(m_out); SAFE_RELEASE(m_out);
} }
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma) void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
{ {
HRESULT hr; HRESULT hr;
// Reset API // Reset API
g_renderer->ResetAPIState(); g_renderer->ResetAPIState();
// Set up all the state for XFB encoding // Set up all the state for XFB encoding
D3D::context->PSSetShader(m_pShader, NULL, 0); D3D::context->PSSetShader(m_pShader, NULL, 0);
D3D::context->VSSetShader(m_vShader, NULL, 0); D3D::context->VSSetShader(m_vShader, NULL, 0);
D3D::stateman->PushBlendState(m_xfbEncodeBlendState); D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
D3D::stateman->PushDepthState(m_xfbEncodeDepthState); D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
D3D::stateman->Apply(); D3D::stateman->Apply();
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height)); D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
D3D::context->IASetInputLayout(m_quadLayout); D3D::context->IASetInputLayout(m_quadLayout);
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
UINT stride = sizeof(QuadVertex); UINT stride = sizeof(QuadVertex);
UINT offset = 0; UINT offset = 0;
D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset); D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset);
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
XFBEncodeParams params = { 0 }; XFBEncodeParams params = { 0 };
params.Width = FLOAT(width); params.Width = FLOAT(width);
params.Height = FLOAT(height); params.Height = FLOAT(height);
params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetFullTargetWidth(); params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetFullTargetWidth();
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetFullTargetHeight(); params.TexTop = FLOAT(targetRect.top) / g_renderer->GetFullTargetHeight();
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetFullTargetWidth(); params.TexRight = FLOAT(targetRect.right) / g_renderer->GetFullTargetWidth();
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetFullTargetHeight(); params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetFullTargetHeight();
params.Gamma = gamma; params.Gamma = gamma;
D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, &params, 0, 0); D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, &params, 0, 0);
D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams); D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams);
D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL); D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL);
ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV(); ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV();
D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams); D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams);
D3D::context->PSSetShaderResources(0, 1, &pEFB); D3D::context->PSSetShaderResources(0, 1, &pEFB);
D3D::context->PSSetSamplers(0, 1, &m_efbSampler); D3D::context->PSSetSamplers(0, 1, &m_efbSampler);
// Encode! // Encode!
D3D::context->Draw(4, 0); D3D::context->Draw(4, 0);
// Copy to staging buffer // Copy to staging buffer
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1); D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1);
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
// Clean up state // Clean up state
IUnknown* nullDummy = NULL; IUnknown* nullDummy = NULL;
D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy); D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy);
D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy); D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy);
D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy); D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
D3D::context->OMSetRenderTargets(0, NULL, NULL); D3D::context->OMSetRenderTargets(0, NULL, NULL);
D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy); D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
D3D::stateman->PopRasterizerState(); D3D::stateman->PopRasterizerState();
D3D::stateman->PopDepthState(); D3D::stateman->PopDepthState();
D3D::stateman->PopBlendState(); D3D::stateman->PopBlendState();
D3D::context->PSSetShader(NULL, NULL, 0); D3D::context->PSSetShader(NULL, NULL, 0);
D3D::context->VSSetShader(NULL, NULL, 0); D3D::context->VSSetShader(NULL, NULL, 0);
// Transfer staging buffer to GameCube/Wii RAM // Transfer staging buffer to GameCube/Wii RAM
D3D11_MAPPED_SUBRESOURCE map = { 0 }; D3D11_MAPPED_SUBRESOURCE map = { 0 };
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
CHECK(SUCCEEDED(hr), "map staging buffer"); CHECK(SUCCEEDED(hr), "map staging buffer");
u8* src = (u8*)map.pData; u8* src = (u8*)map.pData;
for (unsigned int y = 0; y < height; ++y) for (unsigned int y = 0; y < height; ++y)
{ {
memcpy(dst, src, 2*width); memcpy(dst, src, 2*width);
dst += bpmem.copyMipMapStrideChannels*32; dst += bpmem.copyMipMapStrideChannels*32;
src += map.RowPitch; src += map.RowPitch;
} }
D3D::context->Unmap(m_outStage, 0); D3D::context->Unmap(m_outStage, 0);
// Restore API // Restore API
g_renderer->RestoreAPIState(); g_renderer->RestoreAPIState();
D3D::context->OMSetRenderTargets(1, D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(), &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV()); FramebufferManager::GetEFBDepthTexture()->GetDSV());
} }
} }

View File

@ -1,68 +1,68 @@
// Copyright (C) 2003 Dolphin Project. // Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0. // the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful, // This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details. // GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program. // A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/ // If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#ifndef _XFBENCODER_H #ifndef _XFBENCODER_H
#define _XFBENCODER_H #define _XFBENCODER_H
#include "VideoCommon.h" #include "VideoCommon.h"
struct ID3D11Texture2D; struct ID3D11Texture2D;
struct ID3D11RenderTargetView; struct ID3D11RenderTargetView;
struct ID3D11Buffer; struct ID3D11Buffer;
struct ID3D11VertexShader; struct ID3D11VertexShader;
struct ID3D11PixelShader; struct ID3D11PixelShader;
struct ID3D11InputLayout; struct ID3D11InputLayout;
struct ID3D11BlendState; struct ID3D11BlendState;
struct ID3D11DepthStencilState; struct ID3D11DepthStencilState;
struct ID3D11RasterizerState; struct ID3D11RasterizerState;
struct ID3D11SamplerState; struct ID3D11SamplerState;
namespace DX11 namespace DX11
{ {
class XFBEncoder class XFBEncoder
{ {
public: public:
XFBEncoder(); XFBEncoder();
void Init(); void Init();
void Shutdown(); void Shutdown();
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma); void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
private: private:
ID3D11Texture2D* m_out; ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV; ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage; ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams; ID3D11Buffer* m_encodeParams;
ID3D11Buffer* m_quad; ID3D11Buffer* m_quad;
ID3D11VertexShader* m_vShader; ID3D11VertexShader* m_vShader;
ID3D11InputLayout* m_quadLayout; ID3D11InputLayout* m_quadLayout;
ID3D11PixelShader* m_pShader; ID3D11PixelShader* m_pShader;
ID3D11BlendState* m_xfbEncodeBlendState; ID3D11BlendState* m_xfbEncodeBlendState;
ID3D11DepthStencilState* m_xfbEncodeDepthState; ID3D11DepthStencilState* m_xfbEncodeDepthState;
ID3D11RasterizerState* m_xfbEncodeRastState; ID3D11RasterizerState* m_xfbEncodeRastState;
ID3D11SamplerState* m_efbSampler; ID3D11SamplerState* m_efbSampler;
}; };
} }
#endif #endif