gstreamer/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11pluginutils.cpp
Seungha Yang b16665dc75 d3d11convert: Add support for sampling with anisotropic filter
Anisotropic filtering might produce better quality than linear filtering

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5572>
2023-10-28 22:56:28 +09:00

1157 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>
#include <wrl.h>
#include "hlsl/gstd3d11plugin-hlsl.h"
/* Disable platform-specific intrinsics */
#define _XM_NO_INTRINSICS_
#include <DirectXMath.h>
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_plugin_utils_debug);
#define GST_CAT_DEFAULT gst_d3d11_plugin_utils_debug
/* *INDENT-OFF* */
using namespace Microsoft::WRL;
using namespace DirectX;
/* *INDENT-ON* */
/**
* GstD3D11AlphaMode:
*
* Since: 1.24
*/
GType
gst_d3d11_alpha_mode_get_type (void)
{
static GType type = 0;
static const GEnumValue alpha_mode[] = {
/**
* GstD3D11AlphaMode::unspecified:
*
* Since: 1.24
*/
{GST_D3D11_ALPHA_MODE_UNSPECIFIED, "Unspecified", "unspecified"},
/**
* GstD3D11AlphaMode::premultiplied:
*
* Since: 1.24
*/
{GST_D3D11_ALPHA_MODE_PREMULTIPLIED, "Premultiplied", "premultiplied"},
/**
* GstD3D11AlphaMode::straight:
*
* Since: 1.24
*/
{GST_D3D11_ALPHA_MODE_STRAIGHT, "Straight", "straight"},
{0, nullptr, nullptr},
};
GST_D3D11_CALL_ONCE_BEGIN {
type = g_enum_register_static ("GstD3D11AlphaMode", alpha_mode);
} GST_D3D11_CALL_ONCE_END;
return type;
}
/**
* GstD3D11MSAAMode:
*
* Since: 1.24
*/
GType
gst_d3d11_msaa_mode_get_type (void)
{
static GType type = 0;
static const GEnumValue msaa_mode[] = {
{GST_D3D11_MSAA_DISABLED, "Disabled", "disabled"},
{GST_D3D11_MSAA_2X, "2x MSAA", "2x"},
{GST_D3D11_MSAA_4X, "4x MSAA", "4x"},
{GST_D3D11_MSAA_8X, "8x MSAA", "8x"},
{0, nullptr, nullptr},
};
GST_D3D11_CALL_ONCE_BEGIN {
type = g_enum_register_static ("GstD3D11MSAAMode", msaa_mode);
} GST_D3D11_CALL_ONCE_END;
return type;
}
/**
* GstD3D11SamplingMethod:
*
* Texture sampling method
*
* Since: 1.24
*/
GType
gst_d3d11_sampling_method_get_type (void)
{
static GType type = 0;
static const GEnumValue methods[] = {
/**
* GstD3D11SamplingMethod::nearest-neighbour:
*
* Since: 1.24
*/
{GST_D3D11_SAMPLING_METHOD_NEAREST,
"Nearest Neighbour", "nearest-neighbour"},
/**
* GstD3D11SamplingMethod::bilinear:
*
* Since: 1.24
*/
{GST_D3D11_SAMPLING_METHOD_BILINEAR,
"Bilinear", "bilinear"},
/**
* GstD3D11SamplingMethod::linear-minification:
*
* Since: 1.24
*/
{GST_D3D11_SAMPLING_METHOD_LINEAR_MINIFICATION,
"Linear minification, point magnification", "linear-minification"},
/**
* GstD3D11SamplingMethod::anisotropic:
*
* Since: 1.24
*/
{GST_D3D11_SAMPLING_METHOD_ANISOTROPIC, "Anisotropic", "anisotropic"},
{0, nullptr, nullptr},
};
GST_D3D11_CALL_ONCE_BEGIN {
type = g_enum_register_static ("GstD3D11SamplingMethod", methods);
} GST_D3D11_CALL_ONCE_END;
return type;
}
/* Max Texture Dimension for feature level 11_0 ~ 12_1 */
static guint _gst_d3d11_texture_max_dimension = 16384;
void
gst_d3d11_plugin_utils_init (D3D_FEATURE_LEVEL feature_level)
{
GST_D3D11_CALL_ONCE_BEGIN {
/* https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-downlevel-intro */
if (feature_level >= D3D_FEATURE_LEVEL_11_0)
_gst_d3d11_texture_max_dimension = 16384;
else if (feature_level >= D3D_FEATURE_LEVEL_10_0)
_gst_d3d11_texture_max_dimension = 8192;
else
_gst_d3d11_texture_max_dimension = 4096;
}
GST_D3D11_CALL_ONCE_END;
}
GstCaps *
gst_d3d11_get_updated_template_caps (GstStaticCaps * template_caps)
{
GstCaps *caps;
g_return_val_if_fail (template_caps != NULL, NULL);
caps = gst_static_caps_get (template_caps);
if (!caps) {
GST_ERROR ("Couldn't get caps from static caps");
return NULL;
}
caps = gst_caps_make_writable (caps);
gst_caps_set_simple (caps,
"width", GST_TYPE_INT_RANGE, 1, _gst_d3d11_texture_max_dimension,
"height", GST_TYPE_INT_RANGE, 1, _gst_d3d11_texture_max_dimension, NULL);
return caps;
}
gboolean
gst_d3d11_is_windows_8_or_greater (void)
{
static gboolean ret = FALSE;
GST_D3D11_CALL_ONCE_BEGIN {
#if (!GST_D3D11_WINAPI_ONLY_APP)
if (IsWindows8OrGreater ())
ret = TRUE;
#else
ret = TRUE;
#endif
} GST_D3D11_CALL_ONCE_END;
return ret;
}
GstD3D11DeviceVendor
gst_d3d11_get_device_vendor_from_id (guint vendor_id)
{
GstD3D11DeviceVendor vendor = GST_D3D11_DEVICE_VENDOR_UNKNOWN;
switch (vendor_id) {
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;
}
return vendor;
}
GstD3D11DeviceVendor
gst_d3d11_get_device_vendor (GstD3D11Device * device)
{
guint device_id = 0;
guint vendor_id = 0;
gchar *desc = nullptr;
GstD3D11DeviceVendor vendor = GST_D3D11_DEVICE_VENDOR_UNKNOWN;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device),
GST_D3D11_DEVICE_VENDOR_UNKNOWN);
g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id,
"description", &desc, nullptr);
if (device_id == 0 && desc && g_strrstr (desc, "SraKmd"))
vendor = GST_D3D11_DEVICE_VENDOR_XBOX;
g_free (desc);
if (vendor != GST_D3D11_DEVICE_VENDOR_UNKNOWN)
return vendor;
return gst_d3d11_get_device_vendor_from_id (vendor_id);
}
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;
}
gboolean
gst_d3d11_find_swap_chain_color_space (const GstVideoInfo * info,
IDXGISwapChain3 * swapchain, DXGI_COLOR_SPACE_TYPE * color_space)
{
UINT can_support = 0;
HRESULT hr;
DXGI_COLOR_SPACE_TYPE color;
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (swapchain != NULL, FALSE);
g_return_val_if_fail (color_space != NULL, FALSE);
if (!GST_VIDEO_INFO_IS_RGB (info)) {
GST_WARNING ("Swapchain colorspace should be RGB format");
return FALSE;
}
/* Select PQ color space only if input is also PQ */
if (info->colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_BT2020 &&
info->colorimetry.transfer == GST_VIDEO_TRANSFER_SMPTE2084) {
color = (DXGI_COLOR_SPACE_TYPE) 12;
hr = swapchain->CheckColorSpaceSupport (color, &can_support);
if (SUCCEEDED (hr) && can_support) {
*color_space = color;
return TRUE;
}
}
/* otherwise use standard sRGB color space */
color = (DXGI_COLOR_SPACE_TYPE) 0;
hr = swapchain->CheckColorSpaceSupport (color, &can_support);
if (SUCCEEDED (hr) && can_support) {
*color_space = color;
return TRUE;
}
return FALSE;
}
static void
fill_staging_desc (const D3D11_TEXTURE2D_DESC * ref,
D3D11_TEXTURE2D_DESC * staging)
{
memset (staging, 0, sizeof (D3D11_TEXTURE2D_DESC));
staging->Width = ref->Width;
staging->Height = ref->Height;
staging->MipLevels = 1;
staging->Format = ref->Format;
staging->SampleDesc.Count = 1;
staging->ArraySize = 1;
staging->Usage = D3D11_USAGE_STAGING;
staging->CPUAccessFlags = (D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE);
}
GstBuffer *
gst_d3d11_allocate_staging_buffer_for (GstBuffer * buffer,
const GstVideoInfo * info, gboolean add_videometa)
{
GstD3D11Memory *dmem;
GstD3D11Device *device;
GstBuffer *staging_buffer = NULL;
gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
guint i;
gsize size = 0;
GstD3D11Format format;
D3D11_TEXTURE2D_DESC desc;
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;
if (!gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (info),
&format)) {
GST_ERROR ("Unknown d3d11 format");
return NULL;
}
staging_buffer = gst_buffer_new ();
for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
D3D11_TEXTURE2D_DESC staging_desc;
GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
GstD3D11Memory *new_mem;
guint cur_stride = 0;
gst_d3d11_memory_get_texture_desc (mem, &desc);
fill_staging_desc (&desc, &staging_desc);
new_mem = (GstD3D11Memory *)
gst_d3d11_allocator_alloc (nullptr, mem->device, &staging_desc);
if (!new_mem) {
GST_ERROR ("Failed to allocate memory");
goto error;
}
if (!gst_d3d11_memory_get_resource_stride (new_mem, &cur_stride) ||
cur_stride < staging_desc.Width) {
GST_ERROR ("Failed to calculate memory size");
gst_memory_unref (GST_MEMORY_CAST (mem));
goto error;
}
offset[i] = size;
stride[i] = cur_stride;
size += GST_MEMORY_CAST (new_mem)->size;
gst_buffer_append_memory (staging_buffer, GST_MEMORY_CAST (new_mem));
}
/* single texture semi-planar formats */
if (format.dxgi_format != DXGI_FORMAT_UNKNOWN &&
GST_VIDEO_INFO_N_PLANES (info) == 2) {
stride[1] = stride[0];
offset[1] = stride[0] * desc.Height;
}
gst_buffer_add_video_meta_full (staging_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 staging_buffer;
error:
gst_clear_buffer (&staging_buffer);
return NULL;
}
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,
(GstMapFlags) (GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)))
goto invalid_buffer;
if (!gst_video_frame_map (&out_frame, (GstVideoInfo *) info, dst,
(GstMapFlags) (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,
(GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
GST_ERROR ("Cannot map dst d3d11 memory");
return FALSE;
}
if (!gst_memory_map (src_mem, &src_info,
(GstMapFlags) (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);
GstD3D11DeviceLockGuard lk (device);
device_context->CopySubresourceRegion (dst_texture, dst_subidx, 0, 0, 0,
src_texture, src_subidx, &src_box);
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;
guint 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 = (GstMapFlags) (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:
{
guint i;
for (i = 0; i < num_mapped; i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
gst_memory_unmap (mem, &info[i]);
}
return FALSE;
}
}
gboolean
gst_d3d11_buffer_unmap (GstBuffer * buffer,
GstMapInfo info[GST_VIDEO_MAX_PLANES])
{
guint 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])
{
guint 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;
guint 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])
{
guint 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;
guint 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;
}
HRESULT
gst_d3d11_get_pixel_shader_checker_luma (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_checker_luma, sizeof (g_PSMain_checker_luma),
g_PSMain_checker_luma_str, sizeof (g_PSMain_checker_luma_str),
"PSMain_checker_luma", nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_checker_rgb (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_checker_rgb, sizeof (g_PSMain_checker_rgb),
g_PSMain_checker_rgb_str, sizeof (g_PSMain_checker_rgb_str),
"PSMain_checker_rgb", nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_checker_vuya (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_checker_vuya, sizeof (g_PSMain_checker_vuya),
g_PSMain_checker_vuya_str, sizeof (g_PSMain_checker_vuya_str),
"PSMain_checker_vuya", nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_checker (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_checker, sizeof (g_PSMain_checker),
g_PSMain_checker_str, sizeof (g_PSMain_checker_str),
"PSMain_checker", nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_color (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_color, sizeof (g_PSMain_color),
g_PSMain_color_str, sizeof (g_PSMain_color_str), "PSMain_color",
nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_sample_premul (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_sample_premul, sizeof (g_PSMain_sample_premul),
g_PSMain_sample_premul_str, sizeof (g_PSMain_sample_premul_str),
"PSMain_sample_premul", nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_sample (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_sample, sizeof (g_PSMain_sample),
g_PSMain_sample_str, sizeof (g_PSMain_sample_str), "PSMain_sample",
nullptr, ps);
}
HRESULT
gst_d3d11_get_pixel_shader_snow (GstD3D11Device * device,
ID3D11PixelShader ** ps)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_pixel_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
return gst_d3d11_device_get_pixel_shader (device, token,
g_PSMain_snow, sizeof (g_PSMain_snow),
g_PSMain_snow_str, sizeof (g_PSMain_snow_str), "PSMain_snow",
nullptr, ps);
}
HRESULT
gst_d3d11_get_vertex_shader_color (GstD3D11Device * device,
ID3D11VertexShader ** vs, ID3D11InputLayout ** layout)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_vertex_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
D3D11_INPUT_ELEMENT_DESC input_desc[2];
input_desc[0].SemanticName = "POSITION";
input_desc[0].SemanticIndex = 0;
input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
input_desc[0].InputSlot = 0;
input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
input_desc[0].InstanceDataStepRate = 0;
input_desc[1].SemanticName = "COLOR";
input_desc[1].SemanticIndex = 0;
input_desc[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
input_desc[1].InputSlot = 0;
input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
input_desc[1].InstanceDataStepRate = 0;
return gst_d3d11_device_get_vertex_shader (device, token,
g_VSMain_color, sizeof (g_VSMain_color),
g_VSMain_color_str, sizeof (g_VSMain_color_str), "VSMain_color",
input_desc, G_N_ELEMENTS (input_desc), vs, layout);
}
HRESULT
gst_d3d11_get_vertex_shader_coord (GstD3D11Device * device,
ID3D11VertexShader ** vs, ID3D11InputLayout ** layout)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_vertex_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
D3D11_INPUT_ELEMENT_DESC input_desc[2];
input_desc[0].SemanticName = "POSITION";
input_desc[0].SemanticIndex = 0;
input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
input_desc[0].InputSlot = 0;
input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
input_desc[0].InstanceDataStepRate = 0;
input_desc[1].SemanticName = "TEXCOORD";
input_desc[1].SemanticIndex = 0;
input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
input_desc[1].InputSlot = 0;
input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
input_desc[1].InstanceDataStepRate = 0;
return gst_d3d11_device_get_vertex_shader (device, token,
g_VSMain_coord, sizeof (g_VSMain_coord),
g_VSMain_coord_str, sizeof (g_VSMain_coord_str), "VSMain_coord",
input_desc, G_N_ELEMENTS (input_desc), vs, layout);
}
HRESULT
gst_d3d11_get_vertex_shader_pos (GstD3D11Device * device,
ID3D11VertexShader ** vs, ID3D11InputLayout ** layout)
{
static gint64 token = 0;
GST_D3D11_CALL_ONCE_BEGIN {
token = gst_d3d11_vertex_shader_token_new ();
} GST_D3D11_CALL_ONCE_END;
D3D11_INPUT_ELEMENT_DESC input_desc;
input_desc.SemanticName = "POSITION";
input_desc.SemanticIndex = 0;
input_desc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
input_desc.InputSlot = 0;
input_desc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
input_desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
input_desc.InstanceDataStepRate = 0;
return gst_d3d11_device_get_vertex_shader (device, token,
g_VSMain_pos, sizeof (g_VSMain_pos),
g_VSMain_pos_str, sizeof (g_VSMain_pos_str), "VSMain_pos", &input_desc, 1,
vs, layout);
}
gboolean
gst_d3d11_need_transform (gfloat rotation_x, gfloat rotation_y,
gfloat rotation_z, gfloat scale_x, gfloat scale_y)
{
const gfloat min_diff = 0.00001f;
if (!XMScalarNearEqual (rotation_x, 0.0f, min_diff) ||
!XMScalarNearEqual (rotation_y, 0.0f, min_diff) ||
!XMScalarNearEqual (rotation_z, 0.0f, min_diff) ||
!XMScalarNearEqual (scale_x, 1.0f, min_diff) ||
!XMScalarNearEqual (scale_y, 1.0f, min_diff)) {
return TRUE;
}
return FALSE;
}
static const XMFLOAT4X4 g_matrix_90r = XMFLOAT4X4 (0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_180 = XMFLOAT4X4 (-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_90l = XMFLOAT4X4 (0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_horiz = XMFLOAT4X4 (-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_vert = XMFLOAT4X4 (1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_ul_lr = XMFLOAT4X4 (0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
static const XMFLOAT4X4 g_matrix_ur_ll = XMFLOAT4X4 (0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
void
gst_d3d11_calculate_transform_matrix (GstVideoOrientationMethod method,
gfloat viewport_width, gfloat viewport_height, gfloat fov, gboolean ortho,
gfloat rotation_x, gfloat rotation_y, gfloat rotation_z,
gfloat scale_x, gfloat scale_y, gfloat transform_matrix[16])
{
gfloat aspect_ratio;
gboolean rotated = FALSE;
XMMATRIX rotate_matrix = XMMatrixIdentity ();
switch (method) {
case GST_VIDEO_ORIENTATION_IDENTITY:
case GST_VIDEO_ORIENTATION_AUTO:
case GST_VIDEO_ORIENTATION_CUSTOM:
default:
break;
case GST_VIDEO_ORIENTATION_90R:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_90r);
rotated = TRUE;
break;
case GST_VIDEO_ORIENTATION_180:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_180);
break;
case GST_VIDEO_ORIENTATION_90L:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_90l);
rotated = TRUE;
break;
case GST_VIDEO_ORIENTATION_HORIZ:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_horiz);
break;
case GST_VIDEO_ORIENTATION_VERT:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_vert);
break;
case GST_VIDEO_ORIENTATION_UL_LR:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_ul_lr);
rotated = TRUE;
break;
case GST_VIDEO_ORIENTATION_UR_LL:
rotate_matrix = XMLoadFloat4x4 (&g_matrix_ur_ll);
rotated = TRUE;
break;
}
if (rotated)
aspect_ratio = viewport_height / viewport_width;
else
aspect_ratio = viewport_width / viewport_height;
/* Apply user specified transform matrix first, then rotate-method */
XMMATRIX scale = XMMatrixScaling (scale_x * aspect_ratio, scale_y, 1.0);
XMMATRIX rotate =
XMMatrixRotationX (XMConvertToRadians (rotation_x)) *
XMMatrixRotationY (XMConvertToRadians (-rotation_y)) *
XMMatrixRotationZ (XMConvertToRadians (-rotation_z));
XMMATRIX view = XMMatrixLookAtLH (XMVectorSet (0.0, 0.0, -1.0, 0.0),
XMVectorSet (0.0, 0.0, 0.0, 0.0), XMVectorSet (0.0, 1.0, 0.0, 0.0));
XMMATRIX proj;
if (ortho) {
proj = XMMatrixOrthographicOffCenterLH (-aspect_ratio,
aspect_ratio, -1.0, 1.0, 0.1, 100.0);
} else {
proj = XMMatrixPerspectiveFovLH (XMConvertToRadians (fov),
aspect_ratio, 0.1, 100.0);
}
XMMATRIX mvp = scale * rotate * view * proj * rotate_matrix;
XMFLOAT4X4 matrix;
XMStoreFloat4x4 (&matrix, mvp);
for (guint i = 0; i < 4; i++) {
for (guint j = 0; j < 4; j++) {
transform_matrix[i * 4 + j] = matrix.m[i][j];
}
}
}
struct SamplingMethodMap
{
GstD3D11SamplingMethod method;
D3D11_FILTER filter;
};
static const SamplingMethodMap sampling_method_map[] = {
{GST_D3D11_SAMPLING_METHOD_NEAREST, D3D11_FILTER_MIN_MAG_MIP_POINT},
{GST_D3D11_SAMPLING_METHOD_BILINEAR, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT},
{GST_D3D11_SAMPLING_METHOD_LINEAR_MINIFICATION,
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT},
{GST_D3D11_SAMPLING_METHOD_ANISOTROPIC, D3D11_FILTER_COMPARISON_ANISOTROPIC},
};
D3D11_FILTER
gst_d3d11_sampling_method_to_native (GstD3D11SamplingMethod method)
{
for (guint i = 0; i < G_N_ELEMENTS (sampling_method_map); i++) {
if (sampling_method_map[i].method == method)
return sampling_method_map[i].filter;
}
return D3D11_FILTER_MIN_MAG_MIP_POINT;
}