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