DX11后端框架
This commit is contained in:
parent
3a0593c3ff
commit
8c26893b66
@ -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)
|
||||
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 ()
|
||||
|
39
cmake/configure_glfw_native.cmake
Normal file
39
cmake/configure_glfw_native.cmake
Normal file
@ -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()
|
58
cmake/detect_os.cmake
Normal file
58
cmake/detect_os.cmake
Normal file
@ -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()
|
8
example/CMakeLists.txt
Normal file
8
example/CMakeLists.txt
Normal file
@ -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)
|
21
example/src/main.cpp
Normal file
21
example/src/main.cpp
Normal file
@ -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();
|
||||
}
|
7
src/core/CMakeLists.txt
Normal file
7
src/core/CMakeLists.txt
Normal file
@ -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})
|
28
src/core/misc/scope_exit.h
Normal file
28
src/core/misc/scope_exit.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
|
||||
template<typename FuncType>
|
||||
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 <typename FuncType>
|
||||
scope_exit_guard<FuncType> operator+(FuncType&& InFunc)
|
||||
{
|
||||
return scope_exit_guard<FuncType>((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() + [&]()
|
||||
|
3
src/core/misc/test.cpp
Normal file
3
src/core/misc/test.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
//
|
||||
// Created by 46944 on 24-10-15.
|
||||
//
|
@ -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 ()
|
||||
|
@ -1,51 +0,0 @@
|
||||
#include "dx_backend.h"
|
||||
|
||||
#include "dx_texture.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
std::shared_ptr<renderer_texture> 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<dx_texture>(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;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
#include "renderer.h"
|
||||
#include <d3d11.h>
|
||||
|
||||
class dx_backend : public renderer {
|
||||
inline static dx_backend* instance = nullptr;
|
||||
public:
|
||||
static dx_backend* get_instance() {
|
||||
return static_cast<dx_backend*>(aorii::s_renderer);
|
||||
}
|
||||
bool init() override;
|
||||
|
||||
std::shared_ptr<renderer_texture> 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;
|
||||
};
|
||||
|
70
src/renderer/backend/dx/dx_renderer.cpp
Normal file
70
src/renderer/backend/dx/dx_renderer.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "dx_renderer.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#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;
|
||||
}
|
28
src/renderer/backend/dx/dx_renderer.h
Normal file
28
src/renderer/backend/dx/dx_renderer.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include "renderer_texture.h"
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
|
||||
#include "core/renderer_texture.h"
|
||||
|
||||
// DX11纹理
|
||||
class dx_texture : public renderer_texture {
|
||||
public:
|
||||
|
126
src/renderer/backend/dx/dx_window.cpp
Normal file
126
src/renderer/backend/dx/dx_window.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "dx_window.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#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<dx_renderer>()->get_d3d_device();
|
||||
|
||||
IDXGIDevice* dxgi_device = nullptr;
|
||||
auto hr = d3d_device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&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<void**>(&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<HWND>(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<dx_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<dx_renderer>()->get_d3d_device();
|
||||
const auto d3d_context = aorii::get_renderer<dx_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;
|
||||
}
|
19
src/renderer/backend/dx/dx_window.h
Normal file
19
src/renderer/backend/dx/dx_window.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
|
||||
#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;
|
||||
};
|
47
src/renderer/core/renderer.cpp
Normal file
47
src/renderer/core/renderer.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "renderer.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#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;
|
||||
}
|
40
src/renderer/core/renderer.h
Normal file
40
src/renderer/core/renderer.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
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<typename T>
|
||||
static T* get_renderer() {
|
||||
return static_cast<T*>(s_renderer);
|
||||
}
|
||||
|
||||
bool create_renderer(renderer_api api);
|
||||
void destroy_renderer();
|
||||
}
|
26
src/renderer/core/renderer_window.cpp
Normal file
26
src/renderer/core/renderer_window.cpp
Normal file
@ -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
|
||||
}
|
41
src/renderer/core/renderer_window.h
Normal file
41
src/renderer/core/renderer_window.h
Normal file
@ -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;
|
||||
};
|
44
src/renderer/core/window_manager.cpp
Normal file
44
src/renderer/core/window_manager.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#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;
|
||||
}
|
30
src/renderer/core/window_manager.h
Normal file
30
src/renderer/core/window_manager.h
Normal file
@ -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<renderer_window*> 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(); }
|
||||
}
|
@ -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();
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
class renderer_texture;
|
||||
|
||||
enum class renderer_api {
|
||||
dx11,
|
||||
opengl,
|
||||
vulkan,
|
||||
};
|
||||
|
||||
class renderer {
|
||||
public:
|
||||
virtual ~renderer() = default;
|
||||
|
||||
virtual std::shared_ptr<renderer_texture> 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user