Use a common ShaderId class. Start moving shader ID code to GPU/Common

This commit is contained in:
Henrik Rydgard 2015-10-24 23:24:06 +02:00
parent 67cd018aca
commit 92389a4966
16 changed files with 303 additions and 292 deletions

View File

@ -1446,6 +1446,8 @@ add_library(GPU OBJECT
GPU/Common/GPUStateUtils.h
GPU/Common/DrawEngineCommon.cpp
GPU/Common/DrawEngineCommon.h
GPU/Common/ShaderId.cpp
GPU/Common/ShaderId.h
GPU/Common/SplineCommon.cpp
GPU/Common/SplineCommon.h
GPU/Common/SoftwareTransformCommon.cpp

137
GPU/Common/ShaderId.cpp Normal file
View File

@ -0,0 +1,137 @@
#include <string>
#include <sstream>
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/VertexDecoderCommon.h"
std::string VertexShaderDesc(const ShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";
if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";
if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";
if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";
if (id.Bit(VS_BIT_LMODE)) desc << "LM ";
if (id.Bit(VS_BIT_ENABLE_FOG)) desc << "Fog ";
if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";
if (id.Bit(VS_BIT_DO_TEXTURE)) desc << "Tex ";
if (id.Bit(VS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
if (id.Bit(VS_BIT_FLIP_TEXTURE)) desc << "Flip ";
int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);
const char *uvgModes[4] = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " };
int ls0 = id.Bits(VS_BIT_LS0, 2);
int ls1 = id.Bits(VS_BIT_LS1, 2);
if (uvgMode) desc << uvgModes[uvgMode];
if (id.Bit(VS_BIT_ENABLE_BONES)) desc << "Bones:" << (id.Bits(VS_BIT_BONES, 3) + 1) << " ";
// Lights
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
desc << "Light: ";
for (int i = 0; i < 4; i++) {
if (id.Bit(VS_BIT_LIGHT0_ENABLE + i) || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
desc << i << ": ";
desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";
}
}
}
if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
if (id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2)) desc << "TCScale " << id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2) << " ";
if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
// TODO: More...
return desc.str();
}
bool CanUseHardwareTransform(int prim) {
if (!g_Config.bHardwareTransform)
return false;
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
}
void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) {
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
// lmode: && !isModeThrough!?
ShaderID id;
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_IS_THROUGH, gstate.isModeThrough());
id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
id.SetBit(VS_BIT_HAS_COLOR, hasColor);
if (doTexture) {
id.SetBit(VS_BIT_DO_TEXTURE);
id.SetBit(VS_BIT_FLIP_TEXTURE, gstate_c.flipTexture);
id.SetBit(VS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
}
if (useHWTransform) {
id.SetBit(VS_BIT_USE_HW_TRANSFORM);
id.SetBit(VS_BIT_HAS_NORMAL, hasNormal);
// UV generation mode. doShadeMapping is implicitly stored here.
id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());
// The next bits are used differently depending on UVgen mode
if (doTextureProjection) {
id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());
} else if (doShadeMapping) {
id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());
id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());
}
// Bones.
bool enableBones = vertTypeIsSkinningEnabled(vertType);
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
if (enableBones) {
id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
// 2 bits. We should probably send in the weight scalefactor as a uniform instead,
// or simply preconvert all weights to floats.
id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
}
// Okay, d[1] coming up. ==============
if (gstate.isLightingEnabled() || doShadeMapping) {
// doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled.
if (gstate.isLightingEnabled())
id.SetBit(VS_BIT_LIGHTING_ENABLE);
// Light bits
for (int i = 0; i < 4; i++) {
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, gstate.isLightChanEnabled(i) != 0);
if (gstate.isLightChanEnabled(i) || (doShadeMapping && (gstate.getUVLS0() == i || gstate.getUVLS1() == i))) {
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
}
}
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
}
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
if (doTextureProjection && gstate.getUVProjMode() == GE_PROJMAP_UV) {
id.SetBits(VS_BIT_TEXCOORD_FMTSCALE, 2, (vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT); // two bits
} else {
id.SetBit(VS_BIT_HAS_TEXCOORD, hasTexcoord);
}
}
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
*id_out = id;
}

137
GPU/Common/ShaderId.h Normal file
View File

@ -0,0 +1,137 @@
#pragma once
#include "base/basictypes.h"
// TODO: There will be additional bits, indicating that groups of these will be
// sent to the shader and processed there. This will cut down the number of shaders ("ubershader approach")
// This is probably only really worth doing for lighting and bones.
enum {
VS_BIT_LMODE = 0,
VS_BIT_IS_THROUGH = 1,
VS_BIT_ENABLE_FOG = 2,
VS_BIT_HAS_COLOR = 3,
VS_BIT_DO_TEXTURE = 4,
VS_BIT_FLIP_TEXTURE = 5,
VS_BIT_DO_TEXTURE_PROJ = 6,
VS_BIT_USE_HW_TRANSFORM = 8,
VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform
VS_BIT_NORM_REVERSE = 10,
VS_BIT_HAS_TEXCOORD = 11, // 5 free after
VS_BIT_UVGEN_MODE = 16,
VS_BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0
VS_BIT_LS0 = 18, // 2
VS_BIT_LS1 = 20, // 2
VS_BIT_BONES = 22, // 3 should be enough, not 8
VS_BIT_ENABLE_BONES = 30,
VS_BIT_LIGHT0_COMP = 32, // 2 bits
VS_BIT_LIGHT0_TYPE = 34, // 2 bits
VS_BIT_LIGHT1_COMP = 36, // 2 bits
VS_BIT_LIGHT1_TYPE = 38, // 2 bits
VS_BIT_LIGHT2_COMP = 40, // 2 bits
VS_BIT_LIGHT2_TYPE = 42, // 2 bits
VS_BIT_LIGHT3_COMP = 44, // 2 bits
VS_BIT_LIGHT3_TYPE = 46, // 2 bits
VS_BIT_MATERIAL_UPDATE = 48, // 3 bits, 1 free after
VS_BIT_LIGHT0_ENABLE = 52,
VS_BIT_LIGHT1_ENABLE = 53,
VS_BIT_LIGHT2_ENABLE = 54,
VS_BIT_LIGHT3_ENABLE = 55,
VS_BIT_LIGHTING_ENABLE = 56,
VS_BIT_WEIGHT_FMTSCALE = 57, // only two bits, 1 free after
VS_BIT_TEXCOORD_FMTSCALE = 60,
VS_BIT_FLATSHADE = 62, // 1 free after
};
// Local
enum {
FS_BIT_CLEARMODE = 0,
FS_BIT_DO_TEXTURE = 1,
FS_BIT_TEXFUNC = 2, // 3 bits
FS_BIT_TEXALPHA = 5,
FS_BIT_FLIP_TEXTURE = 6,
FS_BIT_SHADER_TEX_CLAMP = 7,
FS_BIT_CLAMP_S = 8,
FS_BIT_CLAMP_T = 9,
FS_BIT_TEXTURE_AT_OFFSET = 10,
FS_BIT_LMODE = 11,
FS_BIT_ALPHA_TEST = 12,
FS_BIT_ALPHA_TEST_FUNC = 13, // 3 bits
FS_BIT_ALPHA_AGAINST_ZERO = 16,
FS_BIT_COLOR_TEST = 17,
FS_BIT_COLOR_TEST_FUNC = 18, // 2 bits
FS_BIT_COLOR_AGAINST_ZERO = 20,
FS_BIT_ENABLE_FOG = 21,
FS_BIT_DO_TEXTURE_PROJ = 22,
FS_BIT_COLOR_DOUBLE = 23,
FS_BIT_STENCIL_TO_ALPHA = 24, // 2 bits
FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE = 26, // 4 bits
FS_BIT_REPLACE_LOGIC_OP_TYPE = 30, // 2 bits
FS_BIT_REPLACE_BLEND = 32, // 3 bits
FS_BIT_BLENDEQ = 35, // 3 bits
FS_BIT_BLENDFUNC_A = 38, // 4 bits
FS_BIT_BLENDFUNC_B = 42,
FS_BIT_FLATSHADE = 46,
};
struct ShaderID {
ShaderID() {
clear();
}
void clear() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0;
}
}
void set_invalid() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0xFFFFFFFF;
}
}
u32 d[2];
bool operator < (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] < other.d[i])
return true;
if (d[i] > other.d[i])
return false;
}
return false;
}
bool operator == (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] != other.d[i])
return false;
}
return true;
}
bool Bit(int bit) const {
return (d[bit >> 5] >> (bit & 31)) & 1;
}
// Does not handle crossing 32-bit boundaries
int Bits(int bit, int count) const {
const int mask = (1 << count) - 1;
return (d[bit >> 5] >> (bit & 31)) & mask;
}
void SetBit(int bit, bool value = true) {
if (value) {
d[bit >> 5] |= 1 << (bit & 31);
}
}
void SetBits(int bit, int count, int value) {
if (value != 0) {
const int mask = (1 << count) - 1;
d[bit >> 5] |= (value & mask) << (bit & 31);
}
}
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
void FromString(std::string src) {
memcpy(d, &(src)[0], sizeof(d));
}
};

View File

@ -314,7 +314,7 @@ static inline LogicOpReplaceType ReplaceLogicOpType() {
// Here we must take all the bits of the gstate that determine what the fragment shader will
// look like, and concatenate them together into an ID.
void ComputeFragmentShaderIDDX9(FragmentShaderIDDX9 *id) {
void ComputeFragmentShaderIDDX9(ShaderID *id) {
int id0 = 0;
int id1 = 0;
if (gstate.isModeClear()) {

View File

@ -19,34 +19,14 @@
#include "Globals.h"
#include "GPU/Common/ShaderId.h"
// TODO: Bench both ways. Result may be different on old vs new hardware though..
// #define DX9_USE_HW_ALPHA_TEST 1
namespace DX9 {
struct FragmentShaderIDDX9 {
FragmentShaderIDDX9() {clear();}
void clear() {d[0] = 0xFFFFFFFF; d[1] = 0xFFFFFFFF;}
u32 d[2];
bool operator < (const FragmentShaderIDDX9 &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] < other.d[i])
return true;
if (d[i] > other.d[i])
return false;
}
return false;
}
bool operator == (const FragmentShaderIDDX9 &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] != other.d[i])
return false;
}
return true;
}
};
void ComputeFragmentShaderIDDX9(FragmentShaderIDDX9 *id);
void ComputeFragmentShaderIDDX9(ShaderID *id);
void GenerateFragmentShaderDX9(char *buffer);
enum StencilValueType {

View File

@ -593,9 +593,9 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
bool useHWTransform = CanUseHardwareTransformDX9(prim);
VertexShaderIDDX9 VSID;
ShaderID VSID;
ComputeVertexShaderIDDX9(&VSID, vertType, useHWTransform);
FragmentShaderIDDX9 FSID;
ShaderID FSID;
ComputeFragmentShaderIDDX9(&FSID);
// Just update uniforms if this is the same shader as last time.

View File

@ -17,11 +17,13 @@
#pragma once
#include "base/basictypes.h"
#include "../../Globals.h"
#include <map>
#include "base/basictypes.h"
#include "Globals.h"
#include "GPU/Directx9/VertexShaderGeneratorDX9.h"
#include "GPU/Directx9/PixelShaderGeneratorDX9.h"
#include "GPU/Common/ShaderId.h"
#include "thin3d/d3dx9_loader.h"
#include "math/lin/matrix4x4.h"
@ -149,8 +151,8 @@ private:
void Clear();
FragmentShaderIDDX9 lastFSID_;
VertexShaderIDDX9 lastVSID_;
ShaderID lastFSID_;
ShaderID lastVSID_;
u32 globalDirty_;
char *codeBuffer_;
@ -158,10 +160,10 @@ private:
VSShader *lastVShader_;
PSShader *lastPShader_;
typedef std::map<FragmentShaderIDDX9, PSShader *> FSCache;
typedef std::map<ShaderID, PSShader *> FSCache;
FSCache fsCache_;
typedef std::map<VertexShaderIDDX9, VSShader *> VSCache;
typedef std::map<ShaderID, VSShader *> VSCache;
VSCache vsCache_;
};

View File

@ -43,7 +43,7 @@ bool CanUseHardwareTransformDX9(int prim) {
}
// prim so we can special case for RECTANGLES :(
void ComputeVertexShaderIDDX9(VertexShaderIDDX9 *id, u32 vertType, bool useHWTransform) {
void ComputeVertexShaderIDDX9(ShaderID *id, u32 vertType, bool useHWTransform) {
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
bool doShadeMapping = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP;

View File

@ -19,6 +19,8 @@
#include "Globals.h"
#include "GPU/Common/ShaderID.h"
namespace DX9 {
// #define USE_BONE_ARRAY
@ -52,7 +54,7 @@ struct VertexShaderIDDX9
bool CanUseHardwareTransformDX9(int prim);
void ComputeVertexShaderIDDX9(VertexShaderIDDX9 *id, u32 vertType, bool useHWTransform);
void ComputeVertexShaderIDDX9(ShaderID *id, u32 vertType, bool useHWTransform);
void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform);
// Collapse to less skinning shaders to reduce shader switching, which is expensive.

View File

@ -32,6 +32,7 @@
#include "Core/Reporting.h"
#include "Core/Config.h"
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/GLES/FragmentShaderGenerator.h"
#include "GPU/GLES/Framebuffer.h"
#include "GPU/GLES/ShaderManager.h"
@ -301,37 +302,6 @@ static inline LogicOpReplaceType ReplaceLogicOpType() {
return LOGICOPTYPE_NORMAL;
}
// Local
enum {
FS_BIT_CLEARMODE = 0,
FS_BIT_DO_TEXTURE = 1,
FS_BIT_TEXFUNC = 2, // 3 bits
FS_BIT_TEXALPHA = 5,
FS_BIT_FLIP_TEXTURE = 6,
FS_BIT_SHADER_TEX_CLAMP = 7,
FS_BIT_CLAMP_S = 8,
FS_BIT_CLAMP_T = 9,
FS_BIT_TEXTURE_AT_OFFSET = 10,
FS_BIT_LMODE = 11,
FS_BIT_ALPHA_TEST = 12,
FS_BIT_ALPHA_TEST_FUNC = 13, // 3 bits
FS_BIT_ALPHA_AGAINST_ZERO = 16,
FS_BIT_COLOR_TEST = 17,
FS_BIT_COLOR_TEST_FUNC = 18, // 2 bits
FS_BIT_COLOR_AGAINST_ZERO = 20,
FS_BIT_ENABLE_FOG = 21,
FS_BIT_DO_TEXTURE_PROJ = 22,
FS_BIT_COLOR_DOUBLE = 23,
FS_BIT_STENCIL_TO_ALPHA = 24, // 2 bits
FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE = 26, // 4 bits
FS_BIT_REPLACE_LOGIC_OP_TYPE = 30, // 2 bits
FS_BIT_REPLACE_BLEND = 32, // 3 bits
FS_BIT_BLENDEQ = 35, // 3 bits
FS_BIT_BLENDFUNC_A = 38, // 4 bits
FS_BIT_BLENDFUNC_B = 42,
FS_BIT_FLATSHADE = 46,
};
static const char *alphaTestFuncs[] = { "NEVER", "ALWAYS", "==", "!=", "<", "<=", ">", ">=" };
std::string FragmentShaderDesc(const ShaderID &id) {

View File

@ -22,73 +22,12 @@
#include <map>
#include "GPU/Common/ShaderCommon.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/GLES/VertexShaderGenerator.h"
#include "GPU/GLES/FragmentShaderGenerator.h"
class Shader;
struct ShaderID {
ShaderID() {
clear();
}
void clear() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0;
}
}
void set_invalid() {
for (size_t i = 0; i < ARRAY_SIZE(d); i++) {
d[i] = 0xFFFFFFFF;
}
}
u32 d[2];
bool operator < (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] < other.d[i])
return true;
if (d[i] > other.d[i])
return false;
}
return false;
}
bool operator == (const ShaderID &other) const {
for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) {
if (d[i] != other.d[i])
return false;
}
return true;
}
bool Bit(int bit) const {
return (d[bit >> 5] >> (bit & 31)) & 1;
}
// Does not handle crossing 32-bit boundaries
int Bits(int bit, int count) const {
const int mask = (1 << count) - 1;
return (d[bit >> 5] >> (bit & 31)) & mask;
}
void SetBit(int bit, bool value = true) {
if (value) {
d[bit >> 5] |= 1 << (bit & 31);
}
}
void SetBits(int bit, int count, int value) {
if (value != 0) {
const int mask = (1 << count) - 1;
d[bit >> 5] |= (value & mask) << (bit & 31);
}
}
void ToString(std::string *dest) const {
dest->resize(sizeof(d));
memcpy(&(*dest)[0], d, sizeof(d));
}
void FromString(std::string src) {
memcpy(d, &(src)[0], sizeof(d));
}
};
// Pre-fetched attrs and uniforms
enum {
ATTR_POSITION = 0,

View File

@ -31,6 +31,7 @@
#include "Core/Config.h"
#include "GPU/GLES/VertexShaderGenerator.h"
#include "GPU/GLES/ShaderManager.h"
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/VertexDecoderCommon.h"
// SDL 1.2 on Apple does not have support for OpenGL 3 and hence needs
@ -43,171 +44,6 @@
#define WRITE p+=sprintf
// TODO: There will be additional bits, indicating that groups of these will be
// sent to the shader and processed there. This will cut down the number of shaders ("ubershader approach")
enum {
VS_BIT_LMODE = 0,
VS_BIT_IS_THROUGH = 1,
VS_BIT_ENABLE_FOG = 2,
VS_BIT_HAS_COLOR = 3,
VS_BIT_DO_TEXTURE = 4,
VS_BIT_FLIP_TEXTURE = 5,
VS_BIT_DO_TEXTURE_PROJ = 6,
VS_BIT_USE_HW_TRANSFORM = 8,
VS_BIT_HAS_NORMAL = 9, // conditioned on hw transform
VS_BIT_NORM_REVERSE = 10,
VS_BIT_HAS_TEXCOORD = 11, // 5 free after
VS_BIT_UVGEN_MODE = 16,
VS_BIT_UVPROJ_MODE = 18, // 2, can overlap with LS0
VS_BIT_LS0 = 18, // 2
VS_BIT_LS1 = 20, // 2
VS_BIT_BONES = 22, // 3 should be enough, not 8
VS_BIT_ENABLE_BONES = 30,
VS_BIT_LIGHT0_COMP = 32, // 2 bits
VS_BIT_LIGHT0_TYPE = 34, // 2 bits
VS_BIT_LIGHT1_COMP = 36, // 2 bits
VS_BIT_LIGHT1_TYPE = 38, // 2 bits
VS_BIT_LIGHT2_COMP = 40, // 2 bits
VS_BIT_LIGHT2_TYPE = 42, // 2 bits
VS_BIT_LIGHT3_COMP = 44, // 2 bits
VS_BIT_LIGHT3_TYPE = 46, // 2 bits
VS_BIT_MATERIAL_UPDATE = 48, // 3 bits, 1 free after
VS_BIT_LIGHT0_ENABLE = 52,
VS_BIT_LIGHT1_ENABLE = 53,
VS_BIT_LIGHT2_ENABLE = 54,
VS_BIT_LIGHT3_ENABLE = 55,
VS_BIT_LIGHTING_ENABLE = 56,
VS_BIT_WEIGHT_FMTSCALE = 57, // only two bits, 1 free after
VS_BIT_TEXCOORD_FMTSCALE = 60,
VS_BIT_FLATSHADE = 62, // 1 free after
};
std::string VertexShaderDesc(const ShaderID &id) {
std::stringstream desc;
desc << StringFromFormat("%08x:%08x ", id.d[1], id.d[0]);
if (id.Bit(VS_BIT_IS_THROUGH)) desc << "THR ";
if (id.Bit(VS_BIT_USE_HW_TRANSFORM)) desc << "HWX ";
if (id.Bit(VS_BIT_HAS_COLOR)) desc << "C ";
if (id.Bit(VS_BIT_HAS_TEXCOORD)) desc << "T ";
if (id.Bit(VS_BIT_HAS_NORMAL)) desc << "N ";
if (id.Bit(VS_BIT_LMODE)) desc << "LM ";
if (id.Bit(VS_BIT_ENABLE_FOG)) desc << "Fog ";
if (id.Bit(VS_BIT_NORM_REVERSE)) desc << "RevN ";
if (id.Bit(VS_BIT_DO_TEXTURE)) desc << "Tex ";
if (id.Bit(VS_BIT_DO_TEXTURE_PROJ)) desc << "TexProj ";
if (id.Bit(VS_BIT_FLIP_TEXTURE)) desc << "Flip ";
int uvgMode = id.Bits(VS_BIT_UVGEN_MODE, 2);
const char *uvgModes[4] = { "UV ", "UVMtx ", "UVEnv ", "UVUnk " };
int ls0 = id.Bits(VS_BIT_LS0, 2);
int ls1 = id.Bits(VS_BIT_LS1, 2);
if (uvgMode) desc << uvgModes[uvgMode];
if (id.Bit(VS_BIT_ENABLE_BONES)) desc << "Bones:" << (id.Bits(VS_BIT_BONES, 3) + 1) << " ";
// Lights
if (id.Bit(VS_BIT_LIGHTING_ENABLE)) {
desc << "Light: ";
for (int i = 0; i < 4; i++) {
if (id.Bit(VS_BIT_LIGHT0_ENABLE + i) || (uvgMode == GE_TEXMAP_ENVIRONMENT_MAP && (ls0 == i || ls1 == i))) {
desc << i << ": ";
desc << "c:" << id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2) << " t:" << id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2) << " ";
}
}
}
if (id.Bits(VS_BIT_MATERIAL_UPDATE, 3)) desc << "MatUp:" << id.Bits(VS_BIT_MATERIAL_UPDATE, 3) << " ";
if (id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2)) desc << "WScale " << id.Bits(VS_BIT_WEIGHT_FMTSCALE, 2) << " ";
if (id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2)) desc << "TCScale " << id.Bits(VS_BIT_TEXCOORD_FMTSCALE, 2) << " ";
if (id.Bit(VS_BIT_FLATSHADE)) desc << "Flat ";
// TODO: More...
return desc.str();
}
bool CanUseHardwareTransform(int prim) {
if (!g_Config.bHardwareTransform)
return false;
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
}
void ComputeVertexShaderID(ShaderID *id_out, u32 vertType, bool useHWTransform) {
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP);
bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT && !gstate.isModeClear();
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
bool hasNormal = (vertType & GE_VTYPE_NRM_MASK) != 0;
bool hasTexcoord = (vertType & GE_VTYPE_TC_MASK) != 0;
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
// lmode: && !isModeThrough!?
ShaderID id;
id.SetBit(VS_BIT_LMODE, lmode);
id.SetBit(VS_BIT_IS_THROUGH, gstate.isModeThrough());
id.SetBit(VS_BIT_ENABLE_FOG, enableFog);
id.SetBit(VS_BIT_HAS_COLOR, hasColor);
if (doTexture) {
id.SetBit(VS_BIT_DO_TEXTURE);
id.SetBit(VS_BIT_FLIP_TEXTURE, gstate_c.flipTexture);
id.SetBit(VS_BIT_DO_TEXTURE_PROJ, doTextureProjection);
}
if (useHWTransform) {
id.SetBit(VS_BIT_USE_HW_TRANSFORM);
id.SetBit(VS_BIT_HAS_NORMAL, hasNormal);
// UV generation mode. doShadeMapping is implicitly stored here.
id.SetBits(VS_BIT_UVGEN_MODE, 2, gstate.getUVGenMode());
// The next bits are used differently depending on UVgen mode
if (doTextureProjection) {
id.SetBits(VS_BIT_UVPROJ_MODE, 2, gstate.getUVProjMode());
} else if (doShadeMapping) {
id.SetBits(VS_BIT_LS0, 2, gstate.getUVLS0());
id.SetBits(VS_BIT_LS1, 2, gstate.getUVLS1());
}
// Bones.
bool enableBones = vertTypeIsSkinningEnabled(vertType);
id.SetBit(VS_BIT_ENABLE_BONES, enableBones);
if (enableBones) {
id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1);
// 2 bits. We should probably send in the weight scalefactor as a uniform instead,
// or simply preconvert all weights to floats.
id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT);
}
// Okay, d[1] coming up. ==============
if (gstate.isLightingEnabled() || doShadeMapping) {
// doShadeMapping is stored as UVGenMode, so this is enough for isLightingEnabled.
if (gstate.isLightingEnabled())
id.SetBit(VS_BIT_LIGHTING_ENABLE);
// Light bits
for (int i = 0; i < 4; i++) {
id.SetBit(VS_BIT_LIGHT0_ENABLE + i, gstate.isLightChanEnabled(i) != 0);
if (gstate.isLightChanEnabled(i) || (doShadeMapping && (gstate.getUVLS0() == i || gstate.getUVLS1() == i))) {
id.SetBits(VS_BIT_LIGHT0_COMP + 4 * i, 2, gstate.getLightComputation(i));
id.SetBits(VS_BIT_LIGHT0_TYPE + 4 * i, 2, gstate.getLightType(i));
}
}
id.SetBits(VS_BIT_MATERIAL_UPDATE, 3, gstate.getMaterialUpdate() & 7);
}
id.SetBit(VS_BIT_NORM_REVERSE, gstate.areNormalsReversed());
if (doTextureProjection && gstate.getUVProjMode() == GE_PROJMAP_UV) {
id.SetBits(VS_BIT_TEXCOORD_FMTSCALE, 2, (vertType & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT); // two bits
} else {
id.SetBit(VS_BIT_HAS_TEXCOORD, hasTexcoord);
}
}
id.SetBit(VS_BIT_FLATSHADE, doFlatShading);
*id_out = id;
}
static const char * const boneWeightAttrDecl[9] = {
"#ERROR#",
"attribute mediump float w1;\n",

View File

@ -187,6 +187,7 @@
<ClInclude Include="Common\IndexGenerator.h" />
<ClInclude Include="Common\PostShader.h" />
<ClInclude Include="Common\ShaderCommon.h" />
<ClInclude Include="Common\ShaderId.h" />
<ClInclude Include="Common\SoftwareTransformCommon.h" />
<ClInclude Include="Common\SplineCommon.h" />
<ClInclude Include="Common\TextureDecoderNEON.h">
@ -250,6 +251,7 @@
<ClCompile Include="Common\GPUDebugInterface.cpp" />
<ClCompile Include="Common\IndexGenerator.cpp" />
<ClCompile Include="Common\PostShader.cpp" />
<ClCompile Include="Common\ShaderId.cpp" />
<ClCompile Include="Common\SplineCommon.cpp" />
<ClCompile Include="Common\TextureDecoderNEON.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>

View File

@ -198,6 +198,7 @@
<ClInclude Include="Common\ShaderCommon.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\ShaderId.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -377,5 +378,6 @@
<ClCompile Include="GLES\GLStateCache.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="Common\ShaderId.cpp" />
</ItemGroup>
</Project>

View File

@ -47,6 +47,7 @@ SOURCES += $$P/GPU/GeDisasm.cpp \ # GPU
$$P/GPU/Debugger/*.cpp \
$$P/GPU/Common/DepalettizeShaderCommon.cpp \
$$P/GPU/Common/GPUDebugInterface.cpp \
$$P/GPU/Common/ShaderId.cpp \
$$P/GPU/Common/IndexGenerator.cpp \
$$P/GPU/Common/TextureDecoder.cpp \
$$P/GPU/Common/TextureScalerCommon.cpp \

View File

@ -156,6 +156,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Common/FramebufferCommon.cpp \
$(SRC)/GPU/Common/GPUDebugInterface.cpp \
$(SRC)/GPU/Common/IndexGenerator.cpp.arm \
$(SRC)/GPU/Common/ShaderId.cpp.arm \
$(SRC)/GPU/Common/SoftwareTransformCommon.cpp.arm \
$(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \
$(SRC)/GPU/Common/TextureCacheCommon.cpp.arm \