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 纹理