gstreamer/sys/d3d11/gstd3d11pluginutils.c
Seungha Yang 0f7af4b143 d3d11: Move core methods to gst-libs
Move d3d11 device, memory, buffer pool and minimal method
to gst-libs so that other plugins can access d3d11 resource.
Since Direct3D is primary graphics API on Windows, we need
this infrastructure for various plugins can share GPU resource
without downloading GPU memory.
Note that this implementation is public only for -bad scope
for now.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/464>
2021-01-13 15:01:20 +00:00

1011 lines
32 KiB
C

/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
* Copyright (C) 2020 Seungha Yang <seungha@centricular.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 "gstd3d11pluginutils.h"
#include <windows.h>
#include <versionhelpers.h>
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_plugin_utils_debug);
#define GST_CAT_DEFAULT gst_d3d11_plugin_utils_debug
gboolean
gst_d3d11_is_windows_8_or_greater (void)
{
static gsize version_once = 0;
static gboolean ret = FALSE;
if (g_once_init_enter (&version_once)) {
#if (!GST_D3D11_WINAPI_ONLY_APP)
if (IsWindows8OrGreater ())
ret = TRUE;
#else
ret = TRUE;
#endif
g_once_init_leave (&version_once, 1);
}
return ret;
}
GstD3D11DeviceVendor
gst_d3d11_get_device_vendor (GstD3D11Device * device)
{
guint device_id = 0;
guint vendor_id = 0;
gchar *desc = NULL;
GstD3D11DeviceVendor vendor = GST_D3D11_DEVICE_VENDOR_UNKNOWN;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id,
"description", &desc, NULL);
switch (vendor_id) {
case 0:
if (device_id == 0 && desc && g_strrstr (desc, "SraKmd"))
vendor = GST_D3D11_DEVICE_VENDOR_XBOX;
break;
case 0x1002:
case 0x1022:
vendor = GST_D3D11_DEVICE_VENDOR_AMD;
break;
case 0x8086:
vendor = GST_D3D11_DEVICE_VENDOR_INTEL;
break;
case 0x10de:
vendor = GST_D3D11_DEVICE_VENDOR_NVIDIA;
break;
case 0x4d4f4351:
vendor = GST_D3D11_DEVICE_VENDOR_QUALCOMM;
break;
default:
break;
}
g_free (desc);
return vendor;
}
#if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
gboolean
gst_d3d11_hdr_meta_data_to_dxgi (GstVideoMasteringDisplayInfo * minfo,
GstVideoContentLightLevel * cll, DXGI_HDR_METADATA_HDR10 * dxgi_hdr10)
{
g_return_val_if_fail (dxgi_hdr10 != NULL, FALSE);
memset (dxgi_hdr10, 0, sizeof (DXGI_HDR_METADATA_HDR10));
if (minfo) {
dxgi_hdr10->RedPrimary[0] = minfo->display_primaries[0].x;
dxgi_hdr10->RedPrimary[1] = minfo->display_primaries[0].y;
dxgi_hdr10->GreenPrimary[0] = minfo->display_primaries[1].x;
dxgi_hdr10->GreenPrimary[1] = minfo->display_primaries[1].y;
dxgi_hdr10->BluePrimary[0] = minfo->display_primaries[2].x;
dxgi_hdr10->BluePrimary[1] = minfo->display_primaries[2].y;
dxgi_hdr10->WhitePoint[0] = minfo->white_point.x;
dxgi_hdr10->WhitePoint[1] = minfo->white_point.y;
dxgi_hdr10->MaxMasteringLuminance = minfo->max_display_mastering_luminance;
dxgi_hdr10->MinMasteringLuminance = minfo->min_display_mastering_luminance;
}
if (cll) {
dxgi_hdr10->MaxContentLightLevel = cll->max_content_light_level;
dxgi_hdr10->MaxFrameAverageLightLevel = cll->max_frame_average_light_level;
}
return TRUE;
}
#endif
#if (GST_D3D11_DXGI_HEADER_VERSION >= 4)
typedef enum
{
GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0,
GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1,
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2,
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3,
GST_DXGI_COLOR_SPACE_RESERVED = 4,
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6,
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8,
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10,
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11,
GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13,
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 14,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16,
GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18,
GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19,
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709 = 20,
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020 = 21,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709 = 22,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 = 23,
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24,
GST_DXGI_COLOR_SPACE_CUSTOM = 0xFFFFFFFF
} GST_DXGI_COLOR_SPACE_TYPE;
/* https://docs.microsoft.com/en-us/windows/win32/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type */
#define MAKE_COLOR_MAP(d,r,m,t,p) \
{ GST_DXGI_COLOR_SPACE_ ##d, GST_VIDEO_COLOR_RANGE ##r, \
GST_VIDEO_COLOR_MATRIX_ ##m, GST_VIDEO_TRANSFER_ ##t, \
GST_VIDEO_COLOR_PRIMARIES_ ##p }
static const GstDxgiColorSpace rgb_colorspace_map[] = {
/* 1) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
* 2) DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
* 3) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
* 4) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020
* 5) DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
* 6) DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
* 7) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020
* 8) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709
* 9) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020
*
* NOTE: if G24 (Gamma 2.4, SRGB) transfer is not defined,
* it will be approximated as G22.
* NOTE: BT470BG ~= BT709
*/
/* 1) RGB_FULL_G22_NONE_P709 */
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT709, BT709),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT601, BT709),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_10, BT709),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_12, BT709),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT709, BT470BG),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT601, BT470BG),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_10, BT470BG),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_12, BT470BG),
/* 1-1) Approximation for RGB_FULL_G22_NONE_P709 */
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, SRGB, BT709),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, SRGB, BT470BG),
/* 2) RGB_FULL_G10_NONE_P709 */
MAKE_COLOR_MAP (RGB_FULL_G10_NONE_P709, _0_255, UNKNOWN, GAMMA10, BT709),
MAKE_COLOR_MAP (RGB_FULL_G10_NONE_P709, _0_255, UNKNOWN, GAMMA10, BT470BG),
/* 3) RGB_STUDIO_G22_NONE_P709 */
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT709, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT601, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_10, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_12, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT709, BT470BG),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT601, BT470BG),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_10,
BT470BG),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_12,
BT470BG),
/* 3-1) Approximation for RGB_STUDIO_G22_NONE_P709 */
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, SRGB, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, SRGB, BT470BG),
/* 4) RGB_STUDIO_G22_NONE_P2020 */
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT709, BT2020),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT601, BT2020),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT2020_10,
BT2020),
MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT2020_12,
BT2020),
/* 5) RGB_FULL_G2084_NONE_P2020 */
MAKE_COLOR_MAP (RGB_FULL_G2084_NONE_P2020, _0_255, UNKNOWN, SMPTE2084,
BT2020),
/* 6) RGB_STUDIO_G2084_NONE_P2020 */
MAKE_COLOR_MAP (RGB_STUDIO_G2084_NONE_P2020, _16_235, UNKNOWN, SMPTE2084,
BT2020),
/* 7) RGB_FULL_G22_NONE_P2020 */
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT709, BT2020),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT601, BT2020),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT2020_10, BT2020),
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT2020_12, BT2020),
/* 7-1) Approximation for RGB_FULL_G22_NONE_P2020 */
MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, SRGB, BT2020),
/* 8) RGB_STUDIO_G24_NONE_P709 */
MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P709, _16_235, UNKNOWN, SRGB, BT709),
MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P709, _16_235, UNKNOWN, SRGB, BT470BG),
/* 9) RGB_STUDIO_G24_NONE_P2020 */
MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P2020, _16_235, UNKNOWN, SRGB, BT2020),
};
static const GstDxgiColorSpace yuv_colorspace_map[] = {
/* 1) YCBCR_FULL_G22_NONE_P709_X601
* 2) YCBCR_STUDIO_G22_LEFT_P601
* 3) YCBCR_FULL_G22_LEFT_P601
* 4) YCBCR_STUDIO_G22_LEFT_P709
* 5) YCBCR_FULL_G22_LEFT_P709
* 6) YCBCR_STUDIO_G22_LEFT_P2020
* 7) YCBCR_FULL_G22_LEFT_P2020
* 8) YCBCR_STUDIO_G2084_LEFT_P2020
* 9) YCBCR_STUDIO_G22_TOPLEFT_P2020
* 10) YCBCR_STUDIO_G2084_TOPLEFT_P2020
* 11) YCBCR_STUDIO_GHLG_TOPLEFT_P2020
* 12) YCBCR_FULL_GHLG_TOPLEFT_P2020
* 13) YCBCR_STUDIO_G24_LEFT_P709
* 14) YCBCR_STUDIO_G24_LEFT_P2020
* 15) YCBCR_STUDIO_G24_TOPLEFT_P2020
*
* NOTE: BT470BG ~= BT709
*/
/* 1) YCBCR_FULL_G22_NONE_P709_X601 */
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT709, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT601, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_10,
BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_12,
BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT709, BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT601, BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_10,
BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_12,
BT470BG),
/* 2) YCBCR_STUDIO_G22_LEFT_P601 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT601, SMPTE170M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT709, SMPTE170M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_10,
SMPTE170M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_12,
SMPTE170M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT601, SMPTE240M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT709, SMPTE240M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_10,
SMPTE240M),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_12,
SMPTE240M),
/* 3) YCBCR_FULL_G22_LEFT_P601 */
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT601, SMPTE170M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT709, SMPTE170M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_10,
SMPTE170M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_12,
SMPTE170M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT601, SMPTE240M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT709, SMPTE240M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_10,
SMPTE240M),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_12,
SMPTE240M),
/* 4) YCBCR_STUDIO_G22_LEFT_P709 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT709, BT709),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT601, BT709),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_10,
BT709),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_12,
BT709),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT709, BT470BG),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT601, BT470BG),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_10,
BT470BG),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_12,
BT470BG),
/* 5) YCBCR_FULL_G22_LEFT_P709 */
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT709, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT601, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_10, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_12, BT709),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT709, BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT601, BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_10, BT470BG),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_12, BT470BG),
/* 6) YCBCR_STUDIO_G22_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT709, BT2020),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT601, BT2020),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT2020_10,
BT2020),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT2020_12,
BT2020),
/* 7) YCBCR_FULL_G22_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT709, BT2020),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT601, BT2020),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT2020_10,
BT2020),
MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT2020_12,
BT2020),
/* 8) YCBCR_STUDIO_G2084_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G2084_LEFT_P2020, _16_235, BT2020, SMPTE2084,
BT2020),
/* 9) YCBCR_STUDIO_G22_TOPLEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_TOPLEFT_P2020, _16_235, BT2020, BT2020_10,
BT2020),
MAKE_COLOR_MAP (YCBCR_STUDIO_G22_TOPLEFT_P2020, _16_235, BT2020, BT2020_12,
BT2020),
/* 10) YCBCR_STUDIO_G2084_TOPLEFT_P2020 */
/* FIXME: check chroma-site to differentiate this from
* YCBCR_STUDIO_G2084_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G2084_TOPLEFT_P2020, _16_235, BT2020, SMPTE2084,
BT2020),
/* 11) YCBCR_STUDIO_GHLG_TOPLEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_GHLG_TOPLEFT_P2020, _16_235, BT2020,
ARIB_STD_B67, BT2020),
/* 12) YCBCR_FULL_GHLG_TOPLEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_FULL_GHLG_TOPLEFT_P2020, _0_255, BT2020, ARIB_STD_B67,
BT2020),
/* 13) YCBCR_STUDIO_G24_LEFT_P709 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G24_LEFT_P709, _16_235, BT709, SRGB, BT709),
/* 14) YCBCR_STUDIO_G24_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G24_LEFT_P2020, _16_235, BT2020, SRGB, BT2020),
/* 15) YCBCR_STUDIO_G24_TOPLEFT_P2020 */
/* FIXME: check chroma-site to differentiate this from
* YCBCR_STUDIO_G24_LEFT_P2020 */
MAKE_COLOR_MAP (YCBCR_STUDIO_G24_TOPLEFT_P2020, _16_235, BT2020, SRGB,
BT2020),
};
#define SCORE_RANGE_MISMATCH 5
#define SCORE_MATRIX_MISMATCH 5
#define SCORE_TRANSFER_MISMATCH 5
#define SCORE_PRIMARY_MISMATCH 10
static gint
get_score (GstVideoInfo * info, const GstDxgiColorSpace * color_map,
gboolean is_yuv)
{
gint loss = 0;
GstVideoColorimetry *color = &info->colorimetry;
if (color->range != color_map->range)
loss += SCORE_RANGE_MISMATCH;
if (is_yuv && color->matrix != color_map->matrix)
loss += SCORE_MATRIX_MISMATCH;
if (color->transfer != color_map->transfer)
loss += SCORE_TRANSFER_MISMATCH;
if (color->primaries != color_map->primaries)
loss += SCORE_PRIMARY_MISMATCH;
return loss;
}
static const GstDxgiColorSpace *
gst_d3d11_video_info_to_dxgi_color_space_rgb (GstVideoInfo * info)
{
gint best_score = G_MAXINT;
gint score, i;
const GstDxgiColorSpace *colorspace = NULL;
for (i = 0; i < G_N_ELEMENTS (rgb_colorspace_map); i++) {
score = get_score (info, &rgb_colorspace_map[i], FALSE);
if (score < best_score) {
best_score = score;
colorspace = &rgb_colorspace_map[i];
if (score == 0)
break;
}
}
return colorspace;
}
static const GstDxgiColorSpace *
gst_d3d11_video_info_to_dxgi_color_space_yuv (GstVideoInfo * info)
{
gint best_score = G_MAXINT;
gint score, i;
const GstDxgiColorSpace *colorspace = NULL;
for (i = 0; i < G_N_ELEMENTS (yuv_colorspace_map); i++) {
score = get_score (info, &yuv_colorspace_map[i], TRUE);
if (score < best_score) {
best_score = score;
colorspace = &yuv_colorspace_map[i];
if (score == 0)
break;
}
}
return colorspace;
}
const GstDxgiColorSpace *
gst_d3d11_video_info_to_dxgi_color_space (GstVideoInfo * info)
{
g_return_val_if_fail (info != NULL, NULL);
if (GST_VIDEO_INFO_IS_RGB (info)) {
return gst_d3d11_video_info_to_dxgi_color_space_rgb (info);
} else if (GST_VIDEO_INFO_IS_YUV (info)) {
return gst_d3d11_video_info_to_dxgi_color_space_yuv (info);
}
return NULL;
}
const GstDxgiColorSpace *
gst_d3d11_find_swap_chain_color_space (GstVideoInfo * info,
IDXGISwapChain3 * swapchain, gboolean use_hdr10)
{
const GstDxgiColorSpace *colorspace = NULL;
gint best_score = G_MAXINT;
gint i;
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (swapchain != NULL, FALSE);
if (!GST_VIDEO_INFO_IS_RGB (info)) {
GST_WARNING ("Swapchain colorspace should be RGB format");
return FALSE;
}
for (i = 0; i < G_N_ELEMENTS (rgb_colorspace_map); i++) {
UINT can_support = 0;
HRESULT hr;
gint score;
GST_DXGI_COLOR_SPACE_TYPE cur_type =
rgb_colorspace_map[i].dxgi_color_space_type;
/* FIXME: Non-HDR colorspace with BT2020 primaries will break rendering.
* https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/1175
* To workaround it, BT709 colorspace will be chosen for non-HDR case.
*/
if (!use_hdr10 &&
rgb_colorspace_map[i].primaries == GST_VIDEO_COLOR_PRIMARIES_BT2020)
continue;
hr = IDXGISwapChain3_CheckColorSpaceSupport (swapchain,
cur_type, &can_support);
if (FAILED (hr))
continue;
if ((can_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ==
DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) {
score = get_score (info, &rgb_colorspace_map[i], FALSE);
GST_DEBUG ("colorspace %d supported, score %d", cur_type, score);
if (score < best_score) {
best_score = score;
colorspace = &rgb_colorspace_map[i];
}
}
}
return colorspace;
}
#endif
GstBuffer *
gst_d3d11_allocate_staging_buffer (GstD3D11Allocator * allocator,
const GstVideoInfo * info, const GstD3D11Format * format,
const D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES],
gboolean add_videometa)
{
GstBuffer *buffer;
gint i;
gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
GstMemory *mem;
g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
g_return_val_if_fail (info != NULL, NULL);
g_return_val_if_fail (format != NULL, NULL);
g_return_val_if_fail (desc != NULL, NULL);
buffer = gst_buffer_new ();
if (format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
gsize size[GST_VIDEO_MAX_PLANES] = { 0, };
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
mem = gst_d3d11_allocator_alloc_staging (allocator, &desc[i], 0,
&stride[i]);
if (!mem) {
GST_ERROR_OBJECT (allocator, "Couldn't allocate memory for plane %d",
i);
goto error;
}
size[i] = gst_memory_get_sizes (mem, NULL, NULL);
if (i > 0)
offset[i] = offset[i - 1] + size[i - 1];
gst_buffer_append_memory (buffer, mem);
}
} else {
/* must be YUV semi-planar or single plane */
g_assert (GST_VIDEO_INFO_N_PLANES (info) <= 2);
mem = gst_d3d11_allocator_alloc_staging (allocator, &desc[0], 0,
&stride[0]);
if (!mem) {
GST_ERROR_OBJECT (allocator, "Couldn't allocate memory");
goto error;
}
gst_memory_get_sizes (mem, NULL, NULL);
gst_buffer_append_memory (buffer, mem);
if (GST_VIDEO_INFO_N_PLANES (info) == 2) {
stride[1] = stride[0];
offset[1] = stride[0] * desc[0].Height;
}
}
if (add_videometa) {
gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
offset, stride);
}
return buffer;
error:
gst_buffer_unref (buffer);
return NULL;
}
GstBuffer *
gst_d3d11_allocate_staging_buffer_for (GstBuffer * buffer,
const GstVideoInfo * info, gboolean add_videometa)
{
GstD3D11Memory *dmem;
GstD3D11Device *device;
GstD3D11AllocationParams *params = NULL;
GstD3D11Allocator *alloc = NULL;
GstBuffer *staging_buffer = NULL;
D3D11_TEXTURE2D_DESC *desc;
gint i;
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
if (!gst_is_d3d11_memory (mem)) {
GST_DEBUG ("Not a d3d11 memory");
return NULL;
}
}
dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
device = dmem->device;
params = gst_d3d11_allocation_params_new (device, (GstVideoInfo *) info,
0, 0);
if (!params) {
GST_WARNING ("Couldn't create alloc params");
goto done;
}
desc = &params->desc[0];
/* resolution of semi-planar formats must be multiple of 2 */
if (desc[0].Format == DXGI_FORMAT_NV12 || desc[0].Format == DXGI_FORMAT_P010
|| desc[0].Format == DXGI_FORMAT_P016) {
if (desc[0].Width % 2 || desc[0].Height % 2) {
gint width, height;
GstVideoAlignment align;
width = GST_ROUND_UP_2 (desc[0].Width);
height = GST_ROUND_UP_2 (desc[0].Height);
gst_video_alignment_reset (&align);
align.padding_right = width - desc[0].Width;
align.padding_bottom = height - desc[0].Height;
gst_d3d11_allocation_params_alignment (params, &align);
}
}
alloc = gst_d3d11_allocator_new (device);
if (!alloc) {
GST_WARNING ("Couldn't create allocator");
goto done;
}
staging_buffer = gst_d3d11_allocate_staging_buffer (alloc,
info, params->d3d11_format, params->desc, add_videometa);
if (!staging_buffer)
GST_WARNING ("Couldn't allocate staging buffer");
done:
if (params)
gst_d3d11_allocation_params_free (params);
if (alloc)
gst_object_unref (alloc);
return staging_buffer;
}
static gboolean
gst_d3d11_buffer_copy_into_fallback (GstBuffer * dst, GstBuffer * src,
const GstVideoInfo * info)
{
GstVideoFrame in_frame, out_frame;
gboolean ret;
if (!gst_video_frame_map (&in_frame, (GstVideoInfo *) info, src,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
if (!gst_video_frame_map (&out_frame, (GstVideoInfo *) info, dst,
GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
gst_video_frame_unmap (&in_frame);
goto invalid_buffer;
}
ret = gst_video_frame_copy (&out_frame, &in_frame);
gst_video_frame_unmap (&in_frame);
gst_video_frame_unmap (&out_frame);
return ret;
/* ERRORS */
invalid_buffer:
{
GST_ERROR ("Invalid video buffer");
return FALSE;
}
}
gboolean
gst_d3d11_buffer_copy_into (GstBuffer * dst, GstBuffer * src,
const GstVideoInfo * info)
{
guint i;
g_return_val_if_fail (GST_IS_BUFFER (dst), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (src), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
if (gst_buffer_n_memory (dst) != gst_buffer_n_memory (src)) {
GST_LOG ("different memory layout, perform fallback copy");
return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
}
if (!gst_is_d3d11_buffer (dst) || !gst_is_d3d11_buffer (src)) {
GST_LOG ("non-d3d11 memory, perform fallback copy");
return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
}
for (i = 0; i < gst_buffer_n_memory (dst); i++) {
GstMemory *dst_mem, *src_mem;
GstD3D11Memory *dst_dmem, *src_dmem;
GstMapInfo dst_info;
GstMapInfo src_info;
ID3D11Resource *dst_texture, *src_texture;
ID3D11DeviceContext *device_context;
GstD3D11Device *device;
D3D11_BOX src_box = { 0, };
D3D11_TEXTURE2D_DESC dst_desc, src_desc;
guint dst_subidx, src_subidx;
dst_mem = gst_buffer_peek_memory (dst, i);
src_mem = gst_buffer_peek_memory (src, i);
dst_dmem = (GstD3D11Memory *) dst_mem;
src_dmem = (GstD3D11Memory *) src_mem;
device = dst_dmem->device;
if (device != src_dmem->device) {
GST_LOG ("different device, perform fallback copy");
return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
}
gst_d3d11_memory_get_texture_desc (dst_dmem, &dst_desc);
gst_d3d11_memory_get_texture_desc (src_dmem, &src_desc);
if (dst_desc.Format != src_desc.Format) {
GST_WARNING ("different dxgi format");
return FALSE;
}
device_context = gst_d3d11_device_get_device_context_handle (device);
if (!gst_memory_map (dst_mem, &dst_info, GST_MAP_WRITE | GST_MAP_D3D11)) {
GST_ERROR ("Cannot map dst d3d11 memory");
return FALSE;
}
if (!gst_memory_map (src_mem, &src_info, GST_MAP_READ | GST_MAP_D3D11)) {
GST_ERROR ("Cannot map src d3d11 memory");
gst_memory_unmap (dst_mem, &dst_info);
return FALSE;
}
dst_texture = (ID3D11Resource *) dst_info.data;
src_texture = (ID3D11Resource *) src_info.data;
/* src/dst texture size might be different if padding was used.
* select smaller size */
src_box.left = 0;
src_box.top = 0;
src_box.front = 0;
src_box.back = 1;
src_box.right = MIN (src_desc.Width, dst_desc.Width);
src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
dst_subidx = gst_d3d11_memory_get_subresource_index (dst_dmem);
src_subidx = gst_d3d11_memory_get_subresource_index (src_dmem);
gst_d3d11_device_lock (device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
dst_texture, dst_subidx, 0, 0, 0, src_texture, src_subidx, &src_box);
gst_d3d11_device_unlock (device);
gst_memory_unmap (src_mem, &src_info);
gst_memory_unmap (dst_mem, &dst_info);
}
return TRUE;
}
gboolean
gst_is_d3d11_buffer (GstBuffer * buffer)
{
guint i;
guint size;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
size = gst_buffer_n_memory (buffer);
if (size == 0)
return FALSE;
for (i = 0; i < size; i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
if (!gst_is_d3d11_memory (mem))
return FALSE;
}
return TRUE;
}
gboolean
gst_d3d11_buffer_can_access_device (GstBuffer * buffer, ID3D11Device * device)
{
guint i;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (device != NULL, FALSE);
if (!gst_is_d3d11_buffer (buffer)) {
GST_LOG ("Not a d3d11 buffer");
return FALSE;
}
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
ID3D11Device *handle;
handle = gst_d3d11_device_get_device_handle (mem->device);
if (handle != device) {
GST_LOG ("D3D11 device is incompatible");
return FALSE;
}
}
return TRUE;
}
gboolean
gst_d3d11_buffer_map (GstBuffer * buffer, ID3D11Device * device,
GstMapInfo info[GST_VIDEO_MAX_PLANES], GstMapFlags flags)
{
GstMapFlags map_flags;
gint num_mapped = 0;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
if (!gst_d3d11_buffer_can_access_device (buffer, device))
return FALSE;
map_flags = flags | GST_MAP_D3D11;
for (num_mapped = 0; num_mapped < gst_buffer_n_memory (buffer); num_mapped++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, num_mapped);
if (!gst_memory_map (mem, &info[num_mapped], map_flags)) {
GST_ERROR ("Couldn't map memory");
goto error;
}
}
return TRUE;
error:
{
gint i;
for (i = 0; i < num_mapped; i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, num_mapped);
gst_memory_unmap (mem, &info[i]);
}
return FALSE;
}
}
gboolean
gst_d3d11_buffer_unmap (GstBuffer * buffer,
GstMapInfo info[GST_VIDEO_MAX_PLANES])
{
gint i;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
gst_memory_unmap (mem, &info[i]);
}
return TRUE;
}
guint
gst_d3d11_buffer_get_shader_resource_view (GstBuffer * buffer,
ID3D11ShaderResourceView * view[GST_VIDEO_MAX_PLANES])
{
gint i;
guint num_views = 0;
g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
g_return_val_if_fail (view != NULL, 0);
if (!gst_is_d3d11_buffer (buffer)) {
GST_ERROR ("Buffer contains non-d3d11 memory");
return 0;
}
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
guint view_size;
gint j;
view_size = gst_d3d11_memory_get_shader_resource_view_size (mem);
if (!view_size) {
GST_LOG ("SRV is unavailable for memory index %d", i);
return 0;
}
for (j = 0; j < view_size; j++) {
if (num_views >= GST_VIDEO_MAX_PLANES) {
GST_ERROR ("Too many SRVs");
return 0;
}
view[num_views++] = gst_d3d11_memory_get_shader_resource_view (mem, j);
}
}
return num_views;
}
guint
gst_d3d11_buffer_get_render_target_view (GstBuffer * buffer,
ID3D11RenderTargetView * view[GST_VIDEO_MAX_PLANES])
{
gint i;
guint num_views = 0;
g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
g_return_val_if_fail (view != NULL, 0);
if (!gst_is_d3d11_buffer (buffer)) {
GST_ERROR ("Buffer contains non-d3d11 memory");
return 0;
}
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
guint view_size;
gint j;
view_size = gst_d3d11_memory_get_render_target_view_size (mem);
if (!view_size) {
GST_LOG ("RTV is unavailable for memory index %d", i);
return 0;
}
for (j = 0; j < view_size; j++) {
if (num_views >= GST_VIDEO_MAX_PLANES) {
GST_ERROR ("Too many RTVs");
return 0;
}
view[num_views++] = gst_d3d11_memory_get_render_target_view (mem, j);
}
}
return num_views;
}
GstBufferPool *
gst_d3d11_buffer_pool_new_with_options (GstD3D11Device * device,
GstCaps * caps, GstD3D11AllocationParams * alloc_params,
guint min_buffers, guint max_buffers)
{
GstBufferPool *pool;
GstStructure *config;
GstVideoInfo info;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
g_return_val_if_fail (alloc_params != NULL, NULL);
if (!gst_video_info_from_caps (&info, caps)) {
GST_ERROR_OBJECT (device, "invalid caps");
return NULL;
}
pool = gst_d3d11_buffer_pool_new (device);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config,
caps, GST_VIDEO_INFO_SIZE (&info), min_buffers, max_buffers);
gst_buffer_pool_config_set_d3d11_allocation_params (config, alloc_params);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
if (!gst_buffer_pool_set_config (pool, config)) {
GST_ERROR_OBJECT (pool, "Couldn't set config");
gst_object_unref (pool);
return NULL;
}
return pool;
}