mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #1706 from Armada651/line-width
VideoCommon: Merge LineGeometryShader into GeometryShaderGen.
This commit is contained in:
@ -62,11 +62,6 @@ void SetScissor()
|
||||
g_renderer->SetScissorRect(rc);
|
||||
}
|
||||
|
||||
void SetLineWidth()
|
||||
{
|
||||
g_renderer->SetLineWidth();
|
||||
}
|
||||
|
||||
void SetDepthMode()
|
||||
{
|
||||
g_renderer->SetDepthMode();
|
||||
|
@ -18,7 +18,6 @@ namespace BPFunctions
|
||||
void FlushPipeline();
|
||||
void SetGenerationMode();
|
||||
void SetScissor();
|
||||
void SetLineWidth();
|
||||
void SetDepthMode();
|
||||
void SetBlendMode();
|
||||
void SetDitherMode();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "VideoCommon/BPFunctions.h"
|
||||
#include "VideoCommon/BPStructs.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PerfQueryBase.h"
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
@ -125,9 +126,10 @@ static void BPWritten(const BPCmd& bp)
|
||||
case BPMEM_SCISSOROFFSET: // Scissor Offset
|
||||
SetScissor();
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
GeometryShaderManager::SetViewportChanged();
|
||||
return;
|
||||
case BPMEM_LINEPTWIDTH: // Line Width
|
||||
SetLineWidth();
|
||||
GeometryShaderManager::SetLinePtWidthChanged();
|
||||
return;
|
||||
case BPMEM_ZMODE: // Depth Control
|
||||
PRIM_LOG("zmode: test=%d, func=%d, upd=%d", (int)bpmem.zmode.testenable,
|
||||
@ -570,7 +572,10 @@ static void BPWritten(const BPCmd& bp)
|
||||
case BPMEM_SU_SSIZE+14:
|
||||
case BPMEM_SU_TSIZE+14:
|
||||
if (bp.changes)
|
||||
{
|
||||
PixelShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1);
|
||||
GeometryShaderManager::SetTexCoordChanged((bp.address - BPMEM_SU_SSIZE) >> 1);
|
||||
}
|
||||
return;
|
||||
// ------------------------
|
||||
// BPMEM_TX_SETMODE0 - (Texture lookup and filtering mode) LOD/BIAS Clamp, MaxAnsio, LODBIAS, DiagLoad, Min Filter, Mag Filter, Wrap T, S
|
||||
@ -1366,7 +1371,6 @@ void BPReload()
|
||||
// note that PixelShaderManager is already covered since it has its own DoState.
|
||||
SetGenerationMode();
|
||||
SetScissor();
|
||||
SetLineWidth();
|
||||
SetDepthMode();
|
||||
SetLogicOpMode();
|
||||
SetDitherMode();
|
||||
|
@ -10,6 +10,7 @@ set(SRCS BoundingBox.cpp
|
||||
FPSCounter.cpp
|
||||
FramebufferManagerBase.cpp
|
||||
GeometryShaderGen.cpp
|
||||
GeometryShaderManager.cpp
|
||||
HiresTextures.cpp
|
||||
ImageWrite.cpp
|
||||
IndexGenerator.cpp
|
||||
|
@ -43,6 +43,11 @@ struct VertexShaderConstants
|
||||
float4 normalmatrices[32];
|
||||
float4 posttransformmatrices[64];
|
||||
float4 pixelcentercorrection;
|
||||
float4 stereoparams;
|
||||
};
|
||||
|
||||
struct GeometryShaderConstants
|
||||
{
|
||||
float4 stereoparams;
|
||||
float4 lineptparams;
|
||||
int4 texoffset;
|
||||
};
|
||||
|
@ -4,15 +4,33 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
#include "VideoCommon/LightingShaderGen.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static char text[16384];
|
||||
|
||||
static const char* primitives_ogl[] =
|
||||
{
|
||||
"points",
|
||||
"lines",
|
||||
"triangles"
|
||||
};
|
||||
|
||||
static const char* primitives_d3d[] =
|
||||
{
|
||||
"point",
|
||||
"line",
|
||||
"triangle"
|
||||
};
|
||||
|
||||
template<class T> static inline void EmitVertex(T& out, const char* vertex, API_TYPE ApiType);
|
||||
|
||||
template<class T>
|
||||
static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiType)
|
||||
static inline void GenerateGeometryShader(T& out, u32 primitive_type, API_TYPE ApiType)
|
||||
{
|
||||
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
|
||||
geometry_shader_uid_data dummy_data;
|
||||
@ -26,93 +44,154 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
|
||||
if (is_writing_shadercode)
|
||||
text[sizeof(text) - 1] = 0x7C; // canary
|
||||
|
||||
out.Write("//Geometry Shader for 3D stereoscopy\n");
|
||||
uid_data->primitive_type = primitive_type;
|
||||
const unsigned int vertex_in = primitive_type + 1;
|
||||
const unsigned int vertex_out = primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4;
|
||||
|
||||
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
|
||||
if (ApiType == API_OPENGL)
|
||||
{
|
||||
// Insert layout parameters
|
||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
out.Write("layout(triangles, invocations = %d) in;\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
|
||||
{
|
||||
out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type], g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
|
||||
out.Write("layout(triangle_strip, max_vertices = %d) out;\n", vertex_out);
|
||||
}
|
||||
else
|
||||
out.Write("layout(triangles) in;\n");
|
||||
out.Write("layout(triangle_strip, max_vertices = %d) out;\n", g_ActiveConfig.backend_info.bSupportsGSInstancing ? 3 : 6);
|
||||
{
|
||||
out.Write("layout(%s) in;\n", primitives_ogl[primitive_type]);
|
||||
out.Write("layout(triangle_strip, max_vertices = %d) out;\n", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out);
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("%s", s_lighting_struct);
|
||||
|
||||
// uniforms
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : "");
|
||||
out.Write("layout(std140%s) uniform GSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 3" : "");
|
||||
else
|
||||
out.Write("cbuffer VSBlock {\n");
|
||||
out.Write(s_shader_uniforms);
|
||||
out.Write("};\n");
|
||||
out.Write("cbuffer GSBlock {\n");
|
||||
out.Write(
|
||||
"\tfloat4 " I_STEREOPARAMS";\n"
|
||||
"\tfloat4 " I_LINEPTPARAMS";\n"
|
||||
"\tint4 " I_TEXOFFSET";\n"
|
||||
"};\n");
|
||||
|
||||
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
|
||||
uid_data->numTexGens = bpmem.genMode.numtexgens;
|
||||
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
|
||||
|
||||
GenerateVSOutputStruct<T>(out, ApiType);
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
{
|
||||
out.Write("centroid in VS_OUTPUT o[3];\n");
|
||||
out.Write("centroid out VS_OUTPUT vs;\n");
|
||||
out.Write("flat out int layer;\n");
|
||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
out.Write("#define InstanceID gl_InvocationID\n");
|
||||
|
||||
out.Write("in VertexData {\n");
|
||||
out.Write("\tcentroid VS_OUTPUT o;\n");
|
||||
out.Write("} vs[%d];\n", vertex_in);
|
||||
|
||||
out.Write("out VertexData {\n");
|
||||
out.Write("\tcentroid VS_OUTPUT o;\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
out.Write("\tflat int layer;\n");
|
||||
|
||||
out.Write("} ps;\n");
|
||||
|
||||
out.Write("void main()\n{\n");
|
||||
}
|
||||
else // D3D
|
||||
{
|
||||
out.Write("struct GS_OUTPUT {\n");
|
||||
out.Write("\tVS_OUTPUT vs;\n");
|
||||
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
|
||||
out.Write("struct VertexData {\n");
|
||||
out.Write("\tVS_OUTPUT o;\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
|
||||
|
||||
out.Write("};\n");
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
{
|
||||
out.Write("[maxvertexcount(3)]\n[instance(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
|
||||
out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream<GS_OUTPUT> Output, in uint InstanceID : SV_GSInstanceID)\n{\n");
|
||||
out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
|
||||
out.Write("void main(%s VS_OUTPUT o[%d], inout TriangleStream<VertexData> output, in uint InstanceID : SV_GSInstanceID)\n{\n", primitives_d3d[primitive_type], vertex_in);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("[maxvertexcount(6)]\n");
|
||||
out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream<GS_OUTPUT> Output)\n{\n");
|
||||
out.Write("[maxvertexcount(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? vertex_out * 2 : vertex_out);
|
||||
out.Write("void main(%s VS_OUTPUT o[%d], inout TriangleStream<VertexData> output)\n{\n", primitives_d3d[primitive_type], vertex_in);
|
||||
}
|
||||
|
||||
out.Write("\tGS_OUTPUT gs;\n");
|
||||
out.Write("\tVertexData ps;\n");
|
||||
}
|
||||
|
||||
out.Write("\tVS_OUTPUT f;\n");
|
||||
|
||||
// If the GPU supports invocation we don't need a for loop and can simply use the
|
||||
// invocation identifier to determine which layer we're rendering.
|
||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
if (primitive_type == PRIMITIVE_LINES)
|
||||
{
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tint eye = gl_InvocationID;\n");
|
||||
{
|
||||
out.Write("\tVS_OUTPUT start = vs[0].o;\n");
|
||||
out.Write("\tVS_OUTPUT end = vs[1].o;\n");
|
||||
}
|
||||
else
|
||||
out.Write("\tint eye = InstanceID;\n");
|
||||
{
|
||||
out.Write("\tVS_OUTPUT start = o[0];\n");
|
||||
out.Write("\tVS_OUTPUT end = o[1];\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.
|
||||
out.Write(
|
||||
"\tfloat2 offset;\n"
|
||||
"\tfloat2 to = abs(end.pos.xy - start.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.
|
||||
"\tif (" I_LINEPTPARAMS".y * to.y > " I_LINEPTPARAMS".x * to.x) {\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp LineWidth/2 from [0..VpWidth] to [-1..1]
|
||||
"\t\toffset = float2(" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".x, 0);\n"
|
||||
"\t} else {\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp LineWidth/2 from [0..VpHeight] to [1..-1]
|
||||
"\t\toffset = float2(0, -" I_LINEPTPARAMS".z / " I_LINEPTPARAMS".y);\n"
|
||||
"\t}\n");
|
||||
}
|
||||
else
|
||||
out.Write("\tfor (int eye = 0; eye < %d; ++eye) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
|
||||
|
||||
out.Write("\tfor (int i = 0; i < 3; ++i) {\n");
|
||||
|
||||
// Select the output layer
|
||||
if (ApiType == API_OPENGL)
|
||||
else if (primitive_type == PRIMITIVE_POINTS)
|
||||
{
|
||||
out.Write("\t\tgl_Layer = eye;\n");
|
||||
out.Write("\t\tlayer = eye;\n");
|
||||
}
|
||||
else
|
||||
out.Write("\t\tgs.layer = eye;\n");
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tVS_OUTPUT center = vs[0].o;\n");
|
||||
else
|
||||
out.Write("\tVS_OUTPUT center = o[0];\n");
|
||||
|
||||
out.Write("\t\tf = o[i];\n");
|
||||
out.Write("\t\tfloat4 pos = o[i].pos;\n");
|
||||
// Offset from center to upper right vertex
|
||||
// Lerp PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1]
|
||||
out.Write("\tfloat2 offset = float2(" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".x, -" I_LINEPTPARAMS".w / " I_LINEPTPARAMS".y) * center.pos.w;\n");
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
{
|
||||
// If the GPU supports invocation we don't need a for loop and can simply use the
|
||||
// invocation identifier to determine which layer we're rendering.
|
||||
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
out.Write("\tint eye = InstanceID;\n");
|
||||
else
|
||||
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n");
|
||||
}
|
||||
|
||||
out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in);
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tVS_OUTPUT f = vs[i].o;\n");
|
||||
else
|
||||
out.Write("\tVS_OUTPUT f = o[i];\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
{
|
||||
// Select the output layer
|
||||
out.Write("\tps.layer = eye;\n");
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tgl_Layer = eye;\n");
|
||||
|
||||
// For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional
|
||||
// to the depth of the vertex. We retrieve the depth value from the w-component of the projected
|
||||
// vertex which contains the negated z-component of the original vertex.
|
||||
@ -120,30 +199,74 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
|
||||
// the depth value. This results in objects at a distance smaller than the convergence
|
||||
// distance to seemingly appear in front of the screen.
|
||||
// This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide"
|
||||
out.Write("\t\tf.clipPos.x = o[i].clipPos.x + " I_STEREOPARAMS"[eye] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n");
|
||||
out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[eye] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n");
|
||||
out.Write("\tf.clipPos.x += " I_STEREOPARAMS"[eye] * (f.clipPos.w - " I_STEREOPARAMS"[2]);\n");
|
||||
out.Write("\tf.pos.x += " I_STEREOPARAMS"[eye] * (f.pos.w - " I_STEREOPARAMS"[2]);\n");
|
||||
}
|
||||
|
||||
out.Write("\t\tf.pos.x = pos.x;\n");
|
||||
if (primitive_type == PRIMITIVE_LINES)
|
||||
{
|
||||
out.Write("\tVS_OUTPUT l = f;\n"
|
||||
"\tVS_OUTPUT r = f;\n");
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\t\tgl_Position = pos;\n");
|
||||
out.Write("\tl.pos.xy -= offset * l.pos.w;\n"
|
||||
"\tr.pos.xy += offset * r.pos.w;\n");
|
||||
|
||||
out.Write("\t\t%s = f;\n", (ApiType == API_OPENGL) ? "vs" : "gs.vs");
|
||||
out.Write("\tif (" I_TEXOFFSET"[2] != 0) {\n");
|
||||
out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET"[2]);\n");
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\t\tEmitVertex();\n");
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i)
|
||||
{
|
||||
out.Write("\tif (((" I_TEXOFFSET"[0] >> %d) & 0x1) != 0)\n", i);
|
||||
out.Write("\t\tr.tex%d.x += texOffset;\n", i);
|
||||
}
|
||||
out.Write("\t}\n");
|
||||
|
||||
EmitVertex<T>(out, "l", ApiType);
|
||||
EmitVertex<T>(out, "r", ApiType);
|
||||
}
|
||||
else if (primitive_type == PRIMITIVE_POINTS)
|
||||
{
|
||||
out.Write("\tVS_OUTPUT ll = f;\n"
|
||||
"\tVS_OUTPUT lr = f;\n"
|
||||
"\tVS_OUTPUT ul = f;\n"
|
||||
"\tVS_OUTPUT ur = f;\n");
|
||||
|
||||
out.Write("\tll.pos.xy += float2(-1,-1) * offset;\n"
|
||||
"\tlr.pos.xy += float2(1,-1) * offset;\n"
|
||||
"\tul.pos.xy += float2(-1,1) * offset;\n"
|
||||
"\tur.pos.xy += offset;\n");
|
||||
|
||||
out.Write("\tif (" I_TEXOFFSET"[3] != 0) {\n");
|
||||
out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET"[3]), 1.0 / float(" I_TEXOFFSET"[3]));\n");
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i)
|
||||
{
|
||||
out.Write("\tif (((" I_TEXOFFSET"[1] >> %d) & 0x1) != 0) {\n", i);
|
||||
out.Write("\t\tll.tex%d.xy += float2(0,1) * texOffset;\n", i);
|
||||
out.Write("\t\tlr.tex%d.xy += texOffset;\n", i);
|
||||
out.Write("\t\tur.tex%d.xy += float2(1,0) * texOffset;\n", i);
|
||||
out.Write("\t}\n");
|
||||
}
|
||||
out.Write("\t}\n");
|
||||
|
||||
EmitVertex<T>(out, "ll", ApiType);
|
||||
EmitVertex<T>(out, "lr", ApiType);
|
||||
EmitVertex<T>(out, "ul", ApiType);
|
||||
EmitVertex<T>(out, "ur", ApiType);
|
||||
}
|
||||
else
|
||||
out.Write("\t\tOutput.Append(gs);\n");
|
||||
{
|
||||
EmitVertex<T>(out, "f", ApiType);
|
||||
}
|
||||
|
||||
out.Write("\t}\n");
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tEndPrimitive();\n");
|
||||
else
|
||||
out.Write("\tOutput.RestartStrip();\n");
|
||||
out.Write("\toutput.RestartStrip();\n");
|
||||
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
if (g_ActiveConfig.iStereoMode > 0 && !g_ActiveConfig.backend_info.bSupportsGSInstancing)
|
||||
out.Write("\t}\n");
|
||||
|
||||
out.Write("}\n");
|
||||
@ -155,12 +278,32 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy
|
||||
}
|
||||
}
|
||||
|
||||
void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType)
|
||||
template<class T>
|
||||
static inline void EmitVertex(T& out, const char* vertex, API_TYPE ApiType)
|
||||
{
|
||||
GenerateGeometryShader<GeometryShaderUid>(object, components, ApiType);
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tgl_Position = %s.pos;\n", vertex);
|
||||
|
||||
out.Write("\tps.o = %s;\n", vertex);
|
||||
|
||||
if (ApiType == API_OPENGL)
|
||||
out.Write("\tEmitVertex();\n");
|
||||
else
|
||||
out.Write("\toutput.Append(ps);\n");
|
||||
}
|
||||
|
||||
void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType)
|
||||
void GetGeometryShaderUid(GeometryShaderUid& object, u32 primitive_type, API_TYPE ApiType)
|
||||
{
|
||||
GenerateGeometryShader<ShaderCode>(object, components, ApiType);
|
||||
GenerateGeometryShader<GeometryShaderUid>(object, primitive_type, ApiType);
|
||||
}
|
||||
|
||||
void GenerateGeometryShaderCode(ShaderCode& object, u32 primitive_type, API_TYPE ApiType)
|
||||
{
|
||||
GenerateGeometryShader<ShaderCode>(object, primitive_type, ApiType);
|
||||
}
|
||||
|
||||
bool IsPassthroughGeometryShader(GeometryShaderUid& object)
|
||||
{
|
||||
geometry_shader_uid_data* uid_data = object.GetUidData<geometry_shader_uid_data>();
|
||||
return uid_data->primitive_type == PRIMITIVE_TRIANGLES && !uid_data->stereo;
|
||||
}
|
||||
|
@ -16,11 +16,13 @@ struct geometry_shader_uid_data
|
||||
u32 stereo : 1;
|
||||
u32 numTexGens : 4;
|
||||
u32 pixel_lighting : 1;
|
||||
u32 primitive_type : 2;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
|
||||
|
||||
void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType);
|
||||
void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType);
|
||||
void GenerateGeometryShaderCode(ShaderCode& object, u32 primitive_type, API_TYPE ApiType);
|
||||
void GetGeometryShaderUid(GeometryShaderUid& object, u32 primitive_type, API_TYPE ApiType);
|
||||
bool IsPassthroughGeometryShader(GeometryShaderUid& object);
|
||||
|
97
Source/Core/VideoCommon/GeometryShaderManager.cpp
Normal file
97
Source/Core/VideoCommon/GeometryShaderManager.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
static const int LINE_PT_TEX_OFFSETS[8] = {
|
||||
0, 16, 8, 4, 2, 1, 1, 1
|
||||
};
|
||||
|
||||
GeometryShaderConstants GeometryShaderManager::constants;
|
||||
bool GeometryShaderManager::dirty;
|
||||
|
||||
void GeometryShaderManager::Init()
|
||||
{
|
||||
memset(&constants, 0, sizeof(constants));
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
void GeometryShaderManager::Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void GeometryShaderManager::Dirty()
|
||||
{
|
||||
SetViewportChanged();
|
||||
SetProjectionChanged();
|
||||
SetLinePtWidthChanged();
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
SetTexCoordChanged(i);
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetViewportChanged()
|
||||
{
|
||||
constants.lineptparams[0] = 2.0f * xfmem.viewport.wd;
|
||||
constants.lineptparams[1] = -2.0f * xfmem.viewport.ht;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetProjectionChanged()
|
||||
{
|
||||
if (g_ActiveConfig.iStereoMode > 0 && xfmem.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
float offset = (g_ActiveConfig.iStereoSeparation / 1000.0f) * (g_ActiveConfig.iStereoSeparationPercent / 100.0f);
|
||||
constants.stereoparams[0] = (g_ActiveConfig.bStereoSwapEyes) ? offset : -offset;
|
||||
constants.stereoparams[1] = (g_ActiveConfig.bStereoSwapEyes) ? -offset : offset;
|
||||
constants.stereoparams[2] = (g_ActiveConfig.iStereoConvergence / 10.0f) * (g_ActiveConfig.iStereoConvergencePercent / 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
constants.stereoparams[0] = constants.stereoparams[1] = 0;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetLinePtWidthChanged()
|
||||
{
|
||||
constants.lineptparams[2] = bpmem.lineptwidth.linesize / 6.f;
|
||||
constants.lineptparams[3] = bpmem.lineptwidth.pointsize / 6.f;
|
||||
constants.texoffset[2] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
|
||||
constants.texoffset[3] = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::SetTexCoordChanged(u8 texmapid)
|
||||
{
|
||||
TCoordInfo& tc = bpmem.texcoords[texmapid];
|
||||
int bitmask = 1 << texmapid;
|
||||
constants.texoffset[0] &= ~bitmask;
|
||||
constants.texoffset[0] |= tc.s.line_offset << texmapid;
|
||||
constants.texoffset[1] &= ~bitmask;
|
||||
constants.texoffset[1] |= tc.s.point_offset << texmapid;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void GeometryShaderManager::DoState(PointerWrap &p)
|
||||
{
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
// Reload current state from global GPU state
|
||||
// NOTE: This requires that all GPU memory has been loaded already.
|
||||
Dirty();
|
||||
}
|
||||
}
|
28
Source/Core/VideoCommon/GeometryShaderManager.h
Normal file
28
Source/Core/VideoCommon/GeometryShaderManager.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VideoCommon/ConstantManager.h"
|
||||
#include "VideoCommon/GeometryShaderGen.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
// The non-API dependent parts.
|
||||
class GeometryShaderManager
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Dirty();
|
||||
static void Shutdown();
|
||||
static void DoState(PointerWrap &p);
|
||||
|
||||
static void SetViewportChanged();
|
||||
static void SetProjectionChanged();
|
||||
static void SetLinePtWidthChanged();
|
||||
static void SetTexCoordChanged(u8 texmapid);
|
||||
|
||||
static GeometryShaderConstants constants;
|
||||
static bool dirty;
|
||||
};
|
@ -317,16 +317,20 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
|
||||
// is always inside the primitive.
|
||||
// Without MSAA, this flag is defined to have no effect.
|
||||
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("centroid in VS_OUTPUT vs;\n");
|
||||
out.Write("flat in int layer;\n");
|
||||
out.Write("in VertexData {\n");
|
||||
out.Write("\tcentroid VS_OUTPUT o;\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
out.Write("\tflat int layer;\n");
|
||||
|
||||
out.Write("};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
out.Write("centroid in float4 colors_02;\n");
|
||||
out.Write("centroid in float4 colors_12;\n");
|
||||
|
||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||
// Let's set up attributes
|
||||
for (unsigned int i = 0; i < numTexgen; ++i)
|
||||
@ -342,25 +346,25 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
|
||||
|
||||
out.Write("void main()\n{\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
// compute window position if needed because binding semantic WPOS is not widely supported
|
||||
// Let's set up attributes
|
||||
for (unsigned int i = 0; i < numTexgen; ++i)
|
||||
{
|
||||
out.Write("\tfloat3 uv%d = vs.tex%d;\n", i, i);
|
||||
out.Write("\tfloat3 uv%d = o.tex%d;\n", i, i);
|
||||
}
|
||||
out.Write("\tfloat4 clipPos = vs.clipPos;\n");
|
||||
out.Write("\tfloat4 clipPos = o.clipPos;\n");
|
||||
if (g_ActiveConfig.bEnablePixelLighting)
|
||||
{
|
||||
out.Write("\tfloat4 Normal = vs.Normal;\n");
|
||||
out.Write("\tfloat4 Normal = o.Normal;\n");
|
||||
}
|
||||
}
|
||||
|
||||
// On Mali, global variables must be initialized as constants.
|
||||
// This is why we initialize these variables locally instead.
|
||||
out.Write("\tfloat4 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "vs.colors_0" : "colors_02");
|
||||
out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "vs.colors_1" : "colors_12");
|
||||
out.Write("\tfloat4 colors_0 = %s;\n", g_ActiveConfig.backend_info.bSupportsGeometryShaders ? "o.colors_0" : "colors_02");
|
||||
out.Write("\tfloat4 colors_1 = %s;\n", g_ActiveConfig.backend_info.bSupportsGeometryShaders ? "o.colors_1" : "colors_12");
|
||||
|
||||
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ public:
|
||||
virtual void SetDepthMode() = 0;
|
||||
virtual void SetLogicOpMode() = 0;
|
||||
virtual void SetDitherMode() = 0;
|
||||
virtual void SetLineWidth() = 0;
|
||||
virtual void SetSamplerState(int stage,int texindex) = 0;
|
||||
virtual void SetInterlacingMode() = 0;
|
||||
virtual void SetViewport() = 0;
|
||||
|
@ -279,7 +279,10 @@ static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type)
|
||||
#define I_NORMALMATRICES "cnmtx"
|
||||
#define I_POSTTRANSFORMMATRICES "cpostmtx"
|
||||
#define I_PIXELCENTERCORRECTION "cpixelcenter"
|
||||
#define I_STEREOPARAMS "cstereo"
|
||||
|
||||
#define I_STEREOPARAMS "cstereo"
|
||||
#define I_LINEPTPARAMS "clinept"
|
||||
#define I_TEXOFFSET "ctexoffset"
|
||||
|
||||
static const char s_shader_uniforms[] =
|
||||
"\tfloat4 " I_POSNORMALMATRIX"[6];\n"
|
||||
@ -290,5 +293,4 @@ static const char s_shader_uniforms[] =
|
||||
"\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
|
||||
"\tfloat4 " I_NORMALMATRICES"[32];\n"
|
||||
"\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
|
||||
"\tfloat4 " I_PIXELCENTERCORRECTION";\n"
|
||||
"\tfloat4 " I_STEREOPARAMS";\n";
|
||||
"\tfloat4 " I_PIXELCENTERCORRECTION";\n";
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "VideoCommon/BPStructs.h"
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/MainBase.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
|
@ -72,10 +72,11 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
|
||||
out.Write("in float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i, SHADER_TEXTURE0_ATTRIB + i);
|
||||
}
|
||||
|
||||
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
|
||||
if (g_ActiveConfig.iStereoMode > 0)
|
||||
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
out.Write("centroid out VS_OUTPUT o;\n");
|
||||
out.Write("out VertexData {\n"
|
||||
"\tcentroid VS_OUTPUT o;\n"
|
||||
"};\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -87,7 +88,6 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
|
||||
out.Write("centroid out float3 uv%d;\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
out.Write("centroid out float4 clipPos;\n");
|
||||
if (g_ActiveConfig.bEnablePixelLighting)
|
||||
out.Write("centroid out float4 Normal;\n");
|
||||
@ -97,7 +97,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
|
||||
|
||||
out.Write("void main()\n{\n");
|
||||
|
||||
if (g_ActiveConfig.iStereoMode <= 0)
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
out.Write("VS_OUTPUT o;\n");
|
||||
}
|
||||
else // D3D
|
||||
@ -384,21 +384,15 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
|
||||
|
||||
if (api_type == API_OPENGL)
|
||||
{
|
||||
if (g_ActiveConfig.iStereoMode <= 0)
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGeometryShaders)
|
||||
{
|
||||
// Bit ugly here
|
||||
// TODO: Make pretty
|
||||
// Will look better when we bind uniforms in GLSL 1.3
|
||||
// clipPos/w needs to be done in pixel shader, not here
|
||||
|
||||
// TODO: Pass structs between shader stages even if geometry shaders
|
||||
// are not supported, however that will break GL 3.0 and 3.1 support.
|
||||
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
|
||||
out.Write("uv%d.xyz = o.tex%d;\n", i, i);
|
||||
|
||||
out.Write("clipPos = o.clipPos;\n");
|
||||
|
||||
if (g_ActiveConfig.bEnablePixelLighting)
|
||||
out.Write("Normal = o.Normal;\n");
|
||||
|
||||
out.Write("colors_02 = o.colors_0;\n");
|
||||
out.Write("colors_12 = o.colors_1;\n");
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ struct vertex_shader_uid_data
|
||||
u32 numColorChans : 2;
|
||||
u32 dualTexTrans_enabled : 1;
|
||||
u32 pixel_lighting : 1;
|
||||
u32 stereo : 1;
|
||||
u32 pad : 1;
|
||||
|
||||
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide
|
||||
struct {
|
||||
|
@ -512,18 +512,6 @@ void VertexShaderManager::SetConstants()
|
||||
memcpy(constants.projection, correctedMtx.data, 4*16);
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.iStereoMode > 0 && xfmem.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
float offset = (g_ActiveConfig.iStereoSeparation / 1000.0f) * (g_ActiveConfig.iStereoSeparationPercent / 100.0f);
|
||||
constants.stereoparams[0] = (g_ActiveConfig.bStereoSwapEyes) ? offset : -offset;
|
||||
constants.stereoparams[1] = (g_ActiveConfig.bStereoSwapEyes) ? -offset : offset;
|
||||
constants.stereoparams[2] = (g_ActiveConfig.iStereoConvergence / 10.0f) * (g_ActiveConfig.iStereoConvergencePercent / 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
constants.stereoparams[0] = constants.stereoparams[1] = 0;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@
|
||||
<ClCompile Include="RenderBase.cpp" />
|
||||
<ClCompile Include="Statistics.cpp" />
|
||||
<ClCompile Include="GeometryShaderGen.cpp" />
|
||||
<ClCompile Include="GeometryShaderManager.cpp" />
|
||||
<ClCompile Include="TextureCacheBase.cpp" />
|
||||
<ClCompile Include="TextureConversionShader.cpp" />
|
||||
<ClCompile Include="VertexLoader.cpp" />
|
||||
@ -112,6 +113,7 @@
|
||||
<ClInclude Include="ShaderGenCommon.h" />
|
||||
<ClInclude Include="Statistics.h" />
|
||||
<ClInclude Include="GeometryShaderGen.h" />
|
||||
<ClInclude Include="GeometryShaderManager.h" />
|
||||
<ClInclude Include="TextureCacheBase.h" />
|
||||
<ClInclude Include="TextureConversionShader.h" />
|
||||
<ClInclude Include="TextureDecoder.h" />
|
||||
|
@ -146,6 +146,9 @@
|
||||
<ClCompile Include="GeometryShaderGen.cpp">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeometryShaderManager.cpp">
|
||||
<Filter>Shader Managers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CommandProcessor.h" />
|
||||
@ -284,6 +287,9 @@
|
||||
<ClInclude Include="GeometryShaderGen.h">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GeometryShaderManager.h">
|
||||
<Filter>Shader Managers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
@ -214,7 +214,7 @@ void VideoConfig::VerifyValidity()
|
||||
// TODO: Check iMaxAnisotropy value
|
||||
if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) iAdapter = 0;
|
||||
if (iMultisampleMode < 0 || iMultisampleMode >= (int)backend_info.AAModes.size()) iMultisampleMode = 0;
|
||||
if (!backend_info.bSupportsStereoscopy) iStereoMode = 0;
|
||||
if (!backend_info.bSupportsGeometryShaders) iStereoMode = 0;
|
||||
}
|
||||
|
||||
void VideoConfig::Save(const std::string& ini_file)
|
||||
|
@ -151,7 +151,7 @@ struct VideoConfig final
|
||||
bool bSupportsDualSourceBlend;
|
||||
bool bSupportsPrimitiveRestart;
|
||||
bool bSupportsOversizedViewports;
|
||||
bool bSupportsStereoscopy;
|
||||
bool bSupportsGeometryShaders;
|
||||
bool bSupports3DVision;
|
||||
bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon
|
||||
bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/CPMemory.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/TextureDecoder.h"
|
||||
@ -50,6 +51,9 @@ static void DoState(PointerWrap &p)
|
||||
VertexShaderManager::DoState(p);
|
||||
p.DoMarker("VertexShaderManager");
|
||||
|
||||
GeometryShaderManager::DoState(p);
|
||||
p.DoMarker("GeometryShaderManager");
|
||||
|
||||
VertexManager::DoState(p);
|
||||
p.DoMarker("VertexManager");
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "VideoCommon/CPMemory.h"
|
||||
#include "VideoCommon/DataReader.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
@ -110,6 +111,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src)
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
PixelShaderManager::SetViewportChanged();
|
||||
GeometryShaderManager::SetViewportChanged();
|
||||
|
||||
nextAddress = XFMEM_SETVIEWPORT + 6;
|
||||
break;
|
||||
@ -123,6 +125,7 @@ static void XFRegWritten(int transferSize, u32 baseAddress, DataReader src)
|
||||
case XFMEM_SETPROJECTION+6:
|
||||
VertexManager::Flush();
|
||||
VertexShaderManager::SetProjectionChanged();
|
||||
GeometryShaderManager::SetProjectionChanged();
|
||||
|
||||
nextAddress = XFMEM_SETPROJECTION + 7;
|
||||
break;
|
||||
|
Reference in New Issue
Block a user