From 228fc4503563e32c85195466d88a7564983c6a42 Mon Sep 17 00:00:00 2001 From: Nomango Date: Fri, 22 May 2020 21:07:32 +0800 Subject: [PATCH] make Direct3D resources global --- projects/kiwano/kiwano.vcxproj | 1 + projects/kiwano/kiwano.vcxproj.filters | 3 + src/kiwano-imgui/imgui_impl/imgui_impl.h | 12 +- src/kiwano/platform/Window.cpp | 5 - src/kiwano/platform/Window.h | 32 +++- src/kiwano/platform/win32/WindowImpl.cpp | 78 ++++++++ .../render/DirectX/D2DDeviceResources.cpp | 72 ++++---- .../render/DirectX/D2DDeviceResources.h | 17 +- .../render/DirectX/D3D10DeviceResources.cpp | 166 ++++++++++-------- .../render/DirectX/D3D10DeviceResources.h | 11 +- .../render/DirectX/D3D11DeviceResources.cpp | 166 ++++++++++-------- .../render/DirectX/D3D11DeviceResources.h | 10 +- .../render/DirectX/D3DDeviceResources.h | 54 ++++++ .../render/DirectX/D3DDeviceResourcesBase.h | 11 ++ src/kiwano/render/DirectX/RendererImpl.cpp | 94 ++-------- src/kiwano/render/DirectX/RendererImpl.h | 44 +---- src/kiwano/render/DirectX/helper.h | 2 + src/kiwano/render/Renderer.h | 19 -- 18 files changed, 463 insertions(+), 334 deletions(-) create mode 100644 src/kiwano/render/DirectX/D3DDeviceResources.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index 6c148289..7fe3b647 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -79,6 +79,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 3bbe6b4a..bec9acbc 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -336,6 +336,9 @@ core + + render\DirectX + diff --git a/src/kiwano-imgui/imgui_impl/imgui_impl.h b/src/kiwano-imgui/imgui_impl/imgui_impl.h index bd98a2c5..24008337 100644 --- a/src/kiwano-imgui/imgui_impl/imgui_impl.h +++ b/src/kiwano-imgui/imgui_impl/imgui_impl.h @@ -7,13 +7,12 @@ #if !defined(KGE_USE_DIRECTX10) #include -#include +#include inline bool ImGui_Impl_Init() { - ::kiwano::RendererImpl& renderer = ::kiwano::RendererImpl::GetInstance(); - return ImGui_ImplDX11_Init(renderer.GetD3DDeviceResources()->GetDevice(), - renderer.GetD3DDeviceResources()->GetDeviceContext()); + auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); + return ImGui_ImplDX11_Init(d3d->GetDevice(), d3d->GetDeviceContext()); } inline void ImGui_Impl_Shutdown() @@ -44,11 +43,12 @@ inline bool ImGui_Impl_CreateDeviceObjects() #else #include +#include inline bool ImGui_Impl_Init() { - ::kiwano::RendererImpl& renderer = ::kiwano::RendererImpl::GetInstance(); - return ImGui_ImplDX10_Init(renderer.GetD3DDeviceResources()->GetDevice()); + auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); + return ImGui_ImplDX10_Init(d3d->GetDevice()); } inline void ImGui_Impl_Shutdown() diff --git a/src/kiwano/platform/Window.cpp b/src/kiwano/platform/Window.cpp index 1fdd40d7..0dcdb4fc 100644 --- a/src/kiwano/platform/Window.cpp +++ b/src/kiwano/platform/Window.cpp @@ -84,11 +84,6 @@ void Window::SetShouldClose(bool should) should_close_ = should; } -void Window::SetFullscreenState(bool is_fullscreen) -{ - is_fullscreen_ = is_fullscreen; -} - void Window::PushEvent(EventPtr evt) { event_queue_.push(evt); diff --git a/src/kiwano/platform/Window.h b/src/kiwano/platform/Window.h index a982bfaa..749a5304 100644 --- a/src/kiwano/platform/Window.h +++ b/src/kiwano/platform/Window.h @@ -45,6 +45,17 @@ enum class CursorType SizeNWSE, ///< 指向左上到右下方向的箭头 }; +/** + * \~chinese + * @brief 分辨率 + */ +struct Resolution +{ + uint32_t width; ///< 分辨率宽度 + uint32_t height; ///< 分辨率高度 + uint32_t refresh_rate; ///< 刷新率 +}; + #if defined(KGE_PLATFORM_WINDOWS) typedef HWND WindowHandle; @@ -143,6 +154,21 @@ public: */ virtual void SetCursor(CursorType cursor) = 0; + /** + * \~chinese + * @brief 设置分辨率 + * @param width 分辨率宽度 + * @param height 分辨率高度 + * @param fullscreen 是否全屏 + */ + virtual void SetResolution(uint32_t width, uint32_t height, bool fullscreen) = 0; + + /** + * \~chinese + * @brief 获取支持的屏幕分辨率列表 + */ + virtual Vector GetResolutions() = 0; + /** * \~chinese * @brief 轮询窗口事件 @@ -175,12 +201,6 @@ public: */ void SetShouldClose(bool should); - /** - * \~chinese - * @brief 设置当前是否是全屏状态 - */ - void SetFullscreenState(bool is_fullscreen); - protected: Window(); diff --git a/src/kiwano/platform/win32/WindowImpl.cpp b/src/kiwano/platform/win32/WindowImpl.cpp index ffe85838..6cd573ea 100644 --- a/src/kiwano/platform/win32/WindowImpl.cpp +++ b/src/kiwano/platform/win32/WindowImpl.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include // GET_X_LPARAM, GET_Y_LPARAM #include // ImmAssociateContext #pragma comment(lib, "imm32.lib") @@ -60,6 +61,10 @@ public: void SetCursor(CursorType cursor) override; + void SetResolution(uint32_t width, uint32_t height, bool fullscreen) override; + + Vector GetResolutions() override; + void PumpEvents() override; DWORD GetStyle() const; @@ -77,6 +82,7 @@ private: CursorType mouse_cursor_; String device_name_; + Vector resolutions_; std::array key_map_; }; @@ -338,6 +344,78 @@ void WindowWin32Impl::SetCursor(CursorType cursor) mouse_cursor_ = cursor; } +void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen) +{ + auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); + + if (fullscreen) + { + HRESULT hr = d3d->ResizeTarget(width, height); + KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); + + hr = d3d->SetFullscreenState(fullscreen); + KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); + } + else + { + HRESULT hr = d3d->SetFullscreenState(fullscreen); + KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); + + hr = d3d->ResizeTarget(width, height); + KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); + } + + is_fullscreen_ = fullscreen; +} + +Vector WindowWin32Impl::GetResolutions() +{ + if (resolutions_.empty()) + { + auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); + + DXGI_MODE_DESC* mode_descs = nullptr; + int mode_num = 0; + + HRESULT hr = d3d->GetDisplaySettings(&mode_descs, &mode_num); + if (SUCCEEDED(hr)) + { + std::unique_ptr mode_list(mode_descs); + + if (mode_list) + { + for (int i = 0; i < mode_num; i++) + { + Resolution res; + res.width = mode_descs[i].Width; + res.height = mode_descs[i].Height; + res.refresh_rate = 0; + + if (mode_descs[i].RefreshRate.Denominator > 0) + { + res.refresh_rate = mode_descs[i].RefreshRate.Numerator / mode_descs[i].RefreshRate.Denominator; + } + + if (!resolutions_.empty()) + { + auto& back = resolutions_.back(); + if (back.width == res.width && back.height == res.height + && back.refresh_rate == res.refresh_rate) + continue; + } + + resolutions_.push_back(res); + } + } + } + else + { + KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!"); + } + } + return resolutions_; +} + DWORD WindowWin32Impl::GetStyle() const { return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); diff --git a/src/kiwano/render/DirectX/D2DDeviceResources.cpp b/src/kiwano/render/DirectX/D2DDeviceResources.cpp index 3f522162..538725de 100644 --- a/src/kiwano/render/DirectX/D2DDeviceResources.cpp +++ b/src/kiwano/render/DirectX/D2DDeviceResources.cpp @@ -26,6 +26,14 @@ namespace kiwano { +namespace graphics +{ +namespace directx +{ + +// Global pointer for Direct2D device resources +static ComPtr global_d2d_device_resource; + struct D2DDeviceResources : public ID2DDeviceResources { public: @@ -33,6 +41,8 @@ public: virtual ~D2DDeviceResources(); + HRESULT Initialize(_In_ ComPtr dxgi_device, _In_ ComPtr dxgi_swap_chain) override; + HRESULT CreateDeviceIndependentResources(); HRESULT CreateDeviceResources(_In_ ComPtr dxgi_device, _In_ ComPtr dxgi_swap_chain); @@ -57,8 +67,8 @@ public: _In_ ComPtr collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT font_size) override; - HRESULT CreateTextLayout(_Out_ ComPtr& text_layout, _In_ LPCWSTR text, - UINT32 length, _In_ ComPtr text_format) override; + HRESULT CreateTextLayout(_Out_ ComPtr& text_layout, _In_ LPCWSTR text, UINT32 length, + _In_ ComPtr text_format) override; HRESULT SetDpi(float dpi) override; @@ -85,40 +95,14 @@ private: ComPtr dxgi_swap_chain_; }; -HRESULT ID2DDeviceResources::Create(_Out_ ID2DDeviceResources** device_resources, _In_ ComPtr dxgi_device, - _In_ ComPtr dxgi_swap_chain) + +ComPtr GetD2DDeviceResources() { - HRESULT hr = E_FAIL; - if (device_resources) + if (!global_d2d_device_resource) { - D2DDeviceResources* res = new (std::nothrow) D2DDeviceResources; - if (res) - { - hr = res->CreateDeviceIndependentResources(); - - if (SUCCEEDED(hr)) - { - hr = res->CreateDeviceResources(dxgi_device, dxgi_swap_chain); - } - - if (SUCCEEDED(hr)) - { - hr = res->CreateWindowSizeDependentResources(); - } - } - - if (SUCCEEDED(hr)) - { - DX::SafeRelease(*device_resources); - (*device_resources) = DX::SafeAcquire(res); - } - else - { - delete res; - res = nullptr; - } + global_d2d_device_resource.Reset(new (std::nothrow) D2DDeviceResources); } - return hr; + return global_d2d_device_resource; } D2DDeviceResources::D2DDeviceResources() @@ -132,6 +116,22 @@ D2DDeviceResources::~D2DDeviceResources() DiscardResources(); } +HRESULT D2DDeviceResources::Initialize(ComPtr dxgi_device, ComPtr dxgi_swap_chain) +{ + HRESULT hr = this->CreateDeviceIndependentResources(); + + if (SUCCEEDED(hr)) + { + hr = this->CreateDeviceResources(dxgi_device, dxgi_swap_chain); + } + + if (SUCCEEDED(hr)) + { + hr = this->CreateWindowSizeDependentResources(); + } + return hr; +} + STDMETHODIMP_(unsigned long) D2DDeviceResources::AddRef() { return InterlockedIncrement(&ref_count_); @@ -423,8 +423,8 @@ HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr& te return E_UNEXPECTED; ComPtr output; - HRESULT hr = dwrite_factory_->CreateTextFormat(family, collection.Get(), weight, style, stretch, font_size, - L"", &output); + HRESULT hr = + dwrite_factory_->CreateTextFormat(family, collection.Get(), weight, style, stretch, font_size, L"", &output); if (SUCCEEDED(hr)) { @@ -450,4 +450,6 @@ HRESULT D2DDeviceResources::CreateTextLayout(_Out_ ComPtr& te return hr; } +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D2DDeviceResources.h b/src/kiwano/render/DirectX/D2DDeviceResources.h index a61e3f24..4c57f263 100644 --- a/src/kiwano/render/DirectX/D2DDeviceResources.h +++ b/src/kiwano/render/DirectX/D2DDeviceResources.h @@ -26,12 +26,16 @@ namespace kiwano { +namespace graphics +{ +namespace directx +{ + MIDL_INTERFACE("5706684a-bf6d-4b03-b627-094758a33032") KGE_API ID2DDeviceResources : public IUnknown { public: - static HRESULT Create(_Out_ ID2DDeviceResources * *device_resources, _In_ ComPtr dxgi_device, - _In_ ComPtr dxgi_swap_chain); + virtual HRESULT Initialize(_In_ ComPtr dxgi_device, _In_ ComPtr dxgi_swap_chain) = 0; virtual HRESULT CreateBitmapConverter(_Out_ ComPtr & converter, _In_opt_ ComPtr source, _In_ REFWICPixelFormatGUID format, @@ -51,8 +55,8 @@ public: _In_ ComPtr collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, FLOAT font_size) = 0; - virtual HRESULT CreateTextLayout(_Out_ ComPtr & text_layout, _In_ LPCWSTR text, - UINT32 length, _In_ ComPtr text_format) = 0; + virtual HRESULT CreateTextLayout(_Out_ ComPtr & text_layout, _In_ LPCWSTR text, UINT32 length, + _In_ ComPtr text_format) = 0; virtual HRESULT SetDpi(float dpi) = 0; @@ -111,4 +115,9 @@ protected: ComPtr dwrite_factory_; }; + +extern ComPtr GetD2DDeviceResources(); + +} +} } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp index 26897fa8..a5bc29e5 100644 --- a/src/kiwano/render/DirectX/D3D10DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D10DeviceResources.cpp @@ -25,9 +25,14 @@ namespace kiwano { - -namespace DX +namespace graphics { +namespace directx +{ + +// Global pointer for Direct3D11 device resources +static ComPtr global_d3d10_device_resources; + HRESULT CreateD3DDevice(IDXGIAdapter* adapter, D3D10_DRIVER_TYPE driver_type, uint32_t flags, ID3D10Device1** device) { HRESULT hr = S_OK; @@ -60,11 +65,11 @@ inline bool SdkLayersAvailable() } #endif -} // namespace DX - struct D3D10DeviceResources : public ID3D10DeviceResources { public: + HRESULT Initialize(HWND hwnd) override; + HRESULT Present(bool vsync) override; void ClearRenderTarget(Color& clear_color) override; @@ -77,6 +82,8 @@ public: HRESULT SetFullscreenState(bool fullscreen) override; + HRESULT GetFullscreenState(bool* fullscreen) override; + HRESULT ResizeTarget(UINT width, UINT height) override; HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) override; @@ -108,6 +115,16 @@ public: DXGI_FORMAT desired_color_format_; }; + +ComPtr GetD3D10DeviceResources() +{ + if (!global_d3d10_device_resources) + { + global_d3d10_device_resources.Reset(new (std::nothrow) D3D10DeviceResources); + } + return global_d3d10_device_resources; +} + D3D10DeviceResources::D3D10DeviceResources() : ref_count_(0) , hwnd_(nullptr) @@ -121,55 +138,34 @@ D3D10DeviceResources::~D3D10DeviceResources() DiscardResources(); } -HRESULT ID3D10DeviceResources::Create(ID3D10DeviceResources** device_resources, HWND hwnd) +HRESULT D3D10DeviceResources::Initialize(HWND hwnd) { - HRESULT hr = E_FAIL; + RECT rc; + ::GetClientRect(hwnd, &rc); - if (device_resources) + this->hwnd_ = hwnd; + this->logical_size_.x = float(rc.right - rc.left); + this->logical_size_.y = float(rc.bottom - rc.top); + + HRESULT hr = this->CreateDeviceResources(); + + if (SUCCEEDED(hr)) { - D3D10DeviceResources* res = new (std::nothrow) D3D10DeviceResources; - if (res) - { - RECT rc; - ::GetClientRect(hwnd, &rc); - - res->hwnd_ = hwnd; - res->logical_size_.x = float(rc.right - rc.left); - res->logical_size_.y = float(rc.bottom - rc.top); - - hr = res->CreateDeviceResources(); - - if (SUCCEEDED(hr)) - { - hr = res->CreateWindowSizeDependentResources(); - } - - if (SUCCEEDED(hr)) - { - res->AddRef(); - - if (*device_resources) - { - (*device_resources)->Release(); - } - (*device_resources) = res; - } - else - { - delete res; - res = nullptr; - } - } + hr = this->CreateWindowSizeDependentResources(); } return hr; } HRESULT D3D10DeviceResources::Present(bool vsync) { - KGE_ASSERT(dxgi_swap_chain_ != nullptr); + HRESULT hr = E_FAIL; - // The first argument instructs DXGI to block until VSync. - return dxgi_swap_chain_->Present(vsync ? 1 : 0, 0); + if (dxgi_swap_chain_) + { + // The first argument instructs DXGI to block until VSync. + hr = dxgi_swap_chain_->Present(vsync ? 1 : 0, DXGI_PRESENT_DO_NOT_WAIT); + } + return hr; } void D3D10DeviceResources::ClearRenderTarget(Color& clear_color) @@ -202,14 +198,14 @@ HRESULT D3D10DeviceResources::CreateDeviceResources() uint32_t creation_flags = D3D10_CREATE_DEVICE_BGRA_SUPPORT; #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) - if (DX::SdkLayersAvailable()) + if (SdkLayersAvailable()) { creation_flags |= D3D10_CREATE_DEVICE_DEBUG; } #endif ComPtr device; - hr = DX::CreateD3DDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, creation_flags, &device); + hr = CreateD3DDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, creation_flags, &device); if (SUCCEEDED(hr)) { @@ -415,53 +411,79 @@ HRESULT D3D10DeviceResources::SetDpi(float dpi) HRESULT D3D10DeviceResources::SetFullscreenState(bool fullscreen) { - HRESULT hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); + } + return hr; +} + +HRESULT D3D10DeviceResources::GetFullscreenState(bool* fullscreen) +{ + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + BOOL is_fullscreen; + hr = dxgi_swap_chain_->GetFullscreenState(&is_fullscreen, nullptr); + + if (SUCCEEDED(hr)) + { + (*fullscreen) = (is_fullscreen == TRUE); + } + } return hr; } HRESULT D3D10DeviceResources::ResizeTarget(UINT width, UINT height) { - DXGI_MODE_DESC desc = { 0 }; - desc.Width = width; - desc.Height = height; - desc.Format = DXGI_FORMAT_UNKNOWN; + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + DXGI_MODE_DESC desc = { 0 }; + desc.Width = width; + desc.Height = height; + desc.Format = DXGI_FORMAT_UNKNOWN; - HRESULT hr = dxgi_swap_chain_->ResizeTarget(&desc); + hr = dxgi_swap_chain_->ResizeTarget(&desc); + } return hr; } HRESULT D3D10DeviceResources::GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) { - KGE_ASSERT(dxgi_swap_chain_); - - ComPtr output; - HRESULT hr = dxgi_swap_chain_->GetContainingOutput(&output); - - if (SUCCEEDED(hr)) + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) { - UINT num_of_supported_modes = 0; - output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, 0); + ComPtr output; + hr = dxgi_swap_chain_->GetContainingOutput(&output); - if (num_of_supported_modes > 0) + if (SUCCEEDED(hr)) { - DXGI_MODE_DESC* supported_modes = new DXGI_MODE_DESC[num_of_supported_modes]; - ZeroMemory(supported_modes, sizeof(DXGI_MODE_DESC) * num_of_supported_modes); + UINT num_of_supported_modes = 0; + output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, 0); - hr = output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, supported_modes); - if (SUCCEEDED(hr) && mode_descs && num) + if (num_of_supported_modes > 0) { - (*mode_descs) = supported_modes; - (*num) = (int)num_of_supported_modes; + DXGI_MODE_DESC* supported_modes = new DXGI_MODE_DESC[num_of_supported_modes]; + ZeroMemory(supported_modes, sizeof(DXGI_MODE_DESC) * num_of_supported_modes); + + hr = output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, supported_modes); + if (SUCCEEDED(hr) && mode_descs && num) + { + (*mode_descs) = supported_modes; + (*num) = (int)num_of_supported_modes; + } + else + { + delete[] supported_modes; + } } else { - delete[] supported_modes; + hr = E_FAIL; } } - else - { - hr = E_FAIL; - } } return hr; } @@ -509,4 +531,6 @@ STDMETHODIMP D3D10DeviceResources::QueryInterface(const IID& riid, void** object return S_OK; } +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3D10DeviceResources.h b/src/kiwano/render/DirectX/D3D10DeviceResources.h index 7ea02e61..0c12878f 100644 --- a/src/kiwano/render/DirectX/D3D10DeviceResources.h +++ b/src/kiwano/render/DirectX/D3D10DeviceResources.h @@ -26,12 +26,15 @@ namespace kiwano { +namespace graphics +{ +namespace directx +{ + MIDL_INTERFACE("3a150b9d-cc23-4022-a463-7e95452a54c4") KGE_API ID3D10DeviceResources : public ID3DDeviceResourcesBase { public: - static HRESULT Create(ID3D10DeviceResources * *device_resources, HWND hwnd); - inline ID3D10Device* GetDevice() { KGE_ASSERT(device_); @@ -77,4 +80,8 @@ protected: ComPtr dxgi_swap_chain_; }; +extern ComPtr GetD3D11DeviceResources(); + +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp index e39e69f3..65da7e5f 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.cpp +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.cpp @@ -31,9 +31,16 @@ KGE_SUPPRESS_WARNING_POP namespace kiwano { -#if defined(KGE_DEBUG) -namespace DX +namespace graphics { +namespace directx +{ + +// Global pointer for Direct3D11 device resources +static ComPtr global_d3d11_device_resources; + + +#if defined(KGE_DEBUG) inline bool SdkLayersAvailable() { HRESULT hr = D3D11CreateDevice(nullptr, @@ -46,15 +53,15 @@ inline bool SdkLayersAvailable() nullptr, // No need to know the feature level. nullptr // No need to keep the D3D device context reference. ); - return SUCCEEDED(hr); } -} // namespace DX #endif struct D3D11DeviceResources : public ID3D11DeviceResources { public: + HRESULT Initialize(HWND hwnd) override; + HRESULT Present(bool vsync) override; void ClearRenderTarget(Color& clear_color) override; @@ -67,6 +74,8 @@ public: HRESULT SetFullscreenState(bool fullscreen) override; + HRESULT GetFullscreenState(bool* fullscreen) override; + HRESULT ResizeTarget(UINT width, UINT height) override; HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) override; @@ -100,6 +109,16 @@ public: DXGI_FORMAT desired_color_format_; }; + +ComPtr GetD3D11DeviceResources() +{ + if (!global_d3d11_device_resources) + { + global_d3d11_device_resources.Reset(new (std::nothrow) D3D11DeviceResources); + } + return global_d3d11_device_resources; +} + D3D11DeviceResources::D3D11DeviceResources() : ref_count_(0) , hwnd_(nullptr) @@ -114,55 +133,34 @@ D3D11DeviceResources::~D3D11DeviceResources() DiscardResources(); } -HRESULT ID3D11DeviceResources::Create(ID3D11DeviceResources** device_resources, HWND hwnd) +HRESULT D3D11DeviceResources::Initialize(HWND hwnd) { - HRESULT hr = E_FAIL; + RECT rc; + ::GetClientRect(hwnd, &rc); - if (device_resources) + this->hwnd_ = hwnd; + this->logical_size_.x = float(rc.right - rc.left); + this->logical_size_.y = float(rc.bottom - rc.top); + + HRESULT hr = this->CreateDeviceResources(); + + if (SUCCEEDED(hr)) { - D3D11DeviceResources* res = new (std::nothrow) D3D11DeviceResources; - if (res) - { - RECT rc; - ::GetClientRect(hwnd, &rc); - - res->hwnd_ = hwnd; - res->logical_size_.x = float(rc.right - rc.left); - res->logical_size_.y = float(rc.bottom - rc.top); - - hr = res->CreateDeviceResources(); - - if (SUCCEEDED(hr)) - { - hr = res->CreateWindowSizeDependentResources(); - } - - if (SUCCEEDED(hr)) - { - res->AddRef(); - - if (*device_resources) - { - (*device_resources)->Release(); - } - (*device_resources) = res; - } - else - { - delete res; - res = nullptr; - } - } + hr = this->CreateWindowSizeDependentResources(); } return hr; } HRESULT D3D11DeviceResources::Present(bool vsync) { - KGE_ASSERT(dxgi_swap_chain_ != nullptr); + HRESULT hr = E_FAIL; - // The first argument instructs DXGI to block until VSync. - return dxgi_swap_chain_->Present(vsync ? 1 : 0, 0); + if (dxgi_swap_chain_) + { + // The first argument instructs DXGI to block until VSync. + hr = dxgi_swap_chain_->Present(vsync ? 1 : 0, DXGI_PRESENT_DO_NOT_WAIT); + } + return hr; } void D3D11DeviceResources::ClearRenderTarget(Color& clear_color) @@ -204,7 +202,7 @@ HRESULT D3D11DeviceResources::CreateDeviceResources() uint32_t creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if defined(KGE_DEBUG) && defined(KGE_ENABLE_DX_DEBUG) - if (DX::SdkLayersAvailable()) + if (SdkLayersAvailable()) { creation_flags |= D3D11_CREATE_DEVICE_DEBUG; } @@ -436,53 +434,79 @@ HRESULT D3D11DeviceResources::SetDpi(float dpi) HRESULT D3D11DeviceResources::SetFullscreenState(bool fullscreen) { - HRESULT hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + hr = dxgi_swap_chain_->SetFullscreenState(fullscreen ? TRUE : FALSE, nullptr); + } + return hr; +} + +HRESULT D3D11DeviceResources::GetFullscreenState(bool* fullscreen) +{ + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + BOOL is_fullscreen; + hr = dxgi_swap_chain_->GetFullscreenState(&is_fullscreen, nullptr); + + if (SUCCEEDED(hr)) + { + (*fullscreen) = (is_fullscreen == TRUE); + } + } return hr; } HRESULT D3D11DeviceResources::ResizeTarget(UINT width, UINT height) { - DXGI_MODE_DESC desc = { 0 }; - desc.Width = width; - desc.Height = height; - desc.Format = DXGI_FORMAT_UNKNOWN; + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) + { + DXGI_MODE_DESC desc = { 0 }; + desc.Width = width; + desc.Height = height; + desc.Format = DXGI_FORMAT_UNKNOWN; - HRESULT hr = dxgi_swap_chain_->ResizeTarget(&desc); + hr = dxgi_swap_chain_->ResizeTarget(&desc); + } return hr; } HRESULT D3D11DeviceResources::GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) { - KGE_ASSERT(dxgi_swap_chain_); - - ComPtr output; - HRESULT hr = dxgi_swap_chain_->GetContainingOutput(&output); - - if (SUCCEEDED(hr)) + HRESULT hr = E_FAIL; + if (dxgi_swap_chain_) { - UINT num_of_supported_modes = 0; - output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, 0); + ComPtr output; + HRESULT hr = dxgi_swap_chain_->GetContainingOutput(&output); - if (num_of_supported_modes > 0) + if (SUCCEEDED(hr)) { - DXGI_MODE_DESC* supported_modes = new DXGI_MODE_DESC[num_of_supported_modes]; - ZeroMemory(supported_modes, sizeof(DXGI_MODE_DESC) * num_of_supported_modes); + UINT num_of_supported_modes = 0; + output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, 0); - hr = output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, supported_modes); - if (SUCCEEDED(hr) && mode_descs && num) + if (num_of_supported_modes > 0) { - (*mode_descs) = supported_modes; - (*num) = (int)num_of_supported_modes; + DXGI_MODE_DESC* supported_modes = new DXGI_MODE_DESC[num_of_supported_modes]; + ZeroMemory(supported_modes, sizeof(DXGI_MODE_DESC) * num_of_supported_modes); + + hr = output->GetDisplayModeList(desired_color_format_, 0, &num_of_supported_modes, supported_modes); + if (SUCCEEDED(hr) && mode_descs && num) + { + (*mode_descs) = supported_modes; + (*num) = (int)num_of_supported_modes; + } + else + { + delete[] supported_modes; + } } else { - delete[] supported_modes; + hr = E_FAIL; } } - else - { - hr = E_FAIL; - } } return hr; } @@ -530,4 +554,6 @@ STDMETHODIMP D3D11DeviceResources::QueryInterface(const IID& riid, void** object return S_OK; } +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3D11DeviceResources.h b/src/kiwano/render/DirectX/D3D11DeviceResources.h index 8adf06bd..3950a7e6 100644 --- a/src/kiwano/render/DirectX/D3D11DeviceResources.h +++ b/src/kiwano/render/DirectX/D3D11DeviceResources.h @@ -26,13 +26,15 @@ namespace kiwano { +namespace graphics +{ +namespace directx +{ MIDL_INTERFACE("3ede2b87-a202-4799-a39b-2308ad34cae8") KGE_API ID3D11DeviceResources : public ID3DDeviceResourcesBase { public: - static HRESULT Create(ID3D11DeviceResources * *device_resources, HWND hwnd); - inline ID3D11Device* GetDevice() { KGE_ASSERT(device_); @@ -85,4 +87,8 @@ protected: ComPtr dxgi_swap_chain_; }; +extern ComPtr GetD3D11DeviceResources(); + +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3DDeviceResources.h b/src/kiwano/render/DirectX/D3DDeviceResources.h new file mode 100644 index 00000000..fd625ba5 --- /dev/null +++ b/src/kiwano/render/DirectX/D3DDeviceResources.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once + +#if defined(KGE_USE_DIRECTX10) +#include +#else +#include +#endif + +namespace kiwano +{ +namespace graphics +{ +namespace directx +{ + +#if defined(KGE_USE_DIRECTX10) + using ID3DDeviceResources = kiwano::graphics::directx::ID3D10DeviceResources; + + inline ComPtr GetD3DDeviceResources() + { + return kiwano::graphics::directx::GetD3D10DeviceResources(); + } +#else + using ID3DDeviceResources = kiwano::graphics::directx::ID3D11DeviceResources; + + inline ComPtr GetD3DDeviceResources() + { + return kiwano::graphics::directx::GetD3D11DeviceResources(); + } +#endif + +} // namespace directx +} // namespace graphics +} // namespace kiwano diff --git a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h index b83e7856..a14ab67b 100644 --- a/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h +++ b/src/kiwano/render/DirectX/D3DDeviceResourcesBase.h @@ -23,10 +23,17 @@ namespace kiwano { +namespace graphics +{ +namespace directx +{ + MIDL_INTERFACE("fb99fa64-d9cf-4e0e-9c75-90514797b01d") ID3DDeviceResourcesBase : public IUnknown { public: + virtual HRESULT Initialize(HWND hwnd) = 0; + virtual HRESULT Present(bool vsync) = 0; virtual void ClearRenderTarget(Color & clear_color) = 0; @@ -39,6 +46,8 @@ public: virtual HRESULT SetFullscreenState(bool fullscreen) = 0; + virtual HRESULT GetFullscreenState(bool* fullscreen) = 0; + virtual HRESULT ResizeTarget(UINT width, UINT height) = 0; virtual HRESULT GetDisplaySettings(DXGI_MODE_DESC** mode_descs, int* num) = 0; @@ -46,4 +55,6 @@ public: virtual void DiscardResources() = 0; }; +} // namespace directx +} // namespace graphics } // namespace kiwano diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 2b7adb43..de86e279 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -32,6 +32,8 @@ namespace kiwano { +using namespace kiwano::graphics::directx; + Renderer& Renderer::GetInstance() { return RendererImpl::GetInstance(); @@ -64,16 +66,26 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) // Direct3D device resources if (SUCCEEDED(hr)) { - hr = ID3DDeviceResources::Create(&d3d_res_, target_window); + auto d3d_res = graphics::directx::GetD3DDeviceResources(); + + // Initialize Direct3D resources + hr = d3d_res->Initialize(target_window); // Direct2D device resources if (SUCCEEDED(hr)) { - hr = ID2DDeviceResources::Create(&d2d_res_, d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain()); + d3d_res_ = d3d_res; + + auto d2d_res = graphics::directx::GetD2DDeviceResources(); + + // Initialize Direct2D resources + hr = d2d_res->Initialize(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain()); - // Other device resources if (SUCCEEDED(hr)) { + d2d_res_ = d2d_res; + + // Initialize other device resources RenderContextImplPtr ctx = memory::New(); hr = ctx->CreateDeviceResources(d2d_res_->GetFactory(), d2d_res_->GetDeviceContext()); @@ -151,7 +163,10 @@ void RendererImpl::Present() KGE_ASSERT(d3d_res_); HRESULT hr = d3d_res_->Present(vsync_); - KGE_THROW_IF_FAILED(hr, "Unexpected DXGI exception"); + if (FAILED(hr) && hr != DXGI_ERROR_WAS_STILL_DRAWING) + { + KGE_THROW_IF_FAILED(hr, "Unexpected DXGI exception"); + } } void RendererImpl::CreateTexture(Texture& texture, const String& file_path) @@ -949,77 +964,6 @@ RenderContextPtr RendererImpl::CreateTextureRenderContext(Texture& texture, cons return nullptr; } -void RendererImpl::SetResolution(uint32_t width, uint32_t height, bool fullscreen) -{ - KGE_ASSERT(d3d_res_); - - if (fullscreen) - { - HRESULT hr = d3d_res_->ResizeTarget(width, height); - KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); - - hr = d3d_res_->SetFullscreenState(fullscreen); - KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); - } - else - { - HRESULT hr = d3d_res_->SetFullscreenState(fullscreen); - KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); - - hr = d3d_res_->ResizeTarget(width, height); - KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); - } - - Application::GetInstance().GetMainWindow()->SetFullscreenState(fullscreen); -} - -Vector RendererImpl::GetResolutions() -{ - if (resolutions_.empty()) - { - - DXGI_MODE_DESC* mode_descs = nullptr; - int mode_num = 0; - - HRESULT hr = d3d_res_->GetDisplaySettings(&mode_descs, &mode_num); - if (SUCCEEDED(hr)) - { - std::unique_ptr mode_list(mode_descs); - - if (mode_list) - { - for (int i = 0; i < mode_num; i++) - { - Resolution res; - res.width = mode_descs[i].Width; - res.height = mode_descs[i].Height; - res.refresh_rate = 0; - - if (mode_descs[i].RefreshRate.Denominator > 0) - { - res.refresh_rate = mode_descs[i].RefreshRate.Numerator / mode_descs[i].RefreshRate.Denominator; - } - - if (!resolutions_.empty()) - { - auto& back = resolutions_.back(); - if (back.width == res.width && back.height == res.height - && back.refresh_rate == res.refresh_rate) - continue; - } - - resolutions_.push_back(res); - } - } - } - else - { - KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!"); - } - } - return resolutions_; -} - void RendererImpl::Resize(uint32_t width, uint32_t height) { HRESULT hr = S_OK; diff --git a/src/kiwano/render/DirectX/RendererImpl.h b/src/kiwano/render/DirectX/RendererImpl.h index 4851229e..edddaa45 100644 --- a/src/kiwano/render/DirectX/RendererImpl.h +++ b/src/kiwano/render/DirectX/RendererImpl.h @@ -20,24 +20,14 @@ #pragma once #include +#include #include #include -#if defined(KGE_USE_DIRECTX10) -#include -#else -#include -#endif namespace kiwano { -#if defined(KGE_USE_DIRECTX10) -typedef ID3D10DeviceResources ID3DDeviceResources; -#else -typedef ID3D11DeviceResources ID3DDeviceResources; -#endif - class KGE_API RendererImpl : public Renderer { @@ -82,25 +72,11 @@ public: RenderContextPtr CreateTextureRenderContext(Texture& texture, const Size* desired_size = nullptr) override; - void SetResolution(uint32_t width, uint32_t height, bool fullscreen) override; - - Vector GetResolutions() override; - public: void Clear() override; void Present() override; - /// \~chinese - /// @brief 获取Direct2D设备资源 - ID2DDeviceResources* GetD2DDeviceResources(); - - /// \~chinese - /// @brief 获取Direct3D设备资源 - ID3DDeviceResources* GetD3DDeviceResources(); - - /// \~chinese - /// @brief 重设渲染输出大小 void Resize(uint32_t width, uint32_t height) override; protected: @@ -111,27 +87,17 @@ protected: void Destroy() override; private: + using ID2DDeviceResources = kiwano::graphics::directx::ID2DDeviceResources; + using ID3DDeviceResources = kiwano::graphics::directx::ID3DDeviceResources; + ComPtr d2d_res_; ComPtr d3d_res_; ComPtr font_collection_loader_; ComPtr res_font_file_loader_; ComPtr res_font_collection_loader_; - - Vector resolutions_; }; + /** @} */ -inline ID2DDeviceResources* RendererImpl::GetD2DDeviceResources() -{ - KGE_ASSERT(d2d_res_); - return d2d_res_.Get(); -} - -inline ID3DDeviceResources* RendererImpl::GetD3DDeviceResources() -{ - KGE_ASSERT(d3d_res_); - return d3d_res_.Get(); -} - } // namespace kiwano diff --git a/src/kiwano/render/DirectX/helper.h b/src/kiwano/render/DirectX/helper.h index 53f4ceae..5461cac8 100644 --- a/src/kiwano/render/DirectX/helper.h +++ b/src/kiwano/render/DirectX/helper.h @@ -29,6 +29,7 @@ namespace kiwano { namespace DX { + template inline void SafeRelease(T*& ptr) { @@ -174,5 +175,6 @@ inline float ConvertDipsToPixels(float dips, float dpi) static const float dips_per_inch = 96.0f; return math::Floor(dips * dpi / dips_per_inch + 0.5f); // Round to nearest integer. } + } // namespace DX } // namespace kiwano diff --git a/src/kiwano/render/Renderer.h b/src/kiwano/render/Renderer.h index 7b2d60f0..7b80dae3 100644 --- a/src/kiwano/render/Renderer.h +++ b/src/kiwano/render/Renderer.h @@ -39,17 +39,6 @@ namespace kiwano * @{ */ -/** - * \~chinese - * @brief 分辨率 - */ -struct Resolution -{ - uint32_t width; ///< 分辨率宽度 - uint32_t height; ///< 分辨率高度 - uint32_t refresh_rate; ///< 刷新率 -}; - /** * \~chinese @@ -74,14 +63,6 @@ public: /// @brief 开启或关闭垂直同步 virtual void SetVSyncEnabled(bool enabled); - /// \~chinese - /// @brief 设置分辨率 - virtual void SetResolution(uint32_t width, uint32_t height, bool fullscreen) = 0; - - /// \~chinese - /// @brief 获取屏幕分辨率 - virtual Vector GetResolutions() = 0; - /// \~chinese /// @brief 创建纹理内部资源 /// @param[out] texture 纹理