From 8c26893b66cc6e03d8a3fc49584bb705c1de7543 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Tue, 15 Oct 2024 18:07:21 +0800 Subject: [PATCH] =?UTF-8?q?DX11=E5=90=8E=E7=AB=AF=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 13 +- cmake/configure_glfw_native.cmake | 39 ++++++ cmake/detect_os.cmake | 58 +++++++++ example/CMakeLists.txt | 8 ++ example/src/main.cpp | 21 ++++ src/core/CMakeLists.txt | 7 ++ src/core/misc/scope_exit.h | 28 +++++ src/core/misc/test.cpp | 3 + src/renderer/CMakeLists.txt | 47 ++++--- src/renderer/backend/dx/dx_backend.cpp | 51 -------- src/renderer/backend/dx/dx_backend.h | 22 ---- src/renderer/backend/dx/dx_renderer.cpp | 70 +++++++++++ src/renderer/backend/dx/dx_renderer.h | 28 +++++ src/renderer/backend/dx/dx_texture.cpp | 28 ++--- src/renderer/backend/dx/dx_texture.h | 3 +- src/renderer/backend/dx/dx_window.cpp | 126 +++++++++++++++++++ src/renderer/backend/dx/dx_window.h | 19 +++ src/renderer/core/renderer.cpp | 47 +++++++ src/renderer/core/renderer.h | 40 ++++++ src/renderer/{ => core}/renderer_buffer.cpp | 0 src/renderer/{ => core}/renderer_buffer.h | 0 src/renderer/{ => core}/renderer_texture.cpp | 0 src/renderer/{ => core}/renderer_texture.h | 0 src/renderer/core/renderer_window.cpp | 26 ++++ src/renderer/core/renderer_window.h | 41 ++++++ src/renderer/core/window_manager.cpp | 44 +++++++ src/renderer/core/window_manager.h | 30 +++++ src/renderer/renderer.cpp | 29 ----- src/renderer/renderer.h | 26 ---- 29 files changed, 693 insertions(+), 161 deletions(-) create mode 100644 cmake/configure_glfw_native.cmake create mode 100644 cmake/detect_os.cmake create mode 100644 example/CMakeLists.txt create mode 100644 example/src/main.cpp create mode 100644 src/core/CMakeLists.txt create mode 100644 src/core/misc/scope_exit.h create mode 100644 src/core/misc/test.cpp delete mode 100644 src/renderer/backend/dx/dx_backend.cpp delete mode 100644 src/renderer/backend/dx/dx_backend.h create mode 100644 src/renderer/backend/dx/dx_renderer.cpp create mode 100644 src/renderer/backend/dx/dx_renderer.h create mode 100644 src/renderer/backend/dx/dx_window.cpp create mode 100644 src/renderer/backend/dx/dx_window.h create mode 100644 src/renderer/core/renderer.cpp create mode 100644 src/renderer/core/renderer.h rename src/renderer/{ => core}/renderer_buffer.cpp (100%) rename src/renderer/{ => core}/renderer_buffer.h (100%) rename src/renderer/{ => core}/renderer_texture.cpp (100%) rename src/renderer/{ => core}/renderer_texture.h (100%) create mode 100644 src/renderer/core/renderer_window.cpp create mode 100644 src/renderer/core/renderer_window.h create mode 100644 src/renderer/core/window_manager.cpp create mode 100644 src/renderer/core/window_manager.h delete mode 100644 src/renderer/renderer.cpp delete mode 100644 src/renderer/renderer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4678e49..d5099a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,14 +2,25 @@ cmake_minimum_required(VERSION 3.10) project(aorii) include(cmake/retrieve_files.cmake) +include(cmake/detect_os.cmake) +include(cmake/configure_glfw_native.cmake) find_package(Eigen3 REQUIRED) find_package(spdlog REQUIRED) +find_package(glfw3 REQUIRED) # 如果是Debug模式, 添加宏定义 if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions(-DDEBUG=1) -endif() +else () + add_definitions(-DDEBUG=0) +endif () +add_subdirectory(src/core) add_subdirectory(src/renderer) add_subdirectory(src/widget) + +set(BUILD_EXAMPLE FALSE CACHE BOOL "Build example") +if (BUILD_EXAMPLE) + add_subdirectory(example) +endif () diff --git a/cmake/configure_glfw_native.cmake b/cmake/configure_glfw_native.cmake new file mode 100644 index 0000000..e0fed3e --- /dev/null +++ b/cmake/configure_glfw_native.cmake @@ -0,0 +1,39 @@ +function(configure_glfw_native target) + # 检测操作系统 + if(WIN32) + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_WIN32) + message(STATUS "Exposing GLFW native Win32 API") + elseif(APPLE) + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_COCOA) + message(STATUS "Exposing GLFW native Cocoa API") + elseif(UNIX) + # 对于 Unix-like 系统,我们需要进一步检测 + if(CMAKE_SYSTEM_NAME MATCHES "Linux") + # 检测 Wayland + find_package(Wayland) + if(Wayland_FOUND) + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_WAYLAND) + message(STATUS "Exposing GLFW native Wayland API") + else() + # 如果没有 Wayland,默认使用 X11 + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_X11) + message(STATUS "Exposing GLFW native X11 API") + endif() + elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD|OpenBSD|NetBSD") + # BSD 系统通常使用 X11 + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_X11) + message(STATUS "Exposing GLFW native X11 API for BSD") + else() + message(WARNING "Unknown Unix-like system, GLFW native API might not be properly exposed") + endif() + else() + message(WARNING "Unknown operating system, GLFW native API might not be properly exposed") + endif() + + # 对于 EGL 支持,你可能需要额外的检测 + # 这里我们简单地为所有非 Windows 和非 macOS 系统启用它 + if(NOT WIN32 AND NOT APPLE) + target_compile_definitions(${target} PRIVATE GLFW_EXPOSE_NATIVE_EGL) + message(STATUS "Exposing GLFW native EGL API") + endif() +endfunction() diff --git a/cmake/detect_os.cmake b/cmake/detect_os.cmake new file mode 100644 index 0000000..d135253 --- /dev/null +++ b/cmake/detect_os.cmake @@ -0,0 +1,58 @@ +# DetectOS.cmake + +function(add_os_definitions target) + # 初始化所有平台宏为 0 + set(PLATFORMS WINDOWS MACOS LINUX FREEBSD) + + # 检测操作系统并设置相应的宏为 1 + if(WIN32) + target_compile_definitions(${target} PRIVATE WINDOWS=1) + message(STATUS "Detected Windows operating system") + list(REMOVE_ITEM PLATFORMS WINDOWS) + elseif(APPLE) + target_compile_definitions(${target} PRIVATE MACOS=1) + message(STATUS "Detected macOS operating system") + list(REMOVE_ITEM PLATFORMS MACOS) + elseif(UNIX) + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_compile_definitions(${target} PRIVATE LINUX=1) + message(STATUS "Detected Linux operating system") + list(REMOVE_ITEM PLATFORMS LINUX) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + target_compile_definitions(${target} PRIVATE FREEBSD=1) + message(STATUS "Detected FreeBSD operating system") + list(REMOVE_ITEM PLATFORMS FREEBSD) + else() + message(WARNING "Detected unknown Unix-like operating system") + endif() + else() + message(WARNING "Unknown operating system") + endif() + + foreach(PLATFORM ${PLATFORMS}) + target_compile_definitions(${target} PRIVATE ${PLATFORM}=0) + endforeach() + + # 检测并设置架构宏 + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + target_compile_definitions(${target} PRIVATE ARCH_64BIT=1 ARCH_32BIT=0) + message(STATUS "Detected 64-bit architecture") + else() + target_compile_definitions(${target} PRIVATE ARCH_64BIT=0 ARCH_32BIT=1) + message(STATUS "Detected 32-bit architecture") + endif() + + # 设置通用的 UNIX 宏 + if(UNIX) + target_compile_definitions(${target} PRIVATE UNIX=1) + else() + target_compile_definitions(${target} PRIVATE UNIX=0) + endif() + + # 设置通用的 POSIX 宏 + if(UNIX OR APPLE) + target_compile_definitions(${target} PRIVATE POSIX=1) + else() + target_compile_definitions(${target} PRIVATE POSIX=0) + endif() +endfunction() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..34828ec --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,8 @@ +project(aorii_example) + + + +set(SRC_FILES "") +retrieve_files(src SRC_FILES) +add_executable(${PROJECT_NAME} ${SRC_FILES}) +target_link_libraries(${PROJECT_NAME} PRIVATE renderer) diff --git a/example/src/main.cpp b/example/src/main.cpp new file mode 100644 index 0000000..6a7bcb8 --- /dev/null +++ b/example/src/main.cpp @@ -0,0 +1,21 @@ + + +#include "core/renderer.h" +#include "core/renderer_window.h" +#include "core/window_manager.h" + +int main(int argc, char* argv[]) { + aorii::create_renderer(renderer_api::dx11); + aorii::create_window_manager(); + + auto window = aorii::create_window({128, 128}, "hello world"); + auto glfw_window = window->get_glfw_window(); + while (!glfwWindowShouldClose(glfw_window)) { + glfwMakeContextCurrent(glfw_window); + glfwPollEvents(); + aorii::s_renderer->render(0.01); + } + + aorii::destroy_window_manager(); + aorii::destroy_renderer(); +} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000..9850ea7 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,7 @@ +project(aorii_core) + + +set(SRC_FILES "") +retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES) +add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/core/misc/scope_exit.h b/src/core/misc/scope_exit.h new file mode 100644 index 0000000..a887ee3 --- /dev/null +++ b/src/core/misc/scope_exit.h @@ -0,0 +1,28 @@ +#pragma once +#include + +template +class scope_exit_guard { +public: + scope_exit_guard(FuncType&& in_func) : func((FuncType&&)in_func) { + } + ~scope_exit_guard() { + func(); + } +private: + FuncType func; +}; + +struct scope_exit_syntax_support { + template + scope_exit_guard operator+(FuncType&& InFunc) + { + return scope_exit_guard((FuncType&&)InFunc); + } +}; + +#define PRIVATE_CONCATENATE_DETAIL(x, y) x##y +#define PRIVATE_CONCATENATE(x, y) PRIVATE_CONCATENATE_DETAIL(x, y) + +#define ON_SCOPE_EXIT const auto PRIVATE_CONCATENATE(scope_exit, __LINE__) = scope_exit_syntax_support() + [&]() + diff --git a/src/core/misc/test.cpp b/src/core/misc/test.cpp new file mode 100644 index 0000000..9da63d9 --- /dev/null +++ b/src/core/misc/test.cpp @@ -0,0 +1,3 @@ +// +// Created by 46944 on 24-10-15. +// diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt index 36c9a57..42b18f2 100644 --- a/src/renderer/CMakeLists.txt +++ b/src/renderer/CMakeLists.txt @@ -3,37 +3,54 @@ project(renderer) set(GL_BACKEND FALSE CACHE BOOL "OpenGL backend to use") set(DX_BACKEND FALSE CACHE BOOL "DirectX backend to use") set(VK_BACKEND FALSE CACHE BOOL "Vulkan backend to use") +set(METAL_BACKEND FALSE CACHE BOOL "Metal backend to use") -if (NOT GL_BACKEND AND NOT DX_BACKEND AND NOT VK_BACKEND) +if (NOT GL_BACKEND AND NOT DX_BACKEND AND NOT VK_BACKEND AND NOT METAL_BACKEND) message(FATAL_ERROR "No backend selected") endif() -set(RENDERER_SOURCES - renderer.cpp - renderer.h - renderer_buffer.cpp - renderer_buffer.h - renderer_texture.cpp - renderer_texture.h -) - +set(RENDERER_SOURCES "") +retrieve_files(core RENDERER_SOURCES) if (GL_BACKEND) retrieve_files(backend/gl RENDERER_SOURCES) - add_definitions(-DGL_BACKEND=1) endif() if (DX_BACKEND) retrieve_files(backend/dx RENDERER_SOURCES) - add_definitions(-DDX_BACKEND=1) endif () if (VK_BACKEND) retrieve_files(backend/vk RENDERER_SOURCES) - add_definitions(-DVK_BACKEND=1) +endif () +if (METAL_BACKEND) + retrieve_files(backend/metal RENDERER_SOURCES) endif () add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES}) -target_link_libraries(${PROJECT_NAME} Eigen3::Eigen spdlog::spdlog) +target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen spdlog::spdlog glfw aorii_core) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +add_os_definitions(${PROJECT_NAME}) +configure_glfw_native(${PROJECT_NAME}) + +set(ALL_BACKENDS GL_BACKEND DX_BACKEND VK_BACKEND METAL_BACKEND) +if (GL_BACKEND) + target_compile_definitions(${PROJECT_NAME} PUBLIC GL_BACKEND=1) + list(REMOVE_ITEM ALL_BACKENDS GL_BACKEND) +endif() +if (DX_BACKEND) + target_compile_definitions(${PROJECT_NAME} PUBLIC DX_BACKEND=1) + list(REMOVE_ITEM ALL_BACKENDS DX_BACKEND) +endif () +if (VK_BACKEND) + target_compile_definitions(${PROJECT_NAME} PUBLIC VK_BACKEND=1) + list(REMOVE_ITEM ALL_BACKENDS VK_BACKEND) +endif () +if (METAL_BACKEND) + target_compile_definitions(${PROJECT_NAME} PUBLIC METAL_BACKEND=1) + list(REMOVE_ITEM ALL_BACKENDS METAL_BACKEND) +endif () +foreach(BACKEND ${ALL_BACKENDS}) + target_compile_definitions(${PROJECT_NAME} PUBLIC ${BACKEND}=0) +endforeach() if (DX_BACKEND) - target_link_libraries(${PROJECT_NAME} d3d11 d3dcompiler dxgi) + target_link_libraries(${PROJECT_NAME} PRIVATE d3d11 d3dcompiler dxgi) endif () diff --git a/src/renderer/backend/dx/dx_backend.cpp b/src/renderer/backend/dx/dx_backend.cpp deleted file mode 100644 index 90559f9..0000000 --- a/src/renderer/backend/dx/dx_backend.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "dx_backend.h" - -#include "dx_texture.h" -#include "spdlog/spdlog.h" - -std::shared_ptr dx_backend::create_texture(const Eigen::Vector2i& size) { - D3D11_TEXTURE2D_DESC desc = {}; - desc.Width = size.x(); - desc.Height = size.y(); - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - ID3D11Texture2D* texture = nullptr; - if (FAILED(device->CreateTexture2D(&desc, nullptr, &texture))) { - return nullptr; - } - - return std::make_shared(texture); -} - -void dx_backend::destroy_texture(renderer_texture* texture) { -#ifdef DEBUG - spdlog::info("Destroying texture"); -#endif -} - -bool dx_backend::init() { - if (!create_device()) - return false; - if (!create_context()) - return false; - return true; -} - -bool dx_backend::create_device() { - D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 }; - const auto result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, featureLevels, 2, D3D11_SDK_VERSION, &device, nullptr, nullptr); - return SUCCEEDED(result); -} - -bool dx_backend::create_context() { - device->GetImmediateContext(&context); - return true; -} diff --git a/src/renderer/backend/dx/dx_backend.h b/src/renderer/backend/dx/dx_backend.h deleted file mode 100644 index 8c6887f..0000000 --- a/src/renderer/backend/dx/dx_backend.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "renderer.h" -#include - -class dx_backend : public renderer { - inline static dx_backend* instance = nullptr; -public: - static dx_backend* get_instance() { - return static_cast(aorii::s_renderer); - } - bool init() override; - - std::shared_ptr create_texture(const Eigen::Vector2i& size) override; - void destroy_texture(renderer_texture* texture) override; -private: - bool create_device(); - bool create_context(); - - ID3D11Device* device = nullptr; - ID3D11DeviceContext* context = nullptr; -}; - diff --git a/src/renderer/backend/dx/dx_renderer.cpp b/src/renderer/backend/dx/dx_renderer.cpp new file mode 100644 index 0000000..5e46d4d --- /dev/null +++ b/src/renderer/backend/dx/dx_renderer.cpp @@ -0,0 +1,70 @@ +#include "dx_renderer.h" + +#include + +#include "dx_texture.h" +#include "dx_window.h" +#include "core/window_manager.h" +#include "spdlog/spdlog.h" + +bool dx_renderer::init() { + if (!glfwInit()) return false; + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + if (!create_device()) return false; + if (!create_context()) return false; + return true; +} + +void dx_renderer::destroy() { glfwTerminate(); } + +bool dx_renderer::render(float delta_time) { + const auto& all_window = aorii::get_all_window(); + for (const auto& window : all_window) { + window->begin_frame(); + window->end_frame(); + } + return true; +} + +void dx_renderer::destroy_texture(renderer_texture* texture) { +#ifdef DEBUG + spdlog::info("Destroying texture"); +#endif +} + +renderer_texture* dx_renderer::create_texture(const Eigen::Vector2i& size) { + D3D11_TEXTURE2D_DESC desc = {}; + desc.Width = size.x(); + desc.Height = size.y(); + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + ID3D11Texture2D* texture = nullptr; + if (FAILED(device->CreateTexture2D(&desc, nullptr, &texture))) { return nullptr; } + + return new dx_texture(texture); +} + +renderer_window* dx_renderer::create_window() { + return new dx_window(); +} + +bool dx_renderer::create_device() { + constexpr D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 }; + const auto result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, featureLevels, 2, + D3D11_SDK_VERSION, &device, nullptr, nullptr); + return SUCCEEDED(result); +} + +bool dx_renderer::create_context() { + device->GetImmediateContext(&context); + return true; +} diff --git a/src/renderer/backend/dx/dx_renderer.h b/src/renderer/backend/dx/dx_renderer.h new file mode 100644 index 0000000..d584d45 --- /dev/null +++ b/src/renderer/backend/dx/dx_renderer.h @@ -0,0 +1,28 @@ +#pragma once +#include + +#include "core/renderer.h" + +class dx_window; + +class dx_renderer : public renderer { +public: + bool init() override; + void destroy() override; + bool render(float delta_time) override; + + renderer_texture* create_texture(const Eigen::Vector2i& size) override; + void destroy_texture(renderer_texture* texture) override; + + ID3D11Device* get_d3d_device() const { return device; } + ID3D11DeviceContext* get_d3d_context() const { return context; } +private: + renderer_window* create_window() override; + + bool create_device(); + bool create_context(); + + ID3D11Device* device = nullptr; + ID3D11DeviceContext* context = nullptr; +}; + diff --git a/src/renderer/backend/dx/dx_texture.cpp b/src/renderer/backend/dx/dx_texture.cpp index dd3173f..ce87bdd 100644 --- a/src/renderer/backend/dx/dx_texture.cpp +++ b/src/renderer/backend/dx/dx_texture.cpp @@ -1,10 +1,8 @@ #include "dx_texture.h" -#include "dx_backend.h" +#include "dx_renderer.h" -dx_texture::dx_texture(ID3D11Texture2D* texture) { - m_texture = texture; -} +dx_texture::dx_texture(ID3D11Texture2D* texture) { m_texture = texture; } dx_texture::~dx_texture() { // 如果是Debug模式, 检查m_data是否被释放 @@ -22,20 +20,18 @@ void* dx_texture::lock() { } void dx_texture::unlock() { - D3D11_TEXTURE2D_DESC desc; - m_texture->GetDesc(&desc); - D3D11_MAPPED_SUBRESOURCE mappedResource; - auto context = dx_backend::get_instance(); - context->Map(m_texture.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - memcpy(mappedResource.pData, m_data, desc.Width * desc.Height * 4); - context->Unmap(m_texture.get(), 0); - delete[] m_data; - m_data = nullptr; + // D3D11_TEXTURE2D_DESC desc; + // m_texture->GetDesc(&desc); + // D3D11_MAPPED_SUBRESOURCE mappedResource; + // auto context = dx_backend::get_instance(); + // context->Map(m_texture.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + // memcpy(mappedResource.pData, m_data, desc.Width * desc.Height * 4); + // context->Unmap(m_texture.get(), 0); + // delete[] m_data; + // m_data = nullptr; } -bool dx_texture::resize(const Eigen::Vector2i& size) { - return true; -} +bool dx_texture::resize(const Eigen::Vector2i& size) { return true; } Eigen::Vector2i dx_texture::size() { D3D11_TEXTURE2D_DESC desc; diff --git a/src/renderer/backend/dx/dx_texture.h b/src/renderer/backend/dx/dx_texture.h index ec26d23..6f5d12d 100644 --- a/src/renderer/backend/dx/dx_texture.h +++ b/src/renderer/backend/dx/dx_texture.h @@ -1,8 +1,9 @@ #pragma once -#include "renderer_texture.h" #include #include +#include "core/renderer_texture.h" + // DX11纹理 class dx_texture : public renderer_texture { public: diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp new file mode 100644 index 0000000..7a6adc5 --- /dev/null +++ b/src/renderer/backend/dx/dx_window.cpp @@ -0,0 +1,126 @@ +#include "dx_window.h" + +#include + +#include "dx_renderer.h" +#include "misc/scope_exit.h" + +using namespace aorii; + +bool dx_window::create_surface(GLFWwindow* in_window) { + const auto d3d_device = aorii::get_renderer()->get_d3d_device(); + + IDXGIDevice* dxgi_device = nullptr; + auto hr = d3d_device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgi_device)); + if (FAILED(hr)) { + spdlog::critical("Failed to get IDXGIDevice. Error: {0}", hr); + return false; + } + ON_SCOPE_EXIT{ + if (dxgi_device) dxgi_device->Release(); + }; + + IDXGIAdapter* dxgi_adapter = nullptr; + hr = dxgi_device->GetAdapter(&dxgi_adapter); + if (FAILED(hr)) { + spdlog::critical("Failed to get IDXGIAdapter. Error: {0}", hr); + return false; + } + ON_SCOPE_EXIT{ + if (dxgi_adapter) dxgi_adapter->Release(); + }; + + IDXGIFactory2* dxgi_factory = nullptr; + hr = dxgi_adapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgi_factory)); + if (FAILED(hr)) { + spdlog::critical("Failed to get IDXGIFactory. Error: {0}", hr); + return false; + } + ON_SCOPE_EXIT{ + if (dxgi_factory) dxgi_factory->Release(); + }; + + DXGI_SWAP_CHAIN_DESC1 sd = {}; + sd.Width = 0; // 使用窗口宽度 + sd.Height = 0; // 使用窗口高度 + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.BufferCount = 2; + sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + sd.Flags = 0; + + const auto hwnd = static_cast(get_window_handle()); + hr = dxgi_factory->CreateSwapChainForHwnd(d3d_device, hwnd, &sd, nullptr, nullptr, &swap_chain); + if (FAILED(hr)) { + spdlog::critical("Failed to create swap chain. Error: {0}", hr); + return false; + } + build_render_target_view(); + + return true; +} + +void dx_window::begin_frame() { + const auto render = aorii::get_renderer(); + const auto d3d_context = render->get_d3d_context(); + + d3d_context->ClearRenderTargetView(render_target_view, clear_color); + + swap_chain->Present(1, 0); +} + +void dx_window::end_frame() { + +} + +void dx_window::on_resize(const Eigen::Vector2i& in_size) { + if (in_size.isZero()) + return; + if (render_target_view) { + render_target_view->Release(); + render_target_view = nullptr; + } + + auto hr = swap_chain->ResizeBuffers(0, in_size.x(), in_size.y(), DXGI_FORMAT_UNKNOWN, 0); + if (FAILED(hr)) { + spdlog::critical("Failed to resize window. Error: {0}", hr); + return; + } + build_render_target_view(); +} + +bool dx_window::build_render_target_view() { + const auto d3d_device = aorii::get_renderer()->get_d3d_device(); + const auto d3d_context = aorii::get_renderer()->get_d3d_context(); + + ID3D11Texture2D* back_buffer = nullptr; + auto hr = swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer); + if (FAILED(hr)) { + spdlog::critical("Failed to get back buffer. Error: {0}", hr); + return false; + } + ON_SCOPE_EXIT{ + if (back_buffer) back_buffer->Release(); + }; + + hr = d3d_device->CreateRenderTargetView(back_buffer, nullptr, &render_target_view); + if (FAILED(hr)) { + spdlog::critical("Failed to create render target. Error: {0}", hr); + return false; + } + + auto framebuffer_size = get_framebuffer_size(); + + D3D11_VIEWPORT viewport = {}; + viewport.Width = framebuffer_size.x(); + viewport.Height = framebuffer_size.y(); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + d3d_context->RSSetViewports(1, &viewport); + d3d_context->OMSetRenderTargets(1, &render_target_view, nullptr); + return true; +} diff --git a/src/renderer/backend/dx/dx_window.h b/src/renderer/backend/dx/dx_window.h new file mode 100644 index 0000000..9bdecd6 --- /dev/null +++ b/src/renderer/backend/dx/dx_window.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +#include "core/renderer_window.h" + +class dx_window : public renderer_window { +public: + void begin_frame() override; + void end_frame() override; +protected: + bool create_surface(GLFWwindow* in_window) override; + void on_resize(const Eigen::Vector2i& in_size) override; + + bool build_render_target_view(); +private: + IDXGISwapChain1* swap_chain = nullptr; + ID3D11RenderTargetView* render_target_view = nullptr; +}; diff --git a/src/renderer/core/renderer.cpp b/src/renderer/core/renderer.cpp new file mode 100644 index 0000000..94c043e --- /dev/null +++ b/src/renderer/core/renderer.cpp @@ -0,0 +1,47 @@ +#include "renderer.h" + +#include + +#include "renderer_window.h" + +#if DX_BACKEND +#include "backend/dx/dx_renderer.h" +#endif + +bool aorii::create_renderer(renderer_api api) { + if (s_renderer) return true; + switch (api) { +#if DX_BACKEND + case renderer_api::dx11: s_renderer = new dx_renderer(); + break; +#endif +#if GL_BACKEND + case renderer_api::opengl: + break; +#endif +#if VK_BACKEND + case renderer_api::vulkan: + break; +#endif + default: spdlog::critical("Failed to create renderer!"); + assert(false); + } + + if (!s_renderer->init()) { + delete s_renderer; + s_renderer = nullptr; + } + return s_renderer != nullptr; +} + +void aorii::destroy_renderer() { + if (!s_renderer) return; + + s_renderer->destroy(); + delete s_renderer; + s_renderer = nullptr; +} + +void renderer::destroy_window(renderer_window* window) { + delete window; +} diff --git a/src/renderer/core/renderer.h b/src/renderer/core/renderer.h new file mode 100644 index 0000000..27c6a97 --- /dev/null +++ b/src/renderer/core/renderer.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include + +class renderer_window; +class renderer_texture; + +enum class renderer_api { + dx11, + opengl, + vulkan, + metal, +}; + +class renderer { + friend class window_manager; +public: + virtual ~renderer() = default; + + virtual bool init() = 0; + virtual void destroy() = 0; + virtual bool render(float delta_time) = 0; + + virtual renderer_texture* create_texture(const Eigen::Vector2i& size) = 0; + virtual void destroy_texture(renderer_texture* texture) = 0; +private: + virtual renderer_window* create_window() = 0; + virtual void destroy_window(renderer_window* window); +}; + +namespace aorii { + inline renderer* s_renderer = nullptr; + template + static T* get_renderer() { + return static_cast(s_renderer); + } + + bool create_renderer(renderer_api api); + void destroy_renderer(); +} diff --git a/src/renderer/renderer_buffer.cpp b/src/renderer/core/renderer_buffer.cpp similarity index 100% rename from src/renderer/renderer_buffer.cpp rename to src/renderer/core/renderer_buffer.cpp diff --git a/src/renderer/renderer_buffer.h b/src/renderer/core/renderer_buffer.h similarity index 100% rename from src/renderer/renderer_buffer.h rename to src/renderer/core/renderer_buffer.h diff --git a/src/renderer/renderer_texture.cpp b/src/renderer/core/renderer_texture.cpp similarity index 100% rename from src/renderer/renderer_texture.cpp rename to src/renderer/core/renderer_texture.cpp diff --git a/src/renderer/renderer_texture.h b/src/renderer/core/renderer_texture.h similarity index 100% rename from src/renderer/renderer_texture.h rename to src/renderer/core/renderer_texture.h diff --git a/src/renderer/core/renderer_window.cpp b/src/renderer/core/renderer_window.cpp new file mode 100644 index 0000000..b1da31d --- /dev/null +++ b/src/renderer/core/renderer_window.cpp @@ -0,0 +1,26 @@ +#include "renderer_window.h" +#include "GLFW/glfw3native.h" + +renderer_window::~renderer_window() { if (window) glfwDestroyWindow(window); } + +bool renderer_window::init(const Eigen::Vector2i& in_size, const std::string& in_title) { + window = glfwCreateWindow(in_size.x(), in_size.y(), in_title.c_str(), nullptr, nullptr); + if (!window) return false; + return create_surface(window); +} + +void* renderer_window::get_window_handle() const { +#if WINDOWS + return glfwGetWin32Window(window); +#elif MACOS + return glfwGetCocoaWindow(window); +#elif LINUX +#if GLFW_EXPOSE_NATIVE_WAYLAND + return glfwGetWaylandWindow(window); +#else + return (void*)glfwGetX11Window(window); +#endif +#else + return nullptr; +#endif +} diff --git a/src/renderer/core/renderer_window.h b/src/renderer/core/renderer_window.h new file mode 100644 index 0000000..1219977 --- /dev/null +++ b/src/renderer/core/renderer_window.h @@ -0,0 +1,41 @@ +#pragma once +#include "Eigen/Eigen" +#include "GLFW/glfw3.h" + +class renderer_window { + friend class window_manager; +public: + const float clear_color[4] = {0.4, 0.3, 0.6, 1}; + + virtual ~renderer_window(); + + virtual bool init(const Eigen::Vector2i& in_size, const std::string& in_title); + + virtual void begin_frame() = 0; + virtual void end_frame() = 0; + + void resize(const Eigen::Vector2i& in_size) { + if (in_size == get_window_size()) return; + on_resize(in_size); + } + + Eigen::Vector2i get_window_size() const { + int w, h; + glfwGetWindowSize(window, &w, &h); + return Eigen::Vector2i(w, h); + } + + Eigen::Vector2i get_framebuffer_size() const { + int w, h; + glfwGetFramebufferSize(window, &w, &h); + return Eigen::Vector2i(w, h); + } + + void* get_window_handle() const; + GLFWwindow* get_glfw_window() const { return window; } +protected: + virtual bool create_surface(GLFWwindow* in_window) = 0; + virtual void on_resize(const Eigen::Vector2i& in_size) = 0; +private: + GLFWwindow* window = nullptr; +}; diff --git a/src/renderer/core/window_manager.cpp b/src/renderer/core/window_manager.cpp new file mode 100644 index 0000000..8cecc6d --- /dev/null +++ b/src/renderer/core/window_manager.cpp @@ -0,0 +1,44 @@ +#include "window_manager.h" + +#include + +#include "renderer.h" +#include "renderer_window.h" + +void on_window_size_change(GLFWwindow* changed_window, int width, int height) { + aorii::s_window_manager->on_glfw_window_size_callback(changed_window, width, height); +} + +window_manager::~window_manager() { + for (const auto window : windows) { + aorii::s_renderer->destroy_window(window); + } + windows.clear(); +} + +renderer_window* window_manager::create_window(const Eigen::Vector2i& in_size, const std::string& in_title) { + const auto window = aorii::s_renderer->create_window(); + if (!window->init(in_size, in_title)) { + delete window; + spdlog::error("Failed to create window"); + return nullptr; + } + const auto glfw_window = window->get_glfw_window(); + glfwSetFramebufferSizeCallback(glfw_window, on_window_size_change); + windows.push_back(window); + return window; +} + +void window_manager::on_glfw_window_size_callback(GLFWwindow* in_window, int width, int height) { + auto find = find_window(in_window); + if (!find) return; + find->on_resize({ width, height }); +} + +renderer_window* window_manager::find_window(GLFWwindow* in_window) { + auto it = std::find_if(windows.begin(), windows.end(), [in_window](renderer_window* w) { + return w->get_glfw_window() == in_window; + }); + if (it != windows.end()) { return *it; } + return nullptr; +} diff --git a/src/renderer/core/window_manager.h b/src/renderer/core/window_manager.h new file mode 100644 index 0000000..b385d90 --- /dev/null +++ b/src/renderer/core/window_manager.h @@ -0,0 +1,30 @@ +#pragma once +#include "Eigen/Eigen" +#include "GLFW/glfw3.h" + +class renderer_window; + +class window_manager { +public: + ~window_manager(); + renderer_window* create_window(const Eigen::Vector2i& in_size, const std::string& in_title); + + const auto& get_windows() const { return windows; } + + void on_glfw_window_size_callback(GLFWwindow* in_window, int width, int height); +private: + renderer_window* find_window(GLFWwindow* in_window); + std::vector windows; +}; + +namespace aorii { + inline window_manager* s_window_manager; + inline void create_window_manager() { s_window_manager = new window_manager(); } + inline void destroy_window_manager() { delete s_window_manager; } + + inline renderer_window* create_window(const Eigen::Vector2i& in_size, const std::string& in_title) { + return s_window_manager->create_window(in_size, in_title); + } + + inline const auto& get_all_window() { return s_window_manager->get_windows(); } +} diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp deleted file mode 100644 index 6f2c98e..0000000 --- a/src/renderer/renderer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "renderer.h" - -#ifdef DX_BACKEND -#include "backend/dx/dx_backend.h" -#endif - -bool aorii::create_renderer(renderer_api api) { - if (s_renderer) - return true; - switch (api) { -#ifdef DX_BACKEND - case renderer_api::dx11: - s_renderer = new dx_backend(); - break; -#endif -#ifdef GL_BACKEND - case renderer_api::opengl: - break; -#endif -#ifdef VK_BACKEND - case renderer_api::vulkan: - break; -#endif - default: - assert(false); - break; - } - return s_renderer->init(); -} diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h deleted file mode 100644 index ef6e304..0000000 --- a/src/renderer/renderer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include - -class renderer_texture; - -enum class renderer_api { - dx11, - opengl, - vulkan, -}; - -class renderer { -public: - virtual ~renderer() = default; - - virtual std::shared_ptr create_texture(const Eigen::Vector2i& size) = 0; - virtual void destroy_texture(renderer_texture* texture) = 0; - - virtual bool init() = 0; -}; - -namespace aorii { - inline static renderer* s_renderer = nullptr; - bool create_renderer(renderer_api api); -}