summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
diff options
context:
space:
mode:
authorRyan Houdek <Sonicadvance1@gmail.com>2013-12-31 19:18:30 -0600
committerRyan Houdek <Sonicadvance1@gmail.com>2013-12-31 19:18:30 -0600
commit1118226f270d2b44d10dd3cebd9f89fd38042680 (patch)
tree9dd80995633c70581443d40f58d6ac35837e0bd4 /Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
parent8d8b0fc884367bc4d433d698a790ef5badee6957 (diff)
parent16824d5fd17b43b156706bf02a8063b389604766 (diff)
Merge branch 'master' into buffer_storage
Diffstat (limited to 'Source/Core/VideoBackends/D3D/PointGeometryShader.cpp')
-rw-r--r--Source/Core/VideoBackends/D3D/PointGeometryShader.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
new file mode 100644
index 0000000000..30e4434521
--- /dev/null
+++ b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp
@@ -0,0 +1,232 @@
+// Copyright 2013 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "PointGeometryShader.h"
+
+#include <sstream>
+#include "D3DBase.h"
+#include "D3DShader.h"
+#include "VertexShaderGen.h"
+
+namespace DX11
+{
+
+struct PointGSParams
+{
+ FLOAT PointSize; // In units of 1/6 of an EFB pixel
+ FLOAT TexOffset;
+ FLOAT VpWidth; // Width and height of viewport in EFB pixels
+ FLOAT VpHeight;
+ FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off)
+};
+
+union PointGSParams_Padded
+{
+ PointGSParams params;
+ // Constant buffers must be a multiple of 16 bytes in size.
+ u8 pad[(sizeof(PointGSParams) + 15) & ~15];
+};
+
+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"
+ "float VpWidth;\n"
+ "float VpHeight;\n"
+ "float TexOffsetEnable[8];\n"
+ "} Params;\n"
+"}\n"
+
+"[maxvertexcount(4)]\n"
+"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
+"{\n"
+ "VS_OUTPUT ptLL = input[0];\n"
+ "VS_OUTPUT ptLR = ptLL;\n"
+ "VS_OUTPUT ptUL = ptLL;\n"
+ "VS_OUTPUT ptUR = ptLL;\n"
+
+ // Offset from center to upper right vertex
+ // Lerp Params.PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1]
+ "float2 offset = float2(Params.PointSize/Params.VpWidth, -Params.PointSize/Params.VpHeight) * input[0].pos.w;\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
+ // FIXME: The game may be able to enable TexOffset for some coords and
+ // disable for others, but where is that information stored?
+"#if NUM_TEXCOORDS >= 1\n"
+ "ptLL.tex0.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[0];\n"
+ "ptLR.tex0.xy += texOffset * Params.TexOffsetEnable[0];\n"
+ "ptUR.tex0.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[0];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 2\n"
+ "ptLL.tex1.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[1];\n"
+ "ptLR.tex1.xy += texOffset * Params.TexOffsetEnable[1];\n"
+ "ptUR.tex1.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[1];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 3\n"
+ "ptLL.tex2.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[2];\n"
+ "ptLR.tex2.xy += texOffset * Params.TexOffsetEnable[2];\n"
+ "ptUR.tex2.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[2];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 4\n"
+ "ptLL.tex3.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[3];\n"
+ "ptLR.tex3.xy += texOffset * Params.TexOffsetEnable[3];\n"
+ "ptUR.tex3.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[3];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 5\n"
+ "ptLL.tex4.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[4];\n"
+ "ptLR.tex4.xy += texOffset * Params.TexOffsetEnable[4];\n"
+ "ptUR.tex4.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[4];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 6\n"
+ "ptLL.tex5.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[5];\n"
+ "ptLR.tex5.xy += texOffset * Params.TexOffsetEnable[5];\n"
+ "ptUR.tex5.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[5];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 7\n"
+ "ptLL.tex6.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[6];\n"
+ "ptLR.tex6.xy += texOffset * Params.TexOffsetEnable[6];\n"
+ "ptUR.tex6.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[6];\n"
+"#endif\n"
+"#if NUM_TEXCOORDS >= 8\n"
+ "ptLL.tex7.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[7];\n"
+ "ptLR.tex7.xy += texOffset * Params.TexOffsetEnable[7];\n"
+ "ptUR.tex7.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[7];\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_Padded),
+ D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
+ 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, float vpWidth, float vpHeight, const bool* texOffsetEnable)
+{
+ 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 buffer[16384];
+ ShaderCode code;
+ code.SetBuffer(buffer);
+ GenerateVSOutputStructForGS(code, components, API_D3D);
+ code.Write("\n%s", POINT_GS_COMMON);
+
+ std::stringstream numTexCoordsStream;
+ numTexCoordsStream << xfregs.numTexGen.numTexGens;
+
+ INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
+ components, xfregs.numTexGen.numTexGens);
+
+ const std::string& numTexCoordsStr = numTexCoordsStream.str();
+ D3D_SHADER_MACRO macros[] = {
+ { "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
+ { NULL, NULL }
+ };
+ ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), 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)
+ {
+ D3D11_MAPPED_SUBRESOURCE map;
+ HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
+ if (SUCCEEDED(hr))
+ {
+ PointGSParams* params = (PointGSParams*)map.pData;
+ params->PointSize = pointSize;
+
+ params->TexOffset = texOffset;
+ params->VpWidth = vpWidth;
+ params->VpHeight = vpHeight;
+ for (int i = 0; i < 8; ++i)
+ params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f;
+
+ D3D::context->Unmap(m_paramsBuffer, 0);
+ }
+ else
+ ERROR_LOG(VIDEO, "Failed to map point gs params buffer");
+
+ DEBUG_LOG(VIDEO, "Point params: size %f, texOffset %f, vpWidth %f, vpHeight %f",
+ pointSize, texOffset, vpWidth, vpHeight);
+
+ D3D::context->GSSetShader(shaderIt->second, NULL, 0);
+ D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
+
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+}