diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index c4558e1f60d..7e24de8afb3 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1667,6 +1667,14 @@ static void device_free_depth_stencil_state(struct wine_rb_entry *entry, void *c wined3d_depth_stencil_state_decref(state); } +static void device_free_ffp_vertex_shader(struct wine_rb_entry *entry, void *context) +{ + struct wined3d_ffp_vs *vs = WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_vs, entry); + + wined3d_shader_decref(vs->shader); + free(vs); +} + static void device_free_ffp_pixel_shader(struct wine_rb_entry *entry, void *context) { struct wined3d_ffp_ps *ps = WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_ps, entry); @@ -1722,6 +1730,7 @@ void wined3d_device_uninit_3d(struct wined3d_device *device) wine_rb_destroy(&device->rasterizer_states, device_free_rasterizer_state, NULL); wine_rb_destroy(&device->blend_states, device_free_blend_state, NULL); wine_rb_destroy(&device->depth_stencil_states, device_free_depth_stencil_state, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, device_free_ffp_vertex_shader, NULL); wine_rb_destroy(&device->ffp_pixel_shaders, device_free_ffp_pixel_shader, NULL); LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry) @@ -5524,6 +5533,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined wine_rb_init(&device->rasterizer_states, wined3d_rasterizer_state_compare); wine_rb_init(&device->blend_states, wined3d_blend_state_compare); wine_rb_init(&device->depth_stencil_states, wined3d_depth_stencil_state_compare); + wine_rb_init(&device->ffp_vertex_shaders, wined3d_ffp_vertex_program_key_compare); wine_rb_init(&device->ffp_pixel_shaders, wined3d_ffp_frag_program_key_compare); if (vertex_pipeline->vp_states && fragment_pipeline->states @@ -5537,6 +5547,7 @@ HRESULT wined3d_device_init(struct wined3d_device *device, struct wined3d *wined wine_rb_destroy(&device->blend_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->so_descs, NULL, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, NULL, NULL); wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL); wined3d_decref(device->wined3d); return hr; @@ -5565,6 +5576,7 @@ err: wine_rb_destroy(&device->blend_states, NULL, NULL); wine_rb_destroy(&device->depth_stencil_states, NULL, NULL); wine_rb_destroy(&device->so_descs, NULL, NULL); + wine_rb_destroy(&device->ffp_vertex_shaders, NULL, NULL); wine_rb_destroy(&device->ffp_pixel_shaders, NULL, NULL); wined3d_decref(device->wined3d); return hr; diff --git a/dlls/wined3d/ffp_hlsl.c b/dlls/wined3d/ffp_hlsl.c index 72a8e702cad..8451be71e82 100644 --- a/dlls/wined3d/ffp_hlsl.c +++ b/dlls/wined3d/ffp_hlsl.c @@ -23,6 +23,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); +static bool ffp_hlsl_generate_vertex_shader(const struct wined3d_ffp_vs_settings *settings, + struct wined3d_string_buffer *string) +{ + FIXME("Not yet implemented.\n"); + return false; +} + static bool ffp_hlsl_generate_pixel_shader(const struct ffp_frag_settings *settings, struct wined3d_string_buffer *string) { @@ -70,6 +77,32 @@ static bool compile_hlsl_shader(const struct wined3d_string_buffer *hlsl, return true; } +bool ffp_hlsl_compile_vs(const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader_desc *shader_desc) +{ + struct wined3d_string_buffer string; + struct vkd3d_shader_code sm1; + + if (!string_buffer_init(&string)) + return false; + + if (!ffp_hlsl_generate_vertex_shader(settings, &string)) + { + string_buffer_free(&string); + return false; + } + + if (!compile_hlsl_shader(&string, &sm1, "vs_2_0")) + { + string_buffer_free(&string); + return false; + } + string_buffer_free(&string); + + shader_desc->byte_code = sm1.code; + shader_desc->byte_code_size = ~(size_t)0; + return true; +} + bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc) { struct wined3d_string_buffer string; diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 71dffd75761..e3f758f4b9d 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2436,7 +2436,7 @@ static HRESULT shader_set_function(struct wined3d_shader *shader, const struct w WARN("Wrong shader type %s.\n", debug_shader_type(reg_maps->shader_version.type)); return WINED3DERR_INVALIDCALL; } - if (!shader->is_ffp_ps + if (!shader->is_ffp_vs && !shader->is_ffp_ps && version->major > shader_max_version_from_feature_level(shader->device->cs->c.state->feature_level)) { WARN("Shader version %u not supported by this device.\n", version->major); @@ -2550,6 +2550,18 @@ static void wined3d_shader_init_object(void *object) list_add_head(&device->shaders, &shader->shader_list_entry); + if (shader->is_ffp_vs) + { + struct wined3d_ffp_vs_settings *settings = shader->byte_code; + struct wined3d_shader_desc desc; + + if (!ffp_hlsl_compile_vs(settings, &desc)) + return; + free(settings); + shader_set_function(shader, &desc, WINED3D_SHADER_TYPE_VERTEX, NULL, + device->adapter->d3d_info.limits.vs_uniform_count); + } + if (shader->is_ffp_ps) { struct ffp_frag_settings *settings = shader->byte_code; @@ -3327,6 +3339,31 @@ HRESULT CDECL wined3d_shader_create_vs(struct wined3d_device *device, const stru return WINED3D_OK; } +HRESULT wined3d_shader_create_ffp_vs(struct wined3d_device *device, + const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader **shader) +{ + struct wined3d_shader *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + shader_init(object, device, NULL, &wined3d_null_parent_ops); + object->is_ffp_vs = true; + if (!(object->byte_code = malloc(sizeof(*settings)))) + { + free(object); + return E_OUTOFMEMORY; + } + memcpy(object->byte_code, settings, sizeof(*settings)); + + wined3d_cs_init_object(device->cs, wined3d_shader_init_object, object); + + TRACE("Created FFP vertex shader %p.\n", object); + *shader = object; + + return WINED3D_OK; +} + HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device, const struct ffp_frag_settings *settings, struct wined3d_shader **shader) { diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index fa5b3867d58..8d2bfcf8f8a 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -1299,6 +1299,7 @@ void CDECL wined3d_stateblock_set_vertex_shader(struct wined3d_stateblock *state wined3d_shader_decref(stateblock->stateblock_state.vs); stateblock->stateblock_state.vs = shader; stateblock->changed.vertexShader = TRUE; + stateblock->changed.ffp_vs_settings = 1; } static void wined3d_bitmap_set_bits(uint32_t *bitmap, unsigned int start, unsigned int count) @@ -2393,6 +2394,7 @@ static void wined3d_stateblock_invalidate_initial_states(struct wined3d_stateblo memset(stateblock->changed.transform, 0xff, sizeof(stateblock->changed.transform)); stateblock->changed.modelview_matrices = 1; stateblock->changed.point_scale = 1; + stateblock->changed.ffp_vs_settings = 1; stateblock->changed.ffp_ps_settings = 1; } @@ -2911,6 +2913,40 @@ void CDECL wined3d_stateblock_apply_clear_state(struct wined3d_stateblock *state wined3d_device_set_render_state(device, WINED3D_RS_SRGBWRITEENABLE, state->rs[WINED3D_RS_SRGBWRITEENABLE]); } +static struct wined3d_shader *get_ffp_vertex_shader(struct wined3d_device *device, const struct wined3d_state *state) +{ + static const struct wined3d_stream_info dummy_stream_info; + struct wined3d_ffp_vs_settings settings; + const struct wine_rb_entry *entry; + struct wined3d_ffp_vs *vs; + + /* XXX: wined3d_ffp_get_vs_settings() only needs the stream info for the + * swizzle map, which the HLSL pipeline doesn't use (it will be computed and + * used later as part of struct vs_compile_args). + * + * This is nevertheless janky, and we'd like to get rid of it. Eventually + * once the HLSL backend is used everywhere, we can get rid of the swizzle + * map from wined3d_ffp_vs_settings. */ + wined3d_ffp_get_vs_settings(state, &dummy_stream_info, &device->adapter->d3d_info, &settings); + + if ((entry = wine_rb_get(&device->ffp_vertex_shaders, &settings))) + return WINE_RB_ENTRY_VALUE(entry, struct wined3d_ffp_vs, entry.entry)->shader; + + if (!(vs = malloc(sizeof(*vs)))) + return NULL; + + vs->entry.settings = settings; + if (FAILED(wined3d_shader_create_ffp_vs(device, &settings, &vs->shader))) + { + free(vs); + return NULL; + } + if (wine_rb_put(&device->ffp_vertex_shaders, &vs->entry.settings, &vs->entry.entry) == -1) + ERR("Failed to insert FFP vertex shader.\n"); + + return vs->shader; +} + static struct wined3d_shader *get_ffp_pixel_shader(struct wined3d_device *device, const struct wined3d_state *state) { struct ffp_frag_settings settings; @@ -3780,8 +3816,17 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, if (changed->ffp_vs_settings && !state->vs) { - /* Force invalidation of the vertex shader. */ - wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, NULL); + if (device->adapter->d3d_info.ffp_hlsl) + { + struct wined3d_shader *shader = get_ffp_vertex_shader(device, device->cs->c.state); + + wined3d_device_context_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, shader); + } + else + { + /* Force invalidation of the vertex shader. */ + wined3d_device_context_emit_set_shader(context, WINED3D_SHADER_TYPE_VERTEX, NULL); + } } if (changed->ffp_ps_settings && !state->ps) diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 71e73116935..dea43836f06 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -6448,7 +6448,7 @@ void wined3d_ffp_get_vs_settings(const struct wined3d_state *state, const struct memset(settings, 0, sizeof(*settings)); - if (si->position_transformed) + if (vdecl->position_transformed) { settings->transformed = 1; settings->point_size = state->primitive_type == WINED3D_PT_POINTLIST; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7b357218121..bb593a94fa2 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2731,6 +2731,12 @@ struct wined3d_ffp_vs_desc struct wined3d_ffp_vs_settings settings; }; +struct wined3d_ffp_vs +{ + struct wined3d_ffp_vs_desc entry; + struct wined3d_shader *shader; +}; + void wined3d_ffp_get_vs_settings(const struct wined3d_state *state, const struct wined3d_stream_info *si, const struct wined3d_d3d_info *d3d_info, struct wined3d_ffp_vs_settings *settings); @@ -2990,7 +2996,7 @@ struct wined3d_device struct list shaders; /* a linked list to track shaders (pixel and vertex) */ struct wine_rb_tree so_descs; struct wine_rb_tree samplers, rasterizer_states, blend_states, depth_stencil_states; - struct wine_rb_tree ffp_pixel_shaders; + struct wine_rb_tree ffp_vertex_shaders, ffp_pixel_shaders; /* Render Target Support */ struct wined3d_rendertarget_view *auto_depth_stencil_view; @@ -4215,6 +4221,7 @@ struct wined3d_shader void *byte_code; unsigned int byte_code_size; bool load_local_constsF; + bool is_ffp_vs; bool is_ffp_ps; enum vkd3d_shader_source_type source_type; const struct wined3d_shader_frontend *frontend; @@ -4253,6 +4260,8 @@ struct wined3d_shader } u; }; +HRESULT wined3d_shader_create_ffp_vs(struct wined3d_device *device, + const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader **shader); HRESULT wined3d_shader_create_ffp_ps(struct wined3d_device *device, const struct ffp_frag_settings *settings, struct wined3d_shader **shader); @@ -4285,6 +4294,7 @@ BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage us enum vkd3d_shader_visibility vkd3d_shader_visibility_from_wined3d(enum wined3d_shader_type shader_type); +bool ffp_hlsl_compile_vs(const struct wined3d_ffp_vs_settings *settings, struct wined3d_shader_desc *shader_desc); bool ffp_hlsl_compile_ps(const struct ffp_frag_settings *settings, struct wined3d_shader_desc *shader_desc); static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg)