diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h index 3da3185a76..920a0b2dea 100644 --- a/GPU/Common/VertexDecoderCommon.h +++ b/GPU/Common/VertexDecoderCommon.h @@ -285,6 +285,30 @@ public: } } + void ReadColor0_8888(u8 color[4]) const { + switch (decFmt_.c0fmt) { + case DEC_U8_4: + { + const u8 *b = (const u8 *)(data_ + decFmt_.c0off); + for (int i = 0; i < 4; i++) + color[i] = b[i]; + } + break; + case DEC_FLOAT_4: + { + const float *f = (const float *)(data_ + decFmt_.c0off); + for (int i = 0; i < 4; i++) + color[i] = f[i] * 255.0f; + } + break; + default: + ERROR_LOG_REPORT_ONCE(fmt, G3D, "Reader: Unsupported C0 Format %d", decFmt_.c0fmt); + memset(color, 0, sizeof(float) * 4); + break; + } + } + + void ReadColor1(float color[3]) const { switch (decFmt_.c1fmt) { case DEC_U8_4: diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 6281948d3c..45032db21a 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -616,7 +616,7 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) { break; // Discard AA lines in Summon Night 5 - if ((prim == GE_PRIM_LINES) && gstate.isAntiAliasEnabled() && gstate.isSkinningEnabled()) + if ((prim == GE_PRIM_LINES) && gstate.isAntiAliasEnabled() && vertTypeIsSkinningEnabled(gstate.vertType)) break; // This also make skipping drawing very effective. diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 500ddbb862..fc466d97b6 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -101,7 +101,7 @@ D3DXHANDLE LinkedShaderDX9::GetConstantByName(LPCSTR pName) { return ret; } -LinkedShaderDX9::LinkedShaderDX9(VSShader *vs, PSShader *fs, bool useHWTransform) +LinkedShaderDX9::LinkedShaderDX9(VSShader *vs, PSShader *fs, u32 vertType, bool useHWTransform) :dirtyUniforms(0), useHWTransform_(useHWTransform) { INFO_LOG(G3D, "Linked shader: vs %i fs %i", (int)vs->shader, (int)fs->shader); @@ -124,7 +124,7 @@ LinkedShaderDX9::LinkedShaderDX9(VSShader *vs, PSShader *fs, bool useHWTransform u_texmtx = GetConstantByName("u_texmtx"); if (gstate.getWeightMask() != 0) - numBones = TranslateNumBonesDX9(gstate.getNumBoneWeights()); + numBones = TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType)); else numBones = 0; @@ -560,7 +560,7 @@ void ShaderManagerDX9::EndFrame() { // disables vertex arrays } -LinkedShaderDX9 *ShaderManagerDX9::ApplyShader(int prim) { +LinkedShaderDX9 *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) { if (globalDirty_) { if (lastShader_) lastShader_->dirtyUniforms |= globalDirty_; @@ -640,7 +640,7 @@ LinkedShaderDX9 *ShaderManagerDX9::ApplyShader(int prim) { shaderSwitchDirty_ = 0; if (ls == NULL) { - ls = new LinkedShaderDX9(vs, fs, vs->UseHWTransform()); // This does "use" automatically + ls = new LinkedShaderDX9(vs, fs, vertType, vs->UseHWTransform()); // This does "use" automatically const LinkedShaderCacheEntry entry(vs, fs, ls); linkedShaderCache_.push_back(entry); } else { diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index 78510a758e..17c8ef8b84 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -42,7 +42,7 @@ protected: void SetFloatArray(D3DXHANDLE uniform, const float* pArray, int len); void SetFloat(D3DXHANDLE uniform, float value); public: - LinkedShaderDX9(VSShader *vs, PSShader *fs, bool useHWTransform); + LinkedShaderDX9(VSShader *vs, PSShader *fs, u32 vertType, bool useHWTransform); ~LinkedShaderDX9(); void use(); @@ -189,7 +189,7 @@ public: ~ShaderManagerDX9(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - LinkedShaderDX9 *ApplyShader(int prim); + LinkedShaderDX9 *ApplyShader(int prim, u32 vertType); void DirtyShader(); void DirtyUniform(u32 what) { globalDirty_ |= what; diff --git a/GPU/Directx9/TransformPipelineDX9.cpp b/GPU/Directx9/TransformPipelineDX9.cpp index 37f232ef96..84e0b613c4 100644 --- a/GPU/Directx9/TransformPipelineDX9.cpp +++ b/GPU/Directx9/TransformPipelineDX9.cpp @@ -1135,7 +1135,7 @@ void TransformDrawEngineDX9::DoFlush() { GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); - LinkedShaderDX9 *program = shaderManager_->ApplyShader(prim); + LinkedShaderDX9 *program = shaderManager_->ApplyShader(prim, lastVType_); if (program->useHWTransform_) { LPDIRECT3DVERTEXBUFFER9 vb_ = NULL; diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index c4e44c63e1..00e2343660 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -88,7 +88,7 @@ void ComputeVertexShaderIDDX9(VertexShaderIDDX9 *id, int prim, bool useHWTransfo // Bones if (hasBones) - id->d[0] |= (TranslateNumBonesDX9(gstate.getNumBoneWeights()) - 1) << 22; + id->d[0] |= (TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType)) - 1) << 22; // Okay, d[1] coming up. ============== @@ -104,7 +104,7 @@ void ComputeVertexShaderIDDX9(VertexShaderIDDX9 *id, int prim, bool useHWTransfo } } id->d[1] |= gstate.isLightingEnabled() << 24; - id->d[1] |= (gstate.getWeightMask() >> GE_VTYPE_WEIGHT_SHIFT) << 25; + id->d[1] |= (vertTypeGetWeightMask(vertType) >> GE_VTYPE_WEIGHT_SHIFT) << 25; } } @@ -172,7 +172,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) { if (gstate.getUVGenMode() == 1) WRITE(p, "float4x4 u_texmtx;\n"); if (gstate.getWeightMask() != GE_VTYPE_WEIGHT_NONE) { - int numBones = TranslateNumBonesDX9(gstate.getNumBoneWeights()); + int numBones = TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType)); #ifdef USE_BONE_ARRAY WRITE(p, "float4x4 u_bone[%i];\n", numBones); #else @@ -223,7 +223,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) { WRITE(p, " \n"); WRITE(p, " { \n"); if (gstate.getWeightMask() != GE_VTYPE_WEIGHT_NONE) { - WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBonesDX9(gstate.getNumBoneWeights())]); + WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType))]); } if (doTexture) { if (doTextureProjection) @@ -286,7 +286,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) { else WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } else { - int numWeights = TranslateNumBonesDX9(gstate.getNumBoneWeights()); + int numWeights = TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType)); static const char *rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; const char *factor = rescale[gstate.getWeightMask() >> GE_VTYPE_WEIGHT_SHIFT]; diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index c30fed6202..d1bd765ebb 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -675,7 +675,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { break; // Discard AA lines in Summon Night 5 - if ((prim == GE_PRIM_LINES) && gstate.isAntiAliasEnabled() && gstate.isSkinningEnabled()) + if ((prim == GE_PRIM_LINES) && gstate.isAntiAliasEnabled() && vertTypeIsSkinningEnabled(gstate.vertType)) break; // This also make skipping drawing very effective. @@ -759,8 +759,8 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); } - if (gstate.isSkinningEnabled()) { - DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", gstate.getNumBoneWeights()); + if (vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); } // TODO: Get rid of this old horror... @@ -799,8 +799,8 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) { if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); } - if (gstate.isSkinningEnabled()) { - DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", gstate.getNumBoneWeights()); + if (vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); } int sp_ucount = data & 0xFF; diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index 28a5a480d8..74116aad53 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -72,7 +72,7 @@ Shader::~Shader() { glDeleteShader(shader); } -LinkedShader::LinkedShader(Shader *vs, Shader *fs, bool useHWTransform) +LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform) : useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) { program = glCreateProgram(); glAttachShader(program, vs->shader); @@ -118,8 +118,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, bool useHWTransform) u_view = glGetUniformLocation(program, "u_view"); u_world = glGetUniformLocation(program, "u_world"); u_texmtx = glGetUniformLocation(program, "u_texmtx"); - if (gstate.getWeightMask() != GE_VTYPE_WEIGHT_NONE) - numBones = TranslateNumBones(gstate.getNumBoneWeights()); + if (vertTypeGetWeightMask(vertType) != GE_VTYPE_WEIGHT_NONE) + numBones = TranslateNumBones(vertTypeGetNumBoneWeights(vertType)); else numBones = 0; @@ -499,7 +499,7 @@ void ShaderManager::EndFrame() { // disables vertex arrays } -LinkedShader *ShaderManager::ApplyShader(int prim) { +LinkedShader *ShaderManager::ApplyShader(int prim, u32 vertType) { if (globalDirty_) { if (lastShader_) lastShader_->dirtyUniforms |= globalDirty_; @@ -511,7 +511,7 @@ LinkedShader *ShaderManager::ApplyShader(int prim) { VertexShaderID VSID; FragmentShaderID FSID; - ComputeVertexShaderID(&VSID, prim, useHWTransform); + ComputeVertexShaderID(&VSID, vertType, prim, useHWTransform); ComputeFragmentShaderID(&FSID); // Just update uniforms if this is the same shader as last time. @@ -532,7 +532,7 @@ LinkedShader *ShaderManager::ApplyShader(int prim) { Shader *vs; if (vsIter == vsCache_.end()) { // Vertex shader not in cache. Let's compile it. - GenerateVertexShader(prim, codeBuffer_, useHWTransform); + GenerateVertexShader(prim, vertType, codeBuffer_, useHWTransform); vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, useHWTransform); if (vs->Failed()) { @@ -545,7 +545,7 @@ LinkedShader *ShaderManager::ApplyShader(int prim) { // next time and we'll do this over and over... // Can still work with software transform. - GenerateVertexShader(prim, codeBuffer_, false); + GenerateVertexShader(prim, vertType, codeBuffer_, false); vs = new Shader(codeBuffer_, GL_VERTEX_SHADER, false); } @@ -579,7 +579,7 @@ LinkedShader *ShaderManager::ApplyShader(int prim) { shaderSwitchDirty_ = 0; if (ls == NULL) { - ls = new LinkedShader(vs, fs, vs->UseHWTransform()); // This does "use" automatically + ls = new LinkedShader(vs, fs, vertType, vs->UseHWTransform()); // This does "use" automatically const LinkedShaderCacheEntry entry(vs, fs, ls); linkedShaderCache_.push_back(entry); } else { diff --git a/GPU/GLES/ShaderManager.h b/GPU/GLES/ShaderManager.h index fbfc7559ca..2679e12db8 100644 --- a/GPU/GLES/ShaderManager.h +++ b/GPU/GLES/ShaderManager.h @@ -28,7 +28,7 @@ class Shader; class LinkedShader { public: - LinkedShader(Shader *vs, Shader *fs, bool useHWTransform); + LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform); ~LinkedShader(); void use(); @@ -154,7 +154,7 @@ public: ~ShaderManager(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - LinkedShader *ApplyShader(int prim); + LinkedShader *ApplyShader(int prim, u32 vertType); void DirtyShader(); void DirtyUniform(u32 what) { globalDirty_ |= what; diff --git a/GPU/GLES/Spline.cpp b/GPU/GLES/Spline.cpp index 5550795104..e38a0f341a 100644 --- a/GPU/GLES/Spline.cpp +++ b/GPU/GLES/Spline.cpp @@ -17,6 +17,120 @@ #include "TransformPipeline.h" #include "Core/MemMap.h" +#include "GPU/Math3D.h" + +// PSP compatible format so we can use the end of the pipeline +struct SimpleVertex { + float uv[2]; + u8 color[4]; + float nrm[3]; + float pos[3]; +}; + +// This normalizes a set of vertices in any format to SimpleVertex format, by processing away morphing AND skinning. +// The rest of the transform pipeline like lighting will go as normal, either hardware or software. +// The implementation is initially a bit inefficient but shouldn't be a big deal. +// An intermediate buffer of not-easy-to-predict size is stored at bufPtr. +u32 TransformDrawEngine::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType) { + // First, decode the vertices into a GPU compatible format. This step can be eliminated but will need a separate + // implementation of the vertex decoder. + VertexDecoder *dec = GetVertexDecoder(vertType); + dec->DecodeVerts(bufPtr, inPtr, lowerBound, upperBound); + + // OK, morphing eliminated but bones still remain to be taken care of. + // Let's do a partial software transform where we only do skinning. + + VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType); + + SimpleVertex *sverts = (SimpleVertex *)outPtr; + + const u8 defaultColor[4] = { + gstate.getMaterialAmbientR(), + gstate.getMaterialAmbientG(), + gstate.getMaterialAmbientB(), + gstate.getMaterialAmbientA(), + }; + + // Let's have two separate loops, one for non skinning and one for skinning. + if ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { + int numBoneWeights = vertTypeGetNumBoneWeights(vertType); + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } + + if (vertType & GE_VTYPE_COL_MASK) { + reader.ReadColor0_8888(sv.color); + } else { + memcpy(sv.color, defaultColor, 4); + } + + float nrm[3], pos[3]; + float bnrm[3], bpos[3]; + + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tesselation anyway, not sure if any need to supply + reader.ReadNrm(nrm); + } else { + nrm[0] = 0; + nrm[1] = 0; + nrm[2] = 1.0f; + } + reader.ReadPos(pos); + + // Apply skinning transform directly + float weights[8]; + reader.ReadWeights(weights); + // Skinning + Vec3f psum(0,0,0); + Vec3f nsum(0,0,0); + for (int i = 0; i < numBoneWeights; i++) { + if (weights[i] != 0.0f) { + Vec3ByMatrix43(bpos, pos, gstate.boneMatrix+i*12); + Vec3f tpos(bpos); + psum += tpos * weights[i]; + + Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix+i*12); + Vec3f tnorm(bnrm); + nsum += tnorm * weights[i]; + } + } + memcpy(sv.pos, &psum[0], 12); + memcpy(sv.nrm, &nsum[0], 12); + } + } else { + for (int i = lowerBound; i <= upperBound; i++) { + reader.Goto(i); + SimpleVertex &sv = sverts[i]; + if (vertType & GE_VTYPE_TC_MASK) { + reader.ReadUV(sv.uv); + } else { + sv.uv[0] = 0; // This will get filled in during tesselation + sv.uv[1] = 0; + } + if (vertType & GE_VTYPE_COL_MASK) { + reader.ReadColor0_8888(sv.color); + } else { + memcpy(sv.color, defaultColor, 4); + } + if (vertType & GE_VTYPE_NRM_MASK) { + // Normals are generated during tesselation anyway, not sure if any need to supply + reader.ReadNrm(sv.nrm); + } else { + sv.nrm[0] = 0; + sv.nrm[1] = 0; + sv.nrm[2] = 1.0f; + } + reader.ReadPos(sv.pos); + } + } + + // Okay, there we are! Return the new type (but keep the index bits) + return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & GE_VTYPE_IDX_MASK); +} + // Just to get something on the screen, we'll just not subdivide correctly. void TransformDrawEngine::DrawBezier(int ucount, int vcount) { @@ -84,14 +198,15 @@ void TransformDrawEngine::DrawBezier(int ucount, int vcount) { // We decode all vertices into a common format for easy interpolation and stuff. // Not fast but can be optimized later. struct HWSplinePatch { - u8 *points[16]; + SimpleVertex *points[16]; int type; // We need to generate both UVs and normals later... // float u0, v0, u1, v1; }; -static void CopyTriangle(u8 *&dest, u8 *v1, u8 *v2, u8 * v3, int vertexSize) { +static void CopyTriangle(u8 *&dest, SimpleVertex *v1, SimpleVertex *v2, SimpleVertex* v3) { + int vertexSize = sizeof(SimpleVertex); memcpy(dest, v1, vertexSize); dest += vertexSize; memcpy(dest, v2, vertexSize); @@ -100,6 +215,7 @@ static void CopyTriangle(u8 *&dest, u8 *v1, u8 *v2, u8 * v3, int vertexSize) { dest += vertexSize; } + void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, u32 vertex_type) { Flush(); @@ -108,13 +224,6 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int return; } - // We're not actually going to decode, only reshuffle. - VertexDecoder *vdecoder = GetVertexDecoder(vertex_type); - - int undecodedVertexSize = vdecoder->VertexSize(); - - const DecVtxFormat& vtxfmt = vdecoder->GetDecVtxFmt(); - u16 index_lower_bound = 0; u16 index_upper_bound = count_u * count_v - 1; bool indices_16bit = (vertex_type & GE_VTYPE_IDX_MASK) == GE_VTYPE_IDX_16BIT; @@ -123,6 +232,20 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int if (indices) GetIndexBounds(indices, count_u*count_v, vertex_type, &index_lower_bound, &index_upper_bound); + // Simplify away bones and morph before proceeding + SimpleVertex *simplified_control_points = (SimpleVertex *)(decoded + 65536 * 12); + u8 *temp_buffer = decoded + 65536 * 24; + + vertex_type = NormalizeVertices((u8 *)simplified_control_points, temp_buffer, (u8 *)control_points, index_lower_bound, index_upper_bound, vertex_type); + + VertexDecoder *vdecoder = GetVertexDecoder(vertex_type); + + int vertexSize = vdecoder->VertexSize(); + if (vertexSize != sizeof(SimpleVertex)) { + ERROR_LOG(G3D, "Something went really wrong, vertex size: %i vs %i", vertexSize, sizeof(SimpleVertex)); + } + const DecVtxFormat& vtxfmt = vdecoder->GetDecVtxFmt(); + int num_patches_u = count_u - 3; int num_patches_v = count_v - 3; @@ -135,9 +258,9 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int for (int point = 0; point < 16; ++point) { int idx = (patch_u + point%4) + (patch_v + point/4) * count_u; if (indices) - patch.points[point] = (u8 *)control_points + undecodedVertexSize * (indices_16bit ? indices16[idx] : indices8[idx]); + patch.points[point] = simplified_control_points + (indices_16bit ? indices16[idx] : indices8[idx]); else - patch.points[point] = (u8 *)control_points + undecodedVertexSize * idx; + patch.points[point] = simplified_control_points + idx; } patch.type = (type_u | (type_v << 2)); if (patch_u != 0) patch.type &= ~START_OPEN_U; @@ -147,7 +270,7 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int } } - u8 *decoded2 = decoded + 65536 * 24; + u8 *decoded2 = decoded + 65536 * 36; int count = 0; u8 *dest = decoded2; @@ -164,14 +287,13 @@ void TransformDrawEngine::SubmitSpline(void* control_points, void* indices, int for (int tile_v = tile_min_v; tile_v < tile_max_v; ++tile_v) { int point_index = tile_u + tile_v*4; - u8 *v0 = patch.points[point_index]; - u8 *v1 = patch.points[point_index+1]; - u8 *v2 = patch.points[point_index+4]; - u8 *v3 = patch.points[point_index+5]; + SimpleVertex *v0 = patch.points[point_index]; + SimpleVertex *v1 = patch.points[point_index+1]; + SimpleVertex *v2 = patch.points[point_index+4]; + SimpleVertex *v3 = patch.points[point_index+5]; - // TODO: Insert UVs and normals if not present. - CopyTriangle(dest, v0, v2, v1, undecodedVertexSize); - CopyTriangle(dest, v1, v2, v3, undecodedVertexSize); + CopyTriangle(dest, v0, v2, v1); + CopyTriangle(dest, v1, v2, v3); count += 6; } } diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index 3c57794a8a..0d84de8c79 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -490,7 +490,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( if (reader.hasNormal()) reader.ReadNrm(nrm); - if (!gstate.isSkinningEnabled()) { + if (!vertTypeIsSkinningEnabled(vertType)) { Vec3ByMatrix43(out, pos, gstate.worldMatrix); if (reader.hasNormal()) { Norm3ByMatrix43(norm, nrm, gstate.worldMatrix); @@ -502,7 +502,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw( // Skinning Vec3f psum(0,0,0); Vec3f nsum(0,0,0); - for (int i = 0; i < gstate.getNumBoneWeights(); i++) { + for (int i = 0; i < vertTypeGetNumBoneWeights(vertType); i++) { if (weights[i] != 0.0f) { Vec3ByMatrix43(out, pos, gstate.boneMatrix+i*12); Vec3f tpos(out); @@ -1042,7 +1042,7 @@ void TransformDrawEngine::DoFlush() { GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); - LinkedShader *program = shaderManager_->ApplyShader(prim); + LinkedShader *program = shaderManager_->ApplyShader(prim, lastVType_); if (program->useHWTransform_) { GLuint vbo = 0, ebo = 0; diff --git a/GPU/GLES/TransformPipeline.h b/GPU/GLES/TransformPipeline.h index eac63a22d8..40c0c8de5f 100644 --- a/GPU/GLES/TransformPipeline.h +++ b/GPU/GLES/TransformPipeline.h @@ -138,6 +138,9 @@ private: void ApplyDrawState(int prim); bool IsReallyAClear(int numVerts) const; + // Preprocessing for spline/bezier + u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType); + // drawcall ID u32 ComputeFastDCID(); u32 ComputeHash(); // Reads deferred vertex data. diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index e376ed46d9..f7922f8c4b 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -53,8 +53,7 @@ int TranslateNumBones(int bones) { } // prim so we can special case for RECTANGLES :( -void ComputeVertexShaderID(VertexShaderID *id, int prim, bool useHWTransform) { - const u32 vertType = gstate.vertType; +void ComputeVertexShaderID(VertexShaderID *id, u32 vertType, int prim, bool useHWTransform) { int doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doShadeMapping = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP; @@ -91,8 +90,8 @@ void ComputeVertexShaderID(VertexShaderID *id, int prim, bool useHWTransform) { } // Bones - if (gstate.isSkinningEnabled()) - id->d[0] |= (TranslateNumBones(gstate.getNumBoneWeights()) - 1) << 22; + if (vertTypeIsSkinningEnabled(vertType)) + id->d[0] |= (TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1) << 22; // Okay, d[1] coming up. ============== @@ -130,7 +129,7 @@ enum DoLightComputation { LIGHT_FULL, }; -void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { +void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransform) { char *p = buffer; // #define USE_FOR_LOOP @@ -149,7 +148,6 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { WRITE(p, "#define lowp\n"); WRITE(p, "#define mediump\n"); #endif - const u32 vertType = gstate.vertType; int lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); int doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); @@ -174,8 +172,8 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { } } - if (gstate.isSkinningEnabled()) { - WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBones(gstate.getNumBoneWeights())]); + if (vertTypeIsSkinningEnabled(vertType)) { + WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBones(vertTypeGetNumBoneWeights(vertType))]); } if (useHWTransform) @@ -211,8 +209,8 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { WRITE(p, "uniform mat4 u_view;\n"); if (doTextureProjection) WRITE(p, "uniform mediump mat4 u_texmtx;\n"); - if (gstate.isSkinningEnabled()) { - int numBones = TranslateNumBones(gstate.getNumBoneWeights()); + if (vertTypeIsSkinningEnabled(vertType)) { + int numBones = TranslateNumBones(vertTypeGetNumBoneWeights(vertType)); #ifdef USE_BONE_ARRAY WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBones); #else @@ -299,7 +297,7 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { } } else { // Step 1: World Transform / Skinning - if (!gstate.isSkinningEnabled()) { + if (!vertTypeIsSkinningEnabled(vertType)) { // No skinning, just standard T&L. WRITE(p, " vec3 worldpos = (u_world * vec4(a_position.xyz, 1.0)).xyz;\n"); if (hasNormal) @@ -307,7 +305,7 @@ void GenerateVertexShader(int prim, char *buffer, bool useHWTransform) { else WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); } else { - int numWeights = TranslateNumBones(gstate.getNumBoneWeights()); + int numWeights = TranslateNumBones(vertTypeGetNumBoneWeights(vertType)); static const char *rescale[4] = {"", " * 1.9921875", " * 1.999969482421875", ""}; // 2*127.5f/128.f, 2*32767.5f/32768.f, 1.0f}; const char *factor = rescale[gstate.getWeightMask() >> GE_VTYPE_WEIGHT_SHIFT]; diff --git a/GPU/GLES/VertexShaderGenerator.h b/GPU/GLES/VertexShaderGenerator.h index 40e81e6a77..5ab0b23f31 100644 --- a/GPU/GLES/VertexShaderGenerator.h +++ b/GPU/GLES/VertexShaderGenerator.h @@ -50,8 +50,8 @@ struct VertexShaderID bool CanUseHardwareTransform(int prim); -void ComputeVertexShaderID(VertexShaderID *id, int prim, bool useHWTransform); -void GenerateVertexShader(int prim, char *buffer, bool useHWTransform); +void ComputeVertexShaderID(VertexShaderID *id, u32 vertexType, int prim, bool useHWTransform); +void GenerateVertexShader(int prim, u32 vertexType, char *buffer, bool useHWTransform); // Collapse to less skinning shaders to reduce shader switching, which is expensive. int TranslateNumBones(int bones); diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 3c03f8b58f..3d03aead06 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -369,8 +369,6 @@ struct GPUgstate // Vertex type bool isModeThrough() const { return (vertType & GE_VTYPE_THROUGH) != 0; } int getWeightMask() const { return vertType & GE_VTYPE_WEIGHT_MASK; } - int getNumBoneWeights() const { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); } - bool isSkinningEnabled() const { return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); } int getTexCoordMask() const { return vertType & GE_VTYPE_TC_MASK; } bool areNormalsReversed() const { return reversenormals & 1; } @@ -401,6 +399,11 @@ enum SkipDrawReasonFlags { SKIPDRAW_BAD_FB_TEXTURE = 4, }; +inline bool vertTypeIsSkinningEnabled(u32 vertType) { return ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE); } +inline int vertTypeGetNumBoneWeights(u32 vertType) { return 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); } +inline int vertTypeGetWeightMask(u32 vertType) { return vertType & GE_VTYPE_WEIGHT_MASK; } + + // The rest is cached simplified/converted data for fast access. // Does not need to be saved when saving/restoring context. diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index c68261d7da..85a7bad6b2 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -118,14 +118,14 @@ static VertexData ReadVertex(VertexReader& vreader) vertex.normal = -vertex.normal; } - if (gstate.isSkinningEnabled() && !gstate.isModeThrough()) { + if (vertTypeIsSkinningEnabled(gstate.vertType) && !gstate.isModeThrough()) { float W[8] = { 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; vreader.ReadWeights(W); Vec3 tmppos(0.f, 0.f, 0.f); Vec3 tmpnrm(0.f, 0.f, 0.f); - for (int i = 0; i < gstate.getNumBoneWeights(); ++i) { + for (int i = 0; i < vertTypeGetNumBoneWeights(gstate.vertType); ++i) { Mat3x3 bone(&gstate.boneMatrix[12*i]); tmppos += W[i] * (bone * ModelCoords(pos[0], pos[1], pos[2]) + Vec3(gstate.boneMatrix[12*i+9], gstate.boneMatrix[12*i+10], gstate.boneMatrix[12*i+11])); if (vreader.hasNormal())