diff options
author | crupest <crupest@outlook.com> | 2019-12-16 00:09:52 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-12-16 00:09:52 +0800 |
commit | 6ad6638adf64d958cdae44ce1df6a8a3787fed84 (patch) | |
tree | 030af9ca6e19bebc6250a8d278e46af7065fcd2f | |
parent | 221c62de313ad811ca2b3ae8ba43996c96c347bc (diff) | |
download | cru-6ad6638adf64d958cdae44ce1df6a8a3787fed84.tar.gz cru-6ad6638adf64d958cdae44ce1df6a8a3787fed84.tar.bz2 cru-6ad6638adf64d958cdae44ce1df6a8a3787fed84.zip |
...
-rw-r--r-- | include/cru/platform/exception.hpp | 2 | ||||
-rw-r--r-- | include/cru/win/exception.hpp | 29 | ||||
-rw-r--r-- | include/cru/win/graph/direct/factory.hpp | 21 | ||||
-rw-r--r-- | include/cru/win/native/exception.hpp | 1 | ||||
-rw-r--r-- | include/cru/win/native/window_render_target.hpp | 4 | ||||
-rw-r--r-- | src/win/exception.cpp | 26 | ||||
-rw-r--r-- | src/win/graph/direct/brush.cpp | 2 | ||||
-rw-r--r-- | src/win/graph/direct/factory.cpp | 36 | ||||
-rw-r--r-- | src/win/native/ui_application.cpp | 3 | ||||
-rw-r--r-- | src/win/native/window.cpp | 2 | ||||
-rw-r--r-- | src/win/native/window_d2d_painter.cpp | 21 | ||||
-rw-r--r-- | src/win/native/window_d2d_painter.hpp | 8 | ||||
-rw-r--r-- | src/win/native/window_render_target.cpp | 25 |
13 files changed, 96 insertions, 84 deletions
diff --git a/include/cru/platform/exception.hpp b/include/cru/platform/exception.hpp index 1774b12c..afe11c03 100644 --- a/include/cru/platform/exception.hpp +++ b/include/cru/platform/exception.hpp @@ -1,5 +1,5 @@ #pragma once -#include "cru/common/pre_config.hpp" +#include "cru/common/base.hpp" #include <stdexcept> diff --git a/include/cru/win/exception.hpp b/include/cru/win/exception.hpp index 9e038960..95eb4079 100644 --- a/include/cru/win/exception.hpp +++ b/include/cru/win/exception.hpp @@ -10,12 +10,11 @@ namespace cru::platform::win { class HResultError : public platform::PlatformException { public: explicit HResultError(HRESULT h_result); - explicit HResultError(HRESULT h_result, - const std::string_view& additional_message); - HResultError(const HResultError& other) = default; - HResultError(HResultError&& other) = default; - HResultError& operator=(const HResultError& other) = default; - HResultError& operator=(HResultError&& other) = default; + explicit HResultError(HRESULT h_result, const std::string_view& message); + + CRU_DEFAULT_COPY(HResultError) + CRU_DEFAULT_MOVE(HResultError) + ~HResultError() override = default; HRESULT GetHResult() const { return h_result_; } @@ -35,17 +34,19 @@ inline void ThrowIfFailed(const HRESULT h_result, class Win32Error : public platform::PlatformException { public: - explicit Win32Error(DWORD error_code); - Win32Error(DWORD error_code, const std::string_view& additional_message); - Win32Error(const Win32Error& other) = default; - Win32Error(Win32Error&& other) = default; - Win32Error& operator=(const Win32Error& other) = default; - Win32Error& operator=(Win32Error&& other) = default; + // ::GetLastError is automatically called to get the error code. + // The same as Win32Error(::GetLastError(), message) + explicit Win32Error(const std::string_view& message); + Win32Error(DWORD error_code, const std::string_view& message); + + CRU_DEFAULT_COPY(Win32Error) + CRU_DEFAULT_MOVE(Win32Error) + ~Win32Error() override = default; - HRESULT GetErrorCode() const { return error_code_; } + DWORD GetErrorCode() const { return error_code_; } private: DWORD error_code_; }; -} // namespace cru::win +} // namespace cru::platform::win diff --git a/include/cru/win/graph/direct/factory.hpp b/include/cru/win/graph/direct/factory.hpp index 4c106f54..cf5ccaee 100644 --- a/include/cru/win/graph/direct/factory.hpp +++ b/include/cru/win/graph/direct/factory.hpp @@ -11,14 +11,12 @@ class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { CRU_DELETE_COPY(DirectGraphFactory) CRU_DELETE_MOVE(DirectGraphFactory) - ~DirectGraphFactory() override = default; + ~DirectGraphFactory() override; public: - ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.Get(); } - ID2D1DeviceContext* GetD2D1DeviceContext() const { - return d2d1_device_context_.Get(); - } ID3D11Device* GetD3D11Device() const { return d3d11_device_.Get(); } + ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.Get(); } + ID2D1Device* GetD2D1Device() const { return d2d1_device_.Get(); } IDXGIFactory2* GetDxgiFactory() const { return dxgi_factory_.Get(); } IDWriteFactory* GetDWriteFactory() const { return dwrite_factory_.Get(); } IDWriteFontCollection* GetSystemFontCollection() const { @@ -26,6 +24,16 @@ class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { } public: + Microsoft::WRL::ComPtr<ID2D1DeviceContext> CreateD2D1DeviceContext(); + + // This context should only be used to create graphic resources like brush. + // Because graphic resources can be shared if they are created in the same + // device. + ID2D1DeviceContext* GetDefaultD2D1DeviceContext() { + return d2d1_device_context_.Get(); + } + + public: std::unique_ptr<ISolidColorBrush> CreateSolidColorBrush() override; std::unique_ptr<IGeometryBuilder> CreateGeometryBuilder() override; @@ -38,7 +46,10 @@ class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { private: Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; + // ID2D1Factory1 is a interface only available in Windows 8 and Windows 7 with + // update. It is d2d v1.1. Microsoft::WRL::ComPtr<ID2D1Factory1> d2d1_factory_; + Microsoft::WRL::ComPtr<ID2D1Device> d2d1_device_; Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context_; Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory_; Microsoft::WRL::ComPtr<IDWriteFactory> dwrite_factory_; diff --git a/include/cru/win/native/exception.hpp b/include/cru/win/native/exception.hpp index 637f021d..ac15ab2d 100644 --- a/include/cru/win/native/exception.hpp +++ b/include/cru/win/native/exception.hpp @@ -3,4 +3,5 @@ namespace cru::platform::native::win { using platform::win::Win32Error; +using platform::win::HResultError; } // namespace cru::platform::native::win diff --git a/include/cru/win/native/window_render_target.hpp b/include/cru/win/native/window_render_target.hpp index 248bfc25..ab1d68ef 100644 --- a/include/cru/win/native/window_render_target.hpp +++ b/include/cru/win/native/window_render_target.hpp @@ -24,8 +24,7 @@ class WindowRenderTarget : public Object { return factory_; } - // Get the target bitmap which can be set as the ID2D1DeviceContext's target. - ID2D1Bitmap1* GetTargetBitmap() const { return target_bitmap_.Get(); } + ID2D1DeviceContext* GetD2D1DeviceContext() { return d2d1_device_context_.Get(); } // Resize the underlying buffer. void ResizeBuffer(int width, int height); @@ -41,6 +40,7 @@ class WindowRenderTarget : public Object { private: graph::win::direct::DirectGraphFactory* factory_; + Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context_; Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_; Microsoft::WRL::ComPtr<ID2D1Bitmap1> target_bitmap_; }; diff --git a/src/win/exception.cpp b/src/win/exception.cpp index 271067fc..e0f114b5 100644 --- a/src/win/exception.cpp +++ b/src/win/exception.cpp @@ -11,11 +11,9 @@ inline std::string HResultMakeMessage(HRESULT h_result, sprintf_s(buffer, "%#08x", h_result); if (message) - return Format( - "An HResultError is thrown. HRESULT: {}.\nAdditional message: {}\n", - buffer, *message); + return Format("HRESULT: {}.\nMessage: {}\n", buffer, *message); else - return Format("An HResultError is thrown. HRESULT: {}.\n", buffer); + return Format("HRESULT: {}.\n", buffer); } HResultError::HResultError(HRESULT h_result) @@ -28,23 +26,17 @@ HResultError::HResultError(HRESULT h_result, h_result_(h_result) {} inline std::string Win32MakeMessage(DWORD error_code, - const std::string_view* message) { + const std::string_view& message) { char buffer[20]; sprintf_s(buffer, "%#04x", error_code); - if (message) - return Format("Last error code: {}.\nAdditional message: {}\n", buffer, - *message); - else - return Format("Last error code: {}.\n", buffer); + return Format("Last error code: {}.\nMessage: {}\n", buffer, message); } -Win32Error::Win32Error(DWORD error_code) - : PlatformException(Win32MakeMessage(error_code, nullptr)), - error_code_(error_code) {} +Win32Error::Win32Error(const std::string_view& message) + : Win32Error(::GetLastError(), message) {} -Win32Error::Win32Error(DWORD error_code, - const std::string_view& additional_message) - : PlatformException(Win32MakeMessage(error_code, &additional_message)), +Win32Error::Win32Error(DWORD error_code, const std::string_view& message) + : PlatformException(Win32MakeMessage(error_code, message)), error_code_(error_code) {} -} // namespace cru::win +} // namespace cru::platform::win diff --git a/src/win/graph/direct/brush.cpp b/src/win/graph/direct/brush.cpp index 17024a66..b30d8c24 100644 --- a/src/win/graph/direct/brush.cpp +++ b/src/win/graph/direct/brush.cpp @@ -9,7 +9,7 @@ namespace cru::platform::graph::win::direct { D2DSolidColorBrush::D2DSolidColorBrush(DirectGraphFactory* factory) : DirectGraphResource(factory) { - ThrowIfFailed(factory->GetD2D1DeviceContext()->CreateSolidColorBrush( + ThrowIfFailed(factory->GetDefaultD2D1DeviceContext()->CreateSolidColorBrush( Convert(color_), &brush_)); } diff --git a/src/win/graph/direct/factory.cpp b/src/win/graph/direct/factory.cpp index 1fff9fa9..e67bdafe 100644 --- a/src/win/graph/direct/factory.cpp +++ b/src/win/graph/direct/factory.cpp @@ -1,5 +1,6 @@ #include "cru/win/graph/direct/factory.hpp" +#include "cru/common/logger.hpp" #include "cru/win/graph/direct/brush.hpp" #include "cru/win/graph/direct/exception.hpp" #include "cru/win/graph/direct/font.hpp" @@ -11,10 +12,28 @@ #include <utility> namespace cru::platform::graph::win::direct { +namespace { +void InitializeCom() { + const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (FAILED(hresult)) { + throw HResultError(hresult, "Failed to call CoInitializeEx."); + } + if (hresult == S_FALSE) { + log::Debug( + "Try to call CoInitializeEx, but it seems COM is already " + "initialized."); + } +} + +void UninitializeCom() { ::CoUninitialize(); } +} // namespace + DirectGraphFactory::DirectGraphFactory() { // TODO! Detect repeated creation. Because I don't think we can create two d2d // and dwrite factory so we need to prevent the "probably dangerous" behavior. + InitializeCom(); + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #ifdef CRU_DEBUG @@ -39,12 +58,9 @@ DirectGraphFactory::DirectGraphFactory() { ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&d2d1_factory_))); - Microsoft::WRL::ComPtr<ID2D1Device> d2d1_device; + ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device_)); - ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device)); - - ThrowIfFailed(d2d1_device->CreateDeviceContext( - D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context_)); + d2d1_device_context_ = CreateD2D1DeviceContext(); // Identify the physical adapter (GPU or card) this device is runs on. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter; @@ -61,6 +77,16 @@ DirectGraphFactory::DirectGraphFactory() { &dwrite_system_font_collection_)); } +DirectGraphFactory::~DirectGraphFactory() { UninitializeCom(); } + +Microsoft::WRL::ComPtr<ID2D1DeviceContext> +DirectGraphFactory::CreateD2D1DeviceContext() { + Microsoft::WRL::ComPtr<ID2D1DeviceContext> d2d1_device_context; + ThrowIfFailed(d2d1_device_->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context)); + return d2d1_device_context; +} + std::unique_ptr<ISolidColorBrush> DirectGraphFactory::CreateSolidColorBrush() { return std::make_unique<D2DSolidColorBrush>(this); } diff --git a/src/win/native/ui_application.cpp b/src/win/native/ui_application.cpp index 0ae8ee81..75fce6ce 100644 --- a/src/win/native/ui_application.cpp +++ b/src/win/native/ui_application.cpp @@ -28,8 +28,7 @@ WinUiApplication::WinUiApplication() { instance_handle_ = ::GetModuleHandleW(nullptr); if (!instance_handle_) - throw Win32Error(::GetLastError(), - "Failed to get module(instance) handle."); + throw Win32Error("Failed to get module(instance) handle."); log::Logger::GetInstance()->AddSource( std::make_unique<::cru::platform::win::WinDebugLoggerSource>()); diff --git a/src/win/native/window.cpp b/src/win/native/window.cpp index f996af02..d3c12a44 100644 --- a/src/win/native/window.cpp +++ b/src/win/native/window.cpp @@ -163,7 +163,7 @@ void WinNativeWindow::RequestRepaint() { } std::unique_ptr<graph::IPainter> WinNativeWindow::BeginPaint() { - return std::make_unique<WindowD2DPainter>(this); + return std::make_unique<WindowD2DPainter>(window_render_target_.get()); } void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) { diff --git a/src/win/native/window_d2d_painter.cpp b/src/win/native/window_d2d_painter.cpp index ab74a964..023559f4 100644 --- a/src/win/native/window_d2d_painter.cpp +++ b/src/win/native/window_d2d_painter.cpp @@ -9,25 +9,16 @@ namespace cru::platform::native::win { using namespace cru::platform::graph::win::direct; -WindowD2DPainter::WindowD2DPainter(WinNativeWindow* window) - : D2DPainter(window->GetWindowRenderTarget() - ->GetDirectFactory() - ->GetD2D1DeviceContext()), - window_(window) { - window->GetWindowRenderTarget()->SetAsTarget(); - window->GetWindowRenderTarget() - ->GetDirectFactory() - ->GetD2D1DeviceContext() - ->BeginDraw(); +WindowD2DPainter::WindowD2DPainter(WindowRenderTarget* render_target) + : D2DPainter(render_target->GetD2D1DeviceContext()), + render_target_(render_target) { + render_target_->GetD2D1DeviceContext()->BeginDraw(); } WindowD2DPainter::~WindowD2DPainter() { EndDraw(); } void WindowD2DPainter::DoEndDraw() { - ThrowIfFailed(window_->GetWindowRenderTarget() - ->GetDirectFactory() - ->GetD2D1DeviceContext() - ->EndDraw()); - window_->GetWindowRenderTarget()->Present(); + ThrowIfFailed(render_target_->GetD2D1DeviceContext()->EndDraw()); + render_target_->Present(); } } // namespace cru::platform::native::win diff --git a/src/win/native/window_d2d_painter.hpp b/src/win/native/window_d2d_painter.hpp index 6877babd..40a5dee6 100644 --- a/src/win/native/window_d2d_painter.hpp +++ b/src/win/native/window_d2d_painter.hpp @@ -1,19 +1,21 @@ #pragma once #include "cru/win/graph/direct/painter.hpp" -#include "cru/win/native/window.hpp" +#include "cru/win/native/window_render_target.hpp" namespace cru::platform::native::win { class WindowD2DPainter : public graph::win::direct::D2DPainter { public: - explicit WindowD2DPainter(WinNativeWindow* window); + explicit WindowD2DPainter(WindowRenderTarget* window); + CRU_DELETE_COPY(WindowD2DPainter) CRU_DELETE_MOVE(WindowD2DPainter) + ~WindowD2DPainter() override; protected: void DoEndDraw() override; private: - WinNativeWindow* window_; + WindowRenderTarget* render_target_; }; } // namespace cru::platform::native::win diff --git a/src/win/native/window_render_target.cpp b/src/win/native/window_render_target.cpp index f15aeb6e..23ad2afa 100644 --- a/src/win/native/window_render_target.cpp +++ b/src/win/native/window_render_target.cpp @@ -15,6 +15,8 @@ WindowRenderTarget::WindowRenderTarget(DirectGraphFactory* factory, HWND hwnd) const auto d3d11_device = factory->GetD3D11Device(); const auto dxgi_factory = factory->GetDxgiFactory(); + d2d1_device_context_ = factory->CreateD2D1DeviceContext(); + // Allocate a descriptor. DXGI_SWAP_CHAIN_DESC1 swap_chain_desc; swap_chain_desc.Width = 0; // use automatic sizing @@ -41,27 +43,12 @@ WindowRenderTarget::WindowRenderTarget(DirectGraphFactory* factory, HWND hwnd) } void WindowRenderTarget::ResizeBuffer(const int width, const int height) { - const auto factory = factory_; - const auto d2d1_device_context = factory->GetD2D1DeviceContext(); - - Microsoft::WRL::ComPtr<ID2D1Image> old_target; - d2d1_device_context->GetTarget(&old_target); - const auto target_this = old_target == this->target_bitmap_; - if (target_this) d2d1_device_context->SetTarget(nullptr); - - old_target = nullptr; + // In order to resize buffer, we need to untarget the buffer first. + d2d1_device_context_->SetTarget(nullptr); target_bitmap_ = nullptr; - ThrowIfFailed(dxgi_swap_chain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0)); - CreateTargetBitmap(); - - if (target_this) d2d1_device_context->SetTarget(target_bitmap_.Get()); -} - -void WindowRenderTarget::SetAsTarget() { - factory_->GetD2D1DeviceContext()->SetTarget(target_bitmap_.Get()); } void WindowRenderTarget::Present() { @@ -85,7 +72,9 @@ void WindowRenderTarget::CreateTargetBitmap() { // Get a D2D surface from the DXGI back buffer to use as the D2D render // target. - ThrowIfFailed(factory_->GetD2D1DeviceContext()->CreateBitmapFromDxgiSurface( + ThrowIfFailed(d2d1_device_context_->CreateBitmapFromDxgiSurface( dxgi_back_buffer.Get(), &bitmap_properties, &target_bitmap_)); + + d2d1_device_context_->SetTarget(target_bitmap_.Get()); } } // namespace cru::platform::native::win |