diff options
Diffstat (limited to 'src/graph')
| -rw-r--r-- | src/graph/graph.cpp | 226 | ||||
| -rw-r--r-- | src/graph/graph.hpp | 180 | ||||
| -rw-r--r-- | src/graph/graph_manager.cpp | 79 | ||||
| -rw-r--r-- | src/graph/graph_manager.hpp | 60 | ||||
| -rw-r--r-- | src/graph/graph_util.hpp | 63 | ||||
| -rw-r--r-- | src/graph/window_render_target.cpp | 97 | ||||
| -rw-r--r-- | src/graph/window_render_target.hpp | 49 |
7 files changed, 348 insertions, 406 deletions
diff --git a/src/graph/graph.cpp b/src/graph/graph.cpp deleted file mode 100644 index eef95c8c..00000000 --- a/src/graph/graph.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include "graph.hpp" - -#include "application.hpp" -#include "exception.hpp" - -namespace cru::graph -{ - using Microsoft::WRL::ComPtr; - - WindowRenderTarget::WindowRenderTarget(GraphManager* graph_manager, HWND hwnd) - { - this->graph_manager_ = graph_manager; - - const auto d3d11_device = graph_manager->GetD3D11Device(); - const auto dxgi_factory = graph_manager->GetDxgiFactory(); - - // Allocate a descriptor. - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = { 0 }; - swap_chain_desc.Width = 0; // use automatic sizing - swap_chain_desc.Height = 0; - swap_chain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format - swap_chain_desc.Stereo = false; - swap_chain_desc.SampleDesc.Count = 1; // don't use multi-sampling - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.BufferCount = 2; // use double buffering to enable flip - swap_chain_desc.Scaling = DXGI_SCALING_NONE; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect - swap_chain_desc.Flags = 0; - - - - // Get the final swap chain for this window from the DXGI factory. - ThrowIfFailed( - dxgi_factory->CreateSwapChainForHwnd( - d3d11_device.Get(), - hwnd, - &swap_chain_desc, - nullptr, - nullptr, - &dxgi_swap_chain_ - ) - ); - - CreateTargetBitmap(); - } - - WindowRenderTarget::~WindowRenderTarget() - { - - } - - void WindowRenderTarget::ResizeBuffer(const int width, const int height) - { - const auto graph_manager = graph_manager_; - const auto d2d1_device_context = graph_manager->GetD2D1DeviceContext(); - - 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; - 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() - { - GetD2DDeviceContext()->SetTarget(target_bitmap_.Get()); - } - - void WindowRenderTarget::Present() - { - ThrowIfFailed( - dxgi_swap_chain_->Present(1, 0) - ); - } - - void WindowRenderTarget::CreateTargetBitmap() - { - // Direct2D needs the dxgi version of the backbuffer surface pointer. - ComPtr<IDXGISurface> dxgiBackBuffer; - ThrowIfFailed( - dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer)) - ); - - const auto dpi = graph_manager_->GetDpi(); - - auto bitmap_properties = - D2D1::BitmapProperties1( - D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, - D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), - dpi.x, - dpi.y - ); - - // Get a D2D surface from the DXGI back buffer to use as the D2D render target. - ThrowIfFailed( - graph_manager_->GetD2D1DeviceContext()->CreateBitmapFromDxgiSurface( - dxgiBackBuffer.Get(), - &bitmap_properties, - &target_bitmap_ - ) - ); - } - - GraphManager* GraphManager::GetInstance() - { - return Application::GetInstance()->ResolveSingleton<GraphManager>([](auto) - { - return new GraphManager{}; - }); - } - - GraphManager::GraphManager() - { - UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; - -#ifdef CRU_DEBUG - creation_flags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - - const D3D_FEATURE_LEVEL feature_levels[] = - { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1 - }; - - - ThrowIfFailed(D3D11CreateDevice( - nullptr, - D3D_DRIVER_TYPE_HARDWARE, - nullptr, - creation_flags, - feature_levels, - ARRAYSIZE(feature_levels), - D3D11_SDK_VERSION, - &d3d11_device_, - nullptr, - &d3d11_device_context_ - )); - - Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device; - - ThrowIfFailed(d3d11_device_.As(&dxgi_device)); - - ThrowIfFailed(D2D1CreateFactory( - D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory1), - &d2d1_factory_ - )); - - ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device_)); - - ThrowIfFailed(d2d1_device_->CreateDeviceContext( - D2D1_DEVICE_CONTEXT_OPTIONS_NONE, - &d2d1_device_context_ - )); - - // Identify the physical adapter (GPU or card) this device is runs on. - ComPtr<IDXGIAdapter> dxgi_adapter; - ThrowIfFailed( - dxgi_device->GetAdapter(&dxgi_adapter) - ); - - // Get the factory object that created the DXGI device. - ThrowIfFailed( - dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory_)) - ); - - - ThrowIfFailed(DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(dwrite_factory_.GetAddressOf()) - )); - - dwrite_factory_->GetSystemFontCollection(&dwrite_system_font_collection_); - } - - GraphManager::~GraphManager() - { - - } - - std::shared_ptr<WindowRenderTarget> GraphManager::CreateWindowRenderTarget(HWND hwnd) - { - return std::make_shared<WindowRenderTarget>(this, hwnd); - } - - Dpi GraphManager::GetDpi() const - { - Dpi dpi; - d2d1_factory_->GetDesktopDpi(&dpi.x, &dpi.y); - return dpi; - } - - void GraphManager::ReloadSystemMetrics() - { - ThrowIfFailed( - d2d1_factory_->ReloadSystemMetrics() - ); - } - - Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidColorBrush(const D2D1_COLOR_F& color) - { - Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> brush; - ThrowIfFailed(GraphManager::GetInstance()->GetD2D1DeviceContext()->CreateSolidColorBrush(color, &brush)); - return brush; - } -} diff --git a/src/graph/graph.hpp b/src/graph/graph.hpp deleted file mode 100644 index 440b0594..00000000 --- a/src/graph/graph.hpp +++ /dev/null @@ -1,180 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "system_headers.hpp" -#include <memory> -#include <functional> - -#include "base.hpp" - - -namespace cru::graph -{ - class GraphManager; - - //Represents a window render target. - class WindowRenderTarget : public Object - { - public: - WindowRenderTarget(GraphManager* graph_manager, HWND hwnd); - WindowRenderTarget(const WindowRenderTarget& other) = delete; - WindowRenderTarget(WindowRenderTarget&& other) = delete; - WindowRenderTarget& operator=(const WindowRenderTarget& other) = delete; - WindowRenderTarget& operator=(WindowRenderTarget&& other) = delete; - ~WindowRenderTarget() override; - - public: - //Get the graph manager that created the render target. - GraphManager* GetGraphManager() const - { - return graph_manager_; - } - - //Get the d2d device context. - inline Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2DDeviceContext() const; - - //Get the target bitmap which can be set as the ID2D1DeviceContext's target. - Microsoft::WRL::ComPtr<ID2D1Bitmap1> GetTargetBitmap() const - { - return target_bitmap_; - } - - //Resize the underlying buffer. - void ResizeBuffer(int width, int height); - - //Set this render target as the d2d device context's target. - void SetAsTarget(); - - //Present the data of the underlying buffer to the window. - void Present(); - - private: - void CreateTargetBitmap(); - - private: - GraphManager* graph_manager_; - Microsoft::WRL::ComPtr<IDXGISwapChain1> dxgi_swap_chain_; - Microsoft::WRL::ComPtr<ID2D1Bitmap1> target_bitmap_; - }; - - struct Dpi - { - float x; - float y; - }; - - class GraphManager final : public Object - { - public: - static GraphManager* GetInstance(); - - private: - GraphManager(); - public: - GraphManager(const GraphManager& other) = delete; - GraphManager(GraphManager&& other) = delete; - GraphManager& operator=(const GraphManager& other) = delete; - GraphManager& operator=(GraphManager&& other) = delete; - ~GraphManager() override; - - public: - Microsoft::WRL::ComPtr<ID2D1Factory1> GetD2D1Factory() const - { - return d2d1_factory_; - } - - Microsoft::WRL::ComPtr<ID2D1DeviceContext> GetD2D1DeviceContext() const - { - return d2d1_device_context_; - } - - Microsoft::WRL::ComPtr<ID3D11Device> GetD3D11Device() const - { - return d3d11_device_; - } - - Microsoft::WRL::ComPtr<IDXGIFactory2> GetDxgiFactory() const - { - return dxgi_factory_; - } - - Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory() const - { - return dwrite_factory_; - } - - - //Create a window render target with the HWND. - std::shared_ptr<WindowRenderTarget> CreateWindowRenderTarget(HWND hwnd); - - //Get the desktop dpi. - Dpi GetDpi() const; - - //Reload system metrics including desktop dpi. - void ReloadSystemMetrics(); - - Microsoft::WRL::ComPtr<IDWriteFontCollection> GetSystemFontCollection() const - { - return dwrite_system_font_collection_.Get(); - } - - private: - Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_; - Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context_; - 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_; - Microsoft::WRL::ComPtr<IDWriteFontCollection> dwrite_system_font_collection_; - }; - - inline int DipToPixelInternal(const float dip, const float dpi) - { - return static_cast<int>(dip * dpi / 96.0f); - } - - inline int DipToPixelX(const float dip_x) - { - return DipToPixelInternal(dip_x, GraphManager::GetInstance()->GetDpi().x); - } - - inline int DipToPixelY(const float dip_y) - { - return DipToPixelInternal(dip_y, GraphManager::GetInstance()->GetDpi().y); - } - - inline float DipToPixelInternal(const int pixel, const float dpi) - { - return static_cast<float>(pixel) * 96.0f / dpi; - } - - inline float PixelToDipX(const int pixel_x) - { - return DipToPixelInternal(pixel_x, GraphManager::GetInstance()->GetDpi().x); - } - - inline float PixelToDipY(const int pixel_y) - { - return DipToPixelInternal(pixel_y, GraphManager::GetInstance()->GetDpi().y); - } - - Microsoft::WRL::ComPtr<ID2D1DeviceContext> WindowRenderTarget::GetD2DDeviceContext() const - { - return graph_manager_->GetD2D1DeviceContext(); - } - - inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, const std::function<void(ID2D1DeviceContext*)>& action) - { - D2D1_MATRIX_3X2_F old_transform; - device_context->GetTransform(&old_transform); - device_context->SetTransform(old_transform * matrix); - action(device_context); - device_context->SetTransform(old_transform); - } - - Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidColorBrush(const D2D1_COLOR_F& color); -} diff --git a/src/graph/graph_manager.cpp b/src/graph/graph_manager.cpp new file mode 100644 index 00000000..ecc60915 --- /dev/null +++ b/src/graph/graph_manager.cpp @@ -0,0 +1,79 @@ +#include "graph_manager.hpp" + +#include <d2d1_2.h> +#include <d3d11.h> +#include <dwrite.h> +#include <dxgi1_2.h> +#include <wrl/client.h> + +#include "application.hpp" +#include "exception.hpp" +#include "util/com_util.hpp" +#include "window_render_target.hpp" + +namespace cru::graph { + +GraphManager* GraphManager::GetInstance() { + return Application::GetInstance()->ResolveSingleton<GraphManager>( + [](auto) { return new GraphManager{}; }); +} + +GraphManager::GraphManager() { + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#ifdef CRU_DEBUG + creation_flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + const D3D_FEATURE_LEVEL feature_levels[] = { + D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1}; + + Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context; + ID3D11Device* d3d11_device; + + ThrowIfFailed(D3D11CreateDevice( + nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, creation_flags, + feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, + &d3d11_device, nullptr, &d3d11_device_context)); + this->d3d11_device_ = util::CreateComSharedPtr(d3d11_device); + + Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device; + ThrowIfFailed(d3d11_device_->QueryInterface(dxgi_device.GetAddressOf())); + + ID2D1Factory1* d2d1_factory; + ThrowIfFailed(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + IID_PPV_ARGS(&d2d1_factory))); + this->d2d1_factory_ = util::CreateComSharedPtr(d2d1_factory); + + Microsoft::WRL::ComPtr<ID2D1Device> d2d1_device; + + ThrowIfFailed(d2d1_factory_->CreateDevice(dxgi_device.Get(), &d2d1_device)); + + ID2D1DeviceContext* d2d1_device_context; + ThrowIfFailed(d2d1_device->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &d2d1_device_context)); + this->d2d1_device_context_ = util::CreateComSharedPtr(d2d1_device_context); + + // Identify the physical adapter (GPU or card) this device is runs on. + Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter; + ThrowIfFailed(dxgi_device->GetAdapter(&dxgi_adapter)); + + IDXGIFactory2* dxgi_factory; + // Get the factory object that created the DXGI device. + ThrowIfFailed(dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory))); + this->dxgi_factory_ = util::CreateComSharedPtr(dxgi_factory); + + IDWriteFactory* dwrite_factory; + ThrowIfFailed( + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown**>(&dwrite_factory))); + this->dwrite_factory_ = util::CreateComSharedPtr(dwrite_factory); + + IDWriteFontCollection* font_collection; + ThrowIfFailed(dwrite_factory_->GetSystemFontCollection(&font_collection)); + this->dwrite_system_font_collection_ = + util::CreateComSharedPtr(font_collection); +} +} // namespace cru::graph diff --git a/src/graph/graph_manager.hpp b/src/graph/graph_manager.hpp new file mode 100644 index 00000000..4a1e7153 --- /dev/null +++ b/src/graph/graph_manager.hpp @@ -0,0 +1,60 @@ +#pragma once +#include "pre.hpp" + +#include <memory> + +#include "base.hpp" + +struct ID3D11Device; +struct ID3D11DeviceContext; +struct ID2D1Factory1; +struct ID2D1DeviceContext; +struct IDXGIFactory2; +struct IDWriteFontCollection; +struct IDWriteFactory; + +struct ID2D1RenderTarget; + +namespace cru::graph { +class WindowRenderTarget; + +class GraphManager final : public Object { + public: + static GraphManager* GetInstance(); + + private: + GraphManager(); + + public: + GraphManager(const GraphManager& other) = delete; + GraphManager(GraphManager&& other) = delete; + GraphManager& operator=(const GraphManager& other) = delete; + GraphManager& operator=(GraphManager&& other) = delete; + ~GraphManager() override = default; + + public: + ID2D1Factory1* GetD2D1Factory() const { return d2d1_factory_.get(); } + + ID2D1DeviceContext* GetD2D1DeviceContext() const { + return d2d1_device_context_.get(); + } + + ID3D11Device* GetD3D11Device() const { return d3d11_device_.get(); } + + IDXGIFactory2* GetDxgiFactory() const { return dxgi_factory_.get(); } + + IDWriteFactory* GetDWriteFactory() const { return dwrite_factory_.get(); } + + IDWriteFontCollection* GetSystemFontCollection() const { + return dwrite_system_font_collection_.get(); + } + + private: + std::shared_ptr<ID3D11Device> d3d11_device_; + std::shared_ptr<ID2D1Factory1> d2d1_factory_; + std::shared_ptr<ID2D1DeviceContext> d2d1_device_context_; + std::shared_ptr<IDXGIFactory2> dxgi_factory_; + std::shared_ptr<IDWriteFactory> dwrite_factory_; + std::shared_ptr<IDWriteFontCollection> dwrite_system_font_collection_; +}; +} // namespace cru::graph diff --git a/src/graph/graph_util.hpp b/src/graph/graph_util.hpp new file mode 100644 index 00000000..2d5be5f3 --- /dev/null +++ b/src/graph/graph_util.hpp @@ -0,0 +1,63 @@ +#pragma once +#include "pre.hpp" + +#include <d2d1_1.h> +#include <functional> + +#include "exception.hpp" +#include "graph_manager.hpp" + +namespace cru::graph { +struct Dpi { + float x; + float y; +}; + +inline Dpi GetDpi() { + Dpi dpi; + GraphManager::GetInstance()->GetD2D1Factory()->GetDesktopDpi(&dpi.x, &dpi.y); + return dpi; +} + +inline int DipToPixelInternal(const float dip, const float dpi) { + return static_cast<int>(dip * dpi / 96.0f); +} + +inline int DipToPixelX(const float dip_x) { + return DipToPixelInternal(dip_x, GetDpi().x); +} + +inline int DipToPixelY(const float dip_y) { + return DipToPixelInternal(dip_y, GetDpi().y); +} + +inline float DipToPixelInternal(const int pixel, const float dpi) { + return static_cast<float>(pixel) * 96.0f / dpi; +} + +inline float PixelToDipX(const int pixel_x) { + return DipToPixelInternal(pixel_x, GetDpi().x); +} + +inline float PixelToDipY(const int pixel_y) { + return DipToPixelInternal(pixel_y, GetDpi().y); +} + +inline void WithTransform( + ID2D1RenderTarget* render_target, const D2D1_MATRIX_3X2_F matrix, + const std::function<void(ID2D1RenderTarget*)>& action) { + D2D1_MATRIX_3X2_F old_transform; + render_target->GetTransform(&old_transform); + render_target->SetTransform(old_transform * matrix); + action(render_target); + render_target->SetTransform(old_transform); +} + +inline ID2D1SolidColorBrush* CreateSolidColorBrush(const D2D1_COLOR_F& color) { + ID2D1SolidColorBrush* brush; + ThrowIfFailed(GraphManager::GetInstance() + ->GetD2D1DeviceContext() + ->CreateSolidColorBrush(color, &brush)); + return brush; +} +} // namespace cru::graph diff --git a/src/graph/window_render_target.cpp b/src/graph/window_render_target.cpp new file mode 100644 index 00000000..a36e0faf --- /dev/null +++ b/src/graph/window_render_target.cpp @@ -0,0 +1,97 @@ +#include "window_render_target.hpp" + +#include <d2d1_1.h> +#include <d3d11.h> +#include <dxgi1_2.h> +#include <wrl/client.h> + +#include "exception.hpp" +#include "graph_manager.hpp" +#include "graph_util.hpp" +#include "util/com_util.hpp" + +namespace cru::graph { +WindowRenderTarget::WindowRenderTarget(GraphManager* graph_manager, HWND hwnd) { + this->graph_manager_ = graph_manager; + + const auto d3d11_device = graph_manager->GetD3D11Device(); + const auto dxgi_factory = graph_manager->GetDxgiFactory(); + + // Allocate a descriptor. + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {0}; + swap_chain_desc.Width = 0; // use automatic sizing + swap_chain_desc.Height = 0; + swap_chain_desc.Format = + DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format + swap_chain_desc.Stereo = false; + swap_chain_desc.SampleDesc.Count = 1; // don't use multi-sampling + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.BufferCount = 2; // use double buffering to enable flip + swap_chain_desc.Scaling = DXGI_SCALING_NONE; + swap_chain_desc.SwapEffect = + DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect + swap_chain_desc.Flags = 0; + + IDXGISwapChain1* dxgi_swap_chain; + // Get the final swap chain for this window from the DXGI factory. + ThrowIfFailed( + dxgi_factory->CreateSwapChainForHwnd(d3d11_device, hwnd, &swap_chain_desc, + nullptr, nullptr, &dxgi_swap_chain)); + this->dxgi_swap_chain_ = util::CreateComSharedPtr(dxgi_swap_chain); + + CreateTargetBitmap(); +} + +void WindowRenderTarget::ResizeBuffer(const int width, const int height) { + const auto graph_manager = graph_manager_; + const auto d2d1_device_context = graph_manager->GetD2D1DeviceContext(); + + ID2D1Image* old_target; + d2d1_device_context->GetTarget(&old_target); + const auto target_this = old_target == this->target_bitmap_.get(); + if (target_this) d2d1_device_context->SetTarget(nullptr); + + util::SafeRelease(old_target); + target_bitmap_.reset(); + + 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() { + graph_manager_->GetD2D1DeviceContext()->SetTarget(target_bitmap_.get()); +} + +void WindowRenderTarget::Present() { + ThrowIfFailed(dxgi_swap_chain_->Present(1, 0)); +} + +void WindowRenderTarget::CreateTargetBitmap() { + assert(target_bitmap_ == nullptr); // target bitmap must not exist. + + // Direct2D needs the dxgi version of the backbuffer surface pointer. + Microsoft::WRL::ComPtr<IDXGISurface> dxgi_back_buffer; + ThrowIfFailed( + dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer))); + + const auto dpi = GetDpi(); + + auto bitmap_properties = D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), + dpi.x, dpi.y); + + ID2D1Bitmap1* bitmap; + // Get a D2D surface from the DXGI back buffer to use as the D2D render + // target. + ThrowIfFailed( + graph_manager_->GetD2D1DeviceContext()->CreateBitmapFromDxgiSurface( + dxgi_back_buffer.Get(), &bitmap_properties, &bitmap)); + this->target_bitmap_ = util::CreateComSharedPtr(bitmap); +} +} // namespace cru::graph diff --git a/src/graph/window_render_target.hpp b/src/graph/window_render_target.hpp new file mode 100644 index 00000000..9b93df19 --- /dev/null +++ b/src/graph/window_render_target.hpp @@ -0,0 +1,49 @@ +#pragma once +#include "pre.hpp" + +#include <Windows.h> +#include <memory> + +#include "base.hpp" + +struct IDXGISwapChain1; +struct ID2D1Bitmap1; + +namespace cru::graph { +class GraphManager; + +// Represents a window render target. +class WindowRenderTarget : public Object { + public: + WindowRenderTarget(GraphManager* graph_manager, HWND hwnd); + WindowRenderTarget(const WindowRenderTarget& other) = delete; + WindowRenderTarget(WindowRenderTarget&& other) = delete; + WindowRenderTarget& operator=(const WindowRenderTarget& other) = delete; + WindowRenderTarget& operator=(WindowRenderTarget&& other) = delete; + ~WindowRenderTarget() override = default; + + public: + // Get the graph manager that created the render target. + GraphManager* GetGraphManager() const { return graph_manager_; } + + // Get the target bitmap which can be set as the ID2D1DeviceContext's target. + ID2D1Bitmap1* GetTargetBitmap() const { return target_bitmap_.get(); } + + // Resize the underlying buffer. + void ResizeBuffer(int width, int height); + + // Set this render target as the d2d device context's target. + void SetAsTarget(); + + // Present the data of the underlying buffer to the window. + void Present(); + + private: + void CreateTargetBitmap(); + + private: + GraphManager* graph_manager_; + std::shared_ptr<IDXGISwapChain1> dxgi_swap_chain_; + std::shared_ptr<ID2D1Bitmap1> target_bitmap_; +}; +} // namespace cru::graph |
