diff --git a/source/base.c b/source/base.c index a8f6572..a93c1a2 100644 --- a/source/base.c +++ b/source/base.c @@ -49,9 +49,12 @@ static void C3Di_AptEventHook(APT_HookType hookType, void* param) case APTHOOK_ONRESTORE: { ctx->flags |= C3DiF_AttrInfo | C3DiF_BufInfo | C3DiF_Effect | C3DiF_RenderBuf - | C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program + | C3DiF_Viewport | C3DiF_Scissor | C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode | C3DiF_TexAll | C3DiF_TexEnvBuf | C3DiF_TexEnvAll | C3DiF_LightEnv; + C3Di_DirtyUniforms(GPU_VERTEX_SHADER); + C3Di_DirtyUniforms(GPU_GEOMETRY_SHADER); + C3D_LightEnv* env = ctx->lightEnv; if (env) env->Dirty(env); @@ -129,8 +132,8 @@ void C3Di_UpdateContext(void) if (ctx->flags & C3DiF_Program) { - ctx->flags &= ~C3DiF_Program; - shaderProgramUse(ctx->program); + shaderProgramConfigure(ctx->program, (ctx->flags & C3DiF_VshCode) != 0, (ctx->flags & C3DiF_GshCode) != 0); + ctx->flags &= ~(C3DiF_Program | C3DiF_VshCode | C3DiF_GshCode); } if (ctx->flags & C3DiF_RenderBuf) @@ -270,6 +273,27 @@ void C3D_BindProgram(shaderProgram_s* program) if (!(ctx->flags & C3DiF_Active)) return; - ctx->program = program; - ctx->flags |= C3DiF_Program; + shaderProgram_s* oldProg = ctx->program; + shaderInstance_s* newGsh = program->geometryShader; + if (oldProg != program) + { + ctx->program = program; + ctx->flags |= C3DiF_Program; + + if (oldProg) + { + if (oldProg->vertexShader->dvle->dvlp != program->vertexShader->dvle->dvlp) + ctx->flags |= C3DiF_VshCode; + shaderInstance_s* oldGsh = oldProg->geometryShader; + if (newGsh && (!oldGsh || oldGsh->dvle->dvlp != newGsh->dvle->dvlp)) + ctx->flags |= C3DiF_GshCode; + } else + ctx->flags |= C3DiF_VshCode | C3DiF_GshCode; + } + + C3Di_LoadShaderUniforms(program->vertexShader); + if (newGsh) + C3Di_LoadShaderUniforms(newGsh); + else + C3Di_ClearShaderUniforms(GPU_GEOMETRY_SHADER); } diff --git a/source/context.h b/source/context.h index 34c9a37..b886443 100644 --- a/source/context.h +++ b/source/context.h @@ -59,6 +59,8 @@ enum C3DiF_Program = BIT(8), C3DiF_TexEnvBuf = BIT(9), C3DiF_LightEnv = BIT(10), + C3DiF_VshCode = BIT(11), + C3DiF_GshCode = BIT(12), #define C3DiF_Tex(n) BIT(23+(n)) C3DiF_TexAll = 7 << 23, @@ -80,3 +82,7 @@ void C3Di_EffectBind(C3D_Effect* effect); void C3Di_RenderBufBind(C3D_RenderBuf* rb); void C3Di_LightMtlBlend(C3D_Light* light); + +void C3Di_DirtyUniforms(GPU_SHADER_TYPE type); +void C3Di_LoadShaderUniforms(shaderInstance_s* si); +void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type); diff --git a/source/uniforms.c b/source/uniforms.c index 825938f..670ea96 100644 --- a/source/uniforms.c +++ b/source/uniforms.c @@ -9,12 +9,35 @@ bool C3D_FVUnifDirty[2][C3D_FVUNIF_COUNT]; bool C3D_IVUnifDirty[2][C3D_IVUNIF_COUNT]; bool C3D_BoolUnifsDirty[2]; +static struct +{ + bool dirty; + int count; + float24Uniform_s* data; +} C3Di_ShaderFVecData[2]; + +static bool C3Di_FVUnifEverDirty[2][C3D_FVUNIF_COUNT]; +static bool C3Di_IVUnifEverDirty[2][C3D_IVUNIF_COUNT]; + void C3D_UpdateUniforms(GPU_SHADER_TYPE type) { int offset = type == GPU_GEOMETRY_SHADER ? (GPUREG_GSH_BOOLUNIFORM-GPUREG_VSH_BOOLUNIFORM) : 0; + int i = 0; + + // Update FVec uniforms that come from shader constants + if (C3Di_ShaderFVecData[type].dirty) + { + while (i < C3Di_ShaderFVecData[type].count) + { + float24Uniform_s* u = &C3Di_ShaderFVecData[type].data[i++]; + GPUCMD_AddIncrementalWrites(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, (u32*)u, 4); + C3D_FVUnifDirty[type][u->id] = false; + } + C3Di_ShaderFVecData[type].dirty = false; + i = 0; + } // Update FVec uniforms - int i = 0; while (i < C3D_FVUNIF_COUNT) { if (!C3D_FVUnifDirty[type][i]) @@ -27,14 +50,6 @@ void C3D_UpdateUniforms(GPU_SHADER_TYPE type) int j; for (j = i; j < C3D_FVUNIF_COUNT && C3D_FVUnifDirty[type][j]; j ++); - /* - consoleClear(); - printf("FVEC Uniform %02X--%02X\n", i, j-1); - int pp; - for (pp = i; pp < j; pp ++) - printf("%02X: (%f, %f, %f, %f)\n", pp, C3D_FVUnif[pp].x, C3D_FVUnif[pp].y, C3D_FVUnif[pp].z, C3D_FVUnif[pp].w); - */ - // Upload the uniforms GPUCMD_AddWrite(GPUREG_VSH_FLOATUNIFORM_CONFIG+offset, 0x80000000|i); GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+offset, (u32*)&C3D_FVUnif[i], (j-i)*4); @@ -42,7 +57,10 @@ void C3D_UpdateUniforms(GPU_SHADER_TYPE type) // Clear the dirty flag int k; for (k = i; k < j; k ++) + { C3D_FVUnifDirty[type][k] = false; + C3Di_FVUnifEverDirty[type][k] = true; + } // Advance i += j; @@ -55,12 +73,58 @@ void C3D_UpdateUniforms(GPU_SHADER_TYPE type) GPUCMD_AddWrite(GPUREG_VSH_INTUNIFORM_I0+offset+i, C3D_IVUnif[type][i]); C3D_IVUnifDirty[type][i] = false; + C3Di_IVUnifEverDirty[type][i] = false; } // Update bool uniforms if (C3D_BoolUnifsDirty[type]) { - GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM+offset, 0x7FFF0000 | (u32)C3D_BoolUnifs[type]); + GPUCMD_AddWrite(GPUREG_VSH_BOOLUNIFORM+offset, 0x7FFF0000 | (u32)~C3D_BoolUnifs[type]); C3D_BoolUnifsDirty[type] = false; } } + +void C3Di_DirtyUniforms(GPU_SHADER_TYPE type) +{ + int i; + C3D_BoolUnifsDirty[type] = true; + if (C3Di_ShaderFVecData[type].count) + C3Di_ShaderFVecData[type].dirty = true; + for (i = 0; i < C3D_FVUNIF_COUNT; i ++) + C3D_FVUnifDirty[type][i] = C3D_FVUnifDirty[type][i] || C3Di_FVUnifEverDirty[type][i]; + for (i = 0; i < C3D_IVUNIF_COUNT; i ++) + C3D_IVUnifDirty[type][i] = C3D_IVUnifDirty[type][i] || C3Di_IVUnifEverDirty[type][i]; +} + +void C3Di_LoadShaderUniforms(shaderInstance_s* si) +{ + GPU_SHADER_TYPE type = si->dvle->type; + int i; + if (si->boolUniformMask) + { + C3D_BoolUnifs[type] &= ~si->boolUniformMask; + C3D_BoolUnifs[type] |= si->boolUniforms; + C3D_BoolUnifsDirty[type] = true; + } + if (si->intUniformMask) + { + for (i = 0; i < 4; i ++) + { + if (si->intUniformMask & BIT(i)) + { + C3D_IVUnif[type][i] = si->intUniforms[i]; + C3D_IVUnifDirty[type][i] = true; + } + } + } + C3Di_ShaderFVecData[type].dirty = true; + C3Di_ShaderFVecData[type].count = si->numFloat24Uniforms; + C3Di_ShaderFVecData[type].data = si->float24Uniforms; +} + +void C3Di_ClearShaderUniforms(GPU_SHADER_TYPE type) +{ + C3Di_ShaderFVecData[type].dirty = false; + C3Di_ShaderFVecData[type].count = 0; + C3Di_ShaderFVecData[type].data = NULL; +}