mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge branch 'shader-uids-awesome'.
Replaces the old, hardcoded shader ID generator with a semi-automatic mechanism that generates IDs from hints in the code generator. Also introduces a flexible framework to do all kinds of funky stuff with the shader code generation logic. As an example, a uniform usage profile generation class is added (unused for now, though). Functionality can still be tested by setting the EnableShaderDebugging field in the gfx config to True. Any two shaders which are identified with the same ID will be written to a file and an error message will be written to the Dolphin log.
This commit is contained in:
@@ -144,6 +144,11 @@
|
||||
#define TEVALPHAARG_KONST 6
|
||||
#define TEVALPHAARG_ZERO 7
|
||||
|
||||
#define GX_TEVPREV 0
|
||||
#define GX_TEVREG0 1
|
||||
#define GX_TEVREG1 2
|
||||
#define GX_TEVREG2 3
|
||||
|
||||
#define ALPHACMP_NEVER 0
|
||||
#define ALPHACMP_LESS 1
|
||||
#define ALPHACMP_EQUAL 2
|
||||
@@ -371,7 +376,7 @@ struct TevStageCombiner
|
||||
|
||||
union TwoTevStageOrders
|
||||
{
|
||||
struct
|
||||
struct
|
||||
{
|
||||
u32 texmap0 : 3; // indirect tex stage texmap
|
||||
u32 texcoord0 : 3;
|
||||
|
||||
@@ -89,21 +89,21 @@ void GFXDebuggerBase::DumpPixelShader(const char* path)
|
||||
if (!useDstAlpha)
|
||||
{
|
||||
output = "Destination alpha disabled:\n";
|
||||
output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
/// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
|
||||
{
|
||||
output = "Using dual source blending for destination alpha:\n";
|
||||
output += GeneratePixelShaderCode(DSTALPHA_DUAL_SOURCE_BLEND, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
/// output += GeneratePixelShaderCode(DSTALPHA_DUAL_SOURCE_BLEND, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = "Using two passes for emulating destination alpha:\n";
|
||||
output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
/// output += GeneratePixelShaderCode(DSTALPHA_NONE, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
output += "\n\nDestination alpha pass shader:\n";
|
||||
output += GeneratePixelShaderCode(DSTALPHA_ALPHA_PASS, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
/// output += GeneratePixelShaderCode(DSTALPHA_ALPHA_PASS, g_ActiveConfig.backend_info.APIType, g_nativeVertexFmt->m_components);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void GFXDebuggerBase::DumpVertexShader(const char* path)
|
||||
sprintf(filename, "%sdump_vs.txt", path);
|
||||
|
||||
File::CreateEmptyFile(filename);
|
||||
File::WriteStringToFile(true, GenerateVertexShaderCode(g_nativeVertexFmt->m_components, g_ActiveConfig.backend_info.APIType), filename);
|
||||
/// File::WriteStringToFile(true, GenerateVertexShaderCode(g_nativeVertexFmt->m_components, g_ActiveConfig.backend_info.APIType), filename);
|
||||
}
|
||||
|
||||
void GFXDebuggerBase::DumpPixelShaderConstants(const char* path)
|
||||
|
||||
@@ -5,217 +5,3 @@
|
||||
#include "LightingShaderGen.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "XFMemory.h"
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
int GetLightingShaderId(u32* out)
|
||||
{
|
||||
for (u32 i = 0; i < xfregs.numChan.numColorChans; ++i)
|
||||
{
|
||||
out[i] = xfregs.color[i].enablelighting ?
|
||||
(u32)xfregs.color[i].hex :
|
||||
(u32)xfregs.color[i].matsource;
|
||||
out[i] |= (xfregs.alpha[i].enablelighting ?
|
||||
(u32)xfregs.alpha[i].hex :
|
||||
(u32)xfregs.alpha[i].matsource) << 15;
|
||||
}
|
||||
_assert_(xfregs.numChan.numColorChans <= 2);
|
||||
return xfregs.numChan.numColorChans;
|
||||
}
|
||||
|
||||
// coloralpha - 1 if color, 2 if alpha
|
||||
char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char* lightsName, int coloralpha)
|
||||
{
|
||||
const char* swizzle = "xyzw";
|
||||
|
||||
if (coloralpha == 1 )
|
||||
swizzle = "xyz";
|
||||
else if (coloralpha == 2 )
|
||||
swizzle = "w";
|
||||
|
||||
if (!(chan.attnfunc & 1))
|
||||
{
|
||||
// attenuation disabled
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
WRITE(p, "lacc.%s += %s[%d].%s;\n", swizzle, lightsName, index * 5, swizzle);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
case LIGHTDIF_CLAMP:
|
||||
WRITE(p, "ldir = normalize(%s[%d + 3].xyz - pos.xyz);\n", lightsName, index * 5);
|
||||
WRITE(p, "lacc.%s += %sdot(ldir, _norm0)) * %s[%d].%s;\n",
|
||||
swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", lightsName, index * 5, swizzle);
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else // spec and spot
|
||||
{
|
||||
if (chan.attnfunc == 3)
|
||||
{ // spot
|
||||
WRITE(p, "ldir = %s[%d + 3].xyz - pos.xyz;\n", lightsName, index * 5);
|
||||
WRITE(p, "dist2 = dot(ldir, ldir);\n"
|
||||
"dist = sqrt(dist2);\n"
|
||||
"ldir = ldir / dist;\n"
|
||||
"attn = max(0.0f, dot(ldir, %s[%d + 4].xyz));\n", lightsName, index * 5);
|
||||
WRITE(p, "attn = max(0.0f, dot(%s[%d + 1].xyz, float3(1.0f, attn, attn*attn))) / dot(%s[%d + 2].xyz, float3(1.0f,dist,dist2));\n", lightsName, index * 5, lightsName, index * 5);
|
||||
}
|
||||
else if (chan.attnfunc == 1)
|
||||
{ // specular
|
||||
WRITE(p, "ldir = normalize(%s[%d + 3].xyz);\n", lightsName, index * 5);
|
||||
WRITE(p, "attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s[%d + 4].xyz)) : 0.0f;\n", lightsName, index * 5);
|
||||
WRITE(p, "attn = max(0.0f, dot(%s[%d + 1].xyz, float3(1,attn,attn*attn))) / dot(%s[%d + 2].xyz, float3(1,attn,attn*attn));\n", lightsName, index * 5, lightsName, index * 5);
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
WRITE(p, "lacc.%s += attn * %s[%d].%s;\n", swizzle, lightsName, index * 5, swizzle);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
case LIGHTDIF_CLAMP:
|
||||
WRITE(p, "lacc.%s += attn * %sdot(ldir, _norm0)) * %s[%d].%s;\n",
|
||||
swizzle,
|
||||
chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(",
|
||||
lightsName,
|
||||
index * 5,
|
||||
swizzle);
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
WRITE(p, "\n");
|
||||
return p;
|
||||
}
|
||||
|
||||
// vertex shader
|
||||
// lights/colors
|
||||
// materials name is I_MATERIALS in vs and I_PMATERIALS in ps
|
||||
// inColorName is color in vs and colors_ in ps
|
||||
// dest is o.colors_ in vs and colors_ in ps
|
||||
char *GenerateLightingShader(char *p, int components, const char* materialsName, const char* lightsName, const char* inColorName, const char* dest)
|
||||
{
|
||||
for (unsigned int j = 0; j < xfregs.numChan.numColorChans; j++)
|
||||
{
|
||||
const LitChannel& color = xfregs.color[j];
|
||||
const LitChannel& alpha = xfregs.alpha[j];
|
||||
|
||||
WRITE(p, "{\n");
|
||||
|
||||
if (color.matsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0 << j))
|
||||
WRITE(p, "mat = %s%d;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0)
|
||||
WRITE(p, "mat = %s0;\n", inColorName);
|
||||
else
|
||||
WRITE(p, "mat = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
WRITE(p, "mat = %s[%d];\n", materialsName, j+2);
|
||||
}
|
||||
|
||||
if (color.enablelighting)
|
||||
{
|
||||
if (color.ambsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j) )
|
||||
WRITE(p, "lacc = %s%d;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0 )
|
||||
WRITE(p, "lacc = %s0;\n", inColorName);
|
||||
else
|
||||
WRITE(p, "lacc = float4(0.0f, 0.0f, 0.0f, 0.0f);\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
WRITE(p, "lacc = %s[%d];\n", materialsName, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "lacc = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
|
||||
}
|
||||
|
||||
// check if alpha is different
|
||||
if (alpha.matsource != color.matsource)
|
||||
{
|
||||
if (alpha.matsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j))
|
||||
WRITE(p, "mat.w = %s%d.w;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0)
|
||||
WRITE(p, "mat.w = %s0.w;\n", inColorName);
|
||||
else WRITE(p, "mat.w = 1.0f;\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
WRITE(p, "mat.w = %s[%d].w;\n", materialsName, j+2);
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.enablelighting)
|
||||
{
|
||||
if (alpha.ambsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j) )
|
||||
WRITE(p, "lacc.w = %s%d.w;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0 )
|
||||
WRITE(p, "lacc.w = %s0.w;\n", inColorName);
|
||||
else
|
||||
WRITE(p, "lacc.w = 0.0f;\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
WRITE(p, "lacc.w = %s[%d].w;\n", materialsName, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WRITE(p, "lacc.w = 1.0f;\n");
|
||||
}
|
||||
|
||||
if(color.enablelighting && alpha.enablelighting)
|
||||
{
|
||||
// both have lighting, test if they use the same lights
|
||||
int mask = 0;
|
||||
if(color.lightparams == alpha.lightparams)
|
||||
{
|
||||
mask = color.GetFullLightMask() & alpha.GetFullLightMask();
|
||||
if(mask)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask & (1<<i))
|
||||
p = GenerateLightShader(p, i, color, lightsName, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no shared lights
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (!(mask&(1<<i)) && (color.GetFullLightMask() & (1<<i)))
|
||||
p = GenerateLightShader(p, i, color, lightsName, 1);
|
||||
if (!(mask&(1<<i)) && (alpha.GetFullLightMask() & (1<<i)))
|
||||
p = GenerateLightShader(p, i, alpha, lightsName, 2);
|
||||
}
|
||||
}
|
||||
else if (color.enablelighting || alpha.enablelighting)
|
||||
{
|
||||
// lights are disabled on one channel so process only the active ones
|
||||
const LitChannel& workingchannel = color.enablelighting ? color : alpha;
|
||||
int coloralpha = color.enablelighting ? 1 : 2;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (workingchannel.GetFullLightMask() & (1<<i))
|
||||
p = GenerateLightShader(p, i, workingchannel, lightsName, coloralpha);
|
||||
}
|
||||
}
|
||||
WRITE(p, "%s%d = mat * clamp(lacc, 0.0, 1.0);\n", dest, j);
|
||||
WRITE(p, "}\n");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,255 @@
|
||||
#ifndef _LIGHTINGSHADERGEN_H_
|
||||
#define _LIGHTINGSHADERGEN_H_
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "ShaderGenCommon.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "XFMemory.h"
|
||||
|
||||
int GetLightingShaderId(u32* out);
|
||||
char *GenerateLightingShader(char *p, int components, const char* materialsName, const char* lightsName, const char* inColorName, const char* dest);
|
||||
static const char* LightCol(const char* lightsName, unsigned int index, const char* swizzle)
|
||||
{
|
||||
static char result[32];
|
||||
snprintf(result, sizeof(result), "%s[5*%d].%s", lightsName, index, swizzle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* LightCosAtt(const char* lightsName, unsigned int index)
|
||||
{
|
||||
static char result[32];
|
||||
snprintf(result, sizeof(result), "%s[5*%d+1]", lightsName, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* LightDistAtt(const char* lightsName, unsigned int index)
|
||||
{
|
||||
static char result[32];
|
||||
snprintf(result, sizeof(result), "%s[5*%d+2]", lightsName, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* LightPos(const char* lightsName, unsigned int index)
|
||||
{
|
||||
static char result[32];
|
||||
snprintf(result, sizeof(result), "%s[5*%d+3]", lightsName, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char* LightDir(const char* lightsName, unsigned int index)
|
||||
{
|
||||
static char result[32];
|
||||
snprintf(result, sizeof(result), "%s[5*%d+4]", lightsName, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index, const char* lightsName, int coloralpha)
|
||||
{
|
||||
const LitChannel& chan = (litchan_index > 1) ? xfregs.alpha[litchan_index-2] : xfregs.color[litchan_index];
|
||||
const char* swizzle = "xyzw";
|
||||
if (coloralpha == 1)
|
||||
swizzle = "xyz";
|
||||
else if (coloralpha == 2)
|
||||
swizzle = "w";
|
||||
|
||||
uid_data.attnfunc |= chan.attnfunc << (2*litchan_index);
|
||||
uid_data.diffusefunc |= chan.diffusefunc << (2*litchan_index);
|
||||
if (!(chan.attnfunc & 1))
|
||||
{
|
||||
// atten disabled
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
object.Write("lacc.%s += %s;\n", swizzle, LightCol(lightsName, index, swizzle));
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
case LIGHTDIF_CLAMP:
|
||||
object.Write("ldir = normalize(%s.xyz - pos.xyz);\n", LightPos(lightsName, index));
|
||||
object.Write("lacc.%s += %sdot(ldir, _norm0)) * %s;\n",
|
||||
swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", LightCol(lightsName, index, swizzle));
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else // spec and spot
|
||||
{
|
||||
if (chan.attnfunc == 3)
|
||||
{ // spot
|
||||
object.Write("ldir = %s.xyz - pos.xyz;\n", LightPos(lightsName, index));
|
||||
object.Write("dist2 = dot(ldir, ldir);\n"
|
||||
"dist = sqrt(dist2);\n"
|
||||
"ldir = ldir / dist;\n"
|
||||
"attn = max(0.0f, dot(ldir, %s.xyz));\n", LightDir(lightsName, index));
|
||||
object.Write("attn = max(0.0f, dot(%s.xyz, float3(1.0f, attn, attn*attn))) / dot(%s.xyz, float3(1.0f,dist,dist2));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index));
|
||||
}
|
||||
else if (chan.attnfunc == 1)
|
||||
{ // specular
|
||||
object.Write("ldir = normalize(%s.xyz);\n", LightPos(lightsName, index));
|
||||
object.Write("attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s.xyz)) : 0.0f;\n", LightDir(lightsName, index));
|
||||
object.Write("attn = max(0.0f, dot(%s.xyz, float3(1,attn,attn*attn))) / dot(%s.xyz, float3(1,attn,attn*attn));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index));
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
object.Write("lacc.%s += attn * %s;\n", swizzle, LightCol(lightsName, index, swizzle));
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
case LIGHTDIF_CLAMP:
|
||||
object.Write("lacc.%s += attn * %sdot(ldir, _norm0)) * %s;\n",
|
||||
swizzle,
|
||||
chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(",
|
||||
LightCol(lightsName, index, swizzle));
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
object.Write("\n");
|
||||
}
|
||||
|
||||
// vertex shader
|
||||
// lights/colors
|
||||
// materials name is I_MATERIALS in vs and I_PMATERIALS in ps
|
||||
// inColorName is color in vs and colors_ in ps
|
||||
// dest is o.colors_ in vs and colors_ in ps
|
||||
template<class T>
|
||||
static void GenerateLightingShader(T& object, LightingUidData& uid_data, int components, const char* materialsName, const char* lightsName, const char* inColorName, const char* dest)
|
||||
{
|
||||
for (unsigned int j = 0; j < xfregs.numChan.numColorChans; j++)
|
||||
{
|
||||
const LitChannel& color = xfregs.color[j];
|
||||
const LitChannel& alpha = xfregs.alpha[j];
|
||||
|
||||
object.Write("{\n");
|
||||
|
||||
uid_data.matsource |= xfregs.color[j].matsource << j;
|
||||
if (color.matsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0 << j))
|
||||
object.Write("mat = %s%d;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0)
|
||||
object.Write("mat = %s0;\n", inColorName);
|
||||
else
|
||||
object.Write("mat = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
object.Write("mat = %s[%d];\n", materialsName, j+2);
|
||||
}
|
||||
|
||||
uid_data.enablelighting |= xfregs.color[j].enablelighting << j;
|
||||
if (color.enablelighting)
|
||||
{
|
||||
uid_data.ambsource |= xfregs.color[j].ambsource << j;
|
||||
if (color.ambsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j) )
|
||||
object.Write("lacc = %s%d;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0 )
|
||||
object.Write("lacc = %s0;\n", inColorName);
|
||||
else
|
||||
object.Write("lacc = float4(0.0f, 0.0f, 0.0f, 0.0f);\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
object.Write("lacc = %s[%d];\n", materialsName, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
object.Write("lacc = float4(1.0f, 1.0f, 1.0f, 1.0f);\n");
|
||||
}
|
||||
|
||||
// check if alpha is different
|
||||
uid_data.matsource |= xfregs.alpha[j].matsource << (j+2);
|
||||
if (alpha.matsource != color.matsource)
|
||||
{
|
||||
if (alpha.matsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j))
|
||||
object.Write("mat.w = %s%d.w;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0)
|
||||
object.Write("mat.w = %s0.w;\n", inColorName);
|
||||
else object.Write("mat.w = 1.0f;\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
object.Write("mat.w = %s[%d].w;\n", materialsName, j+2);
|
||||
}
|
||||
}
|
||||
|
||||
uid_data.enablelighting |= xfregs.alpha[j].enablelighting << (j+2);
|
||||
if (alpha.enablelighting)
|
||||
{
|
||||
uid_data.ambsource |= xfregs.alpha[j].ambsource << (j+2);
|
||||
if (alpha.ambsource) // from vertex
|
||||
{
|
||||
if (components & (VB_HAS_COL0<<j) )
|
||||
object.Write("lacc.w = %s%d.w;\n", inColorName, j);
|
||||
else if (components & VB_HAS_COL0 )
|
||||
object.Write("lacc.w = %s0.w;\n", inColorName);
|
||||
else
|
||||
object.Write("lacc.w = 0.0f;\n");
|
||||
}
|
||||
else // from color
|
||||
{
|
||||
object.Write("lacc.w = %s[%d].w;\n", materialsName, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
object.Write("lacc.w = 1.0f;\n");
|
||||
}
|
||||
|
||||
if(color.enablelighting && alpha.enablelighting)
|
||||
{
|
||||
// both have lighting, test if they use the same lights
|
||||
int mask = 0;
|
||||
uid_data.attnfunc |= color.attnfunc << (2*j);
|
||||
uid_data.attnfunc |= alpha.attnfunc << (2*(j+2));
|
||||
uid_data.diffusefunc |= color.diffusefunc << (2*j);
|
||||
uid_data.diffusefunc |= alpha.diffusefunc << (2*(j+2));
|
||||
uid_data.light_mask |= color.GetFullLightMask() << (8*j);
|
||||
uid_data.light_mask |= alpha.GetFullLightMask() << (8*(j+2));
|
||||
if(color.lightparams == alpha.lightparams)
|
||||
{
|
||||
mask = color.GetFullLightMask() & alpha.GetFullLightMask();
|
||||
if(mask)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask & (1<<i))
|
||||
{
|
||||
GenerateLightShader<T>(object, uid_data, i, j, lightsName, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no shared lights
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (!(mask&(1<<i)) && (color.GetFullLightMask() & (1<<i)))
|
||||
GenerateLightShader<T>(object, uid_data, i, j, lightsName, 1);
|
||||
if (!(mask&(1<<i)) && (alpha.GetFullLightMask() & (1<<i)))
|
||||
GenerateLightShader<T>(object, uid_data, i, j+2, lightsName, 2);
|
||||
}
|
||||
}
|
||||
else if (color.enablelighting || alpha.enablelighting)
|
||||
{
|
||||
// lights are disabled on one channel so process only the active ones
|
||||
const LitChannel& workingchannel = color.enablelighting ? color : alpha;
|
||||
const int lit_index = color.enablelighting ? j : (j+2);
|
||||
int coloralpha = color.enablelighting ? 1 : 2;
|
||||
|
||||
uid_data.light_mask |= workingchannel.GetFullLightMask() << (8*lit_index);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (workingchannel.GetFullLightMask() & (1<<i))
|
||||
GenerateLightShader<T>(object, uid_data, i, lit_index, lightsName, coloralpha);
|
||||
}
|
||||
}
|
||||
object.Write("%s%d = mat * clamp(lacc, 0.0, 1.0);\n", dest, j);
|
||||
object.Write("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _LIGHTINGSHADERGEN_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,8 @@
|
||||
#define GCOGL_PIXELSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "ShaderGenCommon.h"
|
||||
#include "BPMemory.h"
|
||||
|
||||
#define I_COLORS "color"
|
||||
#define I_KCOLORS "k"
|
||||
@@ -31,8 +33,14 @@
|
||||
#define C_PLIGHTS (C_FOG + 3)
|
||||
#define C_PMATERIALS (C_PLIGHTS + 40)
|
||||
#define C_PENVCONST_END (C_PMATERIALS + 4)
|
||||
#define PIXELSHADERUID_MAX_VALUES 70
|
||||
#define PIXELSHADERUID_MAX_VALUES_SAFE 116
|
||||
|
||||
// Different ways to achieve rendering with destination alpha
|
||||
enum DSTALPHA_MODE
|
||||
{
|
||||
DSTALPHA_NONE, // Render normally, without destination alpha
|
||||
DSTALPHA_ALPHA_PASS, // Render normally first, then render again for alpha
|
||||
DSTALPHA_DUAL_SOURCE_BLEND // Use dual-source blending
|
||||
};
|
||||
|
||||
// Annoying sure, can be removed once we get up to GLSL ~1.3
|
||||
const s_svar PSVar_Loc[] = { {I_COLORS, C_COLORS, 4 },
|
||||
@@ -47,90 +55,135 @@ const s_svar PSVar_Loc[] = { {I_COLORS, C_COLORS, 4 },
|
||||
{I_PMATERIALS, C_PMATERIALS, 4 },
|
||||
};
|
||||
|
||||
// DO NOT make anything in this class virtual.
|
||||
template<bool safe>
|
||||
class _PIXELSHADERUID
|
||||
// TODO: Should compact packing be enabled?
|
||||
//#pragma pack(4)
|
||||
struct pixel_shader_uid_data
|
||||
{
|
||||
public:
|
||||
u32 values[safe ? PIXELSHADERUID_MAX_VALUES_SAFE : PIXELSHADERUID_MAX_VALUES];
|
||||
int num_values;
|
||||
// TODO: Optimize field order for easy access!
|
||||
|
||||
_PIXELSHADERUID()
|
||||
u32 components;
|
||||
u32 dstAlphaMode : 2;
|
||||
u32 Pretest : 2;
|
||||
|
||||
u32 genMode_numtexgens : 4;
|
||||
u32 genMode_numtevstages : 4;
|
||||
u32 genMode_numindstages : 3;
|
||||
|
||||
u32 nIndirectStagesUsed : 8;
|
||||
|
||||
u32 texMtxInfo_n_projection : 8; // 8x1 bit
|
||||
|
||||
u32 tevindref_bi0 : 3;
|
||||
u32 tevindref_bc0 : 3;
|
||||
u32 tevindref_bi1 : 3;
|
||||
u32 tevindref_bc1 : 3;
|
||||
u32 tevindref_bi2 : 3;
|
||||
u32 tevindref_bc3 : 3;
|
||||
u32 tevindref_bi4 : 3;
|
||||
u32 tevindref_bc4 : 3;
|
||||
inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap)
|
||||
{
|
||||
if (index == 0) { tevindref_bc0 = texcoord; tevindref_bi0 = texmap; }
|
||||
else if (index == 1) { tevindref_bc1 = texcoord; tevindref_bi1 = texmap; }
|
||||
else if (index == 2) { tevindref_bc3 = texcoord; tevindref_bi2 = texmap; }
|
||||
else if (index == 3) { tevindref_bc4 = texcoord; tevindref_bi4 = texmap; }
|
||||
}
|
||||
inline void SetTevindrefTexmap(int index, u32 texmap)
|
||||
{
|
||||
if (index == 0) { tevindref_bi0 = texmap; }
|
||||
else if (index == 1) { tevindref_bi1 = texmap; }
|
||||
else if (index == 2) { tevindref_bi2 = texmap; }
|
||||
else if (index == 3) { tevindref_bi4 = texmap; }
|
||||
}
|
||||
|
||||
_PIXELSHADERUID(const _PIXELSHADERUID& r)
|
||||
{
|
||||
num_values = r.num_values;
|
||||
u64 tevorders_n_texcoord : 48; // 16 x 3 bits
|
||||
|
||||
if (safe)
|
||||
memcpy(values, r.values, PIXELSHADERUID_MAX_VALUES_SAFE);
|
||||
else
|
||||
memcpy(values, r.values, r.GetNumValues() * sizeof(values[0]));
|
||||
u64 tevind_n_sw : 48; // 16 x 3 bits
|
||||
u64 tevind_n_tw : 48; // 16 x 3 bits
|
||||
u32 tevind_n_fb_addprev : 16; // 16 x 1 bit
|
||||
u32 tevind_n_bs : 32; // 16 x 2 bits
|
||||
u32 tevind_n_fmt : 32; // 16 x 2 bits
|
||||
u32 tevind_n_bt : 32; // 16 x 2 bits
|
||||
u64 tevind_n_bias : 48; // 16 x 3 bits
|
||||
u64 tevind_n_mid : 64; // 16 x 4 bits
|
||||
|
||||
// NOTE: These assume that the affected bits are zero before calling
|
||||
void Set_tevind_sw(int index, u64 val)
|
||||
{
|
||||
tevind_n_sw |= val << (3*index);
|
||||
}
|
||||
void Set_tevind_tw(int index, u64 val)
|
||||
{
|
||||
tevind_n_tw |= val << (3*index);
|
||||
}
|
||||
void Set_tevind_bias(int index, u64 val)
|
||||
{
|
||||
tevind_n_bias |= val << (3*index);
|
||||
}
|
||||
void Set_tevind_mid(int index, u64 val)
|
||||
{
|
||||
tevind_n_mid |= val << (4*index);
|
||||
}
|
||||
|
||||
int GetNumValues() const
|
||||
{
|
||||
if (safe)
|
||||
return (sizeof(values) / sizeof(u32));
|
||||
else
|
||||
return num_values;
|
||||
}
|
||||
u32 tevksel_n_swap1 : 16; // 8x2 bits
|
||||
u32 tevksel_n_swap2 : 16; // 8x2 bits
|
||||
u64 tevksel_n_kcsel0 : 40; // 8x5 bits
|
||||
u64 tevksel_n_kasel0 : 40; // 8x5 bits
|
||||
u64 tevksel_n_kcsel1 : 40; // 8x5 bits
|
||||
u64 tevksel_n_kasel1 : 40; // 8x5 bits
|
||||
void set_tevksel_kcsel(int index, int i, u64 value) { if (i) tevksel_n_kcsel1 |= value << (5*index); else tevksel_n_kcsel0 |= value << (5*index); }
|
||||
void set_tevksel_kasel(int index, int i, u64 value) { if( i) tevksel_n_kasel1 |= value << (5*index); else tevksel_n_kasel0 |= value << (5*index); }
|
||||
|
||||
bool operator <(const _PIXELSHADERUID& _Right) const
|
||||
{
|
||||
int N = GetNumValues();
|
||||
u64 cc_n_d : 64; // 16x4 bits
|
||||
u64 cc_n_c : 64; // 16x4 bits
|
||||
u64 cc_n_b : 64; // 16x4 bits
|
||||
u64 cc_n_a : 64; // 16x4 bits
|
||||
u32 cc_n_bias : 32; // 16x2 bits
|
||||
u32 cc_n_op : 16; // 16x1 bit
|
||||
u32 cc_n_clamp : 16; // 16x1 bit
|
||||
u32 cc_n_shift : 32; // 16x2 bits
|
||||
u32 cc_n_dest : 32; // 16x2 bits
|
||||
|
||||
if (N < _Right.GetNumValues())
|
||||
return true;
|
||||
else if (N > _Right.GetNumValues())
|
||||
return false;
|
||||
u32 ac_n_rswap : 32; // 16x2 bits
|
||||
u32 ac_n_tswap : 32; // 16x2 bits
|
||||
u64 ac_n_d : 48; // 16x3 bits
|
||||
u64 ac_n_c : 48; // 16x3 bits
|
||||
u64 ac_n_b : 48; // 16x3 bits
|
||||
u64 ac_n_a : 48; // 16x3 bits
|
||||
u32 ac_n_bias : 32; // 16x2 bits
|
||||
u32 ac_n_op : 16; // 16x1 bit
|
||||
u32 ac_n_clamp : 16; // 16x1 bit
|
||||
u32 ac_n_shift : 32; // 16x2 bits
|
||||
u32 ac_n_dest : 32; // 16x2 bits
|
||||
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
if (values[i] < _Right.values[i])
|
||||
return true;
|
||||
else if (values[i] > _Right.values[i])
|
||||
return false;
|
||||
}
|
||||
u32 alpha_test_comp0 : 3;
|
||||
u32 alpha_test_comp1 : 3;
|
||||
u32 alpha_test_logic : 2;
|
||||
u32 alpha_test_use_zcomploc_hack : 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
u32 fog_proj : 1;
|
||||
u32 fog_fsel : 3;
|
||||
u32 fog_RangeBaseEnabled : 1;
|
||||
|
||||
bool operator ==(const _PIXELSHADERUID& _Right) const
|
||||
{
|
||||
int N = GetNumValues();
|
||||
u32 ztex_op : 2;
|
||||
|
||||
if (N != _Right.GetNumValues())
|
||||
return false;
|
||||
u32 fast_depth_calc : 1;
|
||||
u32 per_pixel_depth : 1;
|
||||
u32 bHasIndStage : 16;
|
||||
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
if (values[i] != _Right.values[i])
|
||||
return false;
|
||||
}
|
||||
u32 xfregs_numTexGen_numTexGens : 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
// TODO: I think we're fine without an enablePixelLighting field, should probably double check, though..
|
||||
LightingUidData lighting;
|
||||
};
|
||||
//#pragma pack()
|
||||
|
||||
typedef _PIXELSHADERUID<false> PIXELSHADERUID;
|
||||
typedef _PIXELSHADERUID<true> PIXELSHADERUIDSAFE;
|
||||
typedef ShaderUid<pixel_shader_uid_data> PixelShaderUid;
|
||||
typedef ShaderCode PixelShaderCode; // TODO: Obsolete
|
||||
typedef ShaderConstantProfile PixelShaderConstantProfile; // TODO: Obsolete
|
||||
|
||||
// Different ways to achieve rendering with destination alpha
|
||||
enum DSTALPHA_MODE
|
||||
{
|
||||
DSTALPHA_NONE, // Render normally, without destination alpha
|
||||
DSTALPHA_ALPHA_PASS, // Render normally first, then render again for alpha
|
||||
DSTALPHA_DUAL_SOURCE_BLEND // Use dual-source blending
|
||||
};
|
||||
|
||||
const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components);
|
||||
|
||||
void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
void GetSafePixelShaderId(PIXELSHADERUIDSAFE *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
|
||||
// Used to make sure that our optimized pixel shader IDs don't lose any possible shader code changes
|
||||
void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std::string& old_code, DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
void GeneratePixelShaderCode(PixelShaderCode& object, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components);
|
||||
void GetPixelShaderUid(PixelShaderUid& object, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components);
|
||||
void GetPixelShaderConstantProfile(PixelShaderConstantProfile& object, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components);
|
||||
|
||||
#endif // GCOGL_PIXELSHADER_H
|
||||
|
||||
@@ -29,19 +29,45 @@ static u32 lastTexDims[8]; // width | height << 16 | wrap_s << 28 | wrap_t << 30
|
||||
static u32 lastZBias;
|
||||
static int nMaterialsChanged;
|
||||
|
||||
static float s_constant_cache[C_PENVCONST_END*4];
|
||||
|
||||
inline void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
// if (s_constant_cache[const_number*4] == f1 && s_constant_cache[const_number*4+1] == f2 &&
|
||||
// s_constant_cache[const_number*4+2] == f3 && s_constant_cache[const_number*4+3] == f4)
|
||||
// return;
|
||||
|
||||
g_renderer->SetPSConstant4f(const_number, f1, f2, f3, f4);
|
||||
s_constant_cache[const_number*4] = f1;
|
||||
s_constant_cache[const_number*4+1] = f2;
|
||||
s_constant_cache[const_number*4+2] = f3;
|
||||
s_constant_cache[const_number*4+3] = f4;
|
||||
}
|
||||
|
||||
inline void SetPSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
// if (s_constant_cache[const_number*4] == f[0] && s_constant_cache[const_number*4+1] == f[1] &&
|
||||
// s_constant_cache[const_number*4+2] == f[2] && s_constant_cache[const_number*4+3] == f[3])
|
||||
// return;
|
||||
|
||||
g_renderer->SetPSConstant4fv(const_number, f);
|
||||
s_constant_cache[const_number*4] = f[0];
|
||||
s_constant_cache[const_number*4+1] = f[1];
|
||||
s_constant_cache[const_number*4+2] = f[2];
|
||||
s_constant_cache[const_number*4+3] = f[3];
|
||||
}
|
||||
|
||||
inline void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
// for (unsigned int i = 0; i < 4*count; ++i)
|
||||
// if (s_constant_cache[const_number*4+i] != f[i])
|
||||
// break;
|
||||
// else if (i == 4*count-1)
|
||||
// return;
|
||||
|
||||
g_renderer->SetMultiPSConstant4fv(const_number, count, f);
|
||||
for (unsigned int i = 0; i < 4*count; ++i)
|
||||
s_constant_cache[const_number*4+i] = f[i];
|
||||
}
|
||||
|
||||
void PixelShaderManager::Init()
|
||||
@@ -50,6 +76,7 @@ void PixelShaderManager::Init()
|
||||
memset(lastTexDims, 0, sizeof(lastTexDims));
|
||||
lastZBias = 0;
|
||||
memset(lastRGBAfull, 0, sizeof(lastRGBAfull));
|
||||
memset(s_constant_cache, 0, sizeof(s_constant_cache)); // TODO: Should reflect that on the GPU side....
|
||||
Dirty();
|
||||
}
|
||||
|
||||
@@ -70,11 +97,24 @@ void PixelShaderManager::Shutdown()
|
||||
|
||||
}
|
||||
|
||||
void PixelShaderManager::SetConstants()
|
||||
void PixelShaderManager::SetConstants(u32 components)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.APIType == API_OPENGL && !g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
Dirty();
|
||||
|
||||
// TODO: Probably broken in the non-UBO path
|
||||
PixelShaderConstantProfile constant_profile(C_PENVCONST_END);
|
||||
/// TODO: dst alpha/api/components type parameter...
|
||||
GetPixelShaderConstantProfile(constant_profile, DSTALPHA_DUAL_SOURCE_BLEND, API_OPENGL, components);
|
||||
|
||||
static int saved_updates = 0;
|
||||
static int necessary_updates = 0;
|
||||
|
||||
// TODO: Remove this!
|
||||
#define IncStuff() { \
|
||||
saved_updates++; \
|
||||
/*printf("Saved a constant update at line %d! Saved %d against %d now!\n", __LINE__, saved_updates, necessary_updates);*/ }
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (s_nColorsChanged[i])
|
||||
@@ -82,30 +122,37 @@ void PixelShaderManager::SetConstants()
|
||||
int baseind = i ? C_KCOLORS : C_COLORS;
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
if (s_nColorsChanged[i] & (1 << j))
|
||||
if ((s_nColorsChanged[i] & (1 << j)) && constant_profile.ConstantIsUsed(baseind+j))
|
||||
{
|
||||
SetPSConstant4fv(baseind+j, &lastRGBAfull[i][j][0]);
|
||||
s_nColorsChanged[i] &= ~(1<<j);
|
||||
++necessary_updates;
|
||||
} else if ((s_nColorsChanged[i] & (1 << j))) IncStuff();
|
||||
}
|
||||
s_nColorsChanged[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_nTexDimsChanged)
|
||||
if (s_nTexDimsChanged)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (s_nTexDimsChanged & (1<<i))
|
||||
if ((s_nTexDimsChanged & (1<<i)) && constant_profile.ConstantIsUsed(C_TEXDIMS+i))
|
||||
{
|
||||
++necessary_updates;
|
||||
SetPSTextureDims(i);
|
||||
}
|
||||
s_nTexDimsChanged = 0;
|
||||
}
|
||||
s_nTexDimsChanged &= ~(1<<i);
|
||||
}else if (s_nTexDimsChanged & (1<<i)) IncStuff();
|
||||
}
|
||||
}
|
||||
|
||||
if (s_bAlphaChanged)
|
||||
if (s_bAlphaChanged && constant_profile.ConstantIsUsed(C_ALPHA))
|
||||
{
|
||||
++necessary_updates;
|
||||
SetPSConstant4f(C_ALPHA, (lastAlpha&0xff)/255.0f, ((lastAlpha>>8)&0xff)/255.0f, 0, ((lastAlpha>>16)&0xff)/255.0f);
|
||||
s_bAlphaChanged = false;
|
||||
}
|
||||
} else if (s_bAlphaChanged) IncStuff();
|
||||
|
||||
if (s_bZTextureTypeChanged)
|
||||
if (s_bZTextureTypeChanged && constant_profile.ConstantIsUsed(C_ZBIAS))
|
||||
{
|
||||
float ftemp[4];
|
||||
switch (bpmem.ztex2.type)
|
||||
@@ -121,13 +168,14 @@ void PixelShaderManager::SetConstants()
|
||||
case 2:
|
||||
// 24 bits
|
||||
ftemp[0] = 16711680.0f/16777215.0f; ftemp[1] = 65280.0f/16777215.0f; ftemp[2] = 255.0f/16777215.0f; ftemp[3] = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++necessary_updates;
|
||||
SetPSConstant4fv(C_ZBIAS, ftemp);
|
||||
s_bZTextureTypeChanged = false;
|
||||
}
|
||||
} else if (s_bZTextureTypeChanged) IncStuff();
|
||||
|
||||
if (s_bZBiasChanged || s_bDepthRangeChanged)
|
||||
if ((s_bZBiasChanged || s_bDepthRangeChanged) && constant_profile.ConstantIsUsed(C_ZBIAS+1))
|
||||
{
|
||||
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
|
||||
// [0] = width/2
|
||||
@@ -138,9 +186,10 @@ void PixelShaderManager::SetConstants()
|
||||
// [5] = 16777215 * farz
|
||||
|
||||
//ERROR_LOG("pixel=%x,%x, bias=%x\n", bpmem.zcontrol.pixel_format, bpmem.ztex2.type, lastZBias);
|
||||
++necessary_updates;
|
||||
SetPSConstant4f(C_ZBIAS+1, xfregs.viewport.farZ / 16777216.0f, xfregs.viewport.zRange / 16777216.0f, 0, (float)(lastZBias)/16777215.0f);
|
||||
s_bZBiasChanged = s_bDepthRangeChanged = false;
|
||||
}
|
||||
}else if ((s_bZBiasChanged || s_bDepthRangeChanged)) IncStuff();
|
||||
|
||||
// indirect incoming texture scales
|
||||
if (s_nIndTexScaleChanged)
|
||||
@@ -148,45 +197,51 @@ void PixelShaderManager::SetConstants()
|
||||
// set as two sets of vec4s, each containing S and T of two ind stages.
|
||||
float f[8];
|
||||
|
||||
if (s_nIndTexScaleChanged & 0x03)
|
||||
if ((s_nIndTexScaleChanged & 0x03) && constant_profile.ConstantIsUsed(C_INDTEXSCALE))
|
||||
{
|
||||
for (u32 i = 0; i < 2; ++i)
|
||||
{
|
||||
f[2 * i] = bpmem.texscale[0].getScaleS(i & 1);
|
||||
f[2 * i + 1] = bpmem.texscale[0].getScaleT(i & 1);
|
||||
PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]);
|
||||
}
|
||||
f[2 * i] = bpmem.texscale[0].getScaleS(i & 1);
|
||||
f[2 * i + 1] = bpmem.texscale[0].getScaleT(i & 1);
|
||||
PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]);
|
||||
}
|
||||
++necessary_updates;
|
||||
SetPSConstant4fv(C_INDTEXSCALE, f);
|
||||
}
|
||||
s_nIndTexScaleChanged &= ~0x03;
|
||||
}
|
||||
else if ((s_nIndTexScaleChanged & 0x03)) IncStuff();
|
||||
|
||||
if (s_nIndTexScaleChanged & 0x0c)
|
||||
if ((s_nIndTexScaleChanged & 0x0c) && constant_profile.ConstantIsUsed(C_INDTEXSCALE+1))
|
||||
{
|
||||
for (u32 i = 2; i < 4; ++i)
|
||||
for (u32 i = 2; i < 4; ++i)
|
||||
{
|
||||
f[2 * i] = bpmem.texscale[1].getScaleS(i & 1);
|
||||
f[2 * i + 1] = bpmem.texscale[1].getScaleT(i & 1);
|
||||
PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]);
|
||||
}
|
||||
f[2 * i] = bpmem.texscale[1].getScaleS(i & 1);
|
||||
f[2 * i + 1] = bpmem.texscale[1].getScaleT(i & 1);
|
||||
PRIM_LOG("tex indscale%d: %f %f\n", i, f[2 * i], f[2 * i + 1]);
|
||||
}
|
||||
++necessary_updates;
|
||||
SetPSConstant4fv(C_INDTEXSCALE+1, &f[4]);
|
||||
}
|
||||
|
||||
s_nIndTexScaleChanged = 0;
|
||||
}
|
||||
s_nIndTexScaleChanged &= ~0x0c;
|
||||
}
|
||||
else if ((s_nIndTexScaleChanged & 0x0c)) IncStuff();
|
||||
}
|
||||
|
||||
if (s_nIndTexMtxChanged)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (s_nIndTexMtxChanged & (1 << i))
|
||||
if ((s_nIndTexMtxChanged & (1 << i)) && (constant_profile.ConstantIsUsed(C_INDTEXMTX+2*i) || constant_profile.ConstantIsUsed(C_INDTEXMTX+2*i+1)))
|
||||
{
|
||||
int scale = ((u32)bpmem.indmtx[i].col0.s0 << 0) |
|
||||
((u32)bpmem.indmtx[i].col1.s1 << 2) |
|
||||
((u32)bpmem.indmtx[i].col2.s2 << 4);
|
||||
float fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f;
|
||||
int scale = ((u32)bpmem.indmtx[i].col0.s0 << 0) |
|
||||
((u32)bpmem.indmtx[i].col1.s1 << 2) |
|
||||
((u32)bpmem.indmtx[i].col2.s2 << 4);
|
||||
float fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f;
|
||||
|
||||
// xyz - static matrix
|
||||
// TODO w - dynamic matrix scale / 256...... somehow / 4 works better
|
||||
// rev 2972 - now using / 256.... verify that this works
|
||||
// xyz - static matrix
|
||||
// TODO w - dynamic matrix scale / 256...... somehow / 4 works better
|
||||
// rev 2972 - now using / 256.... verify that this works
|
||||
++necessary_updates;
|
||||
++necessary_updates;
|
||||
SetPSConstant4f(C_INDTEXMTX + 2 * i,
|
||||
bpmem.indmtx[i].col0.ma * fscale,
|
||||
bpmem.indmtx[i].col1.mc * fscale,
|
||||
@@ -198,23 +253,26 @@ void PixelShaderManager::SetConstants()
|
||||
bpmem.indmtx[i].col2.mf * fscale,
|
||||
fscale * 4.0f);
|
||||
|
||||
PRIM_LOG("indmtx%d: scale=%f, mat=(%f %f %f; %f %f %f)\n",
|
||||
i, 1024.0f*fscale,
|
||||
bpmem.indmtx[i].col0.ma * fscale, bpmem.indmtx[i].col1.mc * fscale, bpmem.indmtx[i].col2.me * fscale,
|
||||
bpmem.indmtx[i].col0.mb * fscale, bpmem.indmtx[i].col1.md * fscale, bpmem.indmtx[i].col2.mf * fscale);
|
||||
}
|
||||
}
|
||||
s_nIndTexMtxChanged = 0;
|
||||
}
|
||||
PRIM_LOG("indmtx%d: scale=%f, mat=(%f %f %f; %f %f %f)\n",
|
||||
i, 1024.0f*fscale,
|
||||
bpmem.indmtx[i].col0.ma * fscale, bpmem.indmtx[i].col1.mc * fscale, bpmem.indmtx[i].col2.me * fscale,
|
||||
bpmem.indmtx[i].col0.mb * fscale, bpmem.indmtx[i].col1.md * fscale, bpmem.indmtx[i].col2.mf * fscale);
|
||||
|
||||
if (s_bFogColorChanged)
|
||||
s_nIndTexMtxChanged &= ~(1 << i);
|
||||
}else if ((s_nIndTexMtxChanged & (1 << i))) {IncStuff();IncStuff();}
|
||||
}
|
||||
}
|
||||
|
||||
if (s_bFogColorChanged && constant_profile.ConstantIsUsed(C_FOG))
|
||||
{
|
||||
++necessary_updates;
|
||||
SetPSConstant4f(C_FOG, bpmem.fog.color.r / 255.0f, bpmem.fog.color.g / 255.0f, bpmem.fog.color.b / 255.0f, 0);
|
||||
s_bFogColorChanged = false;
|
||||
}
|
||||
}else if (s_bFogColorChanged) IncStuff();
|
||||
|
||||
if (s_bFogParamChanged)
|
||||
if (s_bFogParamChanged && constant_profile.ConstantIsUsed(C_FOG+1))
|
||||
{
|
||||
++necessary_updates;
|
||||
if(!g_ActiveConfig.bDisableFog)
|
||||
{
|
||||
//downscale magnitude to 0.24 bits
|
||||
@@ -226,11 +284,12 @@ void PixelShaderManager::SetConstants()
|
||||
else
|
||||
SetPSConstant4f(C_FOG + 1, 0.0, 1.0, 0.0, 1.0);
|
||||
|
||||
s_bFogParamChanged = false;
|
||||
}
|
||||
s_bFogParamChanged = false;
|
||||
}else if ( s_bFogParamChanged) IncStuff();
|
||||
|
||||
if (s_bFogRangeAdjustChanged)
|
||||
if (s_bFogRangeAdjustChanged && constant_profile.ConstantIsUsed(C_FOG+2))
|
||||
{
|
||||
++necessary_updates;
|
||||
if(!g_ActiveConfig.bDisableFog && bpmem.fogRange.Base.Enabled == 1)
|
||||
{
|
||||
//bpmem.fogRange.Base.Center : center of the viewport in x axis. observation: bpmem.fogRange.Base.Center = realcenter + 342;
|
||||
@@ -251,8 +310,9 @@ void PixelShaderManager::SetConstants()
|
||||
}
|
||||
|
||||
s_bFogRangeAdjustChanged = false;
|
||||
}
|
||||
}else if ( s_bFogRangeAdjustChanged) IncStuff();
|
||||
|
||||
// TODO: use constant profile here!
|
||||
if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) // config check added because the code in here was crashing for me inside SetPSConstant4f
|
||||
{
|
||||
if (nLightsChanged[0] >= 0)
|
||||
@@ -349,8 +409,10 @@ void PixelShaderManager::SetPSTextureDims(int texid)
|
||||
SetPSConstant4fv(C_TEXDIMS + texid, fdims);
|
||||
}
|
||||
|
||||
// This one is high in profiles (0.5%). TODO: Move conversion out, only store the raw color value
|
||||
// This one is high in profiles (0.5%).
|
||||
// TODO: Move conversion out, only store the raw color value
|
||||
// and update it when the shader constant is set, only.
|
||||
// TODO: Conversion should be checked in the context of tev_fixes..
|
||||
void PixelShaderManager::SetColorChanged(int type, int num, bool high)
|
||||
{
|
||||
float *pf = &lastRGBAfull[type][num][0];
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
static void Shutdown();
|
||||
static void DoState(PointerWrap &p);
|
||||
|
||||
static void SetConstants(); // sets pixel shader constants
|
||||
static void SetConstants(u32 components); // sets pixel shader constants
|
||||
|
||||
// constant management, should be called after memory is committed
|
||||
static void SetColorChanged(int type, int index, bool high);
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
// 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 _SHADERGENCOMMON_H
|
||||
#define _SHADERGENCOMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "VideoCommon.h"
|
||||
|
||||
/**
|
||||
* Common interface for classes that need to go through the shader generation path (GenerateVertexShader, GeneratePixelShader)
|
||||
* In particular, this includes the shader code generator (ShaderCode).
|
||||
* A different class (ShaderUid) can be used to uniquely identify each ShaderCode object.
|
||||
* More interesting things can be done with this, e.g. ShaderConstantProfile checks what shader constants are being used. This can be used to optimize buffer management.
|
||||
* Each of the ShaderCode, ShaderUid and ShaderConstantProfile child classes only implement the subset of ShaderGeneratorInterface methods that are required for the specific tasks.
|
||||
*/
|
||||
class ShaderGeneratorInterface
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Used when the shader generator would write a piece of ShaderCode.
|
||||
* Can be used like printf.
|
||||
* @note In the ShaderCode implementation, this does indeed write the parameter string to an internal buffer. However, you're free to do whatever you like with the parameter.
|
||||
*/
|
||||
void Write(const char* fmt, ...) {}
|
||||
|
||||
/*
|
||||
* Returns a read pointer to the internal buffer.
|
||||
* @note When implementing this method in a child class, you likely want to return the argument of the last SetBuffer call here
|
||||
* @note SetBuffer() should be called before using GetBuffer().
|
||||
*/
|
||||
const char* GetBuffer() { return NULL; }
|
||||
|
||||
/*
|
||||
* Can be used to give the object a place to write to. This should be called before using Write().
|
||||
* @param buffer pointer to a char buffer that the object can write to
|
||||
*/
|
||||
void SetBuffer(char* buffer) { }
|
||||
|
||||
/*
|
||||
* Tells us that a specific constant range (including last_index) is being used by the shader
|
||||
*/
|
||||
inline void SetConstantsUsed(unsigned int first_index, unsigned int last_index) {}
|
||||
|
||||
/*
|
||||
* Returns a pointer to an internally stored object of the uid_data type.
|
||||
* @warning since most child classes use the default implementation you shouldn't access this directly without adding precautions against NULL access (e.g. via adding a dummy structure, cf. the vertex/pixel shader generators)
|
||||
*/
|
||||
template<class uid_data>
|
||||
uid_data& GetUidData() { return *(uid_data*)NULL; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Shader UID class used to uniquely identify the ShaderCode output written in the shader generator.
|
||||
* uid_data can be any struct of parameters that uniquely identify each shader code output.
|
||||
* Unless performance is not an issue, uid_data should be tightly packed to reduce memory footprint.
|
||||
* Shader generators will write to specific uid_data fields; ShaderUid methods will only read raw u32 values from a union.
|
||||
*/
|
||||
template<class uid_data>
|
||||
class ShaderUid : public ShaderGeneratorInterface
|
||||
{
|
||||
public:
|
||||
ShaderUid()
|
||||
{
|
||||
// TODO: Move to Shadergen => can be optimized out
|
||||
memset(values, 0, sizeof(values));
|
||||
}
|
||||
|
||||
bool operator == (const ShaderUid& obj) const
|
||||
{
|
||||
return memcmp(this->values, obj.values, sizeof(values)) == 0;
|
||||
}
|
||||
|
||||
bool operator != (const ShaderUid& obj) const
|
||||
{
|
||||
return memcmp(this->values, obj.values, sizeof(values)) != 0;
|
||||
}
|
||||
|
||||
// determines the storage order inside STL containers
|
||||
bool operator < (const ShaderUid& obj) const
|
||||
{
|
||||
// TODO: Store last frame used and order by that? makes much more sense anyway...
|
||||
for (unsigned int i = 0; i < sizeof(uid_data) / sizeof(u32); ++i)
|
||||
{
|
||||
if (this->values[i] < obj.values[i])
|
||||
return true;
|
||||
else if (this->values[i] > obj.values[i])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T& GetUidData() { return data; }
|
||||
|
||||
const uid_data& GetUidData() const { return data; }
|
||||
size_t GetUidDataSize() const { return sizeof(values); }
|
||||
|
||||
private:
|
||||
union
|
||||
{
|
||||
uid_data data;
|
||||
u32 values[sizeof(uid_data) / sizeof(u32)];
|
||||
};
|
||||
};
|
||||
|
||||
class ShaderCode : public ShaderGeneratorInterface
|
||||
{
|
||||
public:
|
||||
ShaderCode() : buf(NULL), write_ptr(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Write(const char* fmt, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
va_start(arglist, fmt);
|
||||
write_ptr += vsprintf(write_ptr, fmt, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
|
||||
const char* GetBuffer() { return buf; }
|
||||
void SetBuffer(char* buffer) { buf = buffer; write_ptr = buffer; }
|
||||
|
||||
private:
|
||||
const char* buf;
|
||||
char* write_ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a shader constant profile which can be used to query which constants are used in a shader
|
||||
*/
|
||||
class ShaderConstantProfile : public ShaderGeneratorInterface
|
||||
{
|
||||
public:
|
||||
ShaderConstantProfile(int num_constants) { constant_usage.resize(num_constants); }
|
||||
|
||||
inline void SetConstantsUsed(unsigned int first_index, unsigned int last_index)
|
||||
{
|
||||
for (unsigned int i = first_index; i < last_index+1; ++i)
|
||||
constant_usage[i] = true;
|
||||
}
|
||||
|
||||
inline bool ConstantIsUsed(unsigned int index)
|
||||
{
|
||||
// TODO: Not ready for usage yet
|
||||
return true;
|
||||
// return constant_usage[index];
|
||||
}
|
||||
private:
|
||||
std::vector<bool> constant_usage; // TODO: Is vector<bool> appropriate here?
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const u32 num)
|
||||
{
|
||||
if (ApiType == API_OPENGL)
|
||||
return; // Nothing to do here
|
||||
|
||||
object.Write(" : register(%s%d)", prefix, num);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos)
|
||||
{
|
||||
if (using_ubos)
|
||||
return;
|
||||
|
||||
object.Write("uniform ");
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void DeclareUniform(T& object, API_TYPE api_type, bool using_ubos, const u32 num, const char* type, const char* name)
|
||||
{
|
||||
WriteLocation(object, api_type, using_ubos);
|
||||
object.Write("%s %s ", type, name);
|
||||
WriteRegister(object, api_type, "c", num);
|
||||
object.Write(";\n");
|
||||
}
|
||||
|
||||
#pragma pack(4)
|
||||
/**
|
||||
* Common uid data used for shader generators that use lighting calculations.
|
||||
* Expected to be stored as a member called "lighting".
|
||||
*/
|
||||
struct LightingUidData
|
||||
{
|
||||
u32 matsource : 4; // 4x1 bit
|
||||
u32 enablelighting : 4; // 4x1 bit
|
||||
u32 ambsource : 4; // 4x1 bit
|
||||
u32 diffusefunc : 8; // 4x2 bits
|
||||
u32 attnfunc : 8; // 4x2 bits
|
||||
u32 light_mask : 32; // 4x8 bits
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
/**
|
||||
* Checks if there has been
|
||||
*/
|
||||
template<class UidT, class CodeT>
|
||||
class UidChecker
|
||||
{
|
||||
public:
|
||||
void Invalidate()
|
||||
{
|
||||
m_shaders.clear();
|
||||
m_uids.clear();
|
||||
}
|
||||
|
||||
void AddToIndexAndCheck(CodeT& new_code, const UidT& new_uid, const char* shader_type, const char* dump_prefix)
|
||||
{
|
||||
bool uid_is_indexed = std::find(m_uids.begin(), m_uids.end(), new_uid) != m_uids.end();
|
||||
if (!uid_is_indexed)
|
||||
{
|
||||
m_uids.push_back(new_uid);
|
||||
m_shaders[new_uid] = new_code.GetBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// uid is already in the index => check if there's a shader with the same uid but different code
|
||||
auto& old_code = m_shaders[new_uid];
|
||||
if (strcmp(old_code.c_str(), new_code.GetBuffer()) != 0)
|
||||
{
|
||||
static int num_failures = 0;
|
||||
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%s%ssuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(),
|
||||
dump_prefix,
|
||||
++num_failures);
|
||||
|
||||
// TODO: Should also dump uids
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << "Old shader code:\n" << old_code;
|
||||
file << "\n\nNew shader code:\n" << new_code.GetBuffer();
|
||||
file << "\n\nShader uid:\n";
|
||||
for (unsigned int i = 0; i < new_uid.GetUidDataSize(); ++i)
|
||||
{
|
||||
u32 value = ((u32*)&new_uid.GetUidData())[i];
|
||||
if ((i % 4) == 0)
|
||||
{
|
||||
unsigned int last_value = (i+3 < new_uid.GetUidDataSize()-1) ? i+3 : new_uid.GetUidDataSize();
|
||||
file << std::setfill(' ') << std::dec;
|
||||
file << "Values " << std::setw(2) << i << " - " << last_value << ": ";
|
||||
}
|
||||
|
||||
file << std::setw(8) << std::setfill('0') << std::hex << value << std::setw(1);
|
||||
if ((i % 4) < 3)
|
||||
file << ' ';
|
||||
else
|
||||
file << std::endl;
|
||||
}
|
||||
file.close();
|
||||
|
||||
ERROR_LOG(VIDEO, "%s shader uid mismatch! See %s for details", shader_type, szTemp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<UidT,std::string> m_shaders;
|
||||
std::vector<UidT> m_uids;
|
||||
};
|
||||
|
||||
#endif // _SHADERGENCOMMON_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,10 @@
|
||||
#ifndef GCOGL_VERTEXSHADER_H
|
||||
#define GCOGL_VERTEXSHADER_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "XFMemory.h"
|
||||
#include "VideoCommon.h"
|
||||
#include "ShaderGenCommon.h"
|
||||
|
||||
// TODO should be reordered
|
||||
#define SHADER_POSITION_ATTRIB 0
|
||||
@@ -48,7 +50,8 @@
|
||||
#define C_NORMALMATRICES (C_TRANSFORMMATRICES + 64)
|
||||
#define C_POSTTRANSFORMMATRICES (C_NORMALMATRICES + 32)
|
||||
#define C_DEPTHPARAMS (C_POSTTRANSFORMMATRICES + 64)
|
||||
#define C_VENVCONST_END (C_DEPTHPARAMS + 1)
|
||||
#define C_VENVCONST_END (C_DEPTHPARAMS + 1)
|
||||
|
||||
const s_svar VSVar_Loc[] = { {I_POSNORMALMATRIX, C_POSNORMALMATRIX, 6 },
|
||||
{I_PROJECTION , C_PROJECTION, 4 },
|
||||
{I_MATERIALS, C_MATERIALS, 4 },
|
||||
@@ -59,75 +62,40 @@ const s_svar VSVar_Loc[] = { {I_POSNORMALMATRIX, C_POSNORMALMATRIX, 6 },
|
||||
{I_POSTTRANSFORMMATRICES, C_POSTTRANSFORMMATRICES, 64 },
|
||||
{I_DEPTHPARAMS, C_DEPTHPARAMS, 1 },
|
||||
};
|
||||
template<bool safe>
|
||||
class _VERTEXSHADERUID
|
||||
|
||||
#pragma pack(4)
|
||||
|
||||
struct vertex_shader_uid_data
|
||||
{
|
||||
#define NUM_VSUID_VALUES_SAFE 25
|
||||
public:
|
||||
u32 values[safe ? NUM_VSUID_VALUES_SAFE : 9];
|
||||
u32 components;
|
||||
u32 numColorChans : 2;
|
||||
u32 numTexGens : 4;
|
||||
|
||||
_VERTEXSHADERUID()
|
||||
{
|
||||
}
|
||||
struct {
|
||||
u32 projection : 1; // XF_TEXPROJ_X
|
||||
u32 inputform : 2; // XF_TEXINPUT_X
|
||||
u32 texgentype : 3; // XF_TEXGEN_X
|
||||
u32 sourcerow : 5; // XF_SRCGEOM_X
|
||||
u32 embosssourceshift : 3; // what generated texcoord to use
|
||||
u32 embosslightshift : 3; // light index that is used
|
||||
} texMtxInfo[8];
|
||||
struct {
|
||||
u32 index : 6; // base row of dual transform matrix
|
||||
u32 normalize : 1; // normalize before send operation
|
||||
} postMtxInfo[8];
|
||||
struct {
|
||||
u32 enabled : 1;
|
||||
} dualTexTrans;
|
||||
|
||||
_VERTEXSHADERUID(const _VERTEXSHADERUID& r)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(u32); ++i)
|
||||
values[i] = r.values[i];
|
||||
}
|
||||
|
||||
int GetNumValues() const
|
||||
{
|
||||
if (safe) return NUM_VSUID_VALUES_SAFE;
|
||||
else return (((values[0] >> 23) & 0xf) * 3 + 3) / 4 + 3; // numTexGens*3/4+1
|
||||
}
|
||||
|
||||
bool operator <(const _VERTEXSHADERUID& _Right) const
|
||||
{
|
||||
if (values[0] < _Right.values[0])
|
||||
return true;
|
||||
else if (values[0] > _Right.values[0])
|
||||
return false;
|
||||
|
||||
int N = GetNumValues();
|
||||
for (int i = 1; i < N; ++i)
|
||||
{
|
||||
if (values[i] < _Right.values[i])
|
||||
return true;
|
||||
else if (values[i] > _Right.values[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator ==(const _VERTEXSHADERUID& _Right) const
|
||||
{
|
||||
if (values[0] != _Right.values[0])
|
||||
return false;
|
||||
|
||||
int N = GetNumValues();
|
||||
for (int i = 1; i < N; ++i)
|
||||
{
|
||||
if (values[i] != _Right.values[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
LightingUidData lighting;
|
||||
};
|
||||
typedef _VERTEXSHADERUID<false> VERTEXSHADERUID;
|
||||
typedef _VERTEXSHADERUID<true> VERTEXSHADERUIDSAFE;
|
||||
#pragma pack()
|
||||
|
||||
typedef ShaderUid<vertex_shader_uid_data> VertexShaderUid;
|
||||
typedef ShaderCode VertexShaderCode; // TODO: Obsolete..
|
||||
|
||||
// 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);
|
||||
void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components);
|
||||
|
||||
// Used to make sure that our optimized vertex shader IDs don't lose any possible shader code changes
|
||||
void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components);
|
||||
void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type);
|
||||
void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE api_type);
|
||||
void GenerateVSOutputStructForGS(ShaderCode& object, u32 components, API_TYPE api_type);
|
||||
|
||||
#endif // GCOGL_VERTEXSHADER_H
|
||||
|
||||
@@ -252,6 +252,7 @@
|
||||
<ClInclude Include="Src\PixelShaderGen.h" />
|
||||
<ClInclude Include="Src\PixelShaderManager.h" />
|
||||
<ClInclude Include="Src\RenderBase.h" />
|
||||
<ClInclude Include="Src\ShaderGenCommon.h" />
|
||||
<ClInclude Include="Src\Statistics.h" />
|
||||
<ClInclude Include="Src\TextureCacheBase.h" />
|
||||
<ClInclude Include="Src\TextureConversionShader.h" />
|
||||
|
||||
@@ -258,6 +258,9 @@
|
||||
<ClInclude Include="Src\FPSCounter.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\ShaderGenCommon.h">
|
||||
<Filter>Shader Generators</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
@@ -291,4 +294,4 @@
|
||||
<UniqueIdentifier>{e2a527a2-ccc8-4ab8-a93e-dd2628c0f3b6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -169,11 +169,12 @@ bool LineGeometryShader::SetShader(u32 components, float lineWidth,
|
||||
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);
|
||||
|
||||
static char buffer[16384];
|
||||
ShaderCode code;
|
||||
code.SetBuffer(buffer);
|
||||
GenerateVSOutputStructForGS(code, components, API_D3D11);
|
||||
code.Write("\n%s", LINE_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStream;
|
||||
numTexCoordsStream << xfregs.numTexGen.numTexGens;
|
||||
|
||||
@@ -185,7 +186,7 @@ bool LineGeometryShader::SetShader(u32 components, float lineWidth,
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
|
||||
|
||||
@@ -28,9 +28,10 @@ namespace DX11
|
||||
|
||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
||||
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
|
||||
PIXELSHADERUID PixelShaderCache::last_uid;
|
||||
PixelShaderUid PixelShaderCache::last_uid;
|
||||
UidChecker<PixelShaderUid,PixelShaderCode> PixelShaderCache::pixel_uid_checker;
|
||||
|
||||
LinearDiskCache<PIXELSHADERUID, u8> g_ps_disk_cache;
|
||||
LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache;
|
||||
|
||||
ID3D11PixelShader* s_ColorMatrixProgram[2] = {NULL};
|
||||
ID3D11PixelShader* s_ColorCopyProgram[2] = {NULL};
|
||||
@@ -352,10 +353,10 @@ ID3D11Buffer* &PixelShaderCache::GetConstantBuffer()
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader<PIXELSHADERUID, u8>
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader<PixelShaderUid, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const PIXELSHADERUID &key, const u8 *value, u32 value_size)
|
||||
void Read(const PixelShaderUid &key, const u8 *value, u32 value_size)
|
||||
{
|
||||
PixelShaderCache::InsertByteCode(key, value, value_size);
|
||||
}
|
||||
@@ -414,7 +415,8 @@ void PixelShaderCache::Clear()
|
||||
{
|
||||
for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++)
|
||||
iter->second.Destroy();
|
||||
PixelShaders.clear();
|
||||
PixelShaders.clear();
|
||||
pixel_uid_checker.Invalidate();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
@@ -450,8 +452,14 @@ void PixelShaderCache::Shutdown()
|
||||
|
||||
bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
{
|
||||
PIXELSHADERUID uid;
|
||||
GetPixelShaderId(&uid, dstAlphaMode, components);
|
||||
PixelShaderUid uid;
|
||||
GetPixelShaderUid(uid, dstAlphaMode, API_D3D11, components);
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
PixelShaderCode code;
|
||||
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D11, components);
|
||||
pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p");
|
||||
}
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
@@ -459,7 +467,6 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
|
||||
ValidatePixelShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, dstAlphaMode, components);
|
||||
return (last_entry->shader != NULL);
|
||||
}
|
||||
}
|
||||
@@ -475,15 +482,15 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
|
||||
ValidatePixelShaderIDs(API_D3D11, entry.safe_uid, entry.code, dstAlphaMode, components);
|
||||
return (entry.shader != NULL);
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
const char* code = GeneratePixelShaderCode(dstAlphaMode, API_D3D11, components);
|
||||
PixelShaderCode code;
|
||||
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D11, components);
|
||||
|
||||
D3DBlob* pbytecode;
|
||||
if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode))
|
||||
if (!D3D::CompilePixelShader(code.GetBuffer(), (unsigned int)strlen(code.GetBuffer()), &pbytecode))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return false;
|
||||
@@ -497,15 +504,14 @@ bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging && success)
|
||||
{
|
||||
PixelShaders[uid].code = code;
|
||||
GetSafePixelShaderId(&PixelShaders[uid].safe_uid, dstAlphaMode, components);
|
||||
PixelShaders[uid].code = code.GetBuffer();
|
||||
}
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const void* bytecode, unsigned int bytecodelen)
|
||||
bool PixelShaderCache::InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen)
|
||||
{
|
||||
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
||||
if (shader == NULL)
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(DSTALPHA_MODE dstAlphaMode, u32 components); // TODO: Should be renamed to LoadShader
|
||||
static bool InsertByteCode(const PIXELSHADERUID &uid, const void* bytecode, unsigned int bytecodelen);
|
||||
static bool InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen);
|
||||
|
||||
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
|
||||
static ID3D11Buffer* &GetConstantBuffer();
|
||||
@@ -41,18 +41,19 @@ private:
|
||||
{
|
||||
ID3D11PixelShader* shader;
|
||||
|
||||
PIXELSHADERUIDSAFE safe_uid;
|
||||
std::string code;
|
||||
|
||||
PSCacheEntry() : shader(NULL) {}
|
||||
void Destroy() { SAFE_RELEASE(shader); }
|
||||
};
|
||||
|
||||
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
|
||||
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
||||
|
||||
static PSCache PixelShaders;
|
||||
static const PSCacheEntry* last_entry;
|
||||
static PIXELSHADERUID last_uid;
|
||||
static PixelShaderUid last_uid;
|
||||
|
||||
static UidChecker<PixelShaderUid,PixelShaderCode> pixel_uid_checker;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
@@ -163,10 +163,11 @@ bool PointGeometryShader::SetShader(u32 components, float pointSize,
|
||||
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);
|
||||
static char buffer[16384];
|
||||
ShaderCode code;
|
||||
code.SetBuffer(buffer);
|
||||
GenerateVSOutputStructForGS(code, components, API_D3D11);
|
||||
code.Write("\n%s", POINT_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStream;
|
||||
numTexCoordsStream << xfregs.numTexGen.numTexGens;
|
||||
@@ -179,7 +180,7 @@ bool PointGeometryShader::SetShader(u32 components, float pointSize,
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code, unsigned int(strlen(code)), macros);
|
||||
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);
|
||||
|
||||
@@ -238,7 +238,7 @@ void VertexManager::vFlush()
|
||||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
|
||||
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
|
||||
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||
|
||||
@@ -24,14 +24,15 @@ namespace DX11 {
|
||||
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
|
||||
VERTEXSHADERUID VertexShaderCache::last_uid;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
UidChecker<VertexShaderUid,VertexShaderCode> VertexShaderCache::vertex_uid_checker;
|
||||
|
||||
static ID3D11VertexShader* SimpleVertexShader = NULL;
|
||||
static ID3D11VertexShader* ClearVertexShader = NULL;
|
||||
static ID3D11InputLayout* SimpleLayout = NULL;
|
||||
static ID3D11InputLayout* ClearLayout = NULL;
|
||||
|
||||
LinearDiskCache<VERTEXSHADERUID, u8> g_vs_disk_cache;
|
||||
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
|
||||
|
||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
|
||||
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
|
||||
@@ -57,10 +58,10 @@ ID3D11Buffer* &VertexShaderCache::GetConstantBuffer()
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<VERTEXSHADERUID, u8>
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<VertexShaderUid, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const VERTEXSHADERUID &key, const u8 *value, u32 value_size)
|
||||
void Read(const VertexShaderUid &key, const u8 *value, u32 value_size)
|
||||
{
|
||||
D3DBlob* blob = new D3DBlob(value_size, value);
|
||||
VertexShaderCache::InsertByteCode(key, blob);
|
||||
@@ -176,6 +177,7 @@ void VertexShaderCache::Clear()
|
||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
vshaders.clear();
|
||||
vertex_uid_checker.Invalidate();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
@@ -197,14 +199,20 @@ void VertexShaderCache::Shutdown()
|
||||
|
||||
bool VertexShaderCache::SetShader(u32 components)
|
||||
{
|
||||
VERTEXSHADERUID uid;
|
||||
GetVertexShaderId(&uid, components);
|
||||
VertexShaderUid uid;
|
||||
GetVertexShaderUid(uid, components, API_D3D11);
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
VertexShaderCode code;
|
||||
GenerateVertexShaderCode(code, components, API_D3D11);
|
||||
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
|
||||
}
|
||||
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
ValidateVertexShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, components);
|
||||
return (last_entry->shader != NULL);
|
||||
}
|
||||
}
|
||||
@@ -218,14 +226,14 @@ bool VertexShaderCache::SetShader(u32 components)
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
ValidateVertexShaderIDs(API_D3D11, entry.safe_uid, entry.code, components);
|
||||
return (entry.shader != NULL);
|
||||
}
|
||||
|
||||
const char *code = GenerateVertexShaderCode(components, API_D3D11);
|
||||
VertexShaderCode code;
|
||||
GenerateVertexShaderCode(code, components, API_D3D11);
|
||||
|
||||
D3DBlob* pbytecode = NULL;
|
||||
D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode);
|
||||
D3D::CompileVertexShader(code.GetBuffer(), (int)strlen(code.GetBuffer()), &pbytecode);
|
||||
|
||||
if (pbytecode == NULL)
|
||||
{
|
||||
@@ -239,15 +247,14 @@ bool VertexShaderCache::SetShader(u32 components)
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging && success)
|
||||
{
|
||||
vshaders[uid].code = code;
|
||||
GetSafeVertexShaderId(&vshaders[uid].safe_uid, components);
|
||||
vshaders[uid].code = code.GetBuffer();
|
||||
}
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob)
|
||||
bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob)
|
||||
{
|
||||
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
|
||||
if (shader == NULL)
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
static ID3D11InputLayout* GetSimpleInputLayout();
|
||||
static ID3D11InputLayout* GetClearInputLayout();
|
||||
|
||||
static bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob);
|
||||
static bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob);
|
||||
|
||||
private:
|
||||
struct VSCacheEntry
|
||||
@@ -39,7 +39,6 @@ private:
|
||||
ID3D11VertexShader* shader;
|
||||
D3DBlob* bytecode; // needed to initialize the input layout
|
||||
|
||||
VERTEXSHADERUIDSAFE safe_uid;
|
||||
std::string code;
|
||||
|
||||
VSCacheEntry() : shader(NULL), bytecode(NULL) {}
|
||||
@@ -55,11 +54,13 @@ private:
|
||||
SAFE_RELEASE(bytecode);
|
||||
}
|
||||
};
|
||||
typedef std::map<VERTEXSHADERUID, VSCacheEntry> VSCache;
|
||||
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
||||
|
||||
static VSCache vshaders;
|
||||
static const VSCacheEntry* last_entry;
|
||||
static VERTEXSHADERUID last_uid;
|
||||
static VertexShaderUid last_uid;
|
||||
|
||||
static UidChecker<VertexShaderUid,VertexShaderCode> vertex_uid_checker;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user