Merge branch 'mr1' into 'master'

wined3d: FFP HLSL shaders, part 1/3.

See merge request wine/wine!6813
This commit is contained in:
Elizabeth Figura 2024-11-19 22:22:27 +00:00
commit b75290ba6c
13 changed files with 720 additions and 221 deletions

View file

@ -14,6 +14,7 @@ SOURCES = \
device.c \ device.c \
directx.c \ directx.c \
ffp_gl.c \ ffp_gl.c \
ffp_hlsl.c \
gl_compat.c \ gl_compat.c \
glsl_shader.c \ glsl_shader.c \
palette.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->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->filling_convention_offset = gl_info->filling_convention_offset;
d3d_info->persistent_map = !!gl_info->supported[ARB_BUFFER_STORAGE]; 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]) if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
d3d_info->multisample_draw_location = WINED3D_LOCATION_TEXTURE_RGB; 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->fences = true;
d3d_info->persistent_map = true; d3d_info->persistent_map = true;
d3d_info->gpu_push_constants = 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 /* 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. * 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) const struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info)
{ {
/* We need to deal with frequency data! */ /* 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; struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
BOOL use_vshader = use_vs(state);
unsigned int i; unsigned int i;
stream_info->use_map = 0; 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; const struct wined3d_cs_push_constants *op = data;
struct wined3d_device *device = cs->c.device; struct wined3d_device *device = cs->c.device;
unsigned int ffp_start_idx, ffp_end_idx;
unsigned int context_count, i; unsigned int context_count, i;
/* The constant buffers were already updated; this op is just to mark the /* The constant buffers were already updated; this op is just to mark the
* constants as invalid in the device state. */ * 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) if (op->type == WINED3D_PUSH_CONSTANTS_VS_F)
device->shader_backend->shader_update_float_vertex_constants(device, op->start_idx, op->count); device->shader_backend->shader_update_float_vertex_constants(device, op->start_idx, op->count);
else if (op->type == WINED3D_PUSH_CONSTANTS_PS_F) else if (op->type == WINED3D_PUSH_CONSTANTS_PS_F)
device->shader_backend->shader_update_float_pixel_constants(device, op->start_idx, op->count); 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) for (i = 0, context_count = device->context_count; i < context_count; ++i)
device->contexts[i]->constant_update_mask |= op->update_mask; 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); 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) void wined3d_device_uninit_3d(struct wined3d_device *device)
{ {
struct wined3d_state *state = device->cs->c.state; 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->rasterizer_states, device_free_rasterizer_state, NULL);
wine_rb_destroy(&device->blend_states, device_free_blend_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->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) 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->rasterizer_states, wined3d_rasterizer_state_compare);
wine_rb_init(&device->blend_states, wined3d_blend_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->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 if (vertex_pipeline->vp_states && fragment_pipeline->states
&& FAILED(hr = compile_state_table(device->state_table, device->multistate_funcs, && 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->blend_states, NULL, NULL);
wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
wine_rb_destroy(&device->so_descs, 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); wined3d_decref(device->wined3d);
return hr; return hr;
} }
@ -5554,6 +5576,8 @@ err:
wine_rb_destroy(&device->blend_states, NULL, NULL); wine_rb_destroy(&device->blend_states, NULL, NULL);
wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
wine_rb_destroy(&device->so_descs, 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); wined3d_decref(device->wined3d);
return hr; 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; constant_version = prog->constant_version;
update_mask = context->constant_update_mask & prog->constant_update_mask; update_mask = context->constant_update_mask & prog->constant_update_mask;
if (update_mask & WINED3D_SHADER_CONST_VS_F) if (vshader && vshader->is_ffp_vs)
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); /* 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) if (context->constant_update_mask & vs_update_mask)
shader_glsl_load_constants_i(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_I], shader_glsl_load_constants_f(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_FFP],
prog->vs.uniform_i_locations, vshader->reg_maps.integer_constants); 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) if (update_mask & WINED3D_SHADER_CONST_VS_I)
shader_glsl_load_constants_b(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_B], shader_glsl_load_constants_i(vshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_VS_I],
prog->vs.uniform_b_locations, vshader->reg_maps.boolean_constants); 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) 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); WINED3D_LIGHT_PARALLELPOINT, &constants->light.lights[i], prog);
} }
if (update_mask & WINED3D_SHADER_CONST_PS_F) if (pshader && pshader->is_ffp_ps)
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); 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) if (context->constant_update_mask & ps_update_mask)
shader_glsl_load_constants_i(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_I], shader_glsl_load_constants_f(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_FFP],
prog->ps.uniform_i_locations, pshader->reg_maps.integer_constants); 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) if (update_mask & WINED3D_SHADER_CONST_PS_I)
shader_glsl_load_constants_b(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_B], shader_glsl_load_constants_i(pshader, context_gl, device->push_constants[WINED3D_PUSH_CONSTANTS_PS_I],
prog->ps.uniform_b_locations, pshader->reg_maps.boolean_constants); 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) 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_id = ctx_data->glsl_program->vs.id;
vs_list = &ctx_data->glsl_program->vs.shader_entry; 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]; 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; 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, static void glsl_fragment_pipe_fog(struct wined3d_context *context,
const struct wined3d_state *state, DWORD state_id) 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; enum fogsource new_source;
DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART];
DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; 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; 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) 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; 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; unsigned int backend_version;
HRESULT hr; HRESULT hr;
TRACE("shader %p, type %s, float_const_count %u.\n", TRACE("shader %p, byte_code %p, size %#Ix, type %s, float_const_count %u.\n",
shader, debug_shader_type(type), float_const_count); 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) 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)); WARN("Wrong shader type %s.\n", debug_shader_type(reg_maps->shader_version.type));
return WINED3DERR_INVALIDCALL; 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); WARN("Shader version %u not supported by this device.\n", version->major);
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
@ -2421,6 +2550,30 @@ static void wined3d_shader_init_object(void *object)
list_add_head(&device->shaders, &shader->shader_list_entry); 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); 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]._24 == 0.0f
&& state->transforms[WINED3D_TS_PROJECTION]._34 == 0.0f && state->transforms[WINED3D_TS_PROJECTION]._34 == 0.0f
&& state->transforms[WINED3D_TS_PROJECTION]._44 == 1.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 else
{
args->fog_src = VS_FOG_W; args->fog_src = VS_FOG_W;
}
} }
else else
{ {
@ -2613,71 +2784,9 @@ bool vshader_get_input(const struct wined3d_shader *shader,
return false; 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->ref = 1;
shader->device = device; shader->device = device;
shader->parent = parent; shader->parent = parent;
@ -2690,87 +2799,6 @@ static HRESULT shader_init(struct wined3d_shader *shader, struct wined3d_device
shader->lconst_inf_or_nan = FALSE; shader->lconst_inf_or_nan = FALSE;
list_init(&shader->reg_maps.indexable_temps); list_init(&shader->reg_maps.indexable_temps);
list_init(&shader->shader_list_entry); 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, 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; HRESULT hr;
if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) shader_init(shader, device, parent, parent_ops);
return hr;
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))) WINED3D_SHADER_TYPE_VERTEX, NULL, device->adapter->d3d_info.limits.vs_uniform_count)))
{ {
shader_cleanup(shader); shader_cleanup(shader);
@ -2797,10 +2824,9 @@ static HRESULT geometry_shader_init(struct wined3d_shader *shader, struct wined3
{ {
HRESULT hr; HRESULT hr;
if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) shader_init(shader, device, parent, parent_ops);
return hr;
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; goto fail;
return WINED3D_OK; 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, 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) 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; const struct wined3d_d3d_info *d3d_info = context->d3d_info;
struct wined3d_shader_resource_view *view; struct wined3d_shader_resource_view *view;
struct wined3d_texture *texture; 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; 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; enum wined3d_shader_resource_type resource_type = shader->reg_maps.resource_info[i].type;
unsigned int j; 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]) switch (state->render_states[WINED3D_RS_FOGTABLEMODE])
{ {
case WINED3D_FOG_NONE: 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; args->fog = WINED3D_FFP_PS_FOG_LINEAR;
break; 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; const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
HRESULT hr; HRESULT hr;
if (FAILED(hr = shader_init(shader, device, desc, parent, parent_ops))) shader_init(shader, device, parent, parent_ops);
return hr;
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))) WINED3D_SHADER_TYPE_PIXEL, NULL, d3d_info->limits.ps_uniform_count)))
{ {
shader_cleanup(shader); 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)))) if (!(object = calloc(1, sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) shader_init(object, device, parent, parent_ops);
{
WARN("Failed to initialize compute shader, hr %#lx.\n", hr);
free(object);
return hr;
}
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); shader_cleanup(object);
free(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)))) if (!(object = calloc(1, sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) shader_init(object, device, parent, parent_ops);
{
WARN("Failed to initialize domain shader, hr %#lx.\n", hr);
free(object);
return hr;
}
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); shader_cleanup(object);
free(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)))) if (!(object = calloc(1, sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
if (FAILED(hr = shader_init(object, device, desc, parent, parent_ops))) shader_init(object, device, parent, parent_ops);
{
WARN("Failed to initialize hull shader, hr %#lx.\n", hr);
free(object);
return hr;
}
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); shader_cleanup(object);
free(object); free(object);
@ -3346,3 +3357,53 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru
return WINED3D_OK; 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 2005 Oliver Stieber
* Copyright 2007 Stefan Dösinger for CodeWeavers * Copyright 2007 Stefan Dösinger for CodeWeavers
* Copyright 2009 Henri Verbeet 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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); wined3d_shader_decref(stateblock->stateblock_state.vs);
stateblock->stateblock_state.vs = shader; stateblock->stateblock_state.vs = shader;
stateblock->changed.vertexShader = TRUE; 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) 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); wined3d_shader_decref(stateblock->stateblock_state.ps);
stateblock->stateblock_state.ps = shader; stateblock->stateblock_state.ps = shader;
stateblock->changed.pixelShader = TRUE; stateblock->changed.pixelShader = TRUE;
stateblock->changed.ffp_ps_settings = 1;
} }
HRESULT CDECL wined3d_stateblock_set_ps_consts_f(struct wined3d_stateblock *stateblock, 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) || declaration->normal != prev->normal || declaration->point_size != prev->point_size)
stateblock->changed.ffp_vs_settings = 1; stateblock->changed.ffp_vs_settings = 1;
} }
if (declaration->position_transformed != prev->position_transformed)
stateblock->changed.ffp_vs_settings = 1;
} }
else 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. /* Some states, e.g. FFP push constant buffers, do not have a "default" state
* We need to explicitly invalidate them when initializing the context or * on the CS side. We need to explicitly invalidate them when initializing the
* resetting. */ * context or resetting. */
static void wined3d_stateblock_invalidate_push_constants(struct wined3d_stateblock *stateblock) static void wined3d_stateblock_invalidate_initial_states(struct wined3d_stateblock *stateblock)
{ {
stateblock->changed.ffp_ps_constants = 1; stateblock->changed.ffp_ps_constants = 1;
stateblock->changed.lights = 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)); memset(stateblock->changed.transform, 0xff, sizeof(stateblock->changed.transform));
stateblock->changed.modelview_matrices = 1; stateblock->changed.modelview_matrices = 1;
stateblock->changed.point_scale = 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, 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); list_init(&stateblock->changed.changed_lights);
if (type == WINED3D_SBT_PRIMARY) 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) if (type == WINED3D_SBT_RECORDED || type == WINED3D_SBT_PRIMARY)
return WINED3D_OK; 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)); memset(&stateblock->stateblock_state, 0, sizeof(stateblock->stateblock_state));
stateblock->stateblock_state.light_state = &stateblock->light_state; stateblock->stateblock_state.light_state = &stateblock->light_state;
wined3d_stateblock_state_init(&stateblock->stateblock_state, stateblock->device, WINED3D_STATE_INIT_DEFAULT); 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) 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]); 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, void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
struct wined3d_stateblock *stateblock) 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); 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. */ if (device->adapter->d3d_info.ffp_hlsl)
wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, NULL); {
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) if (changed->ffp_ps_settings && !state->ps)
{ {
/* Force invalidation of the pixel shader. */ if (device->adapter->d3d_info.ffp_hlsl)
wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_PIXEL, NULL); {
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)); 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)); memset(settings, 0, sizeof(*settings));
if (si->position_transformed) if (vdecl->position_transformed)
{ {
settings->transformed = 1; settings->transformed = 1;
settings->point_size = state->primitive_type == WINED3D_PT_POINTLIST; 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"); TRACE("Forcing all constant buffers to be write-mappable.\n");
wined3d_settings.cb_access_map_w = TRUE; 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 ); if (appkey) RegCloseKey( appkey );

View file

@ -242,6 +242,7 @@ struct wined3d_d3d_info
uint32_t fences : 1; uint32_t fences : 1;
uint32_t persistent_map : 1; uint32_t persistent_map : 1;
uint32_t gpu_push_constants : 1; uint32_t gpu_push_constants : 1;
uint32_t ffp_hlsl : 1;
enum wined3d_feature_level feature_level; enum wined3d_feature_level feature_level;
DWORD multisample_draw_location; DWORD multisample_draw_location;
@ -475,7 +476,6 @@ struct wined3d_settings
char *logo; char *logo;
unsigned int multisample_textures; unsigned int multisample_textures;
unsigned int sample_count; unsigned int sample_count;
BOOL check_float_constants;
unsigned int strict_shader_math; unsigned int strict_shader_math;
unsigned int max_sm_vs; unsigned int max_sm_vs;
unsigned int max_sm_hs; unsigned int max_sm_hs;
@ -485,7 +485,9 @@ struct wined3d_settings
unsigned int max_sm_cs; unsigned int max_sm_cs;
enum wined3d_renderer renderer; enum wined3d_renderer renderer;
enum wined3d_shader_backend shader_backend; 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; extern struct wined3d_settings wined3d_settings;
@ -2048,10 +2050,11 @@ void context_state_fb(struct wined3d_context *context,
struct wined3d_light_constants struct wined3d_light_constants
{ {
/* Padding is needed for the HLSL backend. */
struct wined3d_color diffuse, specular, ambient; struct wined3d_color diffuse, specular, ambient;
struct wined3d_vec4 position, direction; struct wined3d_vec4 position, direction;
float range, falloff, cos_half_theta, cos_half_phi; 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_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); 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; extern const struct wined3d_parent_ops wined3d_null_parent_ops;
void wined3d_ffp_get_fs_settings(const struct wined3d_state *state, 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_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, 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); 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 struct wined3d_ffp_point_constants
{ {
float scale_const, scale_linear, scale_quad; float scale_const, scale_linear, scale_quad;
float padding; /* For the HLSL backend. */
} point; } point;
struct wined3d_material material; struct wined3d_material material;
float padding[3]; /* For the HLSL backend. */
struct wined3d_ffp_light_constants struct wined3d_ffp_light_constants
{ {
struct wined3d_color ambient; struct wined3d_color ambient;
@ -2983,6 +3000,7 @@ struct wined3d_device
struct list shaders; /* a linked list to track shaders (pixel and vertex) */ struct list shaders; /* a linked list to track shaders (pixel and vertex) */
struct wine_rb_tree so_descs; struct wine_rb_tree so_descs;
struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states; 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 */ /* Render Target Support */
struct wined3d_rendertarget_view *auto_depth_stencil_view; struct wined3d_rendertarget_view *auto_depth_stencil_view;
@ -4206,7 +4224,9 @@ struct wined3d_shader
unsigned int functionLength; unsigned int functionLength;
void *byte_code; void *byte_code;
unsigned int byte_code_size; 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; enum vkd3d_shader_source_type source_type;
const struct wined3d_shader_frontend *frontend; const struct wined3d_shader_frontend *frontend;
void *frontend_data; void *frontend_data;
@ -4244,6 +4264,11 @@ struct wined3d_shader
} u; } 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, enum wined3d_shader_resource_type pixelshader_get_resource_type(const struct wined3d_shader_reg_maps *reg_maps,
unsigned int resource_idx, DWORD tex_types); unsigned int resource_idx, DWORD tex_types);
void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, 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); 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) static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg)
{ {
switch (reg->type) switch (reg->type)