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 1d8bb40cec4..aef0e9341b2 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
Signed-off-by: Stefan Dösinger stefan@codeweavers.com --- dlls/wined3d/resource.c | 6 ++++++ dlls/wined3d/texture.c | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c index fe77923f778..3b76e7ab0cf 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c @@ -632,6 +632,12 @@ void wined3d_resource_memory_colour_fill(struct wined3d_resource *resource, return; }
+ if (resource->format_flags & WINED3DFMT_FLAG_BLOCKS) + { + FIXME("Not implemented for format %s.\n", debug_d3dformat(resource->format->id)); + return; + } + w = box->right - box->left; h = box->bottom - box->top; d = box->back - box->front; 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); }
On 5/17/22 10:27, Stefan Dösinger wrote:
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
dlls/wined3d/resource.c | 6 ++++++ dlls/wined3d/texture.c | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-)
The subject here isn't as specific as it could be. Note that there's basically two patches to this, anyway:
* avoid clearing block formats,
* use wined3d_resource_memory_colour_fill() to clear sysmem in wined3d_texture_load_location().
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c index fe77923f778..3b76e7ab0cf 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c @@ -632,6 +632,12 @@ void wined3d_resource_memory_colour_fill(struct wined3d_resource *resource, return; }
- if (resource->format_flags & WINED3DFMT_FLAG_BLOCKS)
- {
FIXME("Not implemented for format %s.\n", debug_d3dformat(resource->format->id));
return;
- }
w = box->right - box->left; h = box->bottom - box->top; d = box->back - box->front;
Isn't this already covered in wined3d_format_convert_from_float(), though? And if we do implement clearing block formats, we'd want to implement it there.
If we want to avoid touching sysmem in that case, assuming we even care, I'd advocate for returning bool from that function instead.
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
Version 2: Take the new wined3d_texture_vk_clear into account. --- dlls/wined3d/context_vk.c | 41 +++++++++++++++++--- dlls/wined3d/texture.c | 70 ++++++++++++++++++---------------- dlls/wined3d/utils.c | 19 +++++++++ dlls/wined3d/wined3d_private.h | 11 ++++++ 4 files changed, 104 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..a523043cf24 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); @@ -5281,16 +5293,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 +5340,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 +6658,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 +6677,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 +6701,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 +6722,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 aef0e9341b2..f497fd334a1 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,
On 5/17/22 10:27, Stefan Dösinger wrote:
Signed-off-by: Stefan Dösinger stefan@codeweavers.com
Version 2: Take the new wined3d_texture_vk_clear into account.
dlls/wined3d/context_vk.c | 41 +++++++++++++++++--- dlls/wined3d/texture.c | 70 ++++++++++++++++++---------------- dlls/wined3d/utils.c | 19 +++++++++ dlls/wined3d/wined3d_private.h | 11 ++++++ 4 files changed, 104 insertions(+), 37 deletions(-)
This seems to be missing changes to wined3d_texture_gl_clear(), isn't it?
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 0f45d5c844e..a523043cf24 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;
}
It feels awkward to me that we're storing depth/stencil separately in the sub-resource structure, but collapsing it together here. Could we pass, say, a "union wined3d_clear_value" to wined3d_resource_memory_colour_fill() [and wined3d_format_convert_from_float()]?
Am 20.05.2022 um 00:32 schrieb Zebediah Figura zfigura@codeweavers.com:
On 5/17/22 10:27, Stefan Dösinger wrote:
Signed-off-by: Stefan Dösinger stefan@codeweavers.com Version 2: Take the new wined3d_texture_vk_clear into account.
dlls/wined3d/context_vk.c | 41 +++++++++++++++++--- dlls/wined3d/texture.c | 70 ++++++++++++++++++---------------- dlls/wined3d/utils.c | 19 +++++++++ dlls/wined3d/wined3d_private.h | 11 ++++++ 4 files changed, 104 insertions(+), 37 deletions(-)
This seems to be missing changes to wined3d_texture_gl_clear(), isn't it?
Not really, because only the Vulkan codepath will set delayed clears. I could add an ERR if the color is non-zero unexpectedly in wined3d_texture_gl_clear.
It feels awkward to me that we're storing depth/stencil separately in the sub-resource structure, but collapsing it together here. Could we pass, say, a "union wined3d_clear_value" to wined3d_resource_memory_colour_fill() [and wined3d_format_convert_from_float()]?
I considered this, but it would end in the same result at the price of more flags checks in wined3d_format_convert_from_float (check DEPTH / STENCIL flags to read the converted values either from color.rg or depth/stencil. I didn't feel like an actual improvement, but that's not a strong opinion on my end.
I kept it separately for passing to Vulkan because that's how the Vulkan API works.
In practice it is fairly academic because the highest stencil bitcount we'll have is 8 bits, and floats have a large enough mantissa to store them without loss. Depth might be a 32 bit integer, but both Vulkan and GL decided for us to pass those as float unconditionally.
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); }