HW transform: Avoid 4x3 matrices for GLES 2.0 compat. Add option to turn hw transform on.

This commit is contained in:
Henrik Rydgard 2012-12-21 11:08:54 +01:00
parent 4d4370232c
commit 4bf2e52623
8 changed files with 57 additions and 19 deletions

View File

@ -57,6 +57,7 @@ void CConfig::Load(const char *iniFileName)
graphics->Get("DisplayFramebuffer", &bDisplayFramebuffer, false);
graphics->Get("WindowZoom", &iWindowZoom, 1);
graphics->Get("BufferedRendering", &bBufferedRendering, true);
graphics->Get("HardwareTransform", &bHardwareTransform, false);
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Get("Enable", &bEnableSound, true);
@ -93,6 +94,7 @@ void CConfig::Save()
graphics->Set("DisplayFramebuffer", bDisplayFramebuffer);
graphics->Set("WindowZoom", iWindowZoom);
graphics->Set("BufferedRendering", bBufferedRendering);
graphics->Set("HardwareTransform", bHardwareTransform);
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
sound->Set("Enable", bEnableSound);

View File

@ -41,7 +41,10 @@ public:
bool bSpeedLimit;
bool bConfirmOnQuit;
bool bIgnoreBadMemAccess;
// GFX
bool bDisplayFramebuffer;
bool bHardwareTransform;
bool bBufferedRendering;
bool bDrawWireframe;

View File

@ -153,6 +153,27 @@ static void SetColorUniform3ExtraFloat(int uniform, u32 color, float extra)
glUniform4fv(uniform, 1, col);
}
static void SetMatrix4x3(int uniform, const float *m4x3) {
float m4x4[16];
m4x4[0] = m4x3[0];
m4x4[1] = m4x3[1];
m4x4[2] = m4x3[2];
m4x4[3] = 0.0f;
m4x4[4] = m4x3[3];
m4x4[5] = m4x3[4];
m4x4[6] = m4x3[5];
m4x4[7] = 0.0f;
m4x4[8] = m4x3[6];
m4x4[9] = m4x3[7];
m4x4[10] = m4x3[8];
m4x4[11] = 0.0f;
m4x4[12] = m4x3[9];
m4x4[13] = m4x3[10];
m4x4[14] = m4x3[11];
m4x4[15] = 1.0f;
glUniformMatrix4fv(uniform, 1, GL_FALSE, m4x4);
}
void LinkedShader::use() {
glUseProgram(program);
glUniform1i(u_tex, 0);
@ -203,17 +224,17 @@ void LinkedShader::use() {
// Transform
if (u_world != -1 && (dirtyUniforms & DIRTY_WORLDMATRIX)) {
glUniformMatrix4x3fv(u_world, 1, GL_FALSE, gstate.worldMatrix);
SetMatrix4x3(u_world, gstate.worldMatrix);
}
if (u_view != -1 && (dirtyUniforms & DIRTY_VIEWMATRIX)) {
glUniformMatrix4x3fv(u_view, 1, GL_FALSE, gstate.viewMatrix);
SetMatrix4x3(u_view, gstate.viewMatrix);
}
if (u_texmtx != -1 && (dirtyUniforms & DIRTY_TEXMATRIX)) {
glUniformMatrix4x3fv(u_texmtx, 1, GL_FALSE, gstate.tgenMatrix);
SetMatrix4x3(u_texmtx, gstate.tgenMatrix);
}
for (int i = 0; i < 8; i++) {
if (u_bone[i] != -1 && (dirtyUniforms & (DIRTY_BONEMATRIX0 << i))) {
glUniformMatrix4x3fv(u_bone[i], 1, GL_FALSE, gstate.boneMatrix + 12 * i);
SetMatrix4x3(u_bone[i], gstate.boneMatrix + 12 * i);
}
}

View File

@ -26,6 +26,7 @@
#include "../ge_constants.h"
#include "../GPUState.h"
#include "../../Core/Config.h"
#include "VertexShaderGenerator.h"
@ -44,8 +45,9 @@ static char buffer[16384];
bool CanUseHardwareTransform(int prim)
{
return !gstate.isModeThrough() && false; // prim != GE_PRIM_RECTANGLES;
//return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
if (!g_Config.bHardwareTransform)
return false;
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
}
// prim so we can special case for RECTANGLES :(
@ -192,16 +194,16 @@ char *GenerateVertexShader(int prim)
if (hwXForm) {
// When transforming by hardware, we need a great deal more uniforms...
WRITE(p, "uniform mat4x3 u_world;\n");
WRITE(p, "uniform mat4x3 u_view;\n");
WRITE(p, "uniform mat4 u_world;\n");
WRITE(p, "uniform mat4 u_view;\n");
if (gstate.getUVGenMode() == 0)
WRITE(p, "uniform vec4 u_uvscaleoffset;\n");
else if (gstate.getUVGenMode() == 1)
WRITE(p, "uniform mat4x3 u_texmtx;\n");
WRITE(p, "uniform mat4 u_texmtx;\n");
if ((gstate.vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) {
int numBones = 1 + ((gstate.vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT);
for (int i = 0; i < numBones; i++) {
WRITE(p, "uniform mat4x3 u_bone%i;\n", i);
WRITE(p, "uniform mat4 u_bone%i;\n", i);
}
}
if (gstate.lightingEnable & 1) {
@ -258,9 +260,9 @@ char *GenerateVertexShader(int prim)
// Step 1: World Transform / Skinning
if ((gstate.vertType & GE_VTYPE_WEIGHT_MASK) == GE_VTYPE_WEIGHT_NONE) {
// No skinning, just standard T&L.
WRITE(p, " vec3 worldpos = u_world * vec4(a_position, 1.0);\n");
WRITE(p, " vec3 worldpos = (u_world * vec4(a_position, 1.0)).xyz;\n");
if (hasNormal)
WRITE(p, " vec3 worldnormal = normalize(u_world * vec4(a_normal, 0.0));\n");
WRITE(p, " vec3 worldnormal = (u_world * vec4(a_normal, 0.0)).xyz;\n");
} else {
WRITE(p, " vec3 worldpos = vec3(0.0, 0.0, 0.0);\n");
if (hasNormal)
@ -271,15 +273,17 @@ char *GenerateVertexShader(int prim)
// workaround for "cant do .x of scalar" issue
if (numWeights == 1 && i == 0) weightAttr = "a_weight0123";
if (numWeights == 5 && i == 4) weightAttr = "a_weight4567";
WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position, 1.0));\n", weightAttr, i);
WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position, 1.0)).xyz;\n", weightAttr, i);
if (hasNormal)
WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0));\n", weightAttr, i);
WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i);
}
// Finally, multiply by world matrix (yes, we have to).
WRITE(p, " worldpos = u_world * vec4(worldpos, 1.0);\n");
WRITE(p, " worldpos = (u_world * vec4(worldpos, 1.0)).xyz;\n");
if (hasNormal)
WRITE(p, " worldnormal = u_world * vec4(worldnormal, 0.0);\n");
WRITE(p, " worldnormal = (u_world * vec4(worldnormal, 0.0)).xyz;\n");
}
if (hasNormal)
WRITE(p, " worldnormal = normalize(worldnormal);\n");
// Step 2: Color/Lighting
if (hasColor) {
@ -395,7 +399,7 @@ char *GenerateVertexShader(int prim)
}
}
// Step 4: Final view and projection transforms.
WRITE(p, " gl_Position = u_proj * vec4(u_view * vec4(worldpos, 1.0), 1.0);\n");
WRITE(p, " gl_Position = u_proj * (u_view * vec4(worldpos, 1.0));\n");
}
if (gstate.isFogEnabled())
WRITE(p, " v_depth = gl_Position.z;\n");

View File

@ -353,6 +353,11 @@ namespace MainWindow
UpdateMenus();
break;
case ID_OPTIONS_HARDWARETRANSFORM:
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
UpdateMenus();
break;
case ID_FILE_EXIT:
DestroyWindow(hWnd);
break;
@ -632,6 +637,7 @@ namespace MainWindow
CHECKITEM(ID_OPTIONS_BUFFEREDRENDERING, g_Config.bBufferedRendering);
CHECKITEM(ID_OPTIONS_SHOWDEBUGSTATISTICS, g_Config.bShowDebugStats);
CHECKITEM(ID_OPTIONS_WIREFRAME, g_Config.bDrawWireframe);
CHECKITEM(ID_OPTIONS_HARDWARETRANSFORM, g_Config.bHardwareTransform);
BOOL enable = !Core_IsStepping();
EnableMenuItem(menu,ID_EMULATION_RUN,enable);

View File

@ -214,6 +214,7 @@ BEGIN
MENUITEM "&Toggle Full Screen\tF12", ID_OPTIONS_FULLSCREEN
MENUITEM "&Display Raw Framebuffer", ID_OPTIONS_DISPLAYRAWFRAMEBUFFER
MENUITEM "&Buffered Rendering\tF5", ID_OPTIONS_BUFFEREDRENDERING
MENUITEM "&Hardware Transform", ID_OPTIONS_HARDWARETRANSFORM
MENUITEM "&Wireframe (experimental)", ID_OPTIONS_WIREFRAME
MENUITEM "&Show Debug Statistics", ID_OPTIONS_SHOWDEBUGSTATISTICS
MENUITEM SEPARATOR

View File

@ -244,13 +244,14 @@
#define ID_CPU_FASTINTERPRETER 40121
#define ID_OPTIONS_SHOWDEBUGSTATISTICS 40122
#define ID_OPTIONS_WIREFRAME 40123
#define ID_OPTIONS_HARDWARETRANSFORM 40124
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 232
#define _APS_NEXT_COMMAND_VALUE 40124
#define _APS_NEXT_COMMAND_VALUE 40125
#define _APS_NEXT_CONTROL_VALUE 1162
#define _APS_NEXT_SYMED_VALUE 101
#endif

View File

@ -241,7 +241,7 @@ void SettingsScreen::render() {
int y = 50;
UICheckBox(GEN_ID, x, y += 50, "Enable Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound);
UICheckBox(GEN_ID, x, y += 50, "Buffered Rendering (may fix flicker)", ALIGN_TOPLEFT, &g_Config.bBufferedRendering);
UICheckBox(GEN_ID, x, y += 50, "Hardware Transform (experimental)", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
bool useFastInt = g_Config.iCpuCore == CPU_FASTINTERPRETER;
UICheckBox(GEN_ID, x, y += 50, "Slightly faster interpreter (may crash)", ALIGN_TOPLEFT, &useFastInt);