From: Elizabeth Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56205 --- dlls/ddraw/surface.c | 41 ++++----------- dlls/ddraw/tests/ddraw1.c | 2 +- dlls/ddraw/tests/ddraw2.c | 2 +- dlls/ddraw/tests/ddraw4.c | 2 +- dlls/ddraw/tests/ddraw7.c | 2 +- dlls/wined3d/cs.c | 92 ++++++++++++++++++++++++++++++++++ dlls/wined3d/surface.c | 2 +- dlls/wined3d/wined3d.spec | 1 + dlls/wined3d/wined3d_private.h | 3 ++ include/wine/wined3d.h | 3 ++ 10 files changed, 113 insertions(+), 37 deletions(-)
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 8cdaa48b753..565c38b4887 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -1531,33 +1531,6 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface2_Flip(IDirectDrawSurface2 src_impl ? &src_impl->IDirectDrawSurface_iface : NULL, flags); }
-/* Emperor: Rise of the Middle Kingdom accesses the map pointer outside of - * Lock()/Unlock(), and expects those updates to be propagated by a Blt(). - * It also blits to the surface, and color-fills it. - * - * This function is called after a color-fill that might update the GPU side. - * We need to make sure the sysmem surface is synchronized. */ -static void ddraw_surface_sync_pinned_sysmem(struct ddraw_surface *surface) -{ - RECT rect; - - if (!surface->draw_texture) - return; - - if (!(surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) - return; - - SetRect(&rect, 0, 0, surface->surface_desc.dwWidth, surface->surface_desc.dwHeight); - wined3d_device_context_blt(surface->ddraw->immediate_context, - surface->wined3d_texture, surface->sub_resource_idx, &rect, - surface->draw_texture, surface->sub_resource_idx, &rect, - WINED3D_BLT_SYNCHRONOUS, NULL, WINED3D_TEXF_POINT); - - /* The sysmem surface may be updated at any time, so we must invalidate the - * draw texture location here. */ - surface->texture_location = DDRAW_SURFACE_LOCATION_DEFAULT; -} - static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT *dst_rect, struct ddraw_surface *src_surface, const RECT *src_rect, DWORD flags, DWORD fill_colour, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter) @@ -1565,10 +1538,11 @@ static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT * struct ddraw *ddraw = dst_surface->ddraw; struct wined3d_color colour; DWORD wined3d_flags; - HRESULT hr;
if (flags & DDBLT_COLORFILL) { + unsigned int location_flags = dst_rect ? DDRAW_SURFACE_RW : DDRAW_SURFACE_WRITE; + wined3d_flags = WINED3DCLEAR_TARGET; if (!(flags & DDBLT_ASYNC)) wined3d_flags |= WINED3DCLEAR_SYNCHRONOUS; @@ -1577,12 +1551,15 @@ static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT * dst_surface->palette, fill_colour, &colour)) return DDERR_INVALIDPARAMS;
- ddraw_surface_get_draw_texture(dst_surface, dst_rect ? DDRAW_SURFACE_RW : DDRAW_SURFACE_WRITE); - hr = wined3d_device_context_clear_rendertarget_view(ddraw->immediate_context, + if (dst_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) + return wined3d_device_context_clear_sysmem_texture(ddraw->immediate_context, + ddraw_surface_get_default_texture(dst_surface, location_flags), + dst_surface->sub_resource_idx, dst_rect, wined3d_flags, &colour); + + ddraw_surface_get_draw_texture(dst_surface, location_flags); + return wined3d_device_context_clear_rendertarget_view(ddraw->immediate_context, ddraw_surface_get_rendertarget_view(dst_surface), dst_rect, wined3d_flags, &colour, 0.0f, 0); - ddraw_surface_sync_pinned_sysmem(dst_surface); - return hr; }
if (flags & DDBLT_DEPTHFILL) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 060e65a0faa..6cafd6bb762 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15744,7 +15744,7 @@ static void test_sysmem_x_channel(void) hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); colour = *(unsigned int *)surface_desc.lpSurface; - todo_wine ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); + ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); hr = IDirectDrawSurface_Unlock(surface, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr);
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index c0d4f98daeb..bc7602c85ac 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -16804,7 +16804,7 @@ static void test_sysmem_x_channel(void) hr = IDirectDrawSurface_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); colour = *(unsigned int *)surface_desc.lpSurface; - todo_wine ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); + ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); hr = IDirectDrawSurface_Unlock(surface, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr);
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index a8c4f3ab621..7184215b962 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -19879,7 +19879,7 @@ static void test_sysmem_x_channel(void) hr = IDirectDrawSurface4_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); colour = *(unsigned int *)surface_desc.lpSurface; - todo_wine ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); + ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); hr = IDirectDrawSurface4_Unlock(surface, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr);
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index 9c7be81636f..81b053b1d70 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -20315,7 +20315,7 @@ static void test_sysmem_x_channel(void) hr = IDirectDrawSurface7_Lock(surface, NULL, &surface_desc, DDLOCK_READONLY, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); colour = *(unsigned int *)surface_desc.lpSurface; - todo_wine ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); + ok(colour == 0x0000ff00, "Got colour %08x.\n", colour); hr = IDirectDrawSurface7_Unlock(surface, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr);
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 1bd4e2b4242..da903e39488 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -136,6 +136,7 @@ enum wined3d_cs_op WINED3D_CS_OP_BLT_SUB_RESOURCE, WINED3D_CS_OP_UPDATE_SUB_RESOURCE, WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION, + WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE, WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW, WINED3D_CS_OP_COPY_UAV_COUNTER, WINED3D_CS_OP_GENERATE_MIPMAPS, @@ -179,6 +180,15 @@ struct wined3d_cs_clear RECT rects[1]; };
+struct wined3d_cs_clear_sysmem_texture +{ + enum wined3d_cs_op opcode; + struct wined3d_texture *texture; + unsigned int sub_resource_idx; + struct wined3d_color color; + RECT rect; +}; + struct wined3d_cs_dispatch { enum wined3d_cs_op opcode; @@ -612,6 +622,7 @@ static const char *debug_cs_op(enum wined3d_cs_op op) WINED3D_TO_STR(WINED3D_CS_OP_BLT_SUB_RESOURCE); WINED3D_TO_STR(WINED3D_CS_OP_UPDATE_SUB_RESOURCE); WINED3D_TO_STR(WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION); + WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE); WINED3D_TO_STR(WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW); WINED3D_TO_STR(WINED3D_CS_OP_COPY_UAV_COUNTER); WINED3D_TO_STR(WINED3D_CS_OP_GENERATE_MIPMAPS); @@ -868,6 +879,70 @@ void wined3d_device_context_emit_clear_rendertarget_view(struct wined3d_device_c wined3d_device_context_finish(context, WINED3D_CS_QUEUE_DEFAULT); }
+static void wined3d_cs_exec_clear_sysmem_texture(struct wined3d_cs *cs, const void *data) +{ + const struct wined3d_cs_clear_sysmem_texture *op = data; + struct wined3d_box box; + + box.left = op->rect.left; + box.right = op->rect.right; + box.top = op->rect.top; + box.bottom = op->rect.bottom; + box.front = 0; + box.back = 1; + cpu_blitter_clear_texture(op->texture, op->sub_resource_idx, &box, &op->color); +} + +HRESULT CDECL wined3d_device_context_clear_sysmem_texture(struct wined3d_device_context *context, + struct wined3d_texture *texture, unsigned int sub_resource_idx, const RECT *rect, + unsigned int flags, const struct wined3d_color *color) +{ + struct wined3d_cs_clear_sysmem_texture *op; + + TRACE("context %p, texture %p, sub_resource_idx %u, rect %s, flags %#x, color %s.\n", + context, texture, sub_resource_idx, wine_dbgstr_rect(rect), flags, debug_color(color)); + + if (rect) + { + struct wined3d_box b = {rect->left, rect->top, rect->right, rect->bottom, 0, 1}; + HRESULT hr; + + if (FAILED(hr = wined3d_resource_check_box_dimensions(&texture->resource, sub_resource_idx, &b))) + return hr; + } + + wined3d_device_context_lock(context); + + op = wined3d_device_context_require_space(context, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); + op->opcode = WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE; + op->texture = texture; + op->sub_resource_idx = sub_resource_idx; + op->color = *color; + + if (rect) + { + op->rect = *rect; + } + else + { + unsigned int level_idx = sub_resource_idx % texture->level_count; + + op->rect.left = 0; + op->rect.top = 0; + op->rect.right = wined3d_texture_get_level_width(texture, level_idx); + op->rect.bottom = wined3d_texture_get_level_height(texture, level_idx); + } + + wined3d_device_context_reference_resource(context, &texture->resource); + + wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT); + if (flags & WINED3DCLEAR_SYNCHRONOUS) + wined3d_device_context_finish(context, WINED3D_CS_QUEUE_DEFAULT); + + wined3d_device_context_unlock(context); + return S_OK; +} + static void reference_shader_resources(struct wined3d_device_context *context, unsigned int shader_mask) { const struct wined3d_state *state = context->state; @@ -2917,6 +2992,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void /* WINED3D_CS_OP_BLT_SUB_RESOURCE */ wined3d_cs_exec_blt_sub_resource, /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE */ wined3d_cs_exec_update_sub_resource, /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION */ wined3d_cs_exec_add_dirty_texture_region, + /* WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE */ wined3d_cs_exec_clear_sysmem_texture, /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view, /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter, /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, @@ -3738,6 +3814,14 @@ static void wined3d_cs_packet_decref_objects(const struct wined3d_cs_packet *pac break; }
+ case WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE: + { + struct wined3d_cs_clear_sysmem_texture *op = (struct wined3d_cs_clear_sysmem_texture *)packet->data; + + wined3d_texture_decref(op->texture); + break; + } + case WINED3D_CS_OP_DISPATCH: { struct wined3d_cs_dispatch *op = (struct wined3d_cs_dispatch *)packet->data; @@ -3979,6 +4063,14 @@ static void wined3d_cs_packet_incref_objects(struct wined3d_cs_packet *packet) break; }
+ case WINED3D_CS_OP_CLEAR_SYSMEM_TEXTURE: + { + struct wined3d_cs_clear_sysmem_texture *op = (struct wined3d_cs_clear_sysmem_texture *)packet->data; + + wined3d_texture_incref(op->texture); + break; + } + case WINED3D_CS_OP_DISPATCH: { struct wined3d_cs_dispatch *op = (struct wined3d_cs_dispatch *)packet->data; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 028dc4e94b2..4ad1e65fafb 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1125,7 +1125,7 @@ release: return hr; }
-static void cpu_blitter_clear_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx, +void cpu_blitter_clear_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx, const struct wined3d_box *box, const struct wined3d_color *colour) { struct wined3d_device *device = texture->resource.device; diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 16c7624eb9c..3052b47e172 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -91,6 +91,7 @@
@ cdecl wined3d_device_context_blt(ptr ptr long ptr ptr long ptr long ptr long) @ cdecl wined3d_device_context_clear_rendertarget_view(ptr ptr ptr long ptr float long) +@ cdecl wined3d_device_context_clear_sysmem_texture(ptr ptr long ptr long ptr) @ cdecl wined3d_device_context_clear_uav_float(ptr ptr ptr) @ cdecl wined3d_device_context_clear_uav_uint(ptr ptr ptr) @ cdecl wined3d_device_context_copy_resource(ptr ptr ptr) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 39a4aa5da9c..c98f8ef09a5 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2035,6 +2035,9 @@ struct wined3d_blitter_ops struct wined3d_blitter *wined3d_cpu_blitter_create(void); void wined3d_vk_blitter_create(struct wined3d_blitter **next);
+void cpu_blitter_clear_texture(struct wined3d_texture *texture, unsigned int sub_resource_idx, + const struct wined3d_box *box, const struct wined3d_color *colour); + BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other);
void context_invalidate_compute_state(struct wined3d_context *context, DWORD state_id); diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index b9ae23bac16..0f8b5e75081 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2431,6 +2431,9 @@ HRESULT __cdecl wined3d_device_context_blt(struct wined3d_device_context *contex struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, const RECT *dst_rect, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, const RECT *src_rect, unsigned int flags, const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter); +HRESULT __cdecl wined3d_device_context_clear_sysmem_texture(struct wined3d_device_context *context, + struct wined3d_texture *texture, unsigned int sub_resource_idx, const RECT *rect, + unsigned int flags, const struct wined3d_color *color); HRESULT __cdecl wined3d_device_context_clear_rendertarget_view(struct wined3d_device_context *context, struct wined3d_rendertarget_view *view, const RECT *rect, unsigned int flags, const struct wined3d_color *color, float depth, unsigned int stencil);