Signed-off-by: Stefan Dösinger stefan@codeweavers.com
-- v2: d3d9/tests: Extend color_fill_test. wined3d: Store clear colors in subresources (v3). wined3d: Prepare sysmem LOCATION_CLEARED handling for non-zero colors (v2). wined3d: Add a memory_colour_fill path for clearing the entire level to zero.
From: Stefan Dösinger stefan@codeweavers.com
Signed-off-by: Stefan Dösinger stefan@codeweavers.com --- dlls/wined3d/resource.c | 11 ++++++++++- dlls/wined3d/surface.c | 6 +++++- dlls/wined3d/wined3d_private.h | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c index 7fefd516908..fe77923f778 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c @@ -616,13 +616,22 @@ void *resource_offset_map_pointer(struct wined3d_resource *resource, unsigned in
void wined3d_resource_memory_colour_fill(struct wined3d_resource *resource, const struct wined3d_map_desc *map, const struct wined3d_color *colour, - const struct wined3d_box *box) + const struct wined3d_box *box, bool full_subresource) { const struct wined3d_format *format = resource->format; unsigned int w, h, d, x, y, z, bpp; uint8_t *dst, *dst2; uint32_t c[4];
+ /* Fast and simple path for setting everything to zero. The C library's memset is + * more sophisticated than our code below. Also this works for block formats, which + * we still need to zero-initialize for newly created resources. */ + if (full_subresource && !colour->r && !colour->g && !colour->b && !colour->a) + { + memset(map->data, 0, map->slice_pitch * box->back); + return; + } + w = box->right - box->left; h = box->bottom - box->top; d = box->back - box->front; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 29bdef9844f..96aacb78e77 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1181,8 +1181,10 @@ static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view, struct wined3d_context *context; struct wined3d_texture *texture; struct wined3d_bo_address data; + struct wined3d_box level_box; struct wined3d_map_desc map; struct wined3d_range range; + bool full_subresource; unsigned int level; DWORD map_binding;
@@ -1208,6 +1210,8 @@ static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view,
texture = texture_from_resource(view->resource); level = view->sub_resource_idx % texture->level_count; + wined3d_texture_get_level_box(texture_from_resource(view->resource), level, &level_box); + full_subresource = !memcmp(box, &level_box, sizeof(*box));
map_binding = texture->resource.map_binding; if (!wined3d_texture_load_location(texture, view->sub_resource_idx, context, map_binding)) @@ -1220,7 +1224,7 @@ static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view, range.offset = 0; range.size = texture->sub_resources[view->sub_resource_idx].size;
- wined3d_resource_memory_colour_fill(view->resource, &map, colour, box); + wined3d_resource_memory_colour_fill(view->resource, &map, colour, box, full_subresource);
wined3d_context_unmap_bo_address(context, &data, 1, &range); context_release(context); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 00d2cfea8e4..cd88e70c9ce 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4428,7 +4428,7 @@ BOOL wined3d_resource_prepare_sysmem(struct wined3d_resource *resource) DECLSPEC void wined3d_resource_update_draw_binding(struct wined3d_resource *resource) DECLSPEC_HIDDEN; void wined3d_resource_memory_colour_fill(struct wined3d_resource *resource, const struct wined3d_map_desc *map, const struct wined3d_color *colour, - const struct wined3d_box *box) DECLSPEC_HIDDEN; + const struct wined3d_box *box, bool full_subresource) DECLSPEC_HIDDEN;
/* Tests show that the start address of resources is 32 byte aligned */ #define RESOURCE_ALIGNMENT 16
From: Stefan Dösinger stefan@codeweavers.com
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
---
Version 2: Remove the FIXME from wined3d_resource_memory_colour_fill. If it accidentally gets called to fill a blocky format with a non-zero color, wined3d_format_convert_from_float will write a FIXME anyhow. --- dlls/wined3d/texture.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 595baf07788..0f45d5c844e 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -815,7 +815,6 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture, { struct wined3d_bo_address source, destination; struct wined3d_range range; - void *map_ptr;
if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, location)) return FALSE; @@ -824,12 +823,21 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture, range.size = texture->sub_resources[sub_resource_idx].size; if (current & WINED3D_LOCATION_CLEARED) { + static const struct wined3d_color black; + unsigned int level_idx = sub_resource_idx % texture->level_count; + struct wined3d_map_desc map; + struct wined3d_box box; + + wined3d_texture_get_pitch(texture, level_idx, &map.row_pitch, &map.slice_pitch); if (destination.buffer_object) - map_ptr = wined3d_context_map_bo_address(context, &destination, range.size, + map.data = wined3d_context_map_bo_address(context, &destination, range.size, WINED3D_MAP_WRITE | WINED3D_MAP_DISCARD); else - map_ptr = destination.addr; - memset(map_ptr, 0, range.size); + map.data = destination.addr; + + wined3d_texture_get_level_box(texture, level_idx, &box); + wined3d_resource_memory_colour_fill(&texture->resource, &map, &black, &box, true); + if (destination.buffer_object) wined3d_context_unmap_bo_address(context, &destination, 1, &range); }
From: Stefan Dösinger stefan@codeweavers.com
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
---
Version 3: Add an ERR check in the GL path. Version 2: Take the new wined3d_texture_vk_clear into account.
@Zeb: I can't write a FIXME in wined3d_buffer_load_location for non-zero colors because buffers don't (yet) store clear colors. The proper place to write a FIXME would be when delaying a buffer clear, but right now we'll never enter the clear code for buffers. (wined3d_device_clear is <= d3d9 only and wined3d_device_context_clear_rendertarget_view has a FIXME("Not implemented for buffer resources.\n"); --- dlls/wined3d/context_vk.c | 41 +++++++++++++-- dlls/wined3d/texture.c | 91 ++++++++++++++++++++++------------ dlls/wined3d/utils.c | 19 +++++++ dlls/wined3d/wined3d_private.h | 11 ++++ 4 files changed, 125 insertions(+), 37 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index aa3b45d54fd..c257b5f3c86 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -2509,7 +2509,7 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont VkCommandBuffer vk_command_buffer, const struct wined3d_state *state, const struct wined3d_vk_info *vk_info) { struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); - static const VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1]; + VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1]; VkImageView vk_views[WINED3D_MAX_RENDER_TARGETS + 1]; unsigned int fb_width, fb_height, fb_layer_count; struct wined3d_rendertarget_view_vk *rtv_vk; @@ -2518,6 +2518,7 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont struct wined3d_query_vk *query_vk; VkRenderPassBeginInfo begin_info; unsigned int attachment_count, i; + struct wined3d_texture *texture; VkFramebufferCreateInfo fb_desc; VkResult vr;
@@ -2549,10 +2550,25 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont if (view->layer_count < fb_layer_count) fb_layer_count = view->layer_count; context_vk->rt_count = i + 1; - ++attachment_count;
if (wined3d_rendertarget_view_get_locations(view) & WINED3D_LOCATION_CLEARED) - begin_info.clearValueCount = attachment_count; + { + VkClearColorValue *c = &clear_values[attachment_count].color; + + if (view->resource->type == WINED3D_RTYPE_BUFFER) + { + c->int32[0] = c->int32[1] = c->int32[2] = c->int32[3] = 0; + } + else + { + texture = texture_from_resource(view->resource); + wined3d_format_colour_to_vk(view->format, + &texture->sub_resources[view->sub_resource_idx].clear_value.colour, c); + } + + begin_info.clearValueCount = attachment_count + 1; + } + ++attachment_count; }
if ((view = state->fb.depth_stencil)) @@ -2568,10 +2584,25 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont fb_height = view->height; if (view->layer_count < fb_layer_count) fb_layer_count = view->layer_count; - ++attachment_count;
if (wined3d_rendertarget_view_get_locations(view) & WINED3D_LOCATION_CLEARED) - begin_info.clearValueCount = attachment_count; + { + VkClearDepthStencilValue *c = &clear_values[attachment_count].depthStencil; + + if (view->resource->type == WINED3D_RTYPE_BUFFER) + { + c->depth = 0.0f; + c->stencil = 0; + } + else + { + texture = texture_from_resource(view->resource); + c->depth = texture->sub_resources[view->sub_resource_idx].clear_value.depth; + c->stencil = texture->sub_resources[view->sub_resource_idx].clear_value.stencil; + } + begin_info.clearValueCount = attachment_count + 1; + } + ++attachment_count; }
if (!(context_vk->vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, &state->fb, diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 0f45d5c844e..7dfedd65ecc 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -823,10 +823,22 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture, range.size = texture->sub_resources[sub_resource_idx].size; if (current & WINED3D_LOCATION_CLEARED) { - static const struct wined3d_color black; unsigned int level_idx = sub_resource_idx % texture->level_count; struct wined3d_map_desc map; struct wined3d_box box; + struct wined3d_color c; + + if (texture->resource.format->flags[WINED3D_GL_RES_TYPE_TEX_2D] + & WINED3DFMT_FLAG_DEPTH_STENCIL) + { + c.r = texture->sub_resources[sub_resource_idx].clear_value.depth; + c.g = texture->sub_resources[sub_resource_idx].clear_value.stencil; + c.b = c.a = 0.0f; + } + else + { + c = texture->sub_resources[sub_resource_idx].clear_value.colour; + }
wined3d_texture_get_pitch(texture, level_idx, &map.row_pitch, &map.slice_pitch); if (destination.buffer_object) @@ -836,7 +848,7 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture, map.data = destination.addr;
wined3d_texture_get_level_box(texture, level_idx, &box); - wined3d_resource_memory_colour_fill(&texture->resource, &map, &black, &box, true); + wined3d_resource_memory_colour_fill(&texture->resource, &map, &c, &box, true);
if (destination.buffer_object) wined3d_context_unmap_bo_address(context, &destination, 1, &range); @@ -3370,6 +3382,27 @@ static bool wined3d_texture_gl_clear(struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info = context_gl->gl_info; struct wined3d_bo_address addr;
+ /* The code that delays clears is Vulkan-specific, so here we should only + * encounter WINED3D_LOCATION_CLEARED on newly created resources and thus + * a zero clear value. */ + if (!format->depth_size && !format->stencil_size) + { + if (sub_resource->clear_value.colour.r || sub_resource->clear_value.colour.g + || sub_resource->clear_value.colour.b || sub_resource->clear_value.colour.a) + { + ERR("Unexpected color clear value r=%08e, g=%08e, b=%08e, a=%08e.\n", + sub_resource->clear_value.colour.r, sub_resource->clear_value.colour.g, + sub_resource->clear_value.colour.b, sub_resource->clear_value.colour.a); + } + } + else + { + if (format->depth_size && sub_resource->clear_value.depth) + ERR("Unexpected depth clear value %08e.\n", sub_resource->clear_value.depth); + if (format->stencil_size && sub_resource->clear_value.stencil) + ERR("Unexpected stencil clear value %x.\n", sub_resource->clear_value.stencil); + } + if (use_ffp_clear(texture, location)) { GLbitfield clear_mask = 0; @@ -5281,16 +5314,20 @@ static bool wined3d_texture_vk_clear(struct wined3d_texture_vk *texture_vk, struct wined3d_context_vk *context_vk = wined3d_context_vk(context); const struct wined3d_format *format = texture_vk->t.resource.format; const struct wined3d_vk_info *vk_info = context_vk->vk_info; - static const VkClearDepthStencilValue depth_value; - static const VkClearColorValue colour_value; + VkClearDepthStencilValue depth_value; VkCommandBuffer vk_command_buffer; VkImageSubresourceRange vk_range; + VkClearColorValue colour_value; VkImageAspectFlags aspect_mask; VkImage vk_image;
if (texture_vk->t.resource.format_flags & WINED3DFMT_FLAG_COMPRESSED) { struct wined3d_bo_address addr; + struct wined3d_color *c = &sub_resource->clear_value.colour; + + if (c->r || c->g || c-> b || c->a) + FIXME("Compressed resource %p is cleared to a non-zero color.\n", &texture_vk->t);
if (!wined3d_texture_prepare_location(&texture_vk->t, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM)) return false; @@ -5324,11 +5361,18 @@ static bool wined3d_texture_vk_clear(struct wined3d_texture_vk *texture_vk, texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_image, &vk_range);
if (format->depth_size || format->stencil_size) + { + depth_value.depth = sub_resource->clear_value.depth; + depth_value.stencil = sub_resource->clear_value.stencil; VK_CALL(vkCmdClearDepthStencilImage(vk_command_buffer, vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depth_value, 1, &vk_range)); + } else + { + wined3d_format_colour_to_vk(format, &sub_resource->clear_value.colour, &colour_value); VK_CALL(vkCmdClearColorImage(vk_command_buffer, vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colour_value, 1, &vk_range)); + }
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, @@ -6635,18 +6679,12 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk
if (is_full_clear(view, draw_rect, clear_rects)) { - if (!colour->r && !colour->g && !colour->b && !colour->a) - { - wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); - wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); - delay_count++; - continue; - } - else - { - TRACE_(d3d_perf)("non-zero clear\n"); - wined3d_rendertarget_view_prepare_location(view, &context_vk->c, view->resource->draw_binding); - } + struct wined3d_texture *texture = texture_from_resource(view->resource); + wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); + wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); + texture->sub_resources[view->sub_resource_idx].clear_value.colour = *colour; + delay_count++; + continue; } else { @@ -6660,20 +6698,7 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_RENDER_TARGET);
c = &clear_values[attachment_count].color; - if (view->format_flags & WINED3DFMT_FLAG_INTEGER) - { - c->int32[0] = colour->r; - c->int32[1] = colour->g; - c->int32[2] = colour->b; - c->int32[3] = colour->a; - } - else - { - c->float32[0] = colour->r; - c->float32[1] = colour->g; - c->float32[2] = colour->b; - c->float32[3] = colour->a; - } + wined3d_format_colour_to_vk(view->format, colour, c);
if (view->layer_count > layer_count) layer_count = view->layer_count; @@ -6697,8 +6722,7 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk if (view->format->stencil_size) full_flags |= WINED3DCLEAR_STENCIL;
- if (!is_full_clear(view, draw_rect, clear_rects) - || depth || stencil || (flags & full_flags) != full_flags) + if (!is_full_clear(view, draw_rect, clear_rects) || (flags & full_flags) != full_flags) { wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); @@ -6719,6 +6743,9 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk } else { + struct wined3d_texture *texture = texture_from_resource(view->resource); + texture->sub_resources[view->sub_resource_idx].clear_value.depth = depth; + texture->sub_resources[view->sub_resource_idx].clear_value.stencil = stencil; wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED); wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED); flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 088a904ffeb..3680bcf6425 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -6008,6 +6008,25 @@ uint32_t wined3d_format_pack(const struct wined3d_format *format, const struct w return p; }
+void wined3d_format_colour_to_vk(const struct wined3d_format *format, const struct wined3d_color *c, + VkClearColorValue *retval) +{ + if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_INTEGER) + { + retval->int32[0] = c->r; + retval->int32[1] = c->g; + retval->int32[2] = c->b; + retval->int32[3] = c->a; + } + else + { + retval->float32[0] = c->r; + retval->float32[1] = c->g; + retval->float32[2] = c->b; + retval->float32[3] = c->a; + } +} + /* Note: It's the caller's responsibility to ensure values can be expressed * in the requested format. UNORM formats for example can only express values * in the range 0.0f -> 1.0f. diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index cd88e70c9ce..835a1346d03 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4559,6 +4559,15 @@ struct wined3d_texture uint32_t map_flags; DWORD locations; struct wined3d_bo *bo; + union + { + struct wined3d_color colour; + struct + { + float depth; + unsigned int stencil; + }; + } clear_value;
void *user_memory; } *sub_resources; @@ -6211,6 +6220,8 @@ void wined3d_format_calculate_pitch(const struct wined3d_format *format, unsigne unsigned int width, unsigned int height, unsigned int *row_pitch, unsigned int *slice_pitch) DECLSPEC_HIDDEN; UINT wined3d_format_calculate_size(const struct wined3d_format *format, UINT alignment, UINT width, UINT height, UINT depth) DECLSPEC_HIDDEN; +void wined3d_format_colour_to_vk(const struct wined3d_format *format, const struct wined3d_color *c, + VkClearColorValue *retval) DECLSPEC_HIDDEN; void wined3d_format_convert_from_float(const struct wined3d_format *format, const struct wined3d_color *color, void *ret) DECLSPEC_HIDDEN; void wined3d_format_copy_data(const struct wined3d_format *format, const uint8_t *src,
From: Stefan Dösinger stefan@codeweavers.com
So it covers more formats and provokes the clear-to-sysmem path with the Vulkan renderer.
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
---
Yes, the d3d9 support in the Vulkan renderer is good enough for this test to run and produce useful results for map-after-clear. --- dlls/d3d9/tests/visual.c | 132 +++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 26 deletions(-)
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c index f20f1ecb369..70114c0ed85 100644 --- a/dlls/d3d9/tests/visual.c +++ b/dlls/d3d9/tests/visual.c @@ -1548,10 +1548,10 @@ done:
static void color_fill_test(void) { + unsigned int fill_a, expected_a; IDirect3DSurface9 *surface; IDirect3DTexture9 *texture; D3DCOLOR fill_color, color; - DWORD fill_a, expected_a; IDirect3DDevice9 *device; IDirect3D9 *d3d; ULONG refcount; @@ -1580,20 +1580,39 @@ static void color_fill_test(void) { CHECK_FILL_VALUE = 0x1, BLOCKS = 0x2, + FLOAT_VALUES = 0x4, } flags; - DWORD fill_value; + unsigned int fill_i[4]; + float fill_f[4]; } formats[] = { - {D3DFMT_A8R8G8B8, "D3DFMT_A8R8G8B8", CHECK_FILL_VALUE, 0xdeadbeef}, + {D3DFMT_A8R8G8B8, "D3DFMT_A8R8G8B8", CHECK_FILL_VALUE, + {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}}, /* D3DFMT_X8R8G8B8 either set X = A or X = 0, depending on the driver. */ - {D3DFMT_R5G6B5, "D3DFMT_R5G6B5", CHECK_FILL_VALUE, 0xadfdadfd}, - {D3DFMT_G16R16, "D3DFMT_G16R16", CHECK_FILL_VALUE, 0xbebeadad}, + {D3DFMT_R5G6B5, "D3DFMT_R5G6B5", CHECK_FILL_VALUE, + {0xadfdadfd, 0xadfdadfd, 0xadfdadfd, 0xadfdadfd}}, + {D3DFMT_G16R16, "D3DFMT_G16R16", CHECK_FILL_VALUE, + {0xbebeadad, 0xbebeadad, 0xbebeadad, 0xbebeadad}}, + {D3DFMT_A16B16G16R16, "D3DFMT_A16B16G16R16", CHECK_FILL_VALUE, + {0xbebeadad, 0xdedeefef, 0xbebeadad, 0xdedeefef}}, /* Real hardware reliably fills the surface with the blue channel but * the testbot fills it with 0x00. Wine incorrectly uses the alpha * channel. Don't bother checking the result because P8 surfaces are * essentially useless in d3d9. */ - {D3DFMT_P8, "D3DFMT_P8", 0, 0xefefefef}, + {D3DFMT_P8, "D3DFMT_P8", 0, + {0xefefefef, 0xefefefef, 0xefefefef, 0xefefefef}}, + /* Float formats. */ + {D3DFMT_R32F, "D3DFMT_R32F", CHECK_FILL_VALUE | FLOAT_VALUES, + {0, 0, 0, 0}, {0xad / 255.0f, 0xad / 255.0f, 0xad / 255.0f, 0xad / 255.0f}}, + {D3DFMT_A32B32G32R32F, "D3DFMT_A32B32G32R32F", CHECK_FILL_VALUE | FLOAT_VALUES, + {0, 0, 0, 0}, {0xad / 255.0f, 0xbe / 255.0f, 0xef / 255.0f, 0xde / 255.0f}}, + {D3DFMT_R16F, "D3DFMT_R16F", CHECK_FILL_VALUE, + {0x396d396d, 0x396d396d, 0x396d396d, 0x396d396d}}, + {D3DFMT_G16R16F, "D3DFMT_G16R16F", CHECK_FILL_VALUE, + {0x39f5396d, 0x39f5396d, 0x39f5396d, 0x39f5396d}}, + {D3DFMT_A16B16G16R16F, "D3DFMT_A16B16G16R16F", CHECK_FILL_VALUE, + {0x39f5396d, 0x3af63b7f, 0x39f5396d, 0x3af63b7f}}, /* Windows drivers produce different results for these formats. * No driver produces a YUV value that matches the input RGB * value, and no driver produces a proper DXT compression block. @@ -1603,17 +1622,16 @@ static void color_fill_test(void) * * The YUV tests are disabled because they produce a driver-dependent * result on Wine. - * {D3DFMT_YUY2, "D3DFMT_YUY2", BLOCKS, 0}, - * {D3DFMT_UYVY, "D3DFMT_UYVY", BLOCKS, 0}, */ - {D3DFMT_DXT1, "D3DFMT_DXT1", BLOCKS, 0x00000000}, + * {D3DFMT_YUY2, "D3DFMT_YUY2", BLOCKS}, + * {D3DFMT_UYVY, "D3DFMT_UYVY", BLOCKS}, */ + {D3DFMT_DXT1, "D3DFMT_DXT1", BLOCKS}, /* Vendor-specific formats like ATI2N are a non-issue here since they're not * supported as offscreen plain surfaces and do not support D3DUSAGE_RENDERTARGET * when created as texture. */ }; - unsigned int i; - D3DLOCKED_RECT locked_rect; - DWORD *surface_data; static const RECT rect = {4, 4, 8, 8}, rect2 = {5, 5, 7, 7}; + D3DLOCKED_RECT locked_rect; + unsigned int i, j;
window = create_window(); d3d = Direct3DCreate9(D3D_SDK_VERSION); @@ -1732,22 +1750,84 @@ static void color_fill_test(void) ok(SUCCEEDED(hr), "Failed to color fill, hr %#x, fmt=%s.\n", hr, formats[i].name); }
- if (formats[i].flags & CHECK_FILL_VALUE) + if (!(formats[i].flags & CHECK_FILL_VALUE)) { - hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, D3DLOCK_READONLY); - ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, fmt=%s.\n", hr, formats[i].name); - surface_data = locked_rect.pBits; - fill_a = (surface_data[0] & 0xff000000) >> 24; - expected_a = (formats[i].fill_value & 0xff000000) >> 24; - /* Windows drivers disagree on how to promote the 8 bit per channel - * input argument to 16 bit for D3DFMT_G16R16. */ - ok(color_match(surface_data[0], formats[i].fill_value, 2) && - compare_uint(expected_a, fill_a, 2), - "Expected clear value 0x%08x, got 0x%08x, fmt=%s.\n", - formats[i].fill_value, surface_data[0], formats[i].name); - hr = IDirect3DSurface9_UnlockRect(surface); - ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, fmt=%s.\n", hr, formats[i].name); + IDirect3DSurface9_Release(surface); + continue; + } + + hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, 0); + ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, fmt=%s.\n", hr, formats[i].name); + /* Windows drivers disagree on how to promote the 8 bit per channel + * input argument to 16 bit for D3DFMT_G16R16. */ + if (formats[i].flags & FLOAT_VALUES) + { + const struct vec4 *surface_data = locked_rect.pBits; + ok(compare_vec4(surface_data, formats[i].fill_f[0], formats[i].fill_f[1], + formats[i].fill_f[2], formats[i].fill_f[3], 1), + "Expected clear values %f %f %f %f, got %f %f %f %f, fmt=%s\n", + formats[i].fill_f[0], formats[i].fill_f[1], + formats[i].fill_f[2], formats[i].fill_f[3], + surface_data->x, surface_data->y, surface_data->z, surface_data->w, + formats[i].name); } + else + { + const unsigned int *surface_data = locked_rect.pBits; + for (j = 0; j < 4; ++j) + { + fill_a = (surface_data[j] & 0xff000000) >> 24; + expected_a = (formats[i].fill_i[j] & 0xff000000) >> 24; + ok(color_match(surface_data[j], formats[i].fill_i[j], 2) && + compare_uint(expected_a, fill_a, 2), + "Expected clear value 0x%08x, got 0x%08x, fmt=%s, j=%u.\n", + formats[i].fill_i[j], surface_data[j], formats[i].name, j); + } + } + + /* Fill the surface with something else to make sure the test below doesn't pass + * due to stale contents by accident. */ + memset(locked_rect.pBits, 0x55, locked_rect.Pitch * 32); + + hr = IDirect3DSurface9_UnlockRect(surface); + ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, fmt=%s.\n", hr, formats[i].name); + + /* Test clearing "to sysmem". Wined3d's delayed clear will perform the actual clear + * in the lock call and try to fill the sysmem buffer instead of clearing on the + * GPU and downloading it. */ + hr = IDirect3DDevice9_ColorFill(device, surface, NULL, 0xdeadbeef); + ok(SUCCEEDED(hr), "Failed to color fill, hr %#x, fmt=%s.\n", hr, formats[i].name); + hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, D3DLOCK_READONLY); + ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x, fmt=%s.\n", hr, formats[i].name); + + if (formats[i].flags & FLOAT_VALUES) + { + const struct vec4 *surface_data = locked_rect.pBits; + ok(compare_vec4(surface_data, formats[i].fill_f[0], formats[i].fill_f[1], + formats[i].fill_f[2], formats[i].fill_f[3], 1), + "Expected clear values %f %f %f %f, got %f %f %f %f, fmt=%s\n", + formats[i].fill_f[0], formats[i].fill_f[1], + formats[i].fill_f[2], formats[i].fill_f[3], + surface_data->x, surface_data->y, surface_data->z, surface_data->w, + formats[i].name); + } + else + { + const unsigned int *surface_data = locked_rect.pBits; + for (j = 0; j < 4; ++j) + { + fill_a = (surface_data[j] & 0xff000000) >> 24; + expected_a = (formats[i].fill_i[j] & 0xff000000) >> 24; + ok(color_match(surface_data[j], formats[i].fill_i[j], 2) && + compare_uint(expected_a, fill_a, 2), + "Expected clear value 0x%08x, got 0x%08x, fmt=%s, j=%u.\n", + formats[i].fill_i[j], surface_data[j], formats[i].name, j); + } + } + + + hr = IDirect3DSurface9_UnlockRect(surface); + ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x, fmt=%s.\n", hr, formats[i].name);
IDirect3DSurface9_Release(surface); }
I ran the d3d11 tests and on my machine this breaks a few of them slightly, for example, in test_clear_render_target_view_2d() I get 0xbf4d801a instead of 0xbf4c7f19 in line 15945. Not sure how big of an issue that could be. Some others look more badly broken, like test_clear_depth_stencil_view() lines 16116 and later, got 0.0.
`02f0:fixme:d3d:wined3d_format_convert_from_float Conversion for format WINED3DFMT_D32_FLOAT not implemented.` might be relevant. Let me know if you can reproduce that, if not, I'll take a closer look.
Huh, I'll have a look. The d3d11 tests were hard-crashing my system, so they weren't in my test run script. At least I figured out some more details about that crash today...
Oh never mind my excuse, that is GL only. I didn't spot the Vulkan failures because so many things fail right now. Thanks for catching them...
This merge request was approved by Zebediah Figura.