/* GStreamer * Copyright (C) 2019 Seungha Yang * Copyright (C) 2020 Seungha Yang * * 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 #include #include #include "hlsl/gstd3d11plugin-hlsl.h" /* Disable platform-specific intrinsics */ #define _XM_NO_INTRINSICS_ #include 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; }