aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/platform/exception.hpp2
-rw-r--r--include/cru/win/exception.hpp29
-rw-r--r--include/cru/win/graph/direct/factory.hpp21
-rw-r--r--include/cru/win/native/exception.hpp1
-rw-r--r--include/cru/win/native/window_render_target.hpp4
-rw-r--r--src/win/exception.cpp26
-rw-r--r--src/win/graph/direct/brush.cpp2
-rw-r--r--src/win/graph/direct/factory.cpp36
-rw-r--r--src/win/native/ui_application.cpp3
-rw-r--r--src/win/native/window.cpp2
-rw-r--r--src/win/native/window_d2d_painter.cpp21
-rw-r--r--src/win/native/window_d2d_painter.hpp8
-rw-r--r--src/win/native/window_render_target.cpp25
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