DX11后端框架

This commit is contained in:
Nanako 2024-10-15 18:07:21 +08:00
parent 3a0593c3ff
commit 8c26893b66
29 changed files with 693 additions and 161 deletions

View File

@ -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 ()

View 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
View 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
View 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
View 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
View 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})

View 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
View File

@ -0,0 +1,3 @@
//
// Created by 46944 on 24-10-15.
//

View File

@ -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 ()

View File

@ -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;
}

View File

@ -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;
};

View 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;
}

View 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;
};

View File

@ -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;

View File

@ -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:

View 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;
}

View 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;
};

View 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;
}

View 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();
}

View 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
}

View 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;
};

View 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;
}

View 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(); }
}

View File

@ -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();
}

View File

@ -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);
}