DX11: Support thick lines and large points with geometry shaders. Lines still aren't drawn with correct thickness, see Twilight Princess map. But the map corners are drawn with correct shadow "blobs" for the first time!
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7340 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
8fedc3db38
commit
7c536b8f15
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -197,9 +197,11 @@
|
|||
<ClCompile Include="Src\D3DUtil.cpp" />
|
||||
<ClCompile Include="Src\FramebufferManager.cpp" />
|
||||
<ClCompile Include="Src\GfxState.cpp" />
|
||||
<ClCompile Include="Src\LineGeometryShader.cpp" />
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp" />
|
||||
<ClCompile Include="Src\PointGeometryShader.cpp" />
|
||||
<ClCompile Include="Src\PSTextureEncoder.cpp" />
|
||||
<ClCompile Include="Src\Render.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
|
@ -225,8 +227,10 @@
|
|||
<ClInclude Include="Src\FramebufferManager.h" />
|
||||
<ClInclude Include="Src\GfxState.h" />
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\LineGeometryShader.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\PixelShaderCache.h" />
|
||||
<ClInclude Include="Src\PointGeometryShader.h" />
|
||||
<ClInclude Include="Src\PSTextureEncoder.h" />
|
||||
<ClInclude Include="Src\Render.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
|
|
|
@ -51,6 +51,12 @@
|
|||
<ClCompile Include="Src\Television.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\LineGeometryShader.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PointGeometryShader.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
|
@ -105,6 +111,12 @@
|
|||
<ClInclude Include="Src\Television.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\LineGeometryShader.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PointGeometryShader.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D">
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -64,6 +64,7 @@ unsigned int GetBackBufferWidth();
|
|||
unsigned int GetBackBufferHeight();
|
||||
D3DTexture2D* &GetBackBuffer();
|
||||
const char* PixelShaderVersionString();
|
||||
const char* GeometryShaderVersionString();
|
||||
const char* VertexShaderVersionString();
|
||||
bool BGRATexturesSupported();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,452 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "LineGeometryShader.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union LineGSParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[16]; // Pad to the next multiple of 16 bytes
|
||||
};
|
||||
|
||||
static const char LINE_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu line geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match LineGSParams above
|
||||
"{\n"
|
||||
"float LineWidth;\n"
|
||||
"float TexOffset;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
// Pretend input[0] is on the bottom and input[1] is on top.
|
||||
// We generate vertices to the left and right.
|
||||
|
||||
// Correct w coordinate so screen-space math will work
|
||||
"VS_OUTPUT l0 = input[0];\n"
|
||||
"l0.pos /= l0.pos.w;\n"
|
||||
"VS_OUTPUT r0 = l0;\n"
|
||||
"VS_OUTPUT l1 = input[1];\n"
|
||||
"l1.pos /= l1.pos.w;\n"
|
||||
"VS_OUTPUT r1 = l1;\n"
|
||||
|
||||
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||
// use the correct line caps. Instead, the line caps are vertical or
|
||||
// horizontal depending the slope of the line.
|
||||
|
||||
"float2 offset;\n"
|
||||
"float2 to = input[1].pos.xy - input[0].pos.xy;\n"
|
||||
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
|
||||
"if (abs(to.y) > abs(to.x)) {\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp Params.LineWidth/2 from [0..640] to [-1..1]
|
||||
"offset = float2(Params.LineWidth/640, 0);\n"
|
||||
"} else {\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp Params.LineWidth/2 from [0..528] to [1..-1]
|
||||
"offset = float2(0, -Params.LineWidth/528);\n"
|
||||
"}\n"
|
||||
|
||||
"l0.pos.xy -= offset;\n"
|
||||
"r0.pos.xy += offset;\n"
|
||||
"l1.pos.xy -= offset;\n"
|
||||
"r1.pos.xy += offset;\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"r0.tex0.x += Params.TexOffset;\n"
|
||||
"r1.tex0.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"r0.tex1.x += Params.TexOffset;\n"
|
||||
"r1.tex1.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"r0.tex2.x += Params.TexOffset;\n"
|
||||
"r1.tex2.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"r0.tex3.x += Params.TexOffset;\n"
|
||||
"r1.tex3.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"r0.tex4.x += Params.TexOffset;\n"
|
||||
"r1.tex4.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"r0.tex5.x += Params.TexOffset;\n"
|
||||
"r1.tex5.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"r0.tex6.x += Params.TexOffset;\n"
|
||||
"r1.tex6.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"r0.tex7.x += Params.TexOffset;\n"
|
||||
"r1.tex7.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(l0);\n"
|
||||
"outStream.Append(r0);\n"
|
||||
"outStream.Append(l1);\n"
|
||||
"outStream.Append(r1);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
LineGeometryShader::LineGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void LineGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void LineGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool LineGeometryShader::SetShader(u32 components, float lineWidth, float texOffset)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char code[16384];
|
||||
char* p = code;
|
||||
p = GenerateVSOutputStruct(p, components, API_D3D11);
|
||||
p += sprintf(p, "\n%s", LINE_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStr;
|
||||
numTexCoordsStr << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
LineGSParams params = { 0 };
|
||||
params.LineWidth = lineWidth;
|
||||
params.TexOffset = texOffset;
|
||||
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, ¶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 <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union LineGSParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[16]; // Pad to the next multiple of 16 bytes
|
||||
};
|
||||
|
||||
static const char LINE_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu line geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match LineGSParams above
|
||||
"{\n"
|
||||
"float LineWidth;\n"
|
||||
"float TexOffset;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
// Pretend input[0] is on the bottom and input[1] is on top.
|
||||
// We generate vertices to the left and right.
|
||||
|
||||
// Correct w coordinate so screen-space math will work
|
||||
"VS_OUTPUT l0 = input[0];\n"
|
||||
"l0.pos /= l0.pos.w;\n"
|
||||
"VS_OUTPUT r0 = l0;\n"
|
||||
"VS_OUTPUT l1 = input[1];\n"
|
||||
"l1.pos /= l1.pos.w;\n"
|
||||
"VS_OUTPUT r1 = l1;\n"
|
||||
|
||||
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||
// use the correct line caps. Instead, the line caps are vertical or
|
||||
// horizontal depending the slope of the line.
|
||||
|
||||
"float2 offset;\n"
|
||||
"float2 to = input[1].pos.xy - input[0].pos.xy;\n"
|
||||
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
|
||||
"if (abs(to.y) > abs(to.x)) {\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp Params.LineWidth/2 from [0..640] to [-1..1]
|
||||
"offset = float2(Params.LineWidth/640, 0);\n"
|
||||
"} else {\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp Params.LineWidth/2 from [0..528] to [1..-1]
|
||||
"offset = float2(0, -Params.LineWidth/528);\n"
|
||||
"}\n"
|
||||
|
||||
"l0.pos.xy -= offset;\n"
|
||||
"r0.pos.xy += offset;\n"
|
||||
"l1.pos.xy -= offset;\n"
|
||||
"r1.pos.xy += offset;\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"r0.tex0.x += Params.TexOffset;\n"
|
||||
"r1.tex0.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"r0.tex1.x += Params.TexOffset;\n"
|
||||
"r1.tex1.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"r0.tex2.x += Params.TexOffset;\n"
|
||||
"r1.tex2.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"r0.tex3.x += Params.TexOffset;\n"
|
||||
"r1.tex3.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"r0.tex4.x += Params.TexOffset;\n"
|
||||
"r1.tex4.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"r0.tex5.x += Params.TexOffset;\n"
|
||||
"r1.tex5.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"r0.tex6.x += Params.TexOffset;\n"
|
||||
"r1.tex6.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"r0.tex7.x += Params.TexOffset;\n"
|
||||
"r1.tex7.x += Params.TexOffset;\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(l0);\n"
|
||||
"outStream.Append(r0);\n"
|
||||
"outStream.Append(l1);\n"
|
||||
"outStream.Append(r1);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
LineGeometryShader::LineGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void LineGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void LineGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool LineGeometryShader::SetShader(u32 components, float lineWidth, float texOffset)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char code[16384];
|
||||
char* p = code;
|
||||
p = GenerateVSOutputStruct(p, components, API_D3D11);
|
||||
p += sprintf(p, "\n%s", LINE_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStr;
|
||||
numTexCoordsStr << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
LineGSParams params = { 0 };
|
||||
params.LineWidth = lineWidth;
|
||||
params.TexOffset = texOffset;
|
||||
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, ¶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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _LINEGEOMETRYSHADER_H
|
||||
#define _LINEGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of line geometry shaders, one for each
|
||||
// vertex format.
|
||||
class LineGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LineGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float lineWidth, float texOffset);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _LINEGEOMETRYSHADER_H
|
||||
#define _LINEGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of line geometry shaders, one for each
|
||||
// vertex format.
|
||||
class LineGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LineGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float lineWidth, float texOffset);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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())
|
||||
|
|
|
@ -0,0 +1,434 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "PointGeometryShader.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union PointGSParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT PointSize; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[16]; // Pad to the next multiple of 16 bytes
|
||||
};
|
||||
|
||||
static const char POINT_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu point geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match PointGSParams above
|
||||
"{\n"
|
||||
"float PointSize;\n"
|
||||
"float TexOffset;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
// Correct w coordinate so screen-space math will work
|
||||
"VS_OUTPUT ptLL = input[0];\n"
|
||||
"ptLL.pos /= ptLL.pos.w;\n"
|
||||
"VS_OUTPUT ptLR = ptLL;\n"
|
||||
"VS_OUTPUT ptUL = ptLL;\n"
|
||||
"VS_OUTPUT ptUR = ptLL;\n"
|
||||
|
||||
// Distance from center to upper right vertex
|
||||
"float2 offset = float2(Params.PointSize/640, -Params.PointSize/528);\n"
|
||||
|
||||
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
|
||||
"ptLR.pos.xy += float2(1,-1) * offset;\n"
|
||||
"ptUL.pos.xy += float2(-1,1) * offset;\n"
|
||||
"ptUR.pos.xy += offset;\n"
|
||||
|
||||
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"ptLL.tex0.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex0.xy += texOffset;\n"
|
||||
"ptUR.tex0.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"ptLL.tex1.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex1.xy += texOffset;\n"
|
||||
"ptUR.tex1.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"ptLL.tex2.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex2.xy += texOffset;\n"
|
||||
"ptUR.tex2.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"ptLL.tex3.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex3.xy += texOffset;\n"
|
||||
"ptUR.tex3.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"ptLL.tex4.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex4.xy += texOffset;\n"
|
||||
"ptUR.tex4.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"ptLL.tex5.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex5.xy += texOffset;\n"
|
||||
"ptUR.tex5.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"ptLL.tex6.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex6.xy += texOffset;\n"
|
||||
"ptUR.tex6.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"ptLL.tex7.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex7.xy += texOffset;\n"
|
||||
"ptUR.tex7.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(ptLL);\n"
|
||||
"outStream.Append(ptLR);\n"
|
||||
"outStream.Append(ptUL);\n"
|
||||
"outStream.Append(ptUR);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
PointGeometryShader::PointGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void PointGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void PointGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool PointGeometryShader::SetShader(u32 components, float pointSize, float texOffset)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char code[16384];
|
||||
char* p = code;
|
||||
p = GenerateVSOutputStruct(p, components, API_D3D11);
|
||||
p += sprintf(p, "\n%s", POINT_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStr;
|
||||
numTexCoordsStr << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
PointGSParams params = { 0 };
|
||||
params.PointSize = pointSize;
|
||||
params.TexOffset = texOffset;
|
||||
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, ¶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 <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union PointGSParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT PointSize; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[16]; // Pad to the next multiple of 16 bytes
|
||||
};
|
||||
|
||||
static const char POINT_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu point geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match PointGSParams above
|
||||
"{\n"
|
||||
"float PointSize;\n"
|
||||
"float TexOffset;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
// Correct w coordinate so screen-space math will work
|
||||
"VS_OUTPUT ptLL = input[0];\n"
|
||||
"ptLL.pos /= ptLL.pos.w;\n"
|
||||
"VS_OUTPUT ptLR = ptLL;\n"
|
||||
"VS_OUTPUT ptUL = ptLL;\n"
|
||||
"VS_OUTPUT ptUR = ptLL;\n"
|
||||
|
||||
// Distance from center to upper right vertex
|
||||
"float2 offset = float2(Params.PointSize/640, -Params.PointSize/528);\n"
|
||||
|
||||
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
|
||||
"ptLR.pos.xy += float2(1,-1) * offset;\n"
|
||||
"ptUL.pos.xy += float2(-1,1) * offset;\n"
|
||||
"ptUR.pos.xy += offset;\n"
|
||||
|
||||
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"ptLL.tex0.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex0.xy += texOffset;\n"
|
||||
"ptUR.tex0.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"ptLL.tex1.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex1.xy += texOffset;\n"
|
||||
"ptUR.tex1.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"ptLL.tex2.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex2.xy += texOffset;\n"
|
||||
"ptUR.tex2.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"ptLL.tex3.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex3.xy += texOffset;\n"
|
||||
"ptUR.tex3.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"ptLL.tex4.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex4.xy += texOffset;\n"
|
||||
"ptUR.tex4.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"ptLL.tex5.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex5.xy += texOffset;\n"
|
||||
"ptUR.tex5.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"ptLL.tex6.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex6.xy += texOffset;\n"
|
||||
"ptUR.tex6.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"ptLL.tex7.xy += float2(0,1) * texOffset;\n"
|
||||
"ptLR.tex7.xy += texOffset;\n"
|
||||
"ptUR.tex7.xy += float2(1,0) * texOffset;\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(ptLL);\n"
|
||||
"outStream.Append(ptLR);\n"
|
||||
"outStream.Append(ptUL);\n"
|
||||
"outStream.Append(ptUR);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
PointGeometryShader::PointGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void PointGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void PointGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool PointGeometryShader::SetShader(u32 components, float pointSize, float texOffset)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char code[16384];
|
||||
char* p = code;
|
||||
p = GenerateVSOutputStruct(p, components, API_D3D11);
|
||||
p += sprintf(p, "\n%s", POINT_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStr;
|
||||
numTexCoordsStr << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.str().c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
PointGSParams params = { 0 };
|
||||
params.PointSize = pointSize;
|
||||
params.TexOffset = texOffset;
|
||||
D3D::context->UpdateSubresource(m_paramsBuffer, 0, NULL, ¶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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _POINTGEOMETRYSHADER_H
|
||||
#define _POINTGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of point geometry shaders, one for each
|
||||
// vertex format.
|
||||
class PointGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
PointGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float pointSize, float texOffset);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _POINTGEOMETRYSHADER_H
|
||||
#define _POINTGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of point geometry shaders, one for each
|
||||
// vertex format.
|
||||
class PointGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
PointGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float pointSize, float texOffset);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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
|
||||
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
|
||||
|
||||
"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<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
|
||||
MathUtil::Rectangle<float> 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
|
||||
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
|
||||
|
||||
"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<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
|
||||
MathUtil::Rectangle<float> 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.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
|
||||
"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
|
||||
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
|
||||
"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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue