From f94c84c828b39ffb975bbb117e9cd2b2e4641d63 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 3 Nov 2024 04:00:25 +0900 Subject: [PATCH] d3d12converter: Add support for colorbalance Adding support for hue, saturation, brightness, and contrast adjustment Part-of: --- .../gst-libs/gst/d3d11/gstd3d11converter.cpp | 1 + .../gst/d3d12/gstd3d12converter-builder.cpp | 12 +- .../gst/d3d12/gstd3d12converter-builder.h | 2 + .../gst/d3d12/gstd3d12converter-private.h | 28 +- .../gst-libs/gst/d3d12/gstd3d12converter.cpp | 488 ++++++++++++------ .../gst-libs/gst/d3d12/gstd3d12converter.h | 26 + .../gst-libs/gst/d3d12/gstd3d12device.cpp | 12 +- .../converter-hlsl/PSMain_converter.hlsl | 219 +++++++- .../gst/d3dshader/gstd3dshadercache.cpp | 6 + .../gst/d3dshader/gstd3dshadercache.h | 2 + 10 files changed, 612 insertions(+), 184 deletions(-) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11converter.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11converter.cpp index 8eaebe39b5..a06a1d4c2f 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11converter.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11converter.cpp @@ -155,6 +155,7 @@ struct PSAlphaFactor { FLOAT alpha; FLOAT padding[3]; + FLOAT padding_other[4]; }; struct PSConstBuffer diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.cpp index c03527c766..4ddb8173de 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.cpp @@ -61,6 +61,12 @@ gst_d3d12_get_converter_pixel_shader_blob (GstVideoFormat in_format, 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; @@ -202,7 +208,7 @@ ConverterRootSignature::ConverterRootSignature (D3D_ROOT_SIGNATURE_VERSION /* PS alpha constant value, maybe updated */ ps_root_const_ = (UINT) param_list_v1_1.size (); - param.InitAsConstants (1, 1, 0, D3D12_SHADER_VISIBILITY_PIXEL); + param.InitAsConstants (8, 1, 0, D3D12_SHADER_VISIBILITY_PIXEL); param_list_v1_1.push_back (param); /* PS CBV, this is static */ @@ -247,7 +253,9 @@ gst_d3d12_get_converter_root_signature (GstD3D12Device * device, GST_INFO_OBJECT (device, "Device supports version 1.1 root signature"); } - if (type == CONVERT_TYPE::GAMMA || type == CONVERT_TYPE::PRIMARY) + 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 > diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.h index d8ec798483..fe0b7175a3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-builder.h @@ -34,6 +34,8 @@ enum class CONVERT_TYPE RANGE, GAMMA, PRIMARY, + COLOR_BALANCE, + PRIMARY_AND_COLOR_BALANCE, }; struct PixelShaderBlob diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-private.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-private.h index 46321656ec..2855267fae 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-private.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter-private.h @@ -26,16 +26,22 @@ G_BEGIN_DECLS GST_D3D12_API -gboolean gst_d3d12_converter_apply_transform (GstD3D12Converter * converter, - GstVideoOrientationMethod orientation, - 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); +gboolean gst_d3d12_converter_apply_transform (GstD3D12Converter * converter, + GstVideoOrientationMethod orientation, + 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); + +GST_D3D12_API +gboolean gst_d3d12_converter_is_color_balance_needed (gfloat hue, + gfloat saturation, + gfloat brightness, + gfloat contrast); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.cpp index 8797084bfd..69f41bc425 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.cpp @@ -90,6 +90,26 @@ gst_d3d12_converter_alpha_mode_get_type (void) return type; } +GType +gst_d3d12_converter_color_balance_get_type (void) +{ + static GType type = 0; + static const GEnumValue color_balance[] = { + {GST_D3D12_CONVERTER_COLOR_BALANCE_DISABLED, + "GST_D3D12_CONVERTER_COLOR_BALANCE_DISABLED", "disabled"}, + {GST_D3D12_CONVERTER_COLOR_BALANCE_ENABLED, + "GST_D3D12_CONVERTER_COLOR_BALANCE_ENABLED", "enabled"}, + {0, nullptr, nullptr}, + }; + + GST_D3D12_CALL_ONCE_BEGIN { + type = g_enum_register_static ("GstD3D12ConverterColorBalance", + color_balance); + } GST_D3D12_CALL_ONCE_END; + + return type; +} + /* *INDENT-OFF* */ using namespace Microsoft::WRL; using namespace DirectX; @@ -98,6 +118,12 @@ using namespace DirectX; #define GAMMA_LUT_SIZE 4096 #define DEFAULT_BUFFER_COUNT 2 #define DEFAULT_SAMPLER_FILTER D3D12_FILTER_MIN_MAG_MIP_LINEAR +#define DEFAULT_BORDER_COLOR G_GUINT64_CONSTANT(0xffff000000000000) +#define DEFAULT_HUE 0.0 +#define DEFAULT_SATURATION 1.0 +#define DEFAULT_BRIGHTNESS 0.0 +#define DEFAULT_CONTRAST 1.0 + static const WORD g_indices[6] = { 0, 1, 2, 3, 0, 2 }; struct PSColorSpace @@ -118,6 +144,13 @@ struct PSConstBuffer PSColorSpace primariesCoeff; }; +struct PSConstBufferDyn +{ + float alphaFactor; + float padding[3]; + float hsvcFactor[4]; +}; + struct VertexData { struct @@ -210,6 +243,10 @@ enum PROP_BORDER_COLOR, PROP_VIDEO_DIRECTION, PROP_SAMPLER_FILTER, + PROP_HUE, + PROP_SATURATION, + PROP_BRIGHTNESS, + PROP_CONTRAST, }; /* *INDENT-OFF* */ @@ -220,6 +257,14 @@ struct QuadData guint num_rtv; }; +struct PipelineData +{ + PixelShaderBlobList psblob_list; + ConverterRootSignaturePtr crs; + ComPtr rs; + std::vector quad_data; +}; + #define STATE_VERTEX_AND_INDEX \ (D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDEX_BUFFER) @@ -235,6 +280,12 @@ struct _GstD3D12ConverterPrivate sample_desc.Count = 1; sample_desc.Quality = 0; + + const_data_dyn.alphaFactor = 1.0; + const_data_dyn.hsvcFactor[0] = DEFAULT_HUE; + const_data_dyn.hsvcFactor[1] = DEFAULT_SATURATION; + const_data_dyn.hsvcFactor[2] = DEFAULT_BRIGHTNESS; + const_data_dyn.hsvcFactor[3] = DEFAULT_CONTRAST; } ~_GstD3D12ConverterPrivate () @@ -255,7 +306,8 @@ struct _GstD3D12ConverterPrivate GstVideoInfo in_info; GstVideoInfo out_info; - CONVERT_TYPE convert_type = CONVERT_TYPE::IDENTITY; + CONVERT_TYPE convert_type[2] = { CONVERT_TYPE::IDENTITY, + CONVERT_TYPE::COLOR_BALANCE }; D3D12_VIEWPORT viewport[GST_VIDEO_MAX_PLANES]; D3D12_RECT scissor_rect[GST_VIDEO_MAX_PLANES]; @@ -267,12 +319,12 @@ struct _GstD3D12ConverterPrivate gboolean update_pso = FALSE; gboolean update_sampler = FALSE; - ConverterRootSignaturePtr crs; - ComPtr rs; + std::vector pipeline_data; + gboolean have_lut = FALSE; D3D12_VERTEX_BUFFER_VIEW vbv; D3D12_INDEX_BUFFER_VIEW idv; - D3D12_GPU_VIRTUAL_ADDRESS const_buf_addr; + D3D12_GPU_VIRTUAL_ADDRESS const_buf_addr[2]; ComPtr shader_buf; ComPtr vertex_upload; ComPtr gamma_dec_lut; @@ -281,8 +333,6 @@ struct _GstD3D12ConverterPrivate ComPtr gamma_lut_heap; ComPtr sampler_heap; - std::vector quad_data; - GstD3D12DescHeapPool *srv_heap_pool = nullptr; guint srv_inc_size; @@ -297,13 +347,15 @@ struct _GstD3D12ConverterPrivate XMFLOAT4X4A transform; XMFLOAT4X4A custom_transform; - PSConstBuffer const_data; + PSConstBuffer const_data[2]; gboolean clear_background = FALSE; FLOAT clear_color[4][4]; GstD3D12ColorMatrix clear_color_matrix; GstVideoOrientationMethod video_direction; + gboolean color_balance_enabled = FALSE; + gboolean need_color_balance = FALSE; std::mutex prop_lock; guint64 fence_val = 0; @@ -317,9 +369,9 @@ struct _GstD3D12ConverterPrivate gint dest_y = 0; gint dest_width = 0; gint dest_height = 0; - FLOAT alpha = 1.0; + PSConstBufferDyn const_data_dyn; gboolean fill_border = FALSE; - guint64 border_color = 0; + guint64 border_color = DEFAULT_BORDER_COLOR; GstD3D12ConverterAlphaMode src_alpha_mode = GST_D3D12_CONVERTER_ALPHA_MODE_UNSPECIFIED; GstD3D12ConverterAlphaMode dst_alpha_mode = @@ -387,7 +439,7 @@ gst_d3d12_converter_class_init (GstD3D12ConverterClass * klass) g_object_class_install_property (object_class, PROP_BORDER_COLOR, g_param_spec_uint64 ("border-color", "Border Color", "ARGB representation of the border color to use", - 0, G_MAXUINT64, 0xffff000000000000, param_flags)); + 0, G_MAXUINT64, DEFAULT_BORDER_COLOR, param_flags)); g_object_class_install_property (object_class, PROP_VIDEO_DIRECTION, g_param_spec_enum ("video-direction", "Video Direction", "Video direction", GST_TYPE_VIDEO_ORIENTATION_METHOD, @@ -396,6 +448,18 @@ gst_d3d12_converter_class_init (GstD3D12ConverterClass * klass) g_param_spec_enum ("sampler-filter", "Sampler Filter", "Sampler Filter", GST_TYPE_D3D12_CONVERTER_SAMPLER_FILTER, DEFAULT_SAMPLER_FILTER, param_flags)); + g_object_class_install_property (object_class, PROP_HUE, + g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_HUE, + param_flags)); + g_object_class_install_property (object_class, PROP_SATURATION, + g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0, + DEFAULT_SATURATION, param_flags)); + g_object_class_install_property (object_class, PROP_BRIGHTNESS, + g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0, + DEFAULT_BRIGHTNESS, param_flags)); + g_object_class_install_property (object_class, PROP_CONTRAST, + g_param_spec_double ("contrast", "Contrast", "contrast", + 0.0, 2.0, DEFAULT_CONTRAST, param_flags)); GST_DEBUG_CATEGORY_INIT (gst_d3d12_converter_debug, "d3d12converter", 0, "d3d12converter"); @@ -446,6 +510,20 @@ update_dest_rect (GstD3D12Converter * self, gint * old_val, } } +static void +on_color_balance_updated (GstD3D12Converter * self) +{ + auto priv = self->priv; + + if (!priv->color_balance_enabled) + return; + + priv->need_color_balance = + gst_d3d12_converter_is_color_balance_needed (priv-> + const_data_dyn.hsvcFactor[0], priv->const_data_dyn.hsvcFactor[1], + priv->const_data_dyn.hsvcFactor[2], priv->const_data_dyn.hsvcFactor[3]); +} + static void gst_d3d12_converter_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -480,7 +558,7 @@ gst_d3d12_converter_set_property (GObject * object, guint prop_id, update_dest_rect (self, &priv->dest_height, value); break; case PROP_ALPHA: - priv->alpha = g_value_get_double (value); + priv->const_data_dyn.alphaFactor = g_value_get_double (value); break; case PROP_FILL_BORDER: { @@ -521,6 +599,30 @@ gst_d3d12_converter_set_property (GObject * object, guint prop_id, } break; } + case PROP_HUE: + if (priv->color_balance_enabled) { + priv->const_data_dyn.hsvcFactor[0] = g_value_get_double (value); + on_color_balance_updated (self); + } + break; + case PROP_SATURATION: + if (priv->color_balance_enabled) { + priv->const_data_dyn.hsvcFactor[1] = g_value_get_double (value); + on_color_balance_updated (self); + } + break; + case PROP_BRIGHTNESS: + if (priv->color_balance_enabled) { + priv->const_data_dyn.hsvcFactor[2] = g_value_get_double (value); + on_color_balance_updated (self); + } + break; + case PROP_CONTRAST: + if (priv->color_balance_enabled) { + priv->const_data_dyn.hsvcFactor[3] = g_value_get_double (value); + on_color_balance_updated (self); + } + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -561,7 +663,7 @@ gst_d3d12_converter_get_property (GObject * object, guint prop_id, g_value_set_int (value, priv->dest_height); break; case PROP_ALPHA: - g_value_set_double (value, priv->alpha); + g_value_set_double (value, priv->const_data_dyn.alphaFactor); break; case PROP_FILL_BORDER: g_value_set_boolean (value, priv->fill_border); @@ -575,6 +677,18 @@ gst_d3d12_converter_get_property (GObject * object, guint prop_id, case PROP_SAMPLER_FILTER: g_value_set_enum (value, priv->sampler_filter); break; + case PROP_HUE: + g_value_set_double (value, priv->const_data_dyn.hsvcFactor[0]); + break; + case PROP_SATURATION: + g_value_set_double (value, priv->const_data_dyn.hsvcFactor[1]); + break; + case PROP_BRIGHTNESS: + g_value_set_double (value, priv->const_data_dyn.hsvcFactor[2]); + break; + case PROP_CONTRAST: + g_value_set_double (value, priv->const_data_dyn.hsvcFactor[3]); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -685,53 +799,13 @@ static gboolean gst_d3d12_converter_create_sampler (GstD3D12Converter * self, D3D12_FILTER filter, ID3D12DescriptorHeap ** heap) { - auto priv = self->priv; - ComPtr < ID3D12DescriptorHeap > sampler_heap; auto hr = gst_d3d12_device_get_sampler_state (self->device, filter, &sampler_heap); if (!gst_d3d12_result (hr, self->device)) return FALSE; - if (priv->crs->HaveLut ()) { - D3D12_DESCRIPTOR_HEAP_DESC heap_desc = { }; - heap_desc.NumDescriptors = 1; - heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - - ComPtr < ID3D12DescriptorHeap > new_heap; - auto device = gst_d3d12_device_get_device_handle (self->device); - hr = device->CreateDescriptorHeap (&heap_desc, IID_PPV_ARGS (&new_heap)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create sampler heap"); - return FALSE; - } - - auto dst_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE - (GetCPUDescriptorHandleForHeapStart (new_heap)); - device->CopyDescriptorsSimple (1, dst_handle, - GetCPUDescriptorHandleForHeapStart (sampler_heap), - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - - if (filter != DEFAULT_SAMPLER_FILTER) { - hr = gst_d3d12_device_get_sampler_state (self->device, - DEFAULT_SAMPLER_FILTER, sampler_heap.ReleaseAndGetAddressOf ()); - - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create sampler heap"); - return FALSE; - } - } - - dst_handle.Offset (priv->sampler_inc_size); - device->CopyDescriptorsSimple (1, dst_handle, - GetCPUDescriptorHandleForHeapStart (sampler_heap), - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - - *heap = new_heap.Detach (); - } else { - *heap = sampler_heap.Detach (); - } + *heap = sampler_heap.Detach (); return TRUE; } @@ -758,21 +832,43 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, priv->sampler_inc_size = device->GetDescriptorHandleIncrementSize (D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - ComPtr < ID3DBlob > rs_blob; - priv->crs = - gst_d3d12_get_converter_root_signature (self->device, - GST_VIDEO_INFO_FORMAT (in_info), priv->convert_type); - if (!priv->crs) { - GST_ERROR_OBJECT (self, "Couldn't get root signature blob"); - return FALSE; - } + if (priv->color_balance_enabled) + priv->pipeline_data.resize (2); + else + priv->pipeline_data.resize (1); - priv->crs->GetBlob (&rs_blob); - hr = device->CreateRootSignature (0, rs_blob->GetBufferPointer (), - rs_blob->GetBufferSize (), IID_PPV_ARGS (&priv->rs)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create root signature"); - return FALSE; + for (size_t i = 0; i < priv->pipeline_data.size (); i++) { + ComPtr < ID3DBlob > rs_blob; + priv->pipeline_data[i].crs = + gst_d3d12_get_converter_root_signature (self->device, + GST_VIDEO_INFO_FORMAT (in_info), priv->convert_type[i]); + if (!priv->pipeline_data[0].crs) { + GST_ERROR_OBJECT (self, "Couldn't get root signature blob"); + return FALSE; + } + + priv->pipeline_data[i].crs->GetBlob (&rs_blob); + hr = device->CreateRootSignature (0, rs_blob->GetBufferPointer (), + rs_blob->GetBufferSize (), IID_PPV_ARGS (&priv->pipeline_data[i].rs)); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't create root signature"); + return FALSE; + } + + priv->pipeline_data[i].psblob_list = + gst_d3d12_get_converter_pixel_shader_blob (GST_VIDEO_INFO_FORMAT + (in_info), GST_VIDEO_INFO_FORMAT (out_info), + priv->src_alpha_mode == GST_D3D12_CONVERTER_ALPHA_MODE_PREMULTIPLIED, + priv->dst_alpha_mode == GST_D3D12_CONVERTER_ALPHA_MODE_PREMULTIPLIED, + priv->convert_type[i]); + + auto psblob_size = priv->pipeline_data[i].psblob_list.size (); + if (psblob_size == 0) { + GST_ERROR_OBJECT (self, "Couldn't get pixel shader blob"); + return FALSE; + } + + priv->pipeline_data[i].quad_data.resize (psblob_size); } if (!gst_d3d12_converter_create_sampler (self, sampler_filter, @@ -790,17 +886,6 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, priv->sampler_filter = sampler_filter; - auto psblob_list = - gst_d3d12_get_converter_pixel_shader_blob (GST_VIDEO_INFO_FORMAT - (in_info), GST_VIDEO_INFO_FORMAT (out_info), - priv->src_alpha_mode == GST_D3D12_CONVERTER_ALPHA_MODE_PREMULTIPLIED, - priv->dst_alpha_mode == GST_D3D12_CONVERTER_ALPHA_MODE_PREMULTIPLIED, - priv->convert_type); - if (psblob_list.empty ()) { - GST_ERROR_OBJECT (self, "Couldn't get pixel shader blob"); - return FALSE; - } - D3D12_SHADER_BYTECODE vs_blob; hr = gst_d3d12_get_converter_vertex_shader_blob (&vs_blob, priv->input_desc); if (!gst_d3d12_result (hr, self->device)) { @@ -819,45 +904,53 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, rtv_formats.push (format); } - priv->quad_data.resize (psblob_list.size ()); + for (size_t i = 0; i < priv->pipeline_data.size (); i++) { + auto & pipeline_data = priv->pipeline_data[i]; + for (size_t j = 0; j < pipeline_data.quad_data.size (); j++) { + auto & pso_desc = pipeline_data.quad_data[j].desc; - for (size_t i = 0; i < psblob_list.size (); i++) { - auto & pso_desc = priv->quad_data[i].desc; - pso_desc.pRootSignature = priv->rs.Get (); - pso_desc.VS = vs_blob; - pso_desc.PS = psblob_list[i].bytecode; - pso_desc.BlendState = priv->blend_desc; - pso_desc.SampleMask = UINT_MAX; - pso_desc.RasterizerState = CD3DX12_RASTERIZER_DESC (D3D12_DEFAULT); - pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - pso_desc.DepthStencilState.DepthEnable = FALSE; - pso_desc.DepthStencilState.StencilEnable = FALSE; - pso_desc.InputLayout.pInputElementDescs = priv->input_desc; - pso_desc.InputLayout.NumElements = 2; - pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - pso_desc.NumRenderTargets = psblob_list[i].num_rtv; - for (UINT j = 0; j < pso_desc.NumRenderTargets; j++) { - pso_desc.RTVFormats[j] = rtv_formats.front (); - rtv_formats.pop (); + pso_desc.pRootSignature = pipeline_data.rs.Get (); + pso_desc.VS = vs_blob; + pso_desc.PS = pipeline_data.psblob_list[j].bytecode; + pso_desc.BlendState = priv->blend_desc; + pso_desc.SampleMask = UINT_MAX; + pso_desc.RasterizerState = CD3DX12_RASTERIZER_DESC (D3D12_DEFAULT); + pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pso_desc.DepthStencilState.DepthEnable = FALSE; + pso_desc.DepthStencilState.StencilEnable = FALSE; + pso_desc.InputLayout.pInputElementDescs = priv->input_desc; + pso_desc.InputLayout.NumElements = 2; + pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pso_desc.NumRenderTargets = pipeline_data.psblob_list[j].num_rtv; + + for (UINT k = 0; k < pso_desc.NumRenderTargets; k++) { + if (i == 0) { + pso_desc.RTVFormats[k] = rtv_formats.front (); + rtv_formats.pop (); + } else { + pso_desc.RTVFormats[k] = + priv->pipeline_data[0].quad_data[j].desc.RTVFormats[k]; + } + } + pso_desc.SampleDesc.Count = sample_count; + pso_desc.SampleDesc.Quality = sample_quality; + + ComPtr < ID3D12PipelineState > pso; + hr = device->CreateGraphicsPipelineState (&pso_desc, IID_PPV_ARGS (&pso)); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't create PSO"); + return FALSE; + } + + pipeline_data.quad_data[j].pso = pso; + pipeline_data.quad_data[j].num_rtv = pipeline_data.psblob_list[j].num_rtv; } - pso_desc.SampleDesc.Count = sample_count; - pso_desc.SampleDesc.Quality = sample_quality; - - ComPtr < ID3D12PipelineState > pso; - hr = device->CreateGraphicsPipelineState (&pso_desc, IID_PPV_ARGS (&pso)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create PSO"); - return FALSE; - } - - priv->quad_data[i].pso = pso; - priv->quad_data[i].num_rtv = psblob_list[i].num_rtv; } D3D12_DESCRIPTOR_HEAP_DESC srv_heap_desc = { }; srv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - srv_heap_desc.NumDescriptors = priv->crs->GetNumSrv (); - if (priv->crs->HaveLut ()) + srv_heap_desc.NumDescriptors = priv->pipeline_data[0].crs->GetNumSrv (); + if (priv->have_lut) srv_heap_desc.NumDescriptors += 2; srv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; @@ -907,10 +1000,17 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); guint const_size = GST_ROUND_UP_N (g_const_buf_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); + guint other_const_off = GST_ROUND_UP_N (vertex_index_size + const_size, + D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); heap_prop = CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT); - resource_desc = - CD3DX12_RESOURCE_DESC::Buffer (vertex_index_size + const_size); + if (priv->color_balance_enabled) { + resource_desc = + CD3DX12_RESOURCE_DESC::Buffer (other_const_off + const_size); + } else { + resource_desc = + CD3DX12_RESOURCE_DESC::Buffer (vertex_index_size + const_size); + } hr = device->CreateCommittedResource (&heap_prop, heap_flags, &resource_desc, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS (&priv->shader_buf)); @@ -927,7 +1027,8 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, priv->idv.SizeInBytes = g_index_buf_size; priv->idv.Format = DXGI_FORMAT_R16_UINT; - priv->const_buf_addr = priv->vbv.BufferLocation + vertex_index_size; + priv->const_buf_addr[0] = priv->vbv.BufferLocation + vertex_index_size; + priv->const_buf_addr[1] = priv->vbv.BufferLocation + other_const_off; heap_prop = CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_UPLOAD); hr = device->CreateCommittedResource (&heap_prop, @@ -946,11 +1047,13 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, memcpy (data, vertex_data, g_vertex_buf_size); memcpy (data + g_vertex_buf_size, g_indices, g_index_buf_size); - memcpy (data + vertex_index_size, &priv->const_data, g_const_buf_size); + memcpy (data + vertex_index_size, &priv->const_data[0], g_const_buf_size); + if (priv->color_balance_enabled) + memcpy (data + other_const_off, &priv->const_data[1], g_const_buf_size); upload_buf->Unmap (0, nullptr); } - if (priv->crs->HaveLut ()) { + if (priv->have_lut) { heap_prop = CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT); resource_desc = CD3DX12_RESOURCE_DESC::Tex1D (DXGI_FORMAT_R16_UNORM, GAMMA_LUT_SIZE, 1, 1); @@ -995,7 +1098,12 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, } auto in_trc = in_info->colorimetry.transfer; - auto out_trc = out_info->colorimetry.transfer; + auto out_trc = in_info->colorimetry.transfer; + + if (priv->convert_type[0] == CONVERT_TYPE::GAMMA || + priv->convert_type[0] == CONVERT_TYPE::PRIMARY) { + out_trc = out_info->colorimetry.transfer; + } auto gamma_dec_table = gst_d3d12_converter_get_gamma_dec_table (in_trc); auto gamma_enc_table = gst_d3d12_converter_get_gamma_enc_table (out_trc); @@ -1082,7 +1190,7 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (priv->shader_buf. Get (), D3D12_RESOURCE_STATE_COPY_DEST, STATE_VERTEX_AND_INDEX)); - if (priv->crs->HaveLut ()) { + if (priv->have_lut) { D3D12_TEXTURE_COPY_LOCATION src; D3D12_TEXTURE_COPY_LOCATION dst; src = @@ -1502,9 +1610,9 @@ convert_info_gray_to_yuv (const GstVideoInfo * gray, GstVideoInfo * yuv) static gboolean gst_d3d12_converter_calculate_matrix (GstD3D12Converter * self, - const GstVideoInfo * in_info, const GstVideoInfo * out_info) + const GstVideoInfo * in_info, const GstVideoInfo * out_info, + CONVERT_TYPE convert_type, PSConstBuffer * const_data) { - auto priv = self->priv; GstD3D12ColorMatrix pre_coeff; GstD3D12ColorMatrix post_coeff; GstD3D12ColorMatrix primaries_coeff; @@ -1514,7 +1622,7 @@ gst_d3d12_converter_calculate_matrix (GstD3D12Converter * self, gst_d3d12_color_matrix_init (&post_coeff); gst_d3d12_color_matrix_init (&primaries_coeff); - switch (priv->convert_type) { + switch (convert_type) { case CONVERT_TYPE::RANGE: gst_d3d12_color_range_adjust_matrix_unorm (in_info, out_info, &post_coeff); @@ -1528,6 +1636,8 @@ gst_d3d12_converter_calculate_matrix (GstD3D12Converter * self, break; case CONVERT_TYPE::GAMMA: case CONVERT_TYPE::PRIMARY: + case CONVERT_TYPE::COLOR_BALANCE: + case CONVERT_TYPE::PRIMARY_AND_COLOR_BALANCE: if (GST_VIDEO_INFO_IS_RGB (in_info)) { rgb_info = *in_info; if (in_info->colorimetry.range == GST_VIDEO_COLOR_RANGE_16_235) { @@ -1547,7 +1657,8 @@ gst_d3d12_converter_calculate_matrix (GstD3D12Converter * self, gst_d3d12_yuv_to_rgb_matrix_unorm (in_info, &rgb_info, &pre_coeff); } - if (priv->convert_type == CONVERT_TYPE::PRIMARY) { + if (convert_type == CONVERT_TYPE::PRIMARY || + convert_type == CONVERT_TYPE::PRIMARY_AND_COLOR_BALANCE) { const GstVideoColorPrimariesInfo *in_pinfo; const GstVideoColorPrimariesInfo *out_pinfo; @@ -1592,9 +1703,9 @@ gst_d3d12_converter_calculate_matrix (GstD3D12Converter * self, g_free (matrix_dump); } - PSColorSpace *preCoeff = &priv->const_data.preCoeff; - PSColorSpace *postCoeff = &priv->const_data.postCoeff; - PSColorSpace *primariesCoeff = &priv->const_data.primariesCoeff; + PSColorSpace *preCoeff = &const_data->preCoeff; + PSColorSpace *postCoeff = &const_data->postCoeff; + PSColorSpace *primariesCoeff = &const_data->primariesCoeff; for (guint i = 0; i < 3; i++) { preCoeff->coeffX[i] = pre_coeff.matrix[0][i]; @@ -1941,6 +2052,13 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, allow_primaries = TRUE; } + if (gst_structure_get_enum (config, GST_D3D12_CONVERTER_OPT_COLOR_BALANCE, + GST_TYPE_D3D12_CONVERTER_COLOR_BALANCE, &value) && + (GstD3D12ConverterColorBalance) value != + GST_D3D12_CONVERTER_COLOR_BALANCE_DISABLED) { + priv->color_balance_enabled = TRUE; + } + gst_structure_get_enum (config, GST_D3D12_CONVERTER_OPT_SAMPLER_FILTER, GST_TYPE_D3D12_CONVERTER_SAMPLER_FILTER, (int *) &sampler_filter); @@ -1992,8 +2110,6 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, priv->src_height = GST_VIDEO_INFO_HEIGHT (in_info); priv->dest_width = GST_VIDEO_INFO_WIDTH (out_info); priv->dest_height = GST_VIDEO_INFO_HEIGHT (out_info); - priv->alpha = 1.0; - priv->border_color = 0xffff000000000000; if (GST_VIDEO_INFO_IS_RGB (&priv->out_info)) { GstVideoInfo rgb_info = priv->out_info; @@ -2020,13 +2136,14 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, gst_d3d12_converter_calculate_border_color (self); - priv->convert_type = CONVERT_TYPE::IDENTITY; + priv->convert_type[0] = CONVERT_TYPE::IDENTITY; + priv->convert_type[1] = CONVERT_TYPE::COLOR_BALANCE; if (GST_VIDEO_INFO_IS_RGB (in_info) != GST_VIDEO_INFO_IS_RGB (out_info)) { - priv->convert_type = CONVERT_TYPE::SIMPLE; + priv->convert_type[0] = CONVERT_TYPE::SIMPLE; } else if (in_info->colorimetry.range != GST_VIDEO_COLOR_RANGE_UNKNOWN && out_info->colorimetry.range != GST_VIDEO_COLOR_RANGE_UNKNOWN && in_info->colorimetry.range != out_info->colorimetry.range) { - priv->convert_type = CONVERT_TYPE::RANGE; + priv->convert_type[0] = CONVERT_TYPE::RANGE; } if (allow_gamma && @@ -2038,7 +2155,7 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, 0))) { GST_DEBUG_OBJECT (self, "Different transfer function %d -> %d", in_info->colorimetry.transfer, out_info->colorimetry.transfer); - priv->convert_type = CONVERT_TYPE::GAMMA; + priv->convert_type[0] = CONVERT_TYPE::GAMMA; } if (allow_primaries && @@ -2050,7 +2167,8 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, out_info->colorimetry.primaries)) { GST_DEBUG_OBJECT (self, "Different primaries %d -> %d", in_info->colorimetry.primaries, out_info->colorimetry.primaries); - priv->convert_type = CONVERT_TYPE::PRIMARY; + priv->convert_type[0] = CONVERT_TYPE::PRIMARY; + priv->convert_type[1] = CONVERT_TYPE::PRIMARY_AND_COLOR_BALANCE; } if (GST_VIDEO_INFO_IS_RGB (&priv->in_info)) { @@ -2074,11 +2192,26 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue, } if (!gst_d3d12_converter_calculate_matrix (self, - &matrix_in_info, &matrix_out_info)) { + &matrix_in_info, &matrix_out_info, priv->convert_type[0], + &priv->const_data[0])) { gst_object_unref (self); return nullptr; } + if (priv->color_balance_enabled && + !gst_d3d12_converter_calculate_matrix (self, + &matrix_in_info, &matrix_out_info, priv->convert_type[1], + &priv->const_data[1])) { + gst_object_unref (self); + return nullptr; + } + + if (priv->convert_type[0] == CONVERT_TYPE::GAMMA || + priv->convert_type[0] == CONVERT_TYPE::PRIMARY || + priv->color_balance_enabled) { + priv->have_lut = TRUE; + } + if (!gst_d3d12_converter_setup_resource (self, &priv->in_info, &priv->out_info, &in_d3d12_format, &out_d3d12_format, sampler_filter, sample_count, sample_quality)) { @@ -2096,32 +2229,36 @@ gst_d3d12_converter_update_pso (GstD3D12Converter * self) if (!priv->update_pso) return TRUE; - std::vector < QuadData > quad_data; - quad_data.resize (priv->quad_data.size ()); - + priv->update_pso = FALSE; auto device = gst_d3d12_device_get_device_handle (self->device); + for (size_t i = 0; i < priv->pipeline_data.size (); i++) { + auto & pipeline_data = priv->pipeline_data[i]; - for (size_t i = 0; i < quad_data.size (); i++) { - D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = priv->quad_data[i].desc; - pso_desc.BlendState = priv->blend_desc; - pso_desc.SampleDesc = priv->sample_desc; + std::vector < QuadData > quad_data; + quad_data.resize (pipeline_data.quad_data.size ()); - ComPtr < ID3D12PipelineState > pso; - auto hr = - device->CreateGraphicsPipelineState (&pso_desc, IID_PPV_ARGS (&pso)); - if (!gst_d3d12_result (hr, self->device)) { - GST_ERROR_OBJECT (self, "Couldn't create pso"); - return FALSE; + for (size_t j = 0; j < quad_data.size (); j++) { + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = + pipeline_data.quad_data[j].desc; + pso_desc.BlendState = priv->blend_desc; + pso_desc.SampleDesc = priv->sample_desc; + + ComPtr < ID3D12PipelineState > pso; + auto hr = + device->CreateGraphicsPipelineState (&pso_desc, IID_PPV_ARGS (&pso)); + if (!gst_d3d12_result (hr, self->device)) { + GST_ERROR_OBJECT (self, "Couldn't create pso"); + return FALSE; + } + + quad_data[j].desc = pso_desc; + quad_data[j].pso = pso; + quad_data[j].num_rtv = pipeline_data.quad_data[j].num_rtv; } - quad_data[i].desc = pso_desc; - quad_data[i].pso = pso; - quad_data[i].num_rtv = priv->quad_data[i].num_rtv; + pipeline_data.quad_data = quad_data; } - priv->update_pso = FALSE; - priv->quad_data = quad_data; - return TRUE; } @@ -2236,7 +2373,7 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame, cpu_handle.Offset (priv->srv_inc_size); } - if (priv->crs->HaveLut ()) { + if (priv->have_lut) { device->CopyDescriptorsSimple (2, cpu_handle, GetCPUDescriptorHandleForHeapStart (priv->gamma_lut_heap), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); @@ -2253,30 +2390,32 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame, reorder_rtv_handles (GST_VIDEO_INFO_FORMAT (&priv->out_info), out_frame->rtv_desc_handle, reordered_rtv_handle); - auto pso = priv->quad_data[0].pso.Get (); + guint pipeline_index = priv->need_color_balance ? 1 : 0; + auto & pipeline_data = priv->pipeline_data[pipeline_index]; - cl->SetGraphicsRootSignature (priv->rs.Get ()); + auto pso = pipeline_data.quad_data[0].pso.Get (); + cl->SetGraphicsRootSignature (pipeline_data.rs.Get ()); cl->SetPipelineState (pso); ID3D12DescriptorHeap *heaps[] = { srv_heap, priv->sampler_heap.Get () }; cl->SetDescriptorHeaps (2, heaps); - cl->SetGraphicsRootDescriptorTable (priv->crs->GetPsSrvIdx (), + cl->SetGraphicsRootDescriptorTable (pipeline_data.crs->GetPsSrvIdx (), GetGPUDescriptorHandleForHeapStart (srv_heap)); - cl->SetGraphicsRootDescriptorTable (priv->crs->GetPsSamplerIdx (), + cl->SetGraphicsRootDescriptorTable (pipeline_data.crs->GetPsSamplerIdx (), GetGPUDescriptorHandleForHeapStart (priv->sampler_heap)); - cl->SetGraphicsRoot32BitConstants (priv->crs->GetVsRootConstIdx (), + cl->SetGraphicsRoot32BitConstants (pipeline_data.crs->GetVsRootConstIdx (), 16, &priv->transform, 0); - cl->SetGraphicsRoot32BitConstants (priv->crs->GetPsRootConstIdx (), - 1, &priv->alpha, 0); - cl->SetGraphicsRootConstantBufferView (priv->crs->GetPsCbvIdx (), - priv->const_buf_addr); + cl->SetGraphicsRoot32BitConstants (pipeline_data.crs->GetPsRootConstIdx (), + sizeof (priv->const_data_dyn) / 4, &priv->const_data_dyn, 0); + cl->SetGraphicsRootConstantBufferView (pipeline_data.crs->GetPsCbvIdx (), + priv->const_buf_addr[pipeline_index]); cl->IASetIndexBuffer (&priv->idv); cl->IASetVertexBuffers (0, 1, &priv->vbv); cl->IASetPrimitiveTopology (D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); cl->RSSetViewports (1, priv->viewport); cl->RSSetScissorRects (1, priv->scissor_rect); - cl->OMSetRenderTargets (priv->quad_data[0].num_rtv, + cl->OMSetRenderTargets (pipeline_data.quad_data[0].num_rtv, reordered_rtv_handle, FALSE, nullptr); cl->OMSetBlendFactor (priv->blend_factor); cl->DrawIndexedInstanced (6, 1, 0, 0, 0); @@ -2284,14 +2423,14 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame, pso->AddRef (); gst_d3d12_fence_data_push (fence_data, FENCE_NOTIFY_COM (pso)); - auto offset = priv->quad_data[0].num_rtv; - if (priv->quad_data.size () == 2) { - pso = priv->quad_data[1].pso.Get (); + auto offset = pipeline_data.quad_data[0].num_rtv; + if (pipeline_data.quad_data.size () == 2) { + pso = pipeline_data.quad_data[1].pso.Get (); cl->SetPipelineState (pso); cl->RSSetViewports (1, &priv->viewport[offset]); cl->RSSetScissorRects (1, &priv->scissor_rect[offset]); - cl->OMSetRenderTargets (priv->quad_data[1].num_rtv, + cl->OMSetRenderTargets (pipeline_data.quad_data[1].num_rtv, reordered_rtv_handle + offset, FALSE, nullptr); cl->DrawIndexedInstanced (6, 1, 0, 0, 0); @@ -2524,3 +2663,18 @@ gst_d3d12_converter_apply_transform (GstD3D12Converter * converter, return TRUE; } + +gboolean +gst_d3d12_converter_is_color_balance_needed (gfloat hue, gfloat saturation, + gfloat brightness, gfloat contrast) +{ + const float min_diff = 0.0000000001f; + if (fabsf (hue - DEFAULT_HUE) >= min_diff || + fabsf (saturation - DEFAULT_SATURATION) >= min_diff || + fabsf (brightness - DEFAULT_BRIGHTNESS) >= min_diff || + fabsf (contrast - DEFAULT_CONTRAST) >= min_diff) { + return TRUE; + } + + return FALSE; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.h index 8f14da395b..48721fbbb3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12converter.h @@ -136,6 +136,32 @@ GType gst_d3d12_converter_alpha_mode_get_type (void); */ #define GST_D3D12_CONVERTER_OPT_PSO_SAMPLE_DESC_QUALITY "GstD3D12Converter.pso-sample-desc-quality" +/** + * GstD3D12ConverterColorBalance: + * @GST_D3D12_CONVERTER_COLOR_BALANCE_DISABLED: Disable color-balance feature + * @GST_D3D12_CONVERTER_COLOR_BALANCE_ENABLED: Enable color-balance feature + * + * Since: 1.26 + */ +typedef enum +{ + GST_D3D12_CONVERTER_COLOR_BALANCE_DISABLED, + GST_D3D12_CONVERTER_COLOR_BALANCE_ENABLED, +} GstD3D12ConverterColorBalance; + +GST_D3D12_API +GType gst_d3d12_converter_color_balance_get_type (void); +#define GST_TYPE_D3D12_CONVERTER_COLOR_BALANCE (gst_d3d12_converter_color_balance_get_type()) + +/** + * GST_D3D12_CONVERTER_OPT_COLOR_BALANCE: + * + * #GstD3D12ConverterColorBalance, an option to enable color-balance feature + * + * Since: 1.26 + */ +#define GST_D3D12_CONVERTER_OPT_COLOR_BALANCE "GstD3D12Converter.color-balance" + /** * GstD3D12Converter: * diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12device.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12device.cpp index 4340cf9225..0cc0323dc4 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12device.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d12/gstd3d12device.cpp @@ -2192,7 +2192,7 @@ gst_d3d12_device_get_sampler_state (GstD3D12Device * device, } else { ComPtr < ID3D12DescriptorHeap > new_heap; D3D12_DESCRIPTOR_HEAP_DESC heap_desc = { }; - heap_desc.NumDescriptors = 1; + heap_desc.NumDescriptors = 2; heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; @@ -2214,7 +2214,15 @@ gst_d3d12_device_get_sampler_state (GstD3D12Device * device, sampler_desc.MinLOD = 0; sampler_desc.MaxLOD = D3D12_FLOAT32_MAX; - auto cpu_handle = GetCPUDescriptorHandleForHeapStart (new_heap); + auto cpu_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE + (GetCPUDescriptorHandleForHeapStart (new_heap)); + priv->device->CreateSampler (&sampler_desc, cpu_handle); + + sampler_desc.MaxAnisotropy = 1; + sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; + auto inc_size = priv->device->GetDescriptorHandleIncrementSize + (D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + cpu_handle.Offset (inc_size); priv->device->CreateSampler (&sampler_desc, cpu_handle); priv->samplers[filter] = new_heap; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/converter-hlsl/PSMain_converter.hlsl b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/converter-hlsl/PSMain_converter.hlsl index 9df26cccc1..0f04bc1321 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/converter-hlsl/PSMain_converter.hlsl +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/converter-hlsl/PSMain_converter.hlsl @@ -18,9 +18,11 @@ */ #ifdef BUILDING_HLSL -cbuffer PsAlphaFactor : register(b1) +cbuffer PsConstBufferDyn : register(b1) { float alphaFactor; + float3 padding_0; + float4 hsvcFactor; }; struct PSColorSpace @@ -671,6 +673,75 @@ class ConverterGamma : IConverter } }; +float3 AdjustContrast (float3 color) +{ + return saturate(lerp(float3(0.5, 0.5, 0.5), color, hsvcFactor.w)); +} + +float3 AdjustHSV (float3 color) +{ + color.x = frac(color.x + hsvcFactor.x / 2.0); // hue + color.y = saturate(color.y * hsvcFactor.y); // saturation + color.z = saturate(color.z * (hsvcFactor.z + 1.0)); // brightness + return color; +} + +float3 RGB2HSV(float3 color) +{ + float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + float4 p = color.g < color.b ? float4(color.bg, K.wz) : float4(color.gb, K.xy); + float4 q = color.r < p.x ? float4(p.xyw, color.r) : float4(color.r, p.yzx); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +float3 HSV2RGB(float3 color) +{ + float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float3 p = abs(frac(color.xxx + K.xyz) * 6.0 - K.www); + return color.z * lerp(K.xxx, saturate(p - K.xxx), color.y); +} + +float3 DoColorBalance(float3 color) +{ + color = AdjustContrast(color); + color = RGB2HSV(color); + color = AdjustHSV(color); + return HSV2RGB(color); +} + +class ConverterColorBalance : IConverter +{ + float4 Execute (float4 sample) + { + float3 rgb_space; + float3 out_space; + rgb_space.x = dot (preCoeff.CoeffX, sample.xyz); + rgb_space.y = dot (preCoeff.CoeffY, sample.xyz); + rgb_space.z = dot (preCoeff.CoeffZ, sample.xyz); + rgb_space += preCoeff.Offset; + rgb_space = clamp (rgb_space, preCoeff.Min, preCoeff.Max); + + rgb_space.x = gammaDecLUT.Sample (lutSamplerState, rgb_space.x); + rgb_space.y = gammaDecLUT.Sample (lutSamplerState, rgb_space.y); + rgb_space.z = gammaDecLUT.Sample (lutSamplerState, rgb_space.z); + + rgb_space.xyz = DoColorBalance(rgb_space.xyz); + + rgb_space.x = gammaEncLUT.Sample (lutSamplerState, rgb_space.x); + rgb_space.y = gammaEncLUT.Sample (lutSamplerState, rgb_space.y); + rgb_space.z = gammaEncLUT.Sample (lutSamplerState, rgb_space.z); + + out_space.x = dot (postCoeff.CoeffX, rgb_space); + out_space.y = dot (postCoeff.CoeffY, rgb_space); + out_space.z = dot (postCoeff.CoeffZ, rgb_space); + out_space += postCoeff.Offset; + return float4 (clamp (out_space, postCoeff.Min, postCoeff.Max), sample.a); + } +}; + class ConverterPrimary : IConverter { float4 Execute (float4 sample) @@ -705,6 +776,42 @@ class ConverterPrimary : IConverter } }; +class ConverterPrimaryAndColorBalance : IConverter +{ + float4 Execute (float4 sample) + { + float3 rgb_space; + float3 primary_converted; + float3 out_space; + + rgb_space.x = dot (preCoeff.CoeffX, sample.xyz); + rgb_space.y = dot (preCoeff.CoeffY, sample.xyz); + rgb_space.z = dot (preCoeff.CoeffZ, sample.xyz); + rgb_space += preCoeff.Offset; + rgb_space = clamp (rgb_space, preCoeff.Min, preCoeff.Max); + + rgb_space.x = gammaDecLUT.Sample (lutSamplerState, rgb_space.x); + rgb_space.y = gammaDecLUT.Sample (lutSamplerState, rgb_space.y); + rgb_space.z = gammaDecLUT.Sample (lutSamplerState, rgb_space.z); + + primary_converted.x = dot (primariesCoeff.CoeffX, rgb_space); + primary_converted.y = dot (primariesCoeff.CoeffY, rgb_space); + primary_converted.z = dot (primariesCoeff.CoeffZ, rgb_space); + + primary_converted.xyz = DoColorBalance(primary_converted.xyz); + + rgb_space.x = gammaEncLUT.Sample (lutSamplerState, primary_converted.x); + rgb_space.y = gammaEncLUT.Sample (lutSamplerState, primary_converted.y); + rgb_space.z = gammaEncLUT.Sample (lutSamplerState, primary_converted.z); + + out_space.x = dot (postCoeff.CoeffX, rgb_space); + out_space.y = dot (postCoeff.CoeffY, rgb_space); + out_space.z = dot (postCoeff.CoeffZ, rgb_space); + out_space += postCoeff.Offset; + return float4 (clamp (out_space, postCoeff.Min, postCoeff.Max), sample.a); + } +}; + float UnormTo10bit (float sample) { return sample * 1023.0 / 65535.0; @@ -1357,9 +1464,11 @@ OUTPUT_TYPE ENTRY_POINT (PS_INPUT input) } #else /* BUILDING_HLSL */ static const char str_PSMain_converter[] = -"cbuffer PsAlphaFactor : register(b1)\n" +"cbuffer PsConstBufferDyn : register(b1)\n" "{\n" " float alphaFactor;\n" +" float3 padding_0;\n" +" float4 hsvcFactor;\n" "};\n" "\n" "struct PSColorSpace\n" @@ -2010,6 +2119,75 @@ static const char str_PSMain_converter[] = " }\n" "};\n" "\n" +"float3 AdjustContrast (float3 color)\n" +"{\n" +" return saturate(lerp(float3(0.5, 0.5, 0.5), color, hsvcFactor.w));\n" +"}\n" +"\n" +"float3 AdjustHSV (float3 color)\n" +"{\n" +" color.x = frac(color.x + hsvcFactor.x / 2.0); // hue\n" +" color.y = saturate(color.y * hsvcFactor.y); // saturation\n" +" color.z = saturate(color.z * (hsvcFactor.z + 1.0)); // brightness\n" +" return color;\n" +"}\n" +"\n" +"float3 RGB2HSV(float3 color)\n" +"{\n" +" float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n" +" float4 p = color.g < color.b ? float4(color.bg, K.wz) : float4(color.gb, K.xy);\n" +" float4 q = color.r < p.x ? float4(p.xyw, color.r) : float4(color.r, p.yzx);\n" +"\n" +" float d = q.x - min(q.w, q.y);\n" +" float e = 1.0e-10;\n" +" return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n" +"}\n" +"\n" +"float3 HSV2RGB(float3 color)\n" +"{\n" +" float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n" +" float3 p = abs(frac(color.xxx + K.xyz) * 6.0 - K.www);\n" +" return color.z * lerp(K.xxx, saturate(p - K.xxx), color.y);\n" +"}\n" +"\n" +"float3 DoColorBalance(float3 color)\n" +"{\n" +" color = AdjustContrast(color);\n" +" color = RGB2HSV(color);\n" +" color = AdjustHSV(color);\n" +" return HSV2RGB(color);\n" +"}\n" +"\n" +"class ConverterColorBalance : IConverter\n" +"{\n" +" float4 Execute (float4 sample)\n" +" {\n" +" float3 rgb_space;\n" +" float3 out_space;\n" +" rgb_space.x = dot (preCoeff.CoeffX, sample.xyz);\n" +" rgb_space.y = dot (preCoeff.CoeffY, sample.xyz);\n" +" rgb_space.z = dot (preCoeff.CoeffZ, sample.xyz);\n" +" rgb_space += preCoeff.Offset;\n" +" rgb_space = clamp (rgb_space, preCoeff.Min, preCoeff.Max);\n" +"\n" +" rgb_space.x = gammaDecLUT.Sample (lutSamplerState, rgb_space.x);\n" +" rgb_space.y = gammaDecLUT.Sample (lutSamplerState, rgb_space.y);\n" +" rgb_space.z = gammaDecLUT.Sample (lutSamplerState, rgb_space.z);\n" +"\n" +" rgb_space.xyz = DoColorBalance(rgb_space.xyz);\n" +"\n" +" rgb_space.x = gammaEncLUT.Sample (lutSamplerState, rgb_space.x);\n" +" rgb_space.y = gammaEncLUT.Sample (lutSamplerState, rgb_space.y);\n" +" rgb_space.z = gammaEncLUT.Sample (lutSamplerState, rgb_space.z);\n" +"\n" +" out_space.x = dot (postCoeff.CoeffX, rgb_space);\n" +" out_space.y = dot (postCoeff.CoeffY, rgb_space);\n" +" out_space.z = dot (postCoeff.CoeffZ, rgb_space);\n" +" out_space += postCoeff.Offset;\n" +" return float4 (clamp (out_space, postCoeff.Min, postCoeff.Max), sample.a);\n" +" }\n" +"};\n" +"\n" "class ConverterPrimary : IConverter\n" "{\n" " float4 Execute (float4 sample)\n" @@ -2044,6 +2222,42 @@ static const char str_PSMain_converter[] = " }\n" "};\n" "\n" +"class ConverterPrimaryAndColorBalance : IConverter\n" +"{\n" +" float4 Execute (float4 sample)\n" +" {\n" +" float3 rgb_space;\n" +" float3 primary_converted;\n" +" float3 out_space;\n" +"\n" +" rgb_space.x = dot (preCoeff.CoeffX, sample.xyz);\n" +" rgb_space.y = dot (preCoeff.CoeffY, sample.xyz);\n" +" rgb_space.z = dot (preCoeff.CoeffZ, sample.xyz);\n" +" rgb_space += preCoeff.Offset;\n" +" rgb_space = clamp (rgb_space, preCoeff.Min, preCoeff.Max);\n" +"\n" +" rgb_space.x = gammaDecLUT.Sample (lutSamplerState, rgb_space.x);\n" +" rgb_space.y = gammaDecLUT.Sample (lutSamplerState, rgb_space.y);\n" +" rgb_space.z = gammaDecLUT.Sample (lutSamplerState, rgb_space.z);\n" +"\n" +" primary_converted.x = dot (primariesCoeff.CoeffX, rgb_space);\n" +" primary_converted.y = dot (primariesCoeff.CoeffY, rgb_space);\n" +" primary_converted.z = dot (primariesCoeff.CoeffZ, rgb_space);\n" +"\n" +" primary_converted.xyz = DoColorBalance(primary_converted.xyz);\n" +"\n" +" rgb_space.x = gammaEncLUT.Sample (lutSamplerState, primary_converted.x);\n" +" rgb_space.y = gammaEncLUT.Sample (lutSamplerState, primary_converted.y);\n" +" rgb_space.z = gammaEncLUT.Sample (lutSamplerState, primary_converted.z);\n" +"\n" +" out_space.x = dot (postCoeff.CoeffX, rgb_space);\n" +" out_space.y = dot (postCoeff.CoeffY, rgb_space);\n" +" out_space.z = dot (postCoeff.CoeffZ, rgb_space);\n" +" out_space += postCoeff.Offset;\n" +" return float4 (clamp (out_space, postCoeff.Min, postCoeff.Max), sample.a);\n" +" }\n" +"};\n" +"\n" "float UnormTo10bit (float sample)\n" "{\n" " return sample * 1023.0 / 65535.0;\n" @@ -2236,6 +2450,7 @@ static const char str_PSMain_converter[] = " return output;\n" " }\n" "};\n" +"\n" "interface IOutputPlanar\n" "{\n" " PS_OUTPUT_PLANAR Build (float4 sample);\n" diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.cpp index ff82947f96..7caaffe1cd 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.cpp @@ -1031,6 +1031,12 @@ gst_d3d_converter_shader_get_ps_blob (GstVideoFormat in_format, case GST_D3D_CONVERTER_PRIMARY: conv_type_str = "Primary"; break; + case GST_D3D_CONVERTER_COLOR_BALANCE: + conv_type_str = "ColorBalance"; + break; + case GST_D3D_CONVERTER_PRIMARY_AND_COLOR_BALANCE: + conv_type_str = "PrimaryAndColorBalance"; + break; default: g_assert_not_reached (); return 0; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.h index 1b7c474ec4..cd51b1b506 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3dshader/gstd3dshadercache.h @@ -78,6 +78,8 @@ typedef enum GST_D3D_CONVERTER_RANGE, GST_D3D_CONVERTER_GAMMA, GST_D3D_CONVERTER_PRIMARY, + GST_D3D_CONVERTER_COLOR_BALANCE, + GST_D3D_CONVERTER_PRIMARY_AND_COLOR_BALANCE, } GstD3DConverterType; typedef struct _GstD3DConverterCSByteCode