From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/ffp_hlsl.c | 40 +++++++++++++++----- dlls/wined3d/stateblock.c | 77 ++++++++++++++++++++++++++++----------- 2 files changed, 86 insertions(+), 31 deletions(-)
diff --git a/dlls/wined3d/ffp_hlsl.c b/dlls/wined3d/ffp_hlsl.c index bc726c7ce10..973fc064ed7 100644 --- a/dlls/wined3d/ffp_hlsl.c +++ b/dlls/wined3d/ffp_hlsl.c @@ -30,15 +30,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings *settings, struct wined3d_string_buffer *buffer) { + struct wined3d_string_buffer texcoord; + if (settings->lighting) FIXME("Ignoring lighting.\n");
if (settings->point_size) FIXME("Ignoring point size.\n");
- if (settings->transformed) - FIXME("Ignoring pretransformed vertices.\n"); - if (settings->vertexblends) FIXME("Ignoring vertex blend.\n");
@@ -99,12 +98,27 @@ static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings
shader_addline(buffer, "void main(in struct input i, out struct output o)\n"); shader_addline(buffer, "{\n"); - shader_addline(buffer, " float4 ec_pos = 0.0;\n\n");
- shader_addline(buffer, " ec_pos += mul(c.modelview_matrices[0], float4(i.pos.xyz, 1.0));\n\n"); + if (settings->transformed) + { + shader_addline(buffer, " float4 ec_pos = float4(i.pos.xyz, 1.0);\n"); + /* We reuse the projection matrix to undo the transformation from clip + * coordinates to pixel coordinates. */ + shader_addline(buffer, " float4 out_pos = mul(c.projection_matrix, ec_pos);\n\n"); + + /* Use a ternary; this is not the most natural way to write it but is + * nicer to the compiler. */ + shader_addline(buffer, " o.pos = (i.pos.w == 0.0 ? out_pos : out_pos / i.pos.w);\n"); + } + else + { + shader_addline(buffer, " float4 ec_pos = 0.0;\n\n"); + + shader_addline(buffer, " ec_pos += mul(c.modelview_matrices[0], float4(i.pos.xyz, 1.0));\n\n");
- shader_addline(buffer, " o.pos = mul(c.projection_matrix, ec_pos);\n"); - shader_addline(buffer, " ec_pos /= ec_pos.w;\n\n"); + shader_addline(buffer, " o.pos = mul(c.projection_matrix, ec_pos);\n"); + shader_addline(buffer, " ec_pos /= ec_pos.w;\n\n"); + }
/* No lighting. */ if (settings->diffuse) @@ -113,14 +127,16 @@ static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings shader_addline(buffer, " o.diffuse = 1.0;\n"); shader_addline(buffer, " o.specular = i.specular;\n\n");
+ string_buffer_init(&texcoord); for (unsigned int i = 0; i < WINED3D_MAX_FFP_TEXTURES; ++i) { + string_buffer_clear(&texcoord); + switch (settings->texgen[i] & 0xffff0000) { case WINED3DTSS_TCI_PASSTHRU: if (settings->texcoords & (1u << i)) - shader_addline(buffer, " o.texcoord%u = mul(c.texture_matrices[%u], i.texcoord[%u]);\n", - i, i, settings->texgen[i] & 0x0000ffff); + shader_addline(&texcoord, "i.texcoord[%u]", settings->texgen[i] & 0x0000ffff); else continue; break; @@ -129,7 +145,13 @@ static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings FIXME("Unhandled texgen %#x.\n", settings->texgen[i]); break; } + + if (settings->transformed) + shader_addline(buffer, " o.texcoord%u = %s;\n", i, texcoord.buffer); + else + shader_addline(buffer, " o.texcoord%u = mul(c.texture_matrices[%u], %s);\n", i, i, texcoord.buffer); } + string_buffer_free(&texcoord);
switch (settings->fog_mode) { diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index d24b356dc1f..9e10dbafb10 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -67,6 +67,7 @@ struct wined3d_saved_states uint32_t ffp_vs_settings : 1; uint32_t ffp_ps_settings : 1; uint32_t rasterizer_state : 1; + uint32_t position_transformed : 1; };
struct stage_state @@ -1577,10 +1578,18 @@ void CDECL wined3d_stateblock_set_vertex_declaration(struct wined3d_stateblock * }
if (declaration->position_transformed != prev->position_transformed) + { + /* We reuse the projection matrix to undo the translation between + * clip coordinates and pixel coordinates, so we need to invalidate + * it here. */ stateblock->changed.ffp_vs_settings = 1; + stateblock->changed.position_transformed = 1; + stateblock->changed.transforms = 1; + } } else { + stateblock->changed.position_transformed = 1; stateblock->changed.ffp_vs_settings = 1; } } @@ -3537,33 +3546,57 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, } }
- if (changed->transforms) + if (state->vertex_declaration && state->vertex_declaration->position_transformed) { - for (i = 0; i < ARRAY_SIZE(changed->transform); ++i) + /* We reuse the projection matrix to undo the translation between + * clip coordinates and pixel coordinates. */ + if (changed->position_transformed || changed->viewport) { - map = changed->transform[i]; - while (map) + float x = state->viewport.x; + float y = state->viewport.y; + float w = state->viewport.width; + float h = state->viewport.height; + float x_scale = 2.0f / w; + float x_offset = (-(2.0f * x) - w) / w; + float y_scale = 2.0f / -h; + float y_offset = (-(2.0f * y) - h) / -h; + float z_scale = state->rs[WINED3D_RS_ZENABLE] ? 1.0f : 0.0f; + const struct wined3d_matrix matrix = { - j = wined3d_bit_scan(&map); - idx = i * word_bit_count + j; + x_scale, 0.0f, 0.0f, 0.0f, + 0.0f, y_scale, 0.0f, 0.0f, + 0.0f, 0.0f, z_scale, 0.0f, + x_offset, y_offset, 0.0f, 1.0f, + }; + + wined3d_device_context_push_constants(context, WINED3D_PUSH_CONSTANTS_VS_FFP, WINED3D_SHADER_CONST_FFP_PROJ, + offsetof(struct wined3d_ffp_vs_constants, projection_matrix), sizeof(matrix), &matrix); + }
- if (idx == WINED3D_TS_VIEW) - { - changed->lights = 1; - changed->clipplane = wined3d_mask_from_size(WINED3D_MAX_CLIP_DISTANCES); - } + if (wined3d_bitmap_is_set(changed->transform, WINED3D_TS_PROJECTION)) + { + /* wined3d_ffp_vs_settings.ortho_fog still needs the + * device state to be set. */ + wined3d_device_set_transform(device, WINED3D_TS_PROJECTION, &state->transforms[WINED3D_TS_PROJECTION]); + } + } + else if (changed->transforms) + { + if (wined3d_bitmap_is_set(changed->transform, WINED3D_TS_VIEW)) + { + changed->lights = 1; + changed->clipplane = wined3d_mask_from_size(WINED3D_MAX_CLIP_DISTANCES); + }
- if (idx == WINED3D_TS_PROJECTION) - { - wined3d_device_context_push_constants(context, - WINED3D_PUSH_CONSTANTS_VS_FFP, WINED3D_SHADER_CONST_FFP_PROJ, - offsetof(struct wined3d_ffp_vs_constants, projection_matrix), - sizeof(state->transforms[idx]), &state->transforms[idx]); - /* wined3d_ffp_vs_settings.ortho_fog and vs_compile_args.ortho_fog - * still need the device state to be set. */ - wined3d_device_set_transform(device, idx, &state->transforms[idx]); - } - } + if (wined3d_bitmap_is_set(changed->transform, WINED3D_TS_PROJECTION) || changed->position_transformed) + { + wined3d_device_context_push_constants(context, + WINED3D_PUSH_CONSTANTS_VS_FFP, WINED3D_SHADER_CONST_FFP_PROJ, + offsetof(struct wined3d_ffp_vs_constants, projection_matrix), + sizeof(state->transforms[WINED3D_TS_PROJECTION]), &state->transforms[WINED3D_TS_PROJECTION]); + /* wined3d_ffp_vs_settings.ortho_fog and vs_compile_args.ortho_fog + * still need the device state to be set. */ + wined3d_device_set_transform(device, WINED3D_TS_PROJECTION, &state->transforms[WINED3D_TS_PROJECTION]); }
/* Clip planes are affected by the view matrix. */