diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
index 0f69cb5b46..308fd32727 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
@@ -73,6 +73,37 @@ static char text[16384];
#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)
{
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"
);
- 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");
+ p = GenerateVSOutputStruct(p, components, api_type);
// uniforms
diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h
index 1b39c248f0..d7bf362213 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderGen.h
+++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h
@@ -103,6 +103,7 @@ public:
// 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);
void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components);
diff --git a/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj b/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj
index 82601ff250..f1f4d40457 100644
--- a/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj
+++ b/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj
@@ -197,9 +197,11 @@
+
+
@@ -225,8 +227,10 @@
+
+
diff --git a/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj.filters b/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj.filters
index 0feb3c7dd0..6492e887ca 100644
--- a/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj.filters
+++ b/Source/Plugins/Plugin_VideoDX11/Plugin_VideoDX11.vcxproj.filters
@@ -51,6 +51,12 @@
Render
+
+ Render
+
+
+ Render
+
@@ -105,6 +111,12 @@
Render
+
+ Render
+
+
+ Render
+
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp
index 80e3482b95..83eb8246d5 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp
@@ -415,7 +415,6 @@ void Close()
UnloadDXGI();
}
-/* just returning the 4_0 ones here */
const char* VertexShaderVersionString()
{
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";
}
+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()
{
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0";
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h
index 16cc1c7865..20b3bb63bd 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h
+++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h
@@ -64,6 +64,7 @@ unsigned int GetBackBufferWidth();
unsigned int GetBackBufferHeight();
D3DTexture2D* &GetBackBuffer();
const char* PixelShaderVersionString();
+const char* GeometryShaderVersionString();
const char* VertexShaderVersionString();
bool BGRATexturesSupported();
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.cpp b/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.cpp
index a398417e61..b1eb9943eb 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.cpp
@@ -82,6 +82,61 @@ bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
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
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);
}
-ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len)
+ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
+ unsigned int len)
{
D3DBlob* blob = NULL;
if (CompileVertexShader(code, len, &blob))
@@ -151,7 +207,22 @@ ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int
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;
CompilePixelShader(code, len, &blob);
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.h b/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.h
index a60382ca79..8594e22851 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.h
+++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DShader.h
@@ -29,20 +29,38 @@ namespace DX11
namespace D3D
{
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
+ ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
// The returned bytecode buffers should be Release()d.
- bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob);
- bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
+ bool CompileVertexShader(const char* code, unsigned int len,
+ 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
- ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len);
- ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len);
+ ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
+ 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 ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
- inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) { return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); }
- inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
+ inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
+ { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
+ inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
+ { 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
\ No newline at end of file
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.cpp b/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.cpp
new file mode 100644
index 0000000000..0053d32065
--- /dev/null
+++ b/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.cpp
@@ -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
+#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 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, ¶ms, 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
+#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 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, ¶ms, 0, 0);
+
+ D3D::context->GSSetShader(shaderIt->second, NULL, 0);
+ D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
+
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+}
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.h b/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.h
new file mode 100644
index 0000000000..0330ef4ed7
--- /dev/null
+++ b/Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.h
@@ -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 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 ComboMap;
+
+ ComboMap m_shaders;
+
+};
+
+}
+
+#endif
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PSTextureEncoder.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PSTextureEncoder.cpp
index 83e7a6bc45..940c66b523 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/PSTextureEncoder.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/PSTextureEncoder.cpp
@@ -1265,10 +1265,8 @@ bool PSTextureEncoder::SetStaticShader(unsigned int dstFormat, unsigned int srcF
HRESULT hr = D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), NULL, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
- m_staticShaders[key] = newShader;
+ it = m_staticShaders.insert(std::make_pair(key, newShader)).first;
bytecode->Release();
-
- it = m_staticShaders.find(key);
}
if (it != m_staticShaders.end())
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.cpp b/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.cpp
new file mode 100644
index 0000000000..3ba714b57f
--- /dev/null
+++ b/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.cpp
@@ -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
+#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 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, ¶ms, 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
+#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 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, ¶ms, 0, 0);
+
+ D3D::context->GSSetShader(shaderIt->second, NULL, 0);
+ D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
+
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+}
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.h b/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.h
new file mode 100644
index 0000000000..1f6385374f
--- /dev/null
+++ b/Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.h
@@ -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 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 ComboMap;
+
+ ComboMap m_shaders;
+
+};
+
+}
+
+#endif
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Television.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Television.cpp
index 4fbc3be3d4..bed7d8e632 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/Television.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/Television.cpp
@@ -1,154 +1,154 @@
-// 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 "Television.h"
-
-#include "VideoConfig.h"
-#include "D3DBase.h"
-#include "D3DShader.h"
-#include "D3DUtil.h"
-#include "VertexShaderCache.h"
-#include "HW/Memmap.h"
-
-namespace DX11
-{
-
-static const char YUYV_DECODER_PS[] =
-"// dolphin-emu YUYV decoder pixel shader\n"
-
-"Texture2D Tex0 : register(t0);\n"
-"sampler Samp0 : register(s0);\n"
-
-"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
- "1.164, 0.000, 1.596,\n"
- "1.164, -0.392, -0.813,\n"
- "1.164, 2.017, 0.000\n"
- ");\n"
-
-"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
-"{\n"
- "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
-
- // 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.
- // We want to convert it to RGB format with sRGB color primaries, with
- // range 0..255.
-
- // Recover RGB components
- "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"
-
- // If we were really obsessed with accuracy, we would correct for the
- // differing color primaries between BT.601 and sRGB. However, this may not
- // be worth the trouble because:
- // - 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
- // NTSC and PAL primaries.
- // - 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
- // game.
- // - Even the game designers probably don't pay close attention to this
- // stuff.
- // Still, instructions on how to do it can be found at
- //
-
- "ocol0 = float4(rgb_601, 1);\n"
-"}\n"
-;
-
-Television::Television()
- : m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL)
-{ }
-
-void Television::Init()
-{
- HRESULT hr;
-
- // Create YUYV texture for real XFB mode
-
- // This texture format is designed for YUYV data.
- D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
- DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
- hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_yuyvTexture);
- CHECK(SUCCEEDED(hr), "create tv yuyv texture");
- D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
-
- // Create shader resource view for YUYV texture
-
- D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
- m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
- DXGI_FORMAT_G8R8_G8B8_UNORM);
- hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
- CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
- D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
-
- // Create YUYV-decoding pixel shader
-
- m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS));
- CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader");
- D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
-}
-
-void Television::Shutdown()
-{
- SAFE_RELEASE(m_pShader);
- SAFE_RELEASE(m_yuyvTextureSRV);
- SAFE_RELEASE(m_yuyvTexture);
-}
-
-void Television::Submit(u32 xfbAddr, u32 width, u32 height)
-{
- m_curAddr = xfbAddr;
- m_curWidth = width;
- m_curHeight = height;
-
- // Load data from GameCube RAM to YUYV texture
- u8* yuyvSrc = Memory::GetPointer(xfbAddr);
- D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1);
- D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height);
-}
-
-void Television::Render()
-{
- if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
- {
- // Use real XFB mode
- // TODO: If this is the lower field, render at a vertical offset of 1
- // line down. We could even consider implementing a deinterlacing
- // algorithm.
-
- MathUtil::Rectangle sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
- MathUtil::Rectangle destRc(-1.f, 1.f, 1.f, -1.f);
-
- D3D::drawShadedTexSubQuad(
- m_yuyvTextureSRV, &sourceRc,
- MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
- &destRc,
- m_pShader,
- VertexShaderCache::GetSimpleVertexShader(),
- VertexShaderCache::GetSimpleInputLayout());
- }
- else if (g_ActiveConfig.bUseXFB)
- {
- // Use virtual XFB mode
-
- // TODO: Eventually, Television should render the Virtual XFB mode
- // display as well.
- }
-}
-
-}
+// 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 "Television.h"
+
+#include "VideoConfig.h"
+#include "D3DBase.h"
+#include "D3DShader.h"
+#include "D3DUtil.h"
+#include "VertexShaderCache.h"
+#include "HW/Memmap.h"
+
+namespace DX11
+{
+
+static const char YUYV_DECODER_PS[] =
+"// dolphin-emu YUYV decoder pixel shader\n"
+
+"Texture2D Tex0 : register(t0);\n"
+"sampler Samp0 : register(s0);\n"
+
+"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
+ "1.164, 0.000, 1.596,\n"
+ "1.164, -0.392, -0.813,\n"
+ "1.164, 2.017, 0.000\n"
+ ");\n"
+
+"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
+"{\n"
+ "float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
+
+ // 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.
+ // We want to convert it to RGB format with sRGB color primaries, with
+ // range 0..255.
+
+ // Recover RGB components
+ "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"
+
+ // If we were really obsessed with accuracy, we would correct for the
+ // differing color primaries between BT.601 and sRGB. However, this may not
+ // be worth the trouble because:
+ // - 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
+ // NTSC and PAL primaries.
+ // - 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
+ // game.
+ // - Even the game designers probably don't pay close attention to this
+ // stuff.
+ // Still, instructions on how to do it can be found at
+ //
+
+ "ocol0 = float4(rgb_601, 1);\n"
+"}\n"
+;
+
+Television::Television()
+ : m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL)
+{ }
+
+void Television::Init()
+{
+ HRESULT hr;
+
+ // Create YUYV texture for real XFB mode
+
+ // This texture format is designed for YUYV data.
+ D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
+ DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
+ hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_yuyvTexture);
+ CHECK(SUCCEEDED(hr), "create tv yuyv texture");
+ D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
+
+ // Create shader resource view for YUYV texture
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
+ m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
+ DXGI_FORMAT_G8R8_G8B8_UNORM);
+ hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
+ CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
+ D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
+
+ // Create YUYV-decoding pixel shader
+
+ m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS));
+ CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader");
+ D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
+}
+
+void Television::Shutdown()
+{
+ SAFE_RELEASE(m_pShader);
+ SAFE_RELEASE(m_yuyvTextureSRV);
+ SAFE_RELEASE(m_yuyvTexture);
+}
+
+void Television::Submit(u32 xfbAddr, u32 width, u32 height)
+{
+ m_curAddr = xfbAddr;
+ m_curWidth = width;
+ m_curHeight = height;
+
+ // Load data from GameCube RAM to YUYV texture
+ u8* yuyvSrc = Memory::GetPointer(xfbAddr);
+ D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1);
+ D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height);
+}
+
+void Television::Render()
+{
+ if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
+ {
+ // Use real XFB mode
+ // TODO: If this is the lower field, render at a vertical offset of 1
+ // line down. We could even consider implementing a deinterlacing
+ // algorithm.
+
+ MathUtil::Rectangle sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
+ MathUtil::Rectangle destRc(-1.f, 1.f, 1.f, -1.f);
+
+ D3D::drawShadedTexSubQuad(
+ m_yuyvTextureSRV, &sourceRc,
+ MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
+ &destRc,
+ m_pShader,
+ VertexShaderCache::GetSimpleVertexShader(),
+ VertexShaderCache::GetSimpleInputLayout());
+ }
+ else if (g_ActiveConfig.bUseXFB)
+ {
+ // Use virtual XFB mode
+
+ // TODO: Eventually, Television should render the Virtual XFB mode
+ // display as well.
+ }
+}
+
+}
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Television.h b/Source/Plugins/Plugin_VideoDX11/Src/Television.h
index 4b921223ec..0b9a346a7c 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/Television.h
+++ b/Source/Plugins/Plugin_VideoDX11/Src/Television.h
@@ -1,65 +1,65 @@
-// 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 _TELEVISION_H
-#define _TELEVISION_H
-
-#include "VideoCommon.h"
-
-struct ID3D11Texture2D;
-struct ID3D11ShaderResourceView;
-struct ID3D11PixelShader;
-
-namespace DX11
-{
-
-class Television
-{
-
-public:
-
- Television();
-
- void Init();
- void Shutdown();
-
- // 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
- // may be virtualized when rendering so the RAM may not actually be read.
- void Submit(u32 xfbAddr, u32 width, u32 height);
-
- // Render the current state of the TV.
- void Render();
-
-private:
-
- // Properties of last Submit call
- u32 m_curAddr;
- u32 m_curWidth;
- u32 m_curHeight;
-
- // Used for real XFB mode
-
- ID3D11Texture2D* m_yuyvTexture;
- ID3D11ShaderResourceView* m_yuyvTextureSRV;
- ID3D11PixelShader* m_pShader;
-
-};
-
-}
-
-#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 _TELEVISION_H
+#define _TELEVISION_H
+
+#include "VideoCommon.h"
+
+struct ID3D11Texture2D;
+struct ID3D11ShaderResourceView;
+struct ID3D11PixelShader;
+
+namespace DX11
+{
+
+class Television
+{
+
+public:
+
+ Television();
+
+ void Init();
+ void Shutdown();
+
+ // 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
+ // may be virtualized when rendering so the RAM may not actually be read.
+ void Submit(u32 xfbAddr, u32 width, u32 height);
+
+ // Render the current state of the TV.
+ void Render();
+
+private:
+
+ // Properties of last Submit call
+ u32 m_curAddr;
+ u32 m_curWidth;
+ u32 m_curHeight;
+
+ // Used for real XFB mode
+
+ ID3D11Texture2D* m_yuyvTexture;
+ ID3D11ShaderResourceView* m_yuyvTextureSRV;
+ ID3D11PixelShader* m_pShader;
+
+};
+
+}
+
+#endif
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp
index fc144f0518..67171e4b49 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp
@@ -64,10 +64,16 @@ void VertexManager::CreateDeviceObjects()
m_triangleDrawIndex = 0;
m_lineDrawIndex = 0;
m_pointDrawIndex = 0;
+
+ m_lineShader.Init();
+ m_pointShader.Init();
}
void VertexManager::DestroyDeviceObjects()
{
+ m_pointShader.Shutdown();
+ m_lineShader.Shutdown();
+
SAFE_RELEASE(m_vertexBuffer);
SAFE_RELEASE(m_indexBuffer);
}
@@ -126,6 +132,10 @@ void VertexManager::LoadBuffers()
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)
{
D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &m_vertexDrawOffset);
@@ -139,15 +149,31 @@ void VertexManager::Draw(UINT stride)
}
if (IndexGenerator::GetNumLines() > 0)
{
- D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
- D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_lineDrawIndex, 0);
- INCSTAT(stats.thisFrame.numIndexedDrawCalls);
+ float lineWidth = float(bpmem.lineptwidth.linesize) / 6.f;
+ float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
+
+ 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)
{
- D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
- D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_pointDrawIndex, 0);
- INCSTAT(stats.thisFrame.numIndexedDrawCalls);
+ float pointSize = float(bpmem.lineptwidth.pointsize) / 6.f;
+ float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
+
+ 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);
+ }
}
}
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.h b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.h
index f79a03d4d6..a387be5155 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.h
+++ b/Source/Plugins/Plugin_VideoDX11/Src/VertexManager.h
@@ -19,7 +19,8 @@
#define _VERTEXMANAGER_H
#include "VertexManagerBase.h"
-
+#include "LineGeometryShader.h"
+#include "PointGeometryShader.h"
namespace DX11
{
@@ -48,6 +49,9 @@ private:
UINT m_pointDrawIndex;
ID3D11Buffer* m_indexBuffer;
ID3D11Buffer* m_vertexBuffer;
+
+ LineGeometryShader m_lineShader;
+ PointGeometryShader m_pointShader;
};
} // namespace
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp b/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp
index cedad0a880..f1fa0e8387 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp
+++ b/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp
@@ -1,387 +1,387 @@
-// 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 "XFBEncoder.h"
-
-#include "D3DBase.h"
-#include "D3DBlob.h"
-#include "D3DShader.h"
-#include "Render.h"
-#include "GfxState.h"
-#include "FramebufferManager.h"
-
-namespace DX11
-{
-
-union XFBEncodeParams
-{
- struct
- {
- FLOAT Width; // Width and height of encoded XFB in luma pixels
- FLOAT Height;
- FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
- FLOAT TexTop;
- FLOAT TexRight;
- FLOAT TexBottom;
- FLOAT Gamma;
- };
- // Constant buffers must be a multiple of 16 bytes in size
- u8 pad[32]; // Pad to the next multiple of 16
-};
-
-static const char XFB_ENCODE_VS[] =
-"// dolphin-emu XFB encoder vertex shader\n"
-
-"cbuffer cbParams : register(b0)\n"
-"{\n"
- "struct\n" // Should match XFBEncodeParams above
- "{\n"
- "float Width;\n"
- "float Height;\n"
- "float TexLeft;\n"
- "float TexTop;\n"
- "float TexRight;\n"
- "float TexBottom;\n"
- "float Gamma;\n"
- "} Params;\n"
-"}\n"
-
-"struct Output\n"
-"{\n"
- "float4 Pos : SV_Position;\n"
- "float2 Coord : ENCODECOORD;\n"
-"};\n"
-
-"Output main(in float2 Pos : POSITION)\n"
-"{\n"
- "Output result;\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"
- "return result;\n"
-"}\n"
-;
-
-static const char XFB_ENCODE_PS[] =
-"// dolphin-emu XFB encoder pixel shader\n"
-
-"cbuffer cbParams : register(b0)\n"
-"{\n"
- "struct\n" // Should match XFBEncodeParams above
- "{\n"
- "float Width;\n"
- "float Height;\n"
- "float TexLeft;\n"
- "float TexTop;\n"
- "float TexRight;\n"
- "float TexBottom;\n"
- "float Gamma;\n"
- "} Params;\n"
-"}\n"
-
-"Texture2D EFBTexture : register(t0);\n"
-"sampler EFBSampler : register(s0);\n"
-
-// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
-//
-"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
- "0.257, 0.504, 0.098, 16.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"
- ");\n"
-
-"float3 SampleEFB(float2 coord)\n"
-"{\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"
-"}\n"
-
-"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
-"{\n"
- "float2 baseCoord = Coord * float2(2,1);\n"
- // 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.
- "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
- "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
- "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
-
- "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
- "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,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
- // made from a blend of three EFB pixels.
- "float y0 = yuvM.r;\n"
- "float y1 = yuvR.r;\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"
-
- "ocol0 = float4(y0, u0, y1, v0);\n"
-"}\n"
-;
-
-static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
- { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
-};
-
-static const struct QuadVertex
-{
- float posX;
- float posY;
-} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
-
-XFBEncoder::XFBEncoder()
- : 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_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL),
- m_xfbEncodeRastState(NULL), m_efbSampler(NULL)
-{ }
-
-void XFBEncoder::Init()
-{
- HRESULT hr;
-
- // Create output texture
-
- // The pixel shader can generate one YUYV entry per pixel. One YUYV entry
- // is created for every two EFB pixels.
- D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
- DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
- D3D11_BIND_RENDER_TARGET);
- hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out);
- CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
- D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
-
- // Create output render target view
-
- D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
- D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
- hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
- CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
- D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
-
- // Create output staging buffer
-
- t2dd.Usage = D3D11_USAGE_STAGING;
- t2dd.BindFlags = 0;
- t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage);
- CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
- D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
-
- // Create constant buffer for uploading params to shaders
-
- D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
- D3D11_BIND_CONSTANT_BUFFER);
- hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams);
- CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
- D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
-
- // Create vertex quad
-
- bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
- D3D11_USAGE_IMMUTABLE);
- D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
-
- hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
- CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
- D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
-
- // Create vertex shader
-
- D3DBlob* bytecode = NULL;
- if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode))
- {
- ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
- return;
- }
-
- hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader);
- CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
- D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
-
- // Create input layout for vertex quad using bytecode from vertex shader
-
- hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
- sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
- bytecode->Data(), bytecode->Size(), &m_quadLayout);
- CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
- D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
-
- bytecode->Release();
-
- // Create pixel shader
-
- m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS));
- if (!m_pShader)
- {
- ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
- return;
- }
- D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
-
- // Create blend state
-
- D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
- hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
- CHECK(SUCCEEDED(hr), "create xfb encode blend state");
- D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
-
- // Create depth state
-
- D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
- dsd.DepthEnable = FALSE;
- hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
- CHECK(SUCCEEDED(hr), "create xfb encode depth state");
- D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
-
- // Create rasterizer state
-
- D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
- rd.CullMode = D3D11_CULL_NONE;
- rd.DepthClipEnable = FALSE;
- hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
- CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
- D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
-
- // Create EFB texture sampler
-
- D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
- // FIXME: Should we really use point sampling here?
- sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
- hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
- CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
- D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
-}
-
-void XFBEncoder::Shutdown()
-{
- SAFE_RELEASE(m_efbSampler);
- SAFE_RELEASE(m_xfbEncodeRastState);
- SAFE_RELEASE(m_xfbEncodeDepthState);
- SAFE_RELEASE(m_xfbEncodeBlendState);
- SAFE_RELEASE(m_pShader);
- SAFE_RELEASE(m_quadLayout);
- SAFE_RELEASE(m_vShader);
- SAFE_RELEASE(m_quad);
- SAFE_RELEASE(m_encodeParams);
- SAFE_RELEASE(m_outStage);
- SAFE_RELEASE(m_outRTV);
- SAFE_RELEASE(m_out);
-}
-
-void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
-{
- HRESULT hr;
-
- // Reset API
-
- g_renderer->ResetAPIState();
-
- // Set up all the state for XFB encoding
-
- D3D::context->PSSetShader(m_pShader, NULL, 0);
- D3D::context->VSSetShader(m_vShader, NULL, 0);
-
- D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
- D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
- D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
- D3D::stateman->Apply();
-
- D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
- D3D::context->RSSetViewports(1, &vp);
-
- D3D::context->IASetInputLayout(m_quadLayout);
- D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
- UINT stride = sizeof(QuadVertex);
- UINT offset = 0;
- D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset);
-
- TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
-
- XFBEncodeParams params = { 0 };
- params.Width = FLOAT(width);
- params.Height = FLOAT(height);
- params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetFullTargetWidth();
- params.TexTop = FLOAT(targetRect.top) / g_renderer->GetFullTargetHeight();
- params.TexRight = FLOAT(targetRect.right) / g_renderer->GetFullTargetWidth();
- params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetFullTargetHeight();
- params.Gamma = gamma;
- D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, ¶ms, 0, 0);
-
- D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams);
-
- D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL);
-
- ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV();
-
- D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams);
- D3D::context->PSSetShaderResources(0, 1, &pEFB);
- D3D::context->PSSetSamplers(0, 1, &m_efbSampler);
-
- // Encode!
-
- D3D::context->Draw(4, 0);
-
- // Copy to staging buffer
-
- 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);
-
- // Clean up state
-
- IUnknown* nullDummy = NULL;
-
- D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy);
- D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy);
- D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
-
- D3D::context->OMSetRenderTargets(0, NULL, NULL);
-
- D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
-
- D3D::stateman->PopRasterizerState();
- D3D::stateman->PopDepthState();
- D3D::stateman->PopBlendState();
-
- D3D::context->PSSetShader(NULL, NULL, 0);
- D3D::context->VSSetShader(NULL, NULL, 0);
-
- // Transfer staging buffer to GameCube/Wii RAM
-
- D3D11_MAPPED_SUBRESOURCE map = { 0 };
- hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
- CHECK(SUCCEEDED(hr), "map staging buffer");
-
- u8* src = (u8*)map.pData;
- for (unsigned int y = 0; y < height; ++y)
- {
- memcpy(dst, src, 2*width);
- dst += bpmem.copyMipMapStrideChannels*32;
- src += map.RowPitch;
- }
-
- D3D::context->Unmap(m_outStage, 0);
-
- // Restore API
-
- g_renderer->RestoreAPIState();
- D3D::context->OMSetRenderTargets(1,
- &FramebufferManager::GetEFBColorTexture()->GetRTV(),
- FramebufferManager::GetEFBDepthTexture()->GetDSV());
-}
-
-}
+// 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 "XFBEncoder.h"
+
+#include "D3DBase.h"
+#include "D3DBlob.h"
+#include "D3DShader.h"
+#include "Render.h"
+#include "GfxState.h"
+#include "FramebufferManager.h"
+
+namespace DX11
+{
+
+union XFBEncodeParams
+{
+ struct
+ {
+ FLOAT Width; // Width and height of encoded XFB in luma pixels
+ FLOAT Height;
+ FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
+ FLOAT TexTop;
+ FLOAT TexRight;
+ FLOAT TexBottom;
+ FLOAT Gamma;
+ };
+ // Constant buffers must be a multiple of 16 bytes in size
+ u8 pad[32]; // Pad to the next multiple of 16
+};
+
+static const char XFB_ENCODE_VS[] =
+"// dolphin-emu XFB encoder vertex shader\n"
+
+"cbuffer cbParams : register(b0)\n"
+"{\n"
+ "struct\n" // Should match XFBEncodeParams above
+ "{\n"
+ "float Width;\n"
+ "float Height;\n"
+ "float TexLeft;\n"
+ "float TexTop;\n"
+ "float TexRight;\n"
+ "float TexBottom;\n"
+ "float Gamma;\n"
+ "} Params;\n"
+"}\n"
+
+"struct Output\n"
+"{\n"
+ "float4 Pos : SV_Position;\n"
+ "float2 Coord : ENCODECOORD;\n"
+"};\n"
+
+"Output main(in float2 Pos : POSITION)\n"
+"{\n"
+ "Output result;\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"
+ "return result;\n"
+"}\n"
+;
+
+static const char XFB_ENCODE_PS[] =
+"// dolphin-emu XFB encoder pixel shader\n"
+
+"cbuffer cbParams : register(b0)\n"
+"{\n"
+ "struct\n" // Should match XFBEncodeParams above
+ "{\n"
+ "float Width;\n"
+ "float Height;\n"
+ "float TexLeft;\n"
+ "float TexTop;\n"
+ "float TexRight;\n"
+ "float TexBottom;\n"
+ "float Gamma;\n"
+ "} Params;\n"
+"}\n"
+
+"Texture2D EFBTexture : register(t0);\n"
+"sampler EFBSampler : register(s0);\n"
+
+// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
+//
+"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
+ "0.257, 0.504, 0.098, 16.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"
+ ");\n"
+
+"float3 SampleEFB(float2 coord)\n"
+"{\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"
+"}\n"
+
+"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
+"{\n"
+ "float2 baseCoord = Coord * float2(2,1);\n"
+ // 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.
+ "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
+ "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
+ "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
+
+ "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
+ "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,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
+ // made from a blend of three EFB pixels.
+ "float y0 = yuvM.r;\n"
+ "float y1 = yuvR.r;\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"
+
+ "ocol0 = float4(y0, u0, y1, v0);\n"
+"}\n"
+;
+
+static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
+};
+
+static const struct QuadVertex
+{
+ float posX;
+ float posY;
+} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
+
+XFBEncoder::XFBEncoder()
+ : 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_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL),
+ m_xfbEncodeRastState(NULL), m_efbSampler(NULL)
+{ }
+
+void XFBEncoder::Init()
+{
+ HRESULT hr;
+
+ // Create output texture
+
+ // The pixel shader can generate one YUYV entry per pixel. One YUYV entry
+ // is created for every two EFB pixels.
+ D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
+ DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
+ D3D11_BIND_RENDER_TARGET);
+ hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out);
+ CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
+ D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
+
+ // Create output render target view
+
+ D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
+ D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
+ hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
+ CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
+ D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
+
+ // Create output staging buffer
+
+ t2dd.Usage = D3D11_USAGE_STAGING;
+ t2dd.BindFlags = 0;
+ t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage);
+ CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
+ D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
+
+ // Create constant buffer for uploading params to shaders
+
+ D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
+ D3D11_BIND_CONSTANT_BUFFER);
+ hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams);
+ CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
+ D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
+
+ // Create vertex quad
+
+ bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
+ D3D11_USAGE_IMMUTABLE);
+ D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
+
+ hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
+ CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
+ D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
+
+ // Create vertex shader
+
+ D3DBlob* bytecode = NULL;
+ if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode))
+ {
+ ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
+ return;
+ }
+
+ hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader);
+ CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
+ D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
+
+ // Create input layout for vertex quad using bytecode from vertex shader
+
+ hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
+ sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
+ bytecode->Data(), bytecode->Size(), &m_quadLayout);
+ CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
+ D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
+
+ bytecode->Release();
+
+ // Create pixel shader
+
+ m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS));
+ if (!m_pShader)
+ {
+ ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
+ return;
+ }
+ D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
+
+ // Create blend state
+
+ D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
+ hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
+ CHECK(SUCCEEDED(hr), "create xfb encode blend state");
+ D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
+
+ // Create depth state
+
+ D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
+ dsd.DepthEnable = FALSE;
+ hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
+ CHECK(SUCCEEDED(hr), "create xfb encode depth state");
+ D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
+
+ // Create rasterizer state
+
+ D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
+ rd.CullMode = D3D11_CULL_NONE;
+ rd.DepthClipEnable = FALSE;
+ hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
+ CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
+ D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
+
+ // Create EFB texture sampler
+
+ D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+ // FIXME: Should we really use point sampling here?
+ sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
+ CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
+ D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
+}
+
+void XFBEncoder::Shutdown()
+{
+ SAFE_RELEASE(m_efbSampler);
+ SAFE_RELEASE(m_xfbEncodeRastState);
+ SAFE_RELEASE(m_xfbEncodeDepthState);
+ SAFE_RELEASE(m_xfbEncodeBlendState);
+ SAFE_RELEASE(m_pShader);
+ SAFE_RELEASE(m_quadLayout);
+ SAFE_RELEASE(m_vShader);
+ SAFE_RELEASE(m_quad);
+ SAFE_RELEASE(m_encodeParams);
+ SAFE_RELEASE(m_outStage);
+ SAFE_RELEASE(m_outRTV);
+ SAFE_RELEASE(m_out);
+}
+
+void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
+{
+ HRESULT hr;
+
+ // Reset API
+
+ g_renderer->ResetAPIState();
+
+ // Set up all the state for XFB encoding
+
+ D3D::context->PSSetShader(m_pShader, NULL, 0);
+ D3D::context->VSSetShader(m_vShader, NULL, 0);
+
+ D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
+ D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
+ D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
+ D3D::stateman->Apply();
+
+ D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
+ D3D::context->RSSetViewports(1, &vp);
+
+ D3D::context->IASetInputLayout(m_quadLayout);
+ D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ UINT stride = sizeof(QuadVertex);
+ UINT offset = 0;
+ D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset);
+
+ TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
+
+ XFBEncodeParams params = { 0 };
+ params.Width = FLOAT(width);
+ params.Height = FLOAT(height);
+ params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetFullTargetWidth();
+ params.TexTop = FLOAT(targetRect.top) / g_renderer->GetFullTargetHeight();
+ params.TexRight = FLOAT(targetRect.right) / g_renderer->GetFullTargetWidth();
+ params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetFullTargetHeight();
+ params.Gamma = gamma;
+ D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, ¶ms, 0, 0);
+
+ D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams);
+
+ D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL);
+
+ ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV();
+
+ D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams);
+ D3D::context->PSSetShaderResources(0, 1, &pEFB);
+ D3D::context->PSSetSamplers(0, 1, &m_efbSampler);
+
+ // Encode!
+
+ D3D::context->Draw(4, 0);
+
+ // Copy to staging buffer
+
+ 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);
+
+ // Clean up state
+
+ IUnknown* nullDummy = NULL;
+
+ D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy);
+ D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy);
+ D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
+
+ D3D::context->OMSetRenderTargets(0, NULL, NULL);
+
+ D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
+
+ D3D::stateman->PopRasterizerState();
+ D3D::stateman->PopDepthState();
+ D3D::stateman->PopBlendState();
+
+ D3D::context->PSSetShader(NULL, NULL, 0);
+ D3D::context->VSSetShader(NULL, NULL, 0);
+
+ // Transfer staging buffer to GameCube/Wii RAM
+
+ D3D11_MAPPED_SUBRESOURCE map = { 0 };
+ hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
+ CHECK(SUCCEEDED(hr), "map staging buffer");
+
+ u8* src = (u8*)map.pData;
+ for (unsigned int y = 0; y < height; ++y)
+ {
+ memcpy(dst, src, 2*width);
+ dst += bpmem.copyMipMapStrideChannels*32;
+ src += map.RowPitch;
+ }
+
+ D3D::context->Unmap(m_outStage, 0);
+
+ // Restore API
+
+ g_renderer->RestoreAPIState();
+ D3D::context->OMSetRenderTargets(1,
+ &FramebufferManager::GetEFBColorTexture()->GetRTV(),
+ FramebufferManager::GetEFBDepthTexture()->GetDSV());
+}
+
+}
diff --git a/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h b/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h
index dba1fd20e9..000c833dbf 100644
--- a/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h
+++ b/Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h
@@ -1,68 +1,68 @@
-// 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 _XFBENCODER_H
-#define _XFBENCODER_H
-
-#include "VideoCommon.h"
-
-struct ID3D11Texture2D;
-struct ID3D11RenderTargetView;
-struct ID3D11Buffer;
-struct ID3D11VertexShader;
-struct ID3D11PixelShader;
-struct ID3D11InputLayout;
-struct ID3D11BlendState;
-struct ID3D11DepthStencilState;
-struct ID3D11RasterizerState;
-struct ID3D11SamplerState;
-
-namespace DX11
-{
-
-class XFBEncoder
-{
-
-public:
-
- XFBEncoder();
-
- void Init();
- void Shutdown();
-
- void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
-
-private:
-
- ID3D11Texture2D* m_out;
- ID3D11RenderTargetView* m_outRTV;
- ID3D11Texture2D* m_outStage;
- ID3D11Buffer* m_encodeParams;
- ID3D11Buffer* m_quad;
- ID3D11VertexShader* m_vShader;
- ID3D11InputLayout* m_quadLayout;
- ID3D11PixelShader* m_pShader;
- ID3D11BlendState* m_xfbEncodeBlendState;
- ID3D11DepthStencilState* m_xfbEncodeDepthState;
- ID3D11RasterizerState* m_xfbEncodeRastState;
- ID3D11SamplerState* m_efbSampler;
-
-};
-
-}
-
-#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 _XFBENCODER_H
+#define _XFBENCODER_H
+
+#include "VideoCommon.h"
+
+struct ID3D11Texture2D;
+struct ID3D11RenderTargetView;
+struct ID3D11Buffer;
+struct ID3D11VertexShader;
+struct ID3D11PixelShader;
+struct ID3D11InputLayout;
+struct ID3D11BlendState;
+struct ID3D11DepthStencilState;
+struct ID3D11RasterizerState;
+struct ID3D11SamplerState;
+
+namespace DX11
+{
+
+class XFBEncoder
+{
+
+public:
+
+ XFBEncoder();
+
+ void Init();
+ void Shutdown();
+
+ void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
+
+private:
+
+ ID3D11Texture2D* m_out;
+ ID3D11RenderTargetView* m_outRTV;
+ ID3D11Texture2D* m_outStage;
+ ID3D11Buffer* m_encodeParams;
+ ID3D11Buffer* m_quad;
+ ID3D11VertexShader* m_vShader;
+ ID3D11InputLayout* m_quadLayout;
+ ID3D11PixelShader* m_pShader;
+ ID3D11BlendState* m_xfbEncodeBlendState;
+ ID3D11DepthStencilState* m_xfbEncodeDepthState;
+ ID3D11RasterizerState* m_xfbEncodeRastState;
+ ID3D11SamplerState* m_efbSampler;
+
+};
+
+}
+
+#endif