From d9de4b168cb1a4db46f40e4984697ac500b60498 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Wed, 13 Nov 2024 18:01:59 -0600 Subject: [PATCH 1/8] wined3d: Move shader_trace(). --- dlls/wined3d/shader.c | 103 ++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index f1cb92d276a..bde42ed485f 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2268,6 +2268,54 @@ static HRESULT geometry_shader_init_stream_output(struct wined3d_shader *shader, return WINED3D_OK; } +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, enum wined3d_shader_type type, const struct wined3d_stream_output_desc *so_desc, unsigned int float_const_count) { @@ -2613,61 +2661,6 @@ 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) -{ - 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) { From aaac358bed5bd4bbb67d818994909019141d361c Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Thu, 19 Sep 2024 18:19:05 -0500 Subject: [PATCH 2/8] wined3d: Move shader parsing to shader_set_function(). The idea is that we will have wined3d_shader objects that represent shaders not yet in d3d form (specifically, in HLSL form or containing only an FFP settings struct.) Hence we need to make it possible to delay d3d shader parsing, but still keep the rest of shader_init(). --- dlls/wined3d/shader.c | 220 +++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 123 deletions(-) diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index bde42ed485f..3bef05d979d 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2316,7 +2316,7 @@ static void shader_trace(const void *code, size_t size, enum vkd3d_shader_source vkd3d_shader_free_shader_code(&d3d_asm); } -static HRESULT shader_set_function(struct wined3d_shader *shader, +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; @@ -2327,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) { @@ -2661,16 +2741,9 @@ bool vshader_get_input(const struct wined3d_shader *shader, return false; } -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) +static void shader_init(struct wined3d_shader *shader, struct wined3d_device *device, + 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; @@ -2683,87 +2756,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, @@ -2771,10 +2763,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); @@ -2790,10 +2781,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; @@ -3120,10 +3110,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); @@ -3168,14 +3157,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); @@ -3202,14 +3186,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); @@ -3264,14 +3243,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); From 1edafed82745d13a135ce0dea6906ce5858de1fd Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Mon, 23 Sep 2024 18:25:40 -0500 Subject: [PATCH 3/8] wined3d: Create stub FFP pixel shaders. We only compute ffp_frag_settings and stash that in the shader byte_code. The HLSL shader will be compiled to sm2 bytecode on the CS side, and then parsed and interpreted by the shader backend (and all other code) as if it were a real shader. In theory, we could take the extra step of retrieving the settings from this shader in the GLSL backend, instead of from the current state. This however requires changing a number of places which currently check "state->shader[WINED3D_SHADER_TYPE_PIXEL]" to also check "is_ffp_ps", and it also means we need to handle some more states (shade mode, fog, etc.) as part of ffp_frag_settings. Both of these will go away as soon as the GLSL backend can simply consume the generated HLSL shader. --- dlls/wined3d/Makefile.in | 1 + dlls/wined3d/adapter_vk.c | 1 + dlls/wined3d/device.c | 12 +++++ dlls/wined3d/ffp_hlsl.c | 97 ++++++++++++++++++++++++++++++++++ dlls/wined3d/shader.c | 40 +++++++++++++- dlls/wined3d/stateblock.c | 59 +++++++++++++++++---- dlls/wined3d/wined3d_private.h | 16 +++++- 7 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 dlls/wined3d/ffp_hlsl.c 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_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/device.c b/dlls/wined3d/device.c index 0fb71108b27..c4558e1f60d 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1667,6 +1667,14 @@ 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_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 +1722,7 @@ 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_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 +5524,7 @@ 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_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 +5537,7 @@ 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_pixel_shaders, NULL, NULL); wined3d_decref(device->wined3d); return hr; } @@ -5554,6 +5565,7 @@ 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_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..72a8e702cad --- /dev/null +++ b/dlls/wined3d/ffp_hlsl.c @@ -0,0 +1,97 @@ +/* + * Fixed-function pipeline replacement implemented using HLSL shaders + * + * 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_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_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/shader.c b/dlls/wined3d/shader.c index 3bef05d979d..71dffd75761 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2436,7 +2436,8 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, const struct w 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_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; @@ -2549,6 +2550,18 @@ static void wined3d_shader_init_object(void *object) list_add_head(&device->shaders, &shader->shader_list_entry); + 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); } @@ -3313,3 +3326,28 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru 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..fa5b3867d58 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 @@ -1439,6 +1439,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, @@ -2379,10 +2380,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 +2393,7 @@ 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_ps_settings = 1; } static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const struct wined3d_stateblock *device_state, @@ -2409,7 +2411,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 +2488,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 +2911,31 @@ 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_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,6 +3773,11 @@ 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); } + /* 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) { /* Force invalidation of the vertex shader. */ @@ -3754,8 +3786,17 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, 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/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 50418992163..7b357218121 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; @@ -2662,6 +2663,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, @@ -2983,6 +2990,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_pixel_shaders; /* Render Target Support */ struct wined3d_rendertarget_view *auto_depth_stencil_view; @@ -4206,7 +4214,8 @@ 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_ps; enum vkd3d_shader_source_type source_type; const struct wined3d_shader_frontend *frontend; void *frontend_data; @@ -4244,6 +4253,9 @@ struct wined3d_shader } u; }; +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 +4285,8 @@ 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_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) From 6a978ed054f6b3c334aa7231f3e880be187dedac Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Mon, 23 Sep 2024 18:50:26 -0500 Subject: [PATCH 4/8] wined3d: Create stub FFP vertex shaders. --- dlls/wined3d/device.c | 12 +++++++++ dlls/wined3d/ffp_hlsl.c | 33 +++++++++++++++++++++++ dlls/wined3d/shader.c | 39 ++++++++++++++++++++++++++- dlls/wined3d/stateblock.c | 49 ++++++++++++++++++++++++++++++++-- dlls/wined3d/utils.c | 2 +- dlls/wined3d/wined3d_private.h | 12 ++++++++- 6 files changed, 142 insertions(+), 5 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index c4558e1f60d..7e24de8afb3 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1667,6 +1667,14 @@ 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); @@ -1722,6 +1730,7 @@ 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) @@ -5524,6 +5533,7 @@ 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 @@ -5537,6 +5547,7 @@ 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; @@ -5565,6 +5576,7 @@ 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 index 72a8e702cad..8451be71e82 100644 --- a/dlls/wined3d/ffp_hlsl.c +++ b/dlls/wined3d/ffp_hlsl.c @@ -23,6 +23,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); +static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings *settings, + struct wined3d_string_buffer *string) +{ + FIXME("Not yet implemented.\n"); + return false; +} + static bool ffp_hlsl_generate_pixel_shader(const struct ffp_frag_settings *settings, struct wined3d_string_buffer *string) { @@ -70,6 +77,32 @@ static bool compile_hlsl_shader(const struct wined3d_string_buffer *hlsl, 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; diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 71dffd75761..e3f758f4b9d 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2436,7 +2436,7 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, const struct w WARN("Wrong shader type %s.\n", debug_shader_type(reg_maps->shader_version.type)); return WINED3DERR_INVALIDCALL; } - if (!shader->is_ffp_ps + 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); @@ -2550,6 +2550,18 @@ 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; @@ -3327,6 +3339,31 @@ 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) { diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index fa5b3867d58..8d2bfcf8f8a 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -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) @@ -2393,6 +2394,7 @@ static void wined3d_stateblock_invalidate_initial_states(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; } @@ -2911,6 +2913,40 @@ 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; @@ -3780,8 +3816,17 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, if (changed->ffp_vs_settings && !state->vs) { - /* 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) 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_private.h b/dlls/wined3d/wined3d_private.h index 7b357218121..bb593a94fa2 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2731,6 +2731,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); @@ -2990,7 +2996,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_pixel_shaders; + struct wine_rb_tree ffp_vertex_shaders, ffp_pixel_shaders; /* Render Target Support */ struct wined3d_rendertarget_view *auto_depth_stencil_view; @@ -4215,6 +4221,7 @@ struct wined3d_shader void *byte_code; unsigned int byte_code_size; 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; @@ -4253,6 +4260,8 @@ 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); @@ -4285,6 +4294,7 @@ 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) From b38b973efb6ac12c444b8b60cd23763691a64ccd Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Mon, 23 Sep 2024 19:04:15 -0500 Subject: [PATCH 5/8] wined3d: Account for HLSL FFP shaders in find_ps_compile_args(). In most cases, it is possible to construct a D3D shader which behaves identically to a given FFP pipeline. There are two exceptions, related to fog and texture transforms, where the FFP pipeline has special behaviour that cannot be emulated with shaders, and we handle those here by checking whether our shader is actually an FFP replacement shader. --- dlls/wined3d/shader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index e3f758f4b9d..2a67f3944bd 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2854,6 +2854,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; @@ -2881,7 +2882,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; @@ -3051,7 +3052,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; From 1fe2f01aace4b69008e43c4824621402fe280c64 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Sun, 9 Jun 2024 12:50:29 -0500 Subject: [PATCH 6/8] wined3d: Allow using the HLSL FFP replacement with GL. This will allow us to replace the GLSL FFP pipes, and is useful for testing the FFP HLSL backend before the Vulkan backend is mature enough in other respects. This patch introduces the d3d setting "ffp_hlsl", set to a DWORD value. It is disabled by default, and only has an effect on the GL renderer. --- dlls/wined3d/adapter_gl.c | 1 + dlls/wined3d/cs.c | 8 ++++ dlls/wined3d/glsl_shader.c | 72 +++++++++++++++++++++++++--------- dlls/wined3d/wined3d_main.c | 5 +++ dlls/wined3d/wined3d_private.h | 5 ++- 5 files changed, 70 insertions(+), 21 deletions(-) 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/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/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 7ff9ce0427b..785050e7631 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) { @@ -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/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 bb593a94fa2..12b61b68bbb 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -476,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; @@ -486,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; From 8b8ca1acc555bc53e76213cb1c4ab6c48630bacf Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Wed, 7 Aug 2024 20:25:24 -0500 Subject: [PATCH 7/8] wined3d: Use the FFP HLSL pipeline for pretransformed draws as well. --- dlls/wined3d/context.c | 2 +- dlls/wined3d/glsl_shader.c | 4 ++-- dlls/wined3d/shader.c | 20 +++++++++++++++++++- dlls/wined3d/stateblock.c | 6 +++++- 4 files changed, 27 insertions(+), 5 deletions(-) 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/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 785050e7631..61b53da540a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -10425,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; diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 2a67f3944bd..7c18c96dbf6 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2701,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 { diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 8d2bfcf8f8a..d24b356dc1f 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -1575,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 { @@ -3814,7 +3817,8 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, * 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) + if (changed->ffp_vs_settings + && (!state->vs || !state->vertex_declaration || state->vertex_declaration->position_transformed)) { if (device->adapter->d3d_info.ffp_hlsl) { From 2af94b3952d8080f39edcea210738f3e8f563569 Mon Sep 17 00:00:00 2001 From: Elizabeth Figura Date: Sun, 9 Jun 2024 12:50:29 -0500 Subject: [PATCH 8/8] wined3d: Beginnings of an HLSL FFP vertex shader implementation. --- dlls/wined3d/ffp_hlsl.c | 122 ++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d_private.h | 5 +- 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/ffp_hlsl.c b/dlls/wined3d/ffp_hlsl.c index 8451be71e82..959ecd4195a 100644 --- a/dlls/wined3d/ffp_hlsl.c +++ b/dlls/wined3d/ffp_hlsl.c @@ -1,6 +1,10 @@ /* * 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 @@ -24,10 +28,122 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings *settings, - struct wined3d_string_buffer *string) + struct wined3d_string_buffer *buffer) { - FIXME("Not yet implemented.\n"); - return false; + 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, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 12b61b68bbb..2e0a541cea5 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2050,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; }; /***************************************************************************** @@ -2783,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;