diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp index 14649ede27..b517e66bb0 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp @@ -203,7 +203,8 @@ enum /* *INDENT-OFF* */ struct QuadData { - D3D12_GRAPHICS_PIPELINE_STATE_DESC desc; + D3D12_INPUT_ELEMENT_DESC input_desc[2]; + D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { }; ComPtr pso; guint num_rtv; }; @@ -235,6 +236,9 @@ struct _GstD3D12ConverterPrivate blend_desc = CD3DX12_BLEND_DESC (D3D12_DEFAULT); for (guint i = 0; i < 4; i++) blend_factor[i] = 1.0f; + + sample_desc.Count = 1; + sample_desc.Quality = 0; } ~_GstD3D12ConverterPrivate () @@ -260,6 +264,7 @@ struct _GstD3D12ConverterPrivate D3D12_BLEND_DESC blend_desc; FLOAT blend_factor[4]; + DXGI_SAMPLE_DESC sample_desc; gboolean update_pso = FALSE; GstVideoInfo fallback_pool_info; @@ -673,7 +678,10 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, priv->quad_data.resize (psblob_list.size ()); 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.VS = vs_blob; 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.DepthStencilState.DepthEnable = FALSE; pso_desc.DepthStencilState.StencilEnable = FALSE; - pso_desc.InputLayout.pInputElementDescs = input_desc; - pso_desc.InputLayout.NumElements = G_N_ELEMENTS (input_desc); + pso_desc.InputLayout.pInputElementDescs = priv->quad_data[i].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++) { @@ -700,7 +708,6 @@ gst_d3d12_converter_setup_resource (GstD3D12Converter * self, return FALSE; } - priv->quad_data[i].desc = pso_desc; priv->quad_data[i].pso = pso; 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++) { D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = priv->quad_data[i].desc; pso_desc.BlendState = priv->blend_desc; + pso_desc.SampleDesc = priv->sample_desc; ComPtr < ID3D12PipelineState > pso; auto hr = @@ -1829,6 +1837,16 @@ gst_d3d12_converter_execute (GstD3D12Converter * self, 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)) { GST_ERROR_OBJECT (self, "Failed to update dest rect"); return FALSE; diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12memory.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12memory.cpp index 43e7fdc345..03f226783b 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12memory.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12memory.cpp @@ -561,6 +561,8 @@ gst_d3d12_memory_get_render_target_view_heap (GstD3D12Memory * mem, D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { }; rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + if (priv->desc.SampleDesc.Count > 1) + rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; auto cpu_handle = CD3DX12_CPU_DESCRIPTOR_HANDLE @@ -568,7 +570,8 @@ gst_d3d12_memory_get_render_target_view_heap (GstD3D12Memory * mem, for (guint i = 0; i < priv->num_subresources; i++) { rtv_desc.Format = priv->resource_formats[i]; - rtv_desc.Texture2D.PlaneSlice = i; + if (priv->desc.SampleDesc.Count == 1) + rtv_desc.Texture2D.PlaneSlice = i; device->CreateRenderTargetView (priv->resource.Get (), &rtv_desc, cpu_handle); cpu_handle.Offset (priv->rtv_inc_size); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12overlaycompositor.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12overlaycompositor.cpp index 479650f56c..6bda4bd3b8 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12overlaycompositor.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12overlaycompositor.cpp @@ -75,6 +75,12 @@ GST_DEFINE_MINI_OBJECT_TYPE (GstD3D12OverlayRect, gst_d3d12_overlay_rect); struct GstD3D12OverlayCompositorPrivate { + GstD3D12OverlayCompositorPrivate () + { + sample_desc.Count = 1; + sample_desc.Quality = 0; + } + ~GstD3D12OverlayCompositorPrivate () { if (overlays) @@ -89,6 +95,11 @@ struct GstD3D12OverlayCompositorPrivate D3D12_VIEWPORT viewport; 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 rs; ComPtr pso; ComPtr pso_premul; @@ -424,24 +435,25 @@ gst_d3d12_overlay_compositor_setup_shader (GstD3D12OverlayCompositor * self) device->CreateRootSignature (0, rs_blob->GetBufferPointer (), rs_blob->GetBufferSize (), IID_PPV_ARGS (&rs)); - D3D12_INPUT_ELEMENT_DESC input_desc[2]; - input_desc[0].SemanticName = "POSITION"; - input_desc[0].SemanticIndex = 0; - input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; - input_desc[0].InputSlot = 0; - input_desc[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; - input_desc[0].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - input_desc[0].InstanceDataStepRate = 0; + priv->input_desc[0].SemanticName = "POSITION"; + priv->input_desc[0].SemanticIndex = 0; + priv->input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + priv->input_desc[0].InputSlot = 0; + priv->input_desc[0].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; + priv->input_desc[0].InputSlotClass = + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; + priv->input_desc[0].InstanceDataStepRate = 0; - input_desc[1].SemanticName = "TEXCOORD"; - input_desc[1].SemanticIndex = 0; - input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT; - input_desc[1].InputSlot = 0; - input_desc[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; - input_desc[1].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - input_desc[1].InstanceDataStepRate = 0; + priv->input_desc[1].SemanticName = "TEXCOORD"; + priv->input_desc[1].SemanticIndex = 0; + priv->input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT; + priv->input_desc[1].InputSlot = 0; + priv->input_desc[1].AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT; + priv->input_desc[1].InputSlotClass = + 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.VS.BytecodeLength = sizeof (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.DepthStencilState.DepthEnable = FALSE; pso_desc.DepthStencilState.StencilEnable = FALSE; - pso_desc.InputLayout.pInputElementDescs = input_desc; - pso_desc.InputLayout.NumElements = G_N_ELEMENTS (input_desc); + pso_desc.InputLayout.pInputElementDescs = priv->input_desc; + pso_desc.InputLayout.NumElements = 2; pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; pso_desc.NumRenderTargets = 1; 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; - pso_desc.PS.BytecodeLength = sizeof (g_PSMain_sample_premul); - pso_desc.PS.pShaderBytecode = g_PSMain_sample_premul; - hr = device->CreateGraphicsPipelineState (&pso_desc, + auto & pso_premul_desc = priv->pso_premul_desc; + pso_premul_desc = priv->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)); if (!gst_d3d12_result (hr, self->device)) { GST_ERROR_OBJECT (self, "Couldn't create pso"); @@ -678,6 +692,13 @@ gst_d3d12_overlay_compositor_update_viewport (GstD3D12OverlayCompositor * return TRUE; } +static void +pso_free_func (ID3D12PipelineState * pso) +{ + if (pso) + pso->Release (); +} + static gboolean gst_d3d12_overlay_compositor_execute (GstD3D12OverlayCompositor * self, GstBuffer * buf, GstD3D12FenceData * fence_data, @@ -750,6 +771,14 @@ gst_d3d12_overlay_compositor_execute (GstD3D12OverlayCompositor * self, 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; } @@ -768,6 +797,41 @@ gst_d3d12_overlay_compositor_draw (GstD3D12OverlayCompositor * compositor, if (!priv->overlays) 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, buf, fence_data, command_list); } diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp index a8401126be..be306edd1f 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp @@ -70,6 +70,25 @@ gst_d3d12_sampling_method_to_native (GstD3D12SamplingMethod method) 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 gst_d3d12_buffer_after_write (GstBuffer * buffer, guint64 fence_value) { diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h index b3141d1b5f..b719f50e27 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h @@ -25,19 +25,30 @@ G_BEGIN_DECLS -typedef enum +enum GstD3D12SamplingMethod { GST_D3D12_SAMPLING_METHOD_NEAREST, GST_D3D12_SAMPLING_METHOD_BILINEAR, GST_D3D12_SAMPLING_METHOD_LINEAR_MINIFICATION, GST_D3D12_SAMPLING_METHOD_ANISOTROPIC, -} GstD3D12SamplingMethod; +}; #define GST_TYPE_D3D12_SAMPLING_METHOD (gst_d3d12_sampling_method_get_type()) GType gst_d3d12_sampling_method_get_type (void); 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, guint64 fence_value); diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp index e6a034eaf1..2f137340a0 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp @@ -37,6 +37,7 @@ enum PROP_ROTATE_METHOD, PROP_FULLSCREEN_ON_ALT_ENTER, PROP_FULLSCREEN, + PROP_MSAA, }; #define DEFAULT_ADAPTER -1 @@ -45,6 +46,7 @@ enum #define DEFAULT_ROTATE_METHOD GST_VIDEO_ORIENTATION_IDENTITY #define DEFAULT_FULLSCREEN_ON_ALT_ENTER FALSE #define DEFAULT_FULLSCREEN FALSE +#define DEFAULT_MSAA GST_D3D12_MSAA_DISABLED static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -102,6 +104,7 @@ struct GstD3D12VideoSinkPrivate GstVideoOrientationMethod orientation_selected = DEFAULT_ROTATE_METHOD; gboolean fullscreen_on_alt_enter = DEFAULT_FULLSCREEN_ON_ALT_ENTER; gboolean fullscreen = DEFAULT_FULLSCREEN; + GstD3D12MSAAMode msaa = DEFAULT_MSAA; }; /* *INDENT-ON* */ @@ -214,6 +217,12 @@ gst_d3d12_video_sink_class_init (GstD3D12VideoSinkClass * klass) "Fullscreen mode", DEFAULT_FULLSCREEN, (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 = 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->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 @@ -299,6 +310,10 @@ gst_d3d12_videosink_set_property (GObject * object, guint prop_id, priv->fullscreen = g_value_get_boolean (value); gst_d3d12_window_set_fullscreen (priv->window, priv->fullscreen); break; + case PROP_MSAA: + priv->msaa = (GstD3D12MSAAMode) g_value_get_enum (value); + gst_d3d12_window_set_msaa (priv->window, priv->msaa); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -332,6 +347,9 @@ gst_d3d12_videosink_get_property (GObject * object, guint prop_id, case PROP_FULLSCREEN: g_value_set_boolean (value, priv->fullscreen); break; + case PROP_MSAA: + g_value_set_enum (value, priv->msaa); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp index cfcd56c4c1..28b12d3590 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp @@ -23,7 +23,6 @@ #include "gstd3d12window.h" #include "gstd3d12overlaycompositor.h" -#include "gstd3d12pluginutils.h" #include #include #include @@ -118,6 +117,7 @@ struct DeviceContext gst_clear_buffer (&cached_buf); gst_clear_object (&conv); gst_clear_object (&comp); + gst_clear_buffer (&msaa_buf); gst_clear_object (&device); } @@ -131,6 +131,7 @@ struct DeviceContext ComPtr cl; ComPtr swapchain; + GstBuffer *msaa_buf = nullptr; std::vector> swap_buffers; D3D12_RESOURCE_DESC buffer_desc; GstD3D12Converter *conv = nullptr; @@ -202,6 +203,8 @@ struct GstD3D12WindowPrivate std::wstring title; gboolean update_title = FALSE; + GstD3D12MSAAMode msaa = GST_D3D12_MSAA_DISABLED; + /* Win32 window handles */ std::mutex hwnd_lock; std::condition_variable hwnd_cond; @@ -693,7 +696,7 @@ gst_d3d12_window_create_hwnd (GstD3D12Window * self) int h = 0; DWORD style = WS_GST_D3D12; - std::wstring title = L"Direct3D12 renderer"; + std::wstring title = L"Direct3D12 Renderer"; if (!priv->title.empty ()) title = priv->title; @@ -1072,6 +1075,7 @@ gst_d3d12_window_on_resize (GstD3D12Window * self) if (priv->ctx->fence_val != 0) priv->ctx->WaitGpu (); priv->ctx->swap_buffers.clear (); + gst_clear_buffer (&priv->ctx->msaa_buf); DXGI_SWAP_CHAIN_DESC 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)); } + 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->backbuf_rendered = FALSE; @@ -1396,32 +1461,62 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer) (GDestroyNotify) gst_d3d12_command_allocator_unref); 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 = + CD3DX12_RESOURCE_BARRIER::Transition (backbuf_texture, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_RENDER_TARGET); + cl->ResourceBarrier (1, &barrier); + } - D3D12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::Transition (resource, - D3D12_RESOURCE_STATE_COMMON, - D3D12_RESOURCE_STATE_RENDER_TARGET); - - cl->ResourceBarrier (1, &barrier); 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_d3d12_fence_data_unref (fence_data); return GST_FLOW_ERROR; } 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_d3d12_fence_data_unref (fence_data); return GST_FLOW_ERROR; } - barrier = CD3DX12_RESOURCE_BARRIER::Transition (resource, - D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COMMON); + 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->ResourceBarrier (1, &barrier); + 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); + + cl->ResourceBarrier (1, &barrier); + } hr = cl->Close (); 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) 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); + } +} diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h index 821f51717d..1850ec5ab7 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h @@ -22,6 +22,7 @@ #include #include #include "gstd3d12.h" +#include "gstd3d12pluginutils.h" 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, gboolean enable); +void gst_d3d12_window_set_msaa (GstD3D12Window * window, + GstD3D12MSAAMode msaa); + G_END_DECLS