gstreamer/sys/d3d11/gstd3d11format.c
Seungha Yang 6c3311a39e d3d11: Refactor d3d11 memory and dxgi format usage
* Create staging texture only when the CPU access is requested.
Note that we should avoid the CPU access to d3d11 memory as mush as possible.
Incoming d3d11upload and d3d11download will take this GPU memory upload/download.

* Upload/Download texture memory from/to staging only if it needed, similar to
GstGL PBO implementation.

* Define more dxgi formats for future usage (e.g., color conversion, dxva2 decoder).
Because I420_* formats are not supported formats by dxgi, each plane should
be handled likewise GstGL separately, but NV12/P10 formats might be supported ones.
So we decide the number of d3d11memory per GstBuffer for video memory depending on
OS version and dxgi format. For instance, if NV12 is supported by OS,
only one d3d11memory with DXGI_FORMAT_NV12 texture can be allocated by this commit.
One use case of such texture is DXVA. In case DXVA decoder, it might need to produce decoded data
to one DXGI_FORMAT_NV12 instead of seperate Y and UV planes.
Such behavior will be controlled via configuration of GstD3D11BufferPool and
default configuration is separate resources per plane.
2019-12-05 02:29:18 +00:00

307 lines
8.5 KiB
C

/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstd3d11format.h"
#include "gstd3d11utils.h"
#include "gstd3d11device.h"
#ifndef GST_DISABLE_GST_DEBUG
#define GST_CAT_DEFAULT ensure_debug_category()
static GstDebugCategory *
ensure_debug_category (void)
{
static gsize cat_gonce = 0;
if (g_once_init_enter (&cat_gonce)) {
gsize cat_done;
cat_done = (gsize) _gst_debug_category_new ("d3d11format", 0,
"Direct3D11 Format");
g_once_init_leave (&cat_gonce, cat_done);
}
return (GstDebugCategory *) cat_gonce;
}
#else
#define ensure_debug_category() /* NOOP */
#endif /* GST_DISABLE_GST_DEBUG */
/* Following formats were introduced since Windows 8
* DXGI_FORMAT_AYUV
* DXGI_FORMAT_NV12
* DXGI_FORMAT_P010
* ...
*/
static const GstD3D11Format legacy_d3d11_formats[] = {
/* RGB formats */
{GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM,
{DXGI_FORMAT_B8G8R8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM,
{DXGI_FORMAT_R10G10B10A2_UNORM,}},
/* YUV packed */
{GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
/* YUV semi-planner */
{GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}},
{GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}},
/* YUV planner */
{GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}},
{GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}},
/* LAST */
{GST_VIDEO_FORMAT_UNKNOWN,},
};
static const GstD3D11Format d3d11_formats[] = {
/* RGB formats */
{GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM,
{DXGI_FORMAT_B8G8R8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM,
{DXGI_FORMAT_R10G10B10A2_UNORM,}},
/* YUV packed */
{GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_AYUV,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
/* YUV semi-planner */
{GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_NV12,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}},
{GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_P010,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}},
/* YUV planner */
{GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}},
{GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}},
/* LAST */
{GST_VIDEO_FORMAT_UNKNOWN,},
};
static GstD3D11Format *
get_supported_d3d11_formats (void)
{
static gsize format_once = 0;
static GstD3D11Format *supported_d3d11_formats = NULL;
if (g_once_init_enter (&format_once)) {
if (gst_d3d11_is_windows_8_or_greater ())
supported_d3d11_formats = (GstD3D11Format *) d3d11_formats;
else
supported_d3d11_formats = (GstD3D11Format *) legacy_d3d11_formats;
g_once_init_leave (&format_once, 1);
}
return supported_d3d11_formats;
}
GstVideoFormat
gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format)
{
gint i;
GstD3D11Format *format_list;
if (format == DXGI_FORMAT_UNKNOWN)
return GST_VIDEO_FORMAT_UNKNOWN;
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
if (format_list[i].dxgi_format == format)
return format_list[i].format;
}
return GST_VIDEO_FORMAT_UNKNOWN;
}
guint
gst_d3d11_dxgi_format_n_planes (DXGI_FORMAT format)
{
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16G16_UNORM:
return 1;
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
return 2;
default:
break;
}
return 0;
}
gboolean
gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format, guint width, guint height,
guint pitch, gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
{
g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16G16_UNORM:
offset[0] = 0;
stride[0] = pitch;
*size = pitch * height;
break;
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
offset[0] = 0;
stride[0] = pitch;
offset[1] = offset[0] + stride[0] * height;
stride[1] = pitch;
*size = offset[1] + stride[1] * GST_ROUND_UP_2 (height / 2);
break;
default:
return FALSE;
}
GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT
" (dxgi format:%d, %dx%d, Pitch %d)",
*size, format, width, height, pitch);
return TRUE;
}
const GstD3D11Format *
gst_d3d11_format_from_gst (GstVideoFormat format)
{
gint i;
GstD3D11Format *format_list;
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
if (format_list[i].format == format)
return &format_list[i];
}
return NULL;
}
typedef struct
{
GstCaps *caps;
D3D11_FORMAT_SUPPORT flags;
} SupportCapsData;
static void
gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
SupportCapsData * data)
{
ID3D11Device *d3d11_device;
HRESULT hr;
gint i;
GValue v_list = G_VALUE_INIT;
GstCaps *supported_caps;
GstD3D11Format *format_list;
d3d11_device = gst_d3d11_device_get_device_handle (device);
g_value_init (&v_list, GST_TYPE_LIST);
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
UINT format_support = 0;
GstVideoFormat format;
if (format_list[i].dxgi_format == DXGI_FORMAT_UNKNOWN)
continue;
format = format_list[i].format;
hr = ID3D11Device_CheckFormatSupport (d3d11_device,
format_list[i].dxgi_format, &format_support);
if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) {
GValue v_str = G_VALUE_INIT;
g_value_init (&v_str, G_TYPE_STRING);
GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x",
gst_video_format_to_string (format), data->flags);
g_value_set_string (&v_str, gst_video_format_to_string (format));
gst_value_list_append_and_take_value (&v_list, &v_str);
}
}
supported_caps = gst_caps_new_simple ("video/x-raw",
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
gst_caps_set_value (supported_caps, "format", &v_list);
g_value_unset (&v_list);
data->caps = supported_caps;
}
/**
* gst_d3d11_device_get_supported_caps:
* @device: a #GstD3DDevice
* @flags: D3D11_FORMAT_SUPPORT flags
*
* Check supported format with given flags
*
* Returns: a #GstCaps representing supported format
*/
GstCaps *
gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags)
{
SupportCapsData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.caps = NULL;
data.flags = flags;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_get_supported_caps_internal, &data);
return data.caps;
}