From 7c536b8f15f8e6652c060a9295ff952357092d67 Mon Sep 17 00:00:00 2001 From: Nolan Check Date: Mon, 14 Mar 2011 09:38:29 +0000 Subject: [PATCH] DX11: Support thick lines and large points with geometry shaders. Lines still aren't drawn with correct thickness, see Twilight Princess map. But the map corners are drawn with correct shadow "blobs" for the first time! git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7340 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Core/VideoCommon/Src/VertexShaderGen.cpp | 57 +- Source/Core/VideoCommon/Src/VertexShaderGen.h | 1 + .../Plugin_VideoDX11/Plugin_VideoDX11.vcxproj | 4 + .../Plugin_VideoDX11.vcxproj.filters | 12 + .../Plugins/Plugin_VideoDX11/Src/D3DBase.cpp | 8 +- Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h | 1 + .../Plugin_VideoDX11/Src/D3DShader.cpp | 75 +- .../Plugins/Plugin_VideoDX11/Src/D3DShader.h | 34 +- .../Src/LineGeometryShader.cpp | 452 ++++++++++ .../Plugin_VideoDX11/Src/LineGeometryShader.h | 114 +++ .../Plugin_VideoDX11/Src/PSTextureEncoder.cpp | 4 +- .../Src/PointGeometryShader.cpp | 434 ++++++++++ .../Src/PointGeometryShader.h | 114 +++ .../Plugin_VideoDX11/Src/Television.cpp | 308 +++---- .../Plugins/Plugin_VideoDX11/Src/Television.h | 130 +-- .../Plugin_VideoDX11/Src/VertexManager.cpp | 38 +- .../Plugin_VideoDX11/Src/VertexManager.h | 6 +- .../Plugin_VideoDX11/Src/XFBEncoder.cpp | 774 +++++++++--------- .../Plugins/Plugin_VideoDX11/Src/XFBEncoder.h | 136 +-- 19 files changed, 1982 insertions(+), 720 deletions(-) create mode 100644 Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.cpp create mode 100644 Source/Plugins/Plugin_VideoDX11/Src/LineGeometryShader.h create mode 100644 Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.cpp create mode 100644 Source/Plugins/Plugin_VideoDX11/Src/PointGeometryShader.h 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