d3d11videosink: Add a property to support rendering statistics data on window

Add a new property "render-stats" to allow rendering statistics
data on window for debugging and/or development purpose.
Text rendering will be accelerated by GPU since this implementation
uses Direct2D/DirectWrite API and Direct3D inter-op for minimal overhead.
Specifically, text data will be rendered on swapchain backbuffer
directly without any copy/allocation of extra texture.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1830>
This commit is contained in:
Seungha Yang 2020-11-22 04:39:57 +09:00
parent 22990bb9ea
commit 96831233a3
5 changed files with 352 additions and 15 deletions

View file

@ -44,6 +44,7 @@ enum
PROP_ENABLE_NAVIGATION_EVENTS,
PROP_FULLSCREEN_TOGGLE_MODE,
PROP_FULLSCREEN,
PROP_RENDER_STATS,
};
#define DEFAULT_ADAPTER -1
@ -51,6 +52,7 @@ enum
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
#define DEFAULT_FULLSCREEN FALSE
#define DEFAULT_RENDER_STATS FALSE
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@ -84,6 +86,7 @@ struct _GstD3D11VideoSink
gboolean enable_navigation_events;
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
gboolean fullscreen;
gboolean render_stats;
/* saved render rectangle until we have a window */
GstVideoRectangle render_rect;
@ -178,6 +181,16 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass)
"Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
DEFAULT_FULLSCREEN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#ifdef HAVE_DIRECT_WRITE
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
g_param_spec_boolean ("render-stats",
"Render Stats",
"Render statistics data (e.g., average framerate) on window",
DEFAULT_RENDER_STATS,
GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_set_context);
@ -213,6 +226,7 @@ gst_d3d11_video_sink_init (GstD3D11VideoSink * self)
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
self->fullscreen_toggle_mode = DEFAULT_FULLSCREEN_TOGGLE_MODE;
self->fullscreen = DEFAULT_FULLSCREEN;
self->render_stats = DEFAULT_RENDER_STATS;
}
static void
@ -252,6 +266,11 @@ gst_d3d11_videosink_set_property (GObject * object, guint prop_id,
g_object_set (self->window, "fullscreen", self->fullscreen, NULL);
}
break;
#ifdef HAVE_DIRECT_WRITE
case PROP_RENDER_STATS:
self->render_stats = g_value_get_boolean (value);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -285,6 +304,11 @@ gst_d3d11_videosink_get_property (GObject * object, guint prop_id,
g_value_set_boolean (value, self->fullscreen);
}
break;
#ifdef HAVE_DIRECT_WRITE
case PROP_RENDER_STATS:
g_value_set_boolean (value, self->render_stats);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -592,6 +616,9 @@ gst_d3d11_video_sink_start (GstBaseSink * sink)
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
"fullscreen", self->fullscreen,
"enable-navigation-events", self->enable_navigation_events, NULL);
#ifdef HAVE_DIRECT_WRITE
g_object_set (self->window, "render-stats", self->render_stats, NULL);
#endif
GST_OBJECT_UNLOCK (self);
g_signal_connect (self->window, "key-event",
@ -864,6 +891,7 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
gboolean need_unref = FALSE;
gboolean do_device_copy = TRUE;
gint i;
GstStructure *stats = NULL;
render_buf = buf;
@ -955,7 +983,10 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
rect.w = self->video_width;
rect.h = self->video_height;
ret = gst_d3d11_window_render (self->window, render_buf, &rect);
if (self->render_stats)
stats = gst_base_sink_get_stats (GST_BASE_SINK_CAST (self));
ret = gst_d3d11_window_render (self->window, render_buf, &rect, stats);
if (need_unref)
gst_buffer_unref (render_buf);
@ -1013,7 +1044,7 @@ gst_d3d11_video_sink_expose (GstVideoOverlay * overlay)
rect.w = GST_VIDEO_SINK_WIDTH (self);
rect.h = GST_VIDEO_SINK_HEIGHT (self);
gst_d3d11_window_render (self->window, NULL, &rect);
gst_d3d11_window_render (self->window, NULL, &rect, NULL);
}
}

View file

@ -60,6 +60,7 @@ enum
PROP_ENABLE_NAVIGATION_EVENTS,
PROP_FULLSCREEN_TOGGLE_MODE,
PROP_FULLSCREEN,
PROP_RENDER_STATS,
};
/* basesink */
@ -85,6 +86,7 @@ enum
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
#define DEFAULT_FULLSCREEN FALSE
#define DEFAULT_RENDER_STATS FALSE
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
@ -238,6 +240,15 @@ gst_d3d11_video_sink_bin_class_init (GstD3D11VideoSinkBinClass * klass)
"fullscreen",
"Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
DEFAULT_FULLSCREEN, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#ifdef HAVE_DIRECT_WRITE
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
g_param_spec_boolean ("render-stats",
"Render Stats",
"Render statistics data (e.g., average framerate) on window",
DEFAULT_RENDER_STATS,
GST_PARAM_CONDITIONALLY_AVAILABLE | GST_PARAM_MUTABLE_READY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif
gst_element_class_set_static_metadata (element_class,
"Direct3D11 video sink bin", "Sink/Video",

View file

@ -34,9 +34,17 @@
#endif
#include <windows.ui.xaml.h>
#include <windows.applicationmodel.core.h>
#endif
#ifdef HAVE_DIRECT_WRITE
#include <dwrite.h>
#include <d2d1_1.h>
#include <sstream>
#endif
#if GST_D3D11_WINAPI_ONLY_APP || defined(HAVE_DIRECT_WRITE)
#include <wrl.h>
#include <wrl/wrappers/corewrappers.h>
using namespace Microsoft::WRL;
#endif
@ -45,6 +53,21 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
#define GST_CAT_DEFAULT gst_d3d11_window_debug
}
struct _GstD3D11WindowPrivate
{
#ifdef HAVE_DIRECT_WRITE
IDWriteFactory *dwrite_factory;
IDWriteTextFormat *dwrite_format;
ID2D1Factory1 *d2d_factory;
ID2D1Device *d2d_device;
ID2D1DeviceContext *d2d_device_context;
ID2D1SolidColorBrush *d2d_brush;
#else
gpointer dummy;
#endif
};
enum
{
PROP_0,
@ -54,12 +77,14 @@ enum
PROP_FULLSCREEN_TOGGLE_MODE,
PROP_FULLSCREEN,
PROP_WINDOW_HANDLE,
PROP_RENDER_STATS,
};
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
#define DEFAULT_FULLSCREEN FALSE
#define DEFAULT_RENDER_STATS FALSE
enum
{
@ -94,7 +119,8 @@ gst_d3d11_window_fullscreen_toggle_mode_type (void)
}
#define gst_d3d11_window_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE (GstD3D11Window, gst_d3d11_window, GST_TYPE_OBJECT);
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstD3D11Window, gst_d3d11_window,
GST_TYPE_OBJECT);
static void gst_d3d11_window_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
@ -102,7 +128,7 @@ static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_d3d11_window_dispose (GObject * object);
static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
GstBuffer * buffer);
GstBuffer * buffer, GstStructure * stats);
static void gst_d3d11_window_on_resize_default (GstD3D11Window * window,
guint width, guint height);
@ -158,6 +184,15 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)));
#ifdef HAVE_DIRECT_WRITE
g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
g_param_spec_boolean ("render-stats",
"Render Stats",
"Render statistics data (e.g., average framerate) on window",
DEFAULT_RENDER_STATS,
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
#endif
d3d11_window_signals[SIGNAL_KEY_EVENT] =
g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
@ -176,6 +211,10 @@ gst_d3d11_window_init (GstD3D11Window * self)
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
self->fullscreen = DEFAULT_FULLSCREEN;
self->render_stats = DEFAULT_RENDER_STATS;
self->priv =
(GstD3D11WindowPrivate *) gst_d3d11_window_get_instance_private (self);
}
static void
@ -213,6 +252,11 @@ gst_d3d11_window_set_property (GObject * object, guint prop_id,
case PROP_WINDOW_HANDLE:
self->external_handle = (guintptr) g_value_get_pointer (value);
break;
#ifdef HAVE_DIRECT_WRITE
case PROP_RENDER_STATS:
self->render_stats = g_value_get_boolean (value);
break;
#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -244,10 +288,155 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id,
}
}
#ifdef HAVE_DIRECT_WRITE
static void
gst_d3d11_window_release_dwrite_resources (GstD3D11Window * self)
{
GstD3D11WindowPrivate *priv = self->priv;
if (priv->d2d_device_context) {
priv->d2d_device_context->Release ();
priv->d2d_device_context = NULL;
}
if (priv->d2d_factory) {
priv->d2d_factory->Release ();
priv->d2d_factory = NULL;
}
if (priv->d2d_device) {
priv->d2d_device->Release ();
priv->d2d_device = NULL;
}
if (priv->d2d_brush) {
priv->d2d_brush->Release ();
priv->d2d_brush = NULL;
}
if (priv->dwrite_factory) {
priv->dwrite_factory->Release ();
priv->dwrite_factory = NULL;
}
if (priv->dwrite_format) {
priv->dwrite_format->Release ();
priv->dwrite_format = NULL;
}
}
static void
gst_d3d11_window_prepare_dwrite_device (GstD3D11Window * self)
{
GstD3D11WindowPrivate *priv = self->priv;
HRESULT hr;
ComPtr<IDXGIDevice> dxgi_device;
ID3D11Device *device_handle;
if (!self->device) {
GST_ERROR_OBJECT (self, "D3D11Device is unavailable");
return;
}
/* Already prepared */
if (priv->d2d_device)
return;
hr = D2D1CreateFactory (D2D1_FACTORY_TYPE_MULTI_THREADED,
IID_PPV_ARGS (&priv->d2d_factory));
if (!gst_d3d11_result (hr, self->device))
goto error;
device_handle = gst_d3d11_device_get_device_handle (self->device);
hr = device_handle->QueryInterface (IID_PPV_ARGS (&dxgi_device));
if (!gst_d3d11_result (hr, self->device))
goto error;
hr = priv->d2d_factory->CreateDevice (dxgi_device.Get (), &priv->d2d_device);
if (!gst_d3d11_result (hr, self->device))
goto error;
hr = priv->d2d_device->CreateDeviceContext (D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
&priv->d2d_device_context);
if (!gst_d3d11_result (hr, self->device))
goto error;
hr = priv->d2d_device_context->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Yellow),
&priv->d2d_brush);
if (!gst_d3d11_result (hr, self->device))
goto error;
hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory), (IUnknown **) &priv->dwrite_factory);
if (!gst_d3d11_result (hr, self->device))
goto error;
/* Configure font */
hr = priv->dwrite_factory->CreateTextFormat(L"Arial", NULL,
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-US", &priv->dwrite_format);
if (!gst_d3d11_result (hr, self->device))
goto error;
GST_DEBUG_OBJECT (self, "Direct2D device is prepared");
return;
error:
gst_d3d11_window_release_dwrite_resources (self);
}
static void
gst_d3d11_window_dwrite_on_resize (GstD3D11Window * self,
ID3D11Texture2D * backbuffer)
{
GstD3D11WindowPrivate *priv = self->priv;
ComPtr<IDXGISurface> dxgi_surface;
ComPtr<ID2D1Bitmap1> bitmap;
D2D1_BITMAP_PROPERTIES1 prop;
HRESULT hr;
if (!priv->d2d_device)
return;
prop.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
prop.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
/* default dpi */
prop.dpiX = 96.0f;
prop.dpiY = 96.0f;
prop.bitmapOptions =
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
prop.colorContext = NULL;
hr = backbuffer->QueryInterface (IID_PPV_ARGS (&dxgi_surface));
if (!gst_d3d11_result (hr, self->device))
goto error;
hr = priv->d2d_device_context->CreateBitmapFromDxgiSurface (dxgi_surface.Get (),
&prop, &bitmap);
if (!gst_d3d11_result (hr, self->device))
goto error;
priv->d2d_device_context->SetTarget (bitmap.Get ());
GST_LOG_OBJECT (self, "New D2D bitmap has been configured");
return;
error:
gst_d3d11_window_release_dwrite_resources (self);
}
#endif
static void
gst_d3d11_window_release_resources (GstD3D11Device * device,
GstD3D11Window * window)
{
#ifdef HAVE_DIRECT_WRITE
gst_d3d11_window_release_dwrite_resources (window);
#endif
if (window->rtv) {
window->rtv->Release ();
window->rtv = NULL;
@ -287,6 +476,9 @@ static void
gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
guint height)
{
#ifdef HAVE_DIRECT_WRITE
GstD3D11WindowPrivate *priv = window->priv;
#endif
HRESULT hr;
ID3D11Device *device_handle;
D3D11_TEXTURE2D_DESC desc;
@ -312,6 +504,12 @@ gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
window->pov = NULL;
}
#ifdef HAVE_DIRECT_WRITE
/* D2D bitmap need to be cleared before resizing swapchain buffer */
if (priv->d2d_device_context)
priv->d2d_device_context->SetTarget (NULL);
#endif
swap_chain->GetDesc (&swap_desc);
hr = swap_chain->ResizeBuffers (0, width, height, window->dxgi_format,
swap_desc.Flags);
@ -378,10 +576,15 @@ gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
goto done;
}
#ifdef HAVE_DIRECT_WRITE
if (window->render_stats)
gst_d3d11_window_dwrite_on_resize (window, backbuffer);
#endif
window->first_present = TRUE;
/* redraw the last scene if cached buffer exits */
gst_d3d111_window_present (window, NULL);
gst_d3d111_window_present (window, NULL, NULL);
done:
if (backbuffer)
@ -489,14 +692,23 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
return FALSE;
}
for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
if (formats[2].supported) {
chosen_format = &formats[2];
#ifdef HAVE_DIRECT_WRITE
if (window->render_stats && formats[1].supported) {
/* FIXME: D2D seems to be accepting only DXGI_FORMAT_B8G8R8A8_UNORM */
chosen_format = &formats[1];
} else
#else
{
for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
if (formats[2].supported) {
chosen_format = &formats[2];
}
break;
}
break;
}
}
#endif
if (!chosen_format) {
/* prefer native format over conversion */
@ -745,6 +957,11 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
"Cannot create overlay compositor");
goto error;
}
#ifdef HAVE_DIRECT_WRITE
if (window->render_stats)
gst_d3d11_window_prepare_dwrite_device (window);
#endif
gst_d3d11_device_unlock (window->device);
/* call resize to allocated resources */
@ -815,8 +1032,60 @@ gst_d3d11_window_buffer_ensure_processor_input (GstD3D11Window * self,
return TRUE;
}
#ifdef HAVE_DIRECT_WRITE
static void
gst_d3d11_window_present_d2d (GstD3D11Window * self, GstStructure * stats)
{
GstD3D11WindowPrivate *priv = self->priv;
HRESULT hr;
gdouble framerate = 0.0;
guint64 dropped = 0;
guint64 rendered = 0;
std::wostringstream stats_str;
ComPtr<IDWriteTextLayout> layout;
FLOAT left;
FLOAT top;
if (!priv->d2d_device)
return;
if (!stats)
return;
gst_structure_get_double (stats, "average-rate", &framerate);
gst_structure_get_uint64 (stats, "dropped", &dropped);
gst_structure_get_uint64 (stats, "rendered", &rendered);
stats_str.precision (5);
stats_str << "Average-rate: " << framerate << std::endl;
stats_str << "Dropped: " << dropped << std::endl;
stats_str << "Rendered: " << rendered << std::endl;
hr = priv->dwrite_factory->CreateTextLayout (stats_str.str().c_str(),
(UINT32) stats_str.str().size(), priv->dwrite_format,
self->render_rect.right - self->render_rect.left,
self->render_rect.bottom - self->render_rect.top,
&layout);
if (!gst_d3d11_result (hr, self->device))
return;
left = self->render_rect.left + 5.0f;
top = self->render_rect.top + 5.0f;
priv->d2d_device_context->BeginDraw ();
priv->d2d_device_context->DrawTextLayout(D2D1::Point2F(left, top),
layout.Get(), priv->d2d_brush);
hr = priv->d2d_device_context->EndDraw ();
gst_d3d11_result (hr, self->device);
return;
}
#endif
static GstFlowReturn
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
GstStructure * stats)
{
GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (self);
GstFlowReturn ret = GST_FLOW_OK;
@ -885,6 +1154,10 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
}
#endif
#if HAVE_DIRECT_WRITE
gst_d3d11_window_present_d2d (self, stats);
#endif
ret = klass->present (self, present_flags);
self->first_present = FALSE;
@ -895,7 +1168,7 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
GstFlowReturn
gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
GstVideoRectangle * rect)
GstVideoRectangle * rect, GstStructure * stats)
{
GstMemory *mem;
GstFlowReturn ret;
@ -907,13 +1180,19 @@ gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
if (!gst_is_d3d11_memory (mem)) {
GST_ERROR_OBJECT (window, "Invalid buffer");
if (stats)
gst_structure_free (stats);
return GST_FLOW_ERROR;
}
gst_d3d11_device_lock (window->device);
ret = gst_d3d111_window_present (window, buffer);
ret = gst_d3d111_window_present (window, buffer, stats);
gst_d3d11_device_unlock (window->device);
if (stats)
gst_structure_free (stats);
return ret;
}

View file

@ -41,6 +41,7 @@ G_BEGIN_DECLS
typedef struct _GstD3D11Window GstD3D11Window;
typedef struct _GstD3D11WindowClass GstD3D11WindowClass;
typedef struct _GstD3D11WindowPrivate GstD3D11WindowPrivate;
#define GST_D3D11_WINDOW_FLOW_CLOSED GST_FLOW_CUSTOM_ERROR
@ -76,6 +77,7 @@ struct _GstD3D11Window
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
gboolean requested_fullscreen;
gboolean fullscreen;
gboolean render_stats;
GstVideoInfo info;
GstVideoInfo render_info;
@ -103,6 +105,8 @@ struct _GstD3D11Window
GstBuffer *cached_buffer;
gboolean first_present;
gboolean allow_tearing;
GstD3D11WindowPrivate *priv;
};
struct _GstD3D11WindowClass
@ -153,7 +157,8 @@ gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
GstBuffer * buffer,
GstVideoRectangle * src_rect);
GstVideoRectangle * src_rect,
GstStructure * stats);
gboolean gst_d3d11_window_unlock (GstD3D11Window * window);

View file

@ -65,6 +65,8 @@ d3d11_lib = cc.find_library('d3d11', required : d3d11_option)
dxgi_lib = cc.find_library('dxgi', required : d3d11_option)
d3dcompiler_lib = cc.find_library('d3dcompiler', required: d3d11_option)
runtimeobject_lib = cc.find_library('runtimeobject', required : false)
dwrite_lib = cc.find_library('dwrite', required : false)
d2d1_lib = cc.find_library('d2d1', required : false)
foreach dxgi_h: dxgi_headers
if not have_dxgi_header and cc.has_header(dxgi_h[0])
@ -177,6 +179,15 @@ if get_option('debug') and not (winapi_app_only and get_option('b_vscrt') == 'md
set_variable(f.get(3), true)
endif
endforeach
# Maybe we want to implement DirectWrite based text rendering in the future,
# but currently only debugging purpose.
# Also, MinGW is not supported for now because of toolchain issue
if cc.get_id() == 'msvc' and dwrite_lib.found() and d2d1_lib.found() and cc.has_header('dwrite.h') and cc.has_header('d2d1_1.h')
d3d11_conf.set('HAVE_DIRECT_WRITE', 1)
extra_dep += [dwrite_lib, d2d1_lib]
message('Enable DirectWrite support in D3D11 plugin')
endif
else
message('Disable D3D11Debug and DXGIDebug layers')
endif