gstreamer/sys/d3d11/gstd3d11format.c
Seungha Yang 0788492461 d3d11: Use GRecMutex to protect immediate context and dxgi API call
In some cases, rendering and dxgi (e.g., swapchain) APIs should be
called from window message pump thread, but current design (dedicated d3d11 thread)
make it impossible. To solve it, change concurrency model to locking based one
from single-thread model.
2019-12-20 19:21:03 +09:00

271 lines
7.8 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"
#include "gstd3d11memory.h"
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_format_debug);
#define GST_CAT_DEFAULT gst_d3d11_format_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;
}
/**
* 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)
{
ID3D11Device *d3d11_device;
HRESULT hr;
gint i;
GValue v_list = G_VALUE_INIT;
GstCaps *supported_caps;
GstD3D11Format *format_list;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
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 & flags) == 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), 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);
gst_caps_set_features_simple (supported_caps,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY));
return supported_caps;
}