[PATCH 3/6] wined3d: Implement copy operation for textures.

Józef Kucia jkucia at codeweavers.com
Fri Mar 17 06:57:54 CDT 2017


Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

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




More information about the wine-patches mailing list