Compare commits

...

9 commits

Author SHA1 Message Date
Elizabeth Figura
25ed8123dc Merge branch 'mr1' into 'master'
wined3d: FFP HLSL shaders, part 1/3.

See merge request wine/wine!6813
2024-11-16 07:51:42 +00:00
Elizabeth Figura
2af94b3952 wined3d: Beginnings of an HLSL FFP vertex shader implementation. 2024-11-13 18:15:35 -06:00
Elizabeth Figura
8b8ca1acc5 wined3d: Use the FFP HLSL pipeline for pretransformed draws as well. 2024-11-13 18:15:35 -06:00
Elizabeth Figura
1fe2f01aac 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.
2024-11-13 18:14:31 -06:00
Elizabeth Figura
b38b973efb 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.
2024-11-13 18:08:02 -06:00
Elizabeth Figura
6a978ed054 wined3d: Create stub FFP vertex shaders. 2024-11-13 18:07:13 -06:00
Elizabeth Figura
1edafed827 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.
2024-11-13 18:07:13 -06:00
Elizabeth Figura
aaac358bed 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().
2024-11-13 18:06:08 -06:00
Elizabeth Figura
d9de4b168c wined3d: Move shader_trace(). 2024-11-13 18:01:59 -06:00
13 changed files with 720 additions and 221 deletions

View file

@ -14,6 +14,7 @@ SOURCES = \
device.c \
directx.c \
ffp_gl.c \
ffp_hlsl.c \
gl_compat.c \
glsl_shader.c \
palette.c \

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

246
dlls/wined3d/ffp_hlsl.c Normal file
View file

@ -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 <vkd3d_shader.h>
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;
}

View file

@ -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];

View file

@ -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;
}

View file

@ -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));

View file

@ -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;

View file

@ -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 );

View file

@ -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)