mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
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.
This commit is contained in:
parent
aaac358bed
commit
1edafed827
7 changed files with 215 additions and 11 deletions
|
@ -14,6 +14,7 @@ SOURCES = \
|
|||
device.c \
|
||||
directx.c \
|
||||
ffp_gl.c \
|
||||
ffp_hlsl.c \
|
||||
gl_compat.c \
|
||||
glsl_shader.c \
|
||||
palette.c \
|
||||
|
|
|
@ -2359,6 +2359,7 @@ static void wined3d_adapter_vk_init_d3d_info(struct wined3d_adapter_vk *adapter_
|
|||
d3d_info->fences = true;
|
||||
d3d_info->persistent_map = true;
|
||||
d3d_info->gpu_push_constants = true;
|
||||
d3d_info->ffp_hlsl = true;
|
||||
|
||||
/* Like GL, Vulkan doesn't explicitly specify a filling convention and only mandates that a
|
||||
* shared edge of two adjacent triangles generate a fragment for exactly one of the triangles.
|
||||
|
|
|
@ -1667,6 +1667,14 @@ static void device_free_depth_stencil_state(struct wine_rb_entry *entry, void *c
|
|||
wined3d_depth_stencil_state_decref(state);
|
||||
}
|
||||
|
||||
static void device_free_ffp_pixel_shader(struct wine_rb_entry *entry, void *context)
|
||||
{
|
||||
struct wined3d_ffp_ps *ps = WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_ps, entry);
|
||||
|
||||
wined3d_shader_decref(ps->shader);
|
||||
free(ps);
|
||||
}
|
||||
|
||||
void wined3d_device_uninit_3d(struct wined3d_device *device)
|
||||
{
|
||||
struct wined3d_state *state = device->cs->c.state;
|
||||
|
@ -1714,6 +1722,7 @@ void wined3d_device_uninit_3d(struct wined3d_device *device)
|
|||
wine_rb_destroy(&device->rasterizer_states, device_free_rasterizer_state, NULL);
|
||||
wine_rb_destroy(&device->blend_states, device_free_blend_state, NULL);
|
||||
wine_rb_destroy(&device->depth_stencil_states, device_free_depth_stencil_state, NULL);
|
||||
wine_rb_destroy(&device->ffp_pixel_shaders, device_free_ffp_pixel_shader, NULL);
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
|
||||
{
|
||||
|
@ -5515,6 +5524,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
|
|||
wine_rb_init(&device->rasterizer_states, wined3d_rasterizer_state_compare);
|
||||
wine_rb_init(&device->blend_states, wined3d_blend_state_compare);
|
||||
wine_rb_init(&device->depth_stencil_states, wined3d_depth_stencil_state_compare);
|
||||
wine_rb_init(&device->ffp_pixel_shaders, wined3d_ffp_frag_program_key_compare);
|
||||
|
||||
if (vertex_pipeline->vp_states && fragment_pipeline->states
|
||||
&& FAILED(hr = compile_state_table(device->state_table, device->multistate_funcs,
|
||||
|
@ -5527,6 +5537,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined
|
|||
wine_rb_destroy(&device->blend_states, NULL, NULL);
|
||||
wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
|
||||
wine_rb_destroy(&device->so_descs, NULL, NULL);
|
||||
wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL);
|
||||
wined3d_decref(device->wined3d);
|
||||
return hr;
|
||||
}
|
||||
|
@ -5554,6 +5565,7 @@ err:
|
|||
wine_rb_destroy(&device->blend_states, NULL, NULL);
|
||||
wine_rb_destroy(&device->depth_stencil_states, NULL, NULL);
|
||||
wine_rb_destroy(&device->so_descs, NULL, NULL);
|
||||
wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL);
|
||||
wined3d_decref(device->wined3d);
|
||||
return hr;
|
||||
}
|
||||
|
|
97
dlls/wined3d/ffp_hlsl.c
Normal file
97
dlls/wined3d/ffp_hlsl.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Fixed-function pipeline replacement implemented using HLSL shaders
|
||||
*
|
||||
* Copyright 2022,2024 Elizabeth Figura for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "wined3d_private.h"
|
||||
#include <vkd3d_shader.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
|
||||
|
||||
static bool ffp_hlsl_generate_pixel_shader(const struct ffp_frag_settings *settings,
|
||||
struct wined3d_string_buffer *string)
|
||||
{
|
||||
FIXME("Not yet implemented.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool compile_hlsl_shader(const struct wined3d_string_buffer *hlsl,
|
||||
struct vkd3d_shader_code *sm1, const char *profile)
|
||||
{
|
||||
struct vkd3d_shader_hlsl_source_info hlsl_source_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_HLSL_SOURCE_INFO};
|
||||
struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
|
||||
char *messages;
|
||||
int ret;
|
||||
|
||||
compile_info.source.code = hlsl->buffer;
|
||||
compile_info.source.size = hlsl->content_size;
|
||||
compile_info.source_type = VKD3D_SHADER_SOURCE_HLSL;
|
||||
compile_info.target_type = VKD3D_SHADER_TARGET_D3D_BYTECODE;
|
||||
compile_info.log_level = VKD3D_SHADER_LOG_WARNING;
|
||||
|
||||
compile_info.next = &hlsl_source_info;
|
||||
hlsl_source_info.profile = profile;
|
||||
|
||||
ret = vkd3d_shader_compile(&compile_info, sm1, &messages);
|
||||
if (messages && *messages && FIXME_ON(d3d_shader))
|
||||
{
|
||||
const char *ptr, *end, *line;
|
||||
|
||||
FIXME("Shader log:\n");
|
||||
ptr = messages;
|
||||
end = ptr + strlen(ptr);
|
||||
while ((line = wined3d_get_line(&ptr, end)))
|
||||
FIXME(" %.*s", (int)(ptr - line), line);
|
||||
FIXME("\n");
|
||||
}
|
||||
vkd3d_shader_free_messages(messages);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
ERR("Failed to compile HLSL, ret %d.\n", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc)
|
||||
{
|
||||
struct wined3d_string_buffer string;
|
||||
struct vkd3d_shader_code sm1;
|
||||
|
||||
if (!string_buffer_init(&string))
|
||||
return false;
|
||||
|
||||
if (!ffp_hlsl_generate_pixel_shader(settings, &string))
|
||||
{
|
||||
string_buffer_free(&string);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compile_hlsl_shader(&string, &sm1, "ps_2_0"))
|
||||
{
|
||||
string_buffer_free(&string);
|
||||
return false;
|
||||
}
|
||||
string_buffer_free(&string);
|
||||
|
||||
shader_desc->byte_code = sm1.code;
|
||||
shader_desc->byte_code_size = ~(size_t)0;
|
||||
return true;
|
||||
}
|
|
@ -2436,7 +2436,8 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, const struct w
|
|||
WARN("Wrong shader type %s.\n", debug_shader_type(reg_maps->shader_version.type));
|
||||
return WINED3DERR_INVALIDCALL;
|
||||
}
|
||||
if (version->major > shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level))
|
||||
if (!shader->is_ffp_ps
|
||||
&& version->major > shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level))
|
||||
{
|
||||
WARN("Shader version %u not supported by this device.\n", version->major);
|
||||
return WINED3DERR_INVALIDCALL;
|
||||
|
@ -2549,6 +2550,18 @@ static void wined3d_shader_init_object(void *object)
|
|||
|
||||
list_add_head(&device->shaders, &shader->shader_list_entry);
|
||||
|
||||
if (shader->is_ffp_ps)
|
||||
{
|
||||
struct ffp_frag_settings *settings = shader->byte_code;
|
||||
struct wined3d_shader_desc desc;
|
||||
|
||||
if (!ffp_hlsl_compile_ps(settings, &desc))
|
||||
return;
|
||||
free(settings);
|
||||
shader_set_function(shader, &desc, WINED3D_SHADER_TYPE_PIXEL, NULL,
|
||||
device->adapter->d3d_info.limits.ps_uniform_count);
|
||||
}
|
||||
|
||||
device->shader_backend->shader_precompile(device->shader_priv, shader);
|
||||
}
|
||||
|
||||
|
@ -3313,3 +3326,28 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru
|
|||
|
||||
return WINED3D_OK;
|
||||
}
|
||||
|
||||
HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device,
|
||||
const struct ffp_frag_settings *settings, struct wined3d_shader **shader)
|
||||
{
|
||||
struct wined3d_shader *object;
|
||||
|
||||
if (!(object = calloc(1, sizeof(*object))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
shader_init(object, device, NULL, &wined3d_null_parent_ops);
|
||||
object->is_ffp_ps = true;
|
||||
if (!(object->byte_code = malloc(sizeof(*settings))))
|
||||
{
|
||||
free(object);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
memcpy(object->byte_code, settings, sizeof(*settings));
|
||||
|
||||
wined3d_cs_init_object(device->cs, wined3d_shader_init_object, object);
|
||||
|
||||
TRACE("Created FFP pixel shader %p.\n", object);
|
||||
*shader = object;
|
||||
|
||||
return WINED3D_OK;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright 2005 Oliver Stieber
|
||||
* Copyright 2007 Stefan Dösinger for CodeWeavers
|
||||
* Copyright 2009 Henri Verbeet for CodeWeavers
|
||||
* Copyright 2019,2020,2022 Zebediah Figura for CodeWeavers
|
||||
* Copyright 2019,2020,2022-2024 Elizabeth Figura for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -1439,6 +1439,7 @@ void CDECL wined3d_stateblock_set_pixel_shader(struct wined3d_stateblock *stateb
|
|||
wined3d_shader_decref(stateblock->stateblock_state.ps);
|
||||
stateblock->stateblock_state.ps = shader;
|
||||
stateblock->changed.pixelShader = TRUE;
|
||||
stateblock->changed.ffp_ps_settings = 1;
|
||||
}
|
||||
|
||||
HRESULT CDECL wined3d_stateblock_set_ps_consts_f(struct wined3d_stateblock *stateblock,
|
||||
|
@ -2379,10 +2380,10 @@ static void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state
|
|||
|
||||
}
|
||||
|
||||
/* FFP push constant buffers do not have a "default" state on the CS side.
|
||||
* We need to explicitly invalidate them when initializing the context or
|
||||
* resetting. */
|
||||
static void wined3d_stateblock_invalidate_push_constants(struct wined3d_stateblock *stateblock)
|
||||
/* Some states, e.g. FFP push constant buffers, do not have a "default" state
|
||||
* on the CS side. We need to explicitly invalidate them when initializing the
|
||||
* context or resetting. */
|
||||
static void wined3d_stateblock_invalidate_initial_states(struct wined3d_stateblock *stateblock)
|
||||
{
|
||||
stateblock->changed.ffp_ps_constants = 1;
|
||||
stateblock->changed.lights = 1;
|
||||
|
@ -2392,6 +2393,7 @@ static void wined3d_stateblock_invalidate_push_constants(struct wined3d_stateblo
|
|||
memset(stateblock->changed.transform, 0xff, sizeof(stateblock->changed.transform));
|
||||
stateblock->changed.modelview_matrices = 1;
|
||||
stateblock->changed.point_scale = 1;
|
||||
stateblock->changed.ffp_ps_settings = 1;
|
||||
}
|
||||
|
||||
static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const struct wined3d_stateblock *device_state,
|
||||
|
@ -2409,7 +2411,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru
|
|||
list_init(&stateblock->changed.changed_lights);
|
||||
|
||||
if (type == WINED3D_SBT_PRIMARY)
|
||||
wined3d_stateblock_invalidate_push_constants(stateblock);
|
||||
wined3d_stateblock_invalidate_initial_states(stateblock);
|
||||
|
||||
if (type == WINED3D_SBT_RECORDED || type == WINED3D_SBT_PRIMARY)
|
||||
return WINED3D_OK;
|
||||
|
@ -2486,7 +2488,7 @@ void CDECL wined3d_stateblock_reset(struct wined3d_stateblock *stateblock)
|
|||
memset(&stateblock->stateblock_state, 0, sizeof(stateblock->stateblock_state));
|
||||
stateblock->stateblock_state.light_state = &stateblock->light_state;
|
||||
wined3d_stateblock_state_init(&stateblock->stateblock_state, stateblock->device, WINED3D_STATE_INIT_DEFAULT);
|
||||
wined3d_stateblock_invalidate_push_constants(stateblock);
|
||||
wined3d_stateblock_invalidate_initial_states(stateblock);
|
||||
}
|
||||
|
||||
static void wined3d_device_set_base_vertex_index(struct wined3d_device *device, int base_index)
|
||||
|
@ -2909,6 +2911,31 @@ void CDECL wined3d_stateblock_apply_clear_state(struct wined3d_stateblock *state
|
|||
wined3d_device_set_render_state(device, WINED3D_RS_SRGBWRITEENABLE, state->rs[WINED3D_RS_SRGBWRITEENABLE]);
|
||||
}
|
||||
|
||||
static struct wined3d_shader *get_ffp_pixel_shader(struct wined3d_device *device, const struct wined3d_state *state)
|
||||
{
|
||||
struct ffp_frag_settings settings;
|
||||
const struct ffp_frag_desc *desc;
|
||||
struct wined3d_ffp_ps *ps;
|
||||
|
||||
wined3d_ffp_get_fs_settings(state, &device->adapter->d3d_info, &settings);
|
||||
|
||||
if ((desc = find_ffp_frag_shader(&device->ffp_pixel_shaders, &settings)))
|
||||
return CONTAINING_RECORD(desc, struct wined3d_ffp_ps, entry)->shader;
|
||||
|
||||
if (!(ps = malloc(sizeof(*ps))))
|
||||
return NULL;
|
||||
|
||||
ps->entry.settings = settings;
|
||||
if (FAILED(wined3d_shader_create_ffp_ps(device, &settings, &ps->shader)))
|
||||
{
|
||||
free(ps);
|
||||
return NULL;
|
||||
}
|
||||
add_ffp_frag_shader(&device->ffp_pixel_shaders, &ps->entry);
|
||||
|
||||
return ps->shader;
|
||||
}
|
||||
|
||||
void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
|
||||
struct wined3d_stateblock *stateblock)
|
||||
{
|
||||
|
@ -3746,6 +3773,11 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
|
|||
WINED3D_SHADER_CONST_FFP_PS, 0, offsetof(struct wined3d_ffp_ps_constants, color_key), &constants);
|
||||
}
|
||||
|
||||
/* XXX: We don't invalidate HLSL shaders for every field contained in
|
||||
* wined3d_ffp_vs_settings / ffp_frag_settings; only the ones that the HLSL
|
||||
* FFP pipeline cares about. The rest should eventually be removed from
|
||||
* those structs and left only in vs_compile_args / ps_compile_args. */
|
||||
|
||||
if (changed->ffp_vs_settings && !state->vs)
|
||||
{
|
||||
/* Force invalidation of the vertex shader. */
|
||||
|
@ -3753,10 +3785,19 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device,
|
|||
}
|
||||
|
||||
if (changed->ffp_ps_settings && !state->ps)
|
||||
{
|
||||
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));
|
||||
memset(&stateblock->changed, 0, sizeof(stateblock->changed));
|
||||
|
|
|
@ -242,6 +242,7 @@ struct wined3d_d3d_info
|
|||
uint32_t fences : 1;
|
||||
uint32_t persistent_map : 1;
|
||||
uint32_t gpu_push_constants : 1;
|
||||
uint32_t ffp_hlsl : 1;
|
||||
enum wined3d_feature_level feature_level;
|
||||
|
||||
DWORD multisample_draw_location;
|
||||
|
@ -2662,6 +2663,12 @@ struct ffp_frag_desc
|
|||
int wined3d_ffp_frag_program_key_compare(const void *key, const struct wine_rb_entry *entry);
|
||||
int wined3d_ffp_vertex_program_key_compare(const void *key, const struct wine_rb_entry *entry);
|
||||
|
||||
struct wined3d_ffp_ps
|
||||
{
|
||||
struct ffp_frag_desc entry;
|
||||
struct wined3d_shader *shader;
|
||||
};
|
||||
|
||||
extern const struct wined3d_parent_ops wined3d_null_parent_ops;
|
||||
|
||||
void wined3d_ffp_get_fs_settings(const struct wined3d_state *state,
|
||||
|
@ -2983,6 +2990,7 @@ struct wined3d_device
|
|||
struct list shaders; /* a linked list to track shaders (pixel and vertex) */
|
||||
struct wine_rb_tree so_descs;
|
||||
struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states;
|
||||
struct wine_rb_tree ffp_pixel_shaders;
|
||||
|
||||
/* Render Target Support */
|
||||
struct wined3d_rendertarget_view *auto_depth_stencil_view;
|
||||
|
@ -4206,7 +4214,8 @@ struct wined3d_shader
|
|||
unsigned int functionLength;
|
||||
void *byte_code;
|
||||
unsigned int byte_code_size;
|
||||
BOOL load_local_constsF;
|
||||
bool load_local_constsF;
|
||||
bool is_ffp_ps;
|
||||
enum vkd3d_shader_source_type source_type;
|
||||
const struct wined3d_shader_frontend *frontend;
|
||||
void *frontend_data;
|
||||
|
@ -4244,6 +4253,9 @@ struct wined3d_shader
|
|||
} u;
|
||||
};
|
||||
|
||||
HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device,
|
||||
const struct ffp_frag_settings *settings, struct wined3d_shader **shader);
|
||||
|
||||
enum wined3d_shader_resource_type pixelshader_get_resource_type(const struct wined3d_shader_reg_maps *reg_maps,
|
||||
unsigned int resource_idx, DWORD tex_types);
|
||||
void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader,
|
||||
|
@ -4273,6 +4285,8 @@ BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage us
|
|||
|
||||
enum vkd3d_shader_visibility vkd3d_shader_visibility_from_wined3d(enum wined3d_shader_type shader_type);
|
||||
|
||||
bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc);
|
||||
|
||||
static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg)
|
||||
{
|
||||
switch (reg->type)
|
||||
|
|
Loading…
Reference in a new issue