Avoid resolving source texture before the blit due to format conversion in that case.
Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- v5: Fixed cleanup of temporary images --- dlls/d3d10core/tests/d3d10core.c | 12 +-- dlls/d3d11/tests/d3d11.c | 12 +-- dlls/wined3d/surface.c | 12 ++- dlls/wined3d/texture.c | 131 +++++++++++++++++++++++++++++-- 4 files changed, 148 insertions(+), 19 deletions(-)
diff --git a/dlls/d3d10core/tests/d3d10core.c b/dlls/d3d10core/tests/d3d10core.c index e0cb40de89b..927d79d90e9 100644 --- a/dlls/d3d10core/tests/d3d10core.c +++ b/dlls/d3d10core/tests/d3d10core.c @@ -18065,22 +18065,22 @@ static void test_multisample_resolve(void) DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf},
{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_TYPELESS, @@ -18117,12 +18117,12 @@ static void test_multisample_resolve(void) DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index c499aa5f75b..bf8837ab52c 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -30330,22 +30330,22 @@ static void test_multisample_resolve(void) DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf},
{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_TYPELESS, @@ -30382,12 +30382,12 @@ static void test_multisample_resolve(void) DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &green, 0xffbcffbc, TRUE}, + &green, 0xffbcffbc}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, - &color, 0xfff1e1cf, TRUE}, + &color, 0xfff1e1cf}, {DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 4a438f048d6..c5d7a7d9d55 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1482,12 +1482,12 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource; struct wined3d_device *device = dst_texture->resource.device; struct wined3d_swapchain *src_swapchain, *dst_swapchain; + BOOL scale, convert, resolve, resolve_typeless = FALSE; const struct wined3d_format *resolve_format = NULL; const struct wined3d_color_key *colour_key = NULL; DWORD src_location, dst_location, valid_locations; struct wined3d_context *context; enum wined3d_blit_op blit_op; - BOOL scale, convert, resolve; RECT src_rect, dst_rect; bool src_ds, dst_ds;
@@ -1566,6 +1566,14 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ || src_box->bottom - src_box->top != dst_box->bottom - dst_box->top; convert = src_texture->resource.format->id != dst_texture->resource.format->id; resolve = src_texture->resource.multisample_type != dst_texture->resource.multisample_type; + if (resolve) + { + resolve_typeless = (wined3d_format_is_typeless(src_texture->resource.format) + || wined3d_format_is_typeless(dst_texture->resource.format)) + && (src_texture->resource.format->typeless_id == dst_texture->resource.format->typeless_id); + if (resolve_typeless && !resolve_format) + WARN("Resolve format for typeless resolve not specified.\n"); + }
dst_ds = dst_texture->resource.format->depth_size || dst_texture->resource.format->stencil_size; src_ds = src_texture->resource.format->depth_size || src_texture->resource.format->stencil_size; @@ -1704,7 +1712,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
context = context_acquire(device, dst_texture, dst_sub_resource_idx);
- if (src_texture->resource.multisample_type != WINED3D_MULTISAMPLE_NONE + if (src_texture->resource.multisample_type != WINED3D_MULTISAMPLE_NONE && !resolve_typeless && ((scale && !context->d3d_info->scaled_resolve) || convert || !wined3d_is_colour_blit(blit_op))) src_location = WINED3D_LOCATION_RB_RESOLVED; diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 43920944544..5c85b2c91bb 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -322,11 +322,12 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect, const struct wined3d_format *resolve_format) { - struct wined3d_texture *required_texture, *restore_texture; + struct wined3d_texture *required_texture, *restore_texture = NULL, *dst_save_texture = dst_texture; + unsigned int restore_idx, dst_save_sub_resource_idx = dst_sub_resource_idx; + struct wined3d_texture *src_staging_texture = NULL; const struct wined3d_gl_info *gl_info; struct wined3d_context_gl *context_gl; - unsigned int restore_idx; - bool scaled_resolve; + bool resolve, scaled_resolve; GLenum gl_filter; GLenum buffer; RECT s, d; @@ -337,7 +338,8 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect), resolve_format);
- scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location) + resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location); + scaled_resolve = resolve && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top) || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
@@ -346,6 +348,106 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont else gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
+ if (resolve) + { + GLint resolve_internal, src_internal, dst_internal; + enum wined3d_format_id resolve_format_id; + + src_internal = wined3d_gl_get_internal_format(&src_texture->resource, + wined3d_format_gl(src_texture->resource.format), src_location == WINED3D_LOCATION_TEXTURE_SRGB); + dst_internal = wined3d_gl_get_internal_format(&dst_texture->resource, + wined3d_format_gl(dst_texture->resource.format), dst_location == WINED3D_LOCATION_TEXTURE_SRGB); + + if (resolve_format) + { + resolve_internal = wined3d_format_gl(resolve_format)->internal; + resolve_format_id = resolve_format->id; + } + else if (!wined3d_format_is_typeless(src_texture->resource.format)) + { + resolve_internal = src_internal; + resolve_format_id = src_texture->resource.format->id; + } + else + { + resolve_internal = dst_internal; + resolve_format_id = dst_texture->resource.format->id; + } + + /* In case of typeless resolve the texture type may not match the resolve type. + * To handle that, allocate intermediate texture(s) to resolve from/to. + * A possible performance improvement would be to resolve using a shader instead. */ + if (src_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned src_level; + HRESULT hr; + + src_level = src_sub_resource_idx % src_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = src_texture->resource.multisample_type; + desc.multisample_quality = src_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_PRIVATE; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(src_texture, src_level); + desc.height = wined3d_texture_get_level_height(src_texture, src_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &src_staging_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#x.\n", hr); + goto done; + } + + if (src_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the source of a typeless resolve."); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + src_texture, src_sub_resource_idx, src_location, src_rect, + src_staging_texture, 0, src_location, src_rect, + NULL, WINED3D_TEXF_NONE, NULL); + + src_texture = src_staging_texture; + src_sub_resource_idx = 0; + } + + if (dst_internal != resolve_internal) + { + struct wined3d_resource_desc desc; + unsigned dst_level; + HRESULT hr; + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + desc.resource_type = WINED3D_RTYPE_TEXTURE_2D; + desc.format = resolve_format_id; + desc.multisample_type = dst_texture->resource.multisample_type; + desc.multisample_quality = dst_texture->resource.multisample_quality; + desc.usage = WINED3DUSAGE_PRIVATE; + desc.bind_flags = 0; + desc.access = WINED3D_RESOURCE_ACCESS_GPU; + desc.width = wined3d_texture_get_level_width(dst_texture, dst_level); + desc.height = wined3d_texture_get_level_height(dst_texture, dst_level); + desc.depth = 1; + desc.size = 0; + + hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, + &dst_texture); + if (FAILED(hr)) + { + ERR("Failed to create staging texture, hr %#x.\n", hr); + goto done; + } + + wined3d_texture_load_location(dst_texture, 0, context, dst_location); + dst_sub_resource_idx = 0; + } + } + /* Make sure the locations are up-to-date. Loading the destination * surface isn't required if the entire surface is overwritten. (And is * in fact harmful if we're being called by surface_load_location() with @@ -379,7 +481,8 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont { context_release(context); WARN("Invalid context, skipping blit.\n"); - return; + restore_texture = NULL; + goto done; }
gl_info = context_gl->gl_info; @@ -437,6 +540,24 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture) gl_info->gl_ops.gl.p_glFlush();
+ if (dst_texture != dst_save_texture) + { + if (dst_location == WINED3D_LOCATION_DRAWABLE) + FIXME("WINED3D_LOCATION_DRAWABLE not supported for the destination of a typeless resolve."); + + device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context, + dst_texture, 0, dst_location, dst_rect, + dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect, + NULL, WINED3D_TEXF_NONE, NULL); + } + +done: + if (dst_texture != dst_save_texture) + wined3d_texture_decref(dst_texture); + + if (src_staging_texture) + wined3d_texture_decref(src_staging_texture); + if (restore_texture) context_restore(context, restore_texture, restore_idx); }