From 49a49fcfec199ce6e972ee339fa28fbbe4643435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Thu, 15 Feb 2007 03:05:17 +0100 Subject: [PATCH] wined3d: Load one bump mapping environment matrix into pixel shaders if needed. --- dlls/wined3d/baseshader.c | 9 +++++++++ dlls/wined3d/directx.c | 9 ++++++++- dlls/wined3d/glsl_shader.c | 18 ++++++++++++++++-- dlls/wined3d/pixelshader.c | 2 ++ dlls/wined3d/state.c | 12 ++++++++++++ dlls/wined3d/wined3d_private.h | 5 +++++ 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index f13d448f0c4..3bbdb45819f 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -344,6 +344,15 @@ HRESULT shader_get_registers_used( reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D; } } + + /* texbem is only valid with < 1.4 pixel shaders */ + if(WINED3DSIO_TEXBEM == curOpcode->opcode) { + if(reg_maps->bumpmat != 0 && reg_maps->bumpmat != sampler_code) { + FIXME("Pixel shader uses texbem instruction on more than 1 sampler\n"); + } else { + reg_maps->bumpmat = sampler_code; + } + } } /* This will loop over all the registers and try to diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 7e2fc05d0a5..398aca0853a 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -284,10 +284,17 @@ void select_shader_max_constants( switch (ps_selected_mode) { case SHADER_GLSL: - /* Subtract the other potential uniforms from the max available (bools & ints) */ + /* Subtract the other potential uniforms from the max available (bools & ints). + * In theory the texbem instruction may need one more shader constant too. But lets assume + * that a sm <= 1.3 shader does not need all the uniforms provided by a glsl-capable card, + * and lets not take away a uniform needlessly from all other shaders. + */ gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - MAX_CONST_B - MAX_CONST_I; break; case SHADER_ARB: + /* The arb shader only loads the bump mapping environment matrix into the shader if it finds + * a free constant to do that, so no need to reduce the number of available constants. + */ gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF; break; case SHADER_SW: diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 97223127149..566442bdf0a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -283,7 +283,8 @@ void shader_glsl_load_constants( GLhandleARB *constant_locations; struct list *constant_list; GLhandleARB programId; - + GLint pos; + if (!stateBlock->glsl_program) { /* No GLSL program set - nothing to do. */ return; @@ -336,11 +337,22 @@ void shader_glsl_load_constants( shader_glsl_load_constantsI(pshader, gl_info, programId, MAX_CONST_I, stateBlock->pixelShaderConstantI, stateBlock->set.pixelShaderConstantsI); - + /* Load DirectX 9 boolean constants/uniforms for pixel shader */ shader_glsl_load_constantsB(pshader, gl_info, programId, MAX_CONST_B, stateBlock->pixelShaderConstantB, stateBlock->set.pixelShaderConstantsB); + + /* Upload the environment bump map matrix if needed. The needsbumpmat member specifies the texture stage to load the matrix from. + * It can't be 0 for a valid texbem instruction. + */ + if(((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat != 0) { + float *data = (float *) &stateBlock->textureState[(int) ((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; + pos = GL_EXTCALL(glGetUniformLocationARB(programId, "bumpenvmat")); + checkGLcall("glGetUniformLocationARB"); + GL_EXTCALL(glUniform4fvARB(pos, 1, data)); + checkGLcall("glUniform4fvARB"); + } } } @@ -379,6 +391,8 @@ void shader_generate_glsl_declarations( if(!pshader) shader_addline(buffer, "uniform vec4 posFixup;\n"); + else if(reg_maps->bumpmat) + shader_addline(buffer, "uniform vec4 bumpenvmat;\n"); /* Declare texture samplers */ for (i = 0; i < This->baseShader.limits.sampler; i++) { diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 8958ee028c0..e83cab1edb7 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -914,6 +914,8 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateShader( } } + This->needsbumpmat = reg_maps->bumpmat; + #if 1 /* if were using the data buffer of device then we don't need to free it */ HeapFree(GetProcessHeap(), 0, buffer.buffer); #endif diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 769f0d1479a..438f6f0abde 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1951,6 +1951,18 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D } static void tex_bumpenvmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + + if(stateblock->pixelShader && stage != 0 && + ((IWineD3DPixelShaderImpl *) stateblock->pixelShader)->needsbumpmat == stage) { + /* The pixel shader has to know the bump env matrix. Do a constants update if it isn't scheduled + * anyway + */ + if(!isStateDirty(context, STATE_PIXELSHADERCONSTANT) && + !isStateDirty(context, STATE_PIXELSHADER)) { + shaderconstant(STATE_PIXELSHADERCONSTANT, stateblock, context); + } + } } static void transform_world(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 6111f537222..20c90721358 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1468,6 +1468,7 @@ typedef struct shader_reg_maps { /* Sampler usage tokens * Use 0 as default (bit 31 is always 1 on a valid token) */ DWORD samplers[MAX_SAMPLERS]; + char bumpmat; /* Whether or not a loop is used in this shader */ char loop; @@ -1834,6 +1835,10 @@ typedef struct IWineD3DPixelShaderImpl { /* run time data */ PSHADERDATA *data; + /* Some information about the shader behavior */ + char needsbumpmat; + UINT bumpenvmatconst; + #if 0 /* needs reworking */ PSHADERINPUTDATA input; PSHADEROUTPUTDATA output;