The first 4 patches of a 12-patch series. The remaining 8 can be browsed here:
https://gitlab.winehq.org/zfigura/wine/-/commits/dxvaup
ending in "d3d11/tests: Extend NV12 tests."
From: Elizabeth Figura zfigura@codeweavers.com
Some 2-plane formats are already supported by GL using the "height-scale" mechanism. This introduces support for true 2-plane formats, as exposed by Direct3D 10+, which can be bound as shader views by selecting individual planes.
The mechanism uses an attribute WINED3D_FORMAT_ATTR_PLANAR, which needs special handling for blits (and uploads and downloads). This commit introduces that attribute and implements basic handling for maps and uploads. --- dlls/wined3d/cs.c | 38 ++++++++++++++++++++++++---- dlls/wined3d/device.c | 7 ++++++ dlls/wined3d/texture.c | 6 +++++ dlls/wined3d/utils.c | 45 ++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 +++ 5 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 905ee06e1e1..9bac7afdba2 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -2779,8 +2779,29 @@ void wined3d_device_context_emit_update_sub_resource(struct wined3d_device_conte
if (context->ops->map_upload_bo(context, resource, sub_resource_idx, &map_desc, box, WINED3D_MAP_WRITE)) { - wined3d_format_copy_data(resource->format, data, row_pitch, slice_pitch, map_desc.data, map_desc.row_pitch, - map_desc.slice_pitch, box->right - box->left, box->bottom - box->top, box->back - box->front); + const struct wined3d_format *format = resource->format; + + if (format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + unsigned int uv_height = format->uv_height; + unsigned int uv_width = format->uv_width; + const struct wined3d_format *plane_format; + + plane_format = wined3d_get_format(context->device->adapter, format->plane_formats[0], 0); + wined3d_format_copy_data(plane_format, data, row_pitch, slice_pitch, map_desc.data, map_desc.row_pitch, + map_desc.slice_pitch, box->right - box->left, box->bottom - box->top, box->back - box->front); + plane_format = wined3d_get_format(context->device->adapter, format->plane_formats[1], 0); + wined3d_format_copy_data(plane_format, (const uint8_t *)data + (row_pitch * (box->bottom - box->top)), + row_pitch * 2 / uv_width, slice_pitch * 2 / uv_width / uv_height, + (uint8_t *)map_desc.data + map_desc.slice_pitch, + map_desc.row_pitch * 2 / uv_width, map_desc.slice_pitch * 2 / uv_width / uv_height, + (box->right - box->left) / uv_width, (box->bottom - box->top) / uv_height, box->back - box->front); + } + else + { + wined3d_format_copy_data(format, data, row_pitch, slice_pitch, map_desc.data, map_desc.row_pitch, + map_desc.slice_pitch, box->right - box->left, box->bottom - box->top, box->back - box->front); + } context->ops->unmap_upload_bo(context, resource, sub_resource_idx, &dummy_box, &bo); wined3d_device_context_upload_bo(context, resource, sub_resource_idx, box, &bo, map_desc.row_pitch, map_desc.slice_pitch); @@ -3074,9 +3095,16 @@ static void get_map_pitch(const struct wined3d_format *format, const struct wine
wined3d_format_calculate_pitch(format, 1, width, height, &map_desc->row_pitch, &map_desc->slice_pitch);
- *size = (depth - 1) * map_desc->slice_pitch - + ((height - 1) / format->block_height) * map_desc->row_pitch - + ((width + format->block_width - 1) / format->block_width) * format->block_byte_count; + if (format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + *size = wined3d_format_calculate_size(format, 1, width, height, 1); + } + else + { + *size = (depth - 1) * map_desc->slice_pitch + + ((height - 1) / format->block_height) * map_desc->row_pitch + + ((width + format->block_width - 1) / format->block_width) * format->block_byte_count; + } }
static bool wined3d_cs_map_upload_bo(struct wined3d_device_context *context, struct wined3d_resource *resource, diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 503b377662a..19489db3ca9 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4567,6 +4567,7 @@ HRESULT CDECL wined3d_device_context_map(struct wined3d_device_context *context, struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags) { + const struct wined3d_format *format = resource->format; struct wined3d_sub_resource_desc desc; struct wined3d_box b; HRESULT hr; @@ -4616,6 +4617,12 @@ HRESULT CDECL wined3d_device_context_map(struct wined3d_device_context *context,
wined3d_device_context_lock(context); hr = wined3d_device_context_emit_map(context, resource, sub_resource_idx, map_desc, box, flags); + if (format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + unsigned int height = box->bottom - box->top; + map_desc->slice_pitch = map_desc->row_pitch * height + + (map_desc->row_pitch * 2 / format->uv_width * height / format->uv_height); + } wined3d_device_context_unlock(context); return hr; } diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 01ab11369ff..c0d7898fc5d 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -6648,6 +6648,12 @@ static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wine TRACE("Format conversion not supported.\n"); return false; } + + if ((src_format->attrs | dst_format->attrs) & WINED3D_FORMAT_ATTR_PLANAR) + { + TRACE("Planar format conversion is not supported.\n"); + return false; + } }
if (wined3d_resource_get_sample_count(dst_resource) > 1) diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index f4036eed726..60f25e2059f 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -694,6 +694,33 @@ static const struct wined3d_format_block_info format_block_info[] = {WINED3DFMT_R9G9B9E5_SHAREDEXP, 1, 1, 4}, };
+static const struct +{ + enum wined3d_format_id id; + /* Note that all planar formats supported by Direct3D 10/11 are 2-plane + * formats. The documentation does not include any 3-plane formats. + * Moreover, Direct3D 10/11 identifies planes by their format (e.g. R8 or + * R8G8), which in practice means planes are identified by their component + * count, which can only work for formats that pack U and V into the same + * plane. + * + * We assume, in various places, that all formats with + * WINED3D_FORMAT_ATTR_PLANAR are 2-plane formats, with a Y plane followed + * by a UV plane, and that each component has the same number of bytes per + * sample. All planar formats supported by Direct3D 10/11 follow these + * restrictions. + * + * Direct3D 9 does support YV12, a 3-plane format, but it can only be used + * for blitting, not texturing. + */ + enum wined3d_format_id plane_formats[2]; + unsigned int uv_width, uv_height; +} +format_plane_info[] = +{ + {WINED3DFMT_NV12, {WINED3DFMT_R8_UINT, WINED3DFMT_R8G8_UINT}, 2, 2}, +}; + struct wined3d_format_vertex_info { enum wined3d_format_id id; @@ -2223,6 +2250,20 @@ static BOOL init_srgb_formats(struct wined3d_adapter *adapter) return TRUE; }
+static void init_format_plane_info(struct wined3d_adapter *adapter) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(format_plane_info); ++i) + { + struct wined3d_format *format = get_format_internal(adapter, format_plane_info[i].id); + + format->attrs |= WINED3D_FORMAT_ATTR_PLANAR; + format->plane_formats[0] = format_plane_info[i].plane_formats[0]; + format->plane_formats[1] = format_plane_info[i].plane_formats[1]; + format->uv_width = format_plane_info[i].uv_width; + format->uv_height = format_plane_info[i].uv_height; + } +} + static GLenum wined3d_gl_type_to_enum(enum wined3d_gl_resource_type type) { switch (type) @@ -4123,6 +4164,7 @@ static BOOL wined3d_adapter_init_format_info(struct wined3d_adapter *adapter, si goto fail; if (!init_srgb_formats(adapter)) goto fail; + init_format_plane_info(adapter);
return TRUE;
@@ -4529,6 +4571,9 @@ UINT wined3d_format_calculate_size(const struct wined3d_format *format, UINT ali
wined3d_format_calculate_pitch(format, alignment, width, height, &row_pitch, &slice_pitch);
+ if (format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + return row_pitch * height + (row_pitch * 2 / format->uv_width * height / format->uv_height); + return slice_pitch * depth; }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7f482ebc203..11493197d05 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4478,6 +4478,7 @@ extern enum wined3d_format_id pixelformat_for_depth(DWORD depth); #define WINED3D_FORMAT_ATTR_HEIGHT_SCALE 0x00000200 #define WINED3D_FORMAT_ATTR_MAPPABLE 0x00000400 #define WINED3D_FORMAT_ATTR_CAST_TO_BLOCK 0x00000800 +#define WINED3D_FORMAT_ATTR_PLANAR 0x00001000
/* Pixel format capabilities */ #define WINED3D_FORMAT_CAP_POSTPIXELSHADER_BLENDING 0x00000001 @@ -4546,6 +4547,9 @@ struct wined3d_format UINT block_height; UINT block_byte_count;
+ enum wined3d_format_id plane_formats[2]; + unsigned int uv_width, uv_height; + enum wined3d_ffp_emit_idx emit_idx;
UINT conv_byte_count;
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/texture.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index c0d7898fc5d..b26b1221e7a 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -3702,6 +3702,12 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc TRACE("Creating an oversized (%ux%u) surface.\n", desc->width, desc->height); }
+ if ((format->attrs & WINED3D_FORMAT_ATTR_PLANAR) && ((desc->width & 1) || (desc->height & 1))) + { + WARN("Attempt to create a planar texture with unaligned size %ux%u.\n", desc->width, desc->height); + return WINED3DERR_INVALIDCALL; + } + for (i = 0; i < layer_count; ++i) { for (j = 0; j < level_count; ++j)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/device.c | 6 ++++++ dlls/wined3d/resource.c | 14 +++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 19489db3ca9..9c0a6344229 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4403,6 +4403,12 @@ void CDECL wined3d_device_context_update_sub_resource(struct wined3d_device_cont WARN("Invalid box %s specified.\n", debug_box(box)); return; } + else if ((resource->format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + && ((box->left & 1) || (box->right & 1) || (box->top & 1) || (box->bottom & 1))) + { + WARN("Invalid box %s for planar resource.\n", debug_box(box)); + return; + }
wined3d_device_context_lock(context); wined3d_device_context_emit_update_sub_resource(context, resource, diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c index fcfe05db835..2b02424633a 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c @@ -502,14 +502,22 @@ HRESULT wined3d_resource_check_box_dimensions(struct wined3d_resource *resource, return WINEDDERR_INVALIDRECT; }
- if (resource->format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) + if (resource->format_attrs & (WINED3D_FORMAT_ATTR_BLOCKS | WINED3D_FORMAT_ATTR_PLANAR)) { /* This assumes power of two block sizes, but NPOT block sizes would * be silly anyway. * * This also assumes that the format's block depth is 1. */ - width_mask = format->block_width - 1; - height_mask = format->block_height - 1; + if (resource->format_attrs & WINED3D_FORMAT_ATTR_BLOCKS) + { + width_mask = format->block_width - 1; + height_mask = format->block_height - 1; + } + else + { + width_mask = format->uv_width - 1; + height_mask = format->uv_height - 1; + }
if ((box->left & width_mask) || (box->top & height_mask) || (box->right & width_mask && box->right != desc.width)
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/wined3d/view.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c index c72e5044d04..522f19a8e71 100644 --- a/dlls/wined3d/view.c +++ b/dlls/wined3d/view.c @@ -81,11 +81,28 @@ static GLenum get_texture_view_target(const struct wined3d_gl_info *gl_info, return texture_gl->target; }
+static bool find_format_plane_idx(const struct wined3d_format *resource_format, + const struct wined3d_format *plane_format, unsigned int *plane_idx) +{ + if (plane_format->id == resource_format->plane_formats[0]) + { + *plane_idx = 0; + return true; + } + if (plane_format->id == resource_format->plane_formats[1]) + { + *plane_idx = 1; + return true; + } + return false; +} + static const struct wined3d_format *validate_resource_view(const struct wined3d_view_desc *desc, struct wined3d_resource *resource, BOOL mip_slice, BOOL allow_srgb_toggle) { const struct wined3d_adapter *adapter = resource->device->adapter; const struct wined3d_format *format; + unsigned int plane_idx;
format = wined3d_get_format(adapter, desc->format_id, resource->bind_flags); if (resource->type == WINED3D_RTYPE_BUFFER && (desc->flags & WINED3D_VIEW_BUFFER_RAW)) @@ -138,7 +155,16 @@ static const struct wined3d_format *validate_resource_view(const struct wined3d_ struct wined3d_texture *texture = texture_from_resource(resource); unsigned int depth_or_layer_count;
- if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format) + if (resource->format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + if (!find_format_plane_idx(resource->format, format, &plane_idx)) + { + WARN("Invalid view format %s for planar format %s.\n", + debug_d3dformat(format->id), debug_d3dformat(resource->format->id)); + return NULL; + } + } + else if (resource->format->id != format->id && !wined3d_format_is_typeless(resource->format) && (!allow_srgb_toggle || !wined3d_formats_are_srgb_variants(resource->format->id, format->id))) { WARN("Trying to create incompatible view for non typeless format %s.\n", @@ -176,6 +202,12 @@ static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target view_format_gl = wined3d_format_gl(view_format); view->target = view_target;
+ if (texture_gl->t.resource.format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + FIXME("Planar views are not implemented for OpenGL.\n"); + return; + } + context = context_acquire(texture_gl->t.resource.device, NULL, 0); context_gl = wined3d_context_gl(context); gl_info = context_gl->gl_info; @@ -820,6 +852,13 @@ static VkImageView wined3d_view_vk_create_vk_image_view(struct wined3d_context_v if (view_format_vk->f.green_size) create_info.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; } + else if (resource->format->attrs & WINED3D_FORMAT_ATTR_PLANAR) + { + unsigned int plane_idx = 0; + + find_format_plane_idx(resource->format, &view_format_vk->f, &plane_idx); + create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << plane_idx; + } else { create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
This merge request was approved by Jan Sikorski.