1- // This file is a part of media_kit
1+ // This file is a part of media_kit
22// (https://github.com/media-kit/media-kit).
33//
4- // Copyright © 2025 & onwards, Predidit.
4+ // Copyright © 2026 Predidit.
55// All rights reserved.
66// Use of this source code is governed by MIT license that can be found in the
77// LICENSE file.
1313#pragma comment(lib, "dxgi.lib")
1414#pragma comment(lib, "d3d11.lib")
1515
16- #define FAIL (message ) \
17- std::cout << " media_kit: D3D11Renderer: Failure: " << message \
18- << std::endl; \
19- return false
20-
21- #define CHECK_HRESULT (message ) \
22- if (FAILED(hr)) { \
23- FAIL (message); \
24- }
25-
2616int D3D11Renderer::instance_count_ = 0 ;
2717
2818D3D11Renderer::D3D11Renderer (int32_t width, int32_t height)
2919 : width_(width), height_(height) {
30- mutex_ = ::CreateMutex (NULL , FALSE , NULL );
3120 if (!CreateD3D11Device ()) {
3221 throw std::runtime_error (" Unable to create Direct3D 11 device." );
3322 }
34- if (!CreateTexture ()) {
35- throw std::runtime_error (" Unable to create Direct3D 11 texture ." );
23+ if (!CreateMailbox ()) {
24+ throw std::runtime_error (" Unable to create mailbox swap chain ." );
3625 }
3726 instance_count_++;
3827}
3928
4029D3D11Renderer::~D3D11Renderer () {
41- CleanUp (true );
42- ::ReleaseMutex (mutex_);
43- ::CloseHandle (mutex_);
30+ mailbox_swap_chain_.Reset ();
31+
32+ if (d3d_11_device_context_) {
33+ d3d_11_device_context_->Release ();
34+ d3d_11_device_context_ = nullptr ;
35+ }
36+ if (d3d_11_device_) {
37+ d3d_11_device_->Release ();
38+ d3d_11_device_ = nullptr ;
39+ }
4440 instance_count_--;
4541}
4642
4743void D3D11Renderer::SetSize (int32_t width, int32_t height) {
48- if (width == width_ && height == height_) {
49- return ;
50- }
44+ if (width == width_ && height == height_) return ;
5145 width_ = width;
5246 height_ = height;
53-
54- // Release the old texture reference
55- if (shared_texture_) {
56- shared_texture_->Release ();
57- shared_texture_ = nullptr ;
58- }
59-
60- // Resize the swap chain (this will resize the back buffer)
61- if (swap_chain_) {
62- auto hr = swap_chain_->ResizeBuffers (1 , width_, height_,
63- DXGI_FORMAT_B8G8R8A8_UNORM, 0 );
47+ if (mailbox_swap_chain_) {
48+ const HRESULT hr = mailbox_swap_chain_->Resize (width_, height_);
6449 if (FAILED (hr)) {
65- std::cout << " media_kit: D3D11Renderer: Failed to resize swap chain"
66- << std::endl;
67- return ;
50+ std::cout << " media_kit: D3D11Renderer: Mailbox resize failed (hr=0x"
51+ << std::hex << hr << std::dec << " )" << std::endl;
6852 }
6953 }
70-
71- // Recreate the shared texture with the new size
72- CreateTexture ();
7354}
7455
75- void D3D11Renderer::CopyTexture () {
76- ::WaitForSingleObject (mutex_, INFINITE);
77-
78- // With native DXGI rendering, mpv renders directly to the swap chain's back buffer.
79- // We need to copy the back buffer to our shared texture for Flutter.
80- if (d3d_11_device_context_ != nullptr && swap_chain_ != nullptr && shared_texture_) {
81- // Get the back buffer from the swap chain
82- Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer;
83- auto hr = swap_chain_->GetBuffer (0 , __uuidof (ID3D11Texture2D),
84- (void **)&back_buffer);
85- if (SUCCEEDED (hr) && back_buffer) {
86- // Copy from back buffer to shared texture
87- d3d_11_device_context_->CopyResource (shared_texture_.Get (), back_buffer.Get ());
88- d3d_11_device_context_->Flush ();
89- }
56+ void D3D11Renderer::ProducerCommit () {
57+ if (mailbox_swap_chain_) {
58+ mailbox_swap_chain_->ProducerCommit ();
9059 }
91-
92- ::ReleaseMutex (mutex_);
9360}
9461
95- void D3D11Renderer::CleanUp (bool release_device) {
96- // Release texture
97- if (shared_texture_) {
98- shared_texture_->Release ();
99- shared_texture_ = nullptr ;
100- }
101-
102- // Release swap chain
103- if (swap_chain_) {
104- swap_chain_->Release ();
105- swap_chain_ = nullptr ;
62+ HANDLE D3D11Renderer::ConsumerAcquire () {
63+ if (mailbox_swap_chain_) {
64+ return mailbox_swap_chain_->ConsumerAcquire ();
10665 }
66+ return nullptr ;
67+ }
10768
108- // Release device and context if the instance is being destroyed
109- if (release_device) {
110- if (d3d_11_device_context_) {
111- d3d_11_device_context_->Release ();
112- d3d_11_device_context_ = nullptr ;
113- }
114- if (d3d_11_device_) {
115- d3d_11_device_->Release ();
116- d3d_11_device_ = nullptr ;
117- }
69+ HANDLE D3D11Renderer::ReadHandleSnapshot () const {
70+ if (mailbox_swap_chain_) {
71+ return mailbox_swap_chain_->ReadHandleSnapshot ();
11872 }
73+ return nullptr ;
11974}
12075
12176bool D3D11Renderer::CreateD3D11Device () {
122- if (d3d_11_device_ != nullptr ) {
123- return true ; // Already created
124- }
77+ if (d3d_11_device_) return true ;
12578
12679 const D3D_FEATURE_LEVEL feature_levels[] = {
12780 D3D_FEATURE_LEVEL_11_1,
@@ -134,9 +87,7 @@ bool D3D11Renderer::CreateD3D11Device() {
13487 IDXGIAdapter* adapter = nullptr ;
13588 D3D_DRIVER_TYPE driver_type = D3D_DRIVER_TYPE_UNKNOWN;
13689
137- // Automatically selecting adapter on Windows 10 RTM or greater
13890 if (Utils::IsWindows10RTMOrGreater ()) {
139- adapter = nullptr ;
14091 driver_type = D3D_DRIVER_TYPE_HARDWARE;
14192 } else {
14293 IDXGIFactory* dxgi = nullptr ;
@@ -147,74 +98,45 @@ bool D3D11Renderer::CreateD3D11Device() {
14798 }
14899 }
149100
150- // Create swap chain descriptor for offscreen rendering
151- DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
152- swap_chain_desc.BufferDesc .Width = width_;
153- swap_chain_desc.BufferDesc .Height = height_;
154- swap_chain_desc.BufferDesc .Format = DXGI_FORMAT_B8G8R8A8_UNORM;
155- swap_chain_desc.BufferDesc .RefreshRate .Numerator = 0 ;
156- swap_chain_desc.BufferDesc .RefreshRate .Denominator = 1 ;
157- swap_chain_desc.SampleDesc .Count = 1 ;
158- swap_chain_desc.SampleDesc .Quality = 0 ;
159- swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
160- swap_chain_desc.BufferCount = 1 ;
161- // Use desktop window for offscreen rendering
162- swap_chain_desc.OutputWindow = ::GetDesktopWindow ();
163- swap_chain_desc.Windowed = TRUE ;
164- swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
165-
166- auto hr = ::D3D11CreateDeviceAndSwapChain (
167- adapter, driver_type, 0 , 0 , feature_levels,
168- sizeof (feature_levels) / sizeof (D3D_FEATURE_LEVEL), D3D11_SDK_VERSION,
169- &swap_chain_desc, &swap_chain_,
170- &d3d_11_device_, nullptr , &d3d_11_device_context_);
171-
172- CHECK_HRESULT (" D3D11CreateDeviceAndSwapChain" );
173-
174- Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device = nullptr ;
175- auto dxgi_device_success = d3d_11_device_->QueryInterface (
176- __uuidof (IDXGIDevice), (void **)&dxgi_device);
177- if (SUCCEEDED (dxgi_device_success) && dxgi_device != nullptr ) {
178- dxgi_device->SetGPUThreadPriority (5 ); // Must be in interval [-7, 7]
101+ const HRESULT hr = ::D3D11CreateDevice (
102+ adapter, driver_type, nullptr ,
103+ D3D11_CREATE_DEVICE_BGRA_SUPPORT,
104+ feature_levels, static_cast <UINT>(std::size (feature_levels)),
105+ D3D11_SDK_VERSION, &d3d_11_device_, nullptr , &d3d_11_device_context_);
106+
107+ if (adapter) adapter->Release ();
108+
109+ if (FAILED (hr)) {
110+ std::cout << " media_kit: D3D11Renderer: D3D11CreateDevice failed (hr=0x"
111+ << std::hex << hr << std::dec << " )" << std::endl;
112+ return false ;
179113 }
180114
181- auto level = d3d_11_device_->GetFeatureLevel ();
115+ Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
116+ if (SUCCEEDED (d3d_11_device_->QueryInterface (__uuidof (IDXGIDevice),
117+ (void **)&dxgi_device)) &&
118+ dxgi_device) {
119+ dxgi_device->SetGPUThreadPriority (5 );
120+ }
121+
122+ const auto level = d3d_11_device_->GetFeatureLevel ();
182123 std::cout << " media_kit: D3D11Renderer: Direct3D Feature Level: "
183- << ((( unsigned ) level) >> 12 ) << " _"
184- << (((( unsigned ) level) >> 8 ) & 0xf ) << std::endl;
124+ << (static_cast < unsigned >( level) >> 12 ) << " _"
125+ << ((static_cast < unsigned >( level) >> 8 ) & 0xfu ) << std::endl;
185126
186127 return true ;
187128}
188129
189- bool D3D11Renderer::CreateTexture () {
190- // Create a separate shared texture for Flutter
191- // (The swap chain back buffer cannot be shared directly with Flutter)
192- D3D11_TEXTURE2D_DESC texture_desc = {0 };
193- texture_desc.Width = width_;
194- texture_desc.Height = height_;
195- texture_desc.MipLevels = 1 ;
196- texture_desc.ArraySize = 1 ;
197- texture_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
198- texture_desc.SampleDesc .Count = 1 ;
199- texture_desc.SampleDesc .Quality = 0 ;
200- texture_desc.Usage = D3D11_USAGE_DEFAULT;
201- texture_desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
202- texture_desc.CPUAccessFlags = 0 ;
203- texture_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
204-
205- auto hr = d3d_11_device_->CreateTexture2D (&texture_desc, nullptr ,
206- &shared_texture_);
207- CHECK_HRESULT (" ID3D11Device::CreateTexture2D" );
208-
209- Microsoft::WRL::ComPtr<IDXGIResource> resource;
210- hr = shared_texture_.As (&resource);
211- CHECK_HRESULT (" ID3D11Texture2D::As<IDXGIResource>" );
212-
213- // Retrieve the shared HANDLE for interop with Flutter
214- hr = resource->GetSharedHandle (&handle_);
215- CHECK_HRESULT (" IDXGIResource::GetSharedHandle" );
216-
217- shared_texture_->AddRef ();
218-
130+ bool D3D11Renderer::CreateMailbox () {
131+ MailboxSwapChain* raw = nullptr ;
132+ const HRESULT hr =
133+ MailboxSwapChain::Create (d3d_11_device_, width_, height_, &raw);
134+ if (FAILED (hr)) {
135+ std::cout << " media_kit: D3D11Renderer: MailboxSwapChain::Create failed "
136+ " (hr=0x"
137+ << std::hex << hr << std::dec << " )" << std::endl;
138+ return false ;
139+ }
140+ mailbox_swap_chain_.Attach (raw);
219141 return true ;
220- }
142+ }
0 commit comments