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;