diff --git a/dlls/wined3d/Makefile.in b/dlls/wined3d/Makefile.in index 69415ebb7f9..128956c66be 100644 --- a/dlls/wined3d/Makefile.in +++ b/dlls/wined3d/Makefile.in @@ -14,6 +14,7 @@ SOURCES = \ device.c \ directx.c \ ffp_gl.c \ + ffp_hlsl.c \ gl_compat.c \ glsl_shader.c \ palette.c \ diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c index 56aa9b73269..c2803379347 100644 --- a/dlls/wined3d/adapter_gl.c +++ b/dlls/wined3d/adapter_gl.c @@ -4928,6 +4928,7 @@ static void wined3d_adapter_gl_init_d3d_info(struct wined3d_adapter_gl *adapter_ d3d_info->feature_level = feature_level_from_caps(gl_info, &shader_caps, &d3d_info->ffp_fragment_caps); d3d_info->filling_convention_offset = gl_info->filling_convention_offset; d3d_info->persistent_map = !!gl_info->supported[ARB_BUFFER_STORAGE]; + d3d_info->ffp_hlsl = wined3d_settings.ffp_hlsl; if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE]) d3d_info->multisample_draw_location = WINED3D_LOCATION_TEXTURE_RGB; diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index 6f622aae1bc..8c5f75c1316 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -2359,6 +2359,7 @@ static void wined3d_adapter_vk_init_d3d_info(struct wined3d_adapter_vk *adapter_ d3d_info->fences = true; d3d_info->persistent_map = true; d3d_info->gpu_push_constants = true; + d3d_info->ffp_hlsl = true; /* Like GL, Vulkan doesn't explicitly specify a filling convention and only mandates that a * shared edge of two adjacent triangles generate a fragment for exactly one of the triangles. diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c index 1a6ad5dc79a..c05c833f4b3 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -161,8 +161,8 @@ void wined3d_stream_info_from_declaration(struct wined3d_stream_info *stream_inf const struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info) { /* We need to deal with frequency data! */ + BOOL use_vshader = use_vs(state) || (d3d_info->ffp_hlsl && state->shader[WINED3D_SHADER_TYPE_VERTEX]); struct wined3d_vertex_declaration *declaration = state->vertex_declaration; - BOOL use_vshader = use_vs(state); unsigned int i; stream_info->use_map = 0; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 711c031a028..1bd4e2b4242 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -2123,15 +2123,23 @@ static void wined3d_cs_exec_push_constants(struct wined3d_cs *cs, const void *da { const struct wined3d_cs_push_constants *op = data; struct wined3d_device *device = cs->c.device; + unsigned int ffp_start_idx, ffp_end_idx; unsigned int context_count, i; /* The constant buffers were already updated; this op is just to mark the * constants as invalid in the device state. */ + ffp_start_idx = op->start_idx / sizeof(struct wined3d_vec4); + ffp_end_idx = (op->start_idx + op->count + sizeof(struct wined3d_vec4)) / sizeof(struct wined3d_vec4); + if (op->type == WINED3D_PUSH_CONSTANTS_VS_F) device->shader_backend->shader_update_float_vertex_constants(device, op->start_idx, op->count); else if (op->type == WINED3D_PUSH_CONSTANTS_PS_F) device->shader_backend->shader_update_float_pixel_constants(device, op->start_idx, op->count); + else if (op->type == WINED3D_PUSH_CONSTANTS_VS_FFP) + device->shader_backend->shader_update_float_vertex_constants(device, ffp_start_idx, ffp_end_idx - ffp_start_idx); + else if (op->type == WINED3D_PUSH_CONSTANTS_PS_FFP) + device->shader_backend->shader_update_float_pixel_constants(device, ffp_start_idx, ffp_end_idx - ffp_start_idx); for (i = 0, context_count = device->context_count; i < context_count; ++i) device->contexts[i]->constant_update_mask |= op->update_mask; diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 0fb71108b27..7e24de8afb3 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1667,6 +1667,22 @@ static void device_free_depth_stencil_state(struct wine_rb_entry *entry, void *c wined3d_depth_stencil_state_decref(state); } +static void device_free_ffp_vertex_shader(struct wine_rb_entry *entry, void *context) +{ + struct wined3d_ffp_vs *vs = WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_vs, entry); + + wined3d_shader_decref(vs->shader); + free(vs); +} + +static void device_free_ffp_pixel_shader(struct wine_rb_entry *entry, void *context) +{ + struct wined3d_ffp_ps *ps = WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_ps, entry); + + wined3d_shader_decref(ps->shader); + free(ps); +} + void wined3d_device_uninit_3d(struct wined3d_device *device) { struct wined3d_state *state = device->cs->c.state; @@ -1714,6 +1730,8 @@ void wined3d_device_uninit_3d(struct wined3d_device *device) wine_rb_destroy(&device->rasterizer_states, device_free_rasterizer_state, NULL); wine_rb_destroy(&device->blend_states, device_free_blend_state, NULL); wine_rb_destroy(&device->depth_stencil_states, device_free_depth_stencil_state, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, device_free_ffp_vertex_shader, NULL); + wine_rb_destroy(&device->ffp_pixel_shaders, device_free_ffp_pixel_shader, NULL); LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) { @@ -5515,6 +5533,8 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined wine_rb_init(&device->rasterizer_states, wined3d_rasterizer_state_compare); wine_rb_init(&device->blend_states, wined3d_blend_state_compare); wine_rb_init(&device->depth_stencil_states, wined3d_depth_stencil_state_compare); + wine_rb_init(&device->ffp_vertex_shaders, wined3d_ffp_vertex_program_key_compare); + wine_rb_init(&device->ffp_pixel_shaders, wined3d_ffp_frag_program_key_compare); if (vertex_pipeline->vp_states && fragment_pipeline->states && FAILED(hr = compile_state_table(device->state_table, device->multistate_funcs, @@ -5527,6 +5547,8 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined wine_rb_destroy(&device->blend_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->so_descs, NULL, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, NULL, NULL); + wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL); wined3d_decref(device->wined3d); return hr; } @@ -5554,6 +5576,8 @@ err: wine_rb_destroy(&device->blend_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->so_descs, NULL, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, NULL, NULL); + wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL); wined3d_decref(device->wined3d); return hr; } diff --git a/dlls/wined3d/ffp_hlsl.c b/dlls/wined3d/ffp_hlsl.c new file mode 100644 index 00000000000..959ecd4195a --- /dev/null +++ b/dlls/wined3d/ffp_hlsl.c @@ -0,0 +1,246 @@ +/* + * Fixed-function pipeline replacement implemented using HLSL shaders + * + * Copyright 2006 Jason Green + * Copyright 2006-2007 Henri Verbeet + * Copyright 2007-2009,2013 Stefan Dösinger for CodeWeavers + * Copyright 2009-2011 Henri Verbeet for CodeWeavers + * Copyright 2022,2024 Elizabeth Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wined3d_private.h" +#include + +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) +{ + 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"); + + if (settings->normal) + FIXME("Ignoring normals.\n"); + + if (settings->fog_mode != WINED3D_FFP_VS_FOG_OFF) + FIXME("Ignoring fog.\n"); + + /* This must be kept in sync with struct wined3d_ffp_vs_constants. */ + shader_addline(buffer, "uniform struct\n"); + shader_addline(buffer, "{\n"); + shader_addline(buffer, " float4x4 modelview_matrices[%u];\n", MAX_VERTEX_BLENDS); + shader_addline(buffer, " float4x4 projection_matrix;\n"); + shader_addline(buffer, " float4x4 texture_matrices[%u];\n", WINED3D_MAX_FFP_TEXTURES); + shader_addline(buffer, " float4 point_params;\n"); + shader_addline(buffer, " struct\n"); + shader_addline(buffer, " {\n"); + shader_addline(buffer, " float4 diffuse;\n"); + shader_addline(buffer, " float4 ambient;\n"); + shader_addline(buffer, " float4 specular;\n"); + shader_addline(buffer, " float4 emissive;\n"); + shader_addline(buffer, " float power;\n"); + shader_addline(buffer, " } material;\n"); + shader_addline(buffer, " float4 ambient_colour;\n"); + shader_addline(buffer, " struct\n"); + shader_addline(buffer, " {\n"); + shader_addline(buffer, " float4 diffuse, specular, ambient;\n"); + shader_addline(buffer, " float4 position, direction;\n"); + shader_addline(buffer, " float4 packed_params;\n"); + shader_addline(buffer, " float4 attenuation;\n"); + shader_addline(buffer, " } lights[%u];\n", WINED3D_MAX_ACTIVE_LIGHTS); + shader_addline(buffer, "} c;\n"); + + shader_addline(buffer, "struct input\n"); + shader_addline(buffer, "{\n"); + shader_addline(buffer, " float4 pos : POSITION;\n"); + shader_addline(buffer, " float4 blend_weight : BLENDWEIGHT;\n"); + shader_addline(buffer, " uint blend_indices : BLENDINDICES;\n"); + shader_addline(buffer, " float3 normal : NORMAL;\n"); + shader_addline(buffer, " float point_size : PSIZE;\n"); + shader_addline(buffer, " float4 diffuse : COLOR0;\n"); + shader_addline(buffer, " float4 specular : COLOR1;\n"); + shader_addline(buffer, " float4 texcoord[%u] : TEXCOORD;\n", WINED3D_MAX_FFP_TEXTURES); + shader_addline(buffer, "};\n\n"); + + shader_addline(buffer, "struct output\n"); + shader_addline(buffer, "{\n"); + shader_addline(buffer, " float4 pos : POSITION;\n"); + shader_addline(buffer, " float4 diffuse : COLOR0;\n"); + shader_addline(buffer, " float4 specular : COLOR1;\n"); + for (unsigned int i = 0; i < WINED3D_MAX_FFP_TEXTURES; ++i) + { + if (((settings->texgen[i] & 0xffff0000) != WINED3DTSS_TCI_PASSTHRU) || (settings->texcoords & (1u << i))) + shader_addline(buffer, " float4 texcoord%u : TEXCOORD%u;\n", i, i); + } + shader_addline(buffer, "};\n\n"); + + 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"); + + 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) + shader_addline(buffer, " o.diffuse = i.diffuse;\n"); + else + shader_addline(buffer, " o.diffuse = 1.0;\n"); + shader_addline(buffer, " o.specular = i.specular;\n\n"); + + for (unsigned int i = 0; i < WINED3D_MAX_FFP_TEXTURES; ++i) + { + 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); + else + continue; + break; + + default: + FIXME("Unhandled texgen %#x.\n", settings->texgen[i]); + break; + } + } + + switch (settings->fog_mode) + { + case WINED3D_FFP_VS_FOG_OFF: + break; + + default: + FIXME("Unhandled fog mode %#x.\n", settings->fog_mode); + break; + } + + shader_addline(buffer, "}\n"); + + return true; +} + +static bool ffp_hlsl_generate_pixel_shader(const struct ffp_frag_settings *settings, + struct wined3d_string_buffer *string) +{ + FIXME("Not yet implemented.\n"); + return false; +} + +static bool compile_hlsl_shader(const struct wined3d_string_buffer *hlsl, + struct vkd3d_shader_code *sm1, const char *profile) +{ + struct vkd3d_shader_hlsl_source_info hlsl_source_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO}; + struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; + char *messages; + int ret; + + compile_info.source.code = hlsl->buffer; + compile_info.source.size = hlsl->content_size; + compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL; + compile_info.target_type = VKD3D_SHADER_TARGET_D3D_BYTECODE; + compile_info.log_level = VKD3D_SHADER_LOG_WARNING; + + compile_info.next = &hlsl_source_info; + hlsl_source_info.profile = profile; + + ret = vkd3d_shader_compile(&compile_info, sm1, &messages); + if (messages && *messages && FIXME_ON(d3d_shader)) + { + const char *ptr, *end, *line; + + FIXME("Shader log:\n"); + ptr = messages; + end = ptr + strlen(ptr); + while ((line = wined3d_get_line(&ptr, end))) + FIXME(" %.*s", (int)(ptr - line), line); + FIXME("\n"); + } + vkd3d_shader_free_messages(messages); + + if (ret < 0) + { + ERR("Failed to compile HLSL, ret %d.\n", ret); + return false; + } + + return true; +} + +bool ffp_hlsl_compile_vs(const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader_desc *shader_desc) +{ + struct wined3d_string_buffer string; + struct vkd3d_shader_code sm1; + + if (!string_buffer_init(&string)) + return false; + + if (!ffp_hlsl_generate_vertex_shader(settings, &string)) + { + string_buffer_free(&string); + return false; + } + + if (!compile_hlsl_shader(&string, &sm1, "vs_2_0")) + { + string_buffer_free(&string); + return false; + } + string_buffer_free(&string); + + shader_desc->byte_code = sm1.code; + shader_desc->byte_code_size = ~(size_t)0; + return true; +} + +bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc) +{ + struct wined3d_string_buffer string; + struct vkd3d_shader_code sm1; + + if (!string_buffer_init(&string)) + return false; + + if (!ffp_hlsl_generate_pixel_shader(settings, &string)) + { + string_buffer_free(&string); + return false; + } + + if (!compile_hlsl_shader(&string, &sm1, "ps_2_0")) + { + string_buffer_free(&string); + return false; + } + string_buffer_free(&string); + + shader_desc->byte_code = sm1.code; + shader_desc->byte_code_size = ~(size_t)0; + return true; +} diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 7ff9ce0427b..61b53da540a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1735,17 +1735,38 @@ static void shader_glsl_load_constants(struct shader_glsl_priv *priv, constant_version = prog->constant_version; update_mask = context->constant_update_mask & prog->constant_update_mask; - if (update_mask & WINED3D_SHADER_CONST_VS_F) - shader_glsl_load_constants_f(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_F], - prog->vs.uniform_f_locations, &priv->vconst_heap, priv->stack, constant_version); + if (vshader && vshader->is_ffp_vs) + { + /* The shader's constant update mask is WINED3D_SHADER_CONST_VS_F. + * This may be set from shader_glsl_update_graphics_program(). + * However, we also need to update constants when FFP flags change. */ + static const uint32_t vs_update_mask = WINED3D_SHADER_CONST_VS_F + | WINED3D_SHADER_CONST_FFP_LIGHTS + | WINED3D_SHADER_CONST_FFP_MATERIAL + | WINED3D_SHADER_CONST_FFP_MODELVIEW + | WINED3D_SHADER_CONST_FFP_PROJ + | WINED3D_SHADER_CONST_FFP_TEXMATRIX + | WINED3D_SHADER_CONST_FFP_VERTEXBLEND + | WINED3D_SHADER_CONST_VS_POINTSIZE; - if (update_mask & WINED3D_SHADER_CONST_VS_I) - shader_glsl_load_constants_i(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_I], - prog->vs.uniform_i_locations, vshader->reg_maps.integer_constants); + if (context->constant_update_mask & vs_update_mask) + shader_glsl_load_constants_f(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_FFP], + prog->vs.uniform_f_locations, &priv->vconst_heap, priv->stack, constant_version); + } + else + { + if (update_mask & WINED3D_SHADER_CONST_VS_F) + shader_glsl_load_constants_f(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_F], + prog->vs.uniform_f_locations, &priv->vconst_heap, priv->stack, constant_version); - if (update_mask & WINED3D_SHADER_CONST_VS_B) - shader_glsl_load_constants_b(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_B], - prog->vs.uniform_b_locations, vshader->reg_maps.boolean_constants); + if (update_mask & WINED3D_SHADER_CONST_VS_I) + shader_glsl_load_constants_i(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_I], + prog->vs.uniform_i_locations, vshader->reg_maps.integer_constants); + + if (update_mask & WINED3D_SHADER_CONST_VS_B) + shader_glsl_load_constants_b(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_B], + prog->vs.uniform_b_locations, vshader->reg_maps.boolean_constants); + } if (update_mask & WINED3D_SHADER_CONST_VS_CLIP_PLANES) { @@ -1890,17 +1911,30 @@ static void shader_glsl_load_constants(struct shader_glsl_priv *priv, WINED3D_LIGHT_PARALLELPOINT, &constants->light.lights[i], prog); } - if (update_mask & WINED3D_SHADER_CONST_PS_F) - shader_glsl_load_constants_f(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_F], - prog->ps.uniform_f_locations, &priv->pconst_heap, priv->stack, constant_version); + if (pshader && pshader->is_ffp_ps) + { + static const uint32_t ps_update_mask = WINED3D_SHADER_CONST_PS_F + | WINED3D_SHADER_CONST_FFP_COLOR_KEY + | WINED3D_SHADER_CONST_FFP_PS; - if (update_mask & WINED3D_SHADER_CONST_PS_I) - shader_glsl_load_constants_i(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_I], - prog->ps.uniform_i_locations, pshader->reg_maps.integer_constants); + if (context->constant_update_mask & ps_update_mask) + shader_glsl_load_constants_f(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_FFP], + prog->ps.uniform_f_locations, &priv->pconst_heap, priv->stack, constant_version); + } + else + { + if (update_mask & WINED3D_SHADER_CONST_PS_F) + shader_glsl_load_constants_f(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_F], + prog->ps.uniform_f_locations, &priv->pconst_heap, priv->stack, constant_version); - if (update_mask & WINED3D_SHADER_CONST_PS_B) - shader_glsl_load_constants_b(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_B], - prog->ps.uniform_b_locations, pshader->reg_maps.boolean_constants); + if (update_mask & WINED3D_SHADER_CONST_PS_I) + shader_glsl_load_constants_i(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_I], + prog->ps.uniform_i_locations, pshader->reg_maps.integer_constants); + + if (update_mask & WINED3D_SHADER_CONST_PS_B) + shader_glsl_load_constants_b(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_B], + prog->ps.uniform_b_locations, pshader->reg_maps.boolean_constants); + } if (update_mask & WINED3D_SHADER_CONST_PS_BUMP_ENV) { @@ -10391,10 +10425,10 @@ static void set_glsl_shader_program(const struct wined3d_context_gl *context_gl, vs_id = ctx_data->glsl_program->vs.id; vs_list = &ctx_data->glsl_program->vs.shader_entry; - if (use_vs(state)) + if (use_vs(state) || d3d_info->ffp_hlsl) vshader = state->shader[WINED3D_SHADER_TYPE_VERTEX]; } - else if (use_vs(state)) + else if (use_vs(state) || d3d_info->ffp_hlsl) { struct vs_compile_args vs_compile_args; @@ -12113,7 +12147,7 @@ static void glsl_fragment_pipe_fogparams(struct wined3d_context *context, static void glsl_fragment_pipe_fog(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - BOOL use_vshader = use_vs(state); + BOOL use_vshader = use_vs(state) && !state->shader[WINED3D_SHADER_TYPE_VERTEX]->is_ffp_vs; enum fogsource new_source; DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index f1cb92d276a..7c18c96dbf6 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2268,7 +2268,55 @@ static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader, return WINED3D_OK; } -static HRESULT shader_set_function(struct wined3d_shader *shader, +static void shader_trace(const void *code, size_t size, enum vkd3d_shader_source_type source_type) +{ + struct vkd3d_shader_compile_info info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO}; + struct vkd3d_shader_code d3d_asm; + const char *ptr, *end, *line; + char *messages; + int ret; + + static const struct vkd3d_shader_compile_option compile_options[] = + { + {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_6}, + }; + + info.source.code = code; + info.source.size = size; + info.source_type = source_type; + info.target_type = VKD3D_SHADER_TARGET_D3D_ASM; + info.options = compile_options; + info.option_count = ARRAY_SIZE(compile_options); + info.log_level = VKD3D_SHADER_LOG_WARNING; + + ret = vkd3d_shader_compile(&info, &d3d_asm, &messages); + if (messages && *messages && FIXME_ON(d3d_shader)) + { + FIXME("Shader log:\n"); + ptr = messages; + end = ptr + strlen(ptr); + while ((line = wined3d_get_line(&ptr, end))) + FIXME(" %.*s", (int)(ptr - line), line); + FIXME("\n"); + } + vkd3d_shader_free_messages(messages); + + if (ret < 0) + { + ERR("Failed to disassemble, ret %d.\n", ret); + return; + } + + ptr = d3d_asm.code; + end = ptr + d3d_asm.size; + while ((line = wined3d_get_line(&ptr, end))) + TRACE(" %.*s", (int)(ptr - line), line); + TRACE("\n"); + + vkd3d_shader_free_shader_code(&d3d_asm); +} + +static HRESULT shader_set_function(struct wined3d_shader *shader, const struct wined3d_shader_desc *desc, enum wined3d_shader_type type, const struct wined3d_stream_output_desc *so_desc, unsigned int float_const_count) { const struct wined3d_d3d_info *d3d_info = &shader->device->adapter->d3d_info; @@ -2279,8 +2327,88 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, unsigned int backend_version; HRESULT hr; - TRACE("shader %p, type %s, float_const_count %u.\n", - shader, debug_shader_type(type), float_const_count); + TRACE("shader %p, byte_code %p, size %#Ix, type %s, float_const_count %u.\n", + shader, desc->byte_code, desc->byte_code_size, debug_shader_type(type), float_const_count); + + if (!desc->byte_code) + return WINED3DERR_INVALIDCALL; + + if (desc->byte_code_size == ~(size_t)0) + { + struct wined3d_shader_version shader_version; + const struct wined3d_shader_frontend *fe; + struct wined3d_shader_instruction ins; + const DWORD *ptr; + void *fe_data; + + shader->source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE; + if (!(shader->frontend = shader_select_frontend(shader->source_type))) + { + FIXME("Unable to find frontend for shader.\n"); + shader_cleanup(shader); + return WINED3DERR_INVALIDCALL; + } + + fe = shader->frontend; + if (!(fe_data = fe->shader_init(desc->byte_code, desc->byte_code_size, &shader->output_signature))) + { + WARN("Failed to initialise frontend data.\n"); + shader_cleanup(shader); + return WINED3DERR_INVALIDCALL; + } + + fe->shader_read_header(fe_data, &ptr, &shader_version); + while (!fe->shader_is_end(fe_data, &ptr)) + fe->shader_read_instruction(fe_data, &ptr, &ins); + + fe->shader_free(fe_data); + + shader->byte_code_size = (ptr - desc->byte_code) * sizeof(*ptr); + + if (!(shader->byte_code = malloc(shader->byte_code_size))) + { + shader_cleanup(shader); + return E_OUTOFMEMORY; + } + memcpy(shader->byte_code, desc->byte_code, shader->byte_code_size); + + shader->function = shader->byte_code; + shader->functionLength = shader->byte_code_size; + } + else + { + unsigned int max_version; + + if (!(shader->byte_code = malloc(desc->byte_code_size))) + { + shader_cleanup(shader); + return E_OUTOFMEMORY; + } + memcpy(shader->byte_code, desc->byte_code, desc->byte_code_size); + shader->byte_code_size = desc->byte_code_size; + + max_version = shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level); + if (FAILED(hr = wined3d_shader_extract_from_dxbc(shader, max_version, &shader->source_type))) + { + shader_cleanup(shader); + return hr; + } + + if (!(shader->frontend = shader_select_frontend(shader->source_type))) + { + FIXME("Unable to find frontend for shader.\n"); + shader_cleanup(shader); + return WINED3DERR_INVALIDCALL; + } + } + + if (TRACE_ON(d3d_shader)) + { + if (shader->source_type == VKD3D_SHADER_SOURCE_D3D_BYTECODE) + shader_trace(shader->function, shader->functionLength, shader->source_type); + else + shader_trace(shader->byte_code, shader->byte_code_size, shader->source_type); + } if (type == WINED3D_SHADER_TYPE_GEOMETRY) { @@ -2308,7 +2436,8 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, WARN("Wrong shader type %s.\n", debug_shader_type(reg_maps->shader_version.type)); return WINED3DERR_INVALIDCALL; } - if (version->major > shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level)) + if (!shader->is_ffp_vs && !shader->is_ffp_ps + && version->major > shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level)) { WARN("Shader version %u not supported by this device.\n", version->major); return WINED3DERR_INVALIDCALL; @@ -2421,6 +2550,30 @@ static void wined3d_shader_init_object(void *object) list_add_head(&device->shaders, &shader->shader_list_entry); + if (shader->is_ffp_vs) + { + struct wined3d_ffp_vs_settings *settings = shader->byte_code; + struct wined3d_shader_desc desc; + + if (!ffp_hlsl_compile_vs(settings, &desc)) + return; + free(settings); + shader_set_function(shader, &desc, WINED3D_SHADER_TYPE_VERTEX, NULL, + device->adapter->d3d_info.limits.vs_uniform_count); + } + + if (shader->is_ffp_ps) + { + struct ffp_frag_settings *settings = shader->byte_code; + struct wined3d_shader_desc desc; + + if (!ffp_hlsl_compile_ps(settings, &desc)) + return; + free(settings); + shader_set_function(shader, &desc, WINED3D_SHADER_TYPE_PIXEL, NULL, + device->adapter->d3d_info.limits.ps_uniform_count); + } + device->shader_backend->shader_precompile(device->shader_priv, shader); } @@ -2548,9 +2701,27 @@ void find_vs_compile_args(const struct wined3d_state *state, const struct wined3 && state->transforms[WINED3D_TS_PROJECTION]._24 == 0.0f && state->transforms[WINED3D_TS_PROJECTION]._34 == 0.0f && state->transforms[WINED3D_TS_PROJECTION]._44 == 1.0f) - args->fog_src = VS_FOG_Z; + { + /* Fog source is vertex output Z. + * + * However, if drawing RHW (which means we are using an HLSL + * replacement shader, since we got here), and depth testing is + * disabled, primitives are not supposed to be clipped by the + * viewport. We handle this in the vertex shader by essentially + * flushing output Z to zero. + * + * Fog needs to still read from the original Z, however. In this + * case we read from oFog, which contains the original Z. */ + + if (state->vertex_declaration->position_transformed) + args->fog_src = VS_FOG_COORD; + else + args->fog_src = VS_FOG_Z; + } else + { args->fog_src = VS_FOG_W; + } } else { @@ -2613,71 +2784,9 @@ bool vshader_get_input(const struct wined3d_shader *shader, return false; } -static void shader_trace(const void *code, size_t size, enum vkd3d_shader_source_type source_type) +static void shader_init(struct wined3d_shader *shader, struct wined3d_device *device, + void *parent, const struct wined3d_parent_ops *parent_ops) { - struct vkd3d_shader_compile_info info; - struct vkd3d_shader_code d3d_asm; - const char *ptr, *end, *line; - char *messages; - int ret; - - static const struct vkd3d_shader_compile_option compile_options[] = - { - {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_6}, - }; - - info.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO; - info.next = NULL; - info.source.code = code; - info.source.size = size; - info.source_type = source_type; - info.target_type = VKD3D_SHADER_TARGET_D3D_ASM; - info.options = compile_options; - info.option_count = ARRAY_SIZE(compile_options); - info.log_level = VKD3D_SHADER_LOG_WARNING; - info.source_name = NULL; - - ret = vkd3d_shader_compile(&info, &d3d_asm, &messages); - if (messages && *messages && FIXME_ON(d3d_shader)) - { - FIXME("Shader log:\n"); - ptr = messages; - end = ptr + strlen(ptr); - while ((line = wined3d_get_line(&ptr, end))) - { - FIXME(" %.*s", (int)(ptr - line), line); - } - FIXME("\n"); - } - vkd3d_shader_free_messages(messages); - - if (ret < 0) - { - ERR("Failed to disassemble, ret %d.\n", ret); - return; - } - - ptr = d3d_asm.code; - end = ptr + d3d_asm.size; - while ((line = wined3d_get_line(&ptr, end))) - { - TRACE(" %.*s", (int)(ptr - line), line); - } - TRACE("\n"); - - vkd3d_shader_free_shader_code(&d3d_asm); -} - -static HRESULT shader_init(struct wined3d_shader *shader, struct wined3d_device *device, - const struct wined3d_shader_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) -{ - HRESULT hr; - - TRACE("byte_code %p, byte_code_size %#lx.\n", desc->byte_code, (long)desc->byte_code_size); - - if (!desc->byte_code) - return WINED3DERR_INVALIDCALL; - shader->ref = 1; shader->device = device; shader->parent = parent; @@ -2690,87 +2799,6 @@ static HRESULT shader_init(struct wined3d_shader *shader, struct wined3d_device shader->lconst_inf_or_nan = FALSE; list_init(&shader->reg_maps.indexable_temps); list_init(&shader->shader_list_entry); - - if (desc->byte_code_size == ~(size_t)0) - { - struct wined3d_shader_version shader_version; - const struct wined3d_shader_frontend *fe; - struct wined3d_shader_instruction ins; - const DWORD *ptr; - void *fe_data; - - shader->source_type = VKD3D_SHADER_SOURCE_D3D_BYTECODE; - if (!(shader->frontend = shader_select_frontend(shader->source_type))) - { - FIXME("Unable to find frontend for shader.\n"); - hr = WINED3DERR_INVALIDCALL; - goto fail; - } - - fe = shader->frontend; - if (!(fe_data = fe->shader_init(desc->byte_code, desc->byte_code_size, &shader->output_signature))) - { - WARN("Failed to initialise frontend data.\n"); - hr = WINED3DERR_INVALIDCALL; - goto fail; - } - - fe->shader_read_header(fe_data, &ptr, &shader_version); - while (!fe->shader_is_end(fe_data, &ptr)) - fe->shader_read_instruction(fe_data, &ptr, &ins); - - fe->shader_free(fe_data); - - shader->byte_code_size = (ptr - desc->byte_code) * sizeof(*ptr); - - if (!(shader->byte_code = malloc(shader->byte_code_size))) - { - hr = E_OUTOFMEMORY; - goto fail; - } - memcpy(shader->byte_code, desc->byte_code, shader->byte_code_size); - - shader->function = shader->byte_code; - shader->functionLength = shader->byte_code_size; - } - else - { - unsigned int max_version; - - if (!(shader->byte_code = malloc(desc->byte_code_size))) - { - hr = E_OUTOFMEMORY; - goto fail; - } - memcpy(shader->byte_code, desc->byte_code, desc->byte_code_size); - shader->byte_code_size = desc->byte_code_size; - - max_version = shader_max_version_from_feature_level(device->cs->c.state->feature_level); - if (FAILED(hr = wined3d_shader_extract_from_dxbc(shader, max_version, &shader->source_type))) - goto fail; - - if (!(shader->frontend = shader_select_frontend(shader->source_type))) - { - FIXME("Unable to find frontend for shader.\n"); - hr = WINED3DERR_INVALIDCALL; - goto fail; - } - } - - if (TRACE_ON(d3d_shader)) - { - if (shader->source_type == VKD3D_SHADER_SOURCE_D3D_BYTECODE) - shader_trace(shader->function, shader->functionLength, shader->source_type); - else - shader_trace(shader->byte_code, shader->byte_code_size, shader->source_type); - } - - - return WINED3D_OK; - -fail: - shader_cleanup(shader); - return hr; } static HRESULT vertex_shader_init(struct wined3d_shader *shader, struct wined3d_device *device, @@ -2778,10 +2806,9 @@ static HRESULT vertex_shader_init(struct wined3d_shader *shader, struct wined3d_ { HRESULT hr; - if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) - return hr; + shader_init(shader, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(shader, + if (FAILED(hr = shader_set_function(shader, desc, WINED3D_SHADER_TYPE_VERTEX, NULL, device->adapter->d3d_info.limits.vs_uniform_count))) { shader_cleanup(shader); @@ -2797,10 +2824,9 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3 { HRESULT hr; - if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) - return hr; + shader_init(shader, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(shader, WINED3D_SHADER_TYPE_GEOMETRY, so_desc, 0))) + if (FAILED(hr = shader_set_function(shader, desc, WINED3D_SHADER_TYPE_GEOMETRY, so_desc, 0))) goto fail; return WINED3D_OK; @@ -2846,6 +2872,7 @@ void find_gs_compile_args(const struct wined3d_state *state, const struct wined3 void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, BOOL position_transformed, struct ps_compile_args *args, const struct wined3d_context *context) { + const struct wined3d_shader *vs = state->shader[WINED3D_SHADER_TYPE_VERTEX]; const struct wined3d_d3d_info *d3d_info = context->d3d_info; struct wined3d_shader_resource_view *view; struct wined3d_texture *texture; @@ -2873,7 +2900,7 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3 { uint32_t tex_transform = flags & ~WINED3D_TTFF_PROJECTED; - if (!state->shader[WINED3D_SHADER_TYPE_VERTEX]) + if (!vs || vs->is_ffp_vs) { enum wined3d_shader_resource_type resource_type = shader->reg_maps.resource_info[i].type; unsigned int j; @@ -3043,7 +3070,7 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3 switch (state->render_states[WINED3D_RS_FOGTABLEMODE]) { case WINED3D_FOG_NONE: - if (position_transformed || use_vs(state)) + if (position_transformed || (vs && !vs->is_ffp_vs)) { args->fog = WINED3D_FFP_PS_FOG_LINEAR; break; @@ -3127,10 +3154,9 @@ static HRESULT pixel_shader_init(struct wined3d_shader *shader, struct wined3d_d const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info; HRESULT hr; - if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) - return hr; + shader_init(shader, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(shader, + if (FAILED(hr = shader_set_function(shader, desc, WINED3D_SHADER_TYPE_PIXEL, NULL, d3d_info->limits.ps_uniform_count))) { shader_cleanup(shader); @@ -3175,14 +3201,9 @@ HRESULT CDECL wined3d_shader_create_cs(struct wined3d_device *device, const stru if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) - { - WARN("Failed to initialize compute shader, hr %#lx.\n", hr); - free(object); - return hr; - } + shader_init(object, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(object, WINED3D_SHADER_TYPE_COMPUTE, NULL, 0))) + if (FAILED(hr = shader_set_function(object, desc, WINED3D_SHADER_TYPE_COMPUTE, NULL, 0))) { shader_cleanup(object); free(object); @@ -3209,14 +3230,9 @@ HRESULT CDECL wined3d_shader_create_ds(struct wined3d_device *device, const stru if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) - { - WARN("Failed to initialize domain shader, hr %#lx.\n", hr); - free(object); - return hr; - } + shader_init(object, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(object, WINED3D_SHADER_TYPE_DOMAIN, NULL, 0))) + if (FAILED(hr = shader_set_function(object, desc, WINED3D_SHADER_TYPE_DOMAIN, NULL, 0))) { shader_cleanup(object); free(object); @@ -3271,14 +3287,9 @@ HRESULT CDECL wined3d_shader_create_hs(struct wined3d_device *device, const stru if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) - { - WARN("Failed to initialize hull shader, hr %#lx.\n", hr); - free(object); - return hr; - } + shader_init(object, device, parent, parent_ops); - if (FAILED(hr = shader_set_function(object, WINED3D_SHADER_TYPE_HULL, NULL, 0))) + if (FAILED(hr = shader_set_function(object, desc, WINED3D_SHADER_TYPE_HULL, NULL, 0))) { shader_cleanup(object); free(object); @@ -3346,3 +3357,53 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru return WINED3D_OK; } + +HRESULT wined3d_shader_create_ffp_vs(struct wined3d_device *device, + const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader **shader) +{ + struct wined3d_shader *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + shader_init(object, device, NULL, &wined3d_null_parent_ops); + object->is_ffp_vs = true; + if (!(object->byte_code = malloc(sizeof(*settings)))) + { + free(object); + return E_OUTOFMEMORY; + } + memcpy(object->byte_code, settings, sizeof(*settings)); + + wined3d_cs_init_object(device->cs, wined3d_shader_init_object, object); + + TRACE("Created FFP vertex shader %p.\n", object); + *shader = object; + + return WINED3D_OK; +} + +HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device, + const struct ffp_frag_settings *settings, struct wined3d_shader **shader) +{ + struct wined3d_shader *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + shader_init(object, device, NULL, &wined3d_null_parent_ops); + object->is_ffp_ps = true; + if (!(object->byte_code = malloc(sizeof(*settings)))) + { + free(object); + return E_OUTOFMEMORY; + } + memcpy(object->byte_code, settings, sizeof(*settings)); + + wined3d_cs_init_object(device->cs, wined3d_shader_init_object, object); + + TRACE("Created FFP pixel shader %p.\n", object); + *shader = object; + + return WINED3D_OK; +} diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index a79eb7b5f9f..d24b356dc1f 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -6,7 +6,7 @@ * Copyright 2005 Oliver Stieber * Copyright 2007 Stefan Dösinger for CodeWeavers * Copyright 2009 Henri Verbeet for CodeWeavers - * Copyright 2019,2020,2022 Zebediah Figura for CodeWeavers + * Copyright 2019,2020,2022-2024 Elizabeth Figura for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1299,6 +1299,7 @@ void CDECL wined3d_stateblock_set_vertex_shader(struct wined3d_stateblock *state wined3d_shader_decref(stateblock->stateblock_state.vs); stateblock->stateblock_state.vs = shader; stateblock->changed.vertexShader = TRUE; + stateblock->changed.ffp_vs_settings = 1; } static void wined3d_bitmap_set_bits(uint32_t *bitmap, unsigned int start, unsigned int count) @@ -1439,6 +1440,7 @@ void CDECL wined3d_stateblock_set_pixel_shader(struct wined3d_stateblock *stateb wined3d_shader_decref(stateblock->stateblock_state.ps); stateblock->stateblock_state.ps = shader; stateblock->changed.pixelShader = TRUE; + stateblock->changed.ffp_ps_settings = 1; } HRESULT CDECL wined3d_stateblock_set_ps_consts_f(struct wined3d_stateblock *stateblock, @@ -1573,6 +1575,9 @@ void CDECL wined3d_stateblock_set_vertex_declaration(struct wined3d_stateblock * || declaration->normal != prev->normal || declaration->point_size != prev->point_size) stateblock->changed.ffp_vs_settings = 1; } + + if (declaration->position_transformed != prev->position_transformed) + stateblock->changed.ffp_vs_settings = 1; } else { @@ -2379,10 +2384,10 @@ static void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state } -/* FFP push constant buffers do not have a "default" state on the CS side. - * We need to explicitly invalidate them when initializing the context or - * resetting. */ -static void wined3d_stateblock_invalidate_push_constants(struct wined3d_stateblock *stateblock) +/* Some states, e.g. FFP push constant buffers, do not have a "default" state + * on the CS side. We need to explicitly invalidate them when initializing the + * context or resetting. */ +static void wined3d_stateblock_invalidate_initial_states(struct wined3d_stateblock *stateblock) { stateblock->changed.ffp_ps_constants = 1; stateblock->changed.lights = 1; @@ -2392,6 +2397,8 @@ static void wined3d_stateblock_invalidate_push_constants(struct wined3d_stateblo memset(stateblock->changed.transform, 0xff, sizeof(stateblock->changed.transform)); stateblock->changed.modelview_matrices = 1; stateblock->changed.point_scale = 1; + stateblock->changed.ffp_vs_settings = 1; + stateblock->changed.ffp_ps_settings = 1; } static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const struct wined3d_stateblock *device_state, @@ -2409,7 +2416,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru list_init(&stateblock->changed.changed_lights); if (type == WINED3D_SBT_PRIMARY) - wined3d_stateblock_invalidate_push_constants(stateblock); + wined3d_stateblock_invalidate_initial_states(stateblock); if (type == WINED3D_SBT_RECORDED || type == WINED3D_SBT_PRIMARY) return WINED3D_OK; @@ -2486,7 +2493,7 @@ void CDECL wined3d_stateblock_reset(struct wined3d_stateblock *stateblock) memset(&stateblock->stateblock_state, 0, sizeof(stateblock->stateblock_state)); stateblock->stateblock_state.light_state = &stateblock->light_state; wined3d_stateblock_state_init(&stateblock->stateblock_state, stateblock->device, WINED3D_STATE_INIT_DEFAULT); - wined3d_stateblock_invalidate_push_constants(stateblock); + wined3d_stateblock_invalidate_initial_states(stateblock); } static void wined3d_device_set_base_vertex_index(struct wined3d_device *device, int base_index) @@ -2909,6 +2916,65 @@ void CDECL wined3d_stateblock_apply_clear_state(struct wined3d_stateblock *state wined3d_device_set_render_state(device, WINED3D_RS_SRGBWRITEENABLE, state->rs[WINED3D_RS_SRGBWRITEENABLE]); } +static struct wined3d_shader *get_ffp_vertex_shader(struct wined3d_device *device, const struct wined3d_state *state) +{ + static const struct wined3d_stream_info dummy_stream_info; + struct wined3d_ffp_vs_settings settings; + const struct wine_rb_entry *entry; + struct wined3d_ffp_vs *vs; + + /* XXX: wined3d_ffp_get_vs_settings() only needs the stream info for the + * swizzle map, which the HLSL pipeline doesn't use (it will be computed and + * used later as part of struct vs_compile_args). + * + * This is nevertheless janky, and we'd like to get rid of it. Eventually + * once the HLSL backend is used everywhere, we can get rid of the swizzle + * map from wined3d_ffp_vs_settings. */ + wined3d_ffp_get_vs_settings(state, &dummy_stream_info, &device->adapter->d3d_info, &settings); + + if ((entry = wine_rb_get(&device->ffp_vertex_shaders, &settings))) + return WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_vs, entry.entry)->shader; + + if (!(vs = malloc(sizeof(*vs)))) + return NULL; + + vs->entry.settings = settings; + if (FAILED(wined3d_shader_create_ffp_vs(device, &settings, &vs->shader))) + { + free(vs); + return NULL; + } + if (wine_rb_put(&device->ffp_vertex_shaders, &vs->entry.settings, &vs->entry.entry) == -1) + ERR("Failed to insert FFP vertex shader.\n"); + + return vs->shader; +} + +static struct wined3d_shader *get_ffp_pixel_shader(struct wined3d_device *device, const struct wined3d_state *state) +{ + struct ffp_frag_settings settings; + const struct ffp_frag_desc *desc; + struct wined3d_ffp_ps *ps; + + wined3d_ffp_get_fs_settings(state, &device->adapter->d3d_info, &settings); + + if ((desc = find_ffp_frag_shader(&device->ffp_pixel_shaders, &settings))) + return CONTAINING_RECORD(desc, struct wined3d_ffp_ps, entry)->shader; + + if (!(ps = malloc(sizeof(*ps)))) + return NULL; + + ps->entry.settings = settings; + if (FAILED(wined3d_shader_create_ffp_ps(device, &settings, &ps->shader))) + { + free(ps); + return NULL; + } + add_ffp_frag_shader(&device->ffp_pixel_shaders, &ps->entry); + + return ps->shader; +} + void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, struct wined3d_stateblock *stateblock) { @@ -3746,16 +3812,40 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, WINED3D_SHADER_CONST_FFP_PS, 0, offsetof(struct wined3d_ffp_ps_constants, color_key), &constants); } - if (changed->ffp_vs_settings && !state->vs) + /* XXX: We don't invalidate HLSL shaders for every field contained in + * wined3d_ffp_vs_settings / ffp_frag_settings; only the ones that the HLSL + * FFP pipeline cares about. The rest should eventually be removed from + * those structs and left only in vs_compile_args / ps_compile_args. */ + + if (changed->ffp_vs_settings + && (!state->vs || !state->vertex_declaration || state->vertex_declaration->position_transformed)) { - /* Force invalidation of the vertex shader. */ - wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, NULL); + if (device->adapter->d3d_info.ffp_hlsl) + { + struct wined3d_shader *shader = get_ffp_vertex_shader(device, device->cs->c.state); + + wined3d_device_context_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, shader); + } + else + { + /* Force invalidation of the vertex shader. */ + wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, NULL); + } } if (changed->ffp_ps_settings && !state->ps) { - /* Force invalidation of the pixel shader. */ - wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_PIXEL, NULL); + if (device->adapter->d3d_info.ffp_hlsl) + { + struct wined3d_shader *shader = get_ffp_pixel_shader(device, device->cs->c.state); + + wined3d_device_context_set_shader(context, WINED3D_SHADER_TYPE_PIXEL, shader); + } + else + { + /* Force invalidation of the pixel shader. */ + wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_PIXEL, NULL); + } } assert(list_empty(&stateblock->changed.changed_lights)); diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 71e73116935..dea43836f06 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -6448,7 +6448,7 @@ void wined3d_ffp_get_vs_settings(const struct wined3d_state *state, const struct memset(settings, 0, sizeof(*settings)); - if (si->position_transformed) + if (vdecl->position_transformed) { settings->transformed = 1; settings->point_size = state->primitive_type == WINED3D_PT_POINTLIST; diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index 863428bb53a..3b436919559 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -463,6 +463,11 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL) TRACE("Forcing all constant buffers to be write-mappable.\n"); wined3d_settings.cb_access_map_w = TRUE; } + if (!get_config_key_dword(hkey, appkey, env, "ffp_hlsl", &tmpvalue)) + { + ERR_(winediag)("Using the HLSL-based FFP backend.\n"); + wined3d_settings.ffp_hlsl = tmpvalue; + } } if (appkey) RegCloseKey( appkey ); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 50418992163..2e0a541cea5 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -242,6 +242,7 @@ struct wined3d_d3d_info uint32_t fences : 1; uint32_t persistent_map : 1; uint32_t gpu_push_constants : 1; + uint32_t ffp_hlsl : 1; enum wined3d_feature_level feature_level; DWORD multisample_draw_location; @@ -475,7 +476,6 @@ struct wined3d_settings char *logo; unsigned int multisample_textures; unsigned int sample_count; - BOOL check_float_constants; unsigned int strict_shader_math; unsigned int max_sm_vs; unsigned int max_sm_hs; @@ -485,7 +485,9 @@ struct wined3d_settings unsigned int max_sm_cs; enum wined3d_renderer renderer; enum wined3d_shader_backend shader_backend; - BOOL cb_access_map_w; + bool check_float_constants; + bool cb_access_map_w; + bool ffp_hlsl; }; extern struct wined3d_settings wined3d_settings; @@ -2048,10 +2050,11 @@ void context_state_fb(struct wined3d_context *context, struct wined3d_light_constants { + /* Padding is needed for the HLSL backend. */ struct wined3d_color diffuse, specular, ambient; struct wined3d_vec4 position, direction; float range, falloff, cos_half_theta, cos_half_phi; - float const_att, linear_att, quad_att; + float const_att, linear_att, quad_att, padding; }; /***************************************************************************** @@ -2662,6 +2665,12 @@ struct ffp_frag_desc int wined3d_ffp_frag_program_key_compare(const void *key, const struct wine_rb_entry *entry); int wined3d_ffp_vertex_program_key_compare(const void *key, const struct wine_rb_entry *entry); +struct wined3d_ffp_ps +{ + struct ffp_frag_desc entry; + struct wined3d_shader *shader; +}; + extern const struct wined3d_parent_ops wined3d_null_parent_ops; void wined3d_ffp_get_fs_settings(const struct wined3d_state *state, @@ -2724,6 +2733,12 @@ struct wined3d_ffp_vs_desc struct wined3d_ffp_vs_settings settings; }; +struct wined3d_ffp_vs +{ + struct wined3d_ffp_vs_desc entry; + struct wined3d_shader *shader; +}; + void wined3d_ffp_get_vs_settings(const struct wined3d_state *state, const struct wined3d_stream_info *si, const struct wined3d_d3d_info *d3d_info, struct wined3d_ffp_vs_settings *settings); @@ -2769,8 +2784,10 @@ struct wined3d_ffp_vs_constants struct wined3d_ffp_point_constants { float scale_const, scale_linear, scale_quad; + float padding; /* For the HLSL backend. */ } point; struct wined3d_material material; + float padding[3]; /* For the HLSL backend. */ struct wined3d_ffp_light_constants { struct wined3d_color ambient; @@ -2983,6 +3000,7 @@ struct wined3d_device struct list shaders; /* a linked list to track shaders (pixel and vertex) */ struct wine_rb_tree so_descs; struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states; + struct wine_rb_tree ffp_vertex_shaders, ffp_pixel_shaders; /* Render Target Support */ struct wined3d_rendertarget_view *auto_depth_stencil_view; @@ -4206,7 +4224,9 @@ struct wined3d_shader unsigned int functionLength; void *byte_code; unsigned int byte_code_size; - BOOL load_local_constsF; + bool load_local_constsF; + bool is_ffp_vs; + bool is_ffp_ps; enum vkd3d_shader_source_type source_type; const struct wined3d_shader_frontend *frontend; void *frontend_data; @@ -4244,6 +4264,11 @@ struct wined3d_shader } u; }; +HRESULT wined3d_shader_create_ffp_vs(struct wined3d_device *device, + const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader **shader); +HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device, + const struct ffp_frag_settings *settings, struct wined3d_shader **shader); + enum wined3d_shader_resource_type pixelshader_get_resource_type(const struct wined3d_shader_reg_maps *reg_maps, unsigned int resource_idx, DWORD tex_types); void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, @@ -4273,6 +4298,9 @@ BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage us enum vkd3d_shader_visibility vkd3d_shader_visibility_from_wined3d(enum wined3d_shader_type shader_type); +bool ffp_hlsl_compile_vs(const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader_desc *shader_desc); +bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc); + static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg) { switch (reg->type)