diff --git a/reactos/dll/directx/wine/wined3d/Makefile.in b/reactos/dll/directx/wine/wined3d/Makefile.in index 16587b3ba88..9ec6494a53a 100644 --- a/reactos/dll/directx/wine/wined3d/Makefile.in +++ b/reactos/dll/directx/wine/wined3d/Makefile.in @@ -25,6 +25,7 @@ C_SRCS = \ resource.c \ state.c \ stateblock.c \ + surface_base.c \ surface.c \ surface_gdi.c \ swapchain.c \ diff --git a/reactos/dll/directx/wine/wined3d/arb_program_shader.c b/reactos/dll/directx/wine/wined3d/arb_program_shader.c index 5cbadc2a528..d6ca4a87739 100644 --- a/reactos/dll/directx/wine/wined3d/arb_program_shader.c +++ b/reactos/dll/directx/wine/wined3d/arb_program_shader.c @@ -52,7 +52,7 @@ static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_ unsigned int max_constants, float* constants, struct list *constant_list) { constants_entry *constant; local_constant* lconst; - DWORD i, j; + DWORD i, j, k; DWORD *idx; if (TRACE_ON(d3d_shader)) { @@ -67,12 +67,43 @@ static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_ } } } - LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { - idx = constant->idx; - j = constant->count; - while (j--) { - i = *idx++; - GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4))); + /* In 1.X pixel shaders constants are implicitly clamped in the range [-1;1] */ + if(target_type == GL_FRAGMENT_PROGRAM_ARB && + WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1) { + float lcl_const[4]; + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + k = i * 4; + if(constants[k + 0] > 1.0) lcl_const[0] = 1.0; + else if(constants[k + 0] < -1.0) lcl_const[0] = -1.0; + else lcl_const[0] = constants[k + 0]; + + if(constants[k + 1] > 1.0) lcl_const[1] = 1.0; + else if(constants[k + 1] < -1.0) lcl_const[1] = -1.0; + else lcl_const[1] = constants[k + 1]; + + if(constants[k + 2] > 1.0) lcl_const[2] = 1.0; + else if(constants[k + 2] < -1.0) lcl_const[2] = -1.0; + else lcl_const[2] = constants[k + 2]; + + if(constants[k + 3] > 1.0) lcl_const[3] = 1.0; + else if(constants[k + 3] < -1.0) lcl_const[3] = -1.0; + else lcl_const[3] = constants[k + 3]; + + GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, lcl_const)); + } + } + } else { + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4))); + } } } checkGLcall("glProgramEnvParameter4fvARB()"); @@ -85,6 +116,7 @@ static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_ values[0], values[1], values[2], values[3]); } } + /* Immediate constants are clamped for 1.X shaders at loading times */ LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value)); } @@ -122,20 +154,52 @@ void shader_arb_load_constants( if (usePixelShader) { IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader; + IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader; /* Load DirectX 9 float constants for pixel shader */ shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, GL_LIMITS(pshader_constantsF), stateBlock->pixelShaderConstantF, &stateBlock->set_pconstantsF); - if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst) { + if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst != -1) { /* needsbumpmat stores the stage number from where to load the matrix. bumpenvmatconst stores the * number of the constant to load the matrix into. * The state manager takes care that this function is always called if the bump env matrix changes */ - IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader; float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data)); + + if(((IWineD3DPixelShaderImpl *) pshader)->luminanceconst != -1) { + /* WINED3DTSS_BUMPENVLSCALE and WINED3DTSS_BUMPENVLOFFSET are next to each other. + * point gl to the scale, and load 4 floats. x = scale, y = offset, z and w are junk, we + * don't care about them. The pointers are valid for sure because the stateblock is bigger. + * (they're WINED3DTSS_TEXTURETRANSFORMFLAGS and WINED3DTSS_ADDRESSW, so most likely 0 or NaN + */ + float *scale = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVLSCALE]; + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->luminanceconst, scale)); + } + } + if(((IWineD3DPixelShaderImpl *) pshader)->srgb_enabled && + !((IWineD3DPixelShaderImpl *) pshader)->srgb_mode_hardcoded) { + float comparison[4]; + float mul_low[4]; + + if(stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) { + comparison[0] = srgb_cmp; comparison[1] = srgb_cmp; + comparison[2] = srgb_cmp; comparison[3] = srgb_cmp; + + mul_low[0] = srgb_mul_low; mul_low[1] = srgb_mul_low; + mul_low[2] = srgb_mul_low; mul_low[3] = srgb_mul_low; + } else { + comparison[0] = 1.0 / 0.0; comparison[1] = 1.0 / 0.0; + comparison[2] = 1.0 / 0.0; comparison[3] = 1.0 / 0.0; + + mul_low[0] = 1.0; mul_low[1] = 1.0; + mul_low[2] = 1.0; mul_low[3] = 1.0; + } + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_cmp_const, comparison)); + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_low_const, mul_low)); + checkGLcall("Load sRGB correction constants\n"); } } } @@ -148,10 +212,12 @@ void shader_generate_arb_declarations( WineD3D_GL_Info* gl_info) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device; DWORD i; char pshader = shader_is_pshader_version(This->baseShader.hex_version); unsigned max_constantsF = min(This->baseShader.limits.constant_float, (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF))); + UINT extra_constants_needed = 0; /* Temporary Output register */ shader_addline(buffer, "TEMP TMP_OUT;\n"); @@ -177,6 +243,8 @@ void shader_generate_arb_declarations( shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i); } + ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = -1; + ((IWineD3DPixelShaderImpl *)This)->luminanceconst = -1; if(reg_maps->bumpmat != -1 /* Only a pshader can use texbem */) { /* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying @@ -185,9 +253,63 @@ void shader_generate_arb_declarations( if(max_constantsF < GL_LIMITS(pshader_constantsF)) { ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = max_constantsF; shader_addline(buffer, "PARAM bumpenvmat = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst); + + if(reg_maps->luminanceparams != -1 && max_constantsF +1 < GL_LIMITS(pshader_constantsF)) { + extra_constants_needed += 1; + ((IWineD3DPixelShaderImpl *)This)->luminanceconst = max_constantsF + 1; + shader_addline(buffer, "PARAM luminance = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->luminanceconst); + } else if(reg_maps->luminanceparams != -1) { + FIXME("No free constant to load the luminance parameters\n"); + } } else { FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n"); } + extra_constants_needed += 1; + } + if(device->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE] && pshader) { + IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This; + /* If there are 2 constants left to use, use them to pass the sRGB correction values in. This way + * srgb write correction can be turned on and off dynamically without recompilation. Otherwise + * hardcode them. The drawback of hardcoding is that the shader needs recompilation to turn sRGB + * off again + */ + if(max_constantsF + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF) && FALSE) { + /* The idea is that if srgb is enabled, then disabled, the constant loading code + * can effectively disable sRGB correction by passing 1.0 and INF as the multiplication + * and comparison constants. If it disables it that way, the shader won't be recompiled + * and the code will stay in, so sRGB writing can be turned on again by setting the + * constants from the spec + */ + ps_impl->srgb_mode_hardcoded = 0; + ps_impl->srgb_low_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed; + ps_impl->srgb_cmp_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed - 1; + shader_addline(buffer, "PARAM srgb_mul_low = program.env[%d];\n", ps_impl->srgb_low_const); + shader_addline(buffer, "PARAM srgb_comparison = program.env[%d];\n", ps_impl->srgb_cmp_const); + } else { + shader_addline(buffer, "PARAM srgb_mul_low = {%f, %f, %f, 1.0};\n", + srgb_mul_low, srgb_mul_low, srgb_mul_low); + shader_addline(buffer, "PARAM srgb_comparison = {%f, %f, %f, %f};\n", + srgb_cmp, srgb_cmp, srgb_cmp, srgb_cmp); + ps_impl->srgb_mode_hardcoded = 1; + } + /* These can be hardcoded, they do not cause any harm because no fragment will enter the high + * path if the comparison value is set to INF + */ + shader_addline(buffer, "PARAM srgb_pow = {%f, %f, %f, 1.0};\n", + srgb_pow, srgb_pow, srgb_pow); + shader_addline(buffer, "PARAM srgb_mul_hi = {%f, %f, %f, 1.0};\n", + srgb_mul_high, srgb_mul_high, srgb_mul_high); + shader_addline(buffer, "PARAM srgb_sub_hi = {%f, %f, %f, 0.0};\n", + srgb_sub_high, srgb_sub_high, srgb_sub_high); + ps_impl->srgb_enabled = 1; + } else if(pshader) { + IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This; + + /* Do not write any srgb fixup into the shader to save shader size and processing time. + * As a consequence, we can't toggle srgb write on without recompilation + */ + ps_impl->srgb_enabled = 0; + ps_impl->srgb_mode_hardcoded = 1; } /* Need to PARAM the environment parameters (constants) so we can use relative addressing */ @@ -214,10 +336,15 @@ static const char * const shift_tab[] = { "coefdiv.x" /* 15 (d2) */ }; -static void shader_arb_get_write_mask(const DWORD param, char *write_mask) { +static void shader_arb_get_write_mask(SHADER_OPCODE_ARG* arg, const DWORD param, char *write_mask) { + IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) arg->shader; char *ptr = write_mask; + char vshader = shader_is_vshader_version(This->baseShader.hex_version); - if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) { + if(vshader && shader_get_regtype(param) == WINED3DSPR_ADDR) { + *ptr++ = '.'; + *ptr++ = 'x'; + } else if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) { *ptr++ = '.'; if (param & WINED3DSP_WRITEMASK_0) *ptr++ = 'x'; if (param & WINED3DSP_WRITEMASK_1) *ptr++ = 'y'; @@ -340,7 +467,15 @@ static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, strcat(hwLine, tmpReg); break; case WINED3DSPR_CONST: - sprintf(tmpReg, "C[%s%u]", (param & WINED3DSHADER_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg); + if(param & WINED3DSHADER_ADDRMODE_RELATIVE) { + if(reg - This->rel_offset >= 0) { + sprintf(tmpReg, "C[A0.x + %u]", reg - This->rel_offset); + } else { + sprintf(tmpReg, "C[A0.x - %u]", -reg + This->rel_offset); + } + } else { + sprintf(tmpReg, "C[%u]", reg); + } strcat(hwLine, tmpReg); break; case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/ @@ -370,7 +505,7 @@ static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, if (!is_input) { char write_mask[6]; - shader_arb_get_write_mask(param, write_mask); + shader_arb_get_write_mask(arg, param, write_mask); strcat(hwLine, write_mask); } else { char swizzle[6]; @@ -379,12 +514,7 @@ static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, } } -static void shader_hw_sample(SHADER_OPCODE_ARG* arg, DWORD sampler_idx, const char *dst_str, const char *coord_reg, BOOL projective) { - IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; - IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; - IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx]; - WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info; - +static void shader_hw_sample(SHADER_OPCODE_ARG* arg, DWORD sampler_idx, const char *dst_str, const char *coord_reg, BOOL projected, BOOL bias) { SHADER_BUFFER* buffer = arg->buffer; DWORD sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; const char *tex_type; @@ -411,24 +541,201 @@ static void shader_hw_sample(SHADER_OPCODE_ARG* arg, DWORD sampler_idx, const ch tex_type = ""; } - if (projective && deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) { + if (bias) { + /* Shouldn't be possible, but let's check for it */ + if(projected) FIXME("Biased and Projected texture sampling\n"); + /* TXB takes the 4th component of the source vector automatically, as d3d. Nothing more to do */ + shader_addline(buffer, "TXB %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type); + } else if (projected) { shader_addline(buffer, "TXP %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type); } else { shader_addline(buffer, "TEX %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type); } +} - /* Signedness correction */ - if(!GL_SUPPORT(NV_TEXTURE_SHADER3) /* Provides signed formats */ && texture) { - WINED3DFORMAT format = texture->resource.format; +static void shader_arb_color_correction(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) shader->baseShader.device; + WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info; + WINED3DFORMAT fmt; + WINED3DFORMAT conversion_group; + IWineD3DBaseTextureImpl *texture; + UINT i; + BOOL recorded = FALSE; + DWORD sampler_idx; + DWORD hex_version = shader->baseShader.hex_version; + char reg[256]; + char writemask[6]; - if((format == WINED3DFMT_V8U8 && !GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) || - format == WINED3DFMT_Q8W8V8U8 || - format == WINED3DFMT_V16U16) { - shader_addline(buffer, "MAD %s, %s, coefmul.x, -one;\n", dst_str, dst_str); - } else if(format == WINED3DFMT_X8L8V8U8) { - shader_addline(buffer, "MAD %s.rg, %s, coefmul.x, -one;\n", dst_str, dst_str); + switch(arg->opcode->opcode) { + case WINED3DSIO_TEX: + if (hex_version < WINED3DPS_VERSION(2,0)) { + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + } else { + sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK; + } + break; + + case WINED3DSIO_TEXLDL: + FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n"); + return; + + case WINED3DSIO_TEXDP3TEX: + case WINED3DSIO_TEXM3x3TEX: + case WINED3DSIO_TEXM3x3SPEC: + case WINED3DSIO_TEXM3x3VSPEC: + case WINED3DSIO_TEXBEM: + case WINED3DSIO_TEXREG2AR: + case WINED3DSIO_TEXREG2GB: + case WINED3DSIO_TEXREG2RGB: + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + break; + + default: + /* Not a texture sampling instruction, nothing to do */ + return; + }; + + texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx]; + if(texture) { + fmt = texture->resource.format; + conversion_group = texture->baseTexture.shader_conversion_group; + } else { + fmt = WINED3DFMT_UNKNOWN; + conversion_group = WINED3DFMT_UNKNOWN; + } + + /* before doing anything, record the sampler with the format in the format conversion list, + * but check if it's not there already + */ + for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) { + if(shader->baseShader.sampled_samplers[i] == sampler_idx) { + recorded = TRUE; } } + if(!recorded) { + shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx; + shader->baseShader.num_sampled_samplers++; + shader->baseShader.sampled_format[sampler_idx] = conversion_group; + } + + pshader_get_register_name(arg->dst, reg); + shader_arb_get_write_mask(arg, arg->dst, writemask); + if(strlen(writemask) == 0) strcpy(writemask, ".xyzw"); + + switch(fmt) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + if(GL_SUPPORT(NV_TEXTURE_SHADER) || + (GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && fmt == WINED3DFMT_V8U8)) { +#if 0 + /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. Fix this while we're at it :-) + * disabled until an application that needs it is found because it causes unneeded + * shader recompilation in some game + */ + if(strlen(writemask) >= 4) { + shader_addline(arg->buffer, "MOV %s.%c, one.z;\n", reg, writemask[3]); + } +#endif + } else { + /* Correct the sign, but leave the blue as it is - it was loaded correctly already + * ARB shaders are a bit picky wrt writemasks and swizzles. If we're free to scale + * all registers, do so, this saves an instruction. + */ + if(strlen(writemask) >= 5) { + shader_addline(arg->buffer, "MAD %s, %s, coefmul.x, -one;\n", reg, reg); + } else if(strlen(writemask) >= 3) { + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[1], + reg, writemask[1]); + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[2], + reg, writemask[2]); + } else if(strlen(writemask) == 2) { + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", reg, writemask[1], + reg, writemask[1]); + } + } + break; + + case WINED3DFMT_X8L8V8U8: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* Red and blue are the signed channels, fix them up; Blue(=L) is correct already, + * and a(X) is always 1.0. Cannot do a full conversion due to L(blue) + */ + if(strlen(writemask) >= 3) { + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[1], + reg, writemask[1]); + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[2], + reg, writemask[2]); + } else if(strlen(writemask) == 2) { + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[1], + reg, writemask[1]); + } + } + break; + + case WINED3DFMT_L6V5U5: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + if(strlen(writemask) >= 4) { + /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */ + shader_addline(arg->buffer, "MOV TMP.g, %s.%c;\n", + reg, writemask[2]); + shader_addline(arg->buffer, "MAD %s.%c%c, %s.%c%c, coefmul.x, -one;\n", + reg, writemask[1], writemask[1], + reg, writemask[1], writemask[3]); + shader_addline(arg->buffer, "MOV %s.%c, TMP.g;\n", reg, + writemask[3]); + } else if(strlen(writemask) == 3) { + /* This is bad: We have VL, but we need VU */ + FIXME("2 components sampled from a converted L6V5U5 texture\n"); + } else { + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[1], + reg, writemask[1]); + } + } + break; + + case WINED3DFMT_Q8W8V8U8: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* Correct the sign in all channels */ + switch(strlen(writemask)) { + case 4: + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[3], + reg, writemask[3]); + /* drop through */ + case 3: + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[2], + reg, writemask[2]); + /* drop through */ + case 2: + shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", + reg, writemask[1], + reg, writemask[1]); + break; + + /* Should not occur, since it's at minimum '.' and a letter */ + case 1: + ERR("Unexpected writemask: \"%s\"\n", writemask); + break; + + case 5: + default: + shader_addline(arg->buffer, "MAD %s, %s, coefmul.x, -one;\n", reg, reg); + } + } + break; + + /* stupid compiler */ + default: + break; + } } @@ -519,7 +826,7 @@ void pshader_hw_bem(SHADER_OPCODE_ARG* arg) { char dst_wmask[20]; pshader_get_register_name(arg->dst, dst_name); - shader_arb_get_write_mask(arg->dst, dst_wmask); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); strcat(dst_name, dst_wmask); pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); @@ -540,25 +847,36 @@ void pshader_hw_bem(SHADER_OPCODE_ARG* arg) { void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; SHADER_BUFFER* buffer = arg->buffer; char dst_wmask[20]; char dst_name[50]; char src_name[3][50]; + BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE; + DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; /* FIXME: support output modifiers */ /* Handle output register */ pshader_get_register_name(arg->dst, dst_name); - shader_arb_get_write_mask(arg->dst, dst_wmask); - strcat(dst_name, dst_wmask); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); /* Generate input register names (with modifiers) */ pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); - shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]); - shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]); + /* The coissue flag changes the semantic of the cnd instruction in <= 1.3 shaders */ + if (shader->baseShader.hex_version <= WINED3DPS_VERSION(1, 3) && + arg->opcode_token & WINED3DSI_COISSUE) { + shader_addline(buffer, "MOV%s %s%s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, src_name[1]); + } else { + shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]); + shader_addline(buffer, "CMP%s %s%s, TMP, %s, %s;\n", + sat ? "_SAT" : "", dst_name, dst_wmask, src_name[1], src_name[2]); + } + if (shift != 0) + pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name); } void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) { @@ -567,21 +885,52 @@ void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) { char dst_wmask[20]; char dst_name[50]; char src_name[3][50]; + DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE; /* FIXME: support output modifiers */ /* Handle output register */ pshader_get_register_name(arg->dst, dst_name); - shader_arb_get_write_mask(arg->dst, dst_wmask); - strcat(dst_name, dst_wmask); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); /* Generate input register names (with modifiers) */ pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); - shader_addline(buffer, "CMP %s, %s, %s, %s;\n", dst_name, - src_name[0], src_name[2], src_name[1]); + shader_addline(buffer, "CMP%s %s%s, %s, %s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, + src_name[0], src_name[2], src_name[1]); + + if (shift != 0) + pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name); +} + +/** Process the WINED3DSIO_DP2ADD instruction in ARB. + * dst = dot2(src0, src1) + src2 */ +void pshader_hw_dp2add(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + char dst_wmask[20]; + char dst_name[50]; + char src_name[3][50]; + DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE; + + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); + pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); + pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); + + /* Emulate a DP2 with a DP3 and 0.0 */ + shader_addline(buffer, "MOV TMP, %s;\n", src_name[0]); + shader_addline(buffer, "MOV TMP.z, 0.0;\n"); + shader_addline(buffer, "DP3 TMP2, TMP, %s;\n", src_name[1]); + shader_addline(buffer, "ADD%s %s%s, TMP2, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, src_name[2]); + + if (shift != 0) + pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name); } /* Map the opcode 1-to-1 to the GL code */ @@ -632,7 +981,7 @@ void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { /* Handle output register */ pshader_get_register_name(dst, output_rname); strcpy(operands[0], output_rname); - shader_arb_get_write_mask(dst, output_wmask); + shader_arb_get_write_mask(arg, dst, output_wmask); strcat(operands[0], output_wmask); if (saturate && (shift == 0)) @@ -652,14 +1001,39 @@ void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { } } -void pshader_hw_tex(SHADER_OPCODE_ARG* arg) { - +void pshader_hw_texkill(SHADER_OPCODE_ARG* arg) { IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD hex_version = This->baseShader.hex_version; + SHADER_BUFFER* buffer = arg->buffer; + char reg_dest[40]; + + /* No swizzles are allowed in d3d's texkill. PS 1.x ignores the 4th component as documented, + * but >= 2.0 honors it(undocumented, but tested by the d3d9 testsuit) + */ + pshader_get_register_name(arg->dst, reg_dest); + + if(hex_version >= WINED3DPS_VERSION(2,0)) { + /* The arb backend doesn't claim ps 2.0 support, but try to eat what the app feeds to us */ + shader_addline(buffer, "KIL %s;\n", reg_dest); + } else { + /* ARB fp doesn't like swizzles on the parameter of the KIL instruction. To mask the 4th component, + * copy the register into our general purpose TMP variable, overwrite .w and pass TMP to KIL + */ + shader_addline(buffer, "MOV TMP, %s;\n", reg_dest); + shader_addline(buffer, "MOV TMP.w, one.w;\n", reg_dest); + shader_addline(buffer, "KIL TMP;\n", reg_dest); + } +} + +void pshader_hw_tex(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; DWORD dst = arg->dst; DWORD* src = arg->src; SHADER_BUFFER* buffer = arg->buffer; DWORD hex_version = This->baseShader.hex_version; + BOOL projected = FALSE, bias = FALSE; char reg_dest[40]; char reg_coord[40]; @@ -684,7 +1058,35 @@ void pshader_hw_tex(SHADER_OPCODE_ARG* arg) { else reg_sampler_code = src[1] & WINED3DSP_REGNUM_MASK; - shader_hw_sample(arg, reg_sampler_code, reg_dest, reg_coord, TRUE); + /* projection flag: + * 1.1, 1.2, 1.3: Use WINED3DTSS_TEXTURETRANSFORMFLAGS + * 1.4: Use WINED3DSPSM_DZ or WINED3DSPSM_DW on src[0] + * 2.0+: Use WINED3DSI_TEXLD_PROJECT on the opcode + */ + if(hex_version < WINED3DPS_VERSION(1,4)) { + DWORD flags = 0; + if(reg_sampler_code < MAX_TEXTURES) { + flags = deviceImpl->stateBlock->textureState[reg_sampler_code][WINED3DTSS_TEXTURETRANSFORMFLAGS]; + } + if (flags & WINED3DTTFF_PROJECTED) { + projected = TRUE; + } + } else if(hex_version < WINED3DPS_VERSION(2,0)) { + DWORD src_mod = arg->src[0] & WINED3DSP_SRCMOD_MASK; + if (src_mod == WINED3DSPSM_DZ) { + projected = TRUE; + } else if(src_mod == WINED3DSPSM_DW) { + projected = TRUE; + } + } else { + if(arg->opcode_token & WINED3DSI_TEXLD_PROJECT) { + projected = TRUE; + } + if(arg->opcode_token & WINED3DSI_TEXLD_BIAS) { + bias = TRUE; + } + } + shader_hw_sample(arg, reg_sampler_code, reg_dest, reg_coord, projected, bias); } void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) { @@ -695,7 +1097,7 @@ void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) { DWORD hex_version = This->baseShader.hex_version; char tmp[20]; - shader_arb_get_write_mask(dst, tmp); + shader_arb_get_write_mask(arg, dst, tmp); if (hex_version != WINED3DPS_VERSION(1,4)) { DWORD reg = dst & WINED3DSP_REGNUM_MASK; shader_addline(buffer, "MOV_SAT T%u%s, fragment.texcoord[%u];\n", reg, tmp, reg); @@ -711,29 +1113,55 @@ void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) { void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg) { SHADER_BUFFER* buffer = arg->buffer; + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; - DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; char dst_str[8]; + char src_str[50]; sprintf(dst_str, "T%u", reg1); - shader_addline(buffer, "MOV TMP.r, T%u.a;\n", reg2); - shader_addline(buffer, "MOV TMP.g, T%u.r;\n", reg2); - shader_hw_sample(arg, reg1, dst_str, "TMP", TRUE); + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_str); + shader_addline(buffer, "MOV TMP.r, %s.a;\n", src_str); + shader_addline(buffer, "MOV TMP.g, %s.r;\n", src_str); + flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg1, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE); } void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) { SHADER_BUFFER* buffer = arg->buffer; + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; - DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; char dst_str[8]; + char src_str[50]; sprintf(dst_str, "T%u", reg1); - shader_addline(buffer, "MOV TMP.r, T%u.g;\n", reg2); - shader_addline(buffer, "MOV TMP.g, T%u.b;\n", reg2); - shader_hw_sample(arg, reg1, dst_str, "TMP", TRUE); + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_str); + shader_addline(buffer, "MOV TMP.r, %s.g;\n", src_str); + shader_addline(buffer, "MOV TMP.g, %s.b;\n", src_str); + flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg1, dst_str, "TMP", FALSE, FALSE); +} + +void pshader_hw_texreg2rgb(SHADER_OPCODE_ARG* arg) { + + SHADER_BUFFER* buffer = arg->buffer; + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; + DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; + char dst_str[8]; + char src_str[50]; + + sprintf(dst_str, "T%u", reg1); + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_str); + flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg1, dst_str, src_str, FALSE, FALSE); } void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) { @@ -771,10 +1199,22 @@ void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) { shader_addline(buffer, "ADD TMP.rg, TMP, %s;\n", reg_coord); } - shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP", FALSE); + shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP", FALSE, FALSE); + + if(arg->opcode->opcode == WINED3DSIO_TEXBEML && This->luminanceconst != -1) { + shader_addline(buffer, "MAD TMP, T%u.z, luminance.x, luminance.y;\n", src); + shader_addline(buffer, "MUL %s, %s, TMP;\n", reg_coord, reg_coord); + } + } else { + DWORD tf; + if(reg_dest_code < MAX_TEXTURES) { + tf = ((IWineD3DDeviceImpl*) This->baseShader.device)->stateBlock->textureState[reg_dest_code][WINED3DTSS_TEXTURETRANSFORMFLAGS]; + } else { + tf = 0; + } /* Without a bump matrix loaded, just sample with the unmodified coordinates */ - shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord, TRUE); + shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord, tf & WINED3DTTFF_PROJECTED, FALSE); } } @@ -790,6 +1230,9 @@ void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) { void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; SHADER_BUFFER* buffer = arg->buffer; char dst_str[8]; @@ -798,7 +1241,8 @@ void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) { sprintf(dst_str, "T%u", reg); pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); shader_addline(buffer, "DP3 TMP.y, T%u, %s;\n", reg, src0_name); - shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE); } void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) { @@ -817,6 +1261,8 @@ void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) { void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) { IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; SHADER_BUFFER* buffer = arg->buffer; SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; @@ -828,13 +1274,16 @@ void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) { /* Sample the texture using the calculated coordinates */ sprintf(dst_str, "T%u", reg); - shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE); current_state->current_row = 0; } void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) { IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; SHADER_BUFFER* buffer = arg->buffer; SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; @@ -849,20 +1298,28 @@ void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) { shader_addline(buffer, "MOV TMP2.y, fragment.texcoord[%u].w;\n", current_state->texcoord_w[1]); shader_addline(buffer, "MOV TMP2.z, fragment.texcoord[%u].w;\n", reg); - /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */ + /* Calculate reflection vector + */ shader_addline(buffer, "DP3 TMP.w, TMP, TMP2;\n"); + /* The .w is ignored when sampling, so I can use TMP2.w to calculate dot(N, N) */ + shader_addline(buffer, "DP3 TMP2.w, TMP, TMP;\n"); + shader_addline(buffer, "RCP TMP2.w, TMP2.w;\n"); + shader_addline(buffer, "MUL TMP.w, TMP.w, TMP2.w;\n"); shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n"); shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -TMP2;\n"); /* Sample the texture using the calculated coordinates */ sprintf(dst_str, "T%u", reg); - shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE); current_state->current_row = 0; } void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) { IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; DWORD reg3 = arg->src[1] & WINED3DSP_REGNUM_MASK; SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; @@ -873,20 +1330,135 @@ void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) { pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name); - /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */ + /* Calculate reflection vector. + * + * dot(N, E) + * TMP.xyz = 2 * --------- * N - E + * dot(N, N) + * + * Which normalizes the normal vector + */ shader_addline(buffer, "DP3 TMP.w, TMP, C[%u];\n", reg3); + shader_addline(buffer, "DP3 TMP2.w, TMP, TMP;\n"); + shader_addline(buffer, "RCP TMP2.w, TMP2.w;\n"); + shader_addline(buffer, "MUL TMP.w, TMP.w, TMP2.w;\n"); shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n"); shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -C[%u];\n", reg3); /* Sample the texture using the calculated coordinates */ sprintf(dst_str, "T%u", reg); - shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0; + shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE); current_state->current_row = 0; } +void pshader_hw_texdepth(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + char dst_name[50]; + + /* texdepth has an implicit destination, the fragment depth value. It's only parameter, + * which is essentially an input, is the destiantion register because it is the first + * param. According to the msdn, this must be register r5, but let's keep it more flexible + * here + */ + pshader_get_register_name(arg->dst, dst_name); + + /* According to the msdn, the source register(must be r5) is unusable after + * the texdepth instruction, so we're free to modify it + */ + shader_addline(buffer, "MIN %s.g, %s.g, one.g;\n", dst_name, dst_name); + + /* How to deal with the special case dst_name.g == 0? if r != 0, then + * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct + * result. But if r = 0.0, then 0 * inf = 0, which is incorrect. + */ + shader_addline(buffer, "RCP %s.g, %s.g;\n", dst_name, dst_name); + shader_addline(buffer, "MUL TMP.x, %s.r, %s.g;\n", dst_name, dst_name); + shader_addline(buffer, "MIN TMP.x, TMP.x, one.r;\n", dst_name, dst_name); + shader_addline(buffer, "MAX result.depth, TMP.x, 0.0;\n", dst_name, dst_name); +} + +/** Process the WINED3DSIO_TEXDP3TEX instruction in ARB: + * Take a 3-component dot product of the TexCoord[dstreg] and src, + * then perform a 1D texture lookup from stage dstregnum, place into dst. */ +void pshader_hw_texdp3tex(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + char src0[50]; + char dst_str[8]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0); + shader_addline(buffer, "MOV TMP, 0.0;\n"); + shader_addline(buffer, "DP3 TMP.x, T%u, %s;\n", sampler_idx, src0); + + sprintf(dst_str, "T%u", sampler_idx); + shader_hw_sample(arg, sampler_idx, dst_str, "TMP", FALSE /* Only one coord, can't be projected */, FALSE); +} + +/** Process the WINED3DSIO_TEXDP3 instruction in ARB: + * Take a 3-component dot product of the TexCoord[dstreg] and src. */ +void pshader_hw_texdp3(SHADER_OPCODE_ARG* arg) { + char src0[50]; + char dst_str[50]; + char dst_mask[6]; + DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + + /* Handle output register */ + pshader_get_register_name(arg->dst, dst_str); + shader_arb_get_write_mask(arg, arg->dst, dst_mask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0); + shader_addline(buffer, "DP3 %s%s, T%u, %s;\n", dst_str, dst_mask, dstreg, src0); + + /* TODO: Handle output modifiers */ +} + +/** Process the WINED3DSIO_TEXM3X3 instruction in ARB + * Perform the 3rd row of a 3x3 matrix multiply */ +void pshader_hw_texm3x3(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + char dst_str[50]; + char dst_mask[6]; + char src0[50]; + DWORD dst_reg = arg->dst & WINED3DSP_REGNUM_MASK; + + pshader_get_register_name(arg->dst, dst_str); + shader_arb_get_write_mask(arg, arg->dst, dst_mask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0); + shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", dst_reg, src0); + shader_addline(buffer, "MOV %s%s, TMP;\n", dst_str, dst_mask); + + /* TODO: Handle output modifiers */ +} + +/** Process the WINED3DSIO_TEXM3X2DEPTH instruction in ARB: + * Last row of a 3x2 matrix multiply, use the result to calculate the depth: + * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated) + * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y + */ +void pshader_hw_texm3x2depth(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + DWORD dst_reg = arg->dst & WINED3DSP_REGNUM_MASK; + char src0[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0); + shader_addline(buffer, "DP3 TMP.y, T%u, %s;\n", dst_reg, src0); + + /* How to deal with the special case dst_name.g == 0? if r != 0, then + * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct + * result. But if r = 0.0, then 0 * inf = 0, which is incorrect. + */ + shader_addline(buffer, "RCP TMP.y, TMP.y;\n"); + shader_addline(buffer, "MUL TMP.x, TMP.x, TMP.y;\n"); + shader_addline(buffer, "MIN TMP.x, TMP.x, one.r;\n"); + shader_addline(buffer, "MAX result.depth, TMP.x, 0.0;\n"); +} + /** Handles transforming all WINED3DSIO_M?x? opcodes for - Vertex shaders to ARB_vertex_program codes */ -void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) { + Vertex/Pixel shaders to ARB_vertex_program codes */ +void shader_hw_mnxn(SHADER_OPCODE_ARG* arg) { int i; int nComponents = 0; @@ -957,10 +1529,57 @@ void vshader_hw_rsq_rcp(SHADER_OPCODE_ARG* arg) { shader_addline(buffer, "%s;\n", tmpLine); } +void shader_hw_nrm(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + char dst_name[50]; + char src_name[50]; + char dst_wmask[20]; + DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE; + + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name); + shader_addline(buffer, "DP3 TMP, %s, %s;\n", src_name, src_name); + shader_addline(buffer, "RSQ TMP, TMP.x;\n"); + /* dst.w = src[0].w * 1 / (src.x^2 + src.y^2 + src.z^2)^(1/2) according to msdn*/ + shader_addline(buffer, "MUL%s %s%s, %s, TMP;\n", sat ? "_SAT" : "", dst_name, dst_wmask, + src_name); + + if (shift != 0) + pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name); +} + +void shader_hw_sincos(SHADER_OPCODE_ARG* arg) { + /* This instruction exists in ARB, but the d3d instruction takes two extra parameters which + * must contain fixed constants. So we need a separate functin to filter those constants and + * can't use map2gl + */ + SHADER_BUFFER* buffer = arg->buffer; + char dst_name[50]; + char src_name[50]; + char dst_wmask[20]; + DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE; + + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg, arg->dst, dst_wmask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name); + shader_addline(buffer, "SCS%s %s%s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, + src_name); + + if (shift != 0) + pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name); + +} + /* TODO: merge with pixel shader */ /* Map the opcode 1-to-1 to the GL code */ void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { + IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl*) arg->shader; CONST SHADER_OPCODE* curOpcode = arg->opcode; SHADER_BUFFER* buffer = arg->buffer; DWORD dst = arg->dst; @@ -970,9 +1589,17 @@ void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { char tmpLine[256]; unsigned int i; - if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) - strcpy(tmpLine, "ARL"); - else + if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) { + if(shader->rel_offset) { + memset(tmpLine, 0, sizeof(tmpLine)); + vshader_program_add_param(arg, src[0], TRUE, tmpLine); + shader_addline(buffer, "ADD TMP.x, %s, helper_const.z;\n", tmpLine); + shader_addline(buffer, "ARL A0.x, TMP.x;\n"); + return; + } else { + strcpy(tmpLine, "ARL"); + } + } else strcpy(tmpLine, curOpcode->glname); if (curOpcode->num_params > 0) { @@ -1100,5 +1727,6 @@ const shader_backend_t arb_program_shader_backend = { &shader_arb_select, &shader_arb_select_depth_blt, &shader_arb_load_constants, - &shader_arb_cleanup + &shader_arb_cleanup, + &shader_arb_color_correction }; diff --git a/reactos/dll/directx/wine/wined3d/baseshader.c b/reactos/dll/directx/wine/wined3d/baseshader.c index 8035abb0f40..520554fd289 100644 --- a/reactos/dll/directx/wine/wined3d/baseshader.c +++ b/reactos/dll/directx/wine/wined3d/baseshader.c @@ -193,11 +193,13 @@ HRESULT shader_get_registers_used( IWineD3DStateBlockImpl *stateBlock) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + unsigned int cur_loop_depth = 0, max_loop_depth = 0; /* There are some minor differences between pixel and vertex shaders */ char pshader = shader_is_pshader_version(This->baseShader.hex_version); reg_maps->bumpmat = -1; + reg_maps->luminanceparams = -1; if (pToken == NULL) return WINED3D_OK; @@ -266,6 +268,20 @@ HRESULT shader_get_registers_used( if (!lconst) return E_OUTOFMEMORY; lconst->idx = *pToken & WINED3DSP_REGNUM_MASK; memcpy(&lconst->value, pToken + 1, 4 * sizeof(DWORD)); + + /* In pixel shader 1.X shaders, the constants are clamped between [-1;1] */ + if(WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 && pshader) { + float *value = (float *) lconst->value; + if(value[0] < -1.0) value[0] = -1.0; + else if(value[0] > 1.0) value[0] = 1.0; + if(value[1] < -1.0) value[1] = -1.0; + else if(value[1] > 1.0) value[1] = 1.0; + if(value[2] < -1.0) value[2] = -1.0; + else if(value[2] > 1.0) value[2] = 1.0; + if(value[3] < -1.0) value[3] = -1.0; + else if(value[3] > 1.0) value[3] = 1.0; + } + list_add_head(&This->baseShader.constantsF, &lconst->entry); pToken += curOpcode->num_params; @@ -290,9 +306,15 @@ HRESULT shader_get_registers_used( /* If there's a loop in the shader */ } else if (WINED3DSIO_LOOP == curOpcode->opcode || WINED3DSIO_REP == curOpcode->opcode) { - reg_maps->loop = 1; + cur_loop_depth++; + if(cur_loop_depth > max_loop_depth) + max_loop_depth = cur_loop_depth; pToken += curOpcode->num_params; - + + } else if (WINED3DSIO_ENDLOOP == curOpcode->opcode || + WINED3DSIO_ENDREP == curOpcode->opcode) { + cur_loop_depth--; + /* For subroutine prototypes */ } else if (WINED3DSIO_LABEL == curOpcode->opcode) { @@ -300,14 +322,6 @@ HRESULT shader_get_registers_used( reg_maps->labels[snum] = 1; pToken += curOpcode->num_params; - } else if(WINED3DSIO_BEM == curOpcode->opcode) { - DWORD regnum = *pToken & WINED3DSP_REGNUM_MASK; - if(reg_maps->bumpmat != -1 && reg_maps->bumpmat != regnum) { - FIXME("Pixel shader uses bem or texbem instruction on more than 1 sampler\n"); - } else { - reg_maps->bumpmat = regnum; - } - /* Set texture, address, temporary registers */ } else { int i, limit; @@ -354,14 +368,30 @@ HRESULT shader_get_registers_used( } /* texbem is only valid with < 1.4 pixel shaders */ - if(WINED3DSIO_TEXBEM == curOpcode->opcode) { + if(WINED3DSIO_TEXBEM == curOpcode->opcode || + WINED3DSIO_TEXBEML == curOpcode->opcode) { if(reg_maps->bumpmat != -1 && reg_maps->bumpmat != sampler_code) { FIXME("Pixel shader uses texbem instruction on more than 1 sampler\n"); } else { reg_maps->bumpmat = sampler_code; + if(WINED3DSIO_TEXBEML == curOpcode->opcode) { + reg_maps->luminanceparams = sampler_code; + } } } } + if(WINED3DSIO_NRM == curOpcode->opcode) { + reg_maps->usesnrm = 1; + } else if(WINED3DSIO_BEM == curOpcode->opcode) { + DWORD regnum = *pToken & WINED3DSP_REGNUM_MASK; + if(reg_maps->bumpmat != -1 && reg_maps->bumpmat != regnum) { + FIXME("Pixel shader uses bem or texbem instruction on more than 1 sampler\n"); + } else { + reg_maps->bumpmat = regnum; + } + } else if(WINED3DSIO_DSY == curOpcode->opcode) { + reg_maps->usesdsy = 1; + } /* This will loop over all the registers and try to * make a bitmask of the ones we're interested in. @@ -392,14 +422,43 @@ HRESULT shader_get_registers_used( else if (WINED3DSPR_TEMP == regtype) reg_maps->temporary[reg] = 1; - else if (WINED3DSPR_INPUT == regtype && !pshader) - reg_maps->attributes[reg] = 1; + else if (WINED3DSPR_INPUT == regtype) { + if( !pshader) + reg_maps->attributes[reg] = 1; + else { + if(param & WINED3DSHADER_ADDRMODE_RELATIVE) { + /* If relative addressing is used, we must assume that all registers + * are used. Even if it is a construct like v3[aL], we can't assume + * that v0, v1 and v2 aren't read because aL can be negative + */ + unsigned int i; + for(i = 0; i < MAX_REG_INPUT; i++) { + ((IWineD3DPixelShaderImpl *) This)->input_reg_used[i] = TRUE; + } + } else { + ((IWineD3DPixelShaderImpl *) This)->input_reg_used[reg] = TRUE; + } + } + } else if (WINED3DSPR_RASTOUT == regtype && reg == 1) reg_maps->fog = 1; - } + + else if (WINED3DSPR_MISCTYPE == regtype && reg == 0 && pshader) + reg_maps->vpos = 1; + + else if(WINED3DSPR_CONST == regtype && !pshader && + param & WINED3DSHADER_ADDRMODE_RELATIVE) { + if(reg <= ((IWineD3DVertexShaderImpl *) This)->min_rel_offset) { + ((IWineD3DVertexShaderImpl *) This)->min_rel_offset = reg; + } else if(reg >= ((IWineD3DVertexShaderImpl *) This)->max_rel_offset) { + ((IWineD3DVertexShaderImpl *) This)->max_rel_offset = reg; + } + } + } } } + reg_maps->loop_depth = max_loop_depth; return WINED3D_OK; } @@ -699,6 +758,7 @@ void shader_generate_main( CONST DWORD* pFunction) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device; /* To access shader backend callbacks */ const DWORD *pToken = pFunction; const SHADER_OPCODE *curOpcode = NULL; SHADER_HANDLER hw_fct = NULL; @@ -788,6 +848,9 @@ void shader_generate_main( /* Call appropriate function for output target */ hw_fct(&hw_arg); + /* Add color correction if needed */ + device->shader_backend->shader_color_correction(&hw_arg); + /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */ if (This->baseShader.shader_mode == SHADER_GLSL) shader_glsl_add_instruction_modifiers(&hw_arg); @@ -930,6 +993,10 @@ void shader_trace_init( shader_dump_param(iface, *(pToken + 2), 0, 1); TRACE(") "); } + if (opcode_token & WINED3DSI_COISSUE) { + /* PixWin marks instructions with the coissue flag with a '+' */ + TRACE("+"); + } TRACE("%s", curOpcode->name); diff --git a/reactos/dll/directx/wine/wined3d/basetexture.c b/reactos/dll/directx/wine/wined3d/basetexture.c index 8df0b3e8bc3..a1290f869ce 100644 --- a/reactos/dll/directx/wine/wined3d/basetexture.c +++ b/reactos/dll/directx/wine/wined3d/basetexture.c @@ -161,11 +161,39 @@ DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface) { HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + UINT textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) { TRACE("(%p) : returning invalid call\n", This); return WINED3DERR_INVALIDCALL; } + if(This->baseTexture.filterType != FilterType) { + /* What about multithreading? Do we want all the context overhead just to set this value? + * Or should we delay the applying until the texture is used for drawing? For now, apply + * immediately. + */ + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + glBindTexture(textureDimensions, This->baseTexture.textureName); + checkGLcall("glBindTexture"); + switch(FilterType) { + case WINED3DTEXF_NONE: + case WINED3DTEXF_POINT: + glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST); + checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST)"); + + case WINED3DTEXF_LINEAR: + glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); + checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); + + default: + WARN("Unexpected filter type %d, setting to GL_NICEST\n", FilterType); + glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); + checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST)"); + } + LEAVE_GL(); + } This->baseTexture.filterType = FilterType; TRACE("(%p) :\n", This); return WINED3D_OK; @@ -239,6 +267,16 @@ HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) { This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP; IWineD3DBaseTexture_SetDirty(iface, TRUE); isNewTexture = TRUE; + + if(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) { + /* This means double binding the texture at creation, but keeps the code simpler all + * in all, and the run-time path free from additional checks + */ + glBindTexture(textureDimensions, This->baseTexture.textureName); + checkGLcall("glBindTexture"); + glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); + checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)"); + } } /* Bind the texture */ diff --git a/reactos/dll/directx/wine/wined3d/context.c b/reactos/dll/directx/wine/wined3d/context.c index 25078353e23..8311ab5be9d 100644 --- a/reactos/dll/directx/wine/wined3d/context.c +++ b/reactos/dll/directx/wine/wined3d/context.c @@ -131,10 +131,12 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar TRACE("(%p): Creating a %s context for render target %p\n", This, create_pbuffer ? "offscreen" : "onscreen", target); +#define PUSH1(att) attribs[nAttribs++] = (att); +#define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value); if(create_pbuffer) { HDC hdc_parent = GetDC(win_handle); int iPixelFormat = 0; - short red, green, blue, alphaBits, colorBits; + short redBits, greenBits, blueBits, alphaBits, colorBits; short depthBits, stencilBits; IWineD3DSurface *StencilSurface = This->stencilBufferTarget; @@ -144,23 +146,20 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar int nAttribs = 0; unsigned int nFormats; -#define PUSH1(att) attribs[nAttribs++] = (att); -#define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value); - /* Retrieve the specifications for the pixelformat from the backbuffer / stencilbuffer */ - getColorBits(target->resource.format, &red, &green, &blue, &alphaBits, &colorBits); + getColorBits(target->resource.format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits); getDepthStencilBits(StencilBufferFormat, &depthBits, &stencilBits); PUSH2(WGL_DRAW_TO_PBUFFER_ARB, 1); /* We need pbuffer support; doublebuffering isn't needed */ PUSH2(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); /* Make sure we don't get a float or color index format */ PUSH2(WGL_COLOR_BITS_ARB, colorBits); + PUSH2(WGL_RED_BITS_ARB, redBits); + PUSH2(WGL_GREEN_BITS_ARB, greenBits); + PUSH2(WGL_BLUE_BITS_ARB, blueBits); PUSH2(WGL_ALPHA_BITS_ARB, alphaBits); PUSH2(WGL_DEPTH_BITS_ARB, depthBits); PUSH2(WGL_STENCIL_BITS_ARB, stencilBits); PUSH1(0); /* end the list */ -#undef PUSH1 -#undef PUSH2 - /* Try to find a pixelformat that matches exactly. If that fails let ChoosePixelFormat try to find a close match */ if(!GL_EXTCALL(wglChoosePixelFormatARB(hdc_parent, (const int*)&attribs, NULL, 1, &iPixelFormat, &nFormats))) { @@ -205,10 +204,12 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar } else { PIXELFORMATDESCRIPTOR pfd; int iPixelFormat; - short red, green, blue, alpha; - short colorBits; - short depthBits, stencilBits; + short redBits, greenBits, blueBits, alphaBits, colorBits; + short depthBits=0, stencilBits=0; int res; + int attribs[256]; + int nAttribs = 0; + unsigned int nFormats; hdc = GetDC(win_handle); if(hdc == NULL) { @@ -217,36 +218,57 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar } /* PixelFormat selection */ - /* TODO: fill cColorBits/cDepthBits with target->resource.format */ - ZeroMemory(&pfd, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/ - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cDepthBits = 0; - pfd.cStencilBits = 0; - pfd.iLayerType = PFD_MAIN_PLANE; + PUSH2(WGL_DRAW_TO_WINDOW_ARB, GL_TRUE); /* We want to draw to a window */ + PUSH2(WGL_DOUBLE_BUFFER_ARB, GL_TRUE); + PUSH2(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); /* Make sure we don't get a float or color index format */ + PUSH2(WGL_SUPPORT_OPENGL_ARB, GL_TRUE); + PUSH2(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); /* Make sure we receive an accelerated format. On windows (at least on ATI) this is not always the case */ - /* Try to match the colorBits of the d3d format */ - if(getColorBits(target->resource.format, &red, &green, &blue, &alpha, &colorBits)) - pfd.cColorBits = colorBits; + if(!getColorBits(target->resource.format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits)) { + ERR("Unable to get color bits for format %#x!\n", target->resource.format); + return FALSE; + } + PUSH2(WGL_COLOR_BITS_ARB, colorBits); + PUSH2(WGL_RED_BITS_ARB, redBits); + PUSH2(WGL_GREEN_BITS_ARB, greenBits); + PUSH2(WGL_BLUE_BITS_ARB, blueBits); + PUSH2(WGL_ALPHA_BITS_ARB, alphaBits); /* Retrieve the depth stencil format from the present parameters. * The choice of the proper format can give a nice performance boost * in case of GPU limited programs. */ if(pPresentParms->EnableAutoDepthStencil) { TRACE("pPresentParms->EnableAutoDepthStencil=enabled; using AutoDepthStencilFormat=%s\n", debug_d3dformat(pPresentParms->AutoDepthStencilFormat)); - if(getDepthStencilBits(pPresentParms->AutoDepthStencilFormat, &depthBits, &stencilBits)) { - pfd.cDepthBits = depthBits; - pfd.cStencilBits = stencilBits; + if(!getDepthStencilBits(pPresentParms->AutoDepthStencilFormat, &depthBits, &stencilBits)) { + ERR("Unable to get depth / stencil bits for AutoDepthStencilFormat %#x!\n", pPresentParms->AutoDepthStencilFormat); + return FALSE; } + PUSH2(WGL_DEPTH_BITS_ARB, depthBits); + PUSH2(WGL_STENCIL_BITS_ARB, stencilBits); } - iPixelFormat = ChoosePixelFormat(hdc, &pfd); - if(!iPixelFormat) { - /* If this happens something is very wrong as ChoosePixelFormat barely fails */ - ERR("Can't find a suitable iPixelFormat\n"); + PUSH1(0); /* end the list */ + + /* In case of failure hope that standard ChooosePixelFormat will find something suitable */ + if(!GL_EXTCALL(wglChoosePixelFormatARB(hdc, (const int*)&attribs, NULL, 1, &iPixelFormat, &nFormats))) + { + /* PixelFormat selection */ + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/ + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cAlphaBits = alphaBits; + pfd.cColorBits = colorBits; + pfd.cDepthBits = depthBits; + pfd.cStencilBits = stencilBits; + pfd.iLayerType = PFD_MAIN_PLANE; + + iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if(!iPixelFormat) { + /* If this happens something is very wrong as ChoosePixelFormat barely fails */ + ERR("Can't find a suitable iPixelFormat\n"); + } } DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd); @@ -265,6 +287,8 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar } } } +#undef PUSH1 +#undef PUSH2 ctx = pwglCreateContext(hdc); if(This->numContexts) pwglShareLists(This->contexts[0]->glCtx, ctx); @@ -301,6 +325,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar goto out; } + ENTER_GL(); TRACE("Setting up the screen\n"); /* Clear the screen */ glClearColor(1.0, 0.0, 0.0, 0.0); @@ -366,6 +391,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"); } } + LEAVE_GL(); if(oldDrawable && oldCtx) { pwglMakeCurrent(oldDrawable, oldCtx); @@ -568,6 +594,16 @@ static inline void SetupForBlit(IWineD3DDeviceImpl *This, WineD3DContext *contex glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE); checkGLcall("glColorMask"); Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING)); + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + glDisable(GL_COLOR_SUM_EXT); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SPECULARENABLE)); + checkGLcall("glDisable(GL_COLOR_SUM_EXT)"); + } + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB)); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SPECULARENABLE)); + checkGLcall("glFinalCombinerInputNV"); + } /* Setup transforms */ glMatrixMode(GL_MODELVIEW); @@ -638,7 +674,7 @@ static WineD3DContext *findThreadContextForSwapChain(IWineD3DSwapChain *swapchai * Returns: The needed context * *****************************************************************************/ -static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, DWORD tid) { +static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, DWORD tid, GLint *buffer) { IWineD3DSwapChain *swapchain = NULL; HRESULT hr; BOOL readTexture = wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_offscreen; @@ -657,15 +693,12 @@ static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurf * rendering. No context change is needed in that case */ - if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER) { - if(((IWineD3DSwapChainImpl *) swapchain)->backBuffer) { - glDrawBuffer(GL_BACK); - checkGLcall("glDrawBuffer(GL_BACK)"); - } else { - glDrawBuffer(GL_FRONT); - checkGLcall("glDrawBuffer(GL_FRONT)"); - } - } else if(wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER) { + if(((IWineD3DSwapChainImpl *) swapchain)->frontBuffer == target) { + *buffer = GL_FRONT; + } else { + *buffer = GL_BACK; + } + if(wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER) { if(This->pbufferContext && tid == This->pbufferContext->tid) { This->pbufferContext->tid = 0; } @@ -673,16 +706,17 @@ static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurf IWineD3DSwapChain_Release(swapchain); if(oldRenderOffscreen) { - Context_MarkStateDirty(context, WINED3DRS_CULLMODE); Context_MarkStateDirty(context, WINED3DTS_PROJECTION); Context_MarkStateDirty(context, STATE_VDECL); Context_MarkStateDirty(context, STATE_VIEWPORT); Context_MarkStateDirty(context, STATE_SCISSORRECT); + Context_MarkStateDirty(context, STATE_FRONTFACE); } } else { TRACE("Rendering offscreen\n"); This->render_offscreen = TRUE; + *buffer = This->offscreenBuffer; switch(wined3d_settings.offscreen_rendering_mode) { case ORM_FBO: @@ -748,8 +782,6 @@ static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurf */ context = findThreadContextForSwapChain(This->swapchains[0], tid); } - glDrawBuffer(This->offscreenBuffer); - checkGLcall("glDrawBuffer(This->offscreenBuffer)"); break; } @@ -761,11 +793,11 @@ static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurf } if(!oldRenderOffscreen) { - Context_MarkStateDirty(context, WINED3DRS_CULLMODE); Context_MarkStateDirty(context, WINED3DTS_PROJECTION); Context_MarkStateDirty(context, STATE_VDECL); Context_MarkStateDirty(context, STATE_VIEWPORT); Context_MarkStateDirty(context, STATE_SCISSORRECT); + Context_MarkStateDirty(context, STATE_FRONTFACE); } } if (readTexture) { @@ -783,7 +815,7 @@ static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurf IWineD3DSurface_PreLoad(This->lastActiveRenderTarget); /* Assume that the drawable will be modified by some other things now */ - ((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INDRAWABLE; + IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, FALSE); This->isInDraw = oldInDraw; } @@ -813,12 +845,11 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU DWORD dirtyState, idx; BYTE shift; WineD3DContext *context; + GLint drawBuffer=0; TRACE("(%p): Selecting context for render target %p, thread %d\n", This, target, tid); - - ENTER_GL(); if(This->lastActiveRenderTarget != target || tid != This->lastThread) { - context = FindContext(This, target, tid); + context = FindContext(This, target, tid, &drawBuffer); This->lastActiveRenderTarget = target; This->lastThread = tid; } else { @@ -830,15 +861,24 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU if(context != This->activeContext) { BOOL ret; TRACE("Switching gl ctx to %p, hdc=%p ctx=%p\n", context, context->hdc, context->glCtx); - LEAVE_GL(); ret = pwglMakeCurrent(context->hdc, context->glCtx); - ENTER_GL(); if(ret == FALSE) { ERR("Failed to activate the new context\n"); } This->activeContext = context; } + /* We only need ENTER_GL for the gl calls made below and for the helper functions which make GL calls */ + ENTER_GL(); + /* Select the right draw buffer. It is selected in FindContext. */ + if(drawBuffer && context->last_draw_buffer != drawBuffer) { + TRACE("Drawing to buffer: %#x\n", drawBuffer); + context->last_draw_buffer = drawBuffer; + + glDrawBuffer(drawBuffer); + checkGLcall("glDrawBuffer"); + } + switch(usage) { case CTXUSAGE_RESOURCELOAD: /* This does not require any special states to be set up */ diff --git a/reactos/dll/directx/wine/wined3d/cubetexture.c b/reactos/dll/directx/wine/wined3d/cubetexture.c index d91ee6ce9e5..3cb44e62e8a 100644 --- a/reactos/dll/directx/wine/wined3d/cubetexture.c +++ b/reactos/dll/directx/wine/wined3d/cubetexture.c @@ -148,7 +148,7 @@ static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) { for (i = 0; i < This->baseTexture.levels; i++) { for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { - IWineD3DSurfaceImpl_AddDirtyRect(This->surfaces[j][i], NULL); + IWineD3DSurface_AddDirtyRect(This->surfaces[j][i], NULL); IWineD3DSurface_SetGlTextureDesc(This->surfaces[j][i], This->baseTexture.textureName, cube_targets[j]); IWineD3DSurface_LoadTexture(This->surfaces[j][i], srgb_mode); } @@ -272,7 +272,7 @@ static void WINAPI IWineD3DCubeTextureImpl_ApplyStateChanges(IWineD3DCubeTexture ******************************************* */ static void WINAPI IWineD3DCubeTextureImpl_Destroy(IWineD3DCubeTexture *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroySurface) { IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; - int i,j; + unsigned int i,j; TRACE("(%p) : Cleaning up\n",This); for (i = 0; i < This->baseTexture.levels; i++) { for (j = 0; j < 6; j++) { diff --git a/reactos/dll/directx/wine/wined3d/device.c b/reactos/dll/directx/wine/wined3d/device.c index 7b9d92ebae6..ef6a0eaa411 100644 --- a/reactos/dll/directx/wine/wined3d/device.c +++ b/reactos/dll/directx/wine/wined3d/device.c @@ -99,15 +99,16 @@ static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3 *pp##type = NULL; \ return WINED3DERR_OUTOFVIDEOMEMORY; \ } \ - globalChangeGlRam(_size); \ + WineD3DAdapterChangeGLRam(This, _size); \ } \ - object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \ - if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \ + object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \ + if (object->resource.heapMemory == NULL && _size != 0) { \ FIXME("Out of memory!\n"); \ HeapFree(GetProcessHeap(), 0, object); \ *pp##type = NULL; \ return WINED3DERR_OUTOFVIDEOMEMORY; \ } \ + object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \ *pp##type = (IWineD3D##type *) object; \ IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\ TRACE("(%p) : Created resource %p\n", This, object); \ @@ -303,6 +304,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *ifac WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n"); *ppVertexBuffer = NULL; return WINED3DERR_INVALIDCALL; + } else if(Pool == WINED3DPOOL_SCRATCH) { + /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense + * anyway, SCRATCH vertex buffers aren't useable anywhere + */ + WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n"); + *ppVertexBuffer = NULL; + return WINED3DERR_INVALIDCALL; } D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size) @@ -310,9 +318,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *ifac TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object); *ppVertexBuffer = (IWineD3DVertexBuffer *)object; - if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */ - object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size); - } object->fvf = FVF; /* Observations show that drawStridedSlow is faster on dynamic VBs than converting + @@ -398,10 +403,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface /* Allocate the storage for the device */ D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length) - if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */ - object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size); - } - if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) { CreateIndexBufferVBO(This, object); } @@ -469,6 +470,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) { object->contained_render_states[j - 1] = j; } + object->num_contained_render_states = WINEHIGHEST_RENDER_STATE; /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */ for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) { object->contained_transform_states[j - 1] = j; @@ -513,6 +515,21 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, } } + for(i = 0; i < MAX_STREAMS; i++) { + if(object->streamSource[i]) { + IWineD3DVertexBuffer_AddRef(object->streamSource[i]); + } + } + if(object->pIndexData) { + IWineD3DIndexBuffer_AddRef(object->pIndexData); + } + if(object->vertexShader) { + IWineD3DVertexShader_AddRef(object->vertexShader); + } + if(object->pixelShader) { + IWineD3DPixelShader_AddRef(object->pixelShader); + } + } else if (Type == WINED3DSBT_PIXELSTATE) { TRACE("PIXELSTATE => Pretend all pixel shates have changed\n"); @@ -558,6 +575,18 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, object->num_contained_sampler_states++; } } + if(object->pixelShader) { + IWineD3DPixelShader_AddRef(object->pixelShader); + } + + /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting + * on them. This makes releasing the buffer easier + */ + for(i = 0; i < MAX_STREAMS; i++) { + object->streamSource[i] = NULL; + } + object->pIndexData = NULL; + object->vertexShader = NULL; } else if (Type == WINED3DSBT_VERTEXSTATE) { @@ -612,6 +641,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, light->enabledChanged = TRUE; } } + + for(i = 0; i < MAX_STREAMS; i++) { + if(object->streamSource[i]) { + IWineD3DVertexBuffer_AddRef(object->streamSource[i]); + } + } + if(object->vertexShader) { + IWineD3DVertexShader_AddRef(object->vertexShader); + } + object->pIndexData = NULL; + object->pixelShader = NULL; } else { FIXME("Unrecognized state block type %d\n", Type); } @@ -807,6 +847,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U HRESULT hr; unsigned int pow2Width; unsigned int pow2Height; + const GlPixelFormatDesc *glDesc; + getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc); TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage); @@ -843,7 +885,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY); /* Calculate levels for mip mapping */ - if (Levels == 0) { + if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) { + if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { + WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + if(Levels > 1) { + WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + object->baseTexture.levels = 1; + } else if (Levels == 0) { TRACE("calculating levels %d\n", object->baseTexture.levels); object->baseTexture.levels++; tmpW = Width; @@ -879,6 +931,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U tmpW = max(1, tmpW >> 1); tmpH = max(1, tmpH >> 1); } + object->baseTexture.shader_conversion_group = glDesc->conversion_group; TRACE("(%p) : Created texture %p\n", This, object); return WINED3D_OK; @@ -898,6 +951,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa UINT tmpW; UINT tmpH; UINT tmpD; + const GlPixelFormatDesc *glDesc; + + getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc); /* TODO: It should only be possible to create textures for formats that are reported as supported */ @@ -905,6 +961,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This); return WINED3DERR_INVALIDCALL; } + if(!GL_SUPPORT(EXT_TEXTURE3D)) { + WARN("(%p) : Texture cannot be created - no volume texture support\n", This); + return WINED3DERR_INVALIDCALL; + } D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0); D3DINITIALIZEBASETEXTURE(object->baseTexture); @@ -917,7 +977,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa object->depth = Depth; /* Calculate levels for mip mapping */ - if (Levels == 0) { + if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) { + if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { + WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + if(Levels > 1) { + WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + Levels = 1; + } else if (Levels == 0) { object->baseTexture.levels++; tmpW = Width; tmpH = Height; @@ -958,6 +1028,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa tmpH = max(1, tmpH >> 1); tmpD = max(1, tmpD >> 1); } + object->baseTexture.shader_conversion_group = glDesc->conversion_group; *ppVolumeTexture = (IWineD3DVolumeTexture *) object; TRACE("(%p) : Created volume texture %p\n", This, object); @@ -975,6 +1046,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/ const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL); + if(!GL_SUPPORT(EXT_TEXTURE3D)) { + WARN("(%p) : Volume cannot be created - no volume texture support\n", This); + return WINED3DERR_INVALIDCALL; + } + D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth)) TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height, @@ -1007,6 +1083,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface UINT tmpW; HRESULT hr; unsigned int pow2EdgeLength = EdgeLength; + const GlPixelFormatDesc *glDesc; + getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc); /* TODO: It should only be possible to create textures for formats that are reported as supported */ @@ -1037,7 +1115,23 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength); /* Calculate levels for mip mapping */ - if (Levels == 0) { + if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) { + if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { + WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n"); + HeapFree(GetProcessHeap(), 0, object); + *ppCubeTexture = NULL; + + return WINED3DERR_INVALIDCALL; + } + if(Levels > 1) { + WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n"); + HeapFree(GetProcessHeap(), 0, object); + *ppCubeTexture = NULL; + + return WINED3DERR_INVALIDCALL; + } + Levels = 1; + } else if (Levels == 0) { object->baseTexture.levels++; tmpW = EdgeLength; while (tmpW > 1) { @@ -1062,11 +1156,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface int k; int l; for (l = 0; l < j; l++) { - IWineD3DSurface_Release(object->surfaces[j][i]); + IWineD3DSurface_Release(object->surfaces[l][i]); } for (k = 0; k < i; k++) { for (l = 0; l < 6; l++) { - IWineD3DSurface_Release(object->surfaces[l][j]); + IWineD3DSurface_Release(object->surfaces[l][k]); } } @@ -1080,6 +1174,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface } tmpW = max(1, tmpW >> 1); } + object->baseTexture.shader_conversion_group = glDesc->conversion_group; TRACE("(%p) : Created Cube Texture %p\n", This, object); *ppCubeTexture = (IWineD3DCubeTexture *) object; @@ -1135,20 +1230,22 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINE /* allocated the 'extended' data based on the type of query requested */ switch(Type){ case WINED3DQUERYTYPE_OCCLUSION: + object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData)); + ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext; + if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) { TRACE("(%p) Allocating data for an occlusion query\n", This); - object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData)); GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId)); break; } case WINED3DQUERYTYPE_EVENT: - /* TODO: GL_APPLE_fence */ + object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); + ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext; + if(GL_SUPPORT(APPLE_FENCE)) { - object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId)); checkGLcall("glGenFencesAPPLE"); } else if(GL_SUPPORT(NV_FENCE)) { - object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId)); checkGLcall("glGenFencesNV"); } @@ -1271,6 +1368,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/ HRESULT hr = WINED3D_OK; IUnknown *bufferParent; + BOOL displaymode_set = FALSE; TRACE("(%p) : Created Aditional Swap Chain\n", This); @@ -1298,8 +1396,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic if (!object->win_handle) { object->win_handle = This->createParms.hFocusWindow; } + if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle); - object->win_handle = GetAncestor(object->win_handle, GA_ROOT); hDc = GetDC(object->win_handle); TRACE("Using hDc %p\n", hDc); @@ -1320,7 +1418,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic if (pPresentationParameters->Windowed && ((pPresentationParameters->BackBufferWidth == 0) || - (pPresentationParameters->BackBufferHeight == 0))) { + (pPresentationParameters->BackBufferHeight == 0) || + (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) { RECT Rect; GetClientRect(object->win_handle, &Rect); @@ -1333,6 +1432,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic pPresentationParameters->BackBufferHeight = Rect.bottom; TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight); } + if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) { + pPresentationParameters->BackBufferFormat = object->orig_fmt; + TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt)); + } } /* Put the correct figures in the presentation parameters */ @@ -1351,39 +1454,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic &object->frontBuffer, NULL /* pShared (always null)*/); if (object->frontBuffer != NULL) { + IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE); IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object); } else { ERR("Failed to create the front buffer\n"); goto error; } - /** - * Create an opengl context for the display visual - * NOTE: the visual is chosen as the window is created and the glcontext cannot - * use different properties after that point in time. FIXME: How to handle when requested format - * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one - * it chooses is identical to the one already being used! - **********************************/ - /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/ - - object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context)); - if(!object->context) - return E_OUTOFMEMORY; - object->num_contexts = 1; - - ENTER_GL(); - object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters); - LEAVE_GL(); - - if (!object->context[0]) { - ERR("Failed to create a new context\n"); - hr = WINED3DERR_NOTAVAILABLE; - goto error; - } else { - TRACE("Context created (HWND=%p, glContext=%p)\n", - object->win_handle, object->context[0]->glCtx); - } - /********************* * Windowed / Fullscreen *******************/ @@ -1414,6 +1491,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth; devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight; ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); + displaymode_set = TRUE; /* For GetDisplayMode */ This->ddraw_width = devmode.dmPelsWidth; @@ -1427,6 +1505,30 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic ClipCursor(&clip_rc); } + /** + * Create an opengl context for the display visual + * NOTE: the visual is chosen as the window is created and the glcontext cannot + * use different properties after that point in time. FIXME: How to handle when requested format + * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one + * it chooses is identical to the one already being used! + **********************************/ + /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/ + + object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context)); + if(!object->context) + return E_OUTOFMEMORY; + object->num_contexts = 1; + + object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters); + if (!object->context[0]) { + ERR("Failed to create a new context\n"); + hr = WINED3DERR_NOTAVAILABLE; + goto error; + } else { + TRACE("Context created (HWND=%p, glContext=%p)\n", + object->win_handle, object->context[0]->glCtx); + } + /********************* * Create the back, front and stencil buffers *******************/ @@ -1504,6 +1606,30 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevic return WINED3D_OK; error: + if (displaymode_set) { + DEVMODEW devmode; + HDC hdc; + int bpp = 0; + RECT clip_rc; + + SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height); + ClipCursor(NULL); + + /* Get info on the current display setup */ + hdc = GetDC(0); + bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); + + /* Change the display settings */ + memset(&devmode, 0, sizeof(devmode)); + devmode.dmSize = sizeof(devmode); + devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */ + devmode.dmPelsWidth = object->orig_width; + devmode.dmPelsHeight = object->orig_height; + ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); + } + if (object->backBuffer) { int i; for(i = 0; i < object->presentParms.BackBufferCount; i++) { @@ -1795,6 +1921,63 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DW return WINED3D_OK; } +static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) { + HBITMAP hbm; + BITMAP bm; + HRESULT hr; + HDC dcb = NULL, dcs = NULL; + WINEDDCOLORKEY colorkey; + + hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); + if(hbm) + { + GetObjectA(hbm, sizeof(BITMAP), &bm); + dcb = CreateCompatibleDC(NULL); + if(!dcb) goto out; + SelectObject(dcb, hbm); + } + else + { + /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image + * couldn't be loaded + */ + memset(&bm, 0, sizeof(bm)); + bm.bmWidth = 32; + bm.bmHeight = 32; + } + + hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, + TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0, + WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL); + if(FAILED(hr)) { + ERR("Wine logo requested, but failed to create surface\n"); + goto out; + } + + if(dcb) { + hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs); + if(FAILED(hr)) goto out; + BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY); + IWineD3DSurface_ReleaseDC(This->logo_surface, dcs); + + colorkey.dwColorSpaceLowValue = 0; + colorkey.dwColorSpaceHighValue = 0; + IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey); + } else { + /* Fill the surface with a white color to show that wined3d is there */ + IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff); + } + + out: + if(dcb) { + DeleteDC(dcb); + } + if(hbm) { + DeleteObject(hbm); + } + return; +} + static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; IWineD3DSwapChainImpl *swapchain; @@ -1814,15 +1997,16 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR NULL); if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */ WARN("Failed to create stateblock\n"); - return hr; + goto err_out; } TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock); This->updateStateBlock = This->stateBlock; IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock); hr = allocate_shader_constants(This->updateStateBlock); - if (WINED3D_OK != hr) - return hr; + if (WINED3D_OK != hr) { + goto err_out; + } This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers)); This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers)); @@ -1844,20 +2028,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain); if (FAILED(hr) || !swapchain) { WARN("Failed to create implicit swapchain\n"); - return hr; + goto err_out; } This->NumberOfSwapChains = 1; This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *)); if(!This->swapchains) { ERR("Out of memory!\n"); - IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain); - return E_OUTOFMEMORY; + goto err_out; } This->swapchains[0] = (IWineD3DSwapChain *) swapchain; - if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle); - if(swapchain->backBuffer && swapchain->backBuffer[0]) { TRACE("Setting rendertarget to %p\n", swapchain->backBuffer); This->render_targets[0] = swapchain->backBuffer[0]; @@ -1931,7 +2112,27 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPR 0x00, 1.0, 0); This->d3d_initialized = TRUE; + + if(wined3d_settings.logo) { + IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo); + } return WINED3D_OK; + + err_out: + HeapFree(GetProcessHeap(), 0, This->render_targets); + HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments); + HeapFree(GetProcessHeap(), 0, This->draw_buffers); + HeapFree(GetProcessHeap(), 0, This->swapchains); + This->NumberOfSwapChains = 0; + if(swapchain) { + IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain); + } + This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers)); + if(This->stateBlock) { + IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock); + This->stateBlock = NULL; + } + return hr; } static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) { @@ -1947,6 +2148,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D */ ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface); + TRACE("Deleting high order patches\n"); for(i = 0; i < PATCHMAP_SIZE; i++) { struct list *e1, *e2; @@ -1957,6 +2160,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D } } + /* Delete the palette conversion shader if it is around */ + if(This->paletteConversionShader) { + GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader)); + This->paletteConversionShader = 0; + } + /* Delete the pbuffer context if there is any */ if(This->pbufferContext) DestroyContext(This, This->pbufferContext); @@ -2058,11 +2267,11 @@ static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL This->ddraw_fullscreen = fullscreen; } -/* Enables thead safety in the wined3d device and its resources. Called by DirectDraw - * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from +/* Enables thread safety in the wined3d device and its resources. Called by DirectDraw + * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from * CreateDevice if D3DCREATE_MULTITHREADED is passed. * - * There is no way to deactivate thread safety once it is enabled + * There is no way to deactivate thread safety once it is enabled. */ static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; @@ -2147,24 +2356,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWin } static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) { - /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever) - * into the video ram as possible and seeing how many fit - * you can also get the correct initial value from nvidia and ATI's driver via X - * texture memory is video memory + AGP memory - *******************/ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - static BOOL showfixmes = TRUE; - if (showfixmes) { - FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This, - (wined3d_settings.emulated_textureram/(1024*1024)), - ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); - showfixmes = FALSE; - } + TRACE("(%p) : simulating %dMB, returning %dMB left\n", This, - (wined3d_settings.emulated_textureram/(1024*1024)), - ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); + (This->adapter->TextureRam/(1024*1024)), + ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024))); /* return simulated texture memory left */ - return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram); + return (This->adapter->TextureRam - This->adapter->UsedTextureRam); } @@ -2209,7 +2407,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, return WINED3DERR_INVALIDCALL; } - oldSrc = This->stateBlock->streamSource[StreamNumber]; + oldSrc = This->updateStateBlock->streamSource[StreamNumber]; TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride); This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE; @@ -2230,6 +2428,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, /* Handle recording of state blocks */ if (This->isRecordingState) { TRACE("Recording... not performing anything\n"); + if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData); + if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc); return WINED3D_OK; } @@ -2240,9 +2440,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, if (pStreamData != NULL) { IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData; InterlockedIncrement(&vbImpl->bindCount); + IWineD3DVertexBuffer_AddRef(pStreamData); } if (oldSrc != NULL) { InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount); + IWineD3DVertexBuffer_Release(oldSrc); } IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); @@ -2508,12 +2710,17 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I * furthermore if still used, probably nobody pays attention to such details. */ if (pLight->Falloff == 0) { - rho = 6.28f; + /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the + * falloff resp. exponent parameter as an exponent, so the spot light lighting + * will always be 1.0 for both of them, and we don't have to care for the + * rest of the rather complex calculation + */ + object->exponent = 0; } else { rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff); + if (rho < 0.0001) rho = 0.0001f; + object->exponent = -0.3/log(cos(rho/2)); } - if (rho < 0.0001) rho = 0.0001f; - object->exponent = -0.3/log(cos(rho/2)); if (object->exponent > 128.0) { object->exponent = 128.0; } @@ -2791,6 +2998,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWine /* Handle recording of state blocks */ if (This->isRecordingState) { TRACE("Recording... not performing anything\n"); + if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData); + if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs); return WINED3D_OK; } @@ -2820,7 +3029,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWine } /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */ -static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) { +static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; TRACE("(%p)->(%d)\n", This, BaseIndex); @@ -2840,7 +3049,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *ifac return WINED3D_OK; } -static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) { +static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; TRACE("(%p) : base_index %p\n", This, base_index); @@ -3054,6 +3263,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, This->updateStateBlock->changed.vertexShader = TRUE; if (This->isRecordingState) { + if(pShader) IWineD3DVertexShader_AddRef(pShader); + if(oldShader) IWineD3DVertexShader_Release(oldShader); TRACE("Recording... not performing anything\n"); return WINED3D_OK; } else if(oldShader == pShader) { @@ -3063,6 +3274,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, } TRACE("(%p) : setting pShader(%p)\n", This, pShader); + if(pShader) IWineD3DVertexShader_AddRef(pShader); + if(oldShader) IWineD3DVertexShader_Release(oldShader); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER); @@ -3441,6 +3654,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, I if (This->isRecordingState) { TRACE("Recording... not performing anything\n"); + if(pShader) IWineD3DPixelShader_AddRef(pShader); + if(oldShader) IWineD3DPixelShader_Release(oldShader); return WINED3D_OK; } @@ -3449,6 +3664,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, I return WINED3D_OK; } + if(pShader) IWineD3DPixelShader_AddRef(pShader); + if(oldShader) IWineD3DPixelShader_Release(oldShader); + TRACE("(%p) : setting pShader(%p)\n", This, pShader); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER); @@ -4181,7 +4399,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD } /** NOTE: MSDN says that setTexture increases the reference count, - * and the the application must set the texture back to null (or have a leaky application), + * and that the application must set the texture back to null (or have a leaky application), * This means we should pass the refcount up to the parent *******************************/ if (NULL != This->updateStateBlock->textures[Stage]) { @@ -4344,7 +4562,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) HRESULT temp_result; int i; - ERR("(%p)\n", This); + TRACE("(%p)\n", This); if (This->isRecordingState) { return WINED3DERR_INVALIDCALL; @@ -4609,7 +4827,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun curRect[0].x2 < target->currentDesc.Width || curRect[0].y2 < target->currentDesc.Height) { TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n"); - blt_to_drawable(This, target); + IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL); } } @@ -4661,12 +4879,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists, * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it */ + IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE); + /* TODO: Move the fbo logic into ModifyLocation() */ if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { target->Flags |= SFLAG_INTEXTURE; - target->Flags &= ~SFLAG_INSYSMEM; - } else { - target->Flags |= SFLAG_INDRAWABLE; - target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM); } return WINED3D_OK; } @@ -4752,13 +4968,16 @@ static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexBuffer *vb; TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType), PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); /* Note in the following, it's not this type, but that's the purpose of streamIsUP */ + vb = This->stateBlock->streamSource[0]; This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; + if(vb) IWineD3DVertexBuffer_Release(vb); This->stateBlock->streamOffset[0] = 0; This->stateBlock->streamStride[0] = VertexStreamZeroStride; This->stateBlock->streamIsUP = TRUE; @@ -4787,6 +5006,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice * UINT VertexStreamZeroStride) { int idxStride; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexBuffer *vb; IWineD3DIndexBuffer *ib; TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n", @@ -4801,7 +5021,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice * } /* Note in the following, it's not this type, but that's the purpose of streamIsUP */ + vb = This->stateBlock->streamSource[0]; This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; + if(vb) IWineD3DVertexBuffer_Release(vb); This->stateBlock->streamIsUP = TRUE; This->stateBlock->streamOffset[0] = 0; This->stateBlock->streamStride[0] = VertexStreamZeroStride; @@ -4864,6 +5086,37 @@ static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDev return WINED3D_OK; } +static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) { + /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's + * not callable by the app directly no parameter validation checks are needed here. + */ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + WINED3DLOCKED_BOX src; + WINED3DLOCKED_BOX dst; + HRESULT hr; + TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume); + + /* TODO: Implement direct loading into the gl volume instead of using memcpy and + * dirtification to improve loading performance. + */ + hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY); + if(FAILED(hr)) return hr; + hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD); + if(FAILED(hr)) { + IWineD3DVolume_UnlockBox(pSourceVolume); + return hr; + } + + memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size); + + hr = IWineD3DVolume_UnlockBox(pDestinationVolume); + if(FAILED(hr)) { + IWineD3DVolume_UnlockBox(pSourceVolume); + } else { + hr = IWineD3DVolume_UnlockBox(pSourceVolume); + } + return hr; +} /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){ @@ -4964,18 +5217,18 @@ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, I } } break; -#if 0 /* TODO: Add support for volume textures */ + case WINED3DRTYPE_VOLUMETEXTURE: { - IWineD3DVolume srcVolume = NULL; - IWineD3DSurface destVolume = NULL; + IWineD3DVolume *srcVolume = NULL; + IWineD3DVolume *destVolume = NULL; for (i = 0 ; i < levels ; ++i) { - IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume); - IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume); - hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL); - IWineD3DVolume_Release(srcSurface); - IWineD3DVolume_Release(destSurface); + IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume); + IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume); + hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume); + IWineD3DVolume_Release(srcVolume); + IWineD3DVolume_Release(destVolume); if (WINED3D_OK != hr) { WARN("(%p) : Call to update volume failed\n", This); return hr; @@ -4983,7 +5236,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, I } } break; -#endif + default: FIXME("(%p) : Unsupported source and destination type\n", This); hr = WINED3DERR_INVALIDCALL; @@ -5323,8 +5576,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, LEAVE_GL(); - ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM; - ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE; + IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE); IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0)); return WINED3D_OK; @@ -5496,7 +5748,8 @@ static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWOR IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl); } - GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0)); + GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, + surface_impl->glDescription.textureName, surface_impl->glDescription.level)); checkGLcall("attach_surface_fbo"); } @@ -5556,6 +5809,113 @@ static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONS } } +static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) { + unsigned int r, g, b, a; + DWORD ret; + + if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 || + destfmt == WINED3DFMT_R8G8B8) + return color; + + TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt)); + + a = (color & 0xff000000) >> 24; + r = (color & 0x00ff0000) >> 16; + g = (color & 0x0000ff00) >> 8; + b = (color & 0x000000ff) >> 0; + + switch(destfmt) + { + case WINED3DFMT_R5G6B5: + if(r == 0xff && g == 0xff && b == 0xff) return 0xffff; + r = (r * 32) / 256; + g = (g * 64) / 256; + b = (b * 32) / 256; + ret = r << 11; + ret |= g << 5; + ret |= b; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_X1R5G5B5: + case WINED3DFMT_A1R5G5B5: + a = (a * 2) / 256; + r = (r * 32) / 256; + g = (g * 32) / 256; + b = (b * 32) / 256; + ret = a << 15; + ret |= r << 10; + ret |= g << 5; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_A8: + TRACE("Returning %08x\n", a); + return a; + + case WINED3DFMT_X4R4G4B4: + case WINED3DFMT_A4R4G4B4: + a = (a * 16) / 256; + r = (r * 16) / 256; + g = (g * 16) / 256; + b = (b * 16) / 256; + ret = a << 12; + ret |= r << 8; + ret |= g << 4; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_R3G3B2: + r = (r * 8) / 256; + g = (g * 8) / 256; + b = (b * 4) / 256; + ret = r << 5; + ret |= g << 2; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_X8B8G8R8: + case WINED3DFMT_A8B8G8R8: + ret = a << 24; + ret |= b << 16; + ret |= g << 8; + ret |= r << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_A2R10G10B10: + a = (a * 4) / 256; + r = (r * 1024) / 256; + g = (g * 1024) / 256; + b = (b * 1024) / 256; + ret = a << 30; + ret |= r << 20; + ret |= g << 10; + ret |= b << 0; + TRACE("Returning %08x\n", ret); + return ret; + + case WINED3DFMT_A2B10G10R10: + a = (a * 4) / 256; + r = (r * 1024) / 256; + g = (g * 1024) / 256; + b = (b * 1024) / 256; + ret = a << 30; + ret |= b << 20; + ret |= g << 10; + ret |= r << 0; + TRACE("Returning %08x\n", ret); + return ret; + + default: + FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt)); + return 0; + } +} + static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface; @@ -5574,7 +5934,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD /* Just forward this to the DirectDraw blitting engine */ memset(&BltFx, 0, sizeof(BltFx)); BltFx.dwSize = sizeof(BltFx); - BltFx.u5.dwFillColor = color; + BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format); return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE); } } @@ -5691,8 +6051,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice if(*ppZStencilSurface != NULL) { /* Note inc ref on returned surface */ IWineD3DSurface_AddRef(*ppZStencilSurface); + return WINED3D_OK; + } else { + return WINED3DERR_NOTFOUND; } - return WINED3D_OK; } /* TODO: Handle stencil attachments */ @@ -5733,7 +6095,8 @@ static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_ IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl); } - GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0)); + GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, + depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level)); checkGLcall("glFramebufferTexture2DEXT()"); } } else { @@ -6562,6 +6925,37 @@ static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IW /* Cleanup any FBO attachments if d3d is enabled */ if(This->d3d_initialized) { + if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) { + IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL; + + TRACE("Last active render target destroyed\n"); + /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL + * checks, so switch to a valid target as long as the currently set surface is still valid. Use the + * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed + * and the lastActiveRenderTarget member shouldn't matter + */ + if(swapchain) { + if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) { + TRACE("Activating primary back buffer\n"); + ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD); + } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) { + /* Single buffering environment */ + TRACE("Activating primary front buffer\n"); + ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD); + } else { + TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n"); + /* Implicit render target destroyed, that means the device is being destroyed + * whatever we set here, it shouldn't matter + */ + This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe; + } + } else { + /* May happen during ddraw uninitialization */ + TRACE("Render target set, but swapchain does not exist!\n"); + This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe; + } + } + for (i = 0; i < GL_LIMITS(buffers); ++i) { if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) { bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); @@ -6911,7 +7305,9 @@ const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = { WINED3DRS_RANGEFOGENABLE , WINED3DRS_SPECULARMATERIALSOURCE , WINED3DRS_TWEENFACTOR , - WINED3DRS_VERTEXBLEND + WINED3DRS_VERTEXBLEND , + WINED3DRS_CULLMODE , + WINED3DRS_FOGCOLOR }; const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = { diff --git a/reactos/dll/directx/wine/wined3d/directx.c b/reactos/dll/directx/wine/wined3d/directx.c index e9b2acada7d..5401ff5fea6 100644 --- a/reactos/dll/directx/wine/wined3d/directx.c +++ b/reactos/dll/directx/wine/wined3d/directx.c @@ -44,6 +44,8 @@ static const struct { /* APPLE */ {"GL_APPLE_client_storage", APPLE_CLIENT_STORAGE}, {"GL_APPLE_fence", APPLE_FENCE}, + {"GL_APPLE_flush_render", APPLE_FLUSH_RENDER}, + {"GL_APPLE_ycbcr_422", APPLE_YCBCR_422}, /* ATI */ {"GL_ATI_separate_stencil", ATI_SEPARATE_STENCIL}, @@ -117,6 +119,10 @@ static const struct { {"GL_NV_vertex_program1_1", NV_VERTEX_PROGRAM1_1}, {"GL_NV_vertex_program2", NV_VERTEX_PROGRAM2}, {"GL_NV_vertex_program3", NV_VERTEX_PROGRAM3}, + {"GL_NV_depth_clamp", NV_DEPTH_CLAMP}, + + /* SGI */ + {"GL_SGIS_generate_mipmap", SGIS_GENERATE_MIPMAP}, }; /********************************************************** @@ -188,13 +194,11 @@ static void WineD3D_ReleaseFakeGLContext(void) { assert(wined3d_fake_gl_context_ref >= 0); LeaveCriticalSection(&wined3d_fake_gl_context_cs); - LEAVE_GL(); } static BOOL WineD3D_CreateFakeGLContext(void) { HGLRC glCtx = NULL; - ENTER_GL(); EnterCriticalSection(&wined3d_fake_gl_context_cs); TRACE("getting context...\n"); @@ -269,10 +273,17 @@ static BOOL WineD3D_CreateFakeGLContext(void) { wined3d_fake_gl_context_hwnd = NULL; if(glCtx) pwglDeleteContext(glCtx); LeaveCriticalSection(&wined3d_fake_gl_context_cs); - LEAVE_GL(); return FALSE; } +/* Adjust the amount of used texture memory */ +long WineD3DAdapterChangeGLRam(IWineD3DDeviceImpl *D3DDevice, long glram){ + UINT Adapter = D3DDevice->adapterNo; + + Adapters[Adapter].UsedTextureRam += glram; + TRACE("Adjusted gl ram by %ld to %d\n", glram, Adapters[Adapter].UsedTextureRam); + return Adapters[Adapter].UsedTextureRam; +} /********************************************************** * IUnknown parts follows @@ -326,7 +337,13 @@ static void select_shader_mode( if (wined3d_settings.vs_mode == VS_NONE) { *vs_selected = SHADER_NONE; } else if (gl_info->supported[ARB_VERTEX_SHADER] && wined3d_settings.glslRequested) { - *vs_selected = SHADER_GLSL; + /* Geforce4 cards support GLSL but for vertex shaders only. Further its reported GLSL caps are + * wrong. This combined with the fact that glsl won't offer more features or performance, use ARB + * shaders only on this card. */ + if(gl_info->vs_nv_version && gl_info->vs_nv_version < VS_VERSION_20) + *vs_selected = SHADER_ARB; + else + *vs_selected = SHADER_GLSL; } else if (gl_info->supported[ARB_VERTEX_PROGRAM]) { *vs_selected = SHADER_ARB; } else { @@ -392,6 +409,38 @@ static void select_shader_max_constants( **********************************************************/ #define GLINFO_LOCATION (*gl_info) +static inline BOOL test_arb_vs_offset_limit(WineD3D_GL_Info *gl_info) { + GLuint prog; + BOOL ret = FALSE; + const char *testcode = + "!!ARBvp1.0\n" + "PARAM C[66] = { program.env[0..65] };\n" + "ADDRESS A0;" + "ARL A0.x, 0.0;\n" + "MOV result.position, C[A0.x + 65];\n" + "END\n"; + + while(glGetError()); + GL_EXTCALL(glGenProgramsARB(1, &prog)); + if(!prog) { + ERR("Failed to create an ARB offset limit test program\n"); + } + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prog)); + GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(testcode), testcode)); + if(glGetError() != 0) { + TRACE("OpenGL implementation does not allow indirect addressing offsets > 63\n"); + TRACE("error: %s\n", debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + ret = TRUE; + } else TRACE("OpenGL implementation allows offsets > 63\n"); + + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0)); + GL_EXTCALL(glDeleteProgramsARB(1, &prog)); + checkGLcall("ARB vp offset limit test cleanup\n"); + + return ret; +} + BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { const char *GL_Extensions = NULL; const char *WGL_Extensions = NULL; @@ -403,43 +452,12 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { BOOL return_value = TRUE; int i; HDC hdc; - HMODULE mod_gl; - -#ifdef USE_WIN32_OPENGL -#define USE_GL_FUNC(pfn) pfn = (void*)GetProcAddress(mod_gl, #pfn); - mod_gl = LoadLibraryA("opengl32.dll"); - if(!mod_gl) { - ERR("Can't load opengl32.dll!\n"); - return FALSE; - } -#else -#define USE_GL_FUNC(pfn) pfn = (void*)pwglGetProcAddress(#pfn); - /* To bypass the opengl32 thunks load wglGetProcAddress from gdi32 (glXGetProcAddress wrapper) instead of opengl32's */ - mod_gl = GetModuleHandleA("gdi32.dll"); -#endif - -/* Load WGL core functions from opengl32.dll */ -#define USE_WGL_FUNC(pfn) p##pfn = (void*)GetProcAddress(mod_gl, #pfn); - WGL_FUNCS_GEN; -#undef USE_WGL_FUNC - - if(!pwglGetProcAddress) { - ERR("Unable to load wglGetProcAddress!\n"); - return FALSE; - } - -/* Dynamicly load all GL core functions */ - GL_FUNCS_GEN; -#undef USE_GL_FUNC - - /* Make sure that we've got a context */ - /* TODO: CreateFakeGLContext should really take a display as a parameter */ - /* Only save the values obtained when a display is provided */ - if (!WineD3D_CreateFakeGLContext() || wined3d_fake_gl_context_foreign) - return_value = FALSE; + unsigned int vidmem=0; TRACE_(d3d_caps)("(%p)\n", gl_info); + ENTER_GL(); + gl_string = (const char *) glGetString(GL_RENDERER); if (NULL == gl_string) gl_string = "None"; @@ -625,6 +643,7 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { TRACE_(d3d_caps)("Maximum texture size support - max texture size=%d\n", gl_max); glGetFloatv(GL_POINT_SIZE_RANGE, gl_floatv); + gl_info->max_pointsizemin = gl_floatv[0]; gl_info->max_pointsize = gl_floatv[1]; TRACE_(d3d_caps)("Maximum point size support - max point size=%f\n", gl_floatv[1]); @@ -707,7 +726,7 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { GLint tmp; glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &tmp); - gl_info->max_fragment_samplers = min(MAX_FRAGMENT_SAMPLERS, tmp); + gl_info->max_fragment_samplers = min(8, tmp); } else { gl_info->max_fragment_samplers = max(gl_info->max_fragment_samplers, gl_max); } @@ -719,6 +738,29 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { gl_info->max_vertex_samplers = tmp; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, &tmp); gl_info->max_combined_samplers = tmp; + + /* Loading GLSL sampler uniforms is much simpler if we can assume that the sampler setup + * is known at shader link time. In a vertex shader + pixel shader combination this isn't + * an issue because then the sampler setup only depends on the two shaders. If a pixel + * shader is used with fixed function vertex processing we're fine too because fixed function + * vertex processing doesn't use any samplers. If fixed function fragment processing is + * used we have to make sure that all vertex sampler setups are valid together with all + * possible fixed function fragment processing setups. This is true if vsamplers + MAX_TEXTURES + * <= max_samplers. This is true on all d3d9 cards that support vtf(gf 6 and gf7 cards). + * dx9 radeon cards do not support vertex texture fetch. DX10 cards have 128 samplers, and + * dx9 is limited to 8 fixed function texture stages and 4 vertex samplers. DX10 does not have + * a fixed function pipeline anymore. + * + * So this is just a check to check that our assumption holds true. If not, write a warning + * and reduce the number of vertex samplers or propably disable vertex texture fetch. + */ + if(gl_info->max_vertex_samplers && + MAX_TEXTURES + gl_info->max_vertex_samplers > gl_info->max_combined_samplers) { + FIXME("OpenGL implementation supports %u vertex samplers and %u total samplers\n", + gl_info->max_vertex_samplers, gl_info->max_combined_samplers); + FIXME("Expected vertex samplers + MAX_TEXTURES(=8) > combined_samplers\n"); + gl_info->max_vertex_samplers = max(0, gl_info->max_combined_samplers - MAX_TEXTURES); + } } else { gl_info->max_combined_samplers = gl_info->max_fragment_samplers; } @@ -745,24 +787,26 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max)); gl_info->ps_arb_constantsF = gl_max; TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM float constants: %d\n", gl_info->ps_arb_constantsF); - GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max)); + GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, &gl_max)); gl_info->ps_arb_max_temps = gl_max; - TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM temporaries: %d\n", gl_info->ps_arb_max_temps); - GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max)); + TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM native temporaries: %d\n", gl_info->ps_arb_max_temps); + GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &gl_max)); gl_info->ps_arb_max_instructions = gl_max; - TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM instructions: %d\n", gl_info->ps_arb_max_instructions); + TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM native instructions: %d\n", gl_info->ps_arb_max_instructions); } if (gl_info->supported[ARB_VERTEX_PROGRAM]) { gl_info->vs_arb_version = VS_VERSION_11; GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max)); gl_info->vs_arb_constantsF = gl_max; TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM float constants: %d\n", gl_info->vs_arb_constantsF); - GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max)); + GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, &gl_max)); gl_info->vs_arb_max_temps = gl_max; - TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM temporaries: %d\n", gl_info->vs_arb_max_temps); - GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max)); + TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM native temporaries: %d\n", gl_info->vs_arb_max_temps); + GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &gl_max)); gl_info->vs_arb_max_instructions = gl_max; - TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM instructions: %d\n", gl_info->vs_arb_max_instructions); + TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM native instructions: %d\n", gl_info->vs_arb_max_instructions); + + gl_info->arb_vs_offset_limit = test_arb_vs_offset_limit(gl_info); } if (gl_info->supported[ARB_VERTEX_SHADER]) { glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max); @@ -773,6 +817,9 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &gl_max); gl_info->ps_glsl_constantsF = gl_max / 4; TRACE_(d3d_caps)("Max ARB_FRAGMENT_SHADER float constants: %u\n", gl_info->ps_glsl_constantsF); + glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &gl_max); + gl_info->max_glsl_varyings = gl_max; + TRACE_(d3d_caps)("Max GLSL varyings: %u (%u 4 component varyings)\n", gl_max, gl_max / 4); } if (gl_info->supported[EXT_VERTEX_SHADER]) { gl_info->vs_ati_version = VS_VERSION_11; @@ -842,7 +889,16 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { * without a full database we can return a card with similar features. Second the size of the database * can be made quite small because when you know what type of 3d functionality a card has, you know to which * GPU family the GPU must belong. Because of this you only have to check a small part of the renderer string - * to distinguishes between different models from that family. + * to distinguishes between different models from that family. + * + * The code also selects a default amount of video memory which we will use for an estimation of the amount + * of free texture memory. In case of real D3D the amount of texture memory includes video memory and system + * memory (to be specific AGP memory or in case of PCIE TurboCache/HyperMemory). We don't know how much + * system memory can be addressed by the system but we can make a reasonable estimation about the amount of + * video memory. If the value is slightly wrong it doesn't matter as we didn't include AGP-like memory which + * makes the amount of addressable memory higher and second OpenGL isn't that critical it moves to system + * memory behind our backs if really needed. + * Note that the amout of video memory can be overruled using a registry setting. */ switch (gl_info->gl_vendor) { case VENDOR_NVIDIA: @@ -850,79 +906,173 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { * shader capabilities, so we use the shader capabilities to distinguish between FX and 6xxx/7xxx. */ if(WINE_D3D9_CAPABLE(gl_info) && (gl_info->vs_nv_version == VS_VERSION_30)) { - if (strstr(gl_info->gl_renderer, "7800") || - strstr(gl_info->gl_renderer, "7900") || - strstr(gl_info->gl_renderer, "7950") || - strstr(gl_info->gl_renderer, "Quadro FX 4") || - strstr(gl_info->gl_renderer, "Quadro FX 5")) - gl_info->gl_card = CARD_NVIDIA_GEFORCE_7800GT; + /* Geforce8 - highend */ + if (strstr(gl_info->gl_renderer, "8800")) { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_8800GTS; + vidmem = 320; /* The 8800GTS uses 320MB, a 8800GTX can have 768MB */ + } + /* Geforce8 - midend */ + else if(strstr(gl_info->gl_renderer, "8600") || + strstr(gl_info->gl_renderer, "8700")) + { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_8600GT; + vidmem = 256; + } + /* Geforce8 - lowend */ + else if(strstr(gl_info->gl_renderer, "8300") || + strstr(gl_info->gl_renderer, "8400") || + strstr(gl_info->gl_renderer, "8500")) + { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_8300GS; + vidmem = 128; /* 128-256MB for a 8300, 256-512MB for a 8400 */ + } + /* Geforce7 - highend */ + else if(strstr(gl_info->gl_renderer, "7800") || + strstr(gl_info->gl_renderer, "7900") || + strstr(gl_info->gl_renderer, "7950") || + strstr(gl_info->gl_renderer, "Quadro FX 4") || + strstr(gl_info->gl_renderer, "Quadro FX 5")) + { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_7800GT; + vidmem = 256; /* A 7800GT uses 256MB while highend 7900 cards can use 512MB */ + } + /* Geforce7 midend / Geforce6 highend */ else if(strstr(gl_info->gl_renderer, "6800") || - strstr(gl_info->gl_renderer, "7600")) - gl_info->gl_card = CARD_NVIDIA_GEFORCE_6800; + strstr(gl_info->gl_renderer, "7600") || + strstr(gl_info->gl_renderer, "7700")) + { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6800; + vidmem = 128; /* The 6800 uses 128-256MB, the 7600 uses 256-512MB */ + } + /* Geforce6 - midend */ else if(strstr(gl_info->gl_renderer, "6600") || strstr(gl_info->gl_renderer, "6610") || strstr(gl_info->gl_renderer, "6700")) - gl_info->gl_card = CARD_NVIDIA_GEFORCE_6600GT; - else - gl_info->gl_card = CARD_NVIDIA_GEFORCE_6200; /* Geforce 6100/6150/6200/7300/7400 */ + { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6600GT; + vidmem = 128; /* A 6600GT has 128-256MB */ + } + /* Geforce6/7 lowend */ + else { + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6200; /* Geforce 6100/6150/6200/7300/7400/7500 */ + vidmem = 64; /* */ + } } else if(WINE_D3D9_CAPABLE(gl_info)) { + /* GeforceFX - highend */ if (strstr(gl_info->gl_renderer, "5800") || strstr(gl_info->gl_renderer, "5900") || strstr(gl_info->gl_renderer, "5950") || strstr(gl_info->gl_renderer, "Quadro FX")) - gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5800; + { + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5800; + vidmem = 256; /* 5800-5900 cards use 256MB */ + } + /* GeforceFX - midend */ else if(strstr(gl_info->gl_renderer, "5600") || strstr(gl_info->gl_renderer, "5650") || strstr(gl_info->gl_renderer, "5700") || strstr(gl_info->gl_renderer, "5750")) - gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600; - else + { + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600; + vidmem = 128; /* A 5600 uses 128-256MB */ + } + /* GeforceFX - lowend */ + else { gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5200; /* GeforceFX 5100/5200/5250/5300/5500 */ + vidmem = 64; /* Normal FX5200 cards use 64-256MB; laptop (non-standard) can have less */ + } } else if(WINE_D3D8_CAPABLE(gl_info)) { - if (strstr(gl_info->gl_renderer, "GeForce4 Ti") || strstr(gl_info->gl_renderer, "Quadro4")) + if (strstr(gl_info->gl_renderer, "GeForce4 Ti") || strstr(gl_info->gl_renderer, "Quadro4")) { gl_info->gl_card = CARD_NVIDIA_GEFORCE4_TI4200; /* Geforce4 Ti4200/Ti4400/Ti4600/Ti4800, Quadro4 */ - else + vidmem = 64; /* Geforce4 Ti cards have 64-128MB */ + } + else { gl_info->gl_card = CARD_NVIDIA_GEFORCE3; /* Geforce3 standard/Ti200/Ti500, Quadro DCC */ + vidmem = 64; /* Geforce3 cards have 64-128MB */ + } } else if(WINE_D3D7_CAPABLE(gl_info)) { - if (strstr(gl_info->gl_renderer, "GeForce4 MX")) + if (strstr(gl_info->gl_renderer, "GeForce4 MX")) { gl_info->gl_card = CARD_NVIDIA_GEFORCE4_MX; /* MX420/MX440/MX460/MX4000 */ - else if(strstr(gl_info->gl_renderer, "GeForce2 MX") || strstr(gl_info->gl_renderer, "Quadro2 MXR")) + vidmem = 64; /* Most Geforce4MX GPUs have at least 64MB of memory, some early models had 32MB but most have 64MB or even 128MB */ + } + else if(strstr(gl_info->gl_renderer, "GeForce2 MX") || strstr(gl_info->gl_renderer, "Quadro2 MXR")) { gl_info->gl_card = CARD_NVIDIA_GEFORCE2_MX; /* Geforce2 standard/MX100/MX200/MX400, Quadro2 MXR */ - else if(strstr(gl_info->gl_renderer, "GeForce2") || strstr(gl_info->gl_renderer, "Quadro2")) + vidmem = 32; /* Geforce2MX GPUs have 32-64MB of video memory */ + } + else if(strstr(gl_info->gl_renderer, "GeForce2") || strstr(gl_info->gl_renderer, "Quadro2")) { gl_info->gl_card = CARD_NVIDIA_GEFORCE2; /* Geforce2 GTS/Pro/Ti/Ultra, Quadro2 */ - else + vidmem = 32; /* Geforce2 GPUs have 32-64MB of video memory */ + } + else { gl_info->gl_card = CARD_NVIDIA_GEFORCE; /* Geforce 256/DDR, Quadro */ + vidmem = 32; /* Most Geforce1 cards have 32MB, there are also some rare 16 and 64MB (Dell) models */ + } } else { - if (strstr(gl_info->gl_renderer, "TNT2")) + if (strstr(gl_info->gl_renderer, "TNT2")) { gl_info->gl_card = CARD_NVIDIA_RIVA_TNT2; /* Riva TNT2 standard/M64/Pro/Ultra */ - else + vidmem = 32; /* Most TNT2 boards have 32MB, though there are 16MB boards too */ + } + else { gl_info->gl_card = CARD_NVIDIA_RIVA_TNT; /* Riva TNT, Vanta */ + vidmem = 16; /* Most TNT boards have 16MB, some rare models have 8MB */ + } } break; case VENDOR_ATI: if(WINE_D3D9_CAPABLE(gl_info)) { + /* Radeon R6xx HD2900 - highend */ + if (strstr(gl_info->gl_renderer, "HD 2900")) { + gl_info->gl_card = CARD_ATI_RADEON_HD2900; + vidmem = 512; /* HD2900 uses 512-1024MB */ + } + /* Radeon R6xx HD2600- midend */ + else if (strstr(gl_info->gl_renderer, "HD 2600")) { + gl_info->gl_card = CARD_ATI_RADEON_HD2600; + vidmem = 256; /* HD2600 uses 256-512MB */ + } + /* Radeon R6xx HD2300/HD2400 - lowend */ + else if (strstr(gl_info->gl_renderer, "HD 2300") || + strstr(gl_info->gl_renderer, "HD 2400")) + { + gl_info->gl_card = CARD_ATI_RADEON_HD2300; + vidmem = 128; /* HD2300 uses at least 128MB, HD2400 uses 256MB */ + } /* Radeon R5xx */ - if (strstr(gl_info->gl_renderer, "X1600") || - strstr(gl_info->gl_renderer, "X1800") || - strstr(gl_info->gl_renderer, "X1900") || - strstr(gl_info->gl_renderer, "X1950")) - gl_info->gl_card = CARD_ATI_RADEON_X1600; - /* Radeon R4xx + X1300/X1400 (lowend R5xx) */ + else if (strstr(gl_info->gl_renderer, "X1600") || + strstr(gl_info->gl_renderer, "X1650") || + strstr(gl_info->gl_renderer, "X1800") || + strstr(gl_info->gl_renderer, "X1900") || + strstr(gl_info->gl_renderer, "X1950")) + { + gl_info->gl_card = CARD_ATI_RADEON_X1600; + vidmem = 128; /* X1600 uses 128-256MB, >=X1800 uses 256MB */ + } + /* Radeon R4xx + X1300/X1400/X1450/X1550/X2300 (lowend R5xx) */ else if(strstr(gl_info->gl_renderer, "X700") || strstr(gl_info->gl_renderer, "X800") || strstr(gl_info->gl_renderer, "X850") || strstr(gl_info->gl_renderer, "X1300") || - strstr(gl_info->gl_renderer, "X1400")) - gl_info->gl_card = CARD_ATI_RADEON_X700; + strstr(gl_info->gl_renderer, "X1400") || + strstr(gl_info->gl_renderer, "X1450") || + strstr(gl_info->gl_renderer, "X1550")) + { + gl_info->gl_card = CARD_ATI_RADEON_X700; + vidmem = 128; /* x700/x8*0 use 128-256MB, >=x1300 128-512MB */ + } /* Radeon R3xx */ - else + else { gl_info->gl_card = CARD_ATI_RADEON_9500; /* Radeon 9500/9550/9600/9700/9800/X300/X550/X600 */ + vidmem = 64; /* Radeon 9500 uses 64MB, higher models use up to 256MB */ + } } else if(WINE_D3D8_CAPABLE(gl_info)) { - gl_info->gl_card = CARD_ATI_RADEON_8500; /* Radeon 8500/9000/9100/9200/9300 */ + gl_info->gl_card = CARD_ATI_RADEON_8500; /* Radeon 8500/9000/9100/9200/9300 */ + vidmem = 64; /* 8500/9000 cards use mostly 64MB, though there are 32MB and 128MB models */ } else if(WINE_D3D7_CAPABLE(gl_info)) { - gl_info->gl_card = CARD_ATI_RADEON_7200; /* Radeon 7000/7100/7200/7500 */ + gl_info->gl_card = CARD_ATI_RADEON_7200; /* Radeon 7000/7100/7200/7500 */ + vidmem = 32; /* There are models with up to 64MB */ } else gl_info->gl_card = CARD_ATI_RAGE_128PRO; + vidmem = 16; /* There are 16-32MB models */ break; case VENDOR_INTEL: if (strstr(gl_info->gl_renderer, "915GM")) { @@ -950,7 +1100,7 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { if(WINE_D3D9_CAPABLE(gl_info)) gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600; else if(WINE_D3D8_CAPABLE(gl_info)) - gl_info->gl_card = CARD_NVIDIA_GEFORCE3; + gl_info->gl_card = CARD_NVIDIA_GEFORCE3; else if(WINE_D3D7_CAPABLE(gl_info)) gl_info->gl_card = CARD_NVIDIA_GEFORCE; else if(WINE_D3D6_CAPABLE(gl_info)) @@ -960,6 +1110,12 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { } TRACE("FOUND (fake) card: 0x%x (vendor id), 0x%x (device id)\n", gl_info->gl_vendor, gl_info->gl_card); + /* If we have an estimate use it, else default to 64MB; */ + if(vidmem) + gl_info->vidmem = vidmem*1024*1024; /* convert from MBs to bytes */ + else + gl_info->vidmem = WINE_DEFAULT_VIDMEM; + /* Load all the lookup tables TODO: It may be a good idea to make minLookup and maxLookup const and populate them in wined3d_private.h where they are declared */ minLookup[WINELOOKUP_WARPPARAM] = WINED3DTADDRESS_WRAP; @@ -1042,9 +1198,8 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { } } } + LEAVE_GL(); - - WineD3D_ReleaseFakeGLContext(); return return_value; } #undef GLINFO_LOCATION @@ -1496,6 +1651,7 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt if (Usage & WINED3DUSAGE_QUERY_FILTER) { switch (CheckFormat) { /* Filtering not supported */ + case WINED3DFMT_R32F: case WINED3DFMT_A32B32G32R32F: TRACE_(d3d_caps)("[FAILED]\n"); return WINED3DERR_NOTAVAILABLE; @@ -1504,6 +1660,67 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt } } + if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) { + if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { + TRACE_(d3d_caps)("[FAILED] - No mipmap generation support\n"); + return WINED3DERR_NOTAVAILABLE; + } + } + + if(RType == WINED3DRTYPE_VOLUMETEXTURE) { + if(!GL_SUPPORT(EXT_TEXTURE3D)) { + TRACE_(d3d_caps)("[FAILED] - No volume texture support\n"); + return WINED3DERR_NOTAVAILABLE; + } + /* Filter formats that need conversion; For one part, this conversion is unimplemented, + * and volume textures are huge, so it would be a big performance hit. Unless we hit an + * app needing one of those formats, don't advertize them to avoid leading apps into + * temptation. The windows drivers don't support most of those formats on volumes anyway, + * except of R32F. + */ + switch(CheckFormat) { + case WINED3DFMT_P8: + case WINED3DFMT_A4L4: + case WINED3DFMT_R32F: + case WINED3DFMT_R16F: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_L6V5U5: + TRACE_(d3d_caps)("[FAILED] - No converted formats on volumes\n"); + return WINED3DERR_NOTAVAILABLE; + + case WINED3DFMT_Q8W8V8U8: + case WINED3DFMT_V16U16: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + TRACE_(d3d_caps)("[FAILED] - No converted formats on volumes\n"); + return WINED3DERR_NOTAVAILABLE; + } + break; + + case WINED3DFMT_V8U8: + if(!GL_SUPPORT(NV_TEXTURE_SHADER) || !GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + TRACE_(d3d_caps)("[FAILED] - No converted formats on volumes\n"); + return WINED3DERR_NOTAVAILABLE; + } + break; + + case WINED3DFMT_DXT1: + case WINED3DFMT_DXT2: + case WINED3DFMT_DXT3: + case WINED3DFMT_DXT4: + case WINED3DFMT_DXT5: + /* The GL_EXT_texture_compression_s3tc spec requires that loading an s3tc + * compressed texture results in an error. While the D3D refrast does + * support s3tc volumes, at least the nvidia windows driver does not, so + * we're free not to support this format. + */ + TRACE_(d3d_caps)("[FAILED] - DXTn does not support 3D textures\n"); + return WINED3DERR_NOTAVAILABLE; + + default: + /* Do nothing, continue with checking the format below */ + break; + } + } /* TODO: Check support against more of the WINED3DUSAGE_QUERY_* constants * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/IDirect3D9__CheckDeviceFormat.asp * and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/D3DUSAGE_QUERY.asp */ @@ -1715,7 +1932,8 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt return WINED3D_OK; /***** - * Not supported for now: Bump mapping formats + * Not supported everywhere(depends on GL_ATI_envmap_bumpmap or + * GL_NV_texture_shader), but advertized to make apps happy. * Enable some because games often fail when they are not available * and are still playable even without bump mapping */ @@ -1724,11 +1942,19 @@ static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapt case WINED3DFMT_L6V5U5: case WINED3DFMT_X8L8V8U8: case WINED3DFMT_Q8W8V8U8: - case WINED3DFMT_W11V11U10: - case WINED3DFMT_A2W10V10U10: WARN_(d3d_caps)("[Not supported, but pretended to do]\n"); return WINED3D_OK; + /* Those are not advertized by the nvidia windows driver, and not + * supported natively by GL_NV_texture_shader or GL_ATI_envmap_bumpmap. + * WINED3DFMT_A2W10V10U10 could be loaded into shaders using the unsigned + * ARGB format if needed + */ + case WINED3DFMT_W11V11U10: + case WINED3DFMT_A2W10V10U10: + WARN_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + /***** * DXTN Formats: Handled above * WINED3DFMT_DXT1 @@ -1836,8 +2062,12 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->Caps2 = WINED3DCAPS2_CANRENDERWINDOWED | WINED3DCAPS2_FULLSCREENGAMMA | WINED3DCAPS2_DYNAMICTEXTURES; + if(GL_SUPPORT(SGIS_GENERATE_MIPMAP)) { + *pCaps->Caps2 |= WINED3DCAPS2_CANAUTOGENMIPMAP; + } *pCaps->Caps3 = WINED3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD; - *pCaps->PresentationIntervals = WINED3DPRESENT_INTERVAL_IMMEDIATE; + *pCaps->PresentationIntervals = WINED3DPRESENT_INTERVAL_IMMEDIATE | + WINED3DPRESENT_INTERVAL_ONE; *pCaps->CursorCaps = WINED3DCURSORCAPS_COLOR | WINED3DCURSORCAPS_LOWRES; @@ -1889,7 +2119,6 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DPRASTERCAPS_ZFOG | WINED3DPRASTERCAPS_FOGVERTEX | WINED3DPRASTERCAPS_FOGTABLE | - WINED3DPRASTERCAPS_FOGRANGE | WINED3DPRASTERCAPS_STIPPLE | WINED3DPRASTERCAPS_SUBPIXEL | WINED3DPRASTERCAPS_ZTEST | @@ -1901,6 +2130,9 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->RasterCaps |= WINED3DPRASTERCAPS_ANISOTROPY | WINED3DPRASTERCAPS_ZBIAS | WINED3DPRASTERCAPS_MIPMAPLODBIAS; + } + if(GL_SUPPORT(NV_FOG_DISTANCE)) { + *pCaps->RasterCaps |= WINED3DPRASTERCAPS_FOGRANGE; } /* FIXME Add: WINED3DPRASTERCAPS_COLORPERSPECTIVE @@ -1934,8 +2166,6 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DPBLENDCAPS_ZERO; *pCaps->DestBlendCaps = WINED3DPBLENDCAPS_BLENDFACTOR | - WINED3DPBLENDCAPS_BOTHINVSRCALPHA | - WINED3DPBLENDCAPS_BOTHSRCALPHA | WINED3DPBLENDCAPS_DESTALPHA | WINED3DPBLENDCAPS_DESTCOLOR | WINED3DPBLENDCAPS_INVDESTALPHA | @@ -1948,6 +2178,9 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DPBLENDCAPS_ZERO; /* NOTE: WINED3DPBLENDCAPS_SRCALPHASAT is not supported as dest blend factor, * according to the glBlendFunc manpage + * + * WINED3DPBLENDCAPS_BOTHINVSRCALPHA and WINED3DPBLENDCAPS_BOTHSRCALPHA are + * legacy settings for srcblend only */ *pCaps->AlphaCmpCaps = WINED3DPCMPCAPS_ALWAYS | @@ -1973,8 +2206,12 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DPTEXTURECAPS_BORDER | WINED3DPTEXTURECAPS_MIPMAP | WINED3DPTEXTURECAPS_PROJECTED | - WINED3DPTEXTURECAPS_PERSPECTIVE | - WINED3DPTEXTURECAPS_NONPOW2CONDITIONAL; + WINED3DPTEXTURECAPS_PERSPECTIVE; + + if( !GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) { + *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_POW2 | + WINED3DPTEXTURECAPS_NONPOW2CONDITIONAL; + } if( GL_SUPPORT(EXT_TEXTURE3D)) { *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_VOLUMEMAP | @@ -2199,14 +2436,17 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, if (vs_selected_mode == SHADER_GLSL) { /* Nvidia Geforce6/7 or Ati R4xx/R5xx cards with GLSL support, support VS 3.0 but older Nvidia/Ati - models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using - vs_nv_version which is based on NV_vertex_program. For Ati cards there's no easy way, so for - now only support 2.0/3.0 detection on Nvidia GeforceFX cards and default to 3.0 for everything else */ - if(GLINFO_LOCATION.vs_nv_version == VS_VERSION_20) + * models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using + * vs_nv_version which is based on NV_vertex_program. + * For Ati cards there's no way using glsl (it abstracts the lowlevel info away) and also not + * using ARB_vertex_program. It is safe to assume that when a card supports pixel shader 2.0 it + * supports vertex shader 2.0 too and the way around. We can detect ps2.0 using the maximum number + * of native instructions, so use that here. For more info see the pixel shader versioning code below. */ + if((GLINFO_LOCATION.vs_nv_version == VS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) *pCaps->VertexShaderVersion = WINED3DVS_VERSION(2,0); else *pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0); - TRACE_(d3d_caps)("Hardware vertex shader version 3.0 enabled (GLSL)\n"); + TRACE_(d3d_caps)("Hardware vertex shader version %d.%d enabled (GLSL)\n", (*pCaps->VertexShaderVersion >> 8) & 0xff, *pCaps->VertexShaderVersion & 0xff); } else if (vs_selected_mode == SHADER_ARB) { *pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1); TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); @@ -2218,18 +2458,38 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); if (ps_selected_mode == SHADER_GLSL) { - /* See the comment about VS2.0/VS3.0 detection as we do the same here but then based on NV_fragment_program - in case of GeforceFX cards. */ - if(GLINFO_LOCATION.ps_nv_version == PS_VERSION_20) + /* Older DX9-class videocards (GeforceFX / Radeon >9500/X*00) only support pixel shader 2.0/2.0a/2.0b. + * In OpenGL the extensions related to GLSL abstract lowlevel GL info away which is needed + * to distinguish between 2.0 and 3.0 (and 2.0a/2.0b). In case of Nvidia we use their fragment + * program extensions. On other hardware including ATI GL_ARB_fragment_program offers the info + * in max native instructions. Intel and others also offer the info in this extension but they + * don't support GLSL (at least on Windows). + * + * PS2.0 requires at least 96 instructions, 2.0a/2.0b go upto 512. Assume that if the number + * of instructions is 512 or less we have to do with ps2.0 hardware. + * NOTE: ps3.0 hardware requires 512 or more instructions but ati and nvidia offer 'enough' (1024 vs 4096) on their most basic ps3.0 hardware. + */ + if((GLINFO_LOCATION.ps_nv_version == PS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) *pCaps->PixelShaderVersion = WINED3DPS_VERSION(2,0); else *pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0); - /* FIXME: The following line is card dependent. -1.0 to 1.0 is a safe default clamp range for now */ - *pCaps->PixelShader1xMaxValue = 1.0; - TRACE_(d3d_caps)("Hardware pixel shader version 3.0 enabled (GLSL)\n"); + /* FIXME: The following line is card dependent. -8.0 to 8.0 is the + * Direct3D minimum requirement. + * + * Both GL_ARB_fragment_program and GLSL require a "maximum representable magnitude" + * of colors to be 2^10, and 2^32 for other floats. Should we use 1024 here? + * + * The problem is that the refrast clamps temporary results in the shader to + * [-MaxValue;+MaxValue]. If the card's max value is bigger than the one we advertize here, + * then applications may miss the clamping behavior. On the other hand, if it is smaller, + * the shader will generate incorrect results too. Unfortunately, GL deliberately doesn't + * offer a way to query this. + */ + *pCaps->PixelShader1xMaxValue = 8.0; + TRACE_(d3d_caps)("Hardware pixel shader version %d.%d enabled (GLSL)\n", (*pCaps->PixelShaderVersion >> 8) & 0xff, *pCaps->PixelShaderVersion & 0xff); } else if (ps_selected_mode == SHADER_ARB) { *pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4); - *pCaps->PixelShader1xMaxValue = 1.0; + *pCaps->PixelShader1xMaxValue = 8.0; TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); } else { *pCaps->PixelShaderVersion = 0; @@ -2408,6 +2668,7 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, } else { object->surface_alignment = 4; } + object->posFixup[0] = 1.0; /* This is needed to get the x coord unmodified through a MAD */ /* Set the state up as invalid until the device is fully created */ object->state = WINED3DERR_DRIVERINTERNALERROR; @@ -2479,9 +2740,70 @@ ULONG WINAPI D3DCB_DefaultDestroyVolume(IWineD3DVolume *pVolume) { return IUnknown_Release(volumeParent); } +static BOOL implementation_is_apple(WineD3D_GL_Info *gl_info) { + /* MacOS has various specialities in the extensions it advertises. Some have to be loaded from + * the opengl 1.2+ core, while other extensions are advertised, but software emulated. So try to + * detect the Apple OpenGL implementation to apply some extension fixups afterwards. + * + * Detecting this isn't really easy. The vendor string doesn't mention Apple. Compile-time checks + * aren't sufficient either because a Linux binary may display on a macos X server via remote X11. + * So try to detect the GL implementation by looking at certain Apple extensions. Some extensions + * like client storage might be supported on other implementations too, but GL_APPLE_flush_render + * is specific to the MacOS window management, and GL_APPLE_ycbcr_422 is a Quicktime specific, so + * it the chance that other implementations support it is rather rare since Win32 Quicktime uses + * DirectDraw, not OpenGL. + */ + if(gl_info->supported[APPLE_FENCE] && + gl_info->supported[APPLE_CLIENT_STORAGE] && + gl_info->supported[APPLE_FLUSH_RENDER] && + gl_info->supported[APPLE_YCBCR_422]) { + TRACE_(d3d_caps)("GL_APPLE_fence, GL_APPLE_client_storage, GL_APPLE_flush_render and GL_ycbcr_422 are supported\n"); + TRACE_(d3d_caps)("Activating MacOS fixups\n"); + return TRUE; + } else { + TRACE_(d3d_caps)("Apple extensions are not supported\n"); + TRACE_(d3d_caps)("Not activating MacOS fixups\n"); + return FALSE; + } +} + +static void fixup_extensions(WineD3D_GL_Info *gl_info) { + if(implementation_is_apple(gl_info)) { + /* MacOS advertises more GLSL vertex shader uniforms than support on hardware, and if more are + * used it falls back to software. While the compiler can detect if the shader uses all declared + * uniforms, the optimization fails if the shader uses relative addressing. So any GLSL shader + * using relative addressing falls back to software. + * + * ARB vp gives the correct amount of uniforms, so use it instead of GLSL + */ + if(gl_info->vs_glsl_constantsF <= gl_info->vs_arb_constantsF) { + FIXME("GLSL doesn't advertise more vertex shader uniforms than ARB. Driver fixup outdated?\n"); + } else { + TRACE("Driver claims %u GLSL vs uniforms, replacing with %u ARB vp uniforms\n", + gl_info->vs_glsl_constantsF, gl_info->vs_arb_constantsF); + gl_info->vs_glsl_constantsF = gl_info->vs_arb_constantsF; + } + + /* MacOS advertises GL_ARB_texture_non_power_of_two on ATI r500 and earlier cards, although + * these cards only support GL_ARB_texture_rectangle(D3DPTEXTURECAPS_NONPOW2CONDITIONAL). + * If real NP2 textures are used, the driver falls back to software. So remove the supported + * flag for this extension + */ + if(gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] && gl_info->gl_vendor == VENDOR_ATI) { + if(gl_info->gl_card == CARD_ATI_RADEON_X700 || gl_info->gl_card == CARD_ATI_RADEON_X1600 || + gl_info->gl_card == CARD_ATI_RADEON_9500 || gl_info->gl_card == CARD_ATI_RADEON_8500 || + gl_info->gl_card == CARD_ATI_RADEON_7200 || gl_info->gl_card == CARD_ATI_RAGE_128PRO) { + TRACE("GL_ARB_texture_non_power_of_two advertised on R500 or earlier card, removing\n"); + gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] = FALSE; + } + } + } +} + #define PUSH1(att) attribs[nAttribs++] = (att); #define GLINFO_LOCATION (Adapters[0].gl_info) BOOL InitAdapters(void) { + static HMODULE mod_gl; BOOL ret; int ps_selected_mode, vs_selected_mode; @@ -2491,77 +2813,132 @@ BOOL InitAdapters(void) { if(numAdapters > 0) return TRUE; TRACE("Initializing adapters\n"); + + if(!mod_gl) { +#ifdef USE_WIN32_OPENGL +#define USE_GL_FUNC(pfn) pfn = (void*)GetProcAddress(mod_gl, #pfn); + mod_gl = LoadLibraryA("opengl32.dll"); + if(!mod_gl) { + ERR("Can't load opengl32.dll!\n"); + return FALSE; + } +#else +#define USE_GL_FUNC(pfn) pfn = (void*)pwglGetProcAddress(#pfn); + /* To bypass the opengl32 thunks load wglGetProcAddress from gdi32 (glXGetProcAddress wrapper) instead of opengl32's */ + mod_gl = GetModuleHandleA("gdi32.dll"); +#endif + } + +/* Load WGL core functions from opengl32.dll */ +#define USE_WGL_FUNC(pfn) p##pfn = (void*)GetProcAddress(mod_gl, #pfn); + WGL_FUNCS_GEN; +#undef USE_WGL_FUNC + + if(!pwglGetProcAddress) { + ERR("Unable to load wglGetProcAddress!\n"); + return FALSE; + } + +/* Dynamically load all GL core functions */ + GL_FUNCS_GEN; +#undef USE_GL_FUNC + /* For now only one default adapter */ { + int iPixelFormat; + int attribs[8]; + int values[8]; + int nAttribs = 0; + int res; + WineD3D_PixelFormat *cfgs; int attribute; DISPLAY_DEVICEW DisplayDevice; + HDC hdc; TRACE("Initializing default adapter\n"); Adapters[0].monitorPoint.x = -1; Adapters[0].monitorPoint.y = -1; + if (!WineD3D_CreateFakeGLContext()) { + ERR("Failed to get a gl context for default adapter\n"); + HeapFree(GetProcessHeap(), 0, Adapters); + WineD3D_ReleaseFakeGLContext(); + return FALSE; + } + ret = IWineD3DImpl_FillGLCaps(&Adapters[0].gl_info); if(!ret) { ERR("Failed to initialize gl caps for default adapter\n"); HeapFree(GetProcessHeap(), 0, Adapters); + WineD3D_ReleaseFakeGLContext(); return FALSE; } ret = initPixelFormats(&Adapters[0].gl_info); if(!ret) { ERR("Failed to init gl formats\n"); HeapFree(GetProcessHeap(), 0, Adapters); + WineD3D_ReleaseFakeGLContext(); + return FALSE; + } + + hdc = pwglGetCurrentDC(); + if(!hdc) { + ERR("Failed to get gl HDC\n"); + HeapFree(GetProcessHeap(), 0, Adapters); + WineD3D_ReleaseFakeGLContext(); return FALSE; } Adapters[0].driver = "Display"; Adapters[0].description = "Direct3D HAL"; + /* Use the VideoRamSize registry setting when set */ + if(wined3d_settings.emulated_textureram) + Adapters[0].TextureRam = wined3d_settings.emulated_textureram; + else + Adapters[0].TextureRam = Adapters[0].gl_info.vidmem; + Adapters[0].UsedTextureRam = 0; + TRACE("Emulating %dMB of texture ram\n", Adapters[0].TextureRam/(1024*1024)); + /* Initialize the Adapter's DeviceName which is required for ChangeDisplaySettings and friends */ DisplayDevice.cb = sizeof(DisplayDevice); EnumDisplayDevicesW(NULL, 0 /* Adapter 0 = iDevNum 0 */, &DisplayDevice, 0); TRACE("DeviceName: %s\n", debugstr_w(DisplayDevice.DeviceName)); strcpyW(Adapters[0].DeviceName, DisplayDevice.DeviceName); - if (WineD3D_CreateFakeGLContext()) { - int iPixelFormat; - int attribs[8]; - int values[8]; - int nAttribs = 0; - int res; - WineD3D_PixelFormat *cfgs; + attribute = WGL_NUMBER_PIXEL_FORMATS_ARB; + GL_EXTCALL(wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, &attribute, &Adapters[0].nCfgs)); - attribute = WGL_NUMBER_PIXEL_FORMATS_ARB; - GL_EXTCALL(wglGetPixelFormatAttribivARB(wined3d_fake_gl_context_hdc, 0, 0, 1, &attribute, &Adapters[0].nCfgs)); + Adapters[0].cfgs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Adapters[0].nCfgs *sizeof(WineD3D_PixelFormat)); + cfgs = Adapters[0].cfgs; + PUSH1(WGL_RED_BITS_ARB) + PUSH1(WGL_GREEN_BITS_ARB) + PUSH1(WGL_BLUE_BITS_ARB) + PUSH1(WGL_ALPHA_BITS_ARB) + PUSH1(WGL_DEPTH_BITS_ARB) + PUSH1(WGL_STENCIL_BITS_ARB) - Adapters[0].cfgs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Adapters[0].nCfgs *sizeof(WineD3D_PixelFormat)); - cfgs = Adapters[0].cfgs; - PUSH1(WGL_RED_BITS_ARB) - PUSH1(WGL_GREEN_BITS_ARB) - PUSH1(WGL_BLUE_BITS_ARB) - PUSH1(WGL_ALPHA_BITS_ARB) - PUSH1(WGL_DEPTH_BITS_ARB) - PUSH1(WGL_STENCIL_BITS_ARB) + for(iPixelFormat=1; iPixelFormat<=Adapters[0].nCfgs; iPixelFormat++) { + res = GL_EXTCALL(wglGetPixelFormatAttribivARB(hdc, iPixelFormat, 0, nAttribs, attribs, values)); - for(iPixelFormat=1; iPixelFormat<=Adapters[0].nCfgs; iPixelFormat++) { - res = GL_EXTCALL(wglGetPixelFormatAttribivARB(wined3d_fake_gl_context_hdc, iPixelFormat, 0, nAttribs, attribs, values)); + if(!res) + continue; - if(!res) - continue; + /* Cache the pixel format */ + cfgs->iPixelFormat = iPixelFormat; + cfgs->redSize = values[0]; + cfgs->greenSize = values[1]; + cfgs->blueSize = values[2]; + cfgs->alphaSize = values[3]; + cfgs->depthSize = values[4]; + cfgs->stencilSize = values[5]; - /* Cache the pixel format */ - cfgs->iPixelFormat = iPixelFormat; - cfgs->redSize = values[0]; - cfgs->greenSize = values[1]; - cfgs->blueSize = values[2]; - cfgs->alphaSize = values[3]; - cfgs->depthSize = values[4]; - cfgs->stencilSize = values[5]; - - TRACE("iPixelFormat=%d, RGBA=%d/%d/%d/%d, depth=%d, stencil=%d\n", cfgs->iPixelFormat, cfgs->redSize, cfgs->greenSize, cfgs->blueSize, cfgs->alphaSize, cfgs->depthSize, cfgs->stencilSize); - cfgs++; - } - WineD3D_ReleaseFakeGLContext(); + TRACE("iPixelFormat=%d, RGBA=%d/%d/%d/%d, depth=%d, stencil=%d\n", cfgs->iPixelFormat, cfgs->redSize, cfgs->greenSize, cfgs->blueSize, cfgs->alphaSize, cfgs->depthSize, cfgs->stencilSize); + cfgs++; } + WineD3D_ReleaseFakeGLContext(); + + fixup_extensions(&Adapters[0].gl_info); select_shader_mode(&Adapters[0].gl_info, WINED3DDEVTYPE_HAL, &ps_selected_mode, &vs_selected_mode); select_shader_max_constants(ps_selected_mode, vs_selected_mode, &Adapters[0].gl_info); diff --git a/reactos/dll/directx/wine/wined3d/drawprim.c b/reactos/dll/directx/wine/wined3d/drawprim.c index e6766a24b4b..c6cb9da96d4 100644 --- a/reactos/dll/directx/wine/wined3d/drawprim.c +++ b/reactos/dll/directx/wine/wined3d/drawprim.c @@ -178,6 +178,7 @@ void primitiveDeclarationConvertToStridedData( if (This->stateBlock->streamSource[element->Stream] == NULL) continue; + stride = This->stateBlock->streamStride[element->Stream]; if (This->stateBlock->streamIsUP) { TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]); streamVBO = 0; @@ -185,6 +186,22 @@ void primitiveDeclarationConvertToStridedData( } else { TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]); data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO); + + /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets + * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory + * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap + * around to some big value. Hope that with the indices, the driver wraps it back internally. If + * not, drawStridedSlow is needed, including a vertex buffer path. + */ + if(This->stateBlock->loadBaseVertexIndex < 0) { + WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex); + streamVBO = 0; + data = ((IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[element->Stream])->resource.allocatedMemory; + if(data + This->stateBlock->loadBaseVertexIndex * stride < 0) { + FIXME("System memory vertex data load offset is negative!\n"); + } + } + if(fixup) { if( streamVBO != 0) *fixup = TRUE; else if(*fixup && !useVertexShaderFunction && @@ -195,7 +212,6 @@ void primitiveDeclarationConvertToStridedData( } } } - stride = This->stateBlock->streamStride[element->Stream]; data += element->Offset; reg = element->Reg; @@ -230,7 +246,10 @@ void primitiveDeclarationConvertToStridedData( * once in there. */ for(i=0; i < numPreloadStreams; i++) { - IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[streams[i]]); + IWineD3DVertexBuffer *vb = This->stateBlock->streamSource[streams[i]]; + if(vb) { + IWineD3DVertexBuffer_PreLoad(vb); + } } } @@ -284,7 +303,8 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData DWORD specularColor = 0; /* Specular Color */ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; UINT *streamOffset = This->stateBlock->streamOffset; - DWORD SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; + long SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; + BOOL pixelShader = use_ps(This); BYTE *texCoords[WINED3DDP_MAXTEXCOORD]; BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL; @@ -334,7 +354,7 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData /* Default settings for data that is not passed */ if (sd->u.s.normal.lpData == NULL) { - glNormal3f(0, 0, 1); + glNormal3f(0, 0, 0); } if(sd->u.s.diffuse.lpData == NULL) { glColor4f(1.0f, 1.0f, 1.0f, 1.0f); @@ -381,9 +401,10 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData } /* Query tex coords */ - if (This->stateBlock->textures[textureNo] != NULL) { + if (This->stateBlock->textures[textureNo] != NULL || pixelShader) { int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX]; + int texture_idx = This->texUnitMap[textureNo]; float *ptrToCoords = NULL; float s = 0.0, t = 0.0, r = 0.0, q = 0.0; @@ -398,9 +419,13 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData ptrToCoords = (float *)(texCoords[coordIdx] + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride)); if (texCoords[coordIdx] == NULL) { TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo); + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1)); + } else { + glTexCoord4f(0, 0, 0, 1); + } continue; } else { - int texture_idx = This->texUnitMap[textureNo]; int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */ if (texture_idx == -1) continue; @@ -413,36 +438,6 @@ static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData case 1: s = ptrToCoords[0]; } - /* Projected is more 'fun' - Move the last coord to the 'q' - parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */ - if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) && - (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) { - - if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) { - switch (coordsToUse) { - case 0: /* Drop Through */ - case 1: - FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n"); - break; - case 2: - q = t; - t = 0.0; - coordsToUse = 4; - break; - case 3: - q = r; - r = 0.0; - coordsToUse = 4; - break; - case 4: /* Nop here */ - break; - default: - FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n", - This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED); - } - } - } - switch (coordsToUse) { /* Supply the provided texture coords */ case WINED3DTTFF_COUNT1: VTRACE(("tex:%d, s=%f\n", textureNo, s)); @@ -761,7 +756,7 @@ static inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVerte break; case WINED3DDECLTYPE_UBYTE4: - GL_EXTCALL(glVertexAttrib4NubvARB(instancedData[j], ptr)); + GL_EXTCALL(glVertexAttrib4ubvARB(instancedData[j], ptr)); break; case WINED3DDECLTYPE_UBYTE4N: case WINED3DDECLTYPE_D3DCOLOR: @@ -834,125 +829,92 @@ static inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVerte } } -struct coords { - int x, y, z; -}; +static inline void remove_vbos(IWineD3DDeviceImpl *This, WineDirect3DVertexStridedData *s) { + unsigned char i; + IWineD3DVertexBufferImpl *vb; -void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface) { - struct coords coords[4]; - int low_coord; - - /* TODO: This could be supported for lazy unlocking */ - if(!(surface->Flags & SFLAG_INTEXTURE)) { - /* It is ok at init to be nowhere */ - if(!(surface->Flags & SFLAG_INSYSMEM)) { - ERR("Blitting surfaces from sysmem not supported yet\n"); + if(s->u.s.position.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.position.streamNo]; + s->u.s.position.VBO = 0; + s->u.s.position.lpData = (BYTE *) ((unsigned long) s->u.s.position.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.blendWeights.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.blendWeights.streamNo]; + s->u.s.blendWeights.VBO = 0; + s->u.s.blendWeights.lpData = (BYTE *) ((unsigned long) s->u.s.blendWeights.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.blendMatrixIndices.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.blendMatrixIndices.streamNo]; + s->u.s.blendMatrixIndices.VBO = 0; + s->u.s.blendMatrixIndices.lpData = (BYTE *) ((unsigned long) s->u.s.blendMatrixIndices.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.normal.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.normal.streamNo]; + s->u.s.normal.VBO = 0; + s->u.s.normal.lpData = (BYTE *) ((unsigned long) s->u.s.normal.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.pSize.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.pSize.streamNo]; + s->u.s.pSize.VBO = 0; + s->u.s.pSize.lpData = (BYTE *) ((unsigned long) s->u.s.pSize.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.diffuse.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.diffuse.streamNo]; + s->u.s.diffuse.VBO = 0; + s->u.s.diffuse.lpData = (BYTE *) ((unsigned long) s->u.s.diffuse.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.specular.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.specular.streamNo]; + s->u.s.specular.VBO = 0; + s->u.s.specular.lpData = (BYTE *) ((unsigned long) s->u.s.specular.lpData + (unsigned long) vb->resource.allocatedMemory); + } + for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) { + if(s->u.s.texCoords[i].VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.texCoords[i].streamNo]; + s->u.s.texCoords[i].VBO = 0; + s->u.s.texCoords[i].lpData = (BYTE *) ((unsigned long) s->u.s.texCoords[i].lpData + (unsigned long) vb->resource.allocatedMemory); } - return; } - - ActivateContext(This, This->render_targets[0], CTXUSAGE_BLIT); - ENTER_GL(); - - if(surface->glDescription.target == GL_TEXTURE_2D) { - glBindTexture(GL_TEXTURE_2D, surface->glDescription.textureName); - checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)"); - - coords[0].x = 0; coords[0].y = 0; coords[0].z = 0; - coords[1].x = 0; coords[1].y = 1; coords[1].z = 0; - coords[2].x = 1; coords[2].y = 1; coords[2].z = 0; - coords[3].x = 1; coords[3].y = 0; coords[3].z = 0; - - low_coord = 0; - } else { - /* Must be a cube map */ - glDisable(GL_TEXTURE_2D); - checkGLcall("glDisable(GL_TEXTURE_2D)"); - glEnable(GL_TEXTURE_CUBE_MAP_ARB); - checkGLcall("glEnable(surface->glDescription.target)"); - glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, surface->glDescription.textureName); - checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)"); - - switch(surface->glDescription.target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - coords[0].x = 1; coords[0].y = -1; coords[0].z = 1; - coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; - coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; - coords[3].x = 1; coords[3].y = -1; coords[3].z = -1; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; - coords[1].x = -1; coords[1].y = 1; coords[1].z = 1; - coords[2].x = -1; coords[2].y = 1; coords[2].z = -1; - coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; - break; - - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - coords[0].x = -1; coords[0].y = 1; coords[0].z = 1; - coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; - coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; - coords[3].x = -1; coords[3].y = 1; coords[3].z = -1; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; - coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; - coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; - coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; - break; - - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; - coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; - coords[2].x = 1; coords[2].y = -1; coords[2].z = 1; - coords[3].x = -1; coords[3].y = -1; coords[3].z = 1; - break; - - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - coords[0].x = -1; coords[0].y = -1; coords[0].z = -1; - coords[1].x = 1; coords[1].y = -1; coords[1].z = -1; - coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; - coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; - - default: - ERR("Unexpected texture target\n"); - LEAVE_GL(); - return; - } - - low_coord = -1; + if(s->u.s.position2.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.position2.streamNo]; + s->u.s.position2.VBO = 0; + s->u.s.position2.lpData = (BYTE *) ((unsigned long) s->u.s.position2.lpData + (unsigned long) vb->resource.allocatedMemory); } - - if(This->render_offscreen) { - coords[0].y = coords[0].y == 1 ? low_coord : 1; - coords[1].y = coords[1].y == 1 ? low_coord : 1; - coords[2].y = coords[2].y == 1 ? low_coord : 1; - coords[3].y = coords[3].y == 1 ? low_coord : 1; + if(s->u.s.normal2.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.normal2.streamNo]; + s->u.s.normal2.VBO = 0; + s->u.s.normal2.lpData = (BYTE *) ((unsigned long) s->u.s.normal2.lpData + (unsigned long) vb->resource.allocatedMemory); } - - glBegin(GL_QUADS); - glTexCoord3iv((GLint *) &coords[0]); - glVertex2i(0, 0); - - glTexCoord3iv((GLint *) &coords[1]); - glVertex2i(0, surface->pow2Height); - - glTexCoord3iv((GLint *) &coords[2]); - glVertex2i(surface->pow2Width, surface->pow2Height); - - glTexCoord3iv((GLint *) &coords[3]); - glVertex2i(surface->pow2Width, 0); - glEnd(); - checkGLcall("glEnd"); - - if(surface->glDescription.target != GL_TEXTURE_2D) { - glEnable(GL_TEXTURE_2D); - checkGLcall("glEnable(GL_TEXTURE_2D)"); - glDisable(GL_TEXTURE_CUBE_MAP_ARB); - checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + if(s->u.s.tangent.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.tangent.streamNo]; + s->u.s.tangent.VBO = 0; + s->u.s.tangent.lpData = (BYTE *) ((unsigned long) s->u.s.tangent.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.binormal.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.binormal.streamNo]; + s->u.s.binormal.VBO = 0; + s->u.s.binormal.lpData = (BYTE *) ((unsigned long) s->u.s.binormal.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.tessFactor.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.tessFactor.streamNo]; + s->u.s.tessFactor.VBO = 0; + s->u.s.tessFactor.lpData = (BYTE *) ((unsigned long) s->u.s.tessFactor.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.fog.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.fog.streamNo]; + s->u.s.fog.VBO = 0; + s->u.s.fog.lpData = (BYTE *) ((unsigned long) s->u.s.fog.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.depth.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.depth.streamNo]; + s->u.s.depth.VBO = 0; + s->u.s.depth.lpData = (BYTE *) ((unsigned long) s->u.s.depth.lpData + (unsigned long) vb->resource.allocatedMemory); + } + if(s->u.s.sample.VBO) { + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[s->u.s.sample.streamNo]; + s->u.s.sample.VBO = 0; + s->u.s.sample.lpData = (BYTE *) ((unsigned long) s->u.s.sample.lpData + (unsigned long) vb->resource.allocatedMemory); } - LEAVE_GL(); } /* Routine common to the draw primitive and draw indexed primitive routines */ @@ -991,33 +953,29 @@ void drawPrimitive(IWineD3DDevice *iface, IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain); /* Need the surface in the drawable! */ - if(!(target->Flags & SFLAG_INDRAWABLE) && (swapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) { - blt_to_drawable(This, target); - } + IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL); + /* TODO: Move fbo logic to ModifyLocation */ + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, TRUE); if(swapchain) { /* Onscreen target. Invalidate system memory copy and texture copy */ - target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE); - target->Flags |= SFLAG_INDRAWABLE; IWineD3DSwapChain_Release(swapchain); } else if(wined3d_settings.offscreen_rendering_mode != ORM_FBO) { /* Non-FBO target: Invalidate system copy, texture copy and dirtify the container */ + /* TODO: Move container dirtification to ModifyLocation */ IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DBaseTexture, (void **)&texture); if(texture) { IWineD3DBaseTexture_SetDirty(texture, TRUE); IWineD3DTexture_Release(texture); } - - target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE); - target->Flags |= SFLAG_INDRAWABLE; } else { - /* FBO offscreen target. Invalidate system memory copy */ - target->Flags &= ~SFLAG_INSYSMEM; + /* FBO offscreen target. Texture == Drawable */ + target->Flags |= SFLAG_INTEXTURE; } } else { /* Must be an fbo render target */ - target->Flags &= ~SFLAG_INSYSMEM; + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, TRUE); target->Flags |= SFLAG_INTEXTURE; } } @@ -1050,40 +1008,24 @@ void drawPrimitive(IWineD3DDevice *iface, if (numberOfVertices == 0 ) numberOfVertices = calculatedNumberOfindices; - if(!This->strided_streams.u.s.position_transformed && !use_vs(This)) { - if(This->activeContext->num_untracked_materials && - This->stateBlock->renderState[WINED3DRS_LIGHTING]) { - IWineD3DVertexBufferImpl *vb; - + if(!use_vs(This)) { + if(!This->strided_streams.u.s.position_transformed && This->activeContext->num_untracked_materials && + This->stateBlock->renderState[WINED3DRS_LIGHTING]) { FIXME("Using software emulation because not all material properties could be tracked\n"); emulation = TRUE; + } + else if(This->activeContext->fog_coord && This->stateBlock->renderState[WINED3DRS_FOGENABLE]) { + /* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte + * to a float in the vertex buffer + */ + FIXME("Using software emulation because manual fog coordinates are provided\n"); + emulation = TRUE; + } + if(emulation) { strided = &stridedlcl; memcpy(&stridedlcl, &This->strided_streams, sizeof(stridedlcl)); - -#define FIXVBO(type) \ -if(stridedlcl.u.s.type.VBO) { \ - vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[stridedlcl.u.s.type.streamNo]; \ - stridedlcl.u.s.type.VBO = 0; \ - stridedlcl.u.s.type.lpData = (BYTE *) ((unsigned long) stridedlcl.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \ -} - FIXVBO(position); - FIXVBO(blendWeights); - FIXVBO(blendMatrixIndices); - FIXVBO(normal); - FIXVBO(pSize); - FIXVBO(diffuse); - FIXVBO(specular); - for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) FIXVBO(texCoords[i]); - FIXVBO(position2); - FIXVBO(normal2); - FIXVBO(tangent); - FIXVBO(binormal); - FIXVBO(tessFactor); - FIXVBO(fog); - FIXVBO(depth); - FIXVBO(sample); -#undef FIXVBO + remove_vbos(This, &stridedlcl); } } diff --git a/reactos/dll/directx/wine/wined3d/glsl_shader.c b/reactos/dll/directx/wine/wined3d/glsl_shader.c index a39caf42fdf..73fb0f69774 100644 --- a/reactos/dll/directx/wine/wined3d/glsl_shader.c +++ b/reactos/dll/directx/wine/wined3d/glsl_shader.c @@ -77,16 +77,16 @@ void print_glsl_info_log(WineD3D_GL_Info *gl_info, GLhandleARB obj) { */ static void shader_glsl_load_psamplers( WineD3D_GL_Info *gl_info, - IWineD3DStateBlock* iface) { + IWineD3DStateBlock* iface, + GLhandleARB programId) { IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface; - GLhandleARB programId = stateBlock->glsl_program->programId; GLhandleARB name_loc; int i; char sampler_name[20]; for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) { - _snprintf(sampler_name, sizeof(sampler_name), "Psampler%d", i); + snprintf(sampler_name, sizeof(sampler_name), "Psampler%d", i); name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name)); if (name_loc != -1) { int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[i]; @@ -101,15 +101,14 @@ static void shader_glsl_load_psamplers( } } -static void shader_glsl_load_vsamplers(WineD3D_GL_Info *gl_info, IWineD3DStateBlock* iface) { +static void shader_glsl_load_vsamplers(WineD3D_GL_Info *gl_info, IWineD3DStateBlock* iface, GLhandleARB programId) { IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface; - GLhandleARB programId = stateBlock->glsl_program->programId; GLhandleARB name_loc; char sampler_name[20]; int i; for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) { - _snprintf(sampler_name, sizeof(sampler_name), "Vsampler%d", i); + snprintf(sampler_name, sizeof(sampler_name), "Vsampler%d", i); name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name)); if (name_loc != -1) { int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[MAX_FRAGMENT_SAMPLERS + i]; @@ -134,7 +133,7 @@ static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL constants_entry *constant; local_constant* lconst; GLhandleARB tmp_loc; - DWORD i, j; + DWORD i, j, k; DWORD *idx; if (TRACE_ON(d3d_shader)) { @@ -152,15 +151,49 @@ static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL } } } - LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { - idx = constant->idx; - j = constant->count; - while (j--) { - i = *idx++; - tmp_loc = constant_locations[i]; - if (tmp_loc != -1) { - /* We found this uniform name in the program - go ahead and send the data */ - GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, constants + (i * 4))); + + /* 1.X pshaders have the constants clamped to [-1;1] implicitly. */ + if(WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 && + shader_is_pshader_version(This->baseShader.hex_version)) { + float lcl_const[4]; + + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + tmp_loc = constant_locations[i]; + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + k = i * 4; + if(constants[k + 0] < -1.0) lcl_const[0] = -1.0; + else if(constants[k + 0] > 1.0) lcl_const[0] = 1.0; + else lcl_const[0] = constants[k + 0]; + if(constants[k + 1] < -1.0) lcl_const[1] = -1.0; + else if(constants[k + 1] > 1.0) lcl_const[1] = 1.0; + else lcl_const[1] = constants[k + 1]; + if(constants[k + 2] < -1.0) lcl_const[2] = -1.0; + else if(constants[k + 2] > 1.0) lcl_const[2] = 1.0; + else lcl_const[2] = constants[k + 2]; + if(constants[k + 3] < -1.0) lcl_const[3] = -1.0; + else if(constants[k + 3] > 1.0) lcl_const[3] = 1.0; + else lcl_const[3] = constants[k + 3]; + + GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, lcl_const)); + } + } + } + } else { + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + tmp_loc = constant_locations[i]; + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, constants + (i * 4))); + } } } } @@ -177,6 +210,7 @@ static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL } } } + /* Immediate constants are clamped to [-1;1] at shader creation time if needed */ LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { tmp_loc = constant_locations[lconst->idx]; if (tmp_loc != -1) { @@ -195,15 +229,12 @@ static void shader_glsl_load_constantsI( IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLhandleARB programId, + GLhandleARB locations[MAX_CONST_I], unsigned max_constants, int* constants, BOOL* constants_set) { - GLhandleARB tmp_loc; int i; - char tmp_name[8]; - char is_pshader = shader_is_pshader_version(This->baseShader.hex_version); - const char* prefix = is_pshader? "PI":"VI"; struct list* ptr; for (i=0; ibaseShader.constantsI, ptr); } } @@ -271,7 +292,7 @@ static void shader_glsl_load_constantsB( /* TODO: Benchmark and see if it would be beneficial to store the * locations of the constants to avoid looking up each time */ - _snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, i); + snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, i); tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name)); if (tmp_loc != -1) { /* We found this uniform name in the program - go ahead and send the data */ @@ -290,7 +311,7 @@ static void shader_glsl_load_constantsB( TRACE_(d3d_constants)("Loading local constants %i: %i\n", idx, values[0]); - _snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx); + snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx); tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name)); if (tmp_loc != -1) { /* We found this uniform name in the program - go ahead and send the data */ @@ -318,30 +339,27 @@ void shader_glsl_load_constants( GLhandleARB *constant_locations; struct list *constant_list; GLhandleARB programId; - GLint pos; + struct glsl_shader_prog_link *prog = stateBlock->glsl_program; - if (!stateBlock->glsl_program) { + if (!prog) { /* No GLSL program set - nothing to do. */ return; } - programId = stateBlock->glsl_program->programId; + programId = prog->programId; if (useVertexShader) { IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader; - GLint pos; - constant_locations = stateBlock->glsl_program->vuniformF_locations; + constant_locations = prog->vuniformF_locations; constant_list = &stateBlock->set_vconstantsF; - /* Load vertex shader samplers */ - shader_glsl_load_vsamplers(gl_info, (IWineD3DStateBlock*)stateBlock); - /* Load DirectX 9 float constants/uniforms for vertex shader */ shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF), stateBlock->vertexShaderConstantF, constant_locations, constant_list); /* Load DirectX 9 integer constants/uniforms for vertex shader */ - shader_glsl_load_constantsI(vshader, gl_info, programId, MAX_CONST_I, + shader_glsl_load_constantsI(vshader, gl_info, programId, + prog->vuniformI_locations, MAX_CONST_I, stateBlock->vertexShaderConstantI, stateBlock->changed.vertexShaderConstantsI); @@ -351,9 +369,7 @@ void shader_glsl_load_constants( stateBlock->changed.vertexShaderConstantsB); /* Upload the position fixup params */ - pos = GL_EXTCALL(glGetUniformLocationARB(programId, "posFixup")); - checkGLcall("glGetUniformLocationARB"); - GL_EXTCALL(glUniform4fvARB(pos, 1, &deviceImpl->posFixup[0])); + GL_EXTCALL(glUniform4fvARB(prog->posFixup_location, 1, &deviceImpl->posFixup[0])); checkGLcall("glUniform4fvARB"); } @@ -361,18 +377,16 @@ void shader_glsl_load_constants( IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader; - constant_locations = stateBlock->glsl_program->puniformF_locations; + constant_locations = prog->puniformF_locations; constant_list = &stateBlock->set_pconstantsF; - /* Load pixel shader samplers */ - shader_glsl_load_psamplers(gl_info, (IWineD3DStateBlock*) stateBlock); - /* Load DirectX 9 float constants/uniforms for pixel shader */ shader_glsl_load_constantsF(pshader, gl_info, GL_LIMITS(pshader_constantsF), stateBlock->pixelShaderConstantF, constant_locations, constant_list); /* Load DirectX 9 integer constants/uniforms for pixel shader */ - shader_glsl_load_constantsI(pshader, gl_info, programId, MAX_CONST_I, + shader_glsl_load_constantsI(pshader, gl_info, programId, + prog->puniformI_locations, MAX_CONST_I, stateBlock->pixelShaderConstantI, stateBlock->changed.pixelShaderConstantsI); @@ -386,10 +400,55 @@ void shader_glsl_load_constants( */ if(((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat != -1) { float *data = (float *) &stateBlock->textureState[(int) ((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; - pos = GL_EXTCALL(glGetUniformLocationARB(programId, "bumpenvmat")); - checkGLcall("glGetUniformLocationARB"); - GL_EXTCALL(glUniformMatrix2fvARB(pos, 1, 0, data)); - checkGLcall("glUniform4fvARB"); + GL_EXTCALL(glUniformMatrix2fvARB(prog->bumpenvmat_location, 1, 0, data)); + checkGLcall("glUniformMatrix2fvARB"); + + /* texbeml needs the luminance scale and offset too. If texbeml is used, needsbumpmat + * is set too, so we can check that in the needsbumpmat check + */ + if(((IWineD3DPixelShaderImpl *) pshader)->baseShader.reg_maps.luminanceparams != -1) { + int stage = ((IWineD3DPixelShaderImpl *) pshader)->baseShader.reg_maps.luminanceparams; + GLfloat *scale = (GLfloat *) &stateBlock->textureState[stage][WINED3DTSS_BUMPENVLSCALE]; + GLfloat *offset = (GLfloat *) &stateBlock->textureState[stage][WINED3DTSS_BUMPENVLOFFSET]; + + GL_EXTCALL(glUniform1fvARB(prog->luminancescale_location, 1, scale)); + checkGLcall("glUniform1fvARB"); + GL_EXTCALL(glUniform1fvARB(prog->luminanceoffset_location, 1, offset)); + checkGLcall("glUniform1fvARB"); + } + } else if(((IWineD3DPixelShaderImpl *) pshader)->srgb_enabled && + !((IWineD3DPixelShaderImpl *) pshader)->srgb_mode_hardcoded) { + float comparison[4]; + float mul_low[4]; + + if(stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) { + comparison[0] = srgb_cmp; comparison[1] = srgb_cmp; + comparison[2] = srgb_cmp; comparison[3] = srgb_cmp; + + mul_low[0] = srgb_mul_low; mul_low[1] = srgb_mul_low; + mul_low[2] = srgb_mul_low; mul_low[3] = srgb_mul_low; + } else { + comparison[0] = 1.0 / 0.0; comparison[1] = 1.0 / 0.0; + comparison[2] = 1.0 / 0.0; comparison[3] = 1.0 / 0.0; + + mul_low[0] = 1.0; mul_low[1] = 1.0; + mul_low[2] = 1.0; mul_low[3] = 1.0; + } + + GL_EXTCALL(glUniform4fvARB(prog->srgb_comparison_location, 1, comparison)); + GL_EXTCALL(glUniform4fvARB(prog->srgb_mul_low_location, 1, mul_low)); + } + if(((IWineD3DPixelShaderImpl *) pshader)->vpos_uniform) { + float correction_params[4]; + if(deviceImpl->render_offscreen) { + correction_params[0] = 0.0; + correction_params[1] = 1.0; + } else { + /* position is window relative, not viewport relative */ + correction_params[0] = ((IWineD3DSurfaceImpl *) deviceImpl->render_targets[0])->currentDesc.Height; + correction_params[1] = -1.0; + } + GL_EXTCALL(glUniform4fvARB(prog->ycorrection_location, 1, correction_params)); } } } @@ -402,7 +461,9 @@ void shader_generate_glsl_declarations( WineD3D_GL_Info* gl_info) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device; int i; + unsigned int extra_constants_needed = 0; /* There are some minor differences between pixel and vertex shaders */ char pshader = shader_is_pshader_version(This->baseShader.hex_version); @@ -427,10 +488,76 @@ void shader_generate_glsl_declarations( if (This->baseShader.limits.constant_bool > 0) shader_addline(buffer, "uniform bool %cB[%u];\n", prefix, This->baseShader.limits.constant_bool); - if(!pshader) + if(!pshader) { shader_addline(buffer, "uniform vec4 posFixup;\n"); - else if(reg_maps->bumpmat != -1) - shader_addline(buffer, "uniform mat2 bumpenvmat;\n"); + /* Predeclaration; This function is added at link time based on the pixel shader. + * VS 3.0 shaders have an array OUT[] the shader writes to, earlier versions don't have + * that. We know the input to the reorder function at vertex shader compile time, so + * we can deal with that. The reorder function for a 1.x and 2.x vertex shader can just + * read gl_FrontColor. The output depends on the pixel shader. The reorder function for a + * 1.x and 2.x pshader or for fixed function will write gl_FrontColor, and for a 3.0 shader + * it will write to the varying array. Here we depend on the shader optimizer on sorting that + * out. The nvidia driver only does that if the parameter is inout instead of out, hence the + * inout. + */ + if(This->baseShader.hex_version >= WINED3DVS_VERSION(3, 0)) { + shader_addline(buffer, "void order_ps_input(in vec4[%u]);\n", MAX_REG_OUTPUT); + } else { + shader_addline(buffer, "void order_ps_input();\n"); + } + } else { + IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This; + + if(reg_maps->bumpmat != -1) { + shader_addline(buffer, "uniform mat2 bumpenvmat;\n"); + if(reg_maps->luminanceparams) { + shader_addline(buffer, "uniform float luminancescale;\n"); + shader_addline(buffer, "uniform float luminanceoffset;\n"); + extra_constants_needed++; + } + extra_constants_needed++; + } + + if(device->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) { + ps_impl->srgb_enabled = 1; + if(This->baseShader.limits.constant_float + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF)) { + shader_addline(buffer, "uniform vec4 srgb_mul_low;\n"); + shader_addline(buffer, "uniform vec4 srgb_comparison;\n"); + ps_impl->srgb_mode_hardcoded = 0; + extra_constants_needed++; + } else { + ps_impl->srgb_mode_hardcoded = 1; + shader_addline(buffer, "const vec4 srgb_mul_low = {%f, %f, %f, %f};\n", + srgb_mul_low, srgb_mul_low, srgb_mul_low, srgb_mul_low); + shader_addline(buffer, "const vec4 srgb_comparison = {%f, %f, %f, %f};\n", + srgb_cmp, srgb_cmp, srgb_cmp, srgb_cmp); + } + } else { + IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This; + + /* Do not write any srgb fixup into the shader to save shader size and processing time. + * As a consequence, we can't toggle srgb write on without recompilation + */ + ps_impl->srgb_enabled = 0; + ps_impl->srgb_mode_hardcoded = 1; + } + if(reg_maps->vpos || reg_maps->usesdsy) { + if(This->baseShader.limits.constant_float + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF)) { + shader_addline(buffer, "uniform vec4 ycorrection;\n"); + ((IWineD3DPixelShaderImpl *) This)->vpos_uniform = 1; + extra_constants_needed++; + } else { + /* This happens because we do not have proper tracking of the constant registers that are + * actually used, only the max limit of the shader version + */ + FIXME("Cannot find a free uniform for vpos correction params\n"); + shader_addline(buffer, "const vec4 ycorrection = {%f, %f, 0.0, 0.0};\n", + device->render_offscreen ? 0.0 : ((IWineD3DSurfaceImpl *) device->render_targets[0])->currentDesc.Height, + device->render_offscreen ? 1.0 : -1.0); + } + shader_addline(buffer, "vec4 vpos;\n"); + } + } /* Declare texture samplers */ for (i = 0; i < This->baseShader.limits.sampler; i++) { @@ -471,16 +598,24 @@ void shader_generate_glsl_declarations( shader_addline(buffer, "vec4 T%lu = gl_TexCoord[%lu];\n", i, i); } - /* Declare input register temporaries */ - for (i=0; i < This->baseShader.limits.packed_input; i++) { - if (reg_maps->packed_input[i]) - shader_addline(buffer, "vec4 IN%lu;\n", i); + /* Declare input register varyings. Only pixel shader, vertex shaders have that declared in the + * helper function shader that is linked in at link time + */ + if(pshader && This->baseShader.hex_version >= WINED3DVS_VERSION(3, 0)) { + if(use_vs(device)) { + shader_addline(buffer, "varying vec4 IN[%lu];\n", GL_LIMITS(glsl_varyings) / 4); + } else { + /* TODO: Write a replacement shader for the fixed function vertex pipeline, so this isn't needed. + * For fixed function vertex processing + 3.0 pixel shader we need a separate function in the + * pixel shader that reads the fixed function color into the packed input registers. + */ + shader_addline(buffer, "vec4 IN[%lu];\n", GL_LIMITS(glsl_varyings) / 4); + } } /* Declare output register temporaries */ - for (i = 0; i < This->baseShader.limits.packed_output; i++) { - if (reg_maps->packed_output[i]) - shader_addline(buffer, "vec4 OUT%lu;\n", i); + if(This->baseShader.limits.packed_output) { + shader_addline(buffer, "vec4 OUT[%lu];\n", This->baseShader.limits.packed_output); } /* Declare temporary variables */ @@ -495,18 +630,21 @@ void shader_generate_glsl_declarations( shader_addline(buffer, "attribute vec4 attrib%i;\n", i); } - /* Declare loop register aL */ - if (reg_maps->loop) { - shader_addline(buffer, "int aL;\n"); - shader_addline(buffer, "int tmpInt;\n"); + /* Declare loop registers aLx */ + for (i = 0; i < reg_maps->loop_depth; i++) { + shader_addline(buffer, "int aL%u;\n", i); + shader_addline(buffer, "int tmpInt%u;\n", i); } - + /* Temporary variables for matrix operations */ shader_addline(buffer, "vec4 tmp0;\n"); shader_addline(buffer, "vec4 tmp1;\n"); /* Start the main program */ shader_addline(buffer, "void main() {\n"); + if(pshader && reg_maps->vpos) { + shader_addline(buffer, "vpos = vec4(0, ycorrection[0], 0, 0) + gl_FragCoord * vec4(1, ycorrection[1], 1, 1) - 0.5;\n"); + } } /***************************************************************************** @@ -626,9 +764,25 @@ static void shader_glsl_get_register_name( case WINED3DSPR_INPUT: if (pshader) { /* Pixel shaders >= 3.0 */ - if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) - sprintf(tmpStr, "IN%u", reg); - else { + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) { + if (param & WINED3DSHADER_ADDRMODE_RELATIVE) { + glsl_src_param_t rel_param; + shader_glsl_add_src_param(arg, addr_token, 0, WINED3DSP_WRITEMASK_0, &rel_param); + + /* Removing a + 0 would be an obvious optimization, but macos doesn't see the NOP + * operation there + */ + if(((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]) { + sprintf(tmpStr, "IN[%s + %u]", rel_param.param_str, + ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]); + } else { + sprintf(tmpStr, "IN[%s]", rel_param.param_str); + } + } else { + sprintf(tmpStr, "IN[%u]", + ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]); + } + } else { if (reg==0) strcpy(tmpStr, "gl_Color"); else @@ -652,9 +806,18 @@ static void shader_glsl_get_register_name( if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2) { glsl_src_param_t rel_param; shader_glsl_add_src_param(arg, addr_token, 0, WINED3DSP_WRITEMASK_0, &rel_param); - sprintf(tmpStr, "%s[%s + %u]", prefix, rel_param.param_str, reg); - } else - sprintf(tmpStr, "%s[A0.x + %u]", prefix, reg); + if(reg) { + sprintf(tmpStr, "%s[%s + %u]", prefix, rel_param.param_str, reg); + } else { + sprintf(tmpStr, "%s[%s]", prefix, rel_param.param_str); + } + } else { + if(reg) { + sprintf(tmpStr, "%s[A0.x + %u]", prefix, reg); + } else { + sprintf(tmpStr, "%s[A0.x]", prefix); + } + } } else sprintf(tmpStr, "%s[%u]", prefix, reg); @@ -681,7 +844,7 @@ static void shader_glsl_get_register_name( } break; case WINED3DSPR_LOOP: - sprintf(tmpStr, "aL"); + sprintf(tmpStr, "aL%u", This->baseShader.cur_loop_regno - 1); break; case WINED3DSPR_SAMPLER: if (pshader) @@ -715,18 +878,20 @@ static void shader_glsl_get_register_name( case WINED3DSPR_TEXCRDOUT: /* Vertex shaders >= 3.0: WINED3DSPR_OUTPUT */ if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) - sprintf(tmpStr, "OUT%u", reg); + sprintf(tmpStr, "OUT[%u]", reg); else sprintf(tmpStr, "gl_TexCoord[%u]", reg); break; case WINED3DSPR_MISCTYPE: if (reg == 0) { /* vPos */ - sprintf(tmpStr, "gl_FragCoord"); + sprintf(tmpStr, "vpos"); + } else if (reg == 1){ + /* Note that gl_FrontFacing is a bool, while vFace is + * a float for which the sign determines front/back + */ + sprintf(tmpStr, "(gl_FrontFacing ? 1.0 : -1.0)"); } else { - /* gl_FrontFacing could be used for vFace, but note that - * gl_FrontFacing is a bool, while vFace is a float for - * which the sign determines front/back */ FIXME("Unhandled misctype register %d\n", reg); sprintf(tmpStr, "unrecognized_register"); } @@ -911,6 +1076,165 @@ static void shader_glsl_get_sample_function(DWORD sampler_type, BOOL projected, } } +static void shader_glsl_color_correction(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) shader->baseShader.device; + WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info; + glsl_dst_param_t dst_param; + glsl_dst_param_t dst_param2; + WINED3DFORMAT fmt; + WINED3DFORMAT conversion_group; + IWineD3DBaseTextureImpl *texture; + DWORD mask, mask_size; + UINT i; + BOOL recorded = FALSE; + DWORD sampler_idx; + DWORD hex_version = shader->baseShader.hex_version; + + switch(arg->opcode->opcode) { + case WINED3DSIO_TEX: + if (hex_version < WINED3DPS_VERSION(2,0)) { + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + } else { + sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK; + } + break; + + case WINED3DSIO_TEXLDL: + FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n"); + return; + + case WINED3DSIO_TEXDP3TEX: + case WINED3DSIO_TEXM3x3TEX: + case WINED3DSIO_TEXM3x3SPEC: + case WINED3DSIO_TEXM3x3VSPEC: + case WINED3DSIO_TEXBEM: + case WINED3DSIO_TEXREG2AR: + case WINED3DSIO_TEXREG2GB: + case WINED3DSIO_TEXREG2RGB: + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + break; + + default: + /* Not a texture sampling instruction, nothing to do */ + return; + }; + + texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx]; + if(texture) { + fmt = texture->resource.format; + conversion_group = texture->baseTexture.shader_conversion_group; + } else { + fmt = WINED3DFMT_UNKNOWN; + conversion_group = WINED3DFMT_UNKNOWN; + } + + /* before doing anything, record the sampler with the format in the format conversion list, + * but check if it's not there already + */ + for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) { + if(shader->baseShader.sampled_samplers[i] == sampler_idx) { + recorded = TRUE; + break; + } + } + if(!recorded) { + shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx; + shader->baseShader.num_sampled_samplers++; + shader->baseShader.sampled_format[sampler_idx] = conversion_group; + } + + switch(fmt) { + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + if(GL_SUPPORT(NV_TEXTURE_SHADER) || + (GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && fmt == WINED3DFMT_V8U8)) { + /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. Fix this while we're at it :-) */ + mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_2, &dst_param); + mask_size = shader_glsl_get_write_mask_size(mask); + if(mask_size >= 3) { + shader_addline(arg->buffer, "%s.%c = 1.0;\n", dst_param.reg_name, dst_param.mask_str[3]); + } + } else { + /* Correct the sign, but leave the blue as it is - it was loaded correctly already */ + mask = shader_glsl_add_dst_param(arg, arg->dst, + WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, + &dst_param); + mask_size = shader_glsl_get_write_mask_size(mask); + if(mask_size >= 2) { + shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n", + dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2], + dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2]); + } else if(mask_size == 1) { + shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n", dst_param.reg_name, dst_param.mask_str[1], + dst_param.reg_name, dst_param.mask_str[1]); + } + } + break; + + case WINED3DFMT_X8L8V8U8: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* Red and blue are the signed channels, fix them up; Blue(=L) is correct already, + * and a(X) is always 1.0 + */ + mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param); + mask_size = shader_glsl_get_write_mask_size(mask); + if(mask_size >= 2) { + shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n", + dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2], + dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2]); + } else if(mask_size == 1) { + shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n", + dst_param.reg_name, dst_param.mask_str[1], + dst_param.reg_name, dst_param.mask_str[1]); + } + } + break; + + case WINED3DFMT_L6V5U5: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param); + mask_size = shader_glsl_get_write_mask_size(mask); + shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_2, &dst_param2); + if(mask_size >= 3) { + /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */ + shader_addline(arg->buffer, "tmp0.g = %s.%c;\n", + dst_param.reg_name, dst_param.mask_str[2]); + shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n", + dst_param.reg_name, dst_param.mask_str[2], dst_param.mask_str[1], + dst_param2.reg_name, dst_param.mask_str[1], dst_param.mask_str[3]); + shader_addline(arg->buffer, "%s.%c = tmp0.g;\n", dst_param.reg_name, + dst_param.mask_str[3]); + } else if(mask_size == 2) { + /* This is bad: We have VL, but we need VU */ + FIXME("2 components sampled from a converted L6V5U5 texture\n"); + } else { + shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n", + dst_param.reg_name, dst_param.mask_str[1], + dst_param2.reg_name, dst_param.mask_str[1]); + } + } + break; + + case WINED3DFMT_Q8W8V8U8: + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* Correct the sign in all channels. The writemask just applies as-is, no + * need for checking the mask size + */ + shader_glsl_add_dst_param(arg, arg->dst, + WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | + WINED3DSP_WRITEMASK_2 | WINED3DSP_WRITEMASK_3, + &dst_param); + shader_addline(arg->buffer, "%s%s = %s%s * 2.0 - 1.0;\n", dst_param.reg_name, dst_param.mask_str, + dst_param.reg_name, dst_param.mask_str); + } + break; + + /* stupid compiler */ + default: + break; + } +} /***************************************************************************** * @@ -1013,7 +1337,7 @@ void shader_glsl_cross(SHADER_OPCODE_ARG *arg) { shader_glsl_append_dst(arg->buffer, arg); shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_mask, &src1_param); - shader_addline(arg->buffer, "cross(%s, %s).%s);\n", src0_param.param_str, src1_param.param_str, dst_mask); + shader_addline(arg->buffer, "cross(%s, %s)%s);\n", src0_param.param_str, src1_param.param_str, dst_mask); } /* Process the WINED3DSIO_POW instruction in GLSL (dst = |src0|^src1) @@ -1039,6 +1363,27 @@ void shader_glsl_pow(SHADER_OPCODE_ARG *arg) { } } +/* Process the WINED3DSIO_LOG instruction in GLSL (dst = log2(|src0|)) + * Src0 is a scalar. Note that D3D uses the absolute of src0, while + * GLSL uses the value as-is. */ +void shader_glsl_log(SHADER_OPCODE_ARG *arg) { + SHADER_BUFFER *buffer = arg->buffer; + glsl_src_param_t src0_param; + DWORD dst_write_mask; + size_t dst_size; + + dst_write_mask = shader_glsl_append_dst(buffer, arg); + dst_size = shader_glsl_get_write_mask_size(dst_write_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + + if (dst_size > 1) { + shader_addline(buffer, "vec%d(log2(abs(%s))));\n", dst_size, src0_param.param_str); + } else { + shader_addline(buffer, "log2(abs(%s)));\n", src0_param.param_str); + } +} + /* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */ void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg) { CONST SHADER_OPCODE* curOpcode = arg->opcode; @@ -1062,7 +1407,7 @@ void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg) { case WINED3DSIO_EXP: instruction = "exp2"; break; case WINED3DSIO_SGN: instruction = "sign"; break; case WINED3DSIO_DSX: instruction = "dFdx"; break; - case WINED3DSIO_DSY: instruction = "dFdy"; break; + case WINED3DSIO_DSY: instruction = "ycorrection.y * dFdy"; break; default: instruction = ""; FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name); break; @@ -1185,17 +1530,17 @@ void shader_glsl_compare(SHADER_OPCODE_ARG* arg) { shader_addline(arg->buffer, "vec%d(%s(%s, %s)));\n", mask_size, compare, src0_param.param_str, src1_param.param_str); } else { - const char *compare; - switch(arg->opcode->opcode) { - case WINED3DSIO_SLT: compare = "<"; break; - case WINED3DSIO_SGE: compare = ">="; break; - default: compare = ""; + case WINED3DSIO_SLT: + shader_addline(arg->buffer, "step(%s, %s));\n", src0_param.param_str, src1_param.param_str); + break; + case WINED3DSIO_SGE: + shader_addline(arg->buffer, "step(%s, %s));\n", src1_param.param_str, src0_param.param_str); + break; + default: FIXME("Can't handle opcode %s\n", arg->opcode->name); } - shader_addline(arg->buffer, "(%s %s %s) ? 1.0 : 0.0);\n", - src0_param.param_str, compare, src1_param.param_str); } } @@ -1206,6 +1551,17 @@ void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) { glsl_src_param_t src2_param; DWORD write_mask, cmp_channel = 0; unsigned int i, j; + char mask_char[6]; + BOOL temp_destination = FALSE; + + DWORD src0reg = arg->src[0] & WINED3DSP_REGNUM_MASK; + DWORD src1reg = arg->src[1] & WINED3DSP_REGNUM_MASK; + DWORD src2reg = arg->src[2] & WINED3DSP_REGNUM_MASK; + DWORD src0regtype = shader_get_regtype(arg->src[0]); + DWORD src1regtype = shader_get_regtype(arg->src[1]); + DWORD src2regtype = shader_get_regtype(arg->src[2]); + DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD dstregtype = shader_get_regtype(arg->dst); /* Cycle through all source0 channels */ for (i=0; i<4; i++) { @@ -1217,16 +1573,38 @@ void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) { cmp_channel = WINED3DSP_WRITEMASK_0 << j; } } - write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); - if (!write_mask) continue; + + /* Splitting the cmp instruction up in multiple lines imposes a problem: + * The first lines may overwrite source parameters of the following lines. + * Deal with that by using a temporary destination register if needed + */ + if((src0reg == dstreg && src0regtype == dstregtype) || + (src1reg == dstreg && src1regtype == dstregtype) || + (src2reg == dstreg && src2regtype == dstregtype)) { + + write_mask = shader_glsl_get_write_mask(arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask), mask_char); + if (!write_mask) continue; + shader_addline(arg->buffer, "tmp0%s = (", mask_char); + temp_destination = TRUE; + } else { + write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); + if (!write_mask) continue; + } shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param); shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); - shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n", - src0_param.param_str, src1_param.param_str, src2_param.param_str); + shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); } + + if(temp_destination) { + shader_glsl_get_write_mask(arg->dst, mask_char); + shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst); + shader_addline(arg->buffer, "tmp0%s);\n", mask_char); + } + } /** Process the CND opcode in GLSL (dst = (src0 > 0.5) ? src1 : src2) */ @@ -1245,8 +1623,14 @@ void shader_glsl_cnd(SHADER_OPCODE_ARG* arg) { shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); - shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", - src0_param.param_str, src1_param.param_str, src2_param.param_str); + + /* Fun: The D3DSI_COISSUE flag changes the semantic of the cnd instruction for < 1.4 shaders */ + if(arg->opcode_token & WINED3DSI_COISSUE) { + shader_addline(arg->buffer, "%s /* COISSUE! */);\n", src1_param.param_str); + } else { + shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); + } return; } /* Cycle through all source0 channels */ @@ -1376,8 +1760,29 @@ void shader_glsl_lit(SHADER_OPCODE_ARG* arg) { shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_1, &src1_param); shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src3_param); - shader_addline(arg->buffer, "vec4(1.0, (%s > 0.0 ? %s : 0.0), (%s > 0.0 ? ((%s > 0.0) ? pow(%s, clamp(%s, -128.0, 128.0)) : 0.0) : 0.0), 1.0)%s);\n", - src0_param.param_str, src0_param.param_str, src0_param.param_str, src1_param.param_str, src1_param.param_str, src3_param.param_str, dst_mask); + /* The sdk specifies the instruction like this + * dst.x = 1.0; + * if(src.x > 0.0) dst.y = src.x + * else dst.y = 0.0. + * if(src.x > 0.0 && src.y > 0.0) dst.z = pow(src.y, power); + * else dst.z = 0.0; + * dst.w = 1.0; + * + * Obviously that has quite a few conditionals in it which we don't like. So the first step is this: + * dst.x = 1.0 ... No further explanation needed + * dst.y = max(src.y, 0.0); ... If x < 0.0, use 0.0, otherwise x. Same as the conditional + * dst.z = x > 0.0 ? pow(max(y, 0.0), p) : 0; ... 0 ^ power is 0, and otherwise we use y anyway + * dst.w = 1.0. ... Nothing fancy. + * + * So we still have one conditional in there. So do this: + * dst.z = pow(max(0.0, src.y) * step(0.0, src.x), power); + * + * step(0.0, x) will return 1 if src.x > 0.0, and 0 otherwise. So if y is 0 we get pow(0.0 * 1.0, power), + * which sets dst.z to 0. If y > 0, but x = 0.0, we get pow(y * 0.0, power), which results in 0 too. + * if both x and y are > 0, we get pow(y * 1.0, power), as it is supposed to + */ + shader_addline(arg->buffer, "vec4(1.0, max(%s, 0.0), pow(max(0.0, %s) * step(0.0, %s), clamp(%s, -128.0, 128.0)), 1.0)%s);\n", + src0_param.param_str, src1_param.param_str, src0_param.param_str, src3_param.param_str, dst_mask); } /** Process the WINED3DSIO_DST instruction in GLSL: @@ -1448,22 +1853,79 @@ void shader_glsl_sincos(SHADER_OPCODE_ARG* arg) { /* FIXME: I don't think nested loops will work correctly this way. */ void shader_glsl_loop(SHADER_OPCODE_ARG* arg) { glsl_src_param_t src1_param; + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + DWORD regtype = shader_get_regtype(arg->src[1]); + DWORD reg = arg->src[1] & WINED3DSP_REGNUM_MASK; + const DWORD *control_values = NULL; + local_constant *constant; shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_ALL, &src1_param); - - shader_addline(arg->buffer, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n", - src1_param.reg_name, src1_param.reg_name, src1_param.reg_name); + + /* Try to hardcode the loop control parameters if possible. Direct3D 9 class hardware doesn't support real + * varying indexing, but Microsoft designed this feature for Shader model 2.x+. If the loop control is + * known at compile time, the GLSL compiler can unroll the loop, and replace indirect addressing with direct + * addressing. + */ + if(regtype == WINED3DSPR_CONSTINT) { + LIST_FOR_EACH_ENTRY(constant, &shader->baseShader.constantsI, local_constant, entry) { + if(constant->idx == reg) { + control_values = constant->value; + break; + } + } + } + + if(control_values) { + if(control_values[2] > 0) { + shader_addline(arg->buffer, "for (aL%u = %d; aL%u < (%d * %d + %d); aL%u += %d) {\n", + shader->baseShader.cur_loop_depth, control_values[1], + shader->baseShader.cur_loop_depth, control_values[0], control_values[2], control_values[1], + shader->baseShader.cur_loop_depth, control_values[2]); + } else if(control_values[2] == 0) { + shader_addline(arg->buffer, "for (aL%u = %d, tmpInt%u = 0; tmpInt%u < %d; tmpInt%u++) {\n", + shader->baseShader.cur_loop_depth, control_values[1], shader->baseShader.cur_loop_depth, + shader->baseShader.cur_loop_depth, control_values[0], + shader->baseShader.cur_loop_depth); + } else { + shader_addline(arg->buffer, "for (aL%u = %d; aL%u > (%d * %d + %d); aL%u += %d) {\n", + shader->baseShader.cur_loop_depth, control_values[1], + shader->baseShader.cur_loop_depth, control_values[0], control_values[2], control_values[1], + shader->baseShader.cur_loop_depth, control_values[2]); + } + } else { + shader_addline(arg->buffer, "for (tmpInt%u = 0, aL%u = %s.y; tmpInt%u < %s.x; tmpInt%u++, aL%u += %s.z) {\n", + shader->baseShader.cur_loop_depth, shader->baseShader.cur_loop_regno, + src1_param.reg_name, shader->baseShader.cur_loop_depth, src1_param.reg_name, + shader->baseShader.cur_loop_depth, shader->baseShader.cur_loop_regno, src1_param.reg_name); + } + + shader->baseShader.cur_loop_depth++; + shader->baseShader.cur_loop_regno++; } void shader_glsl_end(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + shader_addline(arg->buffer, "}\n"); + + if(arg->opcode->opcode == WINED3DSIO_ENDLOOP) { + shader->baseShader.cur_loop_depth--; + shader->baseShader.cur_loop_regno--; + } + if(arg->opcode->opcode == WINED3DSIO_ENDREP) { + shader->baseShader.cur_loop_depth--; + } } void shader_glsl_rep(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; glsl_src_param_t src0_param; shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); - shader_addline(arg->buffer, "for (tmpInt = 0; tmpInt < %s; tmpInt++) {\n", src0_param.param_str); + shader_addline(arg->buffer, "for (tmpInt%d = 0; tmpInt%d < %s; tmpInt%d++) {\n", + shader->baseShader.cur_loop_depth, shader->baseShader.cur_loop_depth, + src0_param.param_str, shader->baseShader.cur_loop_depth); + shader->baseShader.cur_loop_depth++; } void shader_glsl_if(SHADER_OPCODE_ARG* arg) { @@ -1529,6 +1991,7 @@ void shader_glsl_callnz(SHADER_OPCODE_ARG* arg) { ********************************************/ void pshader_glsl_tex(SHADER_OPCODE_ARG* arg) { IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; DWORD hex_version = This->baseShader.hex_version; char dst_swizzle[6]; glsl_sample_function_t sample_function; @@ -1543,7 +2006,6 @@ void pshader_glsl_tex(SHADER_OPCODE_ARG* arg) { /* 1.0-1.4: Use destination register as sampler source. * 2.0+: Use provided sampler source. */ if (hex_version < WINED3DPS_VERSION(1,4)) { - IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; DWORD flags; sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; @@ -1605,8 +2067,17 @@ void pshader_glsl_tex(SHADER_OPCODE_ARG* arg) { } else { glsl_src_param_t coord_param; shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], mask, &coord_param); - shader_addline(arg->buffer, "%s(Psampler%u, %s)%s);\n", - sample_function.name, sampler_idx, coord_param.param_str, dst_swizzle); + if(arg->opcode_token & WINED3DSI_TEXLD_BIAS) { + glsl_src_param_t bias; + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &bias); + + shader_addline(arg->buffer, "%s(Psampler%u, %s, %s)%s);\n", + sample_function.name, sampler_idx, coord_param.param_str, + bias.param_str, dst_swizzle); + } else { + shader_addline(arg->buffer, "%s(Psampler%u, %s)%s);\n", + sample_function.name, sampler_idx, coord_param.param_str, dst_swizzle); + } } } @@ -1695,15 +2166,39 @@ void pshader_glsl_texcoord(SHADER_OPCODE_ARG* arg) { void pshader_glsl_texdp3tex(SHADER_OPCODE_ARG* arg) { glsl_src_param_t src0_param; char dst_mask[6]; + glsl_sample_function_t sample_function; DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); shader_glsl_append_dst(arg->buffer, arg); shader_glsl_get_write_mask(arg->dst, dst_mask); - shader_addline(arg->buffer, "texture2D(Psampler%u, vec2(dot(gl_TexCoord[%u].xyz, %s), 0.5))%s);\n", - sampler_idx, sampler_idx, src0_param.param_str, dst_mask); + + /* Do I have to take care about the projected bit? I don't think so, since the dp3 returns only one + * scalar, and projected sampling would require 4 + */ + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + + switch(count_bits(sample_function.coord_mask)) { + case 1: + shader_addline(arg->buffer, "%s(Psampler%u, dot(gl_TexCoord[%u].xyz, %s))%s);\n", + sample_function.name, sampler_idx, sampler_idx, src0_param.param_str, dst_mask); + break; + + case 2: + shader_addline(arg->buffer, "%s(Psampler%u, vec2(dot(gl_TexCoord[%u].xyz, %s), 0.0))%s);\n", + sample_function.name, sampler_idx, sampler_idx, src0_param.param_str, dst_mask); + break; + + case 3: + shader_addline(arg->buffer, "%s(Psampler%u, vec3(dot(gl_TexCoord[%u].xyz, %s), 0.0, 0.0))%s);\n", + sample_function.name, sampler_idx, sampler_idx, src0_param.param_str, dst_mask); + break; + default: + FIXME("Unexpected mask bitcount %d\n", count_bits(sample_function.coord_mask)); + } } /** Process the WINED3DSIO_TEXDP3 instruction in GLSL: @@ -1733,7 +2228,13 @@ void pshader_glsl_texdepth(SHADER_OPCODE_ARG* arg) { shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); - shader_addline(arg->buffer, "gl_FragDepth = %s.x / %s.y;\n", dst_param.reg_name, dst_param.reg_name); + /* Tests show that texdepth never returns anything below 0.0, and that r5.y is clamped to 1.0. + * Negative input is accepted, -0.25 / -0.5 returns 0.5. GL should clamp gl_FragDepth to [0;1], but + * this doesn't always work, so clamp the results manually. Whether or not the x value is clamped at 1 + * too is irrelevant, since if x = 0, any y value < 1.0 (and > 1.0 is not allowed) results in a result + * >= 1.0 or < 0.0 + */ + shader_addline(arg->buffer, "gl_FragDepth = clamp((%s.x / min(%s.y, 1.0)), 0.0, 1.0);\n", dst_param.reg_name, dst_param.reg_name, dst_param.reg_name); } /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in GLSL: @@ -1836,7 +2337,7 @@ void pshader_glsl_texm3x3(SHADER_OPCODE_ARG* arg) { shader_glsl_append_dst(arg->buffer, arg); shader_glsl_get_write_mask(arg->dst, dst_mask); - shader_addline(arg->buffer, "vec4(tmp.xy, dot(T%u.xyz, %s), 1.0)%s);\n", reg, src0_param.param_str, dst_mask); + shader_addline(arg->buffer, "vec4(tmp0.xy, dot(T%u.xyz, %s), 1.0)%s);\n", reg, src0_param.param_str, dst_mask); current_state->current_row = 0; } @@ -1861,10 +2362,8 @@ void pshader_glsl_texm3x3spec(SHADER_OPCODE_ARG* arg) { /* Perform the last matrix multiply operation */ shader_addline(buffer, "tmp0.z = dot(T%u.xyz, %s);\n", reg, src0_param.param_str); - - /* Calculate reflection vector, 2*(tmp0.src1)*tmp0-src1 - * This is equivalent to reflect(-src1, tmp0); */ - shader_addline(buffer, "tmp0.xyz = reflect(-(%s), tmp0.xyz);\n", src1_param.param_str); + /* Reflection calculation */ + shader_addline(buffer, "tmp0.xyz = -reflect((%s), normalize(tmp0.xyz));\n", src1_param.param_str); shader_glsl_append_dst(buffer, arg); shader_glsl_get_write_mask(arg->dst, dst_mask); @@ -1898,10 +2397,7 @@ void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG* arg) { /* Construct the eye-ray vector from w coordinates */ shader_addline(buffer, "tmp1.xyz = normalize(vec3(gl_TexCoord[%u].w, gl_TexCoord[%u].w, gl_TexCoord[%u].w));\n", current_state->texcoord_w[0], current_state->texcoord_w[1], reg); - - /* Calculate reflection vector (Assume normal is normalized): RF = 2*(tmp0.tmp1)*tmp0-tmp1 - * This is equivalent to reflect(-tmp1, tmp0); */ - shader_addline(buffer, "tmp0.xyz = reflect(-tmp1.xyz, tmp0.xyz);\n"); + shader_addline(buffer, "tmp0.xyz = -reflect(tmp1.xyz, normalize(tmp0.xyz));\n"); shader_glsl_append_dst(buffer, arg); shader_glsl_get_write_mask(arg->dst, dst_mask); @@ -1959,8 +2455,16 @@ void pshader_glsl_texbem(SHADER_OPCODE_ARG* arg) { shader_glsl_append_dst(arg->buffer, arg); shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0|WINED3DSP_WRITEMASK_1, &coord_param); - shader_addline(arg->buffer, "%s(Psampler%u, T%u%s + vec4(bumpenvmat * %s, 0.0, 0.0)%s )%s);\n", - sample_function.name, sampler_idx, sampler_idx, coord_mask, coord_param.param_str, coord_mask, dst_swizzle); + if(arg->opcode->opcode == WINED3DSIO_TEXBEML) { + glsl_src_param_t luminance_param; + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_2, &luminance_param); + shader_addline(arg->buffer, "(%s(Psampler%u, T%u%s + vec4(bumpenvmat * %s, 0.0, 0.0)%s )*(%s * luminancescale + luminanceoffset))%s);\n", + sample_function.name, sampler_idx, sampler_idx, coord_mask, coord_param.param_str, coord_mask, + luminance_param.param_str, dst_swizzle); + } else { + shader_addline(arg->buffer, "%s(Psampler%u, T%u%s + vec4(bumpenvmat * %s, 0.0, 0.0)%s )%s);\n", + sample_function.name, sampler_idx, sampler_idx, coord_mask, coord_param.param_str, coord_mask, dst_swizzle); + } } void pshader_glsl_bem(SHADER_OPCODE_ARG* arg) { @@ -1977,6 +2481,7 @@ void pshader_glsl_bem(SHADER_OPCODE_ARG* arg) { /** Process the WINED3DSIO_TEXREG2AR instruction in GLSL * Sample 2D texture at dst using the alpha & red (wx) components of src as texture coordinates */ void pshader_glsl_texreg2ar(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; char dst_mask[6]; @@ -2022,10 +2527,22 @@ void pshader_glsl_texreg2rgb(SHADER_OPCODE_ARG* arg) { /** Process the WINED3DSIO_TEXKILL instruction in GLSL. * If any of the first 3 components are < 0, discard this pixel */ void pshader_glsl_texkill(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD hex_version = This->baseShader.hex_version; glsl_dst_param_t dst_param; + /* The argument is a destination parameter, and no writemasks are allowed */ shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); - shader_addline(arg->buffer, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_param.reg_name); + if((hex_version >= WINED3DPS_VERSION(2,0))) { + /* 2.0 shaders compare all 4 components in texkill */ + shader_addline(arg->buffer, "if (any(lessThan(%s.xyzw, vec4(0.0)))) discard;\n", dst_param.reg_name); + } else { + /* 1.X shaders only compare the first 3 components, probably due to the nature of the texkill + * instruction as a tex* instruction, and phase, which kills all a / w components. Even if all + * 4 components are defined, only the first 3 are used + */ + shader_addline(arg->buffer, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_param.reg_name); + } } /** Process the WINED3DSIO_DP2ADD instruction in GLSL. @@ -2049,9 +2566,11 @@ void pshader_glsl_dp2add(SHADER_OPCODE_ARG* arg) { void pshader_glsl_input_pack( SHADER_BUFFER* buffer, - semantic* semantics_in) { + semantic* semantics_in, + IWineD3DPixelShader *iface) { unsigned int i; + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *) iface; for (i = 0; i < MAX_REG_INPUT; i++) { @@ -2068,31 +2587,31 @@ void pshader_glsl_input_pack( switch(usage) { + case WINED3DDECLUSAGE_TEXCOORD: + if(usage_idx < 8 && This->vertexprocessing == pretransformed) { + shader_addline(buffer, "IN[%u]%s = gl_TexCoord[%u]%s;\n", + This->input_reg_map[i], reg_mask, usage_idx, reg_mask); + } else { + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + This->input_reg_map[i], reg_mask, reg_mask); + } + break; + case WINED3DDECLUSAGE_COLOR: if (usage_idx == 0) - shader_addline(buffer, "IN%u%s = vec4(gl_Color)%s;\n", - i, reg_mask, reg_mask); + shader_addline(buffer, "IN[%u]%s = vec4(gl_Color)%s;\n", + This->input_reg_map[i], reg_mask, reg_mask); else if (usage_idx == 1) - shader_addline(buffer, "IN%u%s = vec4(gl_SecondaryColor)%s;\n", - i, reg_mask, reg_mask); + shader_addline(buffer, "IN[%u]%s = vec4(gl_SecondaryColor)%s;\n", + This->input_reg_map[i], reg_mask, reg_mask); else - shader_addline(buffer, "IN%u%s = vec4(unsupported_color_input)%s;\n", - i, reg_mask, reg_mask); - break; - - case WINED3DDECLUSAGE_TEXCOORD: - shader_addline(buffer, "IN%u%s = vec4(gl_TexCoord[%u])%s;\n", - i, reg_mask, usage_idx, reg_mask ); - break; - - case WINED3DDECLUSAGE_FOG: - shader_addline(buffer, "IN%u%s = vec4(gl_FogFragCoord)%s;\n", - i, reg_mask, reg_mask); + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + This->input_reg_map[i], reg_mask, reg_mask); break; default: - shader_addline(buffer, "IN%u%s = vec4(unsupported_input)%s;\n", - i, reg_mask, reg_mask); + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + This->input_reg_map[i], reg_mask, reg_mask); } } } @@ -2101,60 +2620,6 @@ void pshader_glsl_input_pack( * Vertex Shader Specific Code begins here ********************************************/ -void vshader_glsl_output_unpack( - SHADER_BUFFER* buffer, - semantic* semantics_out) { - - unsigned int i; - - for (i = 0; i < MAX_REG_OUTPUT; i++) { - - DWORD usage_token = semantics_out[i].usage; - DWORD register_token = semantics_out[i].reg; - DWORD usage, usage_idx; - char reg_mask[6]; - - /* Uninitialized */ - if (!usage_token) continue; - - usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; - usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; - shader_glsl_get_write_mask(register_token, reg_mask); - - switch(usage) { - - case WINED3DDECLUSAGE_COLOR: - if (usage_idx == 0) - shader_addline(buffer, "gl_FrontColor%s = OUT%u%s;\n", reg_mask, i, reg_mask); - else if (usage_idx == 1) - shader_addline(buffer, "gl_FrontSecondaryColor%s = OUT%u%s;\n", reg_mask, i, reg_mask); - else - shader_addline(buffer, "unsupported_color_output%s = OUT%u%s;\n", reg_mask, i, reg_mask); - break; - - case WINED3DDECLUSAGE_POSITION: - shader_addline(buffer, "gl_Position%s = OUT%u%s;\n", reg_mask, i, reg_mask); - break; - - case WINED3DDECLUSAGE_TEXCOORD: - shader_addline(buffer, "gl_TexCoord[%u]%s = OUT%u%s;\n", - usage_idx, reg_mask, i, reg_mask); - break; - - case WINED3DDECLUSAGE_PSIZE: - shader_addline(buffer, "gl_PointSize = OUT%u.x;\n", i); - break; - - case WINED3DDECLUSAGE_FOG: - shader_addline(buffer, "gl_FogFragCoord = OUT%u%s;\n", i, reg_mask); - break; - - default: - shader_addline(buffer, "unsupported_output%s = OUT%u%s;\n", reg_mask, i, reg_mask); - } - } -} - static void add_glsl_program_entry(IWineD3DDeviceImpl *device, struct glsl_shader_prog_link *entry) { glsl_program_key_t *key; @@ -2193,6 +2658,267 @@ void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_li HeapFree(GetProcessHeap(), 0, entry); } +static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, semantic *semantics_out, WineD3D_GL_Info *gl_info, DWORD *map) { + unsigned int i, j; + DWORD usage_token, usage_token_out; + DWORD register_token, register_token_out; + DWORD usage, usage_idx, usage_out, usage_idx_out; + DWORD *set; + char reg_mask[6], reg_mask_out[6]; + + set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (GL_LIMITS(glsl_varyings) / 4)); + + for(i = 0; i < MAX_REG_INPUT; i++) { + usage_token = semantics_in[i].usage; + if (!usage_token) continue; + if(map[i] >= (GL_LIMITS(glsl_varyings) / 4)) { + FIXME("More input varyings declared than supported, expect issues\n"); + continue; + } else if(map[i] == -1) { + /* Declared, but not read register */ + continue; + } + register_token = semantics_in[i].reg; + + usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + set[map[i]] = shader_glsl_get_write_mask(register_token, reg_mask); + + if(!semantics_out) { + switch(usage) { + case WINED3DDECLUSAGE_COLOR: + if (usage_idx == 0) + shader_addline(buffer, "IN[%u]%s = gl_FrontColor%s;\n", + map[i], reg_mask, reg_mask); + else if (usage_idx == 1) + shader_addline(buffer, "IN[%u]%s = gl_FrontSecondaryColor%s;\n", + map[i], reg_mask, reg_mask); + else + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + map[i], reg_mask, reg_mask); + break; + + case WINED3DDECLUSAGE_TEXCOORD: + if (usage_idx < 8) { + shader_addline(buffer, "IN[%u]%s = gl_TexCoord[%u]%s;\n", + map[i], reg_mask, usage_idx, reg_mask); + } else { + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + map[i], reg_mask, reg_mask); + } + break; + + case WINED3DDECLUSAGE_FOG: + shader_addline(buffer, "IN[%u]%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n", + map[i], reg_mask, reg_mask); + break; + + default: + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + map[i], reg_mask, reg_mask); + } + } else { + BOOL found = FALSE; + for(j = 0; j < MAX_REG_OUTPUT; j++) { + usage_token_out = semantics_out[j].usage; + if (!usage_token_out) continue; + register_token_out = semantics_out[j].reg; + + usage_out = (usage_token_out & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx_out = (usage_token_out & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + shader_glsl_get_write_mask(register_token_out, reg_mask_out); + + if(usage == usage_out && + usage_idx == usage_idx_out) { + shader_addline(buffer, "IN[%u]%s = OUT[%u]%s;\n", + map[i], reg_mask, j, reg_mask); + found = TRUE; + } + } + if(!found) { + shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", + map[i], reg_mask, reg_mask); + } + } + } + + /* This is solely to make the compiler / linker happy and avoid warning about undefined + * varyings. It shouldn't result in any real code executed on the GPU, since all read + * input varyings are assigned above, if the optimizer works properly. + */ + for(i = 0; i < GL_LIMITS(glsl_varyings) / 4; i++) { + if(set[i] != WINED3DSP_WRITEMASK_ALL) { + unsigned int size = 0; + memset(reg_mask, 0, sizeof(reg_mask)); + if(!(set[i] & WINED3DSP_WRITEMASK_0)) { + reg_mask[size] = 'x'; + size++; + } + if(!(set[i] & WINED3DSP_WRITEMASK_1)) { + reg_mask[size] = 'y'; + size++; + } + if(!(set[i] & WINED3DSP_WRITEMASK_2)) { + reg_mask[size] = 'z'; + size++; + } + if(!(set[i] & WINED3DSP_WRITEMASK_3)) { + reg_mask[size] = 'w'; + size++; + } + switch(size) { + case 1: + shader_addline(buffer, "IN[%u].%s = 0.0;\n", i, reg_mask); + break; + case 2: + shader_addline(buffer, "IN[%u].%s = vec2(0.0, 0.0);\n", i, reg_mask); + break; + case 3: + shader_addline(buffer, "IN[%u].%s = vec3(0.0, 0.0, 0.0);\n", i, reg_mask); + break; + case 4: + shader_addline(buffer, "IN[%u].%s = vec4(0.0, 0.0, 0.0, 0.0);\n", i, reg_mask); + break; + } + } + } + + HeapFree(GetProcessHeap(), 0, set); +} + +static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexshader, + IWineD3DPixelShader *pixelshader, + WineD3D_GL_Info *gl_info) { + GLhandleARB ret = 0; + IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader; + IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader; + DWORD vs_major = vs ? WINED3DSHADER_VERSION_MAJOR(vs->baseShader.hex_version) : 0; + DWORD ps_major = ps ? WINED3DSHADER_VERSION_MAJOR(ps->baseShader.hex_version) : 0; + unsigned int i; + SHADER_BUFFER buffer; + DWORD usage_token; + DWORD register_token; + DWORD usage, usage_idx; + char reg_mask[6]; + semantic *semantics_out, *semantics_in; + + buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE); + buffer.bsize = 0; + buffer.lineNo = 0; + buffer.newline = TRUE; + + if(vs_major < 3 && ps_major < 3) { + /* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them */ + shader_addline(&buffer, "void order_ps_input() { /* do nothing */ }\n"); + } else if(ps_major < 3 && vs_major >= 3) { + /* The vertex shader writes to its own varyings, the pixel shader needs them in the builtin ones */ + semantics_out = vs->semantics_out; + + shader_addline(&buffer, "void order_ps_input(in vec4 OUT[%u]) {\n", MAX_REG_OUTPUT); + for(i = 0; i < MAX_REG_OUTPUT; i++) { + usage_token = semantics_out[i].usage; + if (!usage_token) continue; + register_token = semantics_out[i].reg; + + usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + shader_glsl_get_write_mask(register_token, reg_mask); + + switch(usage) { + case WINED3DDECLUSAGE_COLOR: + if (usage_idx == 0) + shader_addline(&buffer, "gl_FrontColor%s = OUT[%u]%s;\n", reg_mask, i, reg_mask); + else if (usage_idx == 1) + shader_addline(&buffer, "gl_FrontSecondaryColor%s = OUT[%u]%s;\n", reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_POSITION: + shader_addline(&buffer, "gl_Position%s = OUT[%u]%s;\n", reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_TEXCOORD: + if (usage_idx < 8) { + shader_addline(&buffer, "gl_TexCoord[%u]%s = OUT[%u]%s;\n", + usage_idx, reg_mask, i, reg_mask); + } + break; + + case WINED3DDECLUSAGE_PSIZE: + shader_addline(&buffer, "gl_PointSize = OUT[%u].x;\n", i); + break; + + case WINED3DDECLUSAGE_FOG: + shader_addline(&buffer, "gl_FogFragCoord = OUT[%u].%c;\n", i, reg_mask[1]); + break; + + default: + break; + } + } + shader_addline(&buffer, "}\n"); + + } else if(ps_major >= 3 && vs_major >= 3) { + semantics_out = vs->semantics_out; + semantics_in = ps->semantics_in; + + /* This one is tricky: a 3.0 pixel shader reads from a 3.0 vertex shader */ + shader_addline(&buffer, "varying vec4 IN[%lu];\n", GL_LIMITS(glsl_varyings) / 4); + shader_addline(&buffer, "void order_ps_input(in vec4 OUT[%u]) {\n", MAX_REG_OUTPUT); + + /* First, sort out position and point size. Those are not passed to the pixel shader */ + for(i = 0; i < MAX_REG_OUTPUT; i++) { + usage_token = semantics_out[i].usage; + if (!usage_token) continue; + register_token = semantics_out[i].reg; + + usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + shader_glsl_get_write_mask(register_token, reg_mask); + + switch(usage) { + case WINED3DDECLUSAGE_POSITION: + shader_addline(&buffer, "gl_Position%s = OUT[%u]%s;\n", reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_PSIZE: + shader_addline(&buffer, "gl_PointSize = OUT[%u].x;\n", i); + break; + + default: + break; + } + } + + /* Then, fix the pixel shader input */ + handle_ps3_input(&buffer, semantics_in, semantics_out, gl_info, ps->input_reg_map); + + shader_addline(&buffer, "}\n"); + } else if(ps_major >= 3 && vs_major < 3) { + semantics_in = ps->semantics_in; + + shader_addline(&buffer, "varying vec4 IN[%lu];\n", GL_LIMITS(glsl_varyings) / 4); + shader_addline(&buffer, "void order_ps_input() {\n"); + /* The vertex shader wrote to the builtin varyings. There is no need to figure out position and + * point size, but we depend on the optimizers kindness to find out that the pixel shader doesn't + * read gl_TexCoord and gl_ColorX, otherwise we'll run out of varyings + */ + handle_ps3_input(&buffer, semantics_in, NULL, gl_info, ps->input_reg_map); + shader_addline(&buffer, "}\n"); + } else { + ERR("Unexpected vertex and pixel shader version condition: vs: %d, ps: %d\n", vs_major, ps_major); + } + + ret = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)); + checkGLcall("glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)"); + GL_EXTCALL(glShaderSourceARB(ret, 1, (const char**)&buffer.buffer, NULL)); + checkGLcall("glShaderSourceARB(ret, 1, (const char**)&buffer.buffer, NULL)"); + GL_EXTCALL(glCompileShaderARB(ret)); + checkGLcall("glCompileShaderARB(ret)"); + + HeapFree(GetProcessHeap(), 0, buffer.buffer); + return ret; +} + /** Sets the GLSL program ID for the given pixel and vertex shader combination. * It sets the programId on the current StateBlock (because it should be called * inside of the DrawPrimitive() part of the render loop). @@ -2208,6 +2934,7 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use IWineD3DVertexShader *vshader = This->stateBlock->vertexShader; struct glsl_shader_prog_link *entry = NULL; GLhandleARB programId = 0; + GLhandleARB reorder_shader_id = 0; int i; char glsl_name[8]; @@ -2253,12 +2980,23 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use * in order to make the bindings work, and it has to be done prior * to linking the GLSL program. */ for (i = 0; i < max_attribs; ++i) { - _snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i); - GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name)); + if (((IWineD3DBaseShaderImpl*)vshader)->baseShader.reg_maps.attributes[i]) { + snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i); + GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name)); + } } checkGLcall("glBindAttribLocationARB"); list_add_head(&((IWineD3DBaseShaderImpl *)vshader)->baseShader.linked_programs, &entry->vshader_entry); + + reorder_shader_id = generate_param_reorder_function(vshader, pshader, gl_info); + TRACE("Attaching GLSL shader object %u to program %u\n", reorder_shader_id, programId); + GL_EXTCALL(glAttachObjectARB(programId, reorder_shader_id)); + checkGLcall("glAttachObjectARB"); + /* Flag the reorder function for deletion, then it will be freed automatically when the program + * is destroyed + */ + GL_EXTCALL(glDeleteObjectARB(reorder_shader_id)); } /* Attach GLSL pshader */ @@ -2277,14 +3015,52 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use entry->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF)); for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) { - _snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i); + snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i); entry->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); } + for (i = 0; i < MAX_CONST_I; ++i) { + snprintf(glsl_name, sizeof(glsl_name), "VI[%i]", i); + entry->vuniformI_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); + } entry->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF)); for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) { - _snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i); + snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i); entry->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); } + for (i = 0; i < MAX_CONST_I; ++i) { + snprintf(glsl_name, sizeof(glsl_name), "PI[%i]", i); + entry->puniformI_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); + } + + entry->posFixup_location = GL_EXTCALL(glGetUniformLocationARB(programId, "posFixup")); + entry->bumpenvmat_location = GL_EXTCALL(glGetUniformLocationARB(programId, "bumpenvmat")); + entry->luminancescale_location = GL_EXTCALL(glGetUniformLocationARB(programId, "luminancescale")); + entry->luminanceoffset_location = GL_EXTCALL(glGetUniformLocationARB(programId, "luminanceoffset")); + entry->srgb_comparison_location = GL_EXTCALL(glGetUniformLocationARB(programId, "srgb_comparison")); + entry->srgb_mul_low_location = GL_EXTCALL(glGetUniformLocationARB(programId, "srgb_mul_low")); + entry->ycorrection_location = GL_EXTCALL(glGetUniformLocationARB(programId, "ycorrection")); + checkGLcall("Find glsl program uniform locations"); + + /* Set the shader to allow uniform loading on it */ + GL_EXTCALL(glUseProgramObjectARB(programId)); + checkGLcall("glUseProgramObjectARB(programId)"); + + /* Load the vertex and pixel samplers now. The function that finds the mappings makes sure + * that it stays the same for each vertexshader-pixelshader pair(=linked glsl program). If + * a pshader with fixed function pipeline is used there are no vertex samplers, and if a + * vertex shader with fixed function pixel processing is used we make sure that the card + * supports enough samplers to allow the max number of vertex samplers with all possible + * fixed function fragment processing setups. So once the program is linked these samplers + * won't change. + */ + if(vshader_id) { + /* Load vertex shader samplers */ + shader_glsl_load_vsamplers(gl_info, (IWineD3DStateBlock*)This->stateBlock, programId); + } + if(pshader_id) { + /* Load pixel shader samplers */ + shader_glsl_load_psamplers(gl_info, (IWineD3DStateBlock*)This->stateBlock, programId); + } } static GLhandleARB create_glsl_blt_shader(WineD3D_GL_Info *gl_info) { @@ -2365,5 +3141,6 @@ const shader_backend_t glsl_shader_backend = { &shader_glsl_select, &shader_glsl_select_depth_blt, &shader_glsl_load_constants, - &shader_glsl_cleanup + &shader_glsl_cleanup, + &shader_glsl_color_correction }; diff --git a/reactos/dll/directx/wine/wined3d/pixelshader.c b/reactos/dll/directx/wine/wined3d/pixelshader.c index 163453bcc14..62a9fe6af28 100644 --- a/reactos/dll/directx/wine/wined3d/pixelshader.c +++ b/reactos/dll/directx/wine/wined3d/pixelshader.c @@ -67,38 +67,30 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_AddRef(IWineD3DPixelShader *iface) return InterlockedIncrement(&This->ref); } +static void destroy_glsl_pshader(IWineD3DPixelShaderImpl *This) { + struct list *linked_programs = &This->baseShader.linked_programs; + + TRACE("Deleting linked programs\n"); + if (linked_programs->next) { + struct glsl_shader_prog_link *entry, *entry2; + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, pshader_entry) { + delete_glsl_program_entry(This->baseShader.device, entry); + } + } + + TRACE("Deleting shader object %u\n", This->baseShader.prgId); + GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); + checkGLcall("glDeleteObjectARB"); +} + static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface) { IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; ULONG ref; TRACE("(%p) : Releasing from %d\n", This, This->ref); ref = InterlockedDecrement(&This->ref); if (ref == 0) { - /* SetPixelShader does not AddRef. If the bound pixel shader is destroyed, the pointer in the stateblock remains - * unchanged. Drawing again will most likely crash, even on windows. A problem can occur if the application creates - * a new pixel shader which resides at the same address. Then SetPixelShader will think it is a NOP change, and won't - * dirtify the state. - * - * Do NOT call GetPixelShader here. This will addRef and cause a recursion. And do NOT set the pixel shader to NULL, - * Windows does not do that(Although no test exists since they'd crash randomly) - */ - if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->pixelShader) { - IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_PIXELSHADER); - } - if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { - struct list *linked_programs = &This->baseShader.linked_programs; - - TRACE("Deleting linked programs\n"); - if (linked_programs->next) { - struct glsl_shader_prog_link *entry, *entry2; - LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, pshader_entry) { - delete_glsl_program_entry(This->baseShader.device, entry); - } - } - - TRACE("Deleting shader object %u\n", This->baseShader.prgId); - GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); - checkGLcall("glDeleteObjectARB"); + destroy_glsl_pshader(This); } shader_delete_constant_list(&This->baseShader.constantsF); shader_delete_constant_list(&This->baseShader.constantsB); @@ -175,7 +167,7 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { {WINED3DSIO_SGE, "sge", "SGE", 1, 3, pshader_hw_map2gl, shader_glsl_compare, 0, 0}, {WINED3DSIO_ABS, "abs", "ABS", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, {WINED3DSIO_EXP, "exp", "EX2", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, - {WINED3DSIO_LOG, "log", "LG2", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_LOG, "log", "LG2", 1, 2, pshader_hw_map2gl, shader_glsl_log, 0, 0}, {WINED3DSIO_EXPP, "expp", "EXP", 1, 2, pshader_hw_map2gl, shader_glsl_expp, 0, 0}, {WINED3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, {WINED3DSIO_DST, "dst", "DST", 1, 3, pshader_hw_map2gl, shader_glsl_dst, 0, 0}, @@ -183,28 +175,18 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { {WINED3DSIO_FRC, "frc", "FRC", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, {WINED3DSIO_CND, "cnd", NULL, 1, 4, pshader_hw_cnd, shader_glsl_cnd, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_CMP, "cmp", NULL, 1, 4, pshader_hw_cmp, shader_glsl_cmp, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(3,0)}, - {WINED3DSIO_POW, "pow", "POW", 1, 3, NULL, shader_glsl_pow, 0, 0}, - {WINED3DSIO_CRS, "crs", "XPS", 1, 3, NULL, shader_glsl_cross, 0, 0}, - /* TODO: xyz normalise can be performed as VS_ARB using one temporary register, - DP3 tmp , vec, vec; - RSQ tmp, tmp.x; - MUL vec.xyz, vec, tmp; - but I think this is better because it accounts for w properly. - DP3 tmp , vec, vec; - RSQ tmp, tmp.x; - MUL vec, vec, tmp; - */ - {WINED3DSIO_NRM, "nrm", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, - {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, NULL, shader_glsl_sincos, WINED3DPS_VERSION(2,0), WINED3DPS_VERSION(2,1)}, - {WINED3DSIO_SINCOS, "sincos", NULL, 1, 2, NULL, shader_glsl_sincos, WINED3DPS_VERSION(3,0), -1}, - /* TODO: dp2add can be made out of multiple instuctions */ - {WINED3DSIO_DP2ADD, "dp2add", GLNAME_REQUIRE_GLSL, 1, 4, NULL, pshader_glsl_dp2add, WINED3DPS_VERSION(2,0), -1}, + {WINED3DSIO_POW, "pow", "POW", 1, 3, pshader_hw_map2gl, shader_glsl_pow, 0, 0}, + {WINED3DSIO_CRS, "crs", "XPD", 1, 3, pshader_hw_map2gl, shader_glsl_cross, 0, 0}, + {WINED3DSIO_NRM, "nrm", NULL, 1, 2, shader_hw_nrm, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, shader_hw_sincos, shader_glsl_sincos, WINED3DPS_VERSION(2,0), WINED3DPS_VERSION(2,1)}, + {WINED3DSIO_SINCOS, "sincos", "SCS", 1, 2, shader_hw_sincos, shader_glsl_sincos, WINED3DPS_VERSION(3,0), -1}, + {WINED3DSIO_DP2ADD, "dp2add", NULL, 1, 4, pshader_hw_dp2add, pshader_glsl_dp2add, WINED3DPS_VERSION(2,0), -1}, /* Matrix */ - {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, /* Register declarations */ {WINED3DSIO_DCL, "dcl", NULL, 0, 2, NULL, NULL, 0, 0}, /* Flow control - requires GLSL or software shaders */ @@ -230,15 +212,15 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { /* Texture */ {WINED3DSIO_TEXCOORD, "texcoord", "undefined", 1, 1, pshader_hw_texcoord, pshader_glsl_texcoord, 0, WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXCOORD, "texcrd", "undefined", 1, 2, pshader_hw_texcoord, pshader_glsl_texcoord, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, - {WINED3DSIO_TEXKILL, "texkill", "KIL", 1, 1, pshader_hw_map2gl, pshader_glsl_texkill, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(3,0)}, + {WINED3DSIO_TEXKILL, "texkill", "KIL", 1, 1, pshader_hw_texkill, pshader_glsl_texkill, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(3,0)}, {WINED3DSIO_TEX, "tex", "undefined", 1, 1, pshader_hw_tex, pshader_glsl_tex, 0, WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEX, "texld", "undefined", 1, 2, pshader_hw_tex, pshader_glsl_tex, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_TEX, "texld", "undefined", 1, 3, pshader_hw_tex, pshader_glsl_tex, WINED3DPS_VERSION(2,0), -1}, {WINED3DSIO_TEXBEM, "texbem", "undefined", 1, 2, pshader_hw_texbem, pshader_glsl_texbem, 0, WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXBEML, "texbeml", GLNAME_REQUIRE_GLSL, 1, 2, NULL, NULL, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXBEML, "texbeml", GLNAME_REQUIRE_GLSL, 1, 2, pshader_hw_texbem, pshader_glsl_texbem, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXREG2AR,"texreg2ar","undefined", 1, 2, pshader_hw_texreg2ar, pshader_glsl_texreg2ar, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXREG2GB,"texreg2gb","undefined", 1, 2, pshader_hw_texreg2gb, pshader_glsl_texreg2gb, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXREG2RGB, "texreg2rgb", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texreg2rgb, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXREG2RGB, "texreg2rgb", "undefined", 1, 2, pshader_hw_texreg2rgb, pshader_glsl_texreg2rgb, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x2PAD, "texm3x2pad", "undefined", 1, 2, pshader_hw_texm3x2pad, pshader_glsl_texm3x2pad, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x2TEX, "texm3x2tex", "undefined", 1, 2, pshader_hw_texm3x2tex, pshader_glsl_texm3x2tex, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x3PAD, "texm3x3pad", "undefined", 1, 2, pshader_hw_texm3x3pad, pshader_glsl_texm3x3pad, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, @@ -246,11 +228,11 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { {WINED3DSIO_TEXM3x3SPEC, "texm3x3spec", "undefined", 1, 3, pshader_hw_texm3x3spec, pshader_glsl_texm3x3spec, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x3VSPEC, "texm3x3vspec", "undefined", 1, 2, pshader_hw_texm3x3vspec, pshader_glsl_texm3x3vspec, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, {WINED3DSIO_TEXM3x3TEX, "texm3x3tex", "undefined", 1, 2, pshader_hw_texm3x3tex, pshader_glsl_texm3x3tex, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXDP3TEX, "texdp3tex", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texdp3tex, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXM3x2DEPTH, "texm3x2depth", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x2depth, WINED3DPS_VERSION(1,3), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXDP3, "texdp3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texdp3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXM3x3, "texm3x3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, - {WINED3DSIO_TEXDEPTH, "texdepth", GLNAME_REQUIRE_GLSL, 1, 1, NULL, pshader_glsl_texdepth, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_TEXDP3TEX, "texdp3tex", NULL, 1, 2, pshader_hw_texdp3tex, pshader_glsl_texdp3tex, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x2DEPTH, "texm3x2depth", GLNAME_REQUIRE_GLSL, 1, 2, pshader_hw_texm3x2depth, pshader_glsl_texm3x2depth, WINED3DPS_VERSION(1,3), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXDP3, "texdp3", NULL, 1, 2, pshader_hw_texdp3, pshader_glsl_texdp3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3, "texm3x3", NULL, 1, 2, pshader_hw_texm3x3, pshader_glsl_texm3x3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXDEPTH, "texdepth", NULL, 1, 1, pshader_hw_texdepth, pshader_glsl_texdepth, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_BEM, "bem", "undefined", 1, 3, pshader_hw_bem, pshader_glsl_bem, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, {WINED3DSIO_DSX, "dsx", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, {WINED3DSIO_DSY, "dsy", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, @@ -379,8 +361,18 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader( shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); /* Pack 3.0 inputs */ - if (This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) - pshader_glsl_input_pack(&buffer, This->semantics_in); + if (This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) { + + if(((IWineD3DDeviceImpl *) This->baseShader.device)->strided_streams.u.s.position_transformed) { + This->vertexprocessing = pretransformed; + pshader_glsl_input_pack(&buffer, This->semantics_in, iface); + } else if(!use_vs((IWineD3DDeviceImpl *) This->baseShader.device)) { + This->vertexprocessing = fixedfunction; + pshader_glsl_input_pack(&buffer, This->semantics_in, iface); + } else { + This->vertexprocessing = vertexshader; + } + } /* Base Shader Body */ shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); @@ -407,6 +399,23 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader( else shader_addline(&buffer, "gl_FragColor.xyz = mix(gl_Fog.color.xyz, gl_FragColor.xyz, Fog);\n"); } + if(This->srgb_enabled) { + const char *fragcolor; + + if(GL_SUPPORT(ARB_DRAW_BUFFERS)) { + fragcolor = "gl_FragData[0]"; + } else { + fragcolor = "gl_FragColor"; + } + shader_addline(&buffer, "tmp0.xyz = pow(%s.xyz, vec3(%f, %f, %f)) * vec3(%f, %f, %f) - vec3(%f, %f, %f);\n", + fragcolor, srgb_pow, srgb_pow, srgb_pow, srgb_mul_high, srgb_mul_high, srgb_mul_high, + srgb_sub_high, srgb_sub_high, srgb_sub_high); + shader_addline(&buffer, "tmp1.xyz = %s.xyz * srgb_mul_low.xyz;\n", fragcolor); + shader_addline(&buffer, "%s.x = %s.x < srgb_comparison.x ? tmp1.x : tmp0.x;\n", fragcolor, fragcolor); + shader_addline(&buffer, "%s.y = %s.y < srgb_comparison.y ? tmp1.y : tmp0.y;\n", fragcolor, fragcolor); + shader_addline(&buffer, "%s.z = %s.z < srgb_comparison.z ? tmp1.z : tmp0.z;\n", fragcolor, fragcolor); + shader_addline(&buffer, "%s = clamp(%s, 0.0, 1.0);\n", fragcolor, fragcolor); + } shader_addline(&buffer, "}\n"); @@ -448,12 +457,41 @@ static inline VOID IWineD3DPixelShaderImpl_GenerateShader( * -1/(e-s) and e/(e-s) respectively. */ shader_addline(&buffer, "MAD_SAT TMP_FOG, fragment.fogcoord, state.fog.params.y, state.fog.params.z;\n"); - if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { - shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, R0, state.fog.color;\n"); - shader_addline(&buffer, "MOV result.color.a, R0.a;\n"); + + if(This->srgb_enabled) { + if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { + shader_addline(&buffer, "LRP TMP_COLOR.rgb, TMP_FOG.x, R0, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, R0.a;\n"); + } else { + shader_addline(&buffer, "LRP TMP_COLOR.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n"); + } + /* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */ + + /* Calculate the > 0.0031308 case */ + shader_addline(&buffer, "POW TMP.x, TMP_COLOR.x, srgb_pow.x;\n"); + shader_addline(&buffer, "POW TMP.y, TMP_COLOR.y, srgb_pow.y;\n"); + shader_addline(&buffer, "POW TMP.z, TMP_COLOR.z, srgb_pow.z;\n"); + shader_addline(&buffer, "MUL TMP, TMP, srgb_mul_hi;\n"); + shader_addline(&buffer, "SUB TMP, TMP, srgb_sub_hi;\n"); + /* Calculate the < case */ + shader_addline(&buffer, "MUL TMP2, srgb_mul_low, TMP_COLOR;\n"); + /* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */ + shader_addline(&buffer, "SLT TA, srgb_comparison, TMP_COLOR;\n"); + shader_addline(&buffer, "SGE TB, srgb_comparison, TMP_COLOR;\n"); + /* Store the components > 0.0031308 in the destination */ + shader_addline(&buffer, "MUL TMP_COLOR, TMP, TA;\n"); + /* Add the components that are < 0.0031308 */ + shader_addline(&buffer, "MAD result.color.xyz, TMP2, TB, TMP_COLOR;\n"); + /* [0.0;1.0] clamping. Not needed, this is done implicitly */ } else { - shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n"); - shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n"); + if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { + shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, R0, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, R0.a;\n"); + } else { + shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n"); + } } shader_addline(&buffer, "END\n"); @@ -504,6 +542,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) > 1) { shader_reg_maps *reg_maps = &This->baseShader.reg_maps; HRESULT hr; + unsigned int i, j, highest_reg_used = 0, num_regs_used = 0; /* Second pass: figure out which registers are used, what the semantics are, etc.. */ memset(reg_maps, 0, sizeof(shader_reg_maps)); @@ -511,6 +550,41 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i This->semantics_in, NULL, pFunction, NULL); if (FAILED(hr)) return hr; /* FIXME: validate reg_maps against OpenGL */ + + for(i = 0; i < MAX_REG_INPUT; i++) { + if(This->input_reg_used[i]) { + num_regs_used++; + highest_reg_used = i; + } + } + + /* Don't do any register mapping magic if it is not needed, or if we can't + * achive anything anyway + */ + if(highest_reg_used < (GL_LIMITS(glsl_varyings) / 4) || + num_regs_used > (GL_LIMITS(glsl_varyings) / 4) ) { + if(num_regs_used > (GL_LIMITS(glsl_varyings) / 4)) { + /* This happens with relative addressing. The input mapper function + * warns about this if the higher registers are declared too, so + * don't write a FIXME here + */ + WARN("More varying registers used than supported\n"); + } + + for(i = 0; i < MAX_REG_INPUT; i++) { + This->input_reg_map[i] = i; + } + } else { + j = 0; + for(i = 0; i < MAX_REG_INPUT; i++) { + if(This->input_reg_used[i]) { + This->input_reg_map[i] = j; + j++; + } else { + This->input_reg_map[i] = -1; + } + } + } } This->baseShader.shader_mode = deviceImpl->ps_selected_mode; @@ -535,11 +609,76 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface; IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; CONST DWORD *function = This->baseShader.function; + UINT i, sampler; + IWineD3DBaseTextureImpl *texture; TRACE("(%p) : function %p\n", iface, function); - /* We're already compiled. */ - if (This->baseShader.is_compiled) return WINED3D_OK; + /* We're already compiled, but check if any of the hardcoded stateblock assumptions + * changed. + */ + if (This->baseShader.is_compiled) { + char srgbenabled = deviceImpl->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE] ? 1 : 0; + for(i = 0; i < This->baseShader.num_sampled_samplers; i++) { + sampler = This->baseShader.sampled_samplers[i]; + texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler]; + if(texture && texture->baseTexture.shader_conversion_group != This->baseShader.sampled_format[sampler]) { + WARN("Recompiling shader %p due to format change on sampler %d\n", This, sampler); + WARN("Old format group %s, new is %s\n", + debug_d3dformat(This->baseShader.sampled_format[sampler]), + debug_d3dformat(texture->baseTexture.shader_conversion_group)); + goto recompile; + } + } + + /* TODO: Check projected textures */ + /* TODO: Check texture types(2D, Cube, 3D) */ + + if(srgbenabled != This->srgb_enabled && This->srgb_mode_hardcoded) { + WARN("Recompiling shader because srgb correction is different and hardcoded\n"); + goto recompile; + } + if(This->baseShader.reg_maps.vpos && !This->vpos_uniform) { + if(This->render_offscreen != deviceImpl->render_offscreen || + This->height != ((IWineD3DSurfaceImpl *) deviceImpl->render_targets[0])->currentDesc.Height) { + WARN("Recompiling shader because vpos is used, hard compiled and changed\n"); + goto recompile; + } + } + if(This->baseShader.reg_maps.usesdsy && !This->vpos_uniform) { + if(This->render_offscreen ? 0 : 1 != deviceImpl->render_offscreen ? 0 : 1) { + WARN("Recompiling shader because dsy is used, hard compiled and render_offscreen changed\n"); + goto recompile; + } + } + if(This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) { + if(((IWineD3DDeviceImpl *) This->baseShader.device)->strided_streams.u.s.position_transformed && + This->vertexprocessing != pretransformed) { + WARN("Recompiling shader because pretransformed vertices are provided, which wasn't the case before\n"); + goto recompile; + } else if(!use_vs((IWineD3DDeviceImpl *) This->baseShader.device) && + This->vertexprocessing != fixedfunction) { + WARN("Recompiling shader because fixed function vp is in use, which wasn't the case before\n"); + goto recompile; + } else if(This->vertexprocessing != vertexshader) { + WARN("Recompiling shader because vertex shaders are in use, which wasn't the case before\n"); + goto recompile; + } + } + + return WINED3D_OK; + + recompile: + if(This->baseShader.recompile_count > 50) { + FIXME("Shader %p recompiled more than 50 times\n", This); + } else { + This->baseShader.recompile_count++; + } + + if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { + destroy_glsl_pshader(This); + } + } /* We don't need to compile */ if (!function) { @@ -559,6 +698,9 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader /* FIXME: validate reg_maps against OpenGL */ } + /* Reset fields tracking stateblock values being hardcoded in the shader */ + This->baseShader.num_sampled_samplers = 0; + /* Generate the HW shader */ TRACE("(%p) : Generating hardware program\n", This); IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function); diff --git a/reactos/dll/directx/wine/wined3d/query.c b/reactos/dll/directx/wine/wined3d/query.c index 99390f867ea..7c91f2ee663 100644 --- a/reactos/dll/directx/wine/wined3d/query.c +++ b/reactos/dll/directx/wine/wined3d/query.c @@ -167,7 +167,12 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa case WINED3DQUERYTYPE_EVENT: { BOOL* data = pData; - if(GL_SUPPORT(APPLE_FENCE)) { + WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx; + if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) { + /* See comment in IWineD3DQuery::Issue, event query codeblock */ + WARN("Query context not active, reporting GPU idle\n"); + *data = TRUE; + } else if(GL_SUPPORT(APPLE_FENCE)) { *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId)); checkGLcall("glTestFenceAPPLE"); } else if(GL_SUPPORT(NV_FENCE)) { @@ -182,7 +187,9 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa case WINED3DQUERYTYPE_OCCLUSION: { DWORD* data = pData; - if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) { + if (GL_SUPPORT(ARB_OCCLUSION_QUERY) && + ((WineQueryOcclusionData *)This->extendedData)->ctx == This->wineD3DDevice->activeContext && + This->wineD3DDevice->activeContext->tid == GetCurrentThreadId()) { GLuint available; GLuint samples; GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId; @@ -201,7 +208,7 @@ static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pDa res = S_FALSE; } } else { - FIXME("(%p) : Occlusion queries not supported. Returning 1.\n", This); + WARN("(%p) : Occlusion queries not supported, or wrong context. Returning 1.\n", This); *data = 1; res = S_OK; } @@ -375,13 +382,19 @@ static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIs switch (This->type) { case WINED3DQUERYTYPE_OCCLUSION: if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) { - if (dwIssueFlags & WINED3DISSUE_BEGIN) { - GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId)); - checkGLcall("glBeginQuery()"); - } - if (dwIssueFlags & WINED3DISSUE_END) { - GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB)); - checkGLcall("glEndQuery()"); + WineD3DContext *ctx = ((WineQueryOcclusionData *)This->extendedData)->ctx; + + if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) { + WARN("Not the owning context, can't start query\n"); + } else { + if (dwIssueFlags & WINED3DISSUE_BEGIN) { + GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId)); + checkGLcall("glBeginQuery()"); + } + if (dwIssueFlags & WINED3DISSUE_END) { + GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB)); + checkGLcall("glEndQuery()"); + } } } else { FIXME("(%p) : Occlusion queries not supported\n", This); @@ -390,7 +403,17 @@ static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIs case WINED3DQUERYTYPE_EVENT: { if (dwIssueFlags & WINED3DISSUE_END) { - if(GL_SUPPORT(APPLE_FENCE)) { + WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx; + if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) { + /* GL fences can be used only from the context that created them, + * so if a different context is active, don't bother setting the query. The penalty + * of a context switch is most likely higher than the gain of a correct query result + * + * If the query is used from a different thread, don't bother creating a multithread + * context - there's no point in doing that as the query would be unusable anyway + */ + WARN("Query context not active\n"); + } else if(GL_SUPPORT(APPLE_FENCE)) { GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId)); checkGLcall("glSetFenceAPPLE"); } else if (GL_SUPPORT(NV_FENCE)) { diff --git a/reactos/dll/directx/wine/wined3d/resource.c b/reactos/dll/directx/wine/wined3d/resource.c index 6999f060c05..9faaea575b8 100644 --- a/reactos/dll/directx/wine/wined3d/resource.c +++ b/reactos/dll/directx/wine/wined3d/resource.c @@ -71,7 +71,7 @@ void IWineD3DResourceImpl_CleanUp(IWineD3DResource *iface){ TRACE("(%p) Cleaning up resource\n", This); if (This->resource.pool == WINED3DPOOL_DEFAULT) { TRACE("Decrementing device memory pool by %u\n", This->resource.size); - globalChangeGlRam(-This->resource.size); + WineD3DAdapterChangeGLRam(This->resource.wineD3DDevice, -This->resource.size); } LIST_FOR_EACH_SAFE(e1, e2, &This->resource.privateData) { @@ -82,8 +82,9 @@ void IWineD3DResourceImpl_CleanUp(IWineD3DResource *iface){ } } - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + HeapFree(GetProcessHeap(), 0, This->resource.heapMemory); This->resource.allocatedMemory = 0; + This->resource.heapMemory = 0; if (This->resource.wineD3DDevice != NULL) { IWineD3DDevice_ResourceReleased((IWineD3DDevice *)This->resource.wineD3DDevice, iface); @@ -137,6 +138,7 @@ HRESULT WINAPI IWineD3DResourceImpl_SetPrivateData(IWineD3DResource *iface, REFG if (Flags & WINED3DSPD_IUNKNOWN) { if(SizeOfData != sizeof(IUnknown *)) { WARN("IUnknown data with size %d, returning WINED3DERR_INVALIDCALL\n", SizeOfData); + HeapFree(GetProcessHeap(), 0, data); return WINED3DERR_INVALIDCALL; } data->ptr.object = (LPUNKNOWN)pData; diff --git a/reactos/dll/directx/wine/wined3d/state.c b/reactos/dll/directx/wine/wined3d/state.c index 9a768d13230..251e77f93bb 100644 --- a/reactos/dll/directx/wine/wined3d/state.c +++ b/reactos/dll/directx/wine/wined3d/state.c @@ -132,11 +132,9 @@ static void state_zenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD } static void state_cullmode(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - /* TODO: Put this into the offscreen / onscreen rendering block due to device->render_offscreen */ - - /* If we are culling "back faces with clockwise vertices" then - set front faces to be counter clockwise and enable culling - of back faces */ + /* glFrontFace() is set in context.c at context init and on an offscreen / onscreen rendering + * switch + */ switch ((WINED3DCULL) stateblock->renderState[WINED3DRS_CULLMODE]) { case WINED3DCULL_NONE: glDisable(GL_CULL_FACE); @@ -145,26 +143,14 @@ static void state_cullmode(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine case WINED3DCULL_CW: glEnable(GL_CULL_FACE); checkGLcall("glEnable GL_CULL_FACE"); - if (stateblock->wineD3DDevice->render_offscreen) { - glFrontFace(GL_CW); - checkGLcall("glFrontFace GL_CW"); - } else { - glFrontFace(GL_CCW); - checkGLcall("glFrontFace GL_CCW"); - } - glCullFace(GL_BACK); + glCullFace(GL_FRONT); + checkGLcall("glCullFace(GL_FRONT)"); break; case WINED3DCULL_CCW: glEnable(GL_CULL_FACE); checkGLcall("glEnable GL_CULL_FACE"); - if (stateblock->wineD3DDevice->render_offscreen) { - glFrontFace(GL_CCW); - checkGLcall("glFrontFace GL_CCW"); - } else { - glFrontFace(GL_CW); - checkGLcall("glFrontFace GL_CW"); - } glCullFace(GL_BACK); + checkGLcall("glCullFace(GL_BACK)"); break; default: FIXME("Unrecognized/Unhandled WINED3DCULL value %d\n", stateblock->renderState[WINED3DRS_CULLMODE]); @@ -216,6 +202,20 @@ static void state_zfunc(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D int glParm = CompareFunc(stateblock->renderState[WINED3DRS_ZFUNC]); if(glParm) { + if(glParm == GL_EQUAL || glParm == GL_NOTEQUAL) { + static BOOL once = FALSE; + /* There are a few issues with this: First, our inability to + * select a proper Z depth, most of the time we're stuck with + * D24S8, even if the app selects D32 or D16. There seem to be + * some other precision problems which have to be debugged to + * make NOTEQUAL and EQUAL work properly + */ + if(!once) { + once = TRUE; + FIXME("D3DCMP_NOTEQUAL and D3DCMP_EQUAL do not work correctly yet\n"); + } + } + glDepthFunc(glParm); checkGLcall("glDepthFunc"); } @@ -247,33 +247,6 @@ static void state_blend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D return; }; - switch (stateblock->renderState[WINED3DRS_SRCBLEND]) { - case WINED3DBLEND_ZERO : srcBlend = GL_ZERO; break; - case WINED3DBLEND_ONE : srcBlend = GL_ONE; break; - case WINED3DBLEND_SRCCOLOR : srcBlend = GL_SRC_COLOR; break; - case WINED3DBLEND_INVSRCCOLOR : srcBlend = GL_ONE_MINUS_SRC_COLOR; break; - case WINED3DBLEND_SRCALPHA : srcBlend = GL_SRC_ALPHA; break; - case WINED3DBLEND_INVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; break; - case WINED3DBLEND_DESTALPHA : srcBlend = GL_DST_ALPHA; break; - case WINED3DBLEND_INVDESTALPHA : srcBlend = GL_ONE_MINUS_DST_ALPHA; break; - case WINED3DBLEND_DESTCOLOR : srcBlend = GL_DST_COLOR; break; - case WINED3DBLEND_INVDESTCOLOR : srcBlend = GL_ONE_MINUS_DST_COLOR; break; - case WINED3DBLEND_SRCALPHASAT : srcBlend = GL_SRC_ALPHA_SATURATE; break; - - case WINED3DBLEND_BOTHSRCALPHA : srcBlend = GL_SRC_ALPHA; - dstBlend = GL_SRC_ALPHA; - break; - - case WINED3DBLEND_BOTHINVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; - dstBlend = GL_ONE_MINUS_SRC_ALPHA; - break; - - case WINED3DBLEND_BLENDFACTOR : srcBlend = GL_CONSTANT_COLOR; break; - case WINED3DBLEND_INVBLENDFACTOR : srcBlend = GL_ONE_MINUS_CONSTANT_COLOR; break; - default: - FIXME("Unrecognized src blend value %d\n", stateblock->renderState[WINED3DRS_SRCBLEND]); - } - switch (stateblock->renderState[WINED3DRS_DESTBLEND]) { case WINED3DBLEND_ZERO : dstBlend = GL_ZERO; break; case WINED3DBLEND_ONE : dstBlend = GL_ONE; break; @@ -291,12 +264,17 @@ static void state_blend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D WARN("Application uses SRCALPHASAT as dest blend factor, expect problems\n"); break; + /* WINED3DBLEND_BOTHSRCALPHA and WINED3DBLEND_BOTHINVSRCALPHA are legacy source blending + * values which are still valid up to d3d9. They should not occur as dest blend values + */ case WINED3DBLEND_BOTHSRCALPHA : dstBlend = GL_SRC_ALPHA; srcBlend = GL_SRC_ALPHA; + FIXME("WINED3DRS_DESTBLEND = WINED3DBLEND_BOTHSRCALPHA, what to do?\n"); break; case WINED3DBLEND_BOTHINVSRCALPHA : dstBlend = GL_ONE_MINUS_SRC_ALPHA; srcBlend = GL_ONE_MINUS_SRC_ALPHA; + FIXME("WINED3DRS_DESTBLEND = WINED3DBLEND_BOTHINVSRCALPHA, what to do?\n"); break; case WINED3DBLEND_BLENDFACTOR : dstBlend = GL_CONSTANT_COLOR; break; @@ -305,6 +283,34 @@ static void state_blend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D FIXME("Unrecognized dst blend value %d\n", stateblock->renderState[WINED3DRS_DESTBLEND]); } + switch (stateblock->renderState[WINED3DRS_SRCBLEND]) { + case WINED3DBLEND_ZERO : srcBlend = GL_ZERO; break; + case WINED3DBLEND_ONE : srcBlend = GL_ONE; break; + case WINED3DBLEND_SRCCOLOR : srcBlend = GL_SRC_COLOR; break; + case WINED3DBLEND_INVSRCCOLOR : srcBlend = GL_ONE_MINUS_SRC_COLOR; break; + case WINED3DBLEND_SRCALPHA : srcBlend = GL_SRC_ALPHA; break; + case WINED3DBLEND_INVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; break; + case WINED3DBLEND_DESTALPHA : srcBlend = GL_DST_ALPHA; break; + case WINED3DBLEND_INVDESTALPHA : srcBlend = GL_ONE_MINUS_DST_ALPHA; break; + case WINED3DBLEND_DESTCOLOR : srcBlend = GL_DST_COLOR; break; + case WINED3DBLEND_INVDESTCOLOR : srcBlend = GL_ONE_MINUS_DST_COLOR; break; + case WINED3DBLEND_SRCALPHASAT : srcBlend = GL_SRC_ALPHA_SATURATE; break; + + case WINED3DBLEND_BOTHSRCALPHA : srcBlend = GL_SRC_ALPHA; + dstBlend = GL_ONE_MINUS_SRC_ALPHA; + break; + + case WINED3DBLEND_BOTHINVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; + dstBlend = GL_SRC_ALPHA; + break; + + case WINED3DBLEND_BLENDFACTOR : srcBlend = GL_CONSTANT_COLOR; break; + case WINED3DBLEND_INVBLENDFACTOR : srcBlend = GL_ONE_MINUS_CONSTANT_COLOR; break; + default: + FIXME("Unrecognized src blend value %d\n", stateblock->renderState[WINED3DRS_SRCBLEND]); + } + + if(stateblock->renderState[WINED3DRS_EDGEANTIALIAS] || stateblock->renderState[WINED3DRS_ANTIALIASEDLINEENABLE]) { glEnable(GL_LINE_SMOOTH); @@ -330,7 +336,7 @@ static void state_blendfactor(DWORD state, IWineD3DStateBlockImpl *stateblock, W TRACE("Setting BlendFactor to %d\n", stateblock->renderState[WINED3DRS_BLENDFACTOR]); D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_BLENDFACTOR], col); - GL_EXTCALL(glBlendColor (col[0],col[1],col[2],col[3])); + GL_EXTCALL(glBlendColorEXT (col[0],col[1],col[2],col[3])); checkGLcall("glBlendColor"); } @@ -423,9 +429,17 @@ static void state_clipping(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine if (stateblock->renderState[WINED3DRS_CLIPPING]) { enable = stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]; disable = ~stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]; + if(GL_SUPPORT(NV_DEPTH_CLAMP)) { + glDisable(GL_DEPTH_CLAMP_NV); + checkGLcall("glDisable(GL_DEPTH_CLAMP_NV)"); + } } else { disable = 0xffffffff; enable = 0x00; + if(GL_SUPPORT(NV_DEPTH_CLAMP)) { + glEnable(GL_DEPTH_CLAMP_NV); + checkGLcall("glEnable(GL_DEPTH_CLAMP_NV)"); + } } if (enable & WINED3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); } @@ -471,7 +485,7 @@ static void state_blendop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD } TRACE("glBlendEquation(%x)\n", glParm); - GL_EXTCALL(glBlendEquation(glParm)); + GL_EXTCALL(glBlendEquationEXT(glParm)); checkGLcall("glBlendEquation"); } @@ -661,7 +675,7 @@ state_stencil(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *c if( !( func = CompareFunc(stateblock->renderState[WINED3DRS_STENCILFUNC]) ) ) func = GL_ALWAYS; if( !( func_ccw = CompareFunc(stateblock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) ) - func = GL_ALWAYS; + func_ccw = GL_ALWAYS; ref = stateblock->renderState[WINED3DRS_STENCILREF]; mask = stateblock->renderState[WINED3DRS_STENCILMASK]; stencilFail = StencilOp(stateblock->renderState[WINED3DRS_STENCILFAIL]); @@ -678,29 +692,55 @@ state_stencil(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *c func, stencilFail, depthFail, stencilPass, func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw); - if (twosided_enable) { - renderstate_stencil_twosided(stateblock, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass); + if (twosided_enable && onesided_enable) { + glEnable(GL_STENCIL_TEST); + checkGLcall("glEnable GL_STENCIL_TEST"); + + /* Apply back first, then front. This function calls glActiveStencilFaceEXT, + * which has an effect on the code below too. If we apply the front face + * afterwards, we are sure that the active stencil face is set to front, + * and other stencil functions which do not use two sided stencil do not have + * to set it back + */ renderstate_stencil_twosided(stateblock, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw); - } else { - if (onesided_enable) { - glEnable(GL_STENCIL_TEST); - checkGLcall("glEnable GL_STENCIL_TEST"); - glStencilFunc(func, ref, mask); - checkGLcall("glStencilFunc(...)"); - glStencilOp(stencilFail, depthFail, stencilPass); - checkGLcall("glStencilOp(...)"); - } else { - glDisable(GL_STENCIL_TEST); - checkGLcall("glDisable GL_STENCIL_TEST"); + renderstate_stencil_twosided(stateblock, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass); + } else if(onesided_enable) { + if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) { + glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + checkGLcall("glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT)"); } + + glEnable(GL_STENCIL_TEST); + checkGLcall("glEnable GL_STENCIL_TEST"); + glStencilFunc(func, ref, mask); + checkGLcall("glStencilFunc(...)"); + glStencilOp(stencilFail, depthFail, stencilPass); + checkGLcall("glStencilOp(...)"); + } else { + glDisable(GL_STENCIL_TEST); + checkGLcall("glDisable GL_STENCIL_TEST"); } } static void state_stencilwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD mask; + if(stateblock->wineD3DDevice->stencilBufferTarget) { - glStencilMask(stateblock->renderState[WINED3DRS_STENCILWRITEMASK]); + mask = stateblock->renderState[WINED3DRS_STENCILWRITEMASK]; } else { - glStencilMask(0); + mask = 0; + } + + if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) { + GL_EXTCALL(glActiveStencilFaceEXT(GL_BACK)); + checkGLcall("glActiveStencilFaceEXT(GL_BACK)"); + glStencilMask(mask); + checkGLcall("glStencilMask"); + GL_EXTCALL(glActiveStencilFaceEXT(GL_FRONT)); + checkGLcall("glActiveStencilFaceEXT(GL_FRONT)"); + glStencilMask(mask); + } else { + glStencilMask(mask); } checkGLcall("glStencilMask"); } @@ -796,6 +836,12 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo fogstart = 1.0; fogend = 0.0; } + + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; + } context->last_was_foggy_shader = TRUE; } else if( use_ps(stateblock->wineD3DDevice) ) { @@ -831,6 +877,12 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo break; default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", stateblock->renderState[WINED3DRS_FOGVERTEXMODE]); } + + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; + } } /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, * the system will apply only pixel(=table) fog effects." @@ -846,9 +898,10 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo if(!context->last_was_rhw) { glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; } @@ -857,9 +910,10 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo if(!context->last_was_rhw) { glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; } @@ -868,9 +922,10 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo if(!context->last_was_rhw) { glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; } @@ -881,8 +936,11 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo * Same happens with Vertexfog on transformed vertices */ if(GL_SUPPORT(EXT_FOG_COORD)) { - glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT); - checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n"); + if(context->fog_coord == FALSE) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n"); + context->fog_coord = TRUE; + } glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); fogstart = 0xff; @@ -904,27 +962,30 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo case WINED3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; case WINED3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; case WINED3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); - if(GL_SUPPORT(EXT_FOG_COORD)) { + if(GL_SUPPORT(EXT_FOG_COORD) && context->fog_coord) { glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + context->fog_coord = FALSE; } break; @@ -938,13 +999,26 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo glEnable(GL_FOG); checkGLcall("glEnable GL_FOG"); - glFogfv(GL_FOG_START, &fogstart); - checkGLcall("glFogf(GL_FOG_START, fogstart"); - TRACE("Fog Start == %f\n", fogstart); + if(fogstart != fogend) + { + glFogfv(GL_FOG_START, &fogstart); + checkGLcall("glFogf(GL_FOG_START, fogstart"); + TRACE("Fog Start == %f\n", fogstart); - glFogfv(GL_FOG_END, &fogend); - checkGLcall("glFogf(GL_FOG_END, fogend"); - TRACE("Fog End == %f\n", fogend); + glFogfv(GL_FOG_END, &fogend); + checkGLcall("glFogf(GL_FOG_END, fogend"); + TRACE("Fog End == %f\n", fogend); + } + else + { + glFogf(GL_FOG_START, -1.0 / 0.0); + checkGLcall("glFogf(GL_FOG_START, fogstart"); + TRACE("Fog Start == %f\n", fogstart); + + glFogf(GL_FOG_END, 0.0); + checkGLcall("glFogf(GL_FOG_END, fogend"); + TRACE("Fog End == %f\n", fogend); + } } else { glDisable(GL_FOG); checkGLcall("glDisable GL_FOG"); @@ -959,9 +1033,21 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo checkGLcall("glFogf(GL_FOG_END, fogend"); } } +} - if (GL_SUPPORT(NV_FOG_DISTANCE)) { - glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); +static void state_rangefog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_RANGEFOGENABLE]) { + if (GL_SUPPORT(NV_FOG_DISTANCE)) { + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV); + checkGLcall("glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV)"); + } else { + WARN("Range fog enabled, but not supported by this opengl implementation\n"); + } + } else { + if (GL_SUPPORT(NV_FOG_DISTANCE)) { + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); + checkGLcall("glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV)"); + } } } @@ -1144,7 +1230,16 @@ static void state_zbias(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D static void state_normalize(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - if (stateblock->renderState[WINED3DRS_NORMALIZENORMALS]) { + if(isStateDirty(context, STATE_VDECL)) { + return; + } + /* Without vertex normals, we set the current normal to 0/0/0 to remove the diffuse factor + * from the opengl lighting equation, as d3d does. Normalization of 0/0/0 can lead to a division + * by zero and is not properly defined in opengl, so avoid it + */ + if (stateblock->renderState[WINED3DRS_NORMALIZENORMALS] && ( + stateblock->wineD3DDevice->strided_streams.u.s.normal.lpData || + stateblock->wineD3DDevice->strided_streams.u.s.normal.VBO)) { glEnable(GL_NORMALIZE); checkGLcall("glEnable(GL_NORMALIZE);"); } else { @@ -1153,19 +1248,6 @@ static void state_normalize(DWORD state, IWineD3DStateBlockImpl *stateblock, Win } } -static void state_psize(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - union { - DWORD d; - float f; - } tmpvalue; - - /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */ - tmpvalue.d = stateblock->renderState[WINED3DRS_POINTSIZE]; - TRACE("Set point size to %f\n", tmpvalue.f); - glPointSize(tmpvalue.f); - checkGLcall("glPointSize(...);"); -} - static void state_psizemin(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { union { DWORD d; @@ -1216,31 +1298,49 @@ static void state_pscale(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3 /* Default values */ GLfloat att[3] = {1.0f, 0.0f, 0.0f}; + union { + DWORD d; + float f; + } pointSize, A, B, C; - /* - * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f. - * This means that OpenGL will clamp really small point sizes to 1.0f. - * To correct for this we need to multiply by the scale factor when sizes - * are less than 1.0f. scale_factor = 1.0f / point_size. - */ - GLfloat pointSize = *((float*)&stateblock->renderState[WINED3DRS_POINTSIZE]); - if(pointSize > 0.0f) { + pointSize.d = stateblock->renderState[WINED3DRS_POINTSIZE]; + A.d = stateblock->renderState[WINED3DRS_POINTSCALE_A]; + B.d = stateblock->renderState[WINED3DRS_POINTSCALE_B]; + C.d = stateblock->renderState[WINED3DRS_POINTSCALE_C]; + + if(stateblock->renderState[WINED3DRS_POINTSCALEENABLE]) { GLfloat scaleFactor; + float h = stateblock->viewport.Height; - if(pointSize < 1.0f) { - scaleFactor = pointSize * pointSize; + if(pointSize.f < GL_LIMITS(pointsizemin)) { + /* + * Minimum valid point size for OpenGL is driver specific. For Direct3D it is + * 0.0f. This means that OpenGL will clamp really small point sizes to the + * driver minimum. To correct for this we need to multiply by the scale factor when sizes + * are less than 1.0f. scale_factor = 1.0f / point_size. + */ + scaleFactor = pointSize.f / GL_LIMITS(pointsizemin); + /* Clamp the point size, don't rely on the driver to do it. MacOS says min point size + * is 1.0, but then accepts points below that and draws too small points + */ + pointSize.f = GL_LIMITS(pointsizemin); + } else if(pointSize.f > GL_LIMITS(pointsize)) { + /* gl already scales the input to glPointSize, + * d3d scales the result after the point size scale. + * If the point size is bigger than the max size, use the + * scaling to scale it bigger, and set the gl point size to max + */ + scaleFactor = pointSize.f / GL_LIMITS(pointsize); + TRACE("scale: %f\n", scaleFactor); + pointSize.f = GL_LIMITS(pointsize); } else { scaleFactor = 1.0f; } + scaleFactor = pow(h * scaleFactor, 2); - if(stateblock->renderState[WINED3DRS_POINTSCALEENABLE]) { - att[0] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_A]) / - (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); - att[1] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_B]) / - (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); - att[2] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_C]) / - (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); - } + att[0] = A.f / scaleFactor; + att[1] = B.f / scaleFactor; + att[2] = C.f / scaleFactor; } if(GL_SUPPORT(ARB_POINT_PARAMETERS)) { @@ -1250,9 +1350,12 @@ static void state_pscale(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3 else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) { GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att); checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ..."); - } else { - TRACE("POINT_PARAMETERS not supported in this version of opengl\n"); + } else if(stateblock->renderState[WINED3DRS_POINTSCALEENABLE]) { + WARN("POINT_PARAMETERS not supported in this version of opengl\n"); } + + glPointSize(pointSize.f); + checkGLcall("glPointSize(...);"); } static void state_colorwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { @@ -1468,12 +1571,6 @@ static void state_tessellation(DWORD state, IWineD3DStateBlockImpl *stateblock, FIXME("(WINED3DRS_ENABLEADAPTIVETESSELLATION,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION]); } - -static void state_srgbwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - if(stateblock->renderState[WINED3DRS_SRGBWRITEENABLE]) - FIXME("Render state WINED3DRS_SRGBWRITEENABLE not yet implemented\n"); -} - static void state_separateblend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { TRACE("Stub\n"); if(stateblock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE]) @@ -1807,6 +1904,13 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W DWORD texUnit = state - STATE_TRANSFORM(WINED3DTS_TEXTURE0); DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[texUnit]; + /* Ignore this when a vertex shader is used, or if the streams aren't sorted out yet */ + if(use_vs(stateblock->wineD3DDevice) || + isStateDirty(context, STATE_VDECL)) { + TRACE("Using a vertex shader, or stream sources not sorted out yet, skipping\n"); + return; + } + if (mapped_stage < 0) return; if (GL_SUPPORT(ARB_MULTITEXTURE)) { @@ -1823,7 +1927,11 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W set_texture_matrix((float *)&stateblock->transforms[WINED3DTS_TEXTURE0 + texUnit].u.m[0][0], stateblock->textureState[texUnit][WINED3DTSS_TEXTURETRANSFORMFLAGS], - (stateblock->textureState[texUnit][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU); + (stateblock->textureState[texUnit][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU, + context->last_was_rhw, + stateblock->wineD3DDevice->strided_streams.u.s.texCoords[texUnit].dwStride ? + stateblock->wineD3DDevice->strided_streams.u.s.texCoords[texUnit].dwType: + WINED3DDECLTYPE_UNUSED); } @@ -2067,6 +2175,20 @@ static void tex_coordindex(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine } } +static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; + + /* Vertex and pixel shader states will call a shader upload, don't do anything as long one of them + * has an update pending + */ + if(isStateDirty(context, STATE_VDECL) || + isStateDirty(context, STATE_PIXELSHADER)) { + return; + } + + device->shader_backend->shader_load_constants((IWineD3DDevice *) device, use_ps(device), use_vs(device)); +} + static void tex_bumpenvlscale(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; union { @@ -2074,6 +2196,17 @@ static void tex_bumpenvlscale(DWORD state, IWineD3DStateBlockImpl *stateblock, W float f; } tmpvalue; + if(stateblock->pixelShader && stage != 0 && + ((IWineD3DPixelShaderImpl *) stateblock->pixelShader)->baseShader.reg_maps.luminanceparams == stage) { + /* The pixel shader has to know the luminance scale. Do a constants update if it + * isn't scheduled anyway + */ + if(!isStateDirty(context, STATE_PIXELSHADERCONSTANT) && + !isStateDirty(context, STATE_PIXELSHADER)) { + shaderconstant(STATE_PIXELSHADERCONSTANT, stateblock, context); + } + } + tmpvalue.d = stateblock->textureState[stage][WINED3DTSS_BUMPENVLSCALE]; if(tmpvalue.f != 0.0) { FIXME("WINED3DTSS_BUMPENVLSCALE not supported yet\n"); @@ -2087,6 +2220,17 @@ static void tex_bumpenvloffset(DWORD state, IWineD3DStateBlockImpl *stateblock, float f; } tmpvalue; + if(stateblock->pixelShader && stage != 0 && + ((IWineD3DPixelShaderImpl *) stateblock->pixelShader)->baseShader.reg_maps.luminanceparams == stage) { + /* The pixel shader has to know the luminance offset. Do a constants update if it + * isn't scheduled anyway + */ + if(!isStateDirty(context, STATE_PIXELSHADERCONSTANT) && + !isStateDirty(context, STATE_PIXELSHADER)) { + shaderconstant(STATE_PIXELSHADERCONSTANT, stateblock, context); + } + } + tmpvalue.d = stateblock->textureState[stage][WINED3DTSS_BUMPENVLOFFSET]; if(tmpvalue.f != 0.0) { FIXME("WINED3DTSS_BUMPENVLOFFSET not supported yet\n"); @@ -2206,20 +2350,6 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont } } -static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { - IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; - - /* Vertex and pixel shader states will call a shader upload, don't do anything as long one of them - * has an update pending - */ - if(isStateDirty(context, STATE_VDECL) || - isStateDirty(context, STATE_PIXELSHADER)) { - return; - } - - device->shader_backend->shader_load_constants((IWineD3DDevice *) device, use_ps(device), use_vs(device)); -} - static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; BOOL use_pshader = use_ps(device); @@ -2435,8 +2565,12 @@ static void state_vertexblend(DWORD state, IWineD3DStateBlockImpl *stateblock, W stateblock->wineD3DDevice->vertexBlendUsed = TRUE; } } else { - /* TODO: Implement vertex blending in drawStridedSlow */ - FIXME("Vertex blending enabled, but not supported by hardware\n"); + static BOOL once = FALSE; + if(!once) { + once = TRUE; + /* TODO: Implement vertex blending in drawStridedSlow */ + FIXME("Vertex blending enabled, but not supported by hardware\n"); + } } break; @@ -2543,7 +2677,23 @@ static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock /* Transformed vertices are supposed to bypass the whole transform pipeline including * frustum clipping. This can't be done in opengl, so this code adjusts the Z range to * suppress depth clipping. This can be done because it is an orthogonal projection and - * the Z coordinate does not affect the size of the primitives + * the Z coordinate does not affect the size of the primitives. Half Life 1 and Prince of + * Persia 3D need this. + * + * Note that using minZ and maxZ here doesn't entirely fix the problem, since view frustum + * clipping is still enabled, but it seems to fix it for all apps tested so far. A minor + * problem can be witnessed in half-life 1 engine based games, the weapon is clipped close + * to the viewer. + * + * Also note that this breaks z comparison against z values filled in with clear, + * but no app depending on that and disabled clipping has been found yet. Comparing + * primitives against themselves works, so the Z buffer is still intact for normal hidden + * surface removal. + * + * We could disable clipping entirely by setting the near to infinity and far to -infinity, + * but this would break Z buffer operation. Raising the range to something less than + * infinity would help a bit at the cost of Z precision, but it wouldn't eliminate the + * problem either. */ TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ); if(stateblock->wineD3DDevice->render_offscreen) { @@ -2561,16 +2711,16 @@ static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock */ TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0); if(stateblock->wineD3DDevice->render_offscreen) { - glOrtho(X, X + width, -Y, -Y - height, 1.0, -1.0); + glOrtho(X, X + width, -Y, -Y - height, 0.0, -1.0); } else { - glOrtho(X, X + width, Y + height, Y, 1.0, -1.0); + glOrtho(X, X + width, Y + height, Y, 0.0, -1.0); } } checkGLcall("glOrtho"); - /* Window Coord 0 is the middle of the first pixel, so translate by 3/8 pixels */ - glTranslatef(0.375, 0.375, 0); - checkGLcall("glTranslatef(0.375, 0.375, 0)"); + /* Window Coord 0 is the middle of the first pixel, so translate by 1/2 pixels */ + glTranslatef(0.5, 0.5, 0); + checkGLcall("glTranslatef(0.5, 0.5, 0)"); /* D3D texture coordinates are flipped compared to OpenGL ones, so * render everything upside down when rendering offscreen. */ if (stateblock->wineD3DDevice->render_offscreen) { @@ -2584,9 +2734,21 @@ static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock the left to the right end of the viewport (with all matrices set to be identity), the x coords of both ends of the line would be not -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width) - instead. */ - glTranslatef(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0); - checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)"); + instead. + + 1.0 / Width is used because the coord range goes from -1.0 to 1.0, then we + divide by the Width/Height, so we need the half range(1.0) to translate by + half a pixel. + + The other fun is that d3d's output z range after the transformation is [0;1], + but opengl's is [-1;1]. Since the z buffer is in range [0;1] for both, gl + scales [-1;1] to [0;1]. This would mean that we end up in [0.5;1] and loose a lot + of Z buffer precision and the clear values do not match in the z test. Thus scale + [0;1] to [-1;1], so when gl undoes that we utilize the full z range + */ + glTranslatef(1.0 / stateblock->viewport.Width, -1.0/ stateblock->viewport.Height, -1.0); + checkGLcall("glTranslatef (1.0 / width, -1.0 / height, -1.0)"); + glScalef(1.0, 1.0, 2.0); /* D3D texture coordinates are flipped compared to OpenGL ones, so * render everything upside down when rendering offscreen. */ @@ -2963,8 +3125,8 @@ static void loadVertexData(IWineD3DStateBlockImpl *stateblock, WineDirect3DVerte checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)"); } else { - glNormal3f(0, 0, 1); - checkGLcall("glNormal3f(0, 0, 1)"); + glNormal3f(0, 0, 0); + checkGLcall("glNormal3f(0, 0, 0)"); } /* Diffuse Colour --------------------------------------------*/ @@ -3239,6 +3401,9 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W if(context->last_was_vshader && !isStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPLANEENABLE))) { state_clipping(STATE_RENDER(WINED3DRS_CLIPPLANEENABLE), stateblock, context); } + if(!isStateDirty(context, STATE_RENDER(WINED3DRS_NORMALIZENORMALS))) { + state_normalize(STATE_RENDER(WINED3DRS_NORMALIZENORMALS), stateblock, context); + } } else { /* We compile the shader here because we need the vertex declaration * in order to determine if we need to do any swizzling for D3DCOLOR @@ -3279,6 +3444,14 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W if(updateFog) { state_fog(STATE_RENDER(WINED3DRS_FOGENABLE), stateblock, context); } + if(!useVertexShaderFunction) { + int i; + for(i = 0; i < MAX_TEXTURES; i++) { + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + i))) { + transform_texture(STATE_TRANSFORM(WINED3DTS_TEXTURE0 + i), stateblock, context); + } + } + } } static void viewport(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { @@ -3298,12 +3471,14 @@ static void viewport(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCon checkGLcall("glViewport"); - stateblock->wineD3DDevice->posFixup[2] = 0.9 / stateblock->viewport.Width; - stateblock->wineD3DDevice->posFixup[3] = -0.9 / stateblock->viewport.Height; + stateblock->wineD3DDevice->posFixup[2] = 1.0 / stateblock->viewport.Width; + stateblock->wineD3DDevice->posFixup[3] = -1.0 / stateblock->viewport.Height; if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION))) { transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context); } - + if(!isStateDirty(context, STATE_RENDER(WINED3DRS_POINTSCALEENABLE))) { + state_pscale(STATE_RENDER(WINED3DRS_POINTSCALEENABLE), stateblock, context); + } } static void light(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { @@ -3454,6 +3629,16 @@ static void indexbuffer(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D } } +static void frontface(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->wineD3DDevice->render_offscreen) { + glFrontFace(GL_CCW); + checkGLcall("glFrontFace(GL_CCW)"); + } else { + glFrontFace(GL_CW); + checkGLcall("glFrontFace(GL_CW)"); + } +} + const struct StateEntry StateTable[] = { /* State name representative, apply function */ @@ -3505,7 +3690,7 @@ const struct StateEntry StateTable[] = { /* 45, WINED3DRS_TEXTUREADDRESSV */ 0, /* Handled in ddraw */ state_undefined }, { /* 46, WINED3DRS_MIPMAPLODBIAS */ STATE_RENDER(WINED3DRS_MIPMAPLODBIAS), state_mipmaplodbias }, { /* 47, WINED3DRS_ZBIAS */ STATE_RENDER(WINED3DRS_ZBIAS), state_zbias }, - { /* 48, WINED3DRS_RANGEFOGENABLE */ 0, state_nogl }, + { /* 48, WINED3DRS_RANGEFOGENABLE */ STATE_RENDER(WINED3DRS_RANGEFOGENABLE), state_rangefog }, { /* 49, WINED3DRS_ANISOTROPY */ STATE_RENDER(WINED3DRS_ANISOTROPY), state_anisotropy }, { /* 50, WINED3DRS_FLUSHBATCH */ STATE_RENDER(WINED3DRS_FLUSHBATCH), state_flushbatch }, { /* 51, WINED3DRS_TRANSLUCENTSORTINDEPENDENT */ STATE_RENDER(WINED3DRS_TRANSLUCENTSORTINDEPENDENT), state_translucentsi }, @@ -3612,7 +3797,7 @@ const struct StateEntry StateTable[] = { /*151, WINED3DRS_VERTEXBLEND */ STATE_RENDER(WINED3DRS_VERTEXBLEND), state_vertexblend }, { /*152, WINED3DRS_CLIPPLANEENABLE */ STATE_RENDER(WINED3DRS_CLIPPING), state_clipping }, { /*153, WINED3DRS_SOFTWAREVERTEXPROCESSING */ 0, state_nogl }, - { /*154, WINED3DRS_POINTSIZE */ STATE_RENDER(WINED3DRS_POINTSIZE), state_psize }, + { /*154, WINED3DRS_POINTSIZE */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, { /*155, WINED3DRS_POINTSIZE_MIN */ STATE_RENDER(WINED3DRS_POINTSIZE_MIN), state_psizemin }, { /*156, WINED3DRS_POINTSPRITEENABLE */ STATE_RENDER(WINED3DRS_POINTSPRITEENABLE), state_pointsprite }, { /*157, WINED3DRS_POINTSCALEENABLE */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, @@ -3654,7 +3839,7 @@ const struct StateEntry StateTable[] = { /*191, WINED3DRS_COLORWRITEENABLE2 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, { /*192, WINED3DRS_COLORWRITEENABLE3 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, { /*193, WINED3DRS_BLENDFACTOR */ STATE_RENDER(WINED3DRS_BLENDFACTOR), state_blendfactor }, - { /*194, WINED3DRS_SRGBWRITEENABLE */ STATE_RENDER(WINED3DRS_SRGBWRITEENABLE), state_srgbwrite }, + { /*194, WINED3DRS_SRGBWRITEENABLE */ STATE_PIXELSHADER, pixelshader }, { /*195, WINED3DRS_DEPTHBIAS */ STATE_RENDER(WINED3DRS_DEPTHBIAS), state_depthbias }, { /*196, undefined */ 0, state_undefined }, { /*197, undefined */ 0, state_undefined }, @@ -4525,4 +4710,5 @@ const struct StateEntry StateTable[] = { /* STATE_CLIPPLANE(31) */ STATE_CLIPPLANE(31), clipplane }, { /* STATE_MATERIAL */ STATE_RENDER(WINED3DRS_SPECULARENABLE), state_specularenable}, + { /* STATE_FRONTFACE */ STATE_FRONTFACE, frontface }, }; diff --git a/reactos/dll/directx/wine/wined3d/stateblock.c b/reactos/dll/directx/wine/wined3d/stateblock.c index 772bd788719..758606afaff 100644 --- a/reactos/dll/directx/wine/wined3d/stateblock.c +++ b/reactos/dll/directx/wine/wined3d/stateblock.c @@ -186,8 +186,8 @@ void stateblock_copy( PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry), *light2; light2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*light)); memcpy(light2, light, sizeof(*light)); - list_add_tail(&This->lightMap[l], &light2->entry); - if(light2->glIndex != -1) This->activeLights[light2->glIndex] = light2; + list_add_tail(&Dest->lightMap[l], &light2->entry); + if(light2->glIndex != -1) Dest->activeLights[light2->glIndex] = light2; } } @@ -262,10 +262,19 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) { } } } - if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData); - } + for (counter = 0; counter < MAX_STREAMS; counter++) { + if(This->streamSource[counter]) { + if(0 != IWineD3DVertexBuffer_Release(This->streamSource[counter])) { + TRACE("Vertex buffer still referenced by stateblock, applications has leaked Stream %u, buffer %p\n", counter, This->streamSource[counter]); + } + } + } + if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData); + if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader); + if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader); + for(counter = 0; counter < LIGHTMAP_SIZE; counter++) { struct list *e1, *e2; LIST_FOR_EACH_SAFE(e1, e2, &This->lightMap[counter]) { @@ -379,9 +388,11 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) if (This->blockType == WINED3DSBT_RECORDED) { /* Recorded => Only update 'changed' values */ - if (This->vertexShader != targetStateBlock->vertexShader) { + if (This->changed.vertexShader && This->vertexShader != targetStateBlock->vertexShader) { TRACE("Updating vertex shader from %p to %p\n", This->vertexShader, targetStateBlock->vertexShader); + if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader); + if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader); This->vertexShader = targetStateBlock->vertexShader; } @@ -424,13 +435,6 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) This->vertexShaderConstantB[i] = targetStateBlock->vertexShaderConstantB[i]; } - /* Recorded => Only update 'changed' values */ - if (This->pixelShader != targetStateBlock->pixelShader) { - TRACE("Updating pixel shader from %p to %p\n", This->pixelShader, targetStateBlock->pixelShader); - - This->pixelShader = targetStateBlock->pixelShader; - } - /* Pixel Shader Float Constants */ for (j = 0; j < This->num_contained_ps_consts_f; ++j) { i = This->contained_ps_consts_f[j]; @@ -481,7 +485,9 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) if (This->changed.indices && ((This->pIndexData != targetStateBlock->pIndexData) || (This->baseVertexIndex != targetStateBlock->baseVertexIndex))) { TRACE("Updating pindexData to %p, baseVertexIndex to %d\n", - targetStateBlock->pIndexData, targetStateBlock->baseVertexIndex); + targetStateBlock->pIndexData, targetStateBlock->baseVertexIndex); + if(targetStateBlock->pIndexData) IWineD3DIndexBuffer_AddRef(targetStateBlock->pIndexData); + if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData); This->pIndexData = targetStateBlock->pIndexData; This->baseVertexIndex = targetStateBlock->baseVertexIndex; } @@ -525,6 +531,8 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) TRACE("Updating stream source %d to %p, stride to %d\n", i, targetStateBlock->streamSource[i], targetStateBlock->streamStride[i]); This->streamStride[i] = targetStateBlock->streamStride[i]; + if(targetStateBlock->streamSource[i]) IWineD3DVertexBuffer_AddRef(targetStateBlock->streamSource[i]); + if(This->streamSource[i]) IWineD3DVertexBuffer_Release(This->streamSource[i]); This->streamSource[i] = targetStateBlock->streamSource[i]; } @@ -583,20 +591,22 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) This->samplerState[stage][state]); This->samplerState[stage][state] = targetStateBlock->samplerState[stage][state]; } + if(This->changed.pixelShader && This->pixelShader != targetStateBlock->pixelShader) { + if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader); + if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader); + This->pixelShader = targetStateBlock->pixelShader; + } record_lights(This, targetStateBlock); } else if(This->blockType == WINED3DSBT_ALL) { This->vertexDecl = targetStateBlock->vertexDecl; - This->vertexShader = targetStateBlock->vertexShader; memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI)); memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF)); memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); memcpy(This->streamStride, targetStateBlock->streamStride, sizeof(This->streamStride)); memcpy(This->streamOffset, targetStateBlock->streamOffset, sizeof(This->streamOffset)); - memcpy(This->streamSource, targetStateBlock->streamSource, sizeof(This->streamSource)); memcpy(This->streamFreq, targetStateBlock->streamFreq, sizeof(This->streamFreq)); memcpy(This->streamFlags, targetStateBlock->streamFlags, sizeof(This->streamFlags)); - This->pIndexData = targetStateBlock->pIndexData; This->baseVertexIndex = targetStateBlock->baseVertexIndex; memcpy(This->transforms, targetStateBlock->transforms, sizeof(This->transforms)); record_lights(This, targetStateBlock); @@ -604,7 +614,6 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) This->clip_status = targetStateBlock->clip_status; This->viewport = targetStateBlock->viewport; This->material = targetStateBlock->material; - This->pixelShader = targetStateBlock->pixelShader; memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI)); memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF)); memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); @@ -614,8 +623,30 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) memcpy(This->textureState, targetStateBlock->textureState, sizeof(This->textureState)); memcpy(This->samplerState, targetStateBlock->samplerState, sizeof(This->samplerState)); This->scissorRect = targetStateBlock->scissorRect; + + if(targetStateBlock->pIndexData != This->pIndexData) { + if(targetStateBlock->pIndexData) IWineD3DIndexBuffer_AddRef(targetStateBlock->pIndexData); + if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData); + This->pIndexData = targetStateBlock->pIndexData; + } + for(i = 0; i < MAX_STREAMS; i++) { + if(targetStateBlock->streamSource[i] != This->streamSource[i]) { + if(targetStateBlock->streamSource[i]) IWineD3DVertexBuffer_AddRef(targetStateBlock->streamSource[i]); + if(This->streamSource[i]) IWineD3DVertexBuffer_Release(This->streamSource[i]); + This->streamSource[i] = targetStateBlock->streamSource[i]; + } + } + if(This->vertexShader != targetStateBlock->vertexShader) { + if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader); + if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader); + This->vertexShader = targetStateBlock->vertexShader; + } + if(This->pixelShader != targetStateBlock->pixelShader) { + if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader); + if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader); + This->pixelShader = targetStateBlock->pixelShader; + } } else if(This->blockType == WINED3DSBT_VERTEXSTATE) { - This->vertexShader = targetStateBlock->vertexShader; memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI)); memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF)); memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); @@ -633,8 +664,19 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) This->textureState[j][SavedVertexStates_R[i]] = targetStateBlock->textureState[j][SavedVertexStates_R[i]]; } } + for(i = 0; i < MAX_STREAMS; i++) { + if(targetStateBlock->streamSource[i] != This->streamSource[i]) { + if(targetStateBlock->streamSource[i]) IWineD3DVertexBuffer_AddRef(targetStateBlock->streamSource[i]); + if(This->streamSource[i]) IWineD3DVertexBuffer_Release(This->streamSource[i]); + This->streamSource[i] = targetStateBlock->streamSource[i]; + } + } + if(This->vertexShader != targetStateBlock->vertexShader) { + if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader); + if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader); + This->vertexShader = targetStateBlock->vertexShader; + } } else if(This->blockType == WINED3DSBT_PIXELSTATE) { - This->pixelShader = targetStateBlock->pixelShader; memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI)); memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF)); memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); @@ -651,6 +693,11 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) This->textureState[j][SavedPixelStates_R[i]] = targetStateBlock->textureState[j][SavedPixelStates_R[i]]; } } + if(This->pixelShader != targetStateBlock->pixelShader) { + if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader); + if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader); + This->pixelShader = targetStateBlock->pixelShader; + } } TRACE("(%p) : Updated state block %p ------------------^\n", targetStateBlock, This); diff --git a/reactos/dll/directx/wine/wined3d/surface.c b/reactos/dll/directx/wine/wined3d/surface.c index 58b4ed61450..d3cbc527bcb 100644 --- a/reactos/dll/directx/wine/wined3d/surface.c +++ b/reactos/dll/directx/wine/wined3d/surface.c @@ -7,8 +7,9 @@ * Copyright 2002-2003 Raphael Junqueira * Copyright 2004 Christian Costa * Copyright 2005 Oliver Stieber - * Copyright 2006 Stefan Dösinger for CodeWeavers + * Copyright 2006-2007 Stefan Dösinger for CodeWeavers * Copyright 2007 Henri Verbeet + * Copyright 2006-2007 Roderick Colenbrander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,9 +34,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface); #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf); +static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey); static void surface_download_data(IWineD3DSurfaceImpl *This) { - if (!This->resource.allocatedMemory) This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size + 4); + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + + if (0 == This->glDescription.textureName) { + ERR("Surface does not have a texture, but SFLAG_INTEXTURE is set\n"); + return; + } + + if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { + ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + ENTER_GL(); + /* Make sure that a proper texture unit is selected, bind the texture + * and dirtify the sampler to restore the texture on the next draw + */ + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + checkGLcall("glActiveTextureARB"); + } + IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0)); + IWineD3DSurface_PreLoad((IWineD3DSurface *) This); + if (This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { @@ -45,9 +68,19 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory); - GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory)); - checkGLcall("glGetCompressedTexImageARB()"); + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, NULL)); + checkGLcall("glGetCompressedTexImageARB()"); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } else { + GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory)); + checkGLcall("glGetCompressedTexImageARB()"); + } } + LEAVE_GL(); } else { void *mem; int src_pitch = 0; @@ -55,6 +88,7 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { if(This->Flags & SFLAG_CONVERTED) { FIXME("Read back converted textures unsupported\n"); + LEAVE_GL(); return; } @@ -71,9 +105,22 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, mem); - glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat, - This->glDescription.glType, mem); - checkGLcall("glGetTexImage()"); + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + + glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat, + This->glDescription.glType, NULL); + checkGLcall("glGetTexImage()"); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } else { + glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat, + This->glDescription.glType, mem); + checkGLcall("glGetTexImage()"); + } + LEAVE_GL(); if (This->Flags & SFLAG_NONPOW2) { LPBYTE src_data, dst_data; @@ -141,6 +188,7 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) { HeapFree(GetProcessHeap(), 0, mem); } } + /* Surface has now been downloaded */ This->Flags |= SFLAG_INSYSMEM; } @@ -152,33 +200,58 @@ static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsi if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { FIXME("Using DXT1/3/5 without advertized support\n"); } else { - if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { - /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */ - This->Flags |= SFLAG_CLIENT; - } - - TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data); - ENTER_GL(); /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver) * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this * function uses glCompressedTexImage2D instead of the SubImage call */ - GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal, - width, height, 0 /* border */, This->resource.size, data)); - checkGLcall("glCompressedTexSubImage2D"); + TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data); + ENTER_GL(); + + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data); + + GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal, + width, height, 0 /* border */, This->resource.size, NULL)); + checkGLcall("glCompressedTexSubImage2D"); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } else { + GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal, + width, height, 0 /* border */, This->resource.size, data)); + checkGLcall("glCompressedTexSubImage2D"); + } LEAVE_GL(); } } else { TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data); ENTER_GL(); - glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data); - checkGLcall("glTexSubImage2D"); + + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data); + + glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, NULL); + checkGLcall("glTexSubImage2D"); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } + else { + glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data); + checkGLcall("glTexSubImage2D"); + } + LEAVE_GL(); } } static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) { BOOL enable_client_storage = FALSE; + BYTE *mem = NULL; TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This, This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type); @@ -188,6 +261,18 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */ TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n"); + + /* We have to point GL to the client storage memory here, because upload_data might use a PBO. This means a double upload + * once, unfortunately + */ + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */ + This->Flags |= SFLAG_CLIENT; + mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); + GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal, + width, height, 0 /* border */, This->resource.size, mem)); + } + return; } @@ -204,15 +289,18 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, */ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); - This->Flags &= SFLAG_CLIENT; + This->Flags &= ~SFLAG_CLIENT; enable_client_storage = TRUE; } else { This->Flags |= SFLAG_CLIENT; - /* Below point opengl to our allocated texture memory */ + + /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because + * it might point into a pbo. Instead use heapMemory, but get the alignment right. + */ + mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); } } - glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, - This->Flags & SFLAG_CLIENT ? This->resource.allocatedMemory : NULL); + glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, mem); checkGLcall("glTexImage2D"); if(enable_client_storage) { @@ -292,34 +380,6 @@ GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchai return GL_BACK; } -/* ******************************************* - IWineD3DSurface IUnknown parts follow - ******************************************* */ -HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj) -{ - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - /* Warn ,but be nice about things */ - TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj); - - if (IsEqualGUID(riid, &IID_IUnknown) - || IsEqualGUID(riid, &IID_IWineD3DBase) - || IsEqualGUID(riid, &IID_IWineD3DResource) - || IsEqualGUID(riid, &IID_IWineD3DSurface)) { - IUnknown_AddRef((IUnknown*)iface); - *ppobj = This; - return S_OK; - } - *ppobj = NULL; - return E_NOINTERFACE; -} - -ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - ULONG ref = InterlockedIncrement(&This->resource.ref); - TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1); - return ref; -} - ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; ULONG ref = InterlockedDecrement(&This->resource.ref); @@ -329,44 +389,13 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { renderbuffer_entry_t *entry, *entry2; TRACE("(%p) : cleaning up\n", This); - if(iface == device->lastActiveRenderTarget) { - IWineD3DSwapChainImpl *swapchain = device->swapchains ? (IWineD3DSwapChainImpl *) device->swapchains[0] : NULL; - - TRACE("Last active render target destroyed\n"); - /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL - * checks, so switch to a valid target as long as the currently set surface is still valid. Use the - * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed - * and the lastActiveRenderTarget member shouldn't matter - */ - if(swapchain) { - if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) { - TRACE("Activating primary back buffer\n"); - ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD); - } else if(!swapchain->backBuffer && swapchain->frontBuffer != iface) { - /* Single buffering environment */ - TRACE("Activating primary front buffer\n"); - ActivateContext(device, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD); - } else { - TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n"); - /* Implicit render target destroyed, that means the device is being destroyed - * whatever we set here, it shouldn't matter - */ - device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe; - } - } else { - /* May happen during ddraw uninitialization */ - TRACE("Render target set, but swapchain does not exist!\n"); - device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe; - } - } - if (This->glDescription.textureName != 0) { /* release the openGL texture.. */ /* Need a context to destroy the texture. Use the currently active render target, but only if * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above. * When destroying the primary rt, Uninit3D will activate a context before doing anything */ - if(device->render_targets[0]) { + if(device->render_targets && device->render_targets[0]) { ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); } @@ -376,6 +405,11 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { LEAVE_GL(); } + if(This->Flags & SFLAG_PBO) { + /* Delete the PBO */ + GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo)); + } + if(This->Flags & SFLAG_DIBSECTION) { /* Release the DC */ SelectObject(This->hDC, This->dib.holdbitmap); @@ -408,29 +442,6 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { /* **************************************************** IWineD3DSurface IWineD3DResource parts follow **************************************************** */ -HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) { - return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { - return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { - return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) { - return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); -} - -DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) { - return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); -} - -DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) { - return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); -} void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) { /* TODO: check for locks */ @@ -477,66 +488,15 @@ void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) { return; } -WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) { - TRACE("(%p) : calling resourceimpl_GetType\n", iface); - return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) { - TRACE("(%p) : calling resourceimpl_GetParent\n", iface); - return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); -} - /* ****************************************************** IWineD3DSurface IWineD3DSurface parts follow ****************************************************** */ -HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - IWineD3DBase *container = 0; - - TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer); - - if (!ppContainer) { - ERR("Called without a valid ppContainer.\n"); - } - - /** From MSDN: - * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget, - * or CreateDepthStencilSurface, the surface is considered stand alone. In this case, - * GetContainer will return the Direct3D device used to create the surface. - */ - if (This->container) { - container = This->container; - } else { - container = (IWineD3DBase *)This->resource.wineD3DDevice; - } - - TRACE("Relaying to QueryInterface\n"); - return IUnknown_QueryInterface(container, riid, ppContainer); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - - TRACE("(%p) : copying into %p\n", This, pDesc); - if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format; - if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType; - if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage; - if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool; - if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */ - if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType; - if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality; - if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width; - if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height; - return WINED3D_OK; -} - void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target); if (This->glDescription.textureName == 0 && textureName != 0) { - This->Flags &= ~SFLAG_INTEXTURE; + IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE); IWineD3DSurface_AddDirtyRect(iface, NULL); } This->glDescription.textureName = textureName; @@ -560,36 +520,99 @@ const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) { return (CONST void*)(This->resource.allocatedMemory); } -static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) { +static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) { + IWineD3DSwapChainImpl *swapchain; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; BYTE *mem; GLint fmt; GLint type; BYTE *row, *top, *bottom; int i; BOOL bpp; + RECT local_rect; + BOOL srcIsUpsideDown; + + if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) { + static BOOL warned = FALSE; + if(!warned) { + ERR("The application tries to lock the render target, but render target locking is disabled\n"); + warned = TRUE; + } + return; + } + + IWineD3DSurface_GetContainer((IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain); + /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect. + * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage + * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find + * context->last_was_blit set on the unlock. + */ + ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT); + ENTER_GL(); + + /* Select the correct read buffer, and give some debug output. + * There is no need to keep track of the current read buffer or reset it, every part of the code + * that reads sets the read buffer as desired. + */ + if(!swapchain) { + /* Locking the primary render target which is not on a swapchain(=offscreen render target). + * Read from the back buffer + */ + TRACE("Locking offscreen render target\n"); + glReadBuffer(myDevice->offscreenBuffer); + srcIsUpsideDown = TRUE; + } else { + GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *) This, (IWineD3DSwapChain *)swapchain); + TRACE("Locking %#x buffer\n", buffer); + glReadBuffer(buffer); + checkGLcall("glReadBuffer"); + + IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + srcIsUpsideDown = FALSE; + } + + /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */ + if(!rect) { + local_rect.left = 0; + local_rect.top = 0; + local_rect.right = This->currentDesc.Width; + local_rect.bottom = This->currentDesc.Height; + } else { + local_rect = *rect; + } + /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */ switch(This->resource.format) { case WINED3DFMT_P8: { - /* GL can't return palettized data, so read ARGB pixels into a - * separate block of memory and convert them into palettized format - * in software. Slow, but if the app means to use palettized render - * targets and locks it... - * - * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons - * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out - * for the color channels when palettizing the colors. - */ - fmt = GL_RGB; - type = GL_UNSIGNED_BYTE; - pitch *= 3; - mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3); - if(!mem) { - ERR("Out of memory\n"); - return; + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { + /* In case of P8 render targets the index is stored in the alpha component */ + fmt = GL_ALPHA; + type = GL_UNSIGNED_BYTE; + mem = dest; + bpp = This->bytesPerPixel; + } else { + /* GL can't return palettized data, so read ARGB pixels into a + * separate block of memory and convert them into palettized format + * in software. Slow, but if the app means to use palettized render + * targets and locks it... + * + * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons + * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out + * for the color channels when palettizing the colors. + */ + fmt = GL_RGB; + type = GL_UNSIGNED_BYTE; + pitch *= 3; + mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3); + if(!mem) { + ERR("Out of memory\n"); + LEAVE_GL(); + return; + } + bpp = This->bytesPerPixel * 3; } - bpp = This->bytesPerPixel * 3; } break; @@ -600,31 +623,53 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v bpp = This->bytesPerPixel; } - glReadPixels(rect->left, rect->top, - rect->right - rect->left, - rect->bottom - rect->top, + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + } + + glReadPixels(local_rect.left, local_rect.top, + local_rect.right - local_rect.left, + local_rect.bottom - local_rect.top, fmt, type, mem); vcheckGLcall("glReadPixels"); - /* TODO: Merge this with the palettization loop below for P8 targets */ + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); - if(!srcUpsideDown) { + /* Check if we need to flip the image. If we need to flip use glMapBufferARB + * to get a pointer to it and perform the flipping in software. This is a lot + * faster than calling glReadPixels for each line. In case we want more speed + * we should rerender it flipped in a FBO and read the data back from the FBO. */ + if(!srcIsUpsideDown) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + + mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); + checkGLcall("glMapBufferARB"); + } + } + + /* TODO: Merge this with the palettization loop below for P8 targets */ + if(!srcIsUpsideDown) { UINT len, off; /* glReadPixels returns the image upside down, and there is no way to prevent this. Flip the lines in software */ - len = (rect->right - rect->left) * bpp; - off = rect->left * bpp; + len = (local_rect.right - local_rect.left) * bpp; + off = local_rect.left * bpp; row = HeapAlloc(GetProcessHeap(), 0, len); if(!row) { ERR("Out of memory\n"); if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem); + LEAVE_GL(); return; } - top = mem + pitch * rect->top; - bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1); - for(i = 0; i < (rect->bottom - rect->top) / 2; i++) { + top = mem + pitch * local_rect.top; + bottom = ((BYTE *) mem) + pitch * ( local_rect.bottom - local_rect.top - 1); + for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) { memcpy(row, top + off, len); memcpy(top + off, bottom + off, len); memcpy(bottom + off, row, len); @@ -632,9 +677,20 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v bottom -= pitch; } HeapFree(GetProcessHeap(), 0, row); + + /* Unmap the temp PBO buffer */ + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + } } - if(This->resource.format == WINED3DFMT_P8) { + /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette + * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for + * the same color but we have no choice. + * In case of render targets, the index is stored in the alpha component so no conversion is needed. + */ + if((This->resource.format == WINED3DFMT_P8) && !(This->resource.usage & WINED3DUSAGE_RENDERTARGET)) { PALETTEENTRY *pal; DWORD width = pitch / 3; int x, y, c; @@ -644,8 +700,8 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette]; } - for(y = rect->top; y < rect->bottom; y++) { - for(x = rect->left; x < rect->right; x++) { + for(y = local_rect.top; y < local_rect.bottom; y++) { + for(x = local_rect.left; x < local_rect.right; x++) { /* start lines pixels */ BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3); BYTE *green = blue + 1; @@ -664,70 +720,10 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v } HeapFree(GetProcessHeap(), 0, mem); } + LEAVE_GL(); } -static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; - IWineD3DSwapChainImpl *swapchain = NULL; - - TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); - - if (!(This->Flags & SFLAG_LOCKABLE)) { - /* Note: UpdateTextures calls CopyRects which calls this routine to populate the - texture regions, and since the destination is an unlockable region we need - to tolerate this */ - TRACE("Warning: trying to lock unlockable surf@%p\n", This); - /*return WINED3DERR_INVALIDCALL; */ - } - - pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); - - /* Mark the surface locked */ - This->Flags |= SFLAG_LOCKED; - - /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */ - if(!This->resource.allocatedMemory) { - This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4); - This->Flags &= ~SFLAG_INSYSMEM; /* This is the marker that surface data has to be downloaded */ - } - - /* Calculate the correct start address to report */ - if (NULL == pRect) { - pLockedRect->pBits = This->resource.allocatedMemory; - This->lockedRect.left = 0; - This->lockedRect.top = 0; - This->lockedRect.right = This->currentDesc.Width; - This->lockedRect.bottom = This->currentDesc.Height; - TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom); - } else { - TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom); - - /* DXTn textures are based on compressed blocks of 4x4 pixels, each - * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has - * slightly different meaning compared to regular textures. For DXTn - * textures Pitch is the size of a row of blocks, 4 high and "width" - * long. The x offset is calculated differently as well, since moving 4 - * pixels to the right actually moves an entire 4x4 block to right, ie - * 16 bytes (8 in case of DXT1). */ - if (This->resource.format == WINED3DFMT_DXT1) { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2); - } else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 - || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4); - } else { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel); - } - This->lockedRect.left = pRect->left; - This->lockedRect.top = pRect->top; - This->lockedRect.right = pRect->right; - This->lockedRect.bottom = pRect->bottom; - } - - if (This->Flags & SFLAG_NONPOW2) { - TRACE("Locking non-power 2 texture\n"); - } - +static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This) { /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy. * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is * changed @@ -741,6 +737,75 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED } } + /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces. + * Also don't create a PBO for systemmem surfaces. + */ + if(GL_SUPPORT(ARB_PIXEL_BUFFER_OBJECT) && (This->Flags & SFLAG_DYNLOCK) && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2)) && (This->resource.pool != WINED3DPOOL_SYSTEMMEM)) { + GLenum error; + ENTER_GL(); + + GL_EXTCALL(glGenBuffersARB(1, &This->pbo)); + error = glGetError(); + if(This->pbo == 0 || error != GL_NO_ERROR) { + ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error); + } + + TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + + GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB)); + checkGLcall("glBufferDataARB"); + + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + + /* We don't need the system memory anymore and we can't even use it for PBOs */ + if(!(This->Flags & SFLAG_CLIENT)) { + HeapFree(GetProcessHeap(), 0, This->resource.heapMemory); + This->resource.heapMemory = NULL; + } + This->resource.allocatedMemory = NULL; + This->Flags |= SFLAG_PBO; + LEAVE_GL(); + } else if(!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO)) { + /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy, + * or a pbo to map + */ + if(!This->resource.heapMemory) { + This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT); + } + This->resource.allocatedMemory = + (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); + if(This->Flags & SFLAG_INSYSMEM) { + ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n"); + } + } +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + IWineD3DSwapChain *swapchain = NULL; + + TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); + + /* This is also done in the base class, but we have to verify this before loading any data from + * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag + * may interfere, and all other bad things may happen + */ + if (This->Flags & SFLAG_LOCKED) { + WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + This->Flags |= SFLAG_LOCKED; + + if (!(This->Flags & SFLAG_LOCKABLE)) + { + TRACE("Warning: trying to lock unlockable surf@%p\n", This); + } + if (Flags & WINED3DLOCK_DISCARD) { /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */ TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n"); @@ -749,6 +814,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED if (This->Flags & SFLAG_INSYSMEM) { TRACE("Local copy is up to date, not downloading data\n"); + surface_prepare_system_memory(This); /* Makes sure memory is allocated */ goto lock_end; } @@ -758,69 +824,43 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED */ IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); if(swapchain || iface == myDevice->render_targets[0]) { - BOOL srcIsUpsideDown; + const RECT *pass_rect = pRect; - if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) { - static BOOL warned = FALSE; - if(!warned) { - ERR("The application tries to lock the render target, but render target locking is disabled\n"); - warned = TRUE; - } - if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); - return WINED3D_OK; - } - - /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect. - * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage - * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find - * context->last_was_blit set on the unlock. + /* IWineD3DSurface_LoadLocation does not check if the rectangle specifies the full surfaces + * because most caller functions do not need that. So do that here */ - ActivateContext(myDevice, iface, CTXUSAGE_BLIT); - ENTER_GL(); - - /* Select the correct read buffer, and give some debug output. - * There is no need to keep track of the current read buffer or reset it, every part of the code - * that reads sets the read buffer as desired. - */ - if(!swapchain) { - /* Locking the primary render target which is not on a swapchain(=offscreen render target). - * Read from the back buffer - */ - TRACE("Locking offscreen render target\n"); - glReadBuffer(myDevice->offscreenBuffer); - srcIsUpsideDown = TRUE; - } else { - GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain); - TRACE("Locking %#x buffer\n", buffer); - glReadBuffer(buffer); - checkGLcall("glReadBuffer"); - - IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); - srcIsUpsideDown = FALSE; + if(pRect && + pRect->top == 0 && + pRect->left == 0 && + pRect->right == This->currentDesc.Width && + pRect->bottom == This->currentDesc.Height) { + pass_rect = NULL; } switch(wined3d_settings.rendertargetlock_mode) { + case RTL_TEXDRAW: + case RTL_TEXTEX: + FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n"); +#if 0 + /* Disabled for now. LoadLocation prefers the texture over the drawable as the source. So if we copy to the + * texture first, then to sysmem, we'll avoid glReadPixels and use glCopyTexImage and glGetTexImage2D instead. + * This may be faster on some cards + */ + IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* No partial texture copy yet */); +#endif + /* drop through */ + case RTL_AUTO: case RTL_READDRAW: case RTL_READTEX: - read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown); + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pRect); break; - case RTL_TEXDRAW: - case RTL_TEXTEX: - read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown); - FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n"); + case RTL_DISABLE: break; } - LEAVE_GL(); + if(swapchain) IWineD3DSwapChain_Release(swapchain); - /* Mark the local copy up to date if a full download was done */ - if(This->lockedRect.left == 0 && - This->lockedRect.top == 0 && - This->lockedRect.right == This->currentDesc.Width && - This->lockedRect.bottom == This->currentDesc.Height) { - This->Flags |= SFLAG_INSYSMEM; - } } else if(iface == myDevice->stencilBufferTarget) { /** the depth stencil in openGL has a format of GL_FLOAT * which should be good for WINED3DFMT_D16_LOCKABLE @@ -845,29 +885,31 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED } else { /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */ TRACE("locking an ordinary surface\n"); - - if (0 != This->glDescription.textureName) { - /* Now I have to copy thing bits back */ - - if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { - ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); - } - - ENTER_GL(); - /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */ - if (GL_SUPPORT(ARB_MULTITEXTURE)) { - GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); - checkGLcall("glActiveTextureARB"); - } - IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0)); - IWineD3DSurface_PreLoad(iface); - - surface_download_data(This); - LEAVE_GL(); - } + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */); } lock_end: + if(This->Flags & SFLAG_PBO) { + ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + + /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */ + if(This->resource.allocatedMemory) { + ERR("The surface already has PBO memory allocated!\n"); + } + + This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB)); + checkGLcall("glMapBufferARB"); + + /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */ + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + + LEAVE_GL(); + } + if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) { /* Don't dirtify */ } else { @@ -876,7 +918,7 @@ lock_end: * Dirtify on lock * as seen in msdn docs */ - IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect); + IWineD3DSurface_AddDirtyRect(iface, pRect); /** Dirtify Container if needed */ if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) { @@ -888,9 +930,7 @@ lock_end: } } - TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, - This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); - return WINED3D_OK; + return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags); } static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { @@ -902,6 +942,27 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { BYTE *mem; UINT bpp; UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */ + IWineD3DDeviceImpl *myDevice = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice; + IWineD3DSwapChainImpl *swapchain; + + /* Activate the correct context for the render target */ + ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT); + ENTER_GL(); + + IWineD3DSurface_GetContainer((IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain); + if(!swapchain) { + /* Primary offscreen render target */ + TRACE("Offscreen render target\n"); + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); + } else { + GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *) This, (IWineD3DSwapChain *)swapchain); + TRACE("Unlocking %#x buffer\n", buffer); + glDrawBuffer(buffer); + checkGLcall("glDrawBuffer"); + + IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain); + } glDisable(GL_TEXTURE_2D); vcheckGLcall("glDisable(GL_TEXTURE_2D)"); @@ -933,7 +994,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { * be any interfering gdi accesses, because UnlockRect is called from * ReleaseDC, and the app won't use the dc any more afterwards. */ - if(This->Flags & SFLAG_DIBSECTION) { + if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) { volatile BYTE read; read = This->resource.allocatedMemory[0]; } @@ -1035,7 +1096,7 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD)); if(!mem) { ERR("Out of memory\n"); - return; + goto cleanup; } memory_allocated = TRUE; d3dfmt_convert_surface(This->resource.allocatedMemory, @@ -1061,11 +1122,23 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { bpp = This->bytesPerPixel; } + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + checkGLcall("glBindBufferARB"); + } + glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1, fmt, type, mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top); checkGLcall("glDrawPixels"); + +cleanup: + if(This->Flags & SFLAG_PBO) { + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glBindBufferARB"); + } + glPixelZoom(1.0,1.0); vcheckGLcall("glPixelZoom"); @@ -1087,66 +1160,45 @@ static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { checkGLcall("glEnable(GL_TEXTURE_2D)"); if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem); - return; -} - -static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) { - float glTexCoord[4]; - - glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */ - glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */ - glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */ - glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */ - - IWineD3DSurface_PreLoad((IWineD3DSurface *) This); - - ENTER_GL(); - - glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName); - checkGLcall("glEnable glBindTexture"); - - /* No filtering for blts */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - checkGLcall("glTexParameteri"); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - checkGLcall("glTexParameteri"); - - /* Start drawing a quad */ - glBegin(GL_QUADS); - - glColor3d(1.0f, 1.0f, 1.0f); - glTexCoord2f(glTexCoord[0], glTexCoord[2]); - glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0); - - glTexCoord2f(glTexCoord[0], glTexCoord[3]); - glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0); - - glTexCoord2f(glTexCoord[1], glTexCoord[3]); - glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0); - - glTexCoord2f(glTexCoord[1], glTexCoord[2]); - glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0); - - glEnd(); - checkGLcall("glEnd"); - - /* Unbind the texture */ - glBindTexture(GL_TEXTURE_2D, 0); - checkGLcall("glEnable glBindTexture"); + if(!swapchain) { + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); + } else if(swapchain->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + } else { + glDrawBuffer(GL_FRONT); + checkGLcall("glDrawBuffer(GL_FRONT)"); + } LEAVE_GL(); + + return; } static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; IWineD3DSwapChainImpl *swapchain = NULL; + BOOL fullsurface; if (!(This->Flags & SFLAG_LOCKED)) { WARN("trying to Unlock an unlocked surf@%p\n", This); return WINED3DERR_INVALIDCALL; } + if (This->Flags & SFLAG_PBO) { + TRACE("Freeing PBO memory\n"); + ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo)); + GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)); + GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0)); + checkGLcall("glUnmapBufferARB"); + LEAVE_GL(); + This->resource.allocatedMemory = NULL; + } + TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) { @@ -1155,7 +1207,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { } IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); - if(swapchain || iface == myDevice->render_targets[0]) { + if(swapchain || (myDevice->render_targets && iface == myDevice->render_targets[0])) { if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) { static BOOL warned = FALSE; if(!warned) { @@ -1166,53 +1218,54 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { goto unlock_end; } - /* Activate the correct context for the render target */ - ActivateContext(myDevice, iface, CTXUSAGE_BLIT); - ENTER_GL(); - - if(!swapchain) { - /* Primary offscreen render target */ - TRACE("Offscreen render target\n"); - glDrawBuffer(myDevice->offscreenBuffer); - checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); + if(This->dirtyRect.left == 0 && + This->dirtyRect.top == 0 && + This->dirtyRect.right == This->currentDesc.Width && + This->dirtyRect.bottom == This->currentDesc.Height) { + fullsurface = TRUE; } else { - GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain); - TRACE("Unlocking %#x buffer\n", buffer); - glDrawBuffer(buffer); - checkGLcall("glDrawBuffer"); - - IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain); + /* TODO: Proper partial rectangle tracking */ + fullsurface = FALSE; + This->Flags |= SFLAG_INSYSMEM; } switch(wined3d_settings.rendertargetlock_mode) { + case RTL_READTEX: + case RTL_TEXTEX: + ActivateContext(myDevice, iface, CTXUSAGE_BLIT); + ENTER_GL(); + if (This->glDescription.textureName == 0) { + glGenTextures(1, &This->glDescription.textureName); + checkGLcall("glGenTextures"); + } + glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName); + checkGLcall("glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);"); + LEAVE_GL(); + IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */); + /* drop through */ + case RTL_AUTO: case RTL_READDRAW: case RTL_TEXDRAW: - flush_to_framebuffer_drawpixels(This); + IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect); break; + } - case RTL_READTEX: - case RTL_TEXTEX: - flush_to_framebuffer_texture(This); - break; + if(!fullsurface) { + /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite + * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where + * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy + * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is + * not fully up to date because only a subrectangle was read in LockRect. + */ + This->Flags &= ~SFLAG_INSYSMEM; + This->Flags |= SFLAG_INDRAWABLE; } - if(!swapchain) { - glDrawBuffer(myDevice->offscreenBuffer); - checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); - } else if(swapchain->backBuffer) { - glDrawBuffer(GL_BACK); - checkGLcall("glDrawBuffer(GL_BACK)"); - } else { - glDrawBuffer(GL_FRONT); - checkGLcall("glDrawBuffer(GL_FRONT)"); - } - LEAVE_GL(); This->dirtyRect.left = This->currentDesc.Width; This->dirtyRect.top = This->currentDesc.Height; This->dirtyRect.right = 0; This->dirtyRect.bottom = 0; - This->Flags |= SFLAG_INDRAWABLE; } else if(iface == myDevice->stencilBufferTarget) { FIXME("Depth Stencil buffer locking is not implemented\n"); } else { @@ -1239,13 +1292,8 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; WINED3DLOCKED_RECT lock; - UINT usage; - BITMAPINFO* b_info; - HDC ddc; - DWORD *masks; HRESULT hr; RGBQUAD col[256]; - const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL); TRACE("(%p)->(%p)\n",This,pHDC); @@ -1266,137 +1314,14 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { /* Create a DIB section if there isn't a hdc yet */ if(!This->hDC) { - int extraline = 0; - SYSTEM_INFO sysInfo; - void *oldmem = This->resource.allocatedMemory; - - switch (This->bytesPerPixel) { - case 2: - case 4: - /* Allocate extra space to store the RGB bit masks. */ - b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD)); - break; - - case 3: - b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER)); - break; - - default: - /* Allocate extra space for a palette. */ - b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(BITMAPINFOHEADER) - + sizeof(RGBQUAD) - * (1 << (This->bytesPerPixel * 8))); - break; - } - - if (!b_info) - return E_OUTOFMEMORY; - - /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the - * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size, - * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise - * add an extra line to the dib section - */ - GetSystemInfo(&sysInfo); - if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) { - extraline = 1; - TRACE("Adding an extra line to the dib section\n"); - } - - b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */ - b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel; - b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline; - b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface); - b_info->bmiHeader.biPlanes = 1; - b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8; - - b_info->bmiHeader.biXPelsPerMeter = 0; - b_info->bmiHeader.biYPelsPerMeter = 0; - b_info->bmiHeader.biClrUsed = 0; - b_info->bmiHeader.biClrImportant = 0; - - /* Get the bit masks */ - masks = (DWORD *) &(b_info->bmiColors); - switch (This->resource.format) { - case WINED3DFMT_R8G8B8: - usage = DIB_RGB_COLORS; - b_info->bmiHeader.biCompression = BI_RGB; - break; - - case WINED3DFMT_X1R5G5B5: - case WINED3DFMT_A1R5G5B5: - case WINED3DFMT_A4R4G4B4: - case WINED3DFMT_X4R4G4B4: - case WINED3DFMT_R3G3B2: - case WINED3DFMT_A8R3G3B2: - case WINED3DFMT_A2B10G10R10: - case WINED3DFMT_A8B8G8R8: - case WINED3DFMT_X8B8G8R8: - case WINED3DFMT_A2R10G10B10: - case WINED3DFMT_R5G6B5: - case WINED3DFMT_A16B16G16R16: - usage = 0; - b_info->bmiHeader.biCompression = BI_BITFIELDS; - masks[0] = formatEntry->redMask; - masks[1] = formatEntry->greenMask; - masks[2] = formatEntry->blueMask; - break; - - default: - /* Don't know palette */ - b_info->bmiHeader.biCompression = BI_RGB; - usage = 0; - break; - } - - ddc = GetDC(0); - if (ddc == 0) { - HeapFree(GetProcessHeap(), 0, b_info); - return HRESULT_FROM_WIN32(GetLastError()); - } - - TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage); - This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */); - ReleaseDC(0, ddc); - - if (!This->dib.DIBsection) { - ERR("CreateDIBSection failed!\n"); - HeapFree(GetProcessHeap(), 0, b_info); - return HRESULT_FROM_WIN32(GetLastError()); - } - - TRACE("DIBSection at : %p\n", This->dib.bitmap_data); - - /* copy the existing surface to the dib section */ - if(This->resource.allocatedMemory) { - memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage); - /* We won't need that any more */ - } else { - /* This is to make LockRect read the gl Texture although memory is allocated */ - This->Flags &= ~SFLAG_INSYSMEM; - } - - HeapFree(GetProcessHeap(), 0, b_info); - - /* Use the dib section from now on */ - This->resource.allocatedMemory = This->dib.bitmap_data; - - /* Now allocate a HDC */ - This->hDC = CreateCompatibleDC(0); - This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection); - TRACE("using wined3d palette %p\n", This->palette); - SelectPalette(This->hDC, - This->palette ? This->palette->hpal : 0, - FALSE); - - This->Flags |= SFLAG_DIBSECTION; - + IWineD3DBaseSurfaceImpl_CreateDIBSection(iface); if(This->Flags & SFLAG_CLIENT) { IWineD3DSurface_PreLoad(iface); } - HeapFree(GetProcessHeap(), 0, oldmem); + + /* Use the dib section from now on if we are not using a PBO */ + if(!(This->Flags & SFLAG_PBO)) + This->resource.allocatedMemory = This->dib.bitmap_data; } /* Lock the surface */ @@ -1404,6 +1329,12 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { &lock, NULL, 0); + + if(This->Flags & SFLAG_PBO) { + /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */ + memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size); + } + if(FAILED(hr)) { ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr); /* keep the dib section */ @@ -1452,6 +1383,16 @@ HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) { if (!(This->Flags & SFLAG_DCINUSE)) return WINED3DERR_INVALIDCALL; + if (This->hDC !=hDC) { + WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC); + return WINED3DERR_INVALIDCALL; + } + + if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) { + /* Copy the contents of the DIB over to the PBO */ + memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size); + } + /* we locked first, so unlock now */ IWineD3DSurface_UnlockRect(iface); @@ -1467,6 +1408,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) { HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp, BOOL srgb_mode) { BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT); const GlPixelFormatDesc *glDesc; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BOOL p8_render_target = FALSE; getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc); /* Default values: From the surface */ @@ -1482,10 +1425,18 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ /* **************** Paletted Texture **************** */ + + if (device->render_targets && device->render_targets[0]) { + IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0]; + if((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET) && (render_target->resource.format == WINED3DFMT_P8)) + p8_render_target = TRUE; + } + /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying. + * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which conflicts with this. */ - if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) { + if( !(GL_SUPPORT(EXT_PALETTED_TEXTURE) || (GL_SUPPORT(ARB_FRAGMENT_PROGRAM) && p8_render_target)) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) { *format = GL_RGBA; *internal = GL_RGBA; *type = GL_UNSIGNED_BYTE; @@ -1496,6 +1447,12 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ *convert = CONVERT_PALETTED; } } + else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { + *format = GL_RED; + *internal = GL_RGBA; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 1; + } break; @@ -1563,14 +1520,36 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ *target_bpp = 3; break; + case WINED3DFMT_L6V5U5: + *convert = CONVERT_L6V5U5; + if(GL_SUPPORT(NV_TEXTURE_SHADER)) { + *target_bpp = 3; + /* Use format and types from table */ + } else { + /* Load it into unsigned R5G6B5, swap L and V channels, and revert that in the shader */ + *target_bpp = 2; + *format = GL_RGB; + *internal = GL_RGB5; + *type = GL_UNSIGNED_SHORT_5_6_5; + } + break; + case WINED3DFMT_X8L8V8U8: - if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; *convert = CONVERT_X8L8V8U8; - *format = GL_BGRA; - *internal = GL_RGBA8; - *type = GL_UNSIGNED_BYTE; *target_bpp = 4; - /* Not supported by GL_ATI_envmap_bumpmap */ + if(GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* Use formats from gl table. It is a bit unfortunate, but the conversion + * is needed to set the X format to 255 to get 1.0 for alpha when sampling + * the texture. OpenGL can't use GL_DSDT8_MAG8_NV as internal format with + * the needed type and format parameter, so the internal format contains a + * 4th component, which is returned as alpha + */ + } else { + /* Not supported by GL_ATI_envmap_bumpmap */ + *format = GL_BGRA; + *internal = GL_RGB8; + *type = GL_UNSIGNED_INT_8_8_8_8_REV; + } break; case WINED3DFMT_Q8W8V8U8: @@ -1587,8 +1566,8 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; *convert = CONVERT_V16U16; *format = GL_BGR; - *internal = GL_RGB16; - *type = GL_SHORT; + *internal = GL_RGB16_EXT; + *type = GL_UNSIGNED_SHORT; *target_bpp = 6; /* What should I do here about GL_ATI_envmap_bumpmap? * Convert it or allow data loss by loading it into a 8 bit / channel texture? @@ -1623,7 +1602,7 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ break; case WINED3DFMT_R16F: - /* Simmilar to R32F */ + /* Similar to R32F */ *convert = CONVERT_R16F; *format = GL_RGB; *internal = GL_RGB16F_ARB; @@ -1638,9 +1617,9 @@ HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_ return WINED3D_OK; } -HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) { +HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This) { BYTE *source, *dest; - TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf); + TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This); switch (convert) { case NO_CONVERSION: @@ -1651,56 +1630,15 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN case CONVERT_PALETTED: case CONVERT_PALETTED_CK: { - IWineD3DPaletteImpl* pal = surf->palette; + IWineD3DPaletteImpl* pal = This->palette; BYTE table[256][4]; - unsigned int i; unsigned int x, y; if( pal == NULL) { /* TODO: If we are a sublevel, try to get the palette from level 0 */ } - if (pal == NULL) { - /* Still no palette? Use the device's palette */ - /* Get the surface's palette */ - for (i = 0; i < 256; i++) { - IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice; - - table[i][0] = device->palettes[device->currentPalette][i].peRed; - table[i][1] = device->palettes[device->currentPalette][i].peGreen; - table[i][2] = device->palettes[device->currentPalette][i].peBlue; - if ((convert == CONVERT_PALETTED_CK) && - (i >= surf->SrcBltCKey.dwColorSpaceLowValue) && - (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) { - /* We should maybe here put a more 'neutral' color than the standard bright purple - one often used by application to prevent the nice purple borders when bi-linear - filtering is on */ - table[i][3] = 0x00; - } else { - table[i][3] = 0xFF; - } - } - } else { - TRACE("Using surface palette %p\n", pal); - /* Get the surface's palette */ - for (i = 0; i < 256; i++) { - table[i][0] = pal->palents[i].peRed; - table[i][1] = pal->palents[i].peGreen; - table[i][2] = pal->palents[i].peBlue; - if ((convert == CONVERT_PALETTED_CK) && - (i >= surf->SrcBltCKey.dwColorSpaceLowValue) && - (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) { - /* We should maybe here put a more 'neutral' color than the standard bright purple - one often used by application to prevent the nice purple borders when bi-linear - filtering is on */ - table[i][3] = 0x00; - } else if(pal->Flags & WINEDDPCAPS_ALPHA) { - table[i][3] = pal->palents[i].peFlags; - } else { - table[i][3] = 0xFF; - } - } - } + d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK)); for (y = 0; y < height; y++) { @@ -1742,8 +1680,8 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN for (x = 0; x < width; x++ ) { WORD color = *Source++; *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1)); - if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) || - (color > surf->SrcBltCKey.dwColorSpaceHighValue)) { + if ((color < This->SrcBltCKey.dwColorSpaceLowValue) || + (color > This->SrcBltCKey.dwColorSpaceHighValue)) { *Dest |= 0x0001; } Dest++; @@ -1765,8 +1703,8 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN for (x = 0; x < width; x++ ) { WORD color = *Source++; *Dest = color; - if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) || - (color > surf->SrcBltCKey.dwColorSpaceHighValue)) { + if ((color < This->SrcBltCKey.dwColorSpaceLowValue) || + (color > This->SrcBltCKey.dwColorSpaceHighValue)) { *Dest |= (1 << 15); } else { @@ -1797,6 +1735,25 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN break; } + case CONVERT_V16U16: + { + unsigned int x, y; + DWORD *Source; + unsigned short *Dest; + for(y = 0; y < height; y++) { + Source = (DWORD *) (src + y * pitch); + Dest = (unsigned short *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + DWORD color = (*Source++); + /* B */ Dest[0] = 0xffff; + /* G */ Dest[1] = (color >> 16) + 32768; /* V */ + /* R */ Dest[2] = (color ) + 32768; /* U */ + Dest += 3; + } + } + break; + } + case CONVERT_Q8W8V8U8: { unsigned int x, y; @@ -1817,6 +1774,102 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN break; } + case CONVERT_L6V5U5: + { + unsigned int x, y; + WORD *Source; + unsigned char *Dest; + + if(GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* This makes the gl surface bigger(24 bit instead of 16), but it works with + * fixed function and shaders without further conversion once the surface is + * loaded + */ + for(y = 0; y < height; y++) { + Source = (WORD *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + short color = (*Source++); + unsigned char l = ((color >> 10) & 0xfc); + char v = ((color >> 5) & 0x3e); + char u = ((color ) & 0x1f); + + /* 8 bits destination, 6 bits source, 8th bit is the sign. gl ignores the sign + * and doubles the positive range. Thus shift left only once, gl does the 2nd + * shift. GL reads a signed value and converts it into an unsigned value. + */ + /* M */ Dest[2] = l << 1; + + /* Those are read as signed, but kept signed. Just left-shift 3 times to scale + * from 5 bit values to 8 bit values. + */ + /* V */ Dest[1] = v << 3; + /* U */ Dest[0] = u << 3; + Dest += 3; + } + } + } else { + for(y = 0; y < height; y++) { + unsigned short *Dest_s = (unsigned short *) (dst + y * outpitch); + Source = (WORD *) (src + y * pitch); + for (x = 0; x < width; x++ ) { + short color = (*Source++); + unsigned char l = ((color >> 10) & 0xfc); + short v = ((color >> 5) & 0x3e); + short u = ((color ) & 0x1f); + short v_conv = v + 16; + short u_conv = u + 16; + + *Dest_s = ((v_conv << 11) & 0xf800) | ((l << 5) & 0x7e0) | (u_conv & 0x1f); + Dest_s += 1; + } + } + } + break; + } + + case CONVERT_X8L8V8U8: + { + unsigned int x, y; + DWORD *Source; + unsigned char *Dest; + + if(GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* This implementation works with the fixed function pipeline and shaders + * without further modification after converting the surface. + */ + for(y = 0; y < height; y++) { + Source = (DWORD *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + long color = (*Source++); + /* L */ Dest[2] = ((color >> 16) & 0xff); /* L */ + /* V */ Dest[1] = ((color >> 8 ) & 0xff); /* V */ + /* U */ Dest[0] = (color & 0xff); /* U */ + /* I */ Dest[3] = 255; /* X */ + Dest += 4; + } + } + } else { + /* Doesn't work correctly with the fixed function pipeline, but can work in + * shaders if the shader is adjusted. (There's no use for this format in gl's + * standard fixed function pipeline anyway). + */ + for(y = 0; y < height; y++) { + Source = (DWORD *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + long color = (*Source++); + /* B */ Dest[0] = ((color >> 16) & 0xff); /* L */ + /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */ + /* R */ Dest[2] = (color & 0xff) + 128; /* U */ + Dest += 4; + } + } + } + break; + } + case CONVERT_A4L4: { unsigned int x, y; @@ -1879,26 +1932,35 @@ HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UIN return WINED3D_OK; } -/* This function is used in case of 8bit paletted textures to upload the palette. - For now it only supports GL_EXT_paletted_texture extension but support for other - extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well. -*/ -static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; +static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey) { IWineD3DPaletteImpl* pal = This->palette; - BYTE table[256][4]; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BOOL index_in_alpha = FALSE; int i; + /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets. + * Reading back the RGB output each lockrect (each frame as they lock the whole screen) + * is slow. Further RGB->P8 conversion is not possible because palettes can have + * duplicate entries. Store the color key in the unused alpha component to speed the + * download up and to make conversion unneeded. */ + if (device->render_targets && device->render_targets[0]) { + IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0]; + + if(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET) + index_in_alpha = TRUE; + } + if (pal == NULL) { /* Still no palette? Use the device's palette */ /* Get the surface's palette */ for (i = 0; i < 256; i++) { - IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - table[i][0] = device->palettes[device->currentPalette][i].peRed; table[i][1] = device->palettes[device->currentPalette][i].peGreen; table[i][2] = device->palettes[device->currentPalette][i].peBlue; - if ((convert == CONVERT_PALETTED_CK) && + + if(index_in_alpha) { + table[i][3] = i; + } else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue) && (i <= This->SrcBltCKey.dwColorSpaceHighValue)) { /* We should maybe here put a more 'neutral' color than the standard bright purple @@ -1916,7 +1978,11 @@ static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES conve table[i][0] = pal->palents[i].peRed; table[i][1] = pal->palents[i].peGreen; table[i][2] = pal->palents[i].peBlue; - if ((convert == CONVERT_PALETTED_CK) && + + if(index_in_alpha) { + table[i][3] = i; + } + else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue) && (i <= This->SrcBltCKey.dwColorSpaceHighValue)) { /* We should maybe here put a more 'neutral' color than the standard bright purple @@ -1930,7 +1996,68 @@ static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES conve } } } - GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table)); +} + +const char *fragment_palette_conversion = + "!!ARBfp1.0\n" + "TEMP index;\n" + "PARAM constants = { 0.996, 0.00195, 0, 0 };\n" /* { 255/256, 0.5/255*255/256, 0, 0 } */ + "TEX index.x, fragment.texcoord[0], texture[0], 2D;\n" /* store the red-component of the current pixel */ + "MAD index.x, index.x, constants.x, constants.y;\n" /* Scale the index by 255/256 and add a bias of '0.5' in order to sample in the middle */ + "TEX result.color, index, texture[1], 1D;\n" /* use the red-component as a index in the palette to get the final color */ + "END"; + +/* This function is used in case of 8bit paletted textures to upload the palette. + It supports GL_EXT_paletted_texture and GL_ARB_fragment_program, support for other + extensions like ATI_fragment_shaders is possible. +*/ +static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + BYTE table[256][4]; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK)); + + /* Try to use the paletted texture extension */ + if(GL_SUPPORT(EXT_PALETTED_TEXTURE)) + { + TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n"); + GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table)); + } + else + { + /* Let a fragment shader do the color conversion by uploading the palette to a 1D texture. + * The 8bit pixel data will be used as an index in this palette texture to retrieve the final color. */ + TRACE("Using fragment shaders for emulating 8-bit paletted texture support\n"); + + /* Create the fragment program if we don't have it */ + if(!device->paletteConversionShader) + { + glEnable(GL_FRAGMENT_PROGRAM_ARB); + GL_EXTCALL(glGenProgramsARB(1, &device->paletteConversionShader)); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader)); + GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragment_palette_conversion), (const GLbyte *)fragment_palette_conversion)); + glDisable(GL_FRAGMENT_PROGRAM_ARB); + } + + glEnable(GL_FRAGMENT_PROGRAM_ARB); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader)); + + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1)); + glEnable(GL_TEXTURE_1D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /* Make sure we have discrete color levels. */ + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, table); /* Upload the palette */ + + /* Switch back to unit 0 in which the 2D texture will be stored. */ + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0)); + + /* Rebind the texture because it isn't bound anymore */ + glBindTexture(This->glDescription.target, This->glDescription.textureName); + } } static BOOL palette9_changed(IWineD3DSurfaceImpl *This) { @@ -1954,14 +2081,43 @@ static BOOL palette9_changed(IWineD3DSurfaceImpl *This) { return TRUE; } +static inline void clear_unused_channels(IWineD3DSurfaceImpl *This) { + GLboolean oldwrite[4]; + + /* Some formats have only some color channels, and the others are 1.0. + * since our rendering renders to all channels, and those pixel formats + * are emulated by using a full texture with the other channels set to 1.0 + * manually, clear the unused channels. + * + * This could be done with hacking colorwriteenable to mask the colors, + * but before drawing the buffer would have to be cleared too, so there's + * no gain in that + */ + switch(This->resource.format) { + case WINED3DFMT_R16F: + case WINED3DFMT_R32F: + TRACE("R16F or R32F format, clearing green, blue and alpha to 1.0\n"); + /* Do not activate a context, the correct drawable is active already + * though just the read buffer is set, make sure to have the correct draw + * buffer too + */ + glDrawBuffer(This->resource.wineD3DDevice->offscreenBuffer); + glDisable(GL_SCISSOR_TEST); + glGetBooleanv(GL_COLOR_WRITEMASK, oldwrite); + glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(0.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glColorMask(oldwrite[0], oldwrite[1], oldwrite[2], oldwrite[3]); + if(!This->resource.wineD3DDevice->render_offscreen) glDrawBuffer(GL_BACK); + checkGLcall("Unused channel clear\n"); + break; + + default: break; + } +} + static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - GLenum format, internal, type; - CONVERT_TYPES convert; - int bpp; - int width, pitch, outpitch; - BYTE *mem; if (!(This->Flags & SFLAG_INTEXTURE)) { TRACE("Reloading because surface is dirty\n"); @@ -1974,136 +2130,32 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BO (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) || (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) { TRACE("Reloading because of color keying\n"); + /* To perform the color key conversion we need a sysmem copy of + * the surface. Make sure we have it + */ + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL); } else if(palette9_changed(This)) { TRACE("Reloading surface because the d3d8/9 palette was changed\n"); + /* TODO: This is not necessarily needed with hw palettized texture support */ + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL); } else { TRACE("surface is already in texture\n"); return WINED3D_OK; } - This->Flags |= SFLAG_INTEXTURE; - /* Resources are placed in system RAM and do not need to be recreated when a device is lost. - * These resources are not bound by device size or format restrictions. Because of this, - * these resources cannot be accessed by the Direct3D device nor set as textures or render targets. - * However, these resources can always be created, locked, and copied. - */ + * These resources are not bound by device size or format restrictions. Because of this, + * these resources cannot be accessed by the Direct3D device nor set as textures or render targets. + * However, these resources can always be created, locked, and copied. + */ if (This->resource.pool == WINED3DPOOL_SCRATCH ) { FIXME("(%p) Operation not supported for scratch textures\n",This); return WINED3DERR_INVALIDCALL; } - d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb_mode); - - if (This->Flags & SFLAG_INDRAWABLE) { - if (This->glDescription.level != 0) - FIXME("Surface in texture is only supported for level 0\n"); - else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 || - This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || - This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 || - This->resource.format == WINED3DFMT_DXT5) - FIXME("Format %d not supported\n", This->resource.format); - else { - GLint prevRead; - - ENTER_GL(); - glGetIntegerv(GL_READ_BUFFER, &prevRead); - vcheckGLcall("glGetIntegerv"); - glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer); - vcheckGLcall("glReadBuffer"); - - if(!(This->Flags & SFLAG_ALLOCATED)) { - surface_allocate_surface(This, internal, This->pow2Width, - This->pow2Height, format, type); - } - - glCopyTexSubImage2D(This->glDescription.target, - This->glDescription.level, - 0, 0, 0, 0, - This->currentDesc.Width, - This->currentDesc.Height); - checkGLcall("glCopyTexSubImage2D"); - - glReadBuffer(prevRead); - vcheckGLcall("glReadBuffer"); - - LEAVE_GL(); - - TRACE("Updated target %d\n", This->glDescription.target); - } - return WINED3D_OK; - } else - /* The only place where LoadTexture() might get called when isInDraw=1 - * is ActivateContext where lastActiveRenderTarget is preloaded. - */ - if(iface == device->lastActiveRenderTarget && device->isInDraw) - ERR("Reading back render target but SFLAG_INDRAWABLE not set\n"); - - /* Otherwise: System memory copy must be most up to date */ - - if(This->CKeyFlags & WINEDDSD_CKSRCBLT) { - This->Flags |= SFLAG_GLCKEY; - This->glCKey = This->SrcBltCKey; - } - else This->Flags &= ~SFLAG_GLCKEY; - - /* The width is in 'length' not in bytes */ - width = This->currentDesc.Width; - pitch = IWineD3DSurface_GetPitch(iface); - - if((convert != NO_CONVERSION) && This->resource.allocatedMemory) { - int height = This->currentDesc.Height; - - /* Stick to the alignment for the converted surface too, makes it easier to load the surface */ - outpitch = width * bpp; - outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); - - mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height); - if(!mem) { - ERR("Out of memory %d, %d!\n", outpitch, height); - return WINED3DERR_OUTOFVIDEOMEMORY; - } - d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This); - - This->Flags |= SFLAG_CONVERTED; - } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) { - d3dfmt_p8_upload_palette(iface, convert); - This->Flags &= ~SFLAG_CONVERTED; - mem = This->resource.allocatedMemory; - } else { - This->Flags &= ~SFLAG_CONVERTED; - mem = This->resource.allocatedMemory; - } - - /* Make sure the correct pitch is used */ - glPixelStorei(GL_UNPACK_ROW_LENGTH, width); - - if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) { - TRACE("non power of two support\n"); - if(!(This->Flags & SFLAG_ALLOCATED)) { - surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type); - } - if (mem) { - surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem); - } - } else { - /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory - * changed. So also keep track of memory changes. In this case the texture has to be reallocated - */ - if(!(This->Flags & SFLAG_ALLOCATED)) { - surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type); - } - if (mem) { - surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem); - } - } - - /* Restore the default pitch */ - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - if (mem != This->resource.allocatedMemory) - HeapFree(GetProcessHeap(), 0, mem); + This->srgb = srgb_mode; + IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* no partial locking for textures yet */); #if 0 { @@ -2125,9 +2177,10 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BO #endif if (!(This->Flags & SFLAG_DONOTFREE)) { - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + HeapFree(GetProcessHeap(), 0, This->resource.heapMemory); This->resource.allocatedMemory = NULL; - This->Flags &= ~SFLAG_INSYSMEM; + This->resource.heapMemory = NULL; + IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE); } return WINED3D_OK; @@ -2284,10 +2337,11 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const ch extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; IWineD3DBaseTexture *baseTexture = NULL; - if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE)) - surface_download_data(This); - This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE); + if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE)) + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */); + + IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE); if (NULL != pDirtyRect) { This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left); This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top); @@ -2310,76 +2364,30 @@ extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, C return WINED3D_OK; } -HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - - TRACE("This %p, container %p\n", This, container); - - /* We can't keep a reference to the container, since the container already keeps a reference to us. */ - - TRACE("Setting container to %p from %p\n", container, This->container); - This->container = container; - - return WINED3D_OK; -} - HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + HRESULT hr; const GlPixelFormatDesc *glDesc; - const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc); + getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc); - if (This->resource.format != WINED3DFMT_UNKNOWN) { - FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This); - return WINED3DERR_INVALIDCALL; + TRACE("(%p) : Calling base function first\n", This); + hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format); + if(SUCCEEDED(hr)) { + /* Setup some glformat defaults */ + This->glDescription.glFormat = glDesc->glFormat; + This->glDescription.glFormatInternal = glDesc->glInternal; + This->glDescription.glType = glDesc->glType; + + This->Flags &= ~SFLAG_ALLOCATED; + TRACE("(%p) : glFormat %d, glFotmatInternal %d, glType %d\n", This, + This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType); } - - TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format)); - if (format == WINED3DFMT_UNKNOWN) { - This->resource.size = 0; - } else if (format == WINED3DFMT_DXT1) { - /* DXT1 is half byte per pixel */ - This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1; - - } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 || - format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) { - This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)); - } else { - unsigned char alignment = This->resource.wineD3DDevice->surface_alignment; - This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1); - This->resource.size *= This->pow2Height; - } - - - /* Setup some glformat defaults */ - This->glDescription.glFormat = glDesc->glFormat; - This->glDescription.glFormatInternal = glDesc->glInternal; - This->glDescription.glType = glDesc->glType; - - if (format != WINED3DFMT_UNKNOWN) { - This->bytesPerPixel = formatEntry->bpp; - } else { - This->bytesPerPixel = 0; - } - - This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0; - This->Flags &= ~SFLAG_ALLOCATED; - - This->resource.format = format; - - TRACE("(%p) : Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType); - - return WINED3D_OK; + return hr; } HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */ - if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { - ERR("Not supported on render targets\n"); - return WINED3DERR_INVALIDCALL; - } - if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) { WARN("Surface is locked or the HDC is in use\n"); return WINED3DERR_INVALIDCALL; @@ -2403,13 +2411,14 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { This->hDC = NULL; This->Flags &= ~SFLAG_DIBSECTION; } else if(!(This->Flags & SFLAG_USERPTR)) { - release = This->resource.allocatedMemory; + release = This->resource.heapMemory; + This->resource.heapMemory = NULL; } This->resource.allocatedMemory = Mem; This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM; /* Now the surface memory is most up do date. Invalidate drawable and texture */ - This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE); + IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE); /* For client textures opengl has to be notified */ if(This->Flags & SFLAG_CLIENT) { @@ -2423,6 +2432,8 @@ HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { } else if(This->Flags & SFLAG_USERPTR) { /* Lockrect and GetDC will re-create the dib section and allocated memory */ This->resource.allocatedMemory = NULL; + /* HeapMemory should be NULL already */ + if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n"); This->Flags &= ~SFLAG_USERPTR; if(This->Flags & SFLAG_CLIENT) { @@ -2759,9 +2770,17 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx); /* Get the swapchain. One of the surfaces has to be a primary surface */ + if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) { + WARN("Destination is in sysmem, rejecting gl blt\n"); + return WINED3DERR_INVALIDCALL; + } IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain); if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain); if(Src) { + if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) { + WARN("Src is in sysmem, rejecting gl blt\n"); + return WINED3DERR_INVALIDCALL; + } IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain); if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain); } @@ -2977,15 +2996,16 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * } if(!(This->Flags & SFLAG_DONOTFREE)) { - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + HeapFree(GetProcessHeap(), 0, This->resource.heapMemory); This->resource.allocatedMemory = NULL; + This->resource.heapMemory = NULL; } else { This->Flags &= ~SFLAG_INSYSMEM; } /* The texture is now most up to date - If the surface is a render target and has a drawable, this * path is never entered */ - This->Flags |= SFLAG_INTEXTURE; + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE); return WINED3D_OK; } else if(Src) { @@ -3129,14 +3149,12 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * LEAVE_GL(); /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */ - This->Flags &= ~SFLAG_INSYSMEM; /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture * is outdated now */ - if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) { - This->Flags |= SFLAG_INDRAWABLE; - This->Flags &= ~SFLAG_INTEXTURE; - } else { + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE); + /* TODO: This should be moved to ModifyLocation() */ + if(!(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) { This->Flags |= SFLAG_INTEXTURE; } @@ -3229,15 +3247,36 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx) { IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + float depth; + + if (Flags & WINEDDBLT_DEPTHFILL) { + switch(This->resource.format) { + case WINED3DFMT_D16: + depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff; + break; + case WINED3DFMT_D15S1: + depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe; + break; + case WINED3DFMT_D24S8: + case WINED3DFMT_D24X8: + depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff; + break; + case WINED3DFMT_D32: + depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff; + break; + default: + depth = 0.0; + ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format)); + } - if (Flags & WINEDDBLT_DEPTHFILL) return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice, DestRect == NULL ? 0 : 1, (WINED3DRECT *) DestRect, WINED3DCLEAR_ZBUFFER, 0x00000000, - (float) DDBltFx->u5.dwFillDepth / (float) MAXDWORD, + depth, 0x00000000); + } FIXME("(%p): Unsupp depthstencil blit\n", This); return WINED3DERR_INVALIDCALL; @@ -3273,53 +3312,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *Dest * For RenderTargets this should be implemented OpenGL accelerated in BltOverride, * other Blts are rather rare */ - return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - TRACE("(%p)->(%x)\n", This, Flags); - - switch (Flags) - { - case WINEDDGBS_CANBLT: - case WINEDDGBS_ISBLTDONE: - return WINED3D_OK; - - default: - return WINED3DERR_INVALIDCALL; - } -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) { - /* XXX: DDERR_INVALIDSURFACETYPE */ - - TRACE("(%p)->(%08x)\n",iface,Flags); - switch (Flags) { - case WINEDDGFS_CANFLIP: - case WINEDDGFS_ISFLIPDONE: - return WINED3D_OK; - - default: - return WINED3DERR_INVALIDCALL; - } -} - -HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)\n", This); - - /* D3D8 and 9 loose full devices, ddraw only surfaces */ - return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)\n", This); - - /* So far we don't lose anything :) */ - This->Flags &= ~SFLAG_LOST; - return WINED3D_OK; + return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter); } HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) { @@ -3373,141 +3366,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, D } - return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)->(%p)\n", This, Pal); - - *Pal = (IWineD3DPalette *) This->palette; - return WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - RGBQUAD col[256]; - IWineD3DPaletteImpl *pal = This->palette; - unsigned int n; - TRACE("(%p)\n", This); - - if(This->resource.format == WINED3DFMT_P8 || - This->resource.format == WINED3DFMT_A8P8) - { - if(!This->Flags & SFLAG_INSYSMEM) { - FIXME("Palette changed with surface that does not have an up to date system memory copy\n"); - } - TRACE("Dirtifying surface\n"); - This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE); - } - - if(This->Flags & SFLAG_DIBSECTION) { - TRACE("(%p): Updating the hdc's palette\n", This); - for (n=0; n<256; n++) { - if(pal) { - col[n].rgbRed = pal->palents[n].peRed; - col[n].rgbGreen = pal->palents[n].peGreen; - col[n].rgbBlue = pal->palents[n].peBlue; - } else { - IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - /* Use the default device palette */ - col[n].rgbRed = device->palettes[device->currentPalette][n].peRed; - col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen; - col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue; - } - col[n].rgbReserved = 0; - } - SetDIBColorTable(This->hDC, 0, 256, col); - } - - return WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal; - TRACE("(%p)->(%p)\n", This, Pal); - - if(This->palette != NULL) - if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) - This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE; - - if(PalImpl != NULL) { - if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { - /* Set the device's main palette if the palette - * wasn't a primary palette before - */ - if(!(PalImpl->Flags & WINEDDPCAPS_PRIMARYSURFACE)) { - IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - unsigned int i; - - for(i=0; i < 256; i++) { - device->palettes[device->currentPalette][i] = PalImpl->palents[i]; - } - } - - (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE; - } - } - This->palette = PalImpl; - - return IWineD3DSurface_RealizePalette(iface); -} - -HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey); - - if ((Flags & WINEDDCKEY_COLORSPACE) != 0) { - FIXME(" colorkey value not supported (%08x) !\n", Flags); - return WINED3DERR_INVALIDCALL; - } - - /* Dirtify the surface, but only if a key was changed */ - if(CKey) { - switch (Flags & ~WINEDDCKEY_COLORSPACE) { - case WINEDDCKEY_DESTBLT: - This->DestBltCKey = *CKey; - This->CKeyFlags |= WINEDDSD_CKDESTBLT; - break; - - case WINEDDCKEY_DESTOVERLAY: - This->DestOverlayCKey = *CKey; - This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY; - break; - - case WINEDDCKEY_SRCOVERLAY: - This->SrcOverlayCKey = *CKey; - This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY; - break; - - case WINEDDCKEY_SRCBLT: - This->SrcBltCKey = *CKey; - This->CKeyFlags |= WINEDDSD_CKSRCBLT; - break; - } - } - else { - switch (Flags & ~WINEDDCKEY_COLORSPACE) { - case WINEDDCKEY_DESTBLT: - This->CKeyFlags &= ~WINEDDSD_CKDESTBLT; - break; - - case WINEDDCKEY_DESTOVERLAY: - This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY; - break; - - case WINEDDCKEY_SRCOVERLAY: - This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY; - break; - - case WINEDDCKEY_SRCBLT: - This->CKeyFlags &= ~WINEDDSD_CKSRCBLT; - break; - } - } - - return WINED3D_OK; + return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans); } static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { @@ -3579,167 +3438,405 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { This->glRect.bottom = This->pow2Height; } - if(This->resource.allocatedMemory == NULL) { - /* Make sure memory exists from the start, and it is initialized properly. D3D initializes surfaces, - * gl does not, so we need to upload zeroes to init the gl texture. - */ - This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4); - } This->Flags |= SFLAG_INSYSMEM; return WINED3D_OK; } -DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) { +static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - DWORD ret; - TRACE("(%p)\n", This); + IWineD3DBaseTexture *texture; - /* DXTn formats don't have exact pitches as they are to the new row of blocks, - where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5) - ie pitch = (width/4) * bytes per block */ - if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */ - ret = ((This->currentDesc.Width + 3) >> 2) << 3; - else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || - This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */ - ret = ((This->currentDesc.Width + 3) >> 2) << 4; - else { - unsigned char alignment = This->resource.wineD3DDevice->surface_alignment; - ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */ - ret = (ret + alignment - 1) & ~(alignment - 1); + TRACE("(%p)->(%s, %s)\n", iface, + flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE", + persistent ? "TRUE" : "FALSE"); + + /* TODO: For offscreen textures with fbo offscreen rendering the drawable is the same as the texture.*/ + if(persistent) { + if((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) { + if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) { + TRACE("Passing to container\n"); + IWineD3DBaseTexture_SetDirty(texture, TRUE); + IWineD3DBaseTexture_Release(texture); + } + } + This->Flags &= ~SFLAG_LOCATIONS; + This->Flags |= flag; + } else { + if((This->Flags & SFLAG_INTEXTURE) && (flag & SFLAG_INTEXTURE)) { + if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) { + TRACE("Passing to container\n"); + IWineD3DBaseTexture_SetDirty(texture, TRUE); + IWineD3DBaseTexture_Release(texture); + } + } + This->Flags &= ~flag; } - TRACE("(%p) Returning %d\n", This, ret); - return ret; } -HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; +struct coords { + int x, y, z; +}; - FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y); +static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in) { + struct coords coords[4]; + RECT rect; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) - { - TRACE("(%p): Not an overlay surface\n", This); - return WINEDDERR_NOTAOVERLAYSURFACE; + if(rect_in) { + rect = *rect_in; + } else { + rect.left = 0; + rect.top = 0; + rect.right = This->currentDesc.Width; + rect.bottom = This->currentDesc.Height; } - return WINED3D_OK; -} + ActivateContext(device, device->render_targets[0], CTXUSAGE_BLIT); + ENTER_GL(); -HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + if(This->glDescription.target == GL_TEXTURE_2D) { + glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName); + checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); - FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y); + coords[0].x = rect.left / This->pow2Width; + coords[0].z = 0; - if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) - { - TRACE("(%p): Not an overlay surface\n", This); - return WINEDDERR_NOTAOVERLAYSURFACE; + coords[1].x = rect.left / This->pow2Width; + coords[1].z = 0; + + coords[2].x = rect.right / This->pow2Width; + coords[2].z = 0; + + coords[3].x = rect.right / This->pow2Width; + coords[3].z = 0; + + coords[0].y = rect.top / This->pow2Height; + coords[1].y = rect.bottom / This->pow2Height; + coords[2].y = rect.bottom / This->pow2Height; + coords[3].y = rect.top / This->pow2Height; + } else { + /* Must be a cube map */ + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + glEnable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glEnable(GL_TEXTURE_CUBE_MAP_ARB)"); + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName); + checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)"); + glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + + switch(This->glDescription.target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + coords[0].x = 1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = 1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = -1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = -1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + coords[0].x = -1; coords[0].y = 1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = 1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = 1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = 1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + coords[0].x = -1; coords[0].y = -1; coords[0].z = -1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = -1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + + default: + ERR("Unexpected texture target\n"); + LEAVE_GL(); + return; + } } - return WINED3D_OK; + glBegin(GL_QUADS); + glTexCoord3iv((GLint *) &coords[0]); + glVertex2i(rect.left, device->render_offscreen ? rect.bottom : rect.top); + + glTexCoord3iv((GLint *) &coords[1]); + glVertex2i(0, device->render_offscreen ? rect.top : rect.bottom); + + glTexCoord3iv((GLint *) &coords[2]); + glVertex2i(rect.right, device->render_offscreen ? rect.top : rect.bottom); + + glTexCoord3iv((GLint *) &coords[3]); + glVertex2i(rect.right, device->render_offscreen ? rect.bottom : rect.top); + glEnd(); + checkGLcall("glEnd"); + + if(This->glDescription.target != GL_TEXTURE_2D) { + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable(GL_TEXTURE_2D)"); + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + LEAVE_GL(); } -HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) { +/***************************************************************************** + * IWineD3DSurface::LoadLocation + * + * Copies the current surface data from wherever it is to the requested + * location. The location is one of the surface flags, SFLAG_INSYSMEM, + * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in + * multiple locations, the gl texture is prefered over the drawable, which is + * prefered over system memory. The PBO counts as system memory. If rect is + * not NULL, only the specified rectangle is copied(only supported for + * sysmem<->drawable copies at the moment). If rect is NULL, the destination + * location is marked up to date after the copy. + * + * Parameters: + * flag: Surface location flag to be updated + * rect: rectangle to be copied + * + * Returns: + * WINED3D_OK on success + * WINED3DERR_DEVICELOST on an internal error + * + *****************************************************************************/ +static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + GLenum format, internal, type; + CONVERT_TYPES convert; + int bpp; + int width, pitch, outpitch; + BYTE *mem; - FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl); - - if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) - { - TRACE("(%p): Not an overlay surface\n", This); - return WINEDDERR_NOTAOVERLAYSURFACE; + TRACE("(%p)->(%s, %p)\n", iface, + flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE", + rect); + if(rect) { + TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom); } - return WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) { - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface; - FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX); - - if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) - { - TRACE("(%p): Not an overlay surface\n", This); - return WINEDDERR_NOTAOVERLAYSURFACE; + /* TODO: For fbo targets, texture == drawable */ + if(This->Flags & flag) { + TRACE("Location already up to date\n"); + return WINED3D_OK; } - return WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper) -{ - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)->(%p)\n", This, clipper); - - This->clipper = clipper; - return WINED3D_OK; -} - -HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper) -{ - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - TRACE("(%p)->(%p)\n", This, clipper); - - *clipper = This->clipper; - if(*clipper) { - IWineD3DClipper_AddRef(*clipper); + if(!(This->Flags & SFLAG_LOCATIONS)) { + ERR("Surface does not have any up to date location\n"); + This->Flags |= SFLAG_LOST; + return WINED3DERR_DEVICELOST; } + + if(flag == SFLAG_INSYSMEM) { + surface_prepare_system_memory(This); + + /* Download the surface to system memory */ + if(This->Flags & SFLAG_INTEXTURE) { + surface_download_data(This); + } else { + read_from_framebuffer(This, rect, + This->resource.allocatedMemory, + IWineD3DSurface_GetPitch(iface)); + } + } else if(flag == SFLAG_INDRAWABLE) { + if(This->Flags & SFLAG_INTEXTURE) { + surface_blt_to_drawable(This, rect); + } else { + flush_to_framebuffer_drawpixels(This); + } + } else /* if(flag == SFLAG_INTEXTURE) */ { + d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, This->srgb); + + if (This->Flags & SFLAG_INDRAWABLE) { + GLint prevRead; + + ENTER_GL(); + glGetIntegerv(GL_READ_BUFFER, &prevRead); + vcheckGLcall("glGetIntegerv"); + glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer); + vcheckGLcall("glReadBuffer"); + + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->pow2Width, + This->pow2Height, format, type); + } + + clear_unused_channels(This); + + glCopyTexSubImage2D(This->glDescription.target, + This->glDescription.level, + 0, 0, 0, 0, + This->currentDesc.Width, + This->currentDesc.Height); + checkGLcall("glCopyTexSubImage2D"); + + glReadBuffer(prevRead); + vcheckGLcall("glReadBuffer"); + + LEAVE_GL(); + + TRACE("Updated target %d\n", This->glDescription.target); + } else { + /* The only place where LoadTexture() might get called when isInDraw=1 + * is ActivateContext where lastActiveRenderTarget is preloaded. + */ + if(iface == device->lastActiveRenderTarget && device->isInDraw) + ERR("Reading back render target but SFLAG_INDRAWABLE not set\n"); + + /* Otherwise: System memory copy must be most up to date */ + + if(This->CKeyFlags & WINEDDSD_CKSRCBLT) { + This->Flags |= SFLAG_GLCKEY; + This->glCKey = This->SrcBltCKey; + } + else This->Flags &= ~SFLAG_GLCKEY; + + /* The width is in 'length' not in bytes */ + width = This->currentDesc.Width; + pitch = IWineD3DSurface_GetPitch(iface); + + if((convert != NO_CONVERSION) && This->resource.allocatedMemory) { + int height = This->currentDesc.Height; + + /* Stick to the alignment for the converted surface too, makes it easier to load the surface */ + outpitch = width * bpp; + outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); + + mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height); + if(!mem) { + ERR("Out of memory %d, %d!\n", outpitch, height); + return WINED3DERR_OUTOFVIDEOMEMORY; + } + d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This); + + This->Flags |= SFLAG_CONVERTED; + } else if( (This->resource.format == WINED3DFMT_P8) && (GL_SUPPORT(EXT_PALETTED_TEXTURE) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) ) { + d3dfmt_p8_upload_palette(iface, convert); + This->Flags &= ~SFLAG_CONVERTED; + mem = This->resource.allocatedMemory; + } else { + This->Flags &= ~SFLAG_CONVERTED; + mem = This->resource.allocatedMemory; + } + + /* Make sure the correct pitch is used */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + + if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) { + TRACE("non power of two support\n"); + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type); + } + if (mem || (This->Flags & SFLAG_PBO)) { + surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem); + } + } else { + /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory + * changed. So also keep track of memory changes. In this case the texture has to be reallocated + */ + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type); + } + if (mem || (This->Flags & SFLAG_PBO)) { + surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem); + } + } + + /* Restore the default pitch */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + /* Don't delete PBO memory */ + if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO)) + HeapFree(GetProcessHeap(), 0, mem); + } + } + + if(rect == NULL) { + This->Flags |= flag; + } + return WINED3D_OK; } const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl = { /* IUnknown */ - IWineD3DSurfaceImpl_QueryInterface, - IWineD3DSurfaceImpl_AddRef, + IWineD3DBaseSurfaceImpl_QueryInterface, + IWineD3DBaseSurfaceImpl_AddRef, IWineD3DSurfaceImpl_Release, /* IWineD3DResource */ - IWineD3DSurfaceImpl_GetParent, - IWineD3DSurfaceImpl_GetDevice, - IWineD3DSurfaceImpl_SetPrivateData, - IWineD3DSurfaceImpl_GetPrivateData, - IWineD3DSurfaceImpl_FreePrivateData, - IWineD3DSurfaceImpl_SetPriority, - IWineD3DSurfaceImpl_GetPriority, + IWineD3DBaseSurfaceImpl_GetParent, + IWineD3DBaseSurfaceImpl_GetDevice, + IWineD3DBaseSurfaceImpl_SetPrivateData, + IWineD3DBaseSurfaceImpl_GetPrivateData, + IWineD3DBaseSurfaceImpl_FreePrivateData, + IWineD3DBaseSurfaceImpl_SetPriority, + IWineD3DBaseSurfaceImpl_GetPriority, IWineD3DSurfaceImpl_PreLoad, - IWineD3DSurfaceImpl_GetType, + IWineD3DBaseSurfaceImpl_GetType, /* IWineD3DSurface */ - IWineD3DSurfaceImpl_GetContainer, - IWineD3DSurfaceImpl_GetDesc, + IWineD3DBaseSurfaceImpl_GetContainer, + IWineD3DBaseSurfaceImpl_GetDesc, IWineD3DSurfaceImpl_LockRect, IWineD3DSurfaceImpl_UnlockRect, IWineD3DSurfaceImpl_GetDC, IWineD3DSurfaceImpl_ReleaseDC, IWineD3DSurfaceImpl_Flip, IWineD3DSurfaceImpl_Blt, - IWineD3DSurfaceImpl_GetBltStatus, - IWineD3DSurfaceImpl_GetFlipStatus, - IWineD3DSurfaceImpl_IsLost, - IWineD3DSurfaceImpl_Restore, + IWineD3DBaseSurfaceImpl_GetBltStatus, + IWineD3DBaseSurfaceImpl_GetFlipStatus, + IWineD3DBaseSurfaceImpl_IsLost, + IWineD3DBaseSurfaceImpl_Restore, IWineD3DSurfaceImpl_BltFast, - IWineD3DSurfaceImpl_GetPalette, - IWineD3DSurfaceImpl_SetPalette, - IWineD3DSurfaceImpl_RealizePalette, - IWineD3DSurfaceImpl_SetColorKey, - IWineD3DSurfaceImpl_GetPitch, + IWineD3DBaseSurfaceImpl_GetPalette, + IWineD3DBaseSurfaceImpl_SetPalette, + IWineD3DBaseSurfaceImpl_RealizePalette, + IWineD3DBaseSurfaceImpl_SetColorKey, + IWineD3DBaseSurfaceImpl_GetPitch, IWineD3DSurfaceImpl_SetMem, - IWineD3DSurfaceImpl_SetOverlayPosition, - IWineD3DSurfaceImpl_GetOverlayPosition, - IWineD3DSurfaceImpl_UpdateOverlayZOrder, - IWineD3DSurfaceImpl_UpdateOverlay, - IWineD3DSurfaceImpl_SetClipper, - IWineD3DSurfaceImpl_GetClipper, + IWineD3DBaseSurfaceImpl_SetOverlayPosition, + IWineD3DBaseSurfaceImpl_GetOverlayPosition, + IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder, + IWineD3DBaseSurfaceImpl_UpdateOverlay, + IWineD3DBaseSurfaceImpl_SetClipper, + IWineD3DBaseSurfaceImpl_GetClipper, /* Internal use: */ IWineD3DSurfaceImpl_AddDirtyRect, IWineD3DSurfaceImpl_LoadTexture, IWineD3DSurfaceImpl_SaveSnapshot, - IWineD3DSurfaceImpl_SetContainer, + IWineD3DBaseSurfaceImpl_SetContainer, IWineD3DSurfaceImpl_SetGlTextureDesc, IWineD3DSurfaceImpl_GetGlDesc, IWineD3DSurfaceImpl_GetData, IWineD3DSurfaceImpl_SetFormat, - IWineD3DSurfaceImpl_PrivateSetup + IWineD3DSurfaceImpl_PrivateSetup, + IWineD3DSurfaceImpl_ModifyLocation, + IWineD3DSurfaceImpl_LoadLocation }; diff --git a/reactos/dll/directx/wine/wined3d/surface_gdi.c b/reactos/dll/directx/wine/wined3d/surface_gdi.c index 9f498825cdc..03852f86c18 100644 --- a/reactos/dll/directx/wine/wined3d/surface_gdi.c +++ b/reactos/dll/directx/wine/wined3d/surface_gdi.c @@ -128,6 +128,45 @@ x11_copy_to_screen(IWineD3DSurfaceImpl *This, } } +/***************************************************************************** + * IWineD3DSurface::Release, GDI version + * + * In general a normal COM Release method, but the GDI version doesn't have + * to destroy all the GL things. + * + *****************************************************************************/ +ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice; + TRACE("(%p) : cleaning up\n", This); + + if(This->Flags & SFLAG_DIBSECTION) { + /* Release the DC */ + SelectObject(This->hDC, This->dib.holdbitmap); + DeleteDC(This->hDC); + /* Release the DIB section */ + DeleteObject(This->dib.DIBsection); + This->dib.bitmap_data = NULL; + This->resource.allocatedMemory = NULL; + } + if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL); + + HeapFree(GetProcessHeap(), 0, This->palette9); + + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); + if(iface == device->ddraw_primary) + device->ddraw_primary = NULL; + + TRACE("(%p) Released\n", This); + HeapFree(GetProcessHeap(), 0, This); + + } + return ref; +} + /***************************************************************************** * IWineD3DSurface::PreLoad, GDI version * @@ -173,73 +212,17 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface, /* What should I return here? */ return WINED3DERR_INVALIDCALL; } - - if (!(This->Flags & SFLAG_LOCKABLE)) - { - /* This is some GL specific thing, see the OpenGL version of - * this method, but check for the flag and write a trace - */ - TRACE("Warning: trying to lock unlockable surf@%p\n", This); - } - - TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", - This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); + This->Flags |= SFLAG_LOCKED; if(!This->resource.allocatedMemory) { - HDC hdc; - HRESULT hr; /* This happens on gdi surfaces if the application set a user pointer and resets it. * Recreate the DIB section */ - hr = IWineD3DSurface_GetDC(iface, &hdc); /* will recursively call lockrect, do not set the LOCKED flag to this line */ - if(hr != WINED3D_OK) return hr; - hr = IWineD3DSurface_ReleaseDC(iface, hdc); - if(hr != WINED3D_OK) return hr; + IWineD3DBaseSurfaceImpl_CreateDIBSection(iface); + This->resource.allocatedMemory = This->dib.bitmap_data; } - pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); - - if (NULL == pRect) - { - pLockedRect->pBits = This->resource.allocatedMemory; - This->lockedRect.left = 0; - This->lockedRect.top = 0; - This->lockedRect.right = This->currentDesc.Width; - This->lockedRect.bottom = This->currentDesc.Height; - - TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", - &This->lockedRect, This->lockedRect.left, This->lockedRect.top, - This->lockedRect.right, This->lockedRect.bottom); - } - else - { - TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", - pRect, pRect->left, pRect->top, pRect->right, pRect->bottom); - - if (This->resource.format == WINED3DFMT_DXT1) - { - /* DXT1 is half byte per pixel */ - pLockedRect->pBits = This->resource.allocatedMemory + - (pLockedRect->Pitch * pRect->top) + - ((pRect->left * This->bytesPerPixel / 2)); - } - else - { - pLockedRect->pBits = This->resource.allocatedMemory + - (pLockedRect->Pitch * pRect->top) + - (pRect->left * This->bytesPerPixel); - } - This->lockedRect.left = pRect->left; - This->lockedRect.top = pRect->top; - This->lockedRect.right = pRect->right; - This->lockedRect.bottom = pRect->bottom; - } - - /* No dirtifying is needed for this surface implementation */ - TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch); - - This->Flags |= SFLAG_LOCKED; - return WINED3D_OK; + return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags); } /***************************************************************************** @@ -355,6 +338,13 @@ IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, tmp = This->resource.allocatedMemory; This->resource.allocatedMemory = Target->resource.allocatedMemory; Target->resource.allocatedMemory = tmp; + + if(This->resource.heapMemory) { + ERR("GDI Surface %p has heap memory allocated\n", This); + } + if(Target->resource.heapMemory) { + ERR("GDI Surface %p has heap memory allocated\n", Target); + } } /* client_memory should not be different, but just in case */ @@ -406,961 +396,6 @@ IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, return WINED3D_OK; } -/***************************************************************************** - * _Blt_ColorFill - * - * Helper function that fills a memory area with a specific color - * - * Params: - * buf: memory address to start filling at - * width, height: Dimensions of the area to fill - * bpp: Bit depth of the surface - * lPitch: pitch of the surface - * color: Color to fill with - * - *****************************************************************************/ -static HRESULT -_Blt_ColorFill(BYTE *buf, - int width, int height, - int bpp, LONG lPitch, - DWORD color) -{ - int x, y; - LPBYTE first; - - /* Do first row */ - -#define COLORFILL_ROW(type) \ -{ \ - type *d = (type *) buf; \ - for (x = 0; x < width; x++) \ - d[x] = (type) color; \ - break; \ -} - switch(bpp) - { - case 1: COLORFILL_ROW(BYTE) - case 2: COLORFILL_ROW(WORD) - case 3: - { - BYTE *d = (BYTE *) buf; - for (x = 0; x < width; x++,d+=3) - { - d[0] = (color ) & 0xFF; - d[1] = (color>> 8) & 0xFF; - d[2] = (color>>16) & 0xFF; - } - break; - } - case 4: COLORFILL_ROW(DWORD) - default: - FIXME("Color fill not implemented for bpp %d!\n", bpp*8); - return WINED3DERR_NOTAVAILABLE; - } - -#undef COLORFILL_ROW - - /* Now copy first row */ - first = buf; - for (y = 1; y < height; y++) - { - buf += lPitch; - memcpy(buf, first, width * bpp); - } - return WINED3D_OK; -} - -/***************************************************************************** - * IWineD3DSurface::Blt, GDI version - * - * Performs blits to a surface, eigher from a source of source-less blts - * This is the main functionality of DirectDraw - * - * Params: - * DestRect: Destination rectangle to write to - * SrcSurface: Source surface, can be NULL - * SrcRect: Source rectangle - *****************************************************************************/ -HRESULT WINAPI -IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface, - RECT *DestRect, - IWineD3DSurface *SrcSurface, - RECT *SrcRect, - DWORD Flags, - WINEDDBLTFX *DDBltFx, - WINED3DTEXTUREFILTERTYPE Filter) -{ - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; - RECT xdst,xsrc; - HRESULT ret = WINED3D_OK; - WINED3DLOCKED_RECT dlock, slock; - WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN; - int bpp, srcheight, srcwidth, dstheight, dstwidth, width; - int x, y; - const StaticPixelFormatDesc *sEntry, *dEntry; - LPBYTE dbuf, sbuf; - TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx); - - if (TRACE_ON(d3d_surface)) - { - if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n", - DestRect->left, DestRect->top, DestRect->right, DestRect->bottom); - if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n", - SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom); -#if 0 - TRACE("\tflags: "); - DDRAW_dump_DDBLT(Flags); - if (Flags & WINEDDBLT_DDFX) - { - TRACE("\tblitfx: "); - DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX); - } -#endif - } - - if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED))) - { - WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n"); - return WINEDDERR_SURFACEBUSY; - } - - if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) { - /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */ - FIXME("Filters not supported in software blit\n"); - } - - if (Src == This) - { - IWineD3DSurface_LockRect(iface, &dlock, NULL, 0); - dfmt = This->resource.format; - slock = dlock; - sfmt = dfmt; - sEntry = getFormatDescEntry(sfmt, NULL, NULL); - dEntry = sEntry; - } - else - { - if (Src) - { - IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY); - sfmt = Src->resource.format; - } - sEntry = getFormatDescEntry(sfmt, NULL, NULL); - dfmt = This->resource.format; - dEntry = getFormatDescEntry(dfmt, NULL, NULL); - IWineD3DSurface_LockRect(iface, &dlock,NULL,0); - } - - if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX; - - if (sEntry->isFourcc && dEntry->isFourcc) - { - if (sfmt != dfmt) - { - FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n"); - ret = WINED3DERR_WRONGTEXTUREFORMAT; - goto release; - } - memcpy(dlock.pBits, slock.pBits, This->resource.size); - goto release; - } - - if (sEntry->isFourcc && !dEntry->isFourcc) - { - FIXME("DXTC decompression not supported right now\n"); - goto release; - } - - if (DestRect) - { - memcpy(&xdst,DestRect,sizeof(xdst)); - } - else - { - xdst.top = 0; - xdst.bottom = This->currentDesc.Height; - xdst.left = 0; - xdst.right = This->currentDesc.Width; - } - - if (SrcRect) - { - memcpy(&xsrc,SrcRect,sizeof(xsrc)); - } - else - { - if (Src) - { - xsrc.top = 0; - xsrc.bottom = Src->currentDesc.Height; - xsrc.left = 0; - xsrc.right = Src->currentDesc.Width; - } - else - { - memset(&xsrc,0,sizeof(xsrc)); - } - } - - /* First check for the validity of source / destination rectangles. This was - verified using a test application + by MSDN. - */ - if ((Src != NULL) && - ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) || - (xsrc.top > Src->currentDesc.Height) || (xsrc.top < 0) || - (xsrc.left > Src->currentDesc.Width) || (xsrc.left < 0) || - (xsrc.right > Src->currentDesc.Width) || (xsrc.right < 0) || - (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top))) - { - WARN("Application gave us bad source rectangle for Blt.\n"); - ret = WINEDDERR_INVALIDRECT; - goto release; - } - /* For the Destination rect, it can be out of bounds on the condition that a clipper - is set for the given surface. - */ - if ((/*This->clipper == NULL*/ TRUE) && - ((xdst.bottom > This->currentDesc.Height) || (xdst.bottom < 0) || - (xdst.top > This->currentDesc.Height) || (xdst.top < 0) || - (xdst.left > This->currentDesc.Width) || (xdst.left < 0) || - (xdst.right > This->currentDesc.Width) || (xdst.right < 0) || - (xdst.right < xdst.left) || (xdst.bottom < xdst.top))) - { - WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n"); - ret = WINEDDERR_INVALIDRECT; - goto release; - } - - /* Now handle negative values in the rectangles. Warning: only supported for now - in the 'simple' cases (ie not in any stretching / rotation cases). - - First, the case where nothing is to be done. - */ - if (((xdst.bottom <= 0) || (xdst.right <= 0) || - (xdst.top >= (int) This->currentDesc.Height) || - (xdst.left >= (int) This->currentDesc.Width)) || - ((Src != NULL) && - ((xsrc.bottom <= 0) || (xsrc.right <= 0) || - (xsrc.top >= (int) Src->currentDesc.Height) || - (xsrc.left >= (int) Src->currentDesc.Width)) )) - { - TRACE("Nothing to be done !\n"); - goto release; - } - - /* The easy case : the source-less blits.... */ - if (Src == NULL) - { - RECT full_rect; - RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */ - - full_rect.left = 0; - full_rect.top = 0; - full_rect.right = This->currentDesc.Width; - full_rect.bottom = This->currentDesc.Height; - IntersectRect(&temp_rect, &full_rect, &xdst); - xdst = temp_rect; - } - else - { - /* Only handle clipping on the destination rectangle */ - int clip_horiz = (xdst.left < 0) || (xdst.right > (int) This->currentDesc.Width ); - int clip_vert = (xdst.top < 0) || (xdst.bottom > (int) This->currentDesc.Height); - if (clip_vert || clip_horiz) - { - /* Now check if this is a special case or not... */ - if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) || - (((xdst.right - xdst.left) != (xsrc.right - xsrc.left)) && clip_horiz) || - (Flags & WINEDDBLT_DDFX)) - { - WARN("Out of screen rectangle in special case. Not handled right now.\n"); - goto release; - } - - if (clip_horiz) - { - if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; } - if (xdst.right > This->currentDesc.Width) - { - xsrc.right -= (xdst.right - (int) This->currentDesc.Width); - xdst.right = (int) This->currentDesc.Width; - } - } - if (clip_vert) - { - if (xdst.top < 0) - { - xsrc.top -= xdst.top; - xdst.top = 0; - } - if (xdst.bottom > This->currentDesc.Height) - { - xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height); - xdst.bottom = (int) This->currentDesc.Height; - } - } - /* And check if after clipping something is still to be done... */ - if ((xdst.bottom <= 0) || (xdst.right <= 0) || - (xdst.top >= (int) This->currentDesc.Height) || - (xdst.left >= (int) This->currentDesc.Width) || - (xsrc.bottom <= 0) || (xsrc.right <= 0) || - (xsrc.top >= (int) Src->currentDesc.Height) || - (xsrc.left >= (int) Src->currentDesc.Width)) - { - TRACE("Nothing to be done after clipping !\n"); - goto release; - } - } - } - - bpp = This->bytesPerPixel; - srcheight = xsrc.bottom - xsrc.top; - srcwidth = xsrc.right - xsrc.left; - dstheight = xdst.bottom - xdst.top; - dstwidth = xdst.right - xdst.left; - width = (xdst.right - xdst.left) * bpp; - - assert(width <= dlock.Pitch); - - dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp); - - if (Flags & WINEDDBLT_WAIT) - { - Flags &= ~WINEDDBLT_WAIT; - } - if (Flags & WINEDDBLT_ASYNC) - { - static BOOL displayed = FALSE; - if (!displayed) - FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n"); - displayed = TRUE; - Flags &= ~WINEDDBLT_ASYNC; - } - if (Flags & WINEDDBLT_DONOTWAIT) - { - /* WINEDDBLT_DONOTWAIT appeared in DX7 */ - static BOOL displayed = FALSE; - if (!displayed) - FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n"); - displayed = TRUE; - Flags &= ~WINEDDBLT_DONOTWAIT; - } - - /* First, all the 'source-less' blits */ - if (Flags & WINEDDBLT_COLORFILL) - { - ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, - dlock.Pitch, DDBltFx->u5.dwFillColor); - Flags &= ~WINEDDBLT_COLORFILL; - } - - if (Flags & WINEDDBLT_DEPTHFILL) - { - FIXME("DDBLT_DEPTHFILL needs to be implemented!\n"); - } - if (Flags & WINEDDBLT_ROP) - { - /* Catch some degenerate cases here */ - switch(DDBltFx->dwROP) - { - case BLACKNESS: - ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0); - break; - case 0xAA0029: /* No-op */ - break; - case WHITENESS: - ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0); - break; - case SRCCOPY: /* well, we do that below ? */ - break; - default: - FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern); - goto error; - } - Flags &= ~WINEDDBLT_ROP; - } - if (Flags & WINEDDBLT_DDROPS) - { - FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern); - } - /* Now the 'with source' blits */ - if (Src) - { - LPBYTE sbase; - int sx, xinc, sy, yinc; - - if (!dstwidth || !dstheight) /* hmm... stupid program ? */ - goto release; - sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp; - xinc = (srcwidth << 16) / dstwidth; - yinc = (srcheight << 16) / dstheight; - - if (!Flags) - { - /* No effects, we can cheat here */ - if (dstwidth == srcwidth) - { - if (dstheight == srcheight) - { - /* No stretching in either direction. This needs to be as - * fast as possible */ - sbuf = sbase; - - /* check for overlapping surfaces */ - if (SrcSurface != iface || xdst.top < xsrc.top || - xdst.right <= xsrc.left || xsrc.right <= xdst.left) - { - /* no overlap, or dst above src, so copy from top downwards */ - for (y = 0; y < dstheight; y++) - { - memcpy(dbuf, sbuf, width); - sbuf += slock.Pitch; - dbuf += dlock.Pitch; - } - } - else if (xdst.top > xsrc.top) /* copy from bottom upwards */ - { - sbuf += (slock.Pitch*dstheight); - dbuf += (dlock.Pitch*dstheight); - for (y = 0; y < dstheight; y++) - { - sbuf -= slock.Pitch; - dbuf -= dlock.Pitch; - memcpy(dbuf, sbuf, width); - } - } - else /* src and dst overlapping on the same line, use memmove */ - { - for (y = 0; y < dstheight; y++) - { - memmove(dbuf, sbuf, width); - sbuf += slock.Pitch; - dbuf += dlock.Pitch; - } - } - } else { - /* Stretching in Y direction only */ - for (y = sy = 0; y < dstheight; y++, sy += yinc) { - sbuf = sbase + (sy >> 16) * slock.Pitch; - memcpy(dbuf, sbuf, width); - dbuf += dlock.Pitch; - } - } - } - else - { - /* Stretching in X direction */ - int last_sy = -1; - for (y = sy = 0; y < dstheight; y++, sy += yinc) - { - sbuf = sbase + (sy >> 16) * slock.Pitch; - - if ((sy >> 16) == (last_sy >> 16)) - { - /* this sourcerow is the same as last sourcerow - - * copy already stretched row - */ - memcpy(dbuf, dbuf - dlock.Pitch, width); - } - else - { -#define STRETCH_ROW(type) { \ - type *s = (type *) sbuf, *d = (type *) dbuf; \ - for (x = sx = 0; x < dstwidth; x++, sx += xinc) \ - d[x] = s[sx >> 16]; \ - break; } - - switch(bpp) - { - case 1: STRETCH_ROW(BYTE) - case 2: STRETCH_ROW(WORD) - case 4: STRETCH_ROW(DWORD) - case 3: - { - LPBYTE s,d = dbuf; - for (x = sx = 0; x < dstwidth; x++, sx+= xinc) - { - DWORD pixel; - - s = sbuf+3*(sx>>16); - pixel = s[0]|(s[1]<<8)|(s[2]<<16); - d[0] = (pixel )&0xff; - d[1] = (pixel>> 8)&0xff; - d[2] = (pixel>>16)&0xff; - d+=3; - } - break; - } - default: - FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8); - ret = WINED3DERR_NOTAVAILABLE; - goto error; - } -#undef STRETCH_ROW - } - dbuf += dlock.Pitch; - last_sy = sy; - } - } - } - else - { - LONG dstyinc = dlock.Pitch, dstxinc = bpp; - DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF; - DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF; - if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE)) - { - /* The color keying flags are checked for correctness in ddraw */ - if (Flags & WINEDDBLT_KEYSRC) - { - keylow = Src->SrcBltCKey.dwColorSpaceLowValue; - keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue; - } - else if (Flags & WINEDDBLT_KEYSRCOVERRIDE) - { - keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue; - keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue; - } - - if (Flags & WINEDDBLT_KEYDEST) - { - /* Destination color keys are taken from the source surface ! */ - destkeylow = Src->DestBltCKey.dwColorSpaceLowValue; - destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue; - } - else if (Flags & WINEDDBLT_KEYDESTOVERRIDE) - { - destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue; - destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue; - } - - if(bpp == 1) - { - keymask = 0xff; - } - else - { - keymask = sEntry->redMask | - sEntry->greenMask | - sEntry->blueMask; - } - Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE); - } - - if (Flags & WINEDDBLT_DDFX) - { - LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp; - LONG tmpxy; - dTopLeft = dbuf; - dTopRight = dbuf+((dstwidth-1)*bpp); - dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch); - dBottomRight = dBottomLeft+((dstwidth-1)*bpp); - - if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY) - { - /* I don't think we need to do anything about this flag */ - WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n"); - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT) - { - tmp = dTopRight; - dTopRight = dTopLeft; - dTopLeft = tmp; - tmp = dBottomRight; - dBottomRight = dBottomLeft; - dBottomLeft = tmp; - dstxinc = dstxinc *-1; - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN) - { - tmp = dTopLeft; - dTopLeft = dBottomLeft; - dBottomLeft = tmp; - tmp = dTopRight; - dTopRight = dBottomRight; - dBottomRight = tmp; - dstyinc = dstyinc *-1; - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING) - { - /* I don't think we need to do anything about this flag */ - WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n"); - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180) - { - tmp = dBottomRight; - dBottomRight = dTopLeft; - dTopLeft = tmp; - tmp = dBottomLeft; - dBottomLeft = dTopRight; - dTopRight = tmp; - dstxinc = dstxinc * -1; - dstyinc = dstyinc * -1; - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270) - { - tmp = dTopLeft; - dTopLeft = dBottomLeft; - dBottomLeft = dBottomRight; - dBottomRight = dTopRight; - dTopRight = tmp; - tmpxy = dstxinc; - dstxinc = dstyinc; - dstyinc = tmpxy; - dstxinc = dstxinc * -1; - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90) - { - tmp = dTopLeft; - dTopLeft = dTopRight; - dTopRight = dBottomRight; - dBottomRight = dBottomLeft; - dBottomLeft = tmp; - tmpxy = dstxinc; - dstxinc = dstyinc; - dstyinc = tmpxy; - dstyinc = dstyinc * -1; - } - if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST) - { - /* I don't think we need to do anything about this flag */ - WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n"); - } - dbuf = dTopLeft; - Flags &= ~(WINEDDBLT_DDFX); - } - -#define COPY_COLORKEY_FX(type) { \ - type *s, *d = (type *) dbuf, *dx, tmp; \ - for (y = sy = 0; y < dstheight; y++, sy += yinc) { \ - s = (type*)(sbase + (sy >> 16) * slock.Pitch); \ - dx = d; \ - for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \ - tmp = s[sx >> 16]; \ - if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \ - ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \ - dx[0] = tmp; \ - } \ - dx = (type*)(((LPBYTE)dx)+dstxinc); \ - } \ - d = (type*)(((LPBYTE)d)+dstyinc); \ - } \ - break; } - - switch (bpp) { - case 1: COPY_COLORKEY_FX(BYTE) - case 2: COPY_COLORKEY_FX(WORD) - case 4: COPY_COLORKEY_FX(DWORD) - case 3: - { - LPBYTE s,d = dbuf, dx; - for (y = sy = 0; y < dstheight; y++, sy += yinc) - { - sbuf = sbase + (sy >> 16) * slock.Pitch; - dx = d; - for (x = sx = 0; x < dstwidth; x++, sx+= xinc) - { - DWORD pixel, dpixel = 0; - s = sbuf+3*(sx>>16); - pixel = s[0]|(s[1]<<8)|(s[2]<<16); - dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16); - if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) && - ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh)) - { - dx[0] = (pixel )&0xff; - dx[1] = (pixel>> 8)&0xff; - dx[2] = (pixel>>16)&0xff; - } - dx+= dstxinc; - } - d += dstyinc; - } - break; - } - default: - FIXME("%s color-keyed blit not implemented for bpp %d!\n", - (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8); - ret = WINED3DERR_NOTAVAILABLE; - goto error; -#undef COPY_COLORKEY_FX - } - } - } - -error: - if (Flags && FIXME_ON(d3d_surface)) - { - FIXME("\tUnsupported flags: %08x\n", Flags); - } - -release: - IWineD3DSurface_UnlockRect(iface); - if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface); - return ret; -} - -/***************************************************************************** - * IWineD3DSurface::BltFast, GDI version - * - * This is the software implementation of BltFast, as used by GDI surfaces - * and as a fallback for OpenGL surfaces. This code is taken from the old - * DirectDraw code, and was originally written by TransGaming. - * - * Params: - * dstx: - * dsty: - * Source: Source surface to copy from - * rsrc: Source rectangle - * trans: Some Flags - * - * Returns: - * WINED3D_OK on success - * - *****************************************************************************/ -HRESULT WINAPI -IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface, - DWORD dstx, - DWORD dsty, - IWineD3DSurface *Source, - RECT *rsrc, - DWORD trans) -{ - IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source; - - int bpp, w, h, x, y; - WINED3DLOCKED_RECT dlock,slock; - HRESULT ret = WINED3D_OK; - RECT rsrc2; - RECT lock_src, lock_dst, lock_union; - BYTE *sbuf, *dbuf; - const StaticPixelFormatDesc *sEntry, *dEntry; - - if (TRACE_ON(d3d_surface)) - { - TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans); - - if (rsrc) - { - TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top, - rsrc->right,rsrc->bottom); - } - else - { - TRACE(" srcrect: NULL\n"); - } - } - - if ((This->Flags & SFLAG_LOCKED) || - ((Src != NULL) && (Src->Flags & SFLAG_LOCKED))) - { - WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n"); - return WINEDDERR_SURFACEBUSY; - } - - if (!rsrc) - { - WARN("rsrc is NULL!\n"); - rsrc = &rsrc2; - rsrc->left = 0; - rsrc->top = 0; - rsrc->right = Src->currentDesc.Width; - rsrc->bottom = Src->currentDesc.Height; - } - - /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/ - if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) || - (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) || - (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) || - (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) || - (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top)) - { - WARN("Application gave us bad source rectangle for BltFast.\n"); - return WINEDDERR_INVALIDRECT; - } - - h = rsrc->bottom - rsrc->top; - if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty; - if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top; - if (h <= 0) return WINEDDERR_INVALIDRECT; - - w = rsrc->right - rsrc->left; - if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx; - if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left; - if (w <= 0) return WINEDDERR_INVALIDRECT; - - /* Now compute the locking rectangle... */ - lock_src.left = rsrc->left; - lock_src.top = rsrc->top; - lock_src.right = lock_src.left + w; - lock_src.bottom = lock_src.top + h; - - lock_dst.left = dstx; - lock_dst.top = dsty; - lock_dst.right = dstx + w; - lock_dst.bottom = dsty + h; - - bpp = This->bytesPerPixel; - - /* We need to lock the surfaces, or we won't get refreshes when done. */ - if (Src == This) - { - int pitch; - - UnionRect(&lock_union, &lock_src, &lock_dst); - - /* Lock the union of the two rectangles */ - ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0); - if(ret != WINED3D_OK) goto error; - - pitch = dlock.Pitch; - slock.Pitch = dlock.Pitch; - - /* Since slock was originally copied from this surface's description, we can just reuse it */ - assert(This->resource.allocatedMemory != NULL); - sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp; - dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp; - sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL); - dEntry = sEntry; - } - else - { - ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY); - if(ret != WINED3D_OK) goto error; - ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0); - if(ret != WINED3D_OK) goto error; - - sbuf = slock.pBits; - dbuf = dlock.pBits; - TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf); - - sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL); - dEntry = getFormatDescEntry(This->resource.format, NULL, NULL); - } - - /* Handle first the FOURCC surfaces... */ - if (sEntry->isFourcc && dEntry->isFourcc) - { - TRACE("Fourcc -> Fourcc copy\n"); - if (trans) - FIXME("trans arg not supported when a FOURCC surface is involved\n"); - if (dstx || dsty) - FIXME("offset for destination surface is not supported\n"); - if (Src->resource.format != This->resource.format) - { - FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n"); - ret = WINED3DERR_WRONGTEXTUREFORMAT; - goto error; - } - /* FIXME: Watch out that the size is correct for FOURCC surfaces */ - memcpy(dbuf, sbuf, This->resource.size); - goto error; - } - if (sEntry->isFourcc && !dEntry->isFourcc) - { - /* TODO: Use the libtxc_dxtn.so shared library to do - * software decompression - */ - ERR("DXTC decompression not supported by now\n"); - goto error; - } - - if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY)) - { - DWORD keylow, keyhigh; - TRACE("Color keyed copy\n"); - if (trans & WINEDDBLTFAST_SRCCOLORKEY) - { - keylow = Src->SrcBltCKey.dwColorSpaceLowValue; - keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue; - } - else - { - /* I'm not sure if this is correct */ - FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n"); - keylow = This->DestBltCKey.dwColorSpaceLowValue; - keyhigh = This->DestBltCKey.dwColorSpaceHighValue; - } - -#define COPYBOX_COLORKEY(type) { \ - type *d, *s, tmp; \ - s = (type *) sbuf; \ - d = (type *) dbuf; \ - for (y = 0; y < h; y++) { \ - for (x = 0; x < w; x++) { \ - tmp = s[x]; \ - if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \ - } \ - s = (type *)((BYTE *)s + slock.Pitch); \ - d = (type *)((BYTE *)d + dlock.Pitch); \ - } \ - break; \ - } - - switch (bpp) { - case 1: COPYBOX_COLORKEY(BYTE) - case 2: COPYBOX_COLORKEY(WORD) - case 4: COPYBOX_COLORKEY(DWORD) - case 3: - { - BYTE *d, *s; - DWORD tmp; - s = (BYTE *) sbuf; - d = (BYTE *) dbuf; - for (y = 0; y < h; y++) - { - for (x = 0; x < w * 3; x += 3) - { - tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16); - if (tmp < keylow || tmp > keyhigh) - { - d[x + 0] = s[x + 0]; - d[x + 1] = s[x + 1]; - d[x + 2] = s[x + 2]; - } - } - s += slock.Pitch; - d += dlock.Pitch; - } - break; - } - default: - FIXME("Source color key blitting not supported for bpp %d\n",bpp*8); - ret = WINED3DERR_NOTAVAILABLE; - goto error; - } -#undef COPYBOX_COLORKEY - TRACE("Copy Done\n"); - } - else - { - int width = w * bpp; - TRACE("NO color key copy\n"); - for (y = 0; y < h; y++) - { - /* This is pretty easy, a line for line memcpy */ - memcpy(dbuf, sbuf, width); - sbuf += slock.Pitch; - dbuf += dlock.Pitch; - } - TRACE("Copy done\n"); - } - -error: - if (Src == This) - { - IWineD3DSurface_UnlockRect(iface); - } - else - { - IWineD3DSurface_UnlockRect(iface); - IWineD3DSurface_UnlockRect(Source); - } - - return ret; -} - /***************************************************************************** * IWineD3DSurface::LoadTexture, GDI version * @@ -1490,6 +525,97 @@ const char* filename) return WINED3D_OK; } +HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + WINED3DLOCKED_RECT lock; + HRESULT hr; + RGBQUAD col[256]; + + TRACE("(%p)->(%p)\n",This,pHDC); + + if(This->Flags & SFLAG_USERPTR) { + ERR("Not supported on surfaces with an application-provided surfaces\n"); + return WINEDDERR_NODC; + } + + /* Give more detailed info for ddraw */ + if (This->Flags & SFLAG_DCINUSE) + return WINEDDERR_DCALREADYCREATED; + + /* Can't GetDC if the surface is locked */ + if (This->Flags & SFLAG_LOCKED) + return WINED3DERR_INVALIDCALL; + + memset(&lock, 0, sizeof(lock)); /* To be sure */ + + /* Should have a DIB section already */ + + /* Lock the surface */ + hr = IWineD3DSurface_LockRect(iface, + &lock, + NULL, + 0); + if(FAILED(hr)) { + ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr); + /* keep the dib section */ + return hr; + } + + if(This->resource.format == WINED3DFMT_P8 || + This->resource.format == WINED3DFMT_A8P8) { + unsigned int n; + if(This->palette) { + PALETTEENTRY ent[256]; + + GetPaletteEntries(This->palette->hpal, 0, 256, ent); + for (n=0; n<256; n++) { + col[n].rgbRed = ent[n].peRed; + col[n].rgbGreen = ent[n].peGreen; + col[n].rgbBlue = ent[n].peBlue; + col[n].rgbReserved = 0; + } + } else { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + for (n=0; n<256; n++) { + col[n].rgbRed = device->palettes[device->currentPalette][n].peRed; + col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen; + col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue; + col[n].rgbReserved = 0; + } + + } + SetDIBColorTable(This->hDC, 0, 256, col); + } + + *pHDC = This->hDC; + TRACE("returning %p\n",*pHDC); + This->Flags |= SFLAG_DCINUSE; + + return WINED3D_OK; +} + +HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + TRACE("(%p)->(%p)\n",This,hDC); + + if (!(This->Flags & SFLAG_DCINUSE)) + return WINED3DERR_INVALIDCALL; + + if (This->hDC !=hDC) { + WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC); + return WINED3DERR_INVALIDCALL; + } + + /* we locked first, so unlock now */ + IWineD3DSurface_UnlockRect(iface); + + This->Flags &= ~SFLAG_DCINUSE; + + return WINED3D_OK; +} + /***************************************************************************** * IWineD3DSurface::PrivateSetup, GDI version * @@ -1511,8 +637,6 @@ HRESULT WINAPI IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; - HRESULT hr; - HDC hdc; if(This->resource.usage & WINED3DUSAGE_OVERLAY) { @@ -1522,84 +646,172 @@ IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface) /* Sysmem textures have memory already allocated - * release it, this avoids an unnecessary memcpy */ - HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + HeapFree(GetProcessHeap(), 0, This->resource.heapMemory); This->resource.allocatedMemory = NULL; + This->resource.heapMemory = NULL; /* We don't mind the nonpow2 stuff in GDI */ This->pow2Width = This->currentDesc.Width; This->pow2Height = This->currentDesc.Height; - /* Call GetDC to create a DIB section. We will use that - * DIB section for rendering - * - * Release the DC afterwards to allow the app to use it - */ - hr = IWineD3DSurface_GetDC(iface, &hdc); - if(FAILED(hr)) - { - ERR("(%p) IWineD3DSurface::GetDC failed with hr %08x\n", This, hr); - return hr; - } - hr = IWineD3DSurface_ReleaseDC(iface, hdc); - if(FAILED(hr)) - { - ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08x\n", This, hr); - return hr; - } + IWineD3DBaseSurfaceImpl_CreateDIBSection(iface); + This->resource.allocatedMemory = This->dib.bitmap_data; return WINED3D_OK; } +void WINAPI IWineGDISurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + /* Ignore 0 textureName and target. D3D textures can be created with gdi surfaces as plain + * containers, but they're useless until the app creates a d3d device from a d3d point of + * view, it's not an implementation limitation. This avoids false warnings when the texture + * is destroyed and sets the description back to 0/0 + */ + if(textureName != 0 || target != 0) { + FIXME("(%p) : Should not be called on a GDI surface. textureName %u, target %i\n", This, textureName, target); + DebugBreak(); + } +} + +void WINAPI IWineGDISurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + FIXME("(%p) : Should not be called on a GDI surface\n", This); + *glDescription = NULL; +} + +HRESULT WINAPI IWineGDISurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) { + /* GDI surface data can only be in one location, the system memory dib section. So they are + * always clean by definition. + */ + TRACE("No dirtification in GDI surfaces\n"); + return WINED3D_OK; +} + +HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + + /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */ + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { + ERR("Not supported on render targets\n"); + return WINED3DERR_INVALIDCALL; + } + + if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) { + WARN("Surface is locked or the HDC is in use\n"); + return WINED3DERR_INVALIDCALL; + } + + if(Mem && Mem != This->resource.allocatedMemory) { + void *release = NULL; + + /* Do I have to copy the old surface content? */ + if(This->Flags & SFLAG_DIBSECTION) { + /* Release the DC. No need to hold the critical section for the update + * Thread because this thread runs only on front buffers, but this method + * fails for render targets in the check above. + */ + SelectObject(This->hDC, This->dib.holdbitmap); + DeleteDC(This->hDC); + /* Release the DIB section */ + DeleteObject(This->dib.DIBsection); + This->dib.bitmap_data = NULL; + This->resource.allocatedMemory = NULL; + This->hDC = NULL; + This->Flags &= ~SFLAG_DIBSECTION; + } else if(!(This->Flags & SFLAG_USERPTR)) { + release = This->resource.allocatedMemory; + } + This->resource.allocatedMemory = Mem; + This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM; + + /* Now free the old memory if any */ + HeapFree(GetProcessHeap(), 0, release); + } else if(This->Flags & SFLAG_USERPTR) { + /* Lockrect and GetDC will re-create the dib section and allocated memory */ + This->resource.allocatedMemory = NULL; + This->Flags &= ~SFLAG_USERPTR; + } + return WINED3D_OK; +} + +/*************************** + * + ***************************/ +static void WINAPI IWineGDISurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) { + TRACE("(%p)->(%s, %s)\n", iface, + flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE", + persistent ? "TRUE" : "FALSE"); + /* GDI surfaces can be in system memory only */ + if(flag != SFLAG_INSYSMEM) { + ERR("GDI Surface requested in gl %s memory\n", flag == SFLAG_INDRAWABLE ? "drawable" : "texture"); + } +} + +static HRESULT WINAPI IWineGDISurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) { + if(flag != SFLAG_INSYSMEM) { + ERR("GDI Surface requested to be copied to gl %s\n", flag == SFLAG_INTEXTURE ? "texture" : "drawable"); + } else { + TRACE("Surface requested in surface memory\n"); + } + return WINED3D_OK; +} + +/* FIXME: This vtable should not use any IWineD3DSurface* implementation functions, + * only IWineD3DBaseSurface and IWineGDISurface ones. + */ const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl = { /* IUnknown */ - IWineD3DSurfaceImpl_QueryInterface, - IWineD3DSurfaceImpl_AddRef, - IWineD3DSurfaceImpl_Release, + IWineD3DBaseSurfaceImpl_QueryInterface, + IWineD3DBaseSurfaceImpl_AddRef, + IWineGDISurfaceImpl_Release, /* IWineD3DResource */ - IWineD3DSurfaceImpl_GetParent, - IWineD3DSurfaceImpl_GetDevice, - IWineD3DSurfaceImpl_SetPrivateData, - IWineD3DSurfaceImpl_GetPrivateData, - IWineD3DSurfaceImpl_FreePrivateData, - IWineD3DSurfaceImpl_SetPriority, - IWineD3DSurfaceImpl_GetPriority, + IWineD3DBaseSurfaceImpl_GetParent, + IWineD3DBaseSurfaceImpl_GetDevice, + IWineD3DBaseSurfaceImpl_SetPrivateData, + IWineD3DBaseSurfaceImpl_GetPrivateData, + IWineD3DBaseSurfaceImpl_FreePrivateData, + IWineD3DBaseSurfaceImpl_SetPriority, + IWineD3DBaseSurfaceImpl_GetPriority, IWineGDISurfaceImpl_PreLoad, - IWineD3DSurfaceImpl_GetType, + IWineD3DBaseSurfaceImpl_GetType, /* IWineD3DSurface */ - IWineD3DSurfaceImpl_GetContainer, - IWineD3DSurfaceImpl_GetDesc, + IWineD3DBaseSurfaceImpl_GetContainer, + IWineD3DBaseSurfaceImpl_GetDesc, IWineGDISurfaceImpl_LockRect, IWineGDISurfaceImpl_UnlockRect, - IWineD3DSurfaceImpl_GetDC, - IWineD3DSurfaceImpl_ReleaseDC, + IWineGDISurfaceImpl_GetDC, + IWineGDISurfaceImpl_ReleaseDC, IWineGDISurfaceImpl_Flip, - IWineGDISurfaceImpl_Blt, - IWineD3DSurfaceImpl_GetBltStatus, - IWineD3DSurfaceImpl_GetFlipStatus, - IWineD3DSurfaceImpl_IsLost, - IWineD3DSurfaceImpl_Restore, - IWineGDISurfaceImpl_BltFast, - IWineD3DSurfaceImpl_GetPalette, - IWineD3DSurfaceImpl_SetPalette, - IWineD3DSurfaceImpl_RealizePalette, - IWineD3DSurfaceImpl_SetColorKey, - IWineD3DSurfaceImpl_GetPitch, - IWineD3DSurfaceImpl_SetMem, - IWineD3DSurfaceImpl_SetOverlayPosition, - IWineD3DSurfaceImpl_GetOverlayPosition, - IWineD3DSurfaceImpl_UpdateOverlayZOrder, - IWineD3DSurfaceImpl_UpdateOverlay, - IWineD3DSurfaceImpl_SetClipper, - IWineD3DSurfaceImpl_GetClipper, + IWineD3DBaseSurfaceImpl_Blt, + IWineD3DBaseSurfaceImpl_GetBltStatus, + IWineD3DBaseSurfaceImpl_GetFlipStatus, + IWineD3DBaseSurfaceImpl_IsLost, + IWineD3DBaseSurfaceImpl_Restore, + IWineD3DBaseSurfaceImpl_BltFast, + IWineD3DBaseSurfaceImpl_GetPalette, + IWineD3DBaseSurfaceImpl_SetPalette, + IWineD3DBaseSurfaceImpl_RealizePalette, + IWineD3DBaseSurfaceImpl_SetColorKey, + IWineD3DBaseSurfaceImpl_GetPitch, + IWineGDISurfaceImpl_SetMem, + IWineD3DBaseSurfaceImpl_SetOverlayPosition, + IWineD3DBaseSurfaceImpl_GetOverlayPosition, + IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder, + IWineD3DBaseSurfaceImpl_UpdateOverlay, + IWineD3DBaseSurfaceImpl_SetClipper, + IWineD3DBaseSurfaceImpl_GetClipper, /* Internal use: */ - IWineD3DSurfaceImpl_AddDirtyRect, + IWineGDISurfaceImpl_AddDirtyRect, IWineGDISurfaceImpl_LoadTexture, IWineGDISurfaceImpl_SaveSnapshot, - IWineD3DSurfaceImpl_SetContainer, - IWineD3DSurfaceImpl_SetGlTextureDesc, - IWineD3DSurfaceImpl_GetGlDesc, + IWineD3DBaseSurfaceImpl_SetContainer, + IWineGDISurfaceImpl_SetGlTextureDesc, + IWineGDISurfaceImpl_GetGlDesc, IWineD3DSurfaceImpl_GetData, - IWineD3DSurfaceImpl_SetFormat, - IWineGDISurfaceImpl_PrivateSetup + IWineD3DBaseSurfaceImpl_SetFormat, + IWineGDISurfaceImpl_PrivateSetup, + IWineGDISurfaceImpl_ModifyLocation, + IWineGDISurfaceImpl_LoadLocation }; diff --git a/reactos/dll/directx/wine/wined3d/swapchain.c b/reactos/dll/directx/wine/wined3d/swapchain.c index 5d1edbe9022..81f17c35ed3 100644 --- a/reactos/dll/directx/wine/wined3d/swapchain.c +++ b/reactos/dll/directx/wine/wined3d/swapchain.c @@ -103,6 +103,7 @@ static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB FIXME("(%p) Something's still holding the back buffer\n",This); } } + HeapFree(GetProcessHeap(), 0, This->backBuffer); } /* Restore the screen resolution if we rendered in fullscreen @@ -132,7 +133,6 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO ActivateContext(This->wineD3DDevice, This->backBuffer[0], CTXUSAGE_RESOURCELOAD); - ENTER_GL(); /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ if(This->wineD3DDevice->bCursorVisible && This->wineD3DDevice->cursorTexture) { @@ -175,6 +175,10 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO } IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *) &cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3DTEXF_NONE); } + if(This->wineD3DDevice->logo_surface) { + /* Blit the logo into the upper left corner of the drawable */ + IWineD3DSurface_BltFast(This->backBuffer[0], 0, 0, This->wineD3DDevice->logo_surface, NULL, WINEDDBLTFAST_SRCCOLORKEY); + } if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect); /* TODO: If only source rect or dest rect are supplied then clip the window to match */ @@ -240,7 +244,9 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO #if defined(SHOW_FRAME_MAKEUP) FIXME("Singe Frame snapshots Starting\n"); isDumpingFrames = TRUE; + ENTER_GL(); glClear(GL_COLOR_BUFFER_BIT); + LEAVE_GL(); #endif #if defined(SINGLE_FRAME_DEBUGGING) @@ -268,8 +274,6 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO } #endif - LEAVE_GL(); - if (This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) { TRACE("Clearing the color buffer with pink color\n"); @@ -319,6 +323,29 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO tmp = front->resource.allocatedMemory; front->resource.allocatedMemory = back->resource.allocatedMemory; back->resource.allocatedMemory = tmp; + + tmp = front->resource.heapMemory; + front->resource.heapMemory = back->resource.heapMemory; + back->resource.heapMemory = tmp; + } + + /* Flip the PBO */ + { + DWORD tmp_flags = front->Flags; + + GLuint tmp_pbo = front->pbo; + front->pbo = back->pbo; + back->pbo = tmp_pbo; + + if(back->Flags & SFLAG_PBO) + front->Flags |= SFLAG_PBO; + else + front->Flags &= ~SFLAG_PBO; + + if(tmp_flags & SFLAG_PBO) + back->Flags |= SFLAG_PBO; + else + back->Flags &= ~SFLAG_PBO; } /* client_memory should not be different, but just in case */ @@ -333,8 +360,8 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO if(backuptodate) front->Flags |= SFLAG_INSYSMEM; else front->Flags &= ~SFLAG_INSYSMEM; } else { - back->Flags &= ~SFLAG_INSYSMEM; - front->Flags &= ~SFLAG_INSYSMEM; + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) front, SFLAG_INDRAWABLE, TRUE); + IWineD3DSurface_ModifyLocation((IWineD3DSurface *) back, SFLAG_INDRAWABLE, TRUE); } } diff --git a/reactos/dll/directx/wine/wined3d/texture.c b/reactos/dll/directx/wine/wined3d/texture.c index 48f8c8cb15d..1dcaee18f80 100644 --- a/reactos/dll/directx/wine/wined3d/texture.c +++ b/reactos/dll/directx/wine/wined3d/texture.c @@ -132,7 +132,7 @@ static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { FIXME("Texture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); for (i = 0; i < This->baseTexture.levels; i++) { - IWineD3DSurfaceImpl_AddDirtyRect(This->surfaces[i], NULL); + IWineD3DSurface_AddDirtyRect(This->surfaces[i], NULL); IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], This->baseTexture.textureName, IWineD3DTexture_GetTextureDimensions(iface)); IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode); } diff --git a/reactos/dll/directx/wine/wined3d/utils.c b/reactos/dll/directx/wine/wined3d/utils.c index dfc1fc6f52c..e108fca3078 100644 --- a/reactos/dll/directx/wine/wined3d/utils.c +++ b/reactos/dll/directx/wine/wined3d/utils.c @@ -27,8 +27,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); -#define GLINFO_LOCATION This->adapter->gl_info - /***************************************************************************** * Pixel format array */ @@ -150,14 +148,14 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { {WINED3DFMT_A8R8G8B8 ,GL_RGBA8 ,GL_SRGB8_ALPHA8_EXT ,GL_BGRA ,GL_UNSIGNED_INT_8_8_8_8_REV }, {WINED3DFMT_X8R8G8B8 ,GL_RGB8 ,GL_SRGB8_EXT ,GL_BGRA ,GL_UNSIGNED_INT_8_8_8_8_REV }, {WINED3DFMT_R5G6B5 ,GL_RGB5 ,GL_RGB5 ,GL_RGB ,GL_UNSIGNED_SHORT_5_6_5 }, - {WINED3DFMT_X1R5G5B5 ,GL_RGB5_A1 ,GL_RGB5_A1 ,GL_BGRA ,GL_UNSIGNED_SHORT_1_5_5_5_REV }, + {WINED3DFMT_X1R5G5B5 ,GL_RGB5 ,GL_RGB5_A1 ,GL_BGRA ,GL_UNSIGNED_SHORT_1_5_5_5_REV }, {WINED3DFMT_A1R5G5B5 ,GL_RGB5_A1 ,GL_RGB5_A1 ,GL_BGRA ,GL_UNSIGNED_SHORT_1_5_5_5_REV }, {WINED3DFMT_A4R4G4B4 ,GL_RGBA4 ,GL_SRGB8_ALPHA8_EXT ,GL_BGRA ,GL_UNSIGNED_SHORT_4_4_4_4_REV }, {WINED3DFMT_R3G3B2 ,GL_R3_G3_B2 ,GL_R3_G3_B2 ,GL_RGB ,GL_UNSIGNED_BYTE_3_3_2 }, {WINED3DFMT_A8 ,GL_ALPHA8 ,GL_ALPHA8 ,GL_ALPHA ,GL_UNSIGNED_BYTE }, {WINED3DFMT_A8R3G3B2 ,0 ,0 ,0 ,0 }, {WINED3DFMT_X4R4G4B4 ,GL_RGB4 ,GL_RGB4 ,GL_BGRA ,GL_UNSIGNED_SHORT_4_4_4_4_REV }, - {WINED3DFMT_A2B10G10R10 ,GL_RGB ,GL_RGB ,GL_RGBA ,GL_UNSIGNED_INT_2_10_10_10_REV }, + {WINED3DFMT_A2B10G10R10 ,GL_RGBA ,GL_RGBA ,GL_RGBA ,GL_UNSIGNED_INT_2_10_10_10_REV }, {WINED3DFMT_A8B8G8R8 ,GL_RGBA8 ,GL_RGBA8 ,GL_RGBA ,GL_UNSIGNED_INT_8_8_8_8_REV }, {WINED3DFMT_X8B8G8R8 ,GL_RGB8 ,GL_RGB8 ,GL_RGBA ,GL_UNSIGNED_INT_8_8_8_8_REV }, {WINED3DFMT_G16R16 ,0 ,0 ,0 ,0 }, @@ -169,8 +167,8 @@ static const GlPixelFormatDescTemplate gl_formats_template[] = { {WINED3DFMT_A4L4 ,GL_LUMINANCE4_ALPHA4 ,GL_LUMINANCE4_ALPHA4 ,GL_LUMINANCE_ALPHA ,GL_UNSIGNED_BYTE }, /* Bump mapping stuff */ {WINED3DFMT_V8U8 ,GL_DSDT8_NV ,GL_DSDT8_NV ,GL_DSDT_NV ,GL_BYTE }, - {WINED3DFMT_L6V5U5 ,GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX ,GL_UNSIGNED_SHORT_5_5_5_1 }, - {WINED3DFMT_X8L8V8U8 ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT_MAG_INTENSITY_NV ,GL_BYTE }, + {WINED3DFMT_L6V5U5 ,GL_DSDT8_MAG8_NV ,GL_DSDT8_MAG8_NV ,GL_DSDT_MAG_NV ,GL_BYTE }, + {WINED3DFMT_X8L8V8U8 ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT_MAG_VIB_NV ,GL_UNSIGNED_INT_8_8_S8_S8_REV_NV}, {WINED3DFMT_Q8W8V8U8 ,GL_SIGNED_RGBA8_NV ,GL_SIGNED_RGBA8_NV ,GL_RGBA ,GL_BYTE }, {WINED3DFMT_V16U16 ,GL_SIGNED_HILO16_NV ,GL_SIGNED_HILO16_NV ,GL_HILO_NV ,GL_SHORT }, {WINED3DFMT_W11V11U10 ,0 ,0 ,0 ,0 }, @@ -210,9 +208,11 @@ static inline int getFmtIdx(WINED3DFORMAT fmt) { return -1; } +#define GLINFO_LOCATION (*gl_info) BOOL initPixelFormats(WineD3D_GL_Info *gl_info) { unsigned int src; + int dst; gl_info->gl_formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(formats) / sizeof(formats[0]) * sizeof(gl_info->gl_formats[0])); @@ -222,15 +222,66 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info) * after this loop */ for(src = 0; src < sizeof(gl_formats_template) / sizeof(gl_formats_template[0]); src++) { - int dst = getFmtIdx(gl_formats_template[src].fmt); + dst = getFmtIdx(gl_formats_template[src].fmt); gl_info->gl_formats[dst].glInternal = gl_formats_template[src].glInternal; gl_info->gl_formats[dst].glGammaInternal = gl_formats_template[src].glGammaInternal; gl_info->gl_formats[dst].glFormat = gl_formats_template[src].glFormat; gl_info->gl_formats[dst].glType = gl_formats_template[src].glType; + gl_info->gl_formats[dst].conversion_group= WINED3DFMT_UNKNOWN; + } + + /* V8U8 is supported natively by GL_ATI_envmap_bumpmap and GL_NV_texture_shader. + * V16U16 is only supported by GL_NV_texture_shader. The formats need fixup if + * their extensions are not available. + * + * In theory, V8U8 and V16U16 need a fixup of the undefined blue channel. OpenGL + * returns 0.0 when sampling from it, DirectX 1.0. This is disabled until we find + * an application that needs this because it causes performance problems due to + * shader recompiling in some games. + */ + if(!GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && !GL_SUPPORT(NV_TEXTURE_SHADER2)) { + /* signed -> unsigned fixup */ + dst = getFmtIdx(WINED3DFMT_V8U8); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8; + dst = getFmtIdx(WINED3DFMT_V16U16); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8; + } else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + /* signed -> unsigned fixup */ + dst = getFmtIdx(WINED3DFMT_V16U16); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V16U16; + } else { + /* Blue = 1.0 fixup, disabled for now */ +#if 0 + dst = getFmtIdx(WINED3DFMT_V8U8); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8; + dst = getFmtIdx(WINED3DFMT_V16U16); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8; +#endif + } + + if(!GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* If GL_NV_texture_shader is not supported, those formats are converted, incompatibly + * with each other + */ + dst = getFmtIdx(WINED3DFMT_L6V5U5); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_L6V5U5; + dst = getFmtIdx(WINED3DFMT_X8L8V8U8); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_X8L8V8U8; + dst = getFmtIdx(WINED3DFMT_Q8W8V8U8); + gl_info->gl_formats[dst].conversion_group = WINED3DFMT_Q8W8V8U8; + } else { + /* If GL_NV_texture_shader is supported, WINED3DFMT_L6V5U5 and WINED3DFMT_X8L8V8U8 + * are converted at surface loading time, but they do not need any modification in + * the shader, thus they are compatible with all WINED3DFMT_UNKNOWN group formats. + * WINED3DFMT_Q8W8V8U8 doesn't even need load-time conversion + */ } return TRUE; } +#undef GLINFO_LOCATION + +#define GLINFO_LOCATION This->adapter->gl_info const StaticPixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt, WineD3D_GL_Info *gl_info, const GlPixelFormatDesc **glDesc) { @@ -2418,14 +2469,14 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP #endif /* Setup this textures matrix according to the texture flags*/ -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords) +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype) { float mat[16]; glMatrixMode(GL_TEXTURE); checkGLcall("glMatrixMode(GL_TEXTURE)"); - if (flags == WINED3DTTFF_DISABLE) { + if (flags == WINED3DTTFF_DISABLE || flags == WINED3DTTFF_COUNT1 || transformed) { glLoadIdentity(); checkGLcall("glLoadIdentity()"); return; @@ -2438,12 +2489,6 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords) memcpy(mat, smat, 16 * sizeof(float)); - switch (flags & ~WINED3DTTFF_PROJECTED) { - case WINED3DTTFF_COUNT1: mat[1] = mat[5] = mat[13] = 0; - case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; - default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1; - } - if (flags & WINED3DTTFF_PROJECTED) { switch (flags & ~WINED3DTTFF_PROJECTED) { case WINED3DTTFF_COUNT2: @@ -2455,9 +2500,58 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords) mat[2] = mat[6] = mat[10] = mat[14] = 0; break; } - } else if(!calculatedCoords) { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ - mat[12] = mat[8]; - mat[13] = mat[9]; + } else { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ + if(!calculatedCoords) { + switch(coordtype) { + case WINED3DDECLTYPE_FLOAT1: + /* Direct3D passes the default 1.0 in the 2nd coord, while gl passes it in the 4th. + * swap 2nd and 4th coord. No need to store the value of mat[12] in mat[4] because + * the input value to the transformation will be 0, so the matrix value is irrelevant + */ + mat[12] = mat[4]; + mat[13] = mat[5]; + mat[14] = mat[6]; + mat[15] = mat[7]; + break; + case WINED3DDECLTYPE_FLOAT2: + /* See above, just 3rd and 4th coord + */ + mat[12] = mat[8]; + mat[13] = mat[9]; + mat[14] = mat[10]; + mat[15] = mat[11]; + break; + case WINED3DDECLTYPE_FLOAT3: /* Opengl defaults match dx defaults */ + case WINED3DDECLTYPE_FLOAT4: /* No defaults apply, all app defined */ + + /* This is to prevent swaping the matrix lines and put the default 4th coord = 1.0 + * into a bad place. The division elimination below will apply to make sure the + * 1.0 doesn't do anything bad. The caller will set this value if the stride is 0 + */ + case WINED3DDECLTYPE_UNUSED: /* No texture coords, 0/0/0/1 defaults are passed */ + break; + default: + FIXME("Unexpected fixed function texture coord input\n"); + } + } + switch (flags & ~WINED3DTTFF_PROJECTED) { + /* case WINED3DTTFF_COUNT1: Won't ever get here */ + case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; + /* OpenGL divides the first 3 vertex coord by the 4th by default, + * which is essentially the same as D3DTTFF_PROJECTED. Make sure that + * the 4th coord evaluates to 1.0 to eliminate that. + * + * If the fixed function pipeline is used, the 4th value remains unused, + * so there is no danger in doing this. With vertex shaders we have a + * problem. Should an app hit that problem, the code here would have to + * check for pixel shaders, and the shader has to undo the default gl divide. + * + * A more serious problem occurs if the app passes 4 coordinates in, and the + * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow + * or a replacement shader + */ + default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1; + } } glLoadMatrixf(mat); @@ -2493,6 +2587,8 @@ BOOL getColorBits(WINED3DFORMAT fmt, short *redSize, short *greenSize, short *bl case WINED3DFMT_X1R5G5B5: case WINED3DFMT_A1R5G5B5: case WINED3DFMT_R5G6B5: + case WINED3DFMT_X4R4G4B4: + case WINED3DFMT_A4R4G4B4: case WINED3DFMT_R3G3B2: case WINED3DFMT_A8P8: case WINED3DFMT_P8: diff --git a/reactos/dll/directx/wine/wined3d/vertexdeclaration.c b/reactos/dll/directx/wine/wined3d/vertexdeclaration.c index 292f1f0ae3b..bc22d899135 100644 --- a/reactos/dll/directx/wine/wined3d/vertexdeclaration.c +++ b/reactos/dll/directx/wine/wined3d/vertexdeclaration.c @@ -136,7 +136,7 @@ static HRESULT WINAPI IWineD3DVertexDeclarationImpl_SetDeclaration(IWineD3DVerte This->pDeclarationWine = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DVERTEXELEMENT) * element_count); if (!This->pDeclarationWine) { ERR("Memory allocation failed\n"); - hr = WINED3DERR_OUTOFVIDEOMEMORY; + return WINED3DERR_OUTOFVIDEOMEMORY; } else { CopyMemory(This->pDeclarationWine, elements, sizeof(WINED3DVERTEXELEMENT) * element_count); } diff --git a/reactos/dll/directx/wine/wined3d/vertexshader.c b/reactos/dll/directx/wine/wined3d/vertexshader.c index 1c95d65c155..4e2a7c58dd6 100644 --- a/reactos/dll/directx/wine/wined3d/vertexshader.c +++ b/reactos/dll/directx/wine/wined3d/vertexshader.c @@ -108,30 +108,21 @@ CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = { {WINED3DSIO_DST, "dst", "DST", 1, 3, vshader_hw_map2gl, shader_glsl_dst, 0, 0}, {WINED3DSIO_LRP, "lrp", "LRP", 1, 4, NULL, shader_glsl_lrp, 0, 0}, {WINED3DSIO_FRC, "frc", "FRC", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, - {WINED3DSIO_POW, "pow", "POW", 1, 3, NULL, shader_glsl_pow, 0, 0}, - {WINED3DSIO_CRS, "crs", "XPS", 1, 3, NULL, shader_glsl_cross, 0, 0}, + {WINED3DSIO_POW, "pow", "POW", 1, 3, vshader_hw_map2gl, shader_glsl_pow, 0, 0}, + {WINED3DSIO_CRS, "crs", "XPD", 1, 3, vshader_hw_map2gl, shader_glsl_cross, 0, 0}, /* TODO: sng can possibly be performed a s RCP tmp, vec MUL out, tmp, vec*/ {WINED3DSIO_SGN, "sgn", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, - /* TODO: xyz normalise can be performed as VS_ARB using one temporary register, - DP3 tmp , vec, vec; - RSQ tmp, tmp.x; - MUL vec.xyz, vec, tmp; - but I think this is better because it accounts for w properly. - DP3 tmp , vec, vec; - RSQ tmp, tmp.x; - MUL vec, vec, tmp; - */ - {WINED3DSIO_NRM, "nrm", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, - {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, NULL, shader_glsl_sincos, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)}, - {WINED3DSIO_SINCOS, "sincos", NULL, 1, 2, NULL, shader_glsl_sincos, WINED3DVS_VERSION(3,0), -1}, + {WINED3DSIO_NRM, "nrm", NULL, 1, 2, shader_hw_nrm, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, shader_hw_sincos, shader_glsl_sincos, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)}, + {WINED3DSIO_SINCOS, "sincos", "SCS", 1, 2, shader_hw_sincos, shader_glsl_sincos, WINED3DVS_VERSION(3,0), -1}, /* Matrix */ - {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, - {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, shader_hw_mnxn, shader_glsl_mnxn, 0, 0}, /* Declare registers */ {WINED3DSIO_DCL, "dcl", NULL, 0, 2, NULL, NULL, 0, 0}, /* Constant definitions */ @@ -333,26 +324,34 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); /* Unpack 3.0 outputs */ - if (This->baseShader.hex_version >= WINED3DVS_VERSION(3,0)) - vshader_glsl_output_unpack(&buffer, This->semantics_out); + if (This->baseShader.hex_version >= WINED3DVS_VERSION(3,0)) { + shader_addline(&buffer, "order_ps_input(OUT);\n"); + } else { + shader_addline(&buffer, "order_ps_input();\n"); + } /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */ if (!reg_maps->fog) shader_addline(&buffer, "gl_FogFragCoord = gl_Position.z;\n"); - + /* Write the final position. * * OpenGL coordinates specify the center of the pixel while d3d coords specify - * the corner. The offsets are stored in z and w in the 2nd row of the projection - * matrix to avoid wasting a free shader constant. Add them to the w and z coord - * of the 2nd row + * the corner. The offsets are stored in z and w in posFixup. posFixup.y contains + * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x + * contains 1.0 to allow a mad. */ - shader_addline(&buffer, "gl_Position.x = gl_Position.x + posFixup[2];\n"); - shader_addline(&buffer, "gl_Position.y = gl_Position.y + posFixup[3];\n"); - /* Account for any inverted textures (render to texture case) by reversing the y coordinate - * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices) + shader_addline(&buffer, "gl_Position.xy = gl_Position.xy * posFixup.xy + posFixup.zw;\n"); + + /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c + * + * Basically we want(in homogenous coordinates) z = z * 2 - 1. However, shaders are run + * before the homogenous divide, so we have to take the w into account: z = ((z / w) * 2 - 1) * w, + * which is the same as z = z / 2 - w. */ - shader_addline(&buffer, "gl_Position.y = gl_Position.y * posFixup[1];\n"); + shader_addline(&buffer, "tmp0 = gl_Position;\n"); + shader_addline(&buffer, "gl_Position.z = tmp0.z * 2.0;\n"); + shader_addline(&buffer, "gl_Position.z = gl_Position.z - gl_Position.w;\n"); shader_addline(&buffer, "}\n"); @@ -368,12 +367,18 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( /* Create the hw ARB shader */ shader_addline(&buffer, "!!ARBvp1.0\n"); + shader_addline(&buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset); /* Mesa supports only 95 constants */ if (GL_VEND(MESA) || GL_VEND(WINE)) This->baseShader.limits.constant_float = min(95, This->baseShader.limits.constant_float); + /* Some instructions need a temporary register. Add it if needed, but only if it is really needed */ + if(reg_maps->usesnrm || This->rel_offset) { + shader_addline(&buffer, "TEMP TMP;\n"); + } + /* Base Declarations */ shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); @@ -390,15 +395,17 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( /* Write the final position. * * OpenGL coordinates specify the center of the pixel while d3d coords specify - * the corner. The offsets are stored in the 2nd row of the projection matrix, - * the x offset in z and the y offset in w. Add them to the resulting position + * the corner. The offsets are stored in z and w in posFixup. posFixup.y contains + * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x + * contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that. */ - shader_addline(&buffer, "ADD TMP_OUT.x, TMP_OUT.x, posFixup.z;\n"); - shader_addline(&buffer, "ADD TMP_OUT.y, TMP_OUT.y, posFixup.w;\n"); - /* Account for any inverted textures (render to texture case) by reversing the y coordinate - * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices) + shader_addline(&buffer, "ADD TMP_OUT.x, TMP_OUT.x, posFixup.z;"); + shader_addline(&buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, posFixup.w;"); + + /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c + * and the glsl equivalent */ - shader_addline(&buffer, "MUL TMP_OUT.y, TMP_OUT.y, posFixup.y;\n"); + shader_addline(&buffer, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n"); shader_addline(&buffer, "MOV result.position, TMP_OUT;\n"); @@ -460,11 +467,6 @@ static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface TRACE("(%p) : Releasing from %d\n", This, This->ref); ref = InterlockedDecrement(&This->ref); if (ref == 0) { - if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->vertexShader) { - /* See comment in PixelShader::Release */ - IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_VSHADER); - } - if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { struct list *linked_programs = &This->baseShader.linked_programs; @@ -560,6 +562,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader list_init(&This->baseShader.constantsI); /* Second pass: figure out registers used, semantics, etc.. */ + This->min_rel_offset = GL_LIMITS(vshader_constantsF); + This->max_rel_offset = 0; memset(reg_maps, 0, sizeof(shader_reg_maps)); hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps, This->semantics_in, This->semantics_out, pFunction, NULL); @@ -567,6 +571,23 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader This->baseShader.shader_mode = deviceImpl->vs_selected_mode; + if(deviceImpl->vs_selected_mode == SHADER_ARB && + (GLINFO_LOCATION).arb_vs_offset_limit && + This->min_rel_offset <= This->max_rel_offset) { + + if(This->max_rel_offset - This->min_rel_offset > 127) { + FIXME("The difference between the minimum and maximum relative offset is > 127\n"); + FIXME("Which this OpenGL implementation does not support. Try using GLSL\n"); + FIXME("Min: %d, Max: %d\n", This->min_rel_offset, This->max_rel_offset); + } else if(This->max_rel_offset - This->min_rel_offset > 63) { + This->rel_offset = This->min_rel_offset + 63; + } else if(This->max_rel_offset > 63) { + This->rel_offset = This->min_rel_offset; + } else { + This->rel_offset = 0; + } + } + /* copy the function ... because it will certainly be released by application */ if (NULL != pFunction) { void *function; diff --git a/reactos/dll/directx/wine/wined3d/volume.c b/reactos/dll/directx/wine/wined3d/volume.c index 425a45ed7c8..a70a3519eef 100644 --- a/reactos/dll/directx/wine/wined3d/volume.c +++ b/reactos/dll/directx/wine/wined3d/volume.c @@ -270,9 +270,18 @@ static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, int TRACE("(%p) : level %u, format %s (0x%08x)\n", This, gl_level, debug_d3dformat(format), format); - if(GL_SUPPORT(EXT_TEXTURE3D)) { - TRACE("Calling glTexImage3D %x level=%d, intfmt=%x, w=%d, h=%d,d=%d, 0=%d, glFmt=%x, glType=%x, Mem=%p\n", - GL_TEXTURE_3D, + TRACE("Calling glTexImage3D %x level=%d, intfmt=%x, w=%d, h=%d,d=%d, 0=%d, glFmt=%x, glType=%x, Mem=%p\n", + GL_TEXTURE_3D, + gl_level, + glDesc->glInternal, + This->currentDesc.Width, + This->currentDesc.Height, + This->currentDesc.Depth, + 0, + glDesc->glFormat, + glDesc->glType, + This->resource.allocatedMemory); + GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, gl_level, glDesc->glInternal, This->currentDesc.Width, @@ -281,20 +290,8 @@ static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, int 0, glDesc->glFormat, glDesc->glType, - This->resource.allocatedMemory); - GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, - gl_level, - glDesc->glInternal, - This->currentDesc.Width, - This->currentDesc.Height, - This->currentDesc.Depth, - 0, - glDesc->glFormat, - glDesc->glType, - This->resource.allocatedMemory)); - checkGLcall("glTexImage3D"); - } else - WARN("This OpenGL implementation doesn't support 3D textures\n"); + This->resource.allocatedMemory)); + checkGLcall("glTexImage3D"); /* When adding code releasing This->resource.allocatedMemory to save data keep in mind that * GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by default if supported(GL_APPLE_client_storage). diff --git a/reactos/dll/directx/wine/wined3d/wined3d.rbuild b/reactos/dll/directx/wine/wined3d/wined3d.rbuild index 0262d28b811..f8e3496c308 100644 --- a/reactos/dll/directx/wine/wined3d/wined3d.rbuild +++ b/reactos/dll/directx/wine/wined3d/wined3d.rbuild @@ -1,6 +1,6 @@ - + . include/reactos/wine @@ -36,6 +36,7 @@ resource.c state.c stateblock.c + surface_base.c surface.c surface_gdi.c swapchain.c diff --git a/reactos/dll/directx/wine/wined3d/wined3d_main.c b/reactos/dll/directx/wine/wined3d/wined3d_main.c index 13ab258dbb8..26e7f707cad 100644 --- a/reactos/dll/directx/wine/wined3d/wined3d_main.c +++ b/reactos/dll/directx/wine/wined3d/wined3d_main.c @@ -39,25 +39,13 @@ wined3d_settings_t wined3d_settings = VS_HW, /* Hardware by default */ PS_HW, /* Hardware by default */ VBO_HW, /* Hardware by default */ - FALSE, /* Use of GLSL disabled by default */ + TRUE, /* Use of GLSL enabled by default */ ORM_BACKBUFFER, /* Use the backbuffer to do offscreen rendering */ RTL_AUTO, /* Automatically determine best locking method */ - 64*1024*1024 /* 64MB texture memory by default */ + 0, /* The default of memory is set in FillGLCaps */ + NULL /* No wine logo by default */ }; -WineD3DGlobalStatistics *wineD3DGlobalStatistics = NULL; - -long globalChangeGlRam(long glram){ - /* FIXME: replace this function with object tracking */ - int result; - - wineD3DGlobalStatistics->glsurfaceram += glram; - TRACE("Adjusted gl ram by %ld to %d\n", glram, wineD3DGlobalStatistics->glsurfaceram); - result = wineD3DGlobalStatistics->glsurfaceram; - return result; - -} - IWineD3D* WINAPI WineDirect3DCreate(UINT SDKVersion, UINT dxVersion, IUnknown *parent) { IWineD3DImpl* object; @@ -75,13 +63,6 @@ IWineD3D* WINAPI WineDirect3DCreate(UINT SDKVersion, UINT dxVersion, IUnknown *p object->ref = 1; object->parent = parent; - /*Create a structure for storing global data in*/ - if(wineD3DGlobalStatistics == NULL){ - TRACE("Creating global statistics store\n"); - wineD3DGlobalStatistics = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wineD3DGlobalStatistics)); - - } - TRACE("Created WineD3D object @ %p for d3d%d support\n", object, dxVersion); return (IWineD3D *)object; @@ -112,8 +93,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) DWORD len; WNDCLASSA wc; - wined3d_settings.emulated_textureram = 64*1024*1024; - /* We need our own window class for a fake window which we use to retrieve GL capabilities */ /* We might need CS_OWNDC in the future if we notice strange things on Windows. * Various articles/posts about OpenGL problems on Windows recommend this. */ @@ -205,14 +184,10 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) } if ( !get_config_key( hkey, appkey, "UseGLSL", buffer, size) ) { - if (!strcmp(buffer,"enabled")) - { - TRACE("Use of GL Shading Language enabled for systems that support it\n"); - wined3d_settings.glslRequested = TRUE; - } - else + if (!strcmp(buffer,"disabled")) { TRACE("Use of GL Shading Language disabled\n"); + wined3d_settings.glslRequested = FALSE; } } if ( !get_config_key( hkey, appkey, "OffscreenRenderingMode", buffer, size) ) @@ -274,6 +249,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) else ERR("VideoMemorySize is %i but must be >0\n", TmpVideoMemorySize); } + if ( !get_config_key( hkey, appkey, "WineLogo", buffer, size) ) + { + wined3d_settings.logo = HeapAlloc(GetProcessHeap(), 0, strlen(buffer) + 1); + if(wined3d_settings.logo) strcpy(wined3d_settings.logo, buffer); + } } if (wined3d_settings.vs_mode == VS_HW) TRACE("Allow HW vertex shaders\n"); diff --git a/reactos/dll/directx/wine/wined3d/wined3d_private.h b/reactos/dll/directx/wine/wined3d/wined3d_private.h index 73e83d24ace..60e586b098e 100644 --- a/reactos/dll/directx/wine/wined3d/wined3d_private.h +++ b/reactos/dll/directx/wine/wined3d/wined3d_private.h @@ -97,7 +97,7 @@ void hash_table_remove(hash_table_t *table, void *key); #define NUM_SAVEDPIXELSTATES_R 35 #define NUM_SAVEDPIXELSTATES_T 18 #define NUM_SAVEDPIXELSTATES_S 12 -#define NUM_SAVEDVERTEXSTATES_R 31 +#define NUM_SAVEDVERTEXSTATES_R 34 #define NUM_SAVEDVERTEXSTATES_T 2 #define NUM_SAVEDVERTEXSTATES_S 1 @@ -203,17 +203,20 @@ typedef struct wined3d_settings_s { int rendertargetlock_mode; /* Memory tracking and object counting */ unsigned int emulated_textureram; + char *logo; } wined3d_settings_t; extern wined3d_settings_t wined3d_settings; /* Shader backends */ +struct SHADER_OPCODE_ARG; typedef struct { void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS); void (*shader_select_depth_blt)(IWineD3DDevice *iface); void (*shader_load_constants)(IWineD3DDevice *iface, char usePS, char useVS); void (*shader_cleanup)(IWineD3DDevice *iface); + void (*shader_color_correction)(struct SHADER_OPCODE_ARG *arg); } shader_backend_t; extern const shader_backend_t glsl_shader_backend; @@ -329,23 +332,6 @@ typedef struct IWineD3DSurfaceImpl IWineD3DSurfaceImpl; typedef struct IWineD3DPaletteImpl IWineD3DPaletteImpl; typedef struct IWineD3DDeviceImpl IWineD3DDeviceImpl; -/* Tracking */ - -/* TODO: Move some of this to the device */ -long globalChangeGlRam(long glram); - -/* Memory and object tracking */ - -/*Structure for holding information on all direct3d objects -useful for making sure tracking is ok and when release is called on a device! -and probably quite handy for debugging and dumping states out -*/ -typedef struct WineD3DGlobalStatistics { - int glsurfaceram; /* The aproximate amount of glTexture memory allocated for textures */ -} WineD3DGlobalStatistics; - -extern WineD3DGlobalStatistics* wineD3DGlobalStatistics; - /* Global variables */ extern const float identity[16]; @@ -429,8 +415,6 @@ void primitiveDeclarationConvertToStridedData( DWORD get_flexible_vertex_size(DWORD d3dvtVertexType); -void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface); - #define eps 1e-8 #define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \ @@ -486,7 +470,9 @@ typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock, #define STATE_MATERIAL (STATE_CLIPPLANE(MAX_CLIPPLANES)) -#define STATE_HIGHEST (STATE_MATERIAL) +#define STATE_FRONTFACE (STATE_MATERIAL + 1) + +#define STATE_HIGHEST (STATE_FRONTFACE) struct StateEntry { @@ -513,6 +499,7 @@ struct WineD3DContext { DWORD tid; /* Thread ID which owns this context at the moment */ /* Stores some inforation about the context state for optimization */ + GLint last_draw_buffer; BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */ BOOL last_was_pshader; BOOL last_was_vshader; @@ -524,6 +511,7 @@ struct WineD3DContext { GLenum untracked_materials[2]; BOOL last_was_blit, last_was_ckey; char texShaderBumpMap; + BOOL fog_coord; /* The actual opengl context */ HGLRC glCtx; @@ -597,10 +585,13 @@ struct WineD3DAdapter WCHAR DeviceName[CCHDEVICENAME]; /* DeviceName for use with e.g. ChangeDisplaySettings */ int nCfgs; WineD3D_PixelFormat *cfgs; + unsigned int TextureRam; /* Amount of texture memory both video ram + AGP/TurboCache/HyperMemory/.. */ + unsigned int UsedTextureRam; }; extern BOOL InitAdapters(void); extern BOOL initPixelFormats(WineD3D_GL_Info *gl_info); +extern long WineD3DAdapterChangeGLRam(IWineD3DDeviceImpl *D3DDevice, long glram); /***************************************************************************** * High order patch management @@ -713,6 +704,7 @@ struct IWineD3DDeviceImpl /* palettes texture management */ PALETTEENTRY palettes[MAX_PALETTES][256]; UINT currentPalette; + UINT paletteConversionShader; /* For rendering to a texture using glCopyTexImage */ BOOL render_offscreen; @@ -733,6 +725,9 @@ struct IWineD3DDeviceImpl BOOL haveHardwareCursor; HCURSOR hardwareCursor; + /* The Wine logo surface */ + IWineD3DSurface *logo_surface; + /* Textures for when no other textures are mapped */ UINT dummyTextureName[MAX_TEXTURES]; @@ -829,7 +824,8 @@ typedef struct IWineD3DResourceClass UINT size; DWORD usage; WINED3DFORMAT format; - BYTE *allocatedMemory; + BYTE *allocatedMemory; /* Pointer to the real data location */ + BYTE *heapMemory; /* Pointer to the HeapAlloced block of memory */ struct list privateData; } IWineD3DResourceClass; @@ -841,6 +837,8 @@ typedef struct IWineD3DResourceImpl IWineD3DResourceClass resource; } IWineD3DResourceImpl; +/* Tests show that the start address of resources is 32 byte aligned */ +#define RESOURCE_ALIGNMENT 32 /***************************************************************************** * IWineD3DVertexBuffer implementation structure (extends IWineD3DResourceImpl) @@ -931,6 +929,7 @@ typedef struct IWineD3DBaseTextureClass DWORD sampler; BOOL is_srgb; UINT srgb_mode_change_count; + WINED3DFORMAT shader_conversion_group; } IWineD3DBaseTextureClass; typedef struct IWineD3DBaseTextureImpl @@ -1050,6 +1049,7 @@ typedef struct _WINED3DSURFACET_DESC typedef struct wineD3DSurface_DIB { HBITMAP DIBsection; void* bitmap_data; + UINT bitmap_size; HGDIOBJ holdbitmap; BOOL client_memory; } wineD3DSurface_DIB; @@ -1100,6 +1100,9 @@ struct IWineD3DSurfaceImpl /* Oversized texture */ RECT glRect; + /* PBO */ + GLuint pbo; + #if 0 /* precalculated x and y scalings for texture coords */ float pow2scalingFactorX; /* = (Width / pow2Width ) */ @@ -1112,6 +1115,7 @@ struct IWineD3DSurfaceImpl #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy */ glDescriptor glDescription; + BOOL srgb; /* For GetDC */ wineD3DSurface_DIB dib; @@ -1137,49 +1141,41 @@ extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl; extern const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl; /* Predeclare the shared Surface functions */ -HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj); -ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface); -ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent); -HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice); -HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags); -HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData); -HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid); -DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew); -DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface); -void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface); -WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer); -HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc); -HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags); -HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags); -HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size); -HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal); -HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal); -HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey); -HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface); -extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect); -HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container); -void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target); -void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj); +ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid); +DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew); +DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface); +WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container); +DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_RealizePalette(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format); +HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags); + const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format); -HRESULT WINAPI IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter); -HRESULT WINAPI IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans); -HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal); -HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC); -HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC); -DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface); -HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem); -HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y); -HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y); -HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref); -HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX); -HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper); -HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper); /* Surface flags: */ #define SFLAG_OVERSIZE 0x00000001 /* Surface is bigger than gl size, blts only */ @@ -1200,6 +1196,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DCl #define SFLAG_GLCKEY 0x00008000 /* The gl texture was created with a color key */ #define SFLAG_CLIENT 0x00010000 /* GL_APPLE_client_storage is used on that texture */ #define SFLAG_ALLOCATED 0x00020000 /* A gl texture is allocated for this surface */ +#define SFLAG_PBO 0x00040000 /* Has a PBO attached for speeding up data transfers for dynamically locked surfaces */ /* In some conditions the surface memory must not be freed: * SFLAG_OVERSIZE: Not all data can be kept in GL @@ -1208,6 +1205,7 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DCl * SFLAG_LOCKED: The app requires access to the surface data * SFLAG_DYNLOCK: Avoid freeing the data for performance * SFLAG_DYNCHANGE: Same reason as DYNLOCK + * SFLAG_PBO: PBOs don't use 'normal' memory. It is either allocated by the driver or must be NULL. * SFLAG_CLIENT: OpenGL uses our memory as backup */ #define SFLAG_DONOTFREE (SFLAG_OVERSIZE | \ @@ -1217,8 +1215,12 @@ HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DCl SFLAG_DYNLOCK | \ SFLAG_DYNCHANGE | \ SFLAG_USERPTR | \ + SFLAG_PBO | \ SFLAG_CLIENT) +#define SFLAG_LOCATIONS (SFLAG_INSYSMEM | \ + SFLAG_INTEXTURE | \ + SFLAG_INDRAWABLE) BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]); typedef enum { @@ -1236,6 +1238,7 @@ typedef enum { CONVERT_CK_8888_ARGB, CONVERT_RGB32_888, CONVERT_V8U8, + CONVERT_L6V5U5, CONVERT_X8L8V8U8, CONVERT_Q8W8V8U8, CONVERT_V16U16, @@ -1348,8 +1351,8 @@ struct IWineD3DStateBlockImpl /* Indices */ IWineD3DIndexBuffer* pIndexData; - UINT baseVertexIndex; - UINT loadBaseVertexIndex; /* non-indexed drawing needs 0 here, indexed baseVertexIndex */ + INT baseVertexIndex; + INT loadBaseVertexIndex; /* non-indexed drawing needs 0 here, indexed baseVertexIndex */ /* Transform */ WINED3DMATRIX transforms[HIGHEST_TRANSFORMSTATE + 1]; @@ -1465,10 +1468,12 @@ extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl; /* Datastructures for IWineD3DQueryImpl.extendedData */ typedef struct WineQueryOcclusionData { GLuint queryId; + WineD3DContext *ctx; } WineQueryOcclusionData; typedef struct WineQueryEventData { GLuint fenceId; + WineD3DContext *ctx; } WineQueryEventData; /***************************************************************************** @@ -1535,7 +1540,7 @@ GLenum StencilOp(DWORD op); GLenum CompareFunc(DWORD func); void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3); void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx); -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords); +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype); void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height); GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain); @@ -1545,6 +1550,7 @@ BOOL getDepthStencilBits(WINED3DFORMAT fmt, short *depthSize, short *stencilSize /* Math utils */ void multiply_matrix(WINED3DMATRIX *dest, const WINED3DMATRIX *src1, const WINED3DMATRIX *src2); +unsigned int count_bits(unsigned int mask); /***************************************************************************** * To enable calling of inherited functions, requires prototypes @@ -1600,7 +1606,6 @@ void multiply_matrix(WINED3DMATRIX *dest, const WINED3DMATRIX *src1, const WINED /*** class static members ***/ void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface); -struct SHADER_OPCODE_ARG; typedef void (*SHADER_HANDLER) (struct SHADER_OPCODE_ARG*); /* Struct to maintain a list of GLSL shader programs and their associated pixel and @@ -1612,6 +1617,15 @@ struct glsl_shader_prog_link { GLhandleARB programId; GLhandleARB *vuniformF_locations; GLhandleARB *puniformF_locations; + GLhandleARB vuniformI_locations[MAX_CONST_I]; + GLhandleARB puniformI_locations[MAX_CONST_I]; + GLhandleARB posFixup_location; + GLhandleARB bumpenvmat_location; + GLhandleARB luminancescale_location; + GLhandleARB luminanceoffset_location; + GLhandleARB srgb_comparison_location; + GLhandleARB srgb_mul_low_location; + GLhandleARB ycorrection_location; GLhandleARB vshader; GLhandleARB pshader; }; @@ -1659,10 +1673,11 @@ typedef struct shader_reg_maps { /* Sampler usage tokens * Use 0 as default (bit 31 is always 1 on a valid token) */ DWORD samplers[max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS)]; - char bumpmat; + char bumpmat, luminanceparams; + char usesnrm, vpos, usesdsy; - /* Whether or not a loop is used in this shader */ - char loop; + /* Whether or not loops are used in this shader, and nesting depth */ + unsigned loop_depth; /* Whether or not this shader uses fog */ char fog; @@ -1788,10 +1803,22 @@ extern void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg); extern void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texdepth(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texkill(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texdp3tex(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texdp3(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x3(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x2depth(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_dp2add(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texreg2rgb(SHADER_OPCODE_ARG* arg); + +/* ARB vertex / pixel shader common prototypes */ +extern void shader_hw_nrm(SHADER_OPCODE_ARG* arg); +extern void shader_hw_sincos(SHADER_OPCODE_ARG* arg); +extern void shader_hw_mnxn(SHADER_OPCODE_ARG* arg); /* ARB vertex shader prototypes */ extern void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg); -extern void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg); extern void vshader_hw_rsq_rcp(SHADER_OPCODE_ARG* arg); /* GLSL helper functions */ @@ -1834,6 +1861,7 @@ extern void shader_glsl_call(SHADER_OPCODE_ARG* arg); extern void shader_glsl_callnz(SHADER_OPCODE_ARG* arg); extern void shader_glsl_label(SHADER_OPCODE_ARG* arg); extern void shader_glsl_pow(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_log(SHADER_OPCODE_ARG* arg); extern void shader_glsl_texldl(SHADER_OPCODE_ARG* arg); /** GLSL Pixel Shader Prototypes */ @@ -1859,12 +1887,8 @@ extern void pshader_glsl_texreg2rgb(SHADER_OPCODE_ARG* arg); extern void pshader_glsl_dp2add(SHADER_OPCODE_ARG* arg); extern void pshader_glsl_input_pack( SHADER_BUFFER* buffer, - semantic* semantics_out); - -/** GLSL Vertex Shader Prototypes */ -extern void vshader_glsl_output_unpack( - SHADER_BUFFER* buffer, - semantic* semantics_out); + semantic* semantics_out, + IWineD3DPixelShader *iface); /***************************************************************************** * IDirect3DBaseShader implementation structure @@ -1879,6 +1903,7 @@ typedef struct IWineD3DBaseShaderClass UINT functionLength; GLuint prgId; BOOL is_compiled; + UINT cur_loop_depth, cur_loop_regno; /* Type of shader backend */ int shader_mode; @@ -1892,6 +1917,17 @@ typedef struct IWineD3DBaseShaderClass struct list constantsI; shader_reg_maps reg_maps; + /* Pixel formats of sampled textures, for format conversion. This + * represents the formats found during compilation, it is not initialized + * on the first parser pass. It is needed to check if the shader + * needs recompilation to adjust the format conversion + */ + WINED3DFORMAT sampled_format[MAX_COMBINED_SAMPLERS]; + UINT sampled_samplers[MAX_COMBINED_SAMPLERS]; + UINT num_sampled_samplers; + + UINT recompile_count; + /* Pointer to the parent device */ IWineD3DDevice *device; @@ -2030,6 +2066,9 @@ typedef struct IWineD3DVertexShaderImpl { /* run time datas... */ VSHADERDATA *data; + UINT min_rel_offset, max_rel_offset; + UINT rel_offset; + #if 0 /* needs reworking */ /* run time datas */ VSHADERINPUTDATA input; @@ -2042,6 +2081,13 @@ extern const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl; /***************************************************************************** * IDirect3DPixelShader implementation structure */ + +enum vertexprocessing_mode { + fixedfunction, + vertexshader, + pretransformed +}; + typedef struct IWineD3DPixelShaderImpl { /* IUnknown parts */ const IWineD3DPixelShaderVtbl *lpVtbl; @@ -2055,6 +2101,8 @@ typedef struct IWineD3DPixelShaderImpl { /* Pixel shader input semantics */ semantic semantics_in [MAX_REG_INPUT]; + DWORD input_reg_map[MAX_REG_INPUT]; + BOOL input_reg_used[MAX_REG_INPUT]; /* run time data */ PSHADERDATA *data; @@ -2062,6 +2110,15 @@ typedef struct IWineD3DPixelShaderImpl { /* Some information about the shader behavior */ char needsbumpmat; UINT bumpenvmatconst; + UINT luminanceconst; + char srgb_enabled; + char srgb_mode_hardcoded; + UINT srgb_low_const; + UINT srgb_cmp_const; + char vpos_uniform; + BOOL render_offscreen; + UINT height; + enum vertexprocessing_mode vertexprocessing; #if 0 /* needs reworking */ PSHADERINPUTDATA input; @@ -2072,6 +2129,13 @@ typedef struct IWineD3DPixelShaderImpl { extern const SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[]; extern const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl; +/* sRGB correction constants */ +static const float srgb_cmp = 0.0031308; +static const float srgb_mul_low = 12.92; +static const float srgb_pow = 0.41666; +static const float srgb_mul_high = 1.055; +static const float srgb_sub_high = 0.055; + /***************************************************************************** * IWineD3DPalette implementation structure */ diff --git a/reactos/dll/directx/wine/wined3d/wined3d_private_types.h b/reactos/dll/directx/wine/wined3d/wined3d_private_types.h index 3550910101e..8a7750f8ecd 100644 --- a/reactos/dll/directx/wine/wined3d/wined3d_private_types.h +++ b/reactos/dll/directx/wine/wined3d/wined3d_private_types.h @@ -293,6 +293,7 @@ typedef enum _WINED3DSHADER_INSTRUCTION_OPCODE_TYPE { /* Undocumented opcode control to identify projective texture lookups in ps 2.0 and later */ #define WINED3DSI_TEXLD_PROJECT 0x00010000 +#define WINED3DSI_TEXLD_BIAS 0x00020000 /** Shader version tokens, and shader end tokens **/ diff --git a/reactos/include/reactos/wine/wined3d_gl.h b/reactos/include/reactos/wine/wined3d_gl.h index 132fe432d5e..254826ed856 100644 --- a/reactos/include/reactos/wine/wined3d_gl.h +++ b/reactos/include/reactos/wine/wined3d_gl.h @@ -1137,6 +1137,7 @@ void (WINE_GLAPI *glVertex4s) (GLshort x, GLshort y, GLshort z, GLshort w); void (WINE_GLAPI *glVertex4sv) (const GLshort* v); void (WINE_GLAPI *glVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid* pointer); void (WINE_GLAPI *glViewport) (GLint x, GLint y, GLsizei width, GLsizei height); +void (WINE_GLAPI *glPointParameterfv) (GLenum pname, const GLfloat *params); /* WGL functions */ HGLRC (WINAPI *pwglCreateContext)(HDC); @@ -1483,7 +1484,8 @@ BOOL (WINAPI *pwglShareLists)(HGLRC,HGLRC); USE_GL_FUNC(glVertex4s) \ USE_GL_FUNC(glVertex4sv) \ USE_GL_FUNC(glVertexPointer) \ - USE_GL_FUNC(glViewport) + USE_GL_FUNC(glViewport) \ + USE_GL_FUNC(glPointParameterfv) \ #define WGL_FUNCS_GEN \ USE_WGL_FUNC(wglCreateContext) \ @@ -2353,6 +2355,13 @@ typedef GLhandleARB (WINE_GLAPI * WINED3D_PFNGLGETHANDLEARBPROC) (GLenum pname); typedef void (WINE_GLAPI * WINED3D_PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); typedef void (WINE_GLAPI * WINED3D_PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); typedef GLint (WINE_GLAPI * WINED3D_PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +/* GL_ARB_pixel_buffer_object */ +#ifndef GL_ARB_pixel_buffer_object +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#endif /* GL_EXT_texture */ #ifndef GL_EXT_texture #define GL_EXT_texture 1 @@ -2709,7 +2718,7 @@ typedef void (WINE_GLAPI * PGLFNGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage #endif /** - * Point sprites + * Point sprites */ /* GL_ARB_point_sprite */ #ifndef GL_ARB_point_sprite @@ -2718,11 +2727,11 @@ typedef void (WINE_GLAPI * PGLFNGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage #define GL_COORD_REPLACE_ARB 0x8862 #endif /** - * @TODO: GL_NV_point_sprite + * @TODO: GL_NV_point_sprite */ /** - * Occlusion Queries + * Occlusion Queries */ /* GL_ARB_occlusion_query */ #ifndef GL_ARB_occlusion_query @@ -2833,6 +2842,30 @@ typedef void (WINE_GLAPI * PGLFNGETTEXBUMPPARAMETERFVATIPROC) (GLenum, GLfloat * typedef int (WINE_GLAPI * PGLXFNGETVIDEOSYNCSGIPROC) (unsigned int *); typedef int (WINE_GLAPI * PGLXFNWAITVIDEOSYNCSGIPROC) (int, int, unsigned int *); +/* GL_SGIS_generate_mipmap */ +#ifndef GLX_SGIS_generate_mipmap +#define GL_GENERATE_MIPMAP_SGIS 0x8191 +#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#define GLX_SGIS_generate_mipmap +#endif + +/* GL_NV_depth_clamp */ +#ifndef GL_NV_depth_clamp +#define GL_DEPTH_CLAMP_NV 0x864F +#endif + +/* GL_APPLE_flush_render */ +typedef void (WINE_GLAPI * PGLFNFLUSHRENDERAPPLEPROC) (void); +typedef void (WINE_GLAPI * PGLFNFINISHRENDERAPPLEPROC) (void); + +/* GL_APPLE_ycbcr_422 */ +#ifndef GL_APPLE_ycbcr_422 +#define GL_APPLE_ycbcr_422 +#define GL_YCBCR_422_APPLE 0x85B9 +#define UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#endif + /* GL_VERSION_2_0 */ #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 @@ -3018,8 +3051,8 @@ typedef void (WINE_GLAPI * PGLFNVERTEXATTRIBPOINTERPROC) (GLuint index, GLint si /**************************************************** - * OpenGL Official Version - * defines + * OpenGL Official Version + * defines ****************************************************/ /* GL_VERSION_1_3 */ #if !defined(GL_DOT3_RGBA) @@ -3050,6 +3083,9 @@ typedef enum _GL_Cards { CARD_ATI_RADEON_9500 = 0x4144, CARD_ATI_RADEON_X700 = 0x5e4c, CARD_ATI_RADEON_X1600 = 0x71c2, + CARD_ATI_RADEON_HD2300 = 0x7210, + CARD_ATI_RADEON_HD2600 = 0x9581, + CARD_ATI_RADEON_HD2900 = 0x9400, CARD_NVIDIA_RIVA_128 = 0x0018, CARD_NVIDIA_RIVA_TNT = 0x0020, @@ -3067,6 +3103,9 @@ typedef enum _GL_Cards { CARD_NVIDIA_GEFORCE_6600GT = 0x0140, CARD_NVIDIA_GEFORCE_6800 = 0x0041, CARD_NVIDIA_GEFORCE_7800GT = 0x0092, + CARD_NVIDIA_GEFORCE_8300GS = 0x0423, + CARD_NVIDIA_GEFORCE_8600GT = 0x0402, + CARD_NVIDIA_GEFORCE_8800GTS = 0x0193, CARD_INTEL_845G = 0x2562, CARD_INTEL_I830G = 0x3577, @@ -3076,6 +3115,8 @@ typedef enum _GL_Cards { CARD_INTEL_I915GM = 0x2592 } GL_Cards; +#define WINE_DEFAULT_VIDMEM 64*1024*1024 + typedef enum _GL_VSVersion { VS_VERSION_NOT_SUPPORTED = 0x0, VS_VERSION_10 = 0x10, @@ -3167,6 +3208,7 @@ typedef enum _GL_SupportedExt { NV_VERTEX_PROGRAM2, NV_VERTEX_PROGRAM3, NV_FENCE, + NV_DEPTH_CLAMP, /* ATI */ ATI_SEPARATE_STENCIL, ATI_TEXTURE_ENV_COMBINE3, @@ -3176,8 +3218,11 @@ typedef enum _GL_SupportedExt { /* APPLE */ APPLE_FENCE, APPLE_CLIENT_STORAGE, + APPLE_FLUSH_RENDER, + APPLE_YCBCR_422, /* SGI */ SGI_VIDEO_SYNC, + SGIS_GENERATE_MIPMAP, /* WGL extensions */ WGL_ARB_PBUFFER, @@ -3187,15 +3232,15 @@ typedef enum _GL_SupportedExt { /**************************************************** - * #Defines + * #Defines ****************************************************/ #define GL_EXT_FUNCS_GEN \ /** ARB Extensions **/ \ /* GL_ARB_draw_buffers */ \ USE_GL_FUNC(PGLFNDRAWBUFFERSARBPROC, glDrawBuffersARB); \ - /* GL_ARB_imaging */ \ - USE_GL_FUNC(PGLFNBLENDCOLORPROC, glBlendColor); \ - USE_GL_FUNC(PGLFNBLENDEQUATIONPROC, glBlendEquation); \ + /* GL_ARB_imaging, GL_EXT_blend_minmax */ \ + USE_GL_FUNC(PGLFNBLENDCOLORPROC, glBlendColorEXT); \ + USE_GL_FUNC(PGLFNBLENDEQUATIONPROC, glBlendEquationEXT); \ /* GL_ARB_multisample */ \ USE_GL_FUNC(WINED3D_PFNGLSAMPLECOVERAGEARBPROC, glSampleCoverageARB); \ /* GL_ARB_multitexture */ \ @@ -3343,9 +3388,9 @@ typedef enum _GL_SupportedExt { USE_GL_FUNC(WINED3D_PFNGLUNIFORM2FARBPROC, glUniform2fARB); \ USE_GL_FUNC(WINED3D_PFNGLUNIFORM3FARBPROC, glUniform3fARB); \ USE_GL_FUNC(WINED3D_PFNGLUNIFORM4FARBPROC, glUniform4fARB); \ - USE_GL_FUNC(WINED3D_PFNGLUNIFORM1IVARBPROC, glUniform1fvARB); \ - USE_GL_FUNC(WINED3D_PFNGLUNIFORM2IVARBPROC, glUniform2fvARB); \ - USE_GL_FUNC(WINED3D_PFNGLUNIFORM3IVARBPROC, glUniform3fvARB); \ + USE_GL_FUNC(WINED3D_PFNGLUNIFORM1FVARBPROC, glUniform1fvARB); \ + USE_GL_FUNC(WINED3D_PFNGLUNIFORM2FVARBPROC, glUniform2fvARB); \ + USE_GL_FUNC(WINED3D_PFNGLUNIFORM3FVARBPROC, glUniform3fvARB); \ USE_GL_FUNC(WINED3D_PFNGLUNIFORM4FVARBPROC, glUniform4fvARB); \ USE_GL_FUNC(WINED3D_PFNGLUNIFORM1IVARBPROC, glUniform1ivARB); \ USE_GL_FUNC(WINED3D_PFNGLUNIFORM2IVARBPROC, glUniform2ivARB); \ @@ -3457,6 +3502,9 @@ typedef enum _GL_SupportedExt { /* GLX_SGI_video_sync */ \ USE_GL_FUNC(PGLXFNGETVIDEOSYNCSGIPROC, glXGetVideoSyncSGI); \ USE_GL_FUNC(PGLXFNWAITVIDEOSYNCSGIPROC, glXWaitVideoSyncSGI); \ + /* GL_APPLE_flush_render */ \ + USE_GL_FUNC(PGLFNFLUSHRENDERAPPLEPROC, glFlushRenderApple); \ + USE_GL_FUNC(PGLFNFINISHRENDERAPPLEPROC, glFinishRenderApple); \ /* OpenGL 2.0 functions */ #define GL2_FUNCS_GEN \ @@ -3657,11 +3705,12 @@ typedef BOOL (WINAPI * WINED3D_PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, /**************************************************** - * Structures + * Structures ****************************************************/ typedef struct { GLint glInternal, glGammaInternal, glFormat, glType; + WINED3DFORMAT conversion_group; } GlPixelFormatDesc; #define USE_GL_FUNC(type, pfn) type pfn; @@ -3672,10 +3721,11 @@ typedef struct _WineD3D_GL_Info { GL_Vendors gl_vendor; GL_Cards gl_card; + UINT vidmem; DWORD gl_driver_version; CHAR gl_renderer[255]; /** - * CAPS Constants + * CAPS Constants */ UINT max_buffers; UINT max_lights; @@ -3688,10 +3738,11 @@ typedef struct _WineD3D_GL_Info { UINT max_clipplanes; UINT max_texture_size; UINT max_texture3d_size; - float max_pointsize; + float max_pointsize, max_pointsizemin; UINT max_blends; UINT max_anisotropy; UINT max_aux_buffers; + UINT max_glsl_varyings; unsigned max_vshader_constantsF; unsigned max_pshader_constantsF; @@ -3712,6 +3763,8 @@ typedef struct _WineD3D_GL_Info { GL_VSVersion vs_nv_version; GL_VSVersion vs_ati_version; + BOOL arb_vs_offset_limit; + BOOL supported[OPENGL_SUPPORTED_EXT_END + 1]; /** OpenGL EXT and ARB functions ptr */ diff --git a/reactos/include/reactos/wine/wined3d_interface.h b/reactos/include/reactos/wine/wined3d_interface.h index d58ca958548..d77a18f842d 100644 --- a/reactos/include/reactos/wine/wined3d_interface.h +++ b/reactos/include/reactos/wine/wined3d_interface.h @@ -36,7 +36,7 @@ struct IWineD3DSurface; #include "wined3d_types.h" /***************************************************************** - * THIS FILE MUST NOT CONTAIN X11 or MESA DEFINES + * THIS FILE MUST NOT CONTAIN X11 or MESA DEFINES * PLEASE USE wine/wined3d_gl.h INSTEAD */ @@ -109,14 +109,14 @@ struct IWineD3DClipper; /* {108F9C44-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3D, +DEFINE_GUID(IID_IWineD3D, 0x108f9c44, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); DEFINE_GUID(IID_IWineD3DBase, 0x46799311, 0x8e0e, 0x40ce, 0xb2, 0xec, 0xdd, 0xb9, 0x9f, 0x18, 0xfc, 0xb4); /* {108F9C44-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DDevice, +DEFINE_GUID(IID_IWineD3DDevice, 0x108f9c44, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {f756720c-32b9-4439-b5a3-1d6c97037d9e} */ @@ -124,49 +124,49 @@ DEFINE_GUID(IID_IWineD3DPalette, 0xf756720c, 0x32b9, 0x4439, 0xb5, 0xa3, 0x1d, 0x6c, 0x97, 0x03, 0x7d, 0x9e); /* {1F3BFB34-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DResource, +DEFINE_GUID(IID_IWineD3DResource, 0x1f3bfb34, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {217F671E-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DVertexBuffer, +DEFINE_GUID(IID_IWineD3DVertexBuffer, 0x217f671e, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {24769ED8-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DVolume, +DEFINE_GUID(IID_IWineD3DVolume, 0x24769ed8, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {34D01B10-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DSwapChain, +DEFINE_GUID(IID_IWineD3DSwapChain, 0x34d01b10, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {37CD5526-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DSurface, +DEFINE_GUID(IID_IWineD3DSurface, 0x37cd5526, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {3A02A54E-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DIndexBuffer, +DEFINE_GUID(IID_IWineD3DIndexBuffer, 0x3a02a54e, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {3C2AEBF6-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DBaseTexture, +DEFINE_GUID(IID_IWineD3DBaseTexture, 0x3c2aebf6, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {3E72CC1C-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DTexture, +DEFINE_GUID(IID_IWineD3DTexture, 0x3e72cc1c, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {41752900-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DCubeTexture, +DEFINE_GUID(IID_IWineD3DCubeTexture, 0x41752900, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {7B39470C-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DVolumeTexture, +DEFINE_GUID(IID_IWineD3DVolumeTexture, 0x7b39470c, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {7CD55BE6-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DVertexDeclaration, +DEFINE_GUID(IID_IWineD3DVertexDeclaration, 0x7cd55be6, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {EAC93065-A4DF-446F-86A1-9EF2BCA40A3C} */ @@ -174,19 +174,19 @@ DEFINE_GUID(IID_IWineD3DBaseShader, 0xeac93065, 0xa4df, 0x446f, 0x86, 0xa1, 0x9e, 0xf2, 0xbc, 0xa4, 0x0a, 0x3c); /* {7F7A2B60-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DVertexShader, +DEFINE_GUID(IID_IWineD3DVertexShader, 0x7f7a2b60, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {818503DA-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DPixelShader, +DEFINE_GUID(IID_IWineD3DPixelShader, 0x818503da, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {83B073CE-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DStateBlock, +DEFINE_GUID(IID_IWineD3DStateBlock, 0x83b073ce, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {905DDBAC-6F30-11d9-C687-00046142C14F} */ -DEFINE_GUID(IID_IWineD3DQuery, +DEFINE_GUID(IID_IWineD3DQuery, 0x905ddbac, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); /* {8f2bceb1-d338-488c-ab7f-0ec980bf5d2d} */ @@ -196,53 +196,53 @@ DEFINE_GUID(IID_IWineD3DClipper, /***************************************************************************** * Callback functions required for predefining surfaces / stencils */ -typedef HRESULT WINAPI (*D3DCB_CREATERENDERTARGETFN) (IUnknown *pDevice, +typedef HRESULT (WINAPI *D3DCB_CREATERENDERTARGETFN) (IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, WINED3DFORMAT Format, - WINED3DMULTISAMPLE_TYPE MultiSample, - DWORD MultisampleQuality, - BOOL Lockable, + WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Lockable, struct IWineD3DSurface **ppSurface, HANDLE *pSharedHandle); -typedef HRESULT WINAPI (*D3DCB_CREATESURFACEFN) (IUnknown *pDevice, +typedef HRESULT (WINAPI *D3DCB_CREATESURFACEFN) (IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, WINED3DFORMAT Format, DWORD Usage, - WINED3DPOOL Pool, + WINED3DPOOL Pool, UINT Level, WINED3DCUBEMAP_FACES Face, struct IWineD3DSurface **ppSurface, HANDLE *pSharedHandle); -typedef HRESULT WINAPI (*D3DCB_CREATEDEPTHSTENCILSURFACEFN) (IUnknown *pDevice, +typedef HRESULT (WINAPI *D3DCB_CREATEDEPTHSTENCILSURFACEFN) (IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, WINED3DFORMAT Format, - WINED3DMULTISAMPLE_TYPE MultiSample, - DWORD MultisampleQuality, - BOOL Discard, + WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, + BOOL Discard, struct IWineD3DSurface **ppSurface, HANDLE *pSharedHandle); -typedef HRESULT WINAPI (*D3DCB_CREATEVOLUMEFN) (IUnknown *pDevice, +typedef HRESULT (WINAPI *D3DCB_CREATEVOLUMEFN) (IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, UINT Depth, - WINED3DFORMAT Format, + WINED3DFORMAT Format, WINED3DPOOL Pool, DWORD Usage, struct IWineD3DVolume **ppVolume, HANDLE *pSharedHandle); -typedef HRESULT WINAPI (*D3DCB_CREATEADDITIONALSWAPCHAIN) (IUnknown *pDevice, +typedef HRESULT (WINAPI *D3DCB_CREATEADDITIONALSWAPCHAIN) (IUnknown *pDevice, WINED3DPRESENT_PARAMETERS *pPresentationParameters, struct IWineD3DSwapChain **pSwapChain ); @@ -250,11 +250,11 @@ typedef HRESULT WINAPI (*D3DCB_CREATEADDITIONALSWAPCHAIN) (IUnknown *pDevice, /***************************************************************************** * Callback functions for custom implicit object destruction. */ -typedef ULONG WINAPI (*D3DCB_DESTROYSWAPCHAINFN) (struct IWineD3DSwapChain *pSwapChain); +typedef ULONG (WINAPI *D3DCB_DESTROYSWAPCHAINFN) (struct IWineD3DSwapChain *pSwapChain); -typedef ULONG WINAPI (*D3DCB_DESTROYSURFACEFN) (struct IWineD3DSurface *pSurface); +typedef ULONG (WINAPI *D3DCB_DESTROYSURFACEFN) (struct IWineD3DSurface *pSurface); -typedef ULONG WINAPI (*D3DCB_DESTROYVOLUMEFN) (struct IWineD3DVolume *pVolume); +typedef ULONG (WINAPI *D3DCB_DESTROYVOLUMEFN) (struct IWineD3DVolume *pVolume); /***************************************************************************** * IWineD3DBase interface @@ -282,7 +282,7 @@ DECLARE_INTERFACE_(IWineD3DBase, IUnknown) #endif /***************************************************************************** - * IWineD3D interface + * IWineD3D interface */ #define INTERFACE IWineD3D @@ -341,11 +341,11 @@ DECLARE_INTERFACE_(IWineD3D, IWineD3DBase) IWineD3D* WINAPI WineDirect3DCreate(UINT SDKVersion, UINT dxVersion, IUnknown *parent); /***************************************************************************** - * IWineD3DDevice interface + * IWineD3DDevice interface */ #define INTERFACE IWineD3DDevice -DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) -{ +DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) +{ /*** IUnknown methods ***/ STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; STDMETHOD_(ULONG,AddRef)(THIS) PURE; @@ -356,7 +356,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) STDMETHOD(CreateVertexBuffer)(THIS_ UINT Length,DWORD Usage,DWORD FVF,WINED3DPOOL Pool,struct IWineD3DVertexBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent) PURE; STDMETHOD(CreateIndexBuffer)(THIS_ UINT Length, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, struct IWineD3DIndexBuffer** ppIndexBuffer, HANDLE* pSharedHandle, IUnknown *parent) PURE; STDMETHOD(CreateStateBlock)(THIS_ WINED3DSTATEBLOCKTYPE Type, struct IWineD3DStateBlock **ppStateBlock, IUnknown *parent) PURE; - STDMETHOD(CreateSurface)(THIS_ UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, struct IWineD3DSurface** ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) PURE; + STDMETHOD(CreateSurface)(THIS_ UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, struct IWineD3DSurface** ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) PURE; STDMETHOD(CreateTexture)(THIS_ UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, struct IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATESURFACEFN pFn) PURE; STDMETHOD(CreateVolumeTexture)(THIS_ UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, struct IWineD3DVolumeTexture** ppVolumeTexture, HANDLE* pSharedHandle, IUnknown *parent, D3DCB_CREATEVOLUMEFN pFn) PURE; STDMETHOD(CreateVolume)(THIS_ UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, struct IWineD3DVolume** ppVolumeTexture, HANDLE* pSharedHandle, IUnknown *parent) PURE; @@ -405,8 +405,8 @@ DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) STDMETHOD_(void, GetGammaRamp)(THIS_ UINT iSwapChain, WINED3DGAMMARAMP* pRamp) PURE; STDMETHOD(SetIndices)(THIS_ struct IWineD3DIndexBuffer * pIndexData) PURE; STDMETHOD(GetIndices)(THIS_ struct IWineD3DIndexBuffer ** ppIndexData) PURE; - STDMETHOD(SetBaseVertexIndex)(THIS_ UINT baseIndex); - STDMETHOD(GetBaseVertexIndex)(THIS_ UINT *baseIndex); + STDMETHOD(SetBaseVertexIndex)(THIS_ INT baseIndex); + STDMETHOD(GetBaseVertexIndex)(THIS_ INT *baseIndex); STDMETHOD(SetLight)(THIS_ DWORD Index,CONST WINED3DLIGHT * pLight) PURE; STDMETHOD(GetLight)(THIS_ DWORD Index,WINED3DLIGHT * pLight) PURE; STDMETHOD(SetLightEnable)(THIS_ DWORD Index,BOOL Enable) PURE; @@ -624,7 +624,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) #endif /***************************************************************************** - * WineD3DResource interface + * WineD3DResource interface */ #define INTERFACE IWineD3DResource DECLARE_INTERFACE_(IWineD3DResource,IWineD3DBase) @@ -666,7 +666,7 @@ DECLARE_INTERFACE_(IWineD3DResource,IWineD3DBase) #endif /***************************************************************************** - * WineD3DVertexBuffer interface + * WineD3DVertexBuffer interface */ #define INTERFACE IWineD3DVertexBuffer DECLARE_INTERFACE_(IWineD3DVertexBuffer,IWineD3DResource) @@ -716,7 +716,7 @@ DECLARE_INTERFACE_(IWineD3DVertexBuffer,IWineD3DResource) #endif /***************************************************************************** - * WineD3DIndexBuffer interface + * WineD3DIndexBuffer interface */ #define INTERFACE IWineD3DIndexBuffer DECLARE_INTERFACE_(IWineD3DIndexBuffer,IWineD3DResource) @@ -1141,6 +1141,8 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource) STDMETHOD_(CONST void *, GetData)(THIS) PURE; STDMETHOD(SetFormat)(THIS_ WINED3DFORMAT format) PURE; STDMETHOD(PrivateSetup)(THIS) PURE; + STDMETHOD_(void,ModifyLocation)(THIS_ DWORD flag, BOOL persistent); + STDMETHOD(LoadLocation)(THIS_ DWORD flag, const RECT *rect); }; #undef INTERFACE @@ -1196,6 +1198,8 @@ DECLARE_INTERFACE_(IWineD3DSurface,IWineD3DResource) #define IWineD3DSurface_GetData(p) (p)->lpVtbl->GetData(p) #define IWineD3DSurface_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) #define IWineD3DSurface_PrivateSetup(p) (p)->lpVtbl->PrivateSetup(p) +#define IWineD3DSurface_ModifyLocation(p,a,b) (p)->lpVtbl->ModifyLocation(p,a,b) +#define IWineD3DSurface_LoadLocation(p,a,b) (p)->lpVtbl->LoadLocation(p,a,b) #endif /***************************************************************************** @@ -1210,7 +1214,7 @@ DECLARE_INTERFACE_(IWineD3DVolume,IWineD3DResource) STDMETHOD_(ULONG,Release)(THIS) PURE; /*** IWineD3DBase methods ***/ STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE; - /*** IWineD3DResource methods ***/ + /*** IWineD3DResource methods ***/ STDMETHOD(GetDevice)(THIS_ IWineD3DDevice ** ppDevice) PURE; STDMETHOD(SetPrivateData)(THIS_ REFGUID refguid, CONST void * pData, DWORD SizeOfData, DWORD Flags) PURE; STDMETHOD(GetPrivateData)(THIS_ REFGUID refguid, void * pData, DWORD * pSizeOfData) PURE; @@ -1218,8 +1222,8 @@ DECLARE_INTERFACE_(IWineD3DVolume,IWineD3DResource) STDMETHOD_(DWORD,SetPriority)(THIS_ DWORD PriorityNew) PURE; STDMETHOD_(DWORD,GetPriority)(THIS) PURE; STDMETHOD_(void,PreLoad)(THIS) PURE; - STDMETHOD_(WINED3DRESOURCETYPE, GetType)(THIS) PURE; - /*** IWineD3DVolume methods ***/ + STDMETHOD_(WINED3DRESOURCETYPE, GetType)(THIS) PURE; + /*** IWineD3DVolume methods ***/ STDMETHOD(GetContainer)(THIS_ REFIID riid, void ** ppContainer) PURE; STDMETHOD(GetDesc)(THIS_ WINED3DVOLUME_DESC * pDesc) PURE; STDMETHOD(LockBox)(THIS_ WINED3DLOCKED_BOX* pLockedVolume, CONST WINED3DBOX* pBox, DWORD Flags) PURE; @@ -1291,7 +1295,7 @@ DECLARE_INTERFACE_(IWineD3DVertexDeclaration,IWineD3DBase) #endif /***************************************************************************** - * IWineD3DStateBlock interface + * IWineD3DStateBlock interface */ #define INTERFACE IWineD3DStateBlock DECLARE_INTERFACE_(IWineD3DStateBlock,IWineD3DBase) @@ -1325,7 +1329,7 @@ DECLARE_INTERFACE_(IWineD3DStateBlock,IWineD3DBase) #endif /***************************************************************************** - * WineD3DQuery interface + * WineD3DQuery interface */ #define INTERFACE IWineD3DQuery DECLARE_INTERFACE_(IWineD3DQuery,IWineD3DBase) @@ -1342,7 +1346,7 @@ DECLARE_INTERFACE_(IWineD3DQuery,IWineD3DBase) STDMETHOD_(DWORD,GetDataSize)(THIS) PURE; STDMETHOD_(WINED3DQUERYTYPE, GetType)(THIS) PURE; STDMETHOD(Issue)(THIS_ DWORD dwIssueFlags) PURE; - + }; #undef INTERFACE @@ -1441,7 +1445,7 @@ DECLARE_INTERFACE_(IWineD3DBaseShader,IWineD3DBase) #endif /***************************************************************************** - * IWineD3DVertexShader interface + * IWineD3DVertexShader interface */ #define INTERFACE IWineD3DVertexShader DECLARE_INTERFACE_(IWineD3DVertexShader,IWineD3DBaseShader) diff --git a/reactos/include/reactos/wine/wined3d_types.h b/reactos/include/reactos/wine/wined3d_types.h index 6cf6fcfe1bd..477df2479c1 100644 --- a/reactos/include/reactos/wine/wined3d_types.h +++ b/reactos/include/reactos/wine/wined3d_types.h @@ -219,7 +219,7 @@ typedef enum _WINED3DDEGREETYPE { WINED3DDEGREE_QUADRATIC = 2, WINED3DDEGREE_CUBIC = 3, WINED3DDEGREE_QUINTIC = 5, - + WINED3DDEGREE_FORCE_DWORD = 0x7fffffff } WINED3DDEGREETYPE; @@ -247,7 +247,7 @@ typedef enum _WINED3DFORMAT { WINED3DFMT_G16R16 = 34, WINED3DFMT_A2R10G10B10 = 35, WINED3DFMT_A16B16G16R16 = 36, - + WINED3DFMT_A8P8 = 40, WINED3DFMT_P8 = 41, @@ -294,12 +294,12 @@ typedef enum _WINED3DFORMAT { WINED3DFMT_R16F = 111, WINED3DFMT_G16R16F = 112, WINED3DFMT_A16B16G16R16F = 113, - + /* IEEE formats */ WINED3DFMT_R32F = 114, WINED3DFMT_G32R32F = 115, WINED3DFMT_A32B32G32R32F = 116, - + WINED3DFMT_CxV8U8 = 117, @@ -422,7 +422,7 @@ typedef enum _WINED3DRENDERSTATETYPE { WINED3DRS_AMBIENTMATERIALSOURCE = 147, WINED3DRS_EMISSIVEMATERIALSOURCE = 148, WINED3DRS_VERTEXBLEND = 151, - WINED3DRS_CLIPPLANEENABLE = 152, + WINED3DRS_CLIPPLANEENABLE = 152, WINED3DRS_SOFTWAREVERTEXPROCESSING = 153, /* d3d8 */ WINED3DRS_POINTSIZE = 154, WINED3DRS_POINTSIZE_MIN = 155, @@ -857,7 +857,7 @@ typedef struct _WINED3DADAPTER_IDENTIFIER { char *Driver; char *Description; char *DeviceName; - LARGE_INTEGER *DriverVersion; + LARGE_INTEGER *DriverVersion; DWORD *VendorId; DWORD *DeviceId; DWORD *SubSysId; @@ -1064,13 +1064,13 @@ typedef struct _WINED3DBOX { /*Vertex cache optimization hints.*/ typedef struct WINED3DDEVINFO_VCACHE { /*Must be a 4 char code FOURCC (e.g. CACH)*/ - DWORD Pattern; + DWORD Pattern; /*0 to get the longest strips, 1 vertex cache*/ - DWORD OptMethod; + DWORD OptMethod; /*Cache size to use (only valid if OptMethod==1) */ DWORD CacheSize; /*internal for deciding when to restart strips, non user modifyable (only valid if OptMethod==1)*/ - DWORD MagicNumber; + DWORD MagicNumber; } WINED3DDEVINFO_VCACHE; typedef struct _WINED3DVERTEXBUFFER_DESC { @@ -1196,7 +1196,7 @@ typedef struct _WINED3DCAPS { DWORD *VertexTextureFilterCaps; DWORD *MaxVShaderInstructionsExecuted; DWORD *MaxPShaderInstructionsExecuted; - DWORD *MaxVertexShader30InstructionSlots; + DWORD *MaxVertexShader30InstructionSlots; DWORD *MaxPixelShader30InstructionSlots; DWORD *Reserved2;/* Not in the microsoft headers but documented */ DWORD *Reserved3; @@ -1267,6 +1267,13 @@ typedef struct WineDirect3DStridedData { } WineDirect3DStridedData; typedef struct WineDirect3DVertexStridedData { + /* IMPORTANT: + * + * This structure can be accessed in two ways: Named access, and array + * access. Please note that named access is only valid with the fixed + * function vertex pipeline, and the arrays are only valid with the + * programmable vertex pipeline(vertex shaders) + */ union { struct { @@ -1323,7 +1330,7 @@ typedef enum { #define WINED3DUSAGE_RTPATCHES 0x00000080L #define WINED3DUSAGE_NPATCHES 0x00000100L #define WINED3DUSAGE_DYNAMIC 0x00000200L -#define WINED3DUSAGE_AUTOGENMIPMAP 0x00000400L +#define WINED3DUSAGE_AUTOGENMIPMAP 0x00000400L #define WINED3DUSAGE_DMAP 0x00004000L #define WINED3DUSAGE_MASK 0x00004FFFL #define WINED3DUSAGE_OVERLAY 0x00010000L @@ -1378,7 +1385,7 @@ typedef enum _WINED3DSURFTYPE { #define WINED3DPRASTERCAPS_COLORPERSPECTIVE 0x00400000L #define WINED3DPRASTERCAPS_SCISSORTEST 0x01000000L #define WINED3DPRASTERCAPS_SLOPESCALEDEPTHBIAS 0x02000000L -#define WINED3DPRASTERCAPS_DEPTHBIAS 0x04000000L +#define WINED3DPRASTERCAPS_DEPTHBIAS 0x04000000L #define WINED3DPRASTERCAPS_MULTISAMPLE_TOGGLE 0x08000000L #define WINED3DPSHADECAPS_COLORFLATMONO 0x000001