/* GStreamer * Copyright (C) 2023 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 "gstd3d12.h" #include "gstd3d12converter-builder.h" #include #include #include #include #include #include GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_converter_debug); #define GST_CAT_DEFAULT gst_d3d12_converter_debug /* *INDENT-OFF* */ using namespace Microsoft::WRL; /* *INDENT-ON* */ PixelShaderBlobList gst_d3d12_get_converter_pixel_shader_blob (GstVideoFormat in_format, GstVideoFormat out_format, gboolean in_premul, gboolean out_premul, CONVERT_TYPE type) { GstD3DConverterType conv_type; PixelShaderBlobList ret; switch (type) { case CONVERT_TYPE::IDENTITY: conv_type = GST_D3D_CONVERTER_IDENTITY; break; case CONVERT_TYPE::SIMPLE: conv_type = GST_D3D_CONVERTER_SIMPLE; break; case CONVERT_TYPE::RANGE: conv_type = GST_D3D_CONVERTER_RANGE; break; case CONVERT_TYPE::GAMMA: conv_type = GST_D3D_CONVERTER_GAMMA; break; case CONVERT_TYPE::PRIMARY: conv_type = GST_D3D_CONVERTER_PRIMARY; break; case CONVERT_TYPE::COLOR_BALANCE: conv_type = GST_D3D_CONVERTER_COLOR_BALANCE; break; case CONVERT_TYPE::PRIMARY_AND_COLOR_BALANCE: conv_type = GST_D3D_CONVERTER_PRIMARY_AND_COLOR_BALANCE; break; default: g_assert_not_reached (); return ret; } GstD3DConverterPSByteCode blobs[4]; auto num_blobs = gst_d3d_converter_shader_get_ps_blob (in_format, out_format, in_premul, out_premul, conv_type, GST_D3D_SM_5_0, blobs); if (!num_blobs) { GST_ERROR ("Couldn't get compiled bytecode"); return ret; } for (guint i = 0; i < num_blobs; i++) { auto blob = &blobs[i]; PixelShaderBlob ps; ps.bytecode.pShaderBytecode = blob->byte_code.byte_code; ps.bytecode.BytecodeLength = blob->byte_code.byte_code_len; ps.num_rtv = blob->num_rtv; ret.push_back (ps); } return ret; } HRESULT gst_d3d12_get_converter_vertex_shader_blob (D3D12_SHADER_BYTECODE * vs, D3D12_INPUT_ELEMENT_DESC input_desc[2]) { GstD3DShaderByteCode bytecode = { }; if (!gst_d3d_converter_shader_get_vs_blob (GST_D3D_SM_5_0, &bytecode)) { GST_ERROR ("Couldn't get compiled bytecode"); return E_FAIL; } 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 = D3D12_APPEND_ALIGNED_ELEMENT; input_desc[0].InputSlotClass = D3D12_INPUT_CLASSIFICATION_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 = D3D12_APPEND_ALIGNED_ELEMENT; input_desc[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; input_desc[1].InstanceDataStepRate = 0; vs->BytecodeLength = bytecode.byte_code_len; vs->pShaderBytecode = bytecode.byte_code; return S_OK; } /* root signature * * +-----+---------+------------------+ * | RS | size in | | * | idx | DWORD | | * +-----+---------+------------------+ * | 0 | 1 | table (SRV) | * +-----+---------+------------------+ * | 1 | 1 | table (Sampler) | * +-----+---------+------------------+ * | 2 | 16 | VS matrix | * +-----+---------+------------------+ * | 3 | 1 | PS alpha | * +-----+---------+------------------+ * | 4 | 2 | PS CBV | * +-----+---------+------------------+ */ static const D3D12_ROOT_SIGNATURE_FLAGS rs_flags_ = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS; ConverterRootSignature::ConverterRootSignature (D3D_ROOT_SIGNATURE_VERSION version, UINT num_srv, bool build_lut) { D3D12_VERSIONED_ROOT_SIGNATURE_DESC desc = { }; num_srv_ = num_srv; have_lut_ = build_lut; std::vector < D3D12_DESCRIPTOR_RANGE1 > range_v1_1; std::vector < D3D12_DESCRIPTOR_RANGE1 > sampler_range_v1_1; std::vector < D3D12_ROOT_PARAMETER1 > param_list_v1_1; CD3DX12_ROOT_PARAMETER1 param; ps_srv_ = 0; for (UINT i = 0; i < num_srv; i++) { range_v1_1.push_back (CD3DX12_DESCRIPTOR_RANGE1 (D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, i, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE | D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE)); } if (build_lut) { range_v1_1.push_back (CD3DX12_DESCRIPTOR_RANGE1 (D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 4, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE | D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE)); range_v1_1.push_back (CD3DX12_DESCRIPTOR_RANGE1 (D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 5, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE | D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE)); } param.InitAsDescriptorTable (range_v1_1.size (), range_v1_1.data (), D3D12_SHADER_VISIBILITY_PIXEL); param_list_v1_1.push_back (param); /* sampler state, can be updated */ ps_sampler_ = (UINT) param_list_v1_1.size (); sampler_range_v1_1.push_back (CD3DX12_DESCRIPTOR_RANGE1 (D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE)); if (build_lut) { sampler_range_v1_1.push_back (CD3DX12_DESCRIPTOR_RANGE1 (D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 1, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE)); } param.InitAsDescriptorTable (sampler_range_v1_1.size (), sampler_range_v1_1.data (), D3D12_SHADER_VISIBILITY_PIXEL); param_list_v1_1.push_back (param); /* VS root const, maybe updated */ vs_root_const_ = (UINT) param_list_v1_1.size (); param.InitAsConstants (16, 0, 0, D3D12_SHADER_VISIBILITY_VERTEX); param_list_v1_1.push_back (param); /* PS alpha constant value, maybe updated */ ps_root_const_ = (UINT) param_list_v1_1.size (); param.InitAsConstants (8, 1, 0, D3D12_SHADER_VISIBILITY_PIXEL); param_list_v1_1.push_back (param); /* PS CBV, this is static */ ps_cbv_ = (UINT) param_list_v1_1.size (); param.InitAsConstantBufferView (2, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE, D3D12_SHADER_VISIBILITY_PIXEL); param_list_v1_1.push_back (param); CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC::Init_1_1 (desc, param_list_v1_1.size (), param_list_v1_1.data (), 0, nullptr, rs_flags_); ComPtr < ID3DBlob > error_blob; hr_ = D3DX12SerializeVersionedRootSignature (&desc, version, &blob_, &error_blob); if (FAILED (hr_)) { const gchar *error_msg = nullptr; if (error_blob) error_msg = (const gchar *) error_blob->GetBufferPointer (); GST_ERROR ("Couldn't serialize root signature, hr: 0x%x, error detail: %s", (guint) hr_, GST_STR_NULL (error_msg)); } } ConverterRootSignaturePtr gst_d3d12_get_converter_root_signature (GstD3D12Device * device, GstVideoFormat in_format, CONVERT_TYPE type) { auto info = gst_video_format_get_info (in_format); auto num_planes = GST_VIDEO_FORMAT_INFO_N_PLANES (info); bool build_lut = false; auto device_handle = gst_d3d12_device_get_device_handle (device); D3D_ROOT_SIGNATURE_VERSION rs_version = D3D_ROOT_SIGNATURE_VERSION_1_1; D3D12_FEATURE_DATA_ROOT_SIGNATURE feature_data = { }; feature_data.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; auto hr = device_handle->CheckFeatureSupport (D3D12_FEATURE_ROOT_SIGNATURE, &feature_data, sizeof (feature_data)); if (FAILED (hr)) { rs_version = D3D_ROOT_SIGNATURE_VERSION_1_0; } else { GST_INFO_OBJECT (device, "Device supports version 1.1 root signature"); } if (type == CONVERT_TYPE::GAMMA || type == CONVERT_TYPE::PRIMARY || type == CONVERT_TYPE::COLOR_BALANCE || type == CONVERT_TYPE::PRIMARY_AND_COLOR_BALANCE) build_lut = true; auto rs = std::make_shared < ConverterRootSignature > (rs_version, num_planes, build_lut); if (!rs->IsValid ()) return nullptr; return rs; }