d3d12converter: Add support multiple UV remap in a single path

Add private methods for multiple UV remap operation

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9209>
This commit is contained in:
Seungha Yang 2025-06-12 20:15:15 +09:00 committed by GStreamer Marge Bot
parent 59eaf4cc39
commit ad6ce32a74
2 changed files with 228 additions and 71 deletions

View File

@ -48,4 +48,22 @@ GST_D3D12_API
gboolean gst_d3d12_converter_set_remap (GstD3D12Converter * converter,
ID3D12Resource * remap_vector);
GST_D3D12_API
gboolean gst_d3d12_converter_update_viewport (GstD3D12Converter * converter,
gint x,
gint y,
gint width,
gint height);
GST_D3D12_API
gboolean gst_d3d12_converter_convert_buffer_for_uv_remap (GstD3D12Converter * converter,
GstBuffer * in_buf,
GstBuffer * out_buf,
GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * command_list,
gboolean execute_gpu_wait,
guint num_remap,
ID3D12Resource ** lut,
GstVideoRectangle * viewport);
G_END_DECLS

View File

@ -325,7 +325,6 @@ struct ConvertCtxCommon
D3D12_RECT scissor_rect[GST_VIDEO_MAX_PLANES];
ComPtr<ID3D12Fence> setup_fence;
guint64 setup_fence_val = 0;
gboolean have_lut = FALSE;
gboolean need_color_balance = FALSE;
PSConstBufferDyn const_data_dyn;
};
@ -472,6 +471,12 @@ static void gst_d3d12_converter_get_property (GObject * object, guint prop_id,
static void gst_d3d12_converter_finalize (GObject * object);
static void
gst_d3d12_converter_calculate_border_color (GstD3D12Converter * self);
static gboolean
gst_d3d12_converter_set_remap_unlocked (GstD3D12Converter * self,
ID3D12Resource * remap_vector);
static gboolean
gst_d3d12_converter_update_viewport_unlocked (GstD3D12Converter * self,
gint x, gint y, gint width, gint height);
#define gst_d3d12_converter_parent_class parent_class
G_DEFINE_TYPE (GstD3D12Converter, gst_d3d12_converter, GST_TYPE_OBJECT);
@ -868,7 +873,7 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
const GstVideoInfo * in_info, const GstVideoInfo * out_info,
D3D12_FILTER sampler_filter, const DXGI_SAMPLE_DESC * sample_desc,
const D3D12_BLEND_DESC * blend_desc,
CONVERT_TYPE * convert_type, gboolean have_lut,
CONVERT_TYPE * convert_type,
gboolean color_balance_enabled, GstD3D12ConverterAlphaMode src_alpha,
GstD3D12ConverterAlphaMode dst_alpha, PSConstBuffer * const_data,
ConvertCtxCommonPtr ref)
@ -878,6 +883,7 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
VertexData vertex_data[4];
ComPtr < ID3D12Resource > upload_buf;
GstD3D12Format in_format, out_format;
gboolean have_lut = FALSE;
if (!gst_d3d12_device_get_format (self->device,
GST_VIDEO_INFO_FORMAT (in_info), &in_format)) {
@ -937,6 +943,8 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
}
ctx->pipeline_data[i].quad_data.resize (psblob_size);
if (ctx->pipeline_data[i].crs->HaveLut ())
have_lut = TRUE;
}
D3D12_SHADER_BYTECODE vs_blob;
@ -1014,7 +1022,6 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
ctx->comm = std::make_shared < ConvertCtxCommon > ();
auto comm = ctx->comm;
comm->have_lut = have_lut;
if (!gst_d3d12_converter_create_sampler (self, sampler_filter,
&comm->sampler_heap)) {
@ -1952,14 +1959,12 @@ static gboolean
gst_d3d12_converter_setup_colorspace (GstD3D12Converter * self,
const GstVideoInfo * in_info, const GstVideoInfo * out_info,
gboolean allow_gamma, gboolean allow_primaries,
gboolean color_balance_enabled, gboolean * have_lut,
CONVERT_TYPE * convert_type, PSConstBuffer * const_data)
gboolean color_balance_enabled, CONVERT_TYPE * convert_type,
PSConstBuffer * const_data)
{
GstVideoInfo matrix_in_info;
GstVideoInfo matrix_out_info;
*have_lut = FALSE;
convert_type[0] = CONVERT_TYPE::IDENTITY;
convert_type[1] = CONVERT_TYPE::COLOR_BALANCE;
if (GST_VIDEO_INFO_IS_RGB (in_info) != GST_VIDEO_INFO_IS_RGB (out_info)) {
@ -2026,11 +2031,6 @@ gst_d3d12_converter_setup_colorspace (GstD3D12Converter * self,
return FALSE;
}
if (convert_type[0] == CONVERT_TYPE::GAMMA ||
convert_type[0] == CONVERT_TYPE::PRIMARY || color_balance_enabled) {
*have_lut = TRUE;
}
return TRUE;
}
@ -2225,7 +2225,6 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue,
PSConstBuffer const_data[2];
CONVERT_TYPE convert_type[2];
gboolean have_lut = FALSE;
if (priv->mipgen_enabled) {
GstVideoFormat mipgen_format = GST_VIDEO_FORMAT_RGBA;
@ -2265,7 +2264,7 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue,
* a supported mip format */
if (mipgen_format != GST_VIDEO_INFO_FORMAT (&priv->in_info)) {
if (!gst_d3d12_converter_setup_colorspace (self, &priv->in_info,
&priv->mipgen_info, FALSE, FALSE, FALSE, &have_lut, convert_type,
&priv->mipgen_info, FALSE, FALSE, FALSE, convert_type,
const_data)) {
gst_object_unref (self);
return nullptr;
@ -2279,7 +2278,7 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue,
priv->mipgen_ctx =
gst_d3d12_converter_setup_resource (self, &priv->in_info,
&priv->mipgen_info, DEFAULT_SAMPLER_FILTER, &sample_desc_default,
&blend_desc_default, convert_type, have_lut, FALSE,
&blend_desc_default, convert_type, FALSE,
GST_D3D12_CONVERTER_ALPHA_MODE_STRAIGHT,
GST_D3D12_CONVERTER_ALPHA_MODE_STRAIGHT, const_data, nullptr);
if (!priv->mipgen_ctx) {
@ -2329,14 +2328,14 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue,
if (!gst_d3d12_converter_setup_colorspace (self, &priv->in_info,
&priv->out_info, allow_gamma, allow_primaries,
priv->color_balance_enabled, &have_lut, convert_type, const_data)) {
priv->color_balance_enabled, convert_type, const_data)) {
gst_object_unref (self);
return nullptr;
}
priv->main_ctx = gst_d3d12_converter_setup_resource (self, &priv->in_info,
&priv->out_info, sampler_filter, &priv->sample_desc, &priv->blend_desc,
convert_type, have_lut, priv->color_balance_enabled,
convert_type, priv->color_balance_enabled,
priv->src_alpha_mode, priv->dst_alpha_mode, const_data, nullptr);
if (!priv->main_ctx) {
gst_object_unref (self);
@ -2346,14 +2345,14 @@ gst_d3d12_converter_new (GstD3D12Device * device, GstD3D12CmdQueue * queue,
if (priv->mipgen_ctx) {
if (!gst_d3d12_converter_setup_colorspace (self, &priv->mipgen_info,
&priv->out_info, allow_gamma, allow_primaries,
priv->color_balance_enabled, &have_lut, convert_type, const_data)) {
priv->color_balance_enabled, convert_type, const_data)) {
gst_object_unref (self);
return nullptr;
}
priv->post_mipgen_ctx = gst_d3d12_converter_setup_resource (self,
&priv->mipgen_info, &priv->out_info, sampler_filter, &priv->sample_desc,
&priv->blend_desc, convert_type, have_lut, priv->color_balance_enabled,
&priv->blend_desc, convert_type, priv->color_balance_enabled,
priv->src_alpha_mode, priv->dst_alpha_mode, const_data,
priv->main_ctx->comm);
if (!priv->post_mipgen_ctx) {
@ -2523,6 +2522,12 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame,
GST_DEBUG_OBJECT (self, "Vertex updated");
}
guint pipeline_index = 0;
if (!is_internal && comm->need_color_balance)
pipeline_index = 1;
auto & pipeline_data = ctx->pipeline_data[pipeline_index];
auto device = gst_d3d12_device_get_device_handle (self->device);
GstD3D12DescHeap *descriptor;
@ -2544,13 +2549,19 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame,
cpu_handle.Offset (priv->srv_inc_size);
}
if (comm->have_lut) {
if (pipeline_data.crs->HaveLut ()) {
device->CopyDescriptorsSimple (2, cpu_handle,
GetCPUDescriptorHandleForHeapStart (comm->gamma_lut_heap),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
cpu_handle.Offset (priv->srv_inc_size);
cpu_handle.Offset (2, priv->srv_inc_size);
}
auto prev_sampler_remap = comm->const_data_dyn.samplerRemap;
/* Do not enable UV remap for intermediate conversion */
if (is_internal)
comm->const_data_dyn.samplerRemap = 0;
if (comm->const_data_dyn.samplerRemap) {
device->CreateShaderResourceView (comm->sampler_remap.Get (),
nullptr, cpu_handle);
@ -2567,9 +2578,6 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame,
reorder_rtv_handles (GST_VIDEO_INFO_FORMAT (&out_frame->info),
out_frame->rtv_desc_handle, reordered_rtv_handle);
guint pipeline_index = comm->need_color_balance ? 1 : 0;
auto & pipeline_data = ctx->pipeline_data[pipeline_index];
auto pso = pipeline_data.quad_data[0].pso.Get ();
cl->SetGraphicsRootSignature (pipeline_data.rs.Get ());
cl->SetPipelineState (pso);
@ -2623,12 +2631,15 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, GstD3D12Frame * in_frame,
FENCE_NOTIFY_COM (ctx->vertex_upload.Detach ()));
}
if (ctx->comm->sampler_remap) {
if (ctx->comm->sampler_remap && comm->const_data_dyn.samplerRemap) {
ComPtr < ID3D12Resource > remap_clone = ctx->comm->sampler_remap;
gst_d3d12_fence_data_push (fence_data,
FENCE_NOTIFY_COM (remap_clone.Detach ()));
}
/* Restore remap flag */
comm->const_data_dyn.samplerRemap = prev_sampler_remap;
auto sampler = comm->sampler_heap.Get ();
sampler->AddRef ();
gst_d3d12_fence_data_push (fence_data, FENCE_NOTIFY_COM (sampler));
@ -2670,43 +2681,16 @@ calculate_auto_mipgen_level (GstD3D12Converter * self)
priv->auto_mipgen_level = priv->mipgen_desc.MipLevels;
}
/**
* gst_d3d12_converter_convert_buffer:
* @converter: a #GstD3D12Converter
* @in_buf: a #GstBuffer
* @out_buf: a #GstBuffer
* @fence_data: a #GstD3D12FenceData
* @command_list: a ID3D12GraphicsCommandList
* @execute_gpu_wait: Executes wait operation against @queue
*
* Records command list for conversion operation. converter will attach
* conversion command associated resources such as command allocator
* to @fence_data.
*
* If @execute_wait is %TRUE and buffers are associated with external fences,
* this method will schedule GPU wait operation against @queue.
*
* Returns: %TRUE if successful
*
* Since: 1.26
*/
gboolean
gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
static gboolean
gst_d3d12_converter_convert_buffer_internal (GstD3D12Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf, GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * command_list, gboolean execute_gpu_wait)
ID3D12GraphicsCommandList * command_list, gboolean execute_gpu_wait,
guint num_remap, ID3D12Resource ** lut, GstVideoRectangle * viewport)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (out_buf), FALSE);
g_return_val_if_fail (fence_data, FALSE);
g_return_val_if_fail (command_list, FALSE);
GstD3D12Frame in_frame;
GstD3D12Frame out_frame;
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
auto render_target = gst_d3d12_pack_acquire_render_target (priv->pack,
out_buf);
if (!render_target) {
@ -2932,20 +2916,77 @@ gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
mipgen_frame.srv_desc_handle[0] = cpu_handle;
}
if (priv->post_mipgen_ctx) {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->post_mipgen_ctx,
FALSE, fence_data, command_list);
if (num_remap == 0) {
if (priv->post_mipgen_ctx) {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->post_mipgen_ctx,
FALSE, fence_data, command_list);
} else {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->main_ctx,
FALSE, fence_data, command_list);
}
} else {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->main_ctx,
FALSE, fence_data, command_list);
auto prev_remap = priv->main_ctx->comm->sampler_remap;
auto prev_x = priv->dest_x;
auto prev_y = priv->dest_y;
auto prev_w = priv->dest_width;
auto prev_h = priv->dest_height;
for (guint i = 0; i < num_remap; i++) {
gst_d3d12_converter_set_remap_unlocked (converter, lut[i]);
gst_d3d12_converter_update_viewport_unlocked (converter,
viewport[i].x, viewport[i].y, viewport[i].w, viewport[i].h);
if (priv->post_mipgen_ctx) {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->post_mipgen_ctx,
FALSE, fence_data, command_list);
} else {
ret = gst_d3d12_converter_execute (converter,
&mipgen_frame, &out_frame, priv->main_ctx,
FALSE, fence_data, command_list);
}
if (!ret)
break;
}
/* Restore previous state */
gst_d3d12_converter_set_remap_unlocked (converter, prev_remap.Get ());
gst_d3d12_converter_update_viewport_unlocked (converter,
prev_x, prev_y, prev_w, prev_h);
}
gst_d3d12_frame_unmap (&mipgen_frame);
} else {
ret = gst_d3d12_converter_execute (converter,
&in_frame, &out_frame, priv->main_ctx, FALSE, fence_data, command_list);
if (num_remap == 0) {
ret = gst_d3d12_converter_execute (converter, &in_frame, &out_frame,
priv->main_ctx, FALSE, fence_data, command_list);
} else {
auto prev_remap = priv->main_ctx->comm->sampler_remap;
auto prev_x = priv->dest_x;
auto prev_y = priv->dest_y;
auto prev_w = priv->dest_width;
auto prev_h = priv->dest_height;
for (guint i = 0; i < num_remap; i++) {
gst_d3d12_converter_set_remap_unlocked (converter, lut[i]);
gst_d3d12_converter_update_viewport_unlocked (converter,
viewport[i].x, viewport[i].y, viewport[i].w, viewport[i].h);
ret = gst_d3d12_converter_execute (converter, &in_frame, &out_frame,
priv->main_ctx, FALSE, fence_data, command_list);
if (!ret)
break;
}
/* Restore previous state */
gst_d3d12_converter_set_remap_unlocked (converter, prev_remap.Get ());
gst_d3d12_converter_update_viewport_unlocked (converter,
prev_x, prev_y, prev_w, prev_h);
}
}
if (ret) {
@ -2969,6 +3010,65 @@ gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
return ret;
}
/**
* gst_d3d12_converter_convert_buffer:
* @converter: a #GstD3D12Converter
* @in_buf: a #GstBuffer
* @out_buf: a #GstBuffer
* @fence_data: a #GstD3D12FenceData
* @command_list: a ID3D12GraphicsCommandList
* @execute_gpu_wait: Executes wait operation against @queue
*
* Records command list for conversion operation. converter will attach
* conversion command associated resources such as command allocator
* to @fence_data.
*
* If @execute_wait is %TRUE and buffers are associated with external fences,
* this method will schedule GPU wait operation against @queue.
*
* Returns: %TRUE if successful
*
* Since: 1.26
*/
gboolean
gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf, GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * command_list, gboolean execute_gpu_wait)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (out_buf), FALSE);
g_return_val_if_fail (fence_data, FALSE);
g_return_val_if_fail (command_list, FALSE);
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
return gst_d3d12_converter_convert_buffer_internal (converter,
in_buf, out_buf, fence_data, command_list, execute_gpu_wait,
0, nullptr, nullptr);
}
gboolean
gst_d3d12_converter_convert_buffer_for_uv_remap (GstD3D12Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf, GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * command_list, gboolean execute_gpu_wait,
guint num_remap, ID3D12Resource ** lut, GstVideoRectangle * viewport)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (out_buf), FALSE);
g_return_val_if_fail (fence_data, FALSE);
g_return_val_if_fail (command_list, FALSE);
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
return gst_d3d12_converter_convert_buffer_internal (converter,
in_buf, out_buf, fence_data, command_list, execute_gpu_wait,
num_remap, lut, viewport);
}
/**
* gst_d3d12_converter_update_blend_state:
* @converter: a #GstD3D12Converter
@ -3105,14 +3205,11 @@ gst_d3d12_converter_is_color_balance_needed (gfloat hue, gfloat saturation,
return FALSE;
}
gboolean
gst_d3d12_converter_set_remap (GstD3D12Converter * converter,
static gboolean
gst_d3d12_converter_set_remap_unlocked (GstD3D12Converter * self,
ID3D12Resource * remap_vector)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
auto priv = self->priv;
auto comm = priv->main_ctx->comm;
comm->sampler_remap = remap_vector;
@ -3123,3 +3220,45 @@ gst_d3d12_converter_set_remap (GstD3D12Converter * converter,
return TRUE;
}
gboolean
gst_d3d12_converter_set_remap (GstD3D12Converter * converter,
ID3D12Resource * remap_vector)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
return gst_d3d12_converter_set_remap_unlocked (converter, remap_vector);
}
static gboolean
gst_d3d12_converter_update_viewport_unlocked (GstD3D12Converter * self,
gint x, gint y, gint width, gint height)
{
auto priv = self->priv;
if (priv->dest_x != x || priv->dest_y != y || priv->dest_width != width ||
priv->dest_height != height) {
priv->dest_x = x;
priv->dest_y = y;
priv->dest_width = width;
priv->dest_height = height;
priv->update_dest_rect = TRUE;
}
return TRUE;
}
gboolean
gst_d3d12_converter_update_viewport (GstD3D12Converter * converter, gint x,
gint y, gint width, gint height)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
auto priv = converter->priv;
std::lock_guard < std::mutex > lk (priv->prop_lock);
return gst_d3d12_converter_update_viewport_unlocked (converter, x, y, width,
height);
}