d3d12videosink: Add support for MSAA

Adding "msaa" property to support MSAA rendering

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5891>
This commit is contained in:
Seungha Yang 2024-01-05 20:40:33 +09:00 committed by GStreamer Marge Bot
parent de331217aa
commit 72237d2563
8 changed files with 286 additions and 43 deletions

View file

@ -203,7 +203,8 @@ enum
/* *INDENT-OFF* */ /* *INDENT-OFF* */
struct QuadData struct QuadData
{ {
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc; D3D12_INPUT_ELEMENT_DESC input_desc[2];
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { };
ComPtr<ID3D12PipelineState> pso; ComPtr<ID3D12PipelineState> pso;
guint num_rtv; guint num_rtv;
}; };
@ -235,6 +236,9 @@ struct _GstD3D12ConverterPrivate
blend_desc = CD3DX12_BLEND_DESC (D3D12_DEFAULT); blend_desc = CD3DX12_BLEND_DESC (D3D12_DEFAULT);
for (guint i = 0; i < 4; i++) for (guint i = 0; i < 4; i++)
blend_factor[i] = 1.0f; blend_factor[i] = 1.0f;
sample_desc.Count = 1;
sample_desc.Quality = 0;
} }
~_GstD3D12ConverterPrivate () ~_GstD3D12ConverterPrivate ()
@ -260,6 +264,7 @@ struct _GstD3D12ConverterPrivate
D3D12_BLEND_DESC blend_desc; D3D12_BLEND_DESC blend_desc;
FLOAT blend_factor[4]; FLOAT blend_factor[4];
DXGI_SAMPLE_DESC sample_desc;
gboolean update_pso = FALSE; gboolean update_pso = FALSE;
GstVideoInfo fallback_pool_info; GstVideoInfo fallback_pool_info;
@ -673,7 +678,10 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
priv->quad_data.resize (psblob_list.size ()); priv->quad_data.resize (psblob_list.size ());
for (size_t i = 0; i < psblob_list.size (); i++) { for (size_t i = 0; i < psblob_list.size (); i++) {
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { }; priv->quad_data[i].input_desc[0] = input_desc[0];
priv->quad_data[i].input_desc[1] = input_desc[1];
auto & pso_desc = priv->quad_data[i].desc;
pso_desc.pRootSignature = priv->rs.Get (); pso_desc.pRootSignature = priv->rs.Get ();
pso_desc.VS = vs_blob; pso_desc.VS = vs_blob;
pso_desc.PS = psblob_list[i].bytecode; pso_desc.PS = psblob_list[i].bytecode;
@ -683,8 +691,8 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
pso_desc.DepthStencilState.DepthEnable = FALSE; pso_desc.DepthStencilState.DepthEnable = FALSE;
pso_desc.DepthStencilState.StencilEnable = FALSE; pso_desc.DepthStencilState.StencilEnable = FALSE;
pso_desc.InputLayout.pInputElementDescs = input_desc; pso_desc.InputLayout.pInputElementDescs = priv->quad_data[i].input_desc;
pso_desc.InputLayout.NumElements = G_N_ELEMENTS (input_desc); pso_desc.InputLayout.NumElements = 2;
pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
pso_desc.NumRenderTargets = psblob_list[i].num_rtv; pso_desc.NumRenderTargets = psblob_list[i].num_rtv;
for (UINT j = 0; j < pso_desc.NumRenderTargets; j++) { for (UINT j = 0; j < pso_desc.NumRenderTargets; j++) {
@ -700,7 +708,6 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self,
return FALSE; return FALSE;
} }
priv->quad_data[i].desc = pso_desc;
priv->quad_data[i].pso = pso; priv->quad_data[i].pso = pso;
priv->quad_data[i].num_rtv = psblob_list[i].num_rtv; priv->quad_data[i].num_rtv = psblob_list[i].num_rtv;
} }
@ -1781,6 +1788,7 @@ gst_d3d12_converter_update_pso (GstD3D12Converter * self)
for (size_t i = 0; i < quad_data.size (); i++) { for (size_t i = 0; i < quad_data.size (); i++) {
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = priv->quad_data[i].desc; D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = priv->quad_data[i].desc;
pso_desc.BlendState = priv->blend_desc; pso_desc.BlendState = priv->blend_desc;
pso_desc.SampleDesc = priv->sample_desc;
ComPtr < ID3D12PipelineState > pso; ComPtr < ID3D12PipelineState > pso;
auto hr = auto hr =
@ -1829,6 +1837,16 @@ gst_d3d12_converter_execute (GstD3D12Converter * self,
priv->update_src_rect = TRUE; priv->update_src_rect = TRUE;
} }
mem = (GstD3D12Memory *) gst_buffer_peek_memory (out_buf, 0);
resource = gst_d3d12_memory_get_resource_handle (mem);
desc = resource->GetDesc ();
if (desc.SampleDesc.Count != priv->sample_desc.Count ||
desc.SampleDesc.Quality != priv->sample_desc.Quality) {
GST_DEBUG_OBJECT (self, "Sample desc updated");
priv->sample_desc = desc.SampleDesc;
priv->update_pso = TRUE;
}
if (!gst_d3d12_converter_update_dest_rect (self)) { if (!gst_d3d12_converter_update_dest_rect (self)) {
GST_ERROR_OBJECT (self, "Failed to update dest rect"); GST_ERROR_OBJECT (self, "Failed to update dest rect");
return FALSE; return FALSE;

View file

@ -561,6 +561,8 @@ gst_d3d12_memory_get_render_target_view_heap (GstD3D12Memory * mem,
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { }; D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { };
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
if (priv->desc.SampleDesc.Count > 1)
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
auto cpu_handle = auto cpu_handle =
CD3DX12_CPU_DESCRIPTOR_HANDLE CD3DX12_CPU_DESCRIPTOR_HANDLE
@ -568,6 +570,7 @@ gst_d3d12_memory_get_render_target_view_heap (GstD3D12Memory * mem,
for (guint i = 0; i < priv->num_subresources; i++) { for (guint i = 0; i < priv->num_subresources; i++) {
rtv_desc.Format = priv->resource_formats[i]; rtv_desc.Format = priv->resource_formats[i];
if (priv->desc.SampleDesc.Count == 1)
rtv_desc.Texture2D.PlaneSlice = i; rtv_desc.Texture2D.PlaneSlice = i;
device->CreateRenderTargetView (priv->resource.Get (), &rtv_desc, device->CreateRenderTargetView (priv->resource.Get (), &rtv_desc,
cpu_handle); cpu_handle);

View file

@ -75,6 +75,12 @@ GST_DEFINE_MINI_OBJECT_TYPE (GstD3D12OverlayRect, gst_d3d12_overlay_rect);
struct GstD3D12OverlayCompositorPrivate struct GstD3D12OverlayCompositorPrivate
{ {
GstD3D12OverlayCompositorPrivate ()
{
sample_desc.Count = 1;
sample_desc.Quality = 0;
}
~GstD3D12OverlayCompositorPrivate () ~GstD3D12OverlayCompositorPrivate ()
{ {
if (overlays) if (overlays)
@ -89,6 +95,11 @@ struct GstD3D12OverlayCompositorPrivate
D3D12_VIEWPORT viewport; D3D12_VIEWPORT viewport;
D3D12_RECT scissor_rect; D3D12_RECT scissor_rect;
D3D12_INPUT_ELEMENT_DESC input_desc[2];
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { };
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_premul_desc = { };
DXGI_SAMPLE_DESC sample_desc;
ComPtr<ID3D12RootSignature> rs; ComPtr<ID3D12RootSignature> rs;
ComPtr<ID3D12PipelineState> pso; ComPtr<ID3D12PipelineState> pso;
ComPtr<ID3D12PipelineState> pso_premul; ComPtr<ID3D12PipelineState> pso_premul;
@ -424,24 +435,25 @@ gst_d3d12_overlay_compositor_setup_shader (GstD3D12OverlayCompositor * self)
device->CreateRootSignature (0, rs_blob->GetBufferPointer (), device->CreateRootSignature (0, rs_blob->GetBufferPointer (),
rs_blob->GetBufferSize (), IID_PPV_ARGS (&rs)); rs_blob->GetBufferSize (), IID_PPV_ARGS (&rs));
D3D12_INPUT_ELEMENT_DESC input_desc[2]; priv->input_desc[0].SemanticName = "POSITION";
input_desc[0].SemanticName = "POSITION"; priv->input_desc[0].SemanticIndex = 0;
input_desc[0].SemanticIndex = 0; priv->input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; priv->input_desc[0].InputSlot = 0;
input_desc[0].InputSlot = 0; priv->input_desc[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT;
input_desc[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; priv->input_desc[0].InputSlotClass =
input_desc[0].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
input_desc[0].InstanceDataStepRate = 0; priv->input_desc[0].InstanceDataStepRate = 0;
input_desc[1].SemanticName = "TEXCOORD"; priv->input_desc[1].SemanticName = "TEXCOORD";
input_desc[1].SemanticIndex = 0; priv->input_desc[1].SemanticIndex = 0;
input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT; priv->input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
input_desc[1].InputSlot = 0; priv->input_desc[1].InputSlot = 0;
input_desc[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; priv->input_desc[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT;
input_desc[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; priv->input_desc[1].InputSlotClass =
input_desc[1].InstanceDataStepRate = 0; D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
priv->input_desc[1].InstanceDataStepRate = 0;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { }; auto & pso_desc = priv->pso_desc;
pso_desc.pRootSignature = rs.Get (); pso_desc.pRootSignature = rs.Get ();
pso_desc.VS.BytecodeLength = sizeof (g_VSMain_coord); pso_desc.VS.BytecodeLength = sizeof (g_VSMain_coord);
pso_desc.VS.pShaderBytecode = g_VSMain_coord; pso_desc.VS.pShaderBytecode = g_VSMain_coord;
@ -465,8 +477,8 @@ gst_d3d12_overlay_compositor_setup_shader (GstD3D12OverlayCompositor * self)
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
pso_desc.DepthStencilState.DepthEnable = FALSE; pso_desc.DepthStencilState.DepthEnable = FALSE;
pso_desc.DepthStencilState.StencilEnable = FALSE; pso_desc.DepthStencilState.StencilEnable = FALSE;
pso_desc.InputLayout.pInputElementDescs = input_desc; pso_desc.InputLayout.pInputElementDescs = priv->input_desc;
pso_desc.InputLayout.NumElements = G_N_ELEMENTS (input_desc); pso_desc.InputLayout.NumElements = 2;
pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
pso_desc.NumRenderTargets = 1; pso_desc.NumRenderTargets = 1;
pso_desc.RTVFormats[0] = device_format.resource_format[0]; pso_desc.RTVFormats[0] = device_format.resource_format[0];
@ -480,9 +492,11 @@ gst_d3d12_overlay_compositor_setup_shader (GstD3D12OverlayCompositor * self)
} }
ComPtr < ID3D12PipelineState > pso_premul; ComPtr < ID3D12PipelineState > pso_premul;
pso_desc.PS.BytecodeLength = sizeof (g_PSMain_sample_premul); auto & pso_premul_desc = priv->pso_premul_desc;
pso_desc.PS.pShaderBytecode = g_PSMain_sample_premul; pso_premul_desc = priv->pso_desc;
hr = device->CreateGraphicsPipelineState (&pso_desc, pso_premul_desc.PS.BytecodeLength = sizeof (g_PSMain_sample_premul);
pso_premul_desc.PS.pShaderBytecode = g_PSMain_sample_premul;
hr = device->CreateGraphicsPipelineState (&pso_premul_desc,
IID_PPV_ARGS (&pso_premul)); IID_PPV_ARGS (&pso_premul));
if (!gst_d3d12_result (hr, self->device)) { if (!gst_d3d12_result (hr, self->device)) {
GST_ERROR_OBJECT (self, "Couldn't create pso"); GST_ERROR_OBJECT (self, "Couldn't create pso");
@ -678,6 +692,13 @@ gst_d3d12_overlay_compositor_update_viewport (GstD3D12OverlayCompositor *
return TRUE; return TRUE;
} }
static void
pso_free_func (ID3D12PipelineState * pso)
{
if (pso)
pso->Release ();
}
static gboolean static gboolean
gst_d3d12_overlay_compositor_execute (GstD3D12OverlayCompositor * self, gst_d3d12_overlay_compositor_execute (GstD3D12OverlayCompositor * self,
GstBuffer * buf, GstD3D12FenceData * fence_data, GstBuffer * buf, GstD3D12FenceData * fence_data,
@ -750,6 +771,14 @@ gst_d3d12_overlay_compositor_execute (GstD3D12OverlayCompositor * self,
prev_pso = pso; prev_pso = pso;
} }
priv->pso->AddRef ();
gst_d3d12_fence_data_add_notify (fence_data, priv->pso.Get (),
(GDestroyNotify) pso_free_func);
priv->pso_premul->AddRef ();
gst_d3d12_fence_data_add_notify (fence_data, priv->pso_premul.Get (),
(GDestroyNotify) pso_free_func);
return TRUE; return TRUE;
} }
@ -768,6 +797,41 @@ gst_d3d12_overlay_compositor_draw (GstD3D12OverlayCompositor * compositor,
if (!priv->overlays) if (!priv->overlays)
return TRUE; return TRUE;
auto mem = (GstD3D12Memory *) gst_buffer_peek_memory (buf, 0);
auto resource = gst_d3d12_memory_get_resource_handle (mem);
auto desc = resource->GetDesc ();
if (desc.SampleDesc.Count != priv->sample_desc.Count ||
desc.SampleDesc.Quality != priv->sample_desc.Quality) {
auto device = gst_d3d12_device_get_device_handle (compositor->device);
auto pso_desc = priv->pso_desc;
pso_desc.SampleDesc = desc.SampleDesc;
ComPtr < ID3D12PipelineState > pso;
auto hr = device->CreateGraphicsPipelineState (&pso_desc,
IID_PPV_ARGS (&pso));
if (!gst_d3d12_result (hr, compositor->device)) {
GST_ERROR_OBJECT (compositor, "Couldn't create pso");
return FALSE;
}
ComPtr < ID3D12PipelineState > pso_premul;
auto pso_premul_desc = priv->pso_premul_desc;
pso_premul_desc.SampleDesc = desc.SampleDesc;
hr = device->CreateGraphicsPipelineState (&pso_premul_desc,
IID_PPV_ARGS (&pso_premul));
if (!gst_d3d12_result (hr, compositor->device)) {
GST_ERROR_OBJECT (compositor, "Couldn't create pso");
return FALSE;
}
priv->pso = nullptr;
priv->pso_premul = nullptr;
priv->pso = pso;
priv->pso_premul = pso_premul;
priv->sample_desc = desc.SampleDesc;
}
return gst_d3d12_overlay_compositor_execute (compositor, return gst_d3d12_overlay_compositor_execute (compositor,
buf, fence_data, command_list); buf, fence_data, command_list);
} }

View file

@ -70,6 +70,25 @@ gst_d3d12_sampling_method_to_native (GstD3D12SamplingMethod method)
return D3D12_FILTER_MIN_MAG_MIP_POINT; return D3D12_FILTER_MIN_MAG_MIP_POINT;
} }
GType
gst_d3d12_msaa_mode_get_type (void)
{
static GType type = 0;
static const GEnumValue msaa_mode[] = {
{GST_D3D12_MSAA_DISABLED, "Disabled", "disabled"},
{GST_D3D12_MSAA_2X, "2x MSAA", "2x"},
{GST_D3D12_MSAA_4X, "4x MSAA", "4x"},
{GST_D3D12_MSAA_8X, "8x MSAA", "8x"},
{0, nullptr, nullptr},
};
GST_D3D12_CALL_ONCE_BEGIN {
type = g_enum_register_static ("GstD3D12MSAAMode", msaa_mode);
} GST_D3D12_CALL_ONCE_END;
return type;
}
void void
gst_d3d12_buffer_after_write (GstBuffer * buffer, guint64 fence_value) gst_d3d12_buffer_after_write (GstBuffer * buffer, guint64 fence_value)
{ {

View file

@ -25,19 +25,30 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum enum GstD3D12SamplingMethod
{ {
GST_D3D12_SAMPLING_METHOD_NEAREST, GST_D3D12_SAMPLING_METHOD_NEAREST,
GST_D3D12_SAMPLING_METHOD_BILINEAR, GST_D3D12_SAMPLING_METHOD_BILINEAR,
GST_D3D12_SAMPLING_METHOD_LINEAR_MINIFICATION, GST_D3D12_SAMPLING_METHOD_LINEAR_MINIFICATION,
GST_D3D12_SAMPLING_METHOD_ANISOTROPIC, GST_D3D12_SAMPLING_METHOD_ANISOTROPIC,
} GstD3D12SamplingMethod; };
#define GST_TYPE_D3D12_SAMPLING_METHOD (gst_d3d12_sampling_method_get_type()) #define GST_TYPE_D3D12_SAMPLING_METHOD (gst_d3d12_sampling_method_get_type())
GType gst_d3d12_sampling_method_get_type (void); GType gst_d3d12_sampling_method_get_type (void);
D3D12_FILTER gst_d3d12_sampling_method_to_native (GstD3D12SamplingMethod method); D3D12_FILTER gst_d3d12_sampling_method_to_native (GstD3D12SamplingMethod method);
enum GstD3D12MSAAMode
{
GST_D3D12_MSAA_DISABLED,
GST_D3D12_MSAA_2X,
GST_D3D12_MSAA_4X,
GST_D3D12_MSAA_8X,
};
#define GST_TYPE_D3D12_MSAA_MODE (gst_d3d12_msaa_mode_get_type())
GType gst_d3d12_msaa_mode_get_type (void);
void gst_d3d12_buffer_after_write (GstBuffer * buffer, void gst_d3d12_buffer_after_write (GstBuffer * buffer,
guint64 fence_value); guint64 fence_value);

View file

@ -37,6 +37,7 @@ enum
PROP_ROTATE_METHOD, PROP_ROTATE_METHOD,
PROP_FULLSCREEN_ON_ALT_ENTER, PROP_FULLSCREEN_ON_ALT_ENTER,
PROP_FULLSCREEN, PROP_FULLSCREEN,
PROP_MSAA,
}; };
#define DEFAULT_ADAPTER -1 #define DEFAULT_ADAPTER -1
@ -45,6 +46,7 @@ enum
#define DEFAULT_ROTATE_METHOD GST_VIDEO_ORIENTATION_IDENTITY #define DEFAULT_ROTATE_METHOD GST_VIDEO_ORIENTATION_IDENTITY
#define DEFAULT_FULLSCREEN_ON_ALT_ENTER FALSE #define DEFAULT_FULLSCREEN_ON_ALT_ENTER FALSE
#define DEFAULT_FULLSCREEN FALSE #define DEFAULT_FULLSCREEN FALSE
#define DEFAULT_MSAA GST_D3D12_MSAA_DISABLED
static GstStaticPadTemplate sink_template = static GstStaticPadTemplate sink_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
@ -102,6 +104,7 @@ struct GstD3D12VideoSinkPrivate
GstVideoOrientationMethod orientation_selected = DEFAULT_ROTATE_METHOD; GstVideoOrientationMethod orientation_selected = DEFAULT_ROTATE_METHOD;
gboolean fullscreen_on_alt_enter = DEFAULT_FULLSCREEN_ON_ALT_ENTER; gboolean fullscreen_on_alt_enter = DEFAULT_FULLSCREEN_ON_ALT_ENTER;
gboolean fullscreen = DEFAULT_FULLSCREEN; gboolean fullscreen = DEFAULT_FULLSCREEN;
GstD3D12MSAAMode msaa = DEFAULT_MSAA;
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -214,6 +217,12 @@ gst_d3d12_video_sink_class_init (GstD3D12VideoSinkClass * klass)
"Fullscreen mode", DEFAULT_FULLSCREEN, "Fullscreen mode", DEFAULT_FULLSCREEN,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (object_class, PROP_MSAA,
g_param_spec_enum ("msaa", "MSAA",
"MSAA (Multi-Sampling Anti-Aliasing) level",
GST_TYPE_D3D12_MSAA_MODE, DEFAULT_MSAA,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
element_class->set_context = element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_set_context); GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_set_context);
@ -237,6 +246,8 @@ gst_d3d12_video_sink_class_init (GstD3D12VideoSinkClass * klass)
videosink_class->set_info = GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_set_info); videosink_class->set_info = GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_set_info);
videosink_class->show_frame = videosink_class->show_frame =
GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_show_frame); GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_show_frame);
gst_type_mark_as_plugin_api (GST_TYPE_D3D12_MSAA_MODE, (GstPluginAPIFlags) 0);
} }
static void static void
@ -299,6 +310,10 @@ gst_d3d12_videosink_set_property (GObject * object, guint prop_id,
priv->fullscreen = g_value_get_boolean (value); priv->fullscreen = g_value_get_boolean (value);
gst_d3d12_window_set_fullscreen (priv->window, priv->fullscreen); gst_d3d12_window_set_fullscreen (priv->window, priv->fullscreen);
break; break;
case PROP_MSAA:
priv->msaa = (GstD3D12MSAAMode) g_value_get_enum (value);
gst_d3d12_window_set_msaa (priv->window, priv->msaa);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -332,6 +347,9 @@ gst_d3d12_videosink_get_property (GObject * object, guint prop_id,
case PROP_FULLSCREEN: case PROP_FULLSCREEN:
g_value_set_boolean (value, priv->fullscreen); g_value_set_boolean (value, priv->fullscreen);
break; break;
case PROP_MSAA:
g_value_set_enum (value, priv->msaa);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -23,7 +23,6 @@
#include "gstd3d12window.h" #include "gstd3d12window.h"
#include "gstd3d12overlaycompositor.h" #include "gstd3d12overlaycompositor.h"
#include "gstd3d12pluginutils.h"
#include <directx/d3dx12.h> #include <directx/d3dx12.h>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
@ -118,6 +117,7 @@ struct DeviceContext
gst_clear_buffer (&cached_buf); gst_clear_buffer (&cached_buf);
gst_clear_object (&conv); gst_clear_object (&conv);
gst_clear_object (&comp); gst_clear_object (&comp);
gst_clear_buffer (&msaa_buf);
gst_clear_object (&device); gst_clear_object (&device);
} }
@ -131,6 +131,7 @@ struct DeviceContext
ComPtr<ID3D12GraphicsCommandList> cl; ComPtr<ID3D12GraphicsCommandList> cl;
ComPtr<IDXGISwapChain4> swapchain; ComPtr<IDXGISwapChain4> swapchain;
GstBuffer *msaa_buf = nullptr;
std::vector<std::shared_ptr<SwapBuffer>> swap_buffers; std::vector<std::shared_ptr<SwapBuffer>> swap_buffers;
D3D12_RESOURCE_DESC buffer_desc; D3D12_RESOURCE_DESC buffer_desc;
GstD3D12Converter *conv = nullptr; GstD3D12Converter *conv = nullptr;
@ -202,6 +203,8 @@ struct GstD3D12WindowPrivate
std::wstring title; std::wstring title;
gboolean update_title = FALSE; gboolean update_title = FALSE;
GstD3D12MSAAMode msaa = GST_D3D12_MSAA_DISABLED;
/* Win32 window handles */ /* Win32 window handles */
std::mutex hwnd_lock; std::mutex hwnd_lock;
std::condition_variable hwnd_cond; std::condition_variable hwnd_cond;
@ -693,7 +696,7 @@ gst_d3d12_window_create_hwnd (GstD3D12Window * self)
int h = 0; int h = 0;
DWORD style = WS_GST_D3D12; DWORD style = WS_GST_D3D12;
std::wstring title = L"Direct3D12 renderer"; std::wstring title = L"Direct3D12 Renderer";
if (!priv->title.empty ()) if (!priv->title.empty ())
title = priv->title; title = priv->title;
@ -1072,6 +1075,7 @@ gst_d3d12_window_on_resize (GstD3D12Window * self)
if (priv->ctx->fence_val != 0) if (priv->ctx->fence_val != 0)
priv->ctx->WaitGpu (); priv->ctx->WaitGpu ();
priv->ctx->swap_buffers.clear (); priv->ctx->swap_buffers.clear ();
gst_clear_buffer (&priv->ctx->msaa_buf);
DXGI_SWAP_CHAIN_DESC desc = { }; DXGI_SWAP_CHAIN_DESC desc = { };
priv->ctx->swapchain->GetDesc (&desc); priv->ctx->swapchain->GetDesc (&desc);
@ -1100,6 +1104,67 @@ gst_d3d12_window_on_resize (GstD3D12Window * self)
priv->ctx->swap_buffers.push_back (std::make_shared < SwapBuffer > (buf)); priv->ctx->swap_buffers.push_back (std::make_shared < SwapBuffer > (buf));
} }
guint sample_count = 1;
switch (priv->msaa) {
case GST_D3D12_MSAA_2X:
sample_count = 2;
break;
case GST_D3D12_MSAA_4X:
sample_count = 4;
break;
case GST_D3D12_MSAA_8X:
sample_count = 8;
break;
default:
break;
}
auto device = gst_d3d12_device_get_device_handle (self->device);
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS feature_data = { };
feature_data.Format = priv->ctx->buffer_desc.Format;
feature_data.SampleCount = sample_count;
while (feature_data.SampleCount > 1) {
hr = device->CheckFeatureSupport (D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&feature_data, sizeof (feature_data));
if (SUCCEEDED (hr) && feature_data.NumQualityLevels > 0)
break;
feature_data.SampleCount /= 2;
}
if (feature_data.SampleCount > 1 && feature_data.NumQualityLevels > 0) {
GST_DEBUG_OBJECT (self, "Enable MSAA x%d with quality level %d",
feature_data.SampleCount, feature_data.NumQualityLevels - 1);
D3D12_HEAP_PROPERTIES heap_prop =
CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC resource_desc =
CD3DX12_RESOURCE_DESC::Tex2D (priv->ctx->buffer_desc.Format,
priv->ctx->buffer_desc.Width, priv->ctx->buffer_desc.Height,
1, 1, feature_data.SampleCount, feature_data.NumQualityLevels - 1,
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
D3D12_CLEAR_VALUE clear_value = { };
clear_value.Format = priv->ctx->buffer_desc.Format;
clear_value.Color[0] = 0.0f;
clear_value.Color[1] = 0.0f;
clear_value.Color[2] = 0.0f;
clear_value.Color[3] = 1.0f;
ComPtr < ID3D12Resource > msaa_texture;
hr = device->CreateCommittedResource (&heap_prop, D3D12_HEAP_FLAG_NONE,
&resource_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clear_value,
IID_PPV_ARGS (&msaa_texture));
if (!gst_d3d12_result (hr, self->device)) {
GST_ERROR_OBJECT (self, "Couldn't create MSAA texture");
return GST_FLOW_ERROR;
}
auto mem = gst_d3d12_allocator_alloc_wrapped (nullptr, self->device,
msaa_texture.Get (), 0);
priv->ctx->msaa_buf = gst_buffer_new ();
gst_buffer_append_memory (priv->ctx->msaa_buf, mem);
}
priv->first_present = TRUE; priv->first_present = TRUE;
priv->backbuf_rendered = FALSE; priv->backbuf_rendered = FALSE;
@ -1396,32 +1461,62 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer)
(GDestroyNotify) gst_d3d12_command_allocator_unref); (GDestroyNotify) gst_d3d12_command_allocator_unref);
auto mem = (GstD3D12Memory *) gst_buffer_peek_memory (swapbuf->backbuf, 0); auto mem = (GstD3D12Memory *) gst_buffer_peek_memory (swapbuf->backbuf, 0);
auto resource = gst_d3d12_memory_get_resource_handle (mem); auto backbuf_texture = gst_d3d12_memory_get_resource_handle (mem);
ID3D12Resource *msaa_resource = nullptr;
GstBuffer *conv_outbuf = swapbuf->backbuf;
if (priv->ctx->msaa_buf) {
conv_outbuf = priv->ctx->msaa_buf;
mem = (GstD3D12Memory *) gst_buffer_peek_memory (priv->ctx->msaa_buf, 0);
msaa_resource = gst_d3d12_memory_get_resource_handle (mem);
/* MSAA resource must be render target state here already */
} else {
D3D12_RESOURCE_BARRIER barrier = D3D12_RESOURCE_BARRIER barrier =
CD3DX12_RESOURCE_BARRIER::Transition (resource, CD3DX12_RESOURCE_BARRIER::Transition (backbuf_texture,
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COMMON,
D3D12_RESOURCE_STATE_RENDER_TARGET); D3D12_RESOURCE_STATE_RENDER_TARGET);
cl->ResourceBarrier (1, &barrier); cl->ResourceBarrier (1, &barrier);
}
if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv, if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv,
priv->ctx->cached_buf, swapbuf->backbuf, fence_data, cl.Get ())) { priv->ctx->cached_buf, conv_outbuf, fence_data, cl.Get ())) {
GST_ERROR_OBJECT (window, "Couldn't build convert command"); GST_ERROR_OBJECT (window, "Couldn't build convert command");
gst_d3d12_fence_data_unref (fence_data); gst_d3d12_fence_data_unref (fence_data);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
if (!gst_d3d12_overlay_compositor_draw (priv->ctx->comp, if (!gst_d3d12_overlay_compositor_draw (priv->ctx->comp,
swapbuf->backbuf, fence_data, cl.Get ())) { conv_outbuf, fence_data, cl.Get ())) {
GST_ERROR_OBJECT (window, "Couldn't build overlay command"); GST_ERROR_OBJECT (window, "Couldn't build overlay command");
gst_d3d12_fence_data_unref (fence_data); gst_d3d12_fence_data_unref (fence_data);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
barrier = CD3DX12_RESOURCE_BARRIER::Transition (resource, if (msaa_resource) {
std::vector < D3D12_RESOURCE_BARRIER > barriers;
barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (msaa_resource,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE));
barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (backbuf_texture,
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RESOLVE_DEST));
cl->ResourceBarrier (barriers.size (), barriers.data ());
cl->ResolveSubresource (backbuf_texture, 0, msaa_resource, 0,
priv->display_format);
barriers.clear ();
barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (msaa_resource,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET));
barriers.push_back (CD3DX12_RESOURCE_BARRIER::Transition (backbuf_texture,
D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COMMON));
cl->ResourceBarrier (barriers.size (), barriers.data ());
} else {
D3D12_RESOURCE_BARRIER barrier =
CD3DX12_RESOURCE_BARRIER::Transition (backbuf_texture,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COMMON); D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COMMON);
cl->ResourceBarrier (1, &barrier); cl->ResourceBarrier (1, &barrier);
}
hr = cl->Close (); hr = cl->Close ();
if (!gst_d3d12_result (hr, priv->ctx->device)) { if (!gst_d3d12_result (hr, priv->ctx->device)) {
@ -1619,3 +1714,14 @@ gst_d3d12_window_set_fullscreen (GstD3D12Window * window, gboolean enable)
if (priv->hwnd && priv->applied_fullscreen != priv->requested_fullscreen) if (priv->hwnd && priv->applied_fullscreen != priv->requested_fullscreen)
PostMessageW (priv->hwnd, WM_GST_D3D12_FULLSCREEN, 0, 0); PostMessageW (priv->hwnd, WM_GST_D3D12_FULLSCREEN, 0, 0);
} }
void
gst_d3d12_window_set_msaa (GstD3D12Window * window, GstD3D12MSAAMode msaa)
{
auto priv = window->priv;
std::lock_guard < std::recursive_mutex > lk (priv->lock);
if (priv->msaa != msaa) {
priv->msaa = msaa;
gst_d3d12_window_on_resize (window);
}
}

View file

@ -22,6 +22,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include "gstd3d12.h" #include "gstd3d12.h"
#include "gstd3d12pluginutils.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -83,5 +84,8 @@ void gst_d3d12_window_enable_fullscreen_on_alt_enter (GstD3D12Window
void gst_d3d12_window_set_fullscreen (GstD3D12Window * window, void gst_d3d12_window_set_fullscreen (GstD3D12Window * window,
gboolean enable); gboolean enable);
void gst_d3d12_window_set_msaa (GstD3D12Window * window,
GstD3D12MSAAMode msaa);
G_END_DECLS G_END_DECLS