[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