diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 105128d5315..957ec61b2ad 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -237,6 +237,14 @@ static void shader_delete_constant_list(struct list* clist) { list_init(clist); } +static inline void set_bitmap_bit(DWORD *bitmap, DWORD bit) +{ + DWORD idx, shift; + idx = bit >> 5; + shift = bit & 0x1f; + bitmap[idx] |= (1 << shift); +} + static void shader_record_register_usage(IWineD3DBaseShaderImpl *This, struct shader_reg_maps *reg_maps, DWORD register_type, UINT register_idx, BOOL has_rel_addr, BOOL pshader) { @@ -293,6 +301,10 @@ static void shader_record_register_usage(IWineD3DBaseShaderImpl *This, struct sh } reg_maps->usesrelconstF = TRUE; } + else + { + set_bitmap_bit(reg_maps->constf, register_idx); + } break; case WINED3DSPR_CONSTINT: @@ -309,12 +321,32 @@ static void shader_record_register_usage(IWineD3DBaseShaderImpl *This, struct sh } } +static unsigned char get_instr_regcount(enum WINED3D_SHADER_INSTRUCTION_HANDLER instr, int param) +{ + switch(instr) + { + case WINED3DSIH_M4x4: + case WINED3DSIH_M3x4: + return param == 1 ? 4 : 1; + + case WINED3DSIH_M4x3: + case WINED3DSIH_M3x3: + return param == 1 ? 3 : 1; + + case WINED3DSIH_M3x2: + return param == 1 ? 2 : 1; + + default: + return 1; + } +} + /* Note that this does not count the loop register * as an address register. */ HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3d_shader_frontend *fe, struct shader_reg_maps *reg_maps, struct wined3d_shader_semantic *semantics_in, - struct wined3d_shader_semantic *semantics_out, const DWORD *byte_code) + struct wined3d_shader_semantic *semantics_out, const DWORD *byte_code, DWORD constf_size) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; void *fe_data = This->baseShader.frontend_data; @@ -338,6 +370,13 @@ HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3 reg_maps->shader_version = shader_version; pshader = shader_is_pshader_version(shader_version.type); + reg_maps->constf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(*reg_maps->constf) * ((constf_size + 31) / 32)); + if(!reg_maps->constf) { + ERR("Out of memory\n"); + return E_OUTOFMEMORY; + } + while (!fe->shader_is_end(fe_data, &pToken)) { struct wined3d_shader_instruction ins; @@ -582,6 +621,24 @@ HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3 fe->shader_read_src_param(fe_data, &pToken, &src_param, &src_rel_addr); shader_record_register_usage(This, reg_maps, src_param.reg.type, src_param.reg.idx, !!src_param.reg.rel_addr, pshader); + switch(get_instr_regcount(ins.handler_idx, i)) + { + case 4: + shader_record_register_usage(This, reg_maps, src_param.reg.type, + src_param.reg.idx + 3, !!src_param.reg.rel_addr, pshader); + /* drop through */ + case 3: + shader_record_register_usage(This, reg_maps, src_param.reg.type, + src_param.reg.idx + 2, !!src_param.reg.rel_addr, pshader); + /* drop through */ + case 2: + shader_record_register_usage(This, reg_maps, src_param.reg.type, + src_param.reg.idx + 1, !!src_param.reg.rel_addr, pshader); + /* drop through */ + case 1: + shader_record_register_usage(This, reg_maps, src_param.reg.type, + src_param.reg.idx, !!src_param.reg.rel_addr, pshader); + } } } } @@ -1158,6 +1215,7 @@ void shader_cleanup(IWineD3DBaseShader *iface) IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *)iface; ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_destroy(iface); + HeapFree(GetProcessHeap(), 0, This->baseShader.reg_maps.constf); HeapFree(GetProcessHeap(), 0, This->baseShader.function); shader_delete_constant_list(&This->baseShader.constantsF); shader_delete_constant_list(&This->baseShader.constantsB); diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 485857cbba5..a2e182da1d0 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -238,7 +238,8 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i list_init(&This->baseShader.constantsI); /* Second pass: figure out which registers are used, what the semantics are, etc.. */ - hr = shader_get_registers_used((IWineD3DBaseShader *)This, fe, reg_maps, This->semantics_in, NULL, pFunction); + hr = shader_get_registers_used((IWineD3DBaseShader *)This, fe, reg_maps, This->semantics_in, NULL, pFunction, + GL_LIMITS(pshader_constantsF)); if (FAILED(hr)) return hr; pshader_set_limits(This); diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index e8171ba93fc..e5fb20fdc3d 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -279,7 +279,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader This->min_rel_offset = GL_LIMITS(vshader_constantsF); This->max_rel_offset = 0; hr = shader_get_registers_used((IWineD3DBaseShader*) This, fe, - reg_maps, This->semantics_in, This->semantics_out, pFunction); + reg_maps, This->semantics_in, This->semantics_out, pFunction, + GL_LIMITS(vshader_constantsF)); if (hr != WINED3D_OK) return hr; vshader_set_limits(This); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c5f74fb302e..d40d0ab1e3a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -625,6 +625,7 @@ typedef struct shader_reg_maps char packed_output[MAX_REG_OUTPUT]; /* vertex >= 3.0 */ char attributes[MAX_ATTRIBS]; /* vertex */ char labels[MAX_LABELS]; /* pixel, vertex */ + DWORD *constf; /* pixel, vertex */ DWORD texcoord_mask[MAX_REG_TEXCRD]; /* vertex < 3.0 */ WORD integer_constants; /* MAX_CONST_I, 16 */ WORD boolean_constants; /* MAX_CONST_B, 16 */ @@ -2579,7 +2580,7 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER *buffer, const shader_reg_maps *reg_maps, const DWORD *pFunction); HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3d_shader_frontend *fe, struct shader_reg_maps *reg_maps, struct wined3d_shader_semantic *semantics_in, - struct wined3d_shader_semantic *semantics_out, const DWORD *byte_code); + struct wined3d_shader_semantic *semantics_out, const DWORD *byte_code, DWORD constf_size); void shader_init(struct IWineD3DBaseShaderClass *shader, IWineD3DDevice *device); const struct wined3d_shader_frontend *shader_select_frontend(DWORD version_token); void shader_trace_init(const struct wined3d_shader_frontend *fe, void *fe_data, const DWORD *pFunction);