From: Józef Kucia Subject: [PATCH 3/6] wined3d: Implement copy operation for textures. Message-Id: <20170317115757.14800-3-jkucia@codeweavers.com> Date: Fri, 17 Mar 2017 12:57:54 +0100 In-Reply-To: <20170317115757.14800-1-jkucia@codeweavers.com> References: <20170317115757.14800-1-jkucia@codeweavers.com> Signed-off-by: Józef Kucia --- I plan to extend this function to support copying between compressed and non-compressed formats (table 4.X.1 in the ARB_copy_image spec). Another fallback might be needed as well when blitting cannot be used. --- dlls/wined3d/cs.c | 24 ++----- dlls/wined3d/device.c | 6 -- dlls/wined3d/texture.c | 141 +++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 ++ 4 files changed, 151 insertions(+), 24 deletions(-) diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index b1d9bc4..3f8b5e7 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -1756,26 +1756,14 @@ static void wined3d_cs_exec_copy_sub_resource(struct wined3d_cs *cs, const void op->src_box.right - op->src_box.left))) ERR("Failed to copy buffer.\n"); } - else if (op->dst_resource->type == WINED3D_RTYPE_TEXTURE_2D) - { - struct wined3d_texture *dst_texture, *src_texture; - struct wined3d_surface *dst_surface, *src_surface; - RECT dst_rect, src_rect; - - dst_texture = texture_from_resource(op->dst_resource); - dst_surface = dst_texture->sub_resources[op->dst_sub_resource_idx].u.surface; - src_texture = texture_from_resource(op->src_resource); - src_surface = src_texture->sub_resources[op->src_sub_resource_idx].u.surface; - SetRect(&dst_rect, op->dst_box.left, op->dst_box.top, op->dst_box.right, op->dst_box.bottom); - SetRect(&src_rect, op->src_box.left, op->src_box.top, op->src_box.right, op->src_box.bottom); - - if (FAILED(wined3d_surface_blt(dst_surface, &dst_rect, src_surface, - &src_rect, 0, NULL, WINED3D_TEXF_POINT))) - FIXME("Blit failed.\n"); - } else { - FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(op->dst_resource->type)); + struct wined3d_texture *dst_texture = texture_from_resource(op->dst_resource); + struct wined3d_texture *src_texture = texture_from_resource(op->src_resource); + + if (FAILED(wined3d_texture_copy(dst_texture, op->dst_sub_resource_idx, &op->dst_box, + src_texture, op->src_sub_resource_idx, &op->src_box))) + ERR("Failed to copy texture.\n"); } wined3d_resource_release(op->src_resource); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 0bc494e..cda9e18 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3891,12 +3891,6 @@ void CDECL wined3d_device_copy_resource(struct wined3d_device *device, return; } - if (dst_resource->type != WINED3D_RTYPE_TEXTURE_2D) - { - FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(dst_resource->type)); - return; - } - dst_texture = texture_from_resource(dst_resource); src_texture = texture_from_resource(src_resource); diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index a1aba36..e26f607 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -3071,3 +3071,144 @@ HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsign return WINED3D_OK; } + +static BOOL wined3d_texture_is_full_box(const struct wined3d_texture *texture, + unsigned int level, const struct wined3d_box *box) +{ + unsigned int w, h, d; + + w = wined3d_texture_get_level_width(texture, level); + if (box->left || abs(box->right - box->left) != w) + return FALSE; + h = wined3d_texture_get_level_height(texture, level); + if (box->top || abs(box->bottom - box->top) != h) + return FALSE; + d = wined3d_texture_get_level_depth(texture, level); + if (box->front || abs(box->back - box->front) != d) + return FALSE; + return TRUE; +} + +static BOOL wined3d_texture_use_copy_image(const struct wined3d_gl_info *gl_info, + struct wined3d_texture *dst_texture, struct wined3d_texture *src_texture) +{ + const struct wined3d_format *dst_format = dst_texture->resource.format; + const struct wined3d_format *src_format = src_texture->resource.format; + + /* Avoid invalidating the sysmem location for converted textures. */ + if ((dst_texture->flags & WINED3D_TEXTURE_CONVERTED) || dst_format->convert + || wined3d_format_get_color_key_conversion(dst_texture, TRUE)) + return FALSE; + /* Converted textures aren't supported. */ + if ((src_texture->flags & WINED3D_TEXTURE_CONVERTED) || src_format->convert + || wined3d_format_get_color_key_conversion(src_texture, TRUE)) + return FALSE; + + if (!gl_info->supported[ARB_COPY_IMAGE]) + return FALSE; + + if (gl_info->supported[ARB_TEXTURE_VIEW]) + return dst_format->gl_view_class == src_format->gl_view_class; + return dst_format->id == src_format->id; +} + +HRESULT wined3d_texture_copy(struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + const struct wined3d_box *src_box) +{ + const BOOL blit_supported = dst_texture->resource.type == WINED3D_RTYPE_TEXTURE_2D + && dst_texture->resource.format->id == src_texture->resource.format->id; + unsigned int width, height, depth, dst_level, src_level, dst_z, src_z; + struct gl_texture *src_gl_texture, *dst_gl_texture; + BOOL dst_texture_srgb, src_texture_srgb; + const struct wined3d_gl_info *gl_info; + DWORD dst_location, src_location; + struct wined3d_context *context; + struct wined3d_device *device; + BOOL copy_image_supported; + + device = dst_texture->resource.device; + gl_info = &device->adapter->gl_info; + copy_image_supported = wined3d_texture_use_copy_image(gl_info, dst_texture, src_texture); + + if (!copy_image_supported && blit_supported) + { + struct wined3d_surface *dst_surface, *src_surface; + RECT dst_rect, src_rect; + + dst_surface = dst_texture->sub_resources[dst_sub_resource_idx].u.surface; + src_surface = src_texture->sub_resources[src_sub_resource_idx].u.surface; + SetRect(&dst_rect, dst_box->left, dst_box->top, dst_box->right, dst_box->bottom); + SetRect(&src_rect, src_box->left, src_box->top, src_box->right, src_box->bottom); + + return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, &src_rect, + 0, NULL, WINED3D_TEXF_POINT); + } + + if (!copy_image_supported) + { + FIXME("Unsupported copy from texture %p to texture %p.\n", src_texture, dst_texture); + return E_NOTIMPL; + } + + context = context_acquire(device, NULL, 0); + gl_info = context->gl_info; + + dst_texture_srgb = dst_texture->flags & WINED3D_TEXTURE_IS_SRGB; + if (!needs_separate_srgb_gl_texture(context, dst_texture)) + dst_texture_srgb = FALSE; + dst_location = dst_texture_srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; + + src_location = src_texture->sub_resources[src_sub_resource_idx].locations + & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB); + if (src_location) + { + if (src_location & dst_location) + src_location = dst_location; + src_texture_srgb = src_location == WINED3D_LOCATION_TEXTURE_SRGB; + } + else + { + src_texture_srgb = src_texture->flags & WINED3D_TEXTURE_IS_SRGB; + } + if (!needs_separate_srgb_gl_texture(context, src_texture)) + src_texture_srgb = FALSE; + src_location = src_texture_srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB; + + dst_level = dst_sub_resource_idx % dst_texture->level_count; + if (dst_texture->target == GL_TEXTURE_CUBE_MAP || dst_texture->target == GL_TEXTURE_2D_ARRAY) + dst_z = dst_sub_resource_idx / dst_texture->level_count; + else + dst_z = dst_box->front; + + src_level = src_sub_resource_idx % src_texture->level_count; + if (dst_texture->target == GL_TEXTURE_CUBE_MAP || dst_texture->target == GL_TEXTURE_2D_ARRAY) + src_z = src_sub_resource_idx / src_texture->level_count; + else + src_z = src_box->front; + + if (wined3d_texture_is_full_box(dst_texture, dst_level, dst_box)) + wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location); + else + wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location); + wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location); + + width = dst_box->right - dst_box->left; + height = dst_box->bottom - dst_box->top; + depth = dst_box->back - dst_box->front; + dst_gl_texture = wined3d_texture_get_gl_texture(dst_texture, dst_texture_srgb); + src_gl_texture = wined3d_texture_get_gl_texture(src_texture, src_texture_srgb); + GL_EXTCALL(glCopyImageSubData(src_gl_texture->name, src_texture->target, src_level, + src_box->left, src_box->top, src_z, + dst_gl_texture->name, dst_texture->target, dst_level, + dst_box->left, dst_box->top, dst_z, width, height, depth)); + checkGLcall("copy image data"); + + context_release(context); + + wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location); + wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location); + + return WINED3D_OK; +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d0f7e7e..b2800a3 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2953,6 +2953,10 @@ void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN; HRESULT wined3d_texture_check_box_dimensions(const struct wined3d_texture *texture, unsigned int level, const struct wined3d_box *box) DECLSPEC_HIDDEN; +HRESULT wined3d_texture_copy(struct wined3d_texture *dst_texture, + unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, + struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, + const struct wined3d_box *src_box) DECLSPEC_HIDDEN; GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) DECLSPEC_HIDDEN; void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int sub_resource_idx, struct wined3d_bo_address *data, DWORD locations) DECLSPEC_HIDDEN; -- 2.10.2