This commit is contained in:
Nanako 2024-01-31 00:20:46 +08:00
commit bba0a3a389
36 changed files with 9654 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

15
.gitmodules vendored Normal file
View File

@ -0,0 +1,15 @@
[submodule "third_party/imgui/imgui"]
path = third_party/imgui/imgui
url = https://github.com/ocornut/imgui.git
[submodule "third_party/sdl"]
path = third_party/sdl
url = https://github.com/libsdl-org/SDL.git
[submodule "third_party/portaudio"]
path = third_party/portaudio
url = https://github.com/PortAudio/portaudio.git
[submodule "third_party/spdlog"]
path = third_party/spdlog
url = https://github.com/gabime/spdlog.git
[submodule "third_party/HLSLcc"]
path = third_party/HLSLcc
url = https://github.com/Unity-Technologies/HLSLcc.git

142
CMakeLists.txt Normal file
View File

@ -0,0 +1,142 @@
cmake_minimum_required(VERSION 3.5)
project(arona_core)
function(retrieve_files out_files)
set(source_list)
# .h .hpp. ini HEAD_FILES
file(GLOB_RECURSE HEAD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS *.h *.hpp *.ini)
# *.cpp *.c SRC_FILES
file(GLOB_RECURSE SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS *.cpp *.c)
# HEDADER_FILES SRC_FILES ALL_FILES
set(ALL_FILES ${HEAD_FILES} ${SRC_FILES})
set(RESULT "")
# ALL_FILES 变量里面的所有文件分类(保留资源管理器的目录结构)
foreach(fileItem ${ALL_FILES})
# Get the directory of the source file
get_filename_component(PARENT_DIR "${fileItem}" DIRECTORY)
#
if(PARENT_DIR STREQUAL "windows")
if(WIN32)
set(RESULT "${RESULT};${fileItem}")
else()
continue()
endif()
elseif(PARENT_DIR STREQUAL "linux")
if(UNIX AND NOT APPLE)
set(RESULT "${RESULT};${fileItem}")
else()
continue()
endif()
elseif(PARENT_DIR STREQUAL "mac")
if(APPLE)
set(RESULT "${RESULT};${fileItem}")
else()
continue()
endif()
else()
#
set(RESULT "${RESULT};${fileItem}")
endif()
# Remove common directory prefix to make the group
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}")
# Make sure we are using windows slashes
string(REPLACE "/" "\\" GROUP "${GROUP}")
# Group into "Source Files" and "Header Files"
set(GROUP "${GROUP}")
source_group("${GROUP}" FILES "${fileItem}")
endforeach()
set(${out_files} ${RESULT} PARENT_SCOPE)
endfunction()
add_subdirectory(core)
add_subdirectory(third_party/imgui)
add_subdirectory(third_party/sdl)
add_subdirectory(third_party/portaudio)
add_subdirectory(third_party/spdlog)
add_subdirectory(third_party/HLSLcc)
# setup portaudio
set(PA_USE_ASIO ON CACHE BOOL "" FORCE)
set(PA_BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE)
if (WIN32)
set(PA_USE_WMME OFF CACHE BOOL "" FORCE)
set(PA_USE_WDMKS OFF CACHE BOOL "" FORCE)
set(PA_USE_WDMKS_DEVICE_INFO OFF CACHE BOOL "" FORCE)
set(PA_USE_DS OFF CACHE BOOL "" FORCE)
elseif(APPLE)
set(PA_USE_COREAUDIO ON CACHE BOOL "" FORCE)
endif()
# setup SDL
set(SDL_ASSEMBLY OFF CACHE BOOL "" FORCE)
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
set(SDL_AUDIO OFF CACHE BOOL "" FORCE)
set(SDL_AVX OFF CACHE BOOL "" FORCE)
set(SDL_AVX2 OFF CACHE BOOL "" FORCE)
set(SDL_AVX512F OFF CACHE BOOL "" FORCE)
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
set(SDL_DIRECTX OFF CACHE BOOL "" FORCE)
set(SDL_DISKAUDIO OFF CACHE BOOL "" FORCE)
set(SDL_DUMMYAUDIO OFF CACHE BOOL "" FORCE)
set(SDL_DUMMYVIDEO OFF CACHE BOOL "" FORCE)
set(SDL_FILE OFF CACHE BOOL "" FORCE)
set(SDL_FILESYSTEM OFF CACHE BOOL "" FORCE)
set(SDL_HAPTIC OFF CACHE BOOL "" FORCE)
set(SDL_HIDAPI OFF CACHE BOOL "" FORCE)
set(SDL_HIDAPI_JOYSTICK OFF CACHE BOOL "" FORCE)
set(SDL_JOYSTICK OFF CACHE BOOL "" FORCE)
set(SDL_LIBUDEV OFF CACHE BOOL "" FORCE)
set(SDL_LOCALE OFF CACHE BOOL "" FORCE)
set(SDL_MISC OFF CACHE BOOL "" FORCE)
set(SDL_MMX OFF CACHE BOOL "" FORCE)
set(SDL_OFFSCREEN OFF CACHE BOOL "" FORCE)
set(SDL_OPENGLES OFF CACHE BOOL "" FORCE)
set(SDL_POWER OFF CACHE BOOL "" FORCE)
set(SDL_RENDER OFF CACHE BOOL "" FORCE)
set(SDL_RENDER_D3D OFF CACHE BOOL "" FORCE)
set(SDL_SENSOR OFF CACHE BOOL "" FORCE)
set(SDL_SSE OFF CACHE BOOL "" FORCE)
set(SDL_SSE2 OFF CACHE BOOL "" FORCE)
set(SDL_SSE3 OFF CACHE BOOL "" FORCE)
set(SDL_SSE4_1 OFF CACHE BOOL "" FORCE)
set(SDL_SSE4_2 OFF CACHE BOOL "" FORCE)
set(SDL_TEST OFF CACHE BOOL "" FORCE)
set(SDL_TIMERS OFF CACHE BOOL "" FORCE)
set(SDL_VIRTUAL_JOYSTICK OFF CACHE BOOL "" FORCE)
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
if (WIN32 OR (UNIX AND NOT APPLE))
set(SDL_VULKAN ON CACHE BOOL "" FORCE)
else()
set(SDL_VULKAN OFF CACHE BOOL "" FORCE)
set(SDL_METAL ON CACHE BOOL "" FORCE)
endif()
set(SDL_WASAPI OFF CACHE BOOL "" FORCE)
set(SDL_XINPUT OFF CACHE BOOL "" FORCE)
set(SDL_DISABLE_UNINSTALL ON CACHE BOOL "" FORCE)
set(SDL_OPENGL OFF CACHE BOOL "" FORCE)
# setup spdlog
set(SPDLOG_BUILD_SHARED ON CACHE BOOL "" FORCE)
set(SPDLOG_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE)
set(SPDLOG_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(SPDLOG_BUILD_BENCH OFF CACHE BOOL "" FORCE)
set(SPDLOG_FMT_EXTERNAL OFF CACHE BOOL "" FORCE)
set(SPDLOG_FMT_EXTERNAL_HO OFF CACHE BOOL "" FORCE)
set(SPDLOG_WCHAR_SUPPORT ON CACHE BOOL "" FORCE)
set(SPDLOG_ENABLE_PCH ON CACHE BOOL "" FORCE)
set(SPDLOG_USE_STD_FORMAT OFF CACHE BOOL "" FORCE)
# install
install(DIRECTORY ${CMAKE_SOURCE_DIR}/third_party/imgui/imgui/misc/fonts DESTINATION ${CMAKE_BINARY_DIR}/bin)

18
core/CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.5)
project(core)
set(CMAKE_CXX_STANDARD 23)
set(ALL_FILES "")
retrieve_files(ALL_FILES)
add_library(${PROJECT_NAME} SHARED ${ALL_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui HLSLcc)
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui HLSLcc)
target_link_libraries(${PROJECT_NAME} PUBLIC imgui spdlog ${SDL2_LIBRARIES} HLSLcc)
target_precompile_headers(${PROJECT_NAME} PUBLIC extern.h)
add_definitions(-Dcore_EXPORTS -DSTB_IMAGE_IMPLEMENTATION -DSTBI_WINDOWS_UTF8)

View File

@ -0,0 +1,183 @@
#include "application.h"
#include <assert.h>
#include <iostream>
#include "command_line.h"
#include "imgui_impl_sdl3.h"
#include "imgui_internal.h"
#include "filesystem/stb_image.h"
#include "rhi/texture.h"
#include "spdlog/async.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#if WIN32
#include "rhi/windows/dx11/renderer_dx11.h"
#endif
bool g_is_running = true;
bool g_exit_requested = false;
application::~application()
{
application::shutdown();
}
void application::init(window_params in_window_params, int argc, char** argv)
{
try
{
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/log.txt");
}
catch (const spdlog::spdlog_ex &ex)
{
std::cout << "Log init failed: " << ex.what() << std::endl;
}
command_line::instance().init(argc, argv);
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
init_imgui(ImGui::CreateContext());
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
unsigned int window_flags = 0;
#if WIN32
bool use_dx11 = false;
bool use_dx12 = false;
bool use_vulkan = false;
#else
bool use_vulkan = true;
#endif
#if WIN32
command_line::instance().get_arg("dx11", use_dx11);
command_line::instance().get_arg("dx12", use_dx12);
command_line::instance().get_arg("vulkan", use_vulkan);
// only one renderer can be used at a time
const int renderer_count = use_dx11 + use_dx12 + use_vulkan;
assert(renderer_count <= 1);
// if no renderer is specified, use dx11
if (!(use_dx11 || use_dx12 || use_vulkan))
{
use_dx11 = true;
}
if (use_dx11)
{
renderer_ = new renderer_dx11();
}
// if (use_dx12)
// {
// renderer_ = new renderer_dx12();
// }
// if (use_vulkan)
// {
// renderer_ = new renderer_vulkan();
// window_flags |= SDL_WINDOW_VULKAN;
// }
#else
if (use_vulkan)
{
renderer_ = new renderer_vulkan();
window_flags |= SDL_WINDOW_VULKAN;
}
#endif
// if (!renderer_)
// renderer_ = new renderer_null();
if (in_window_params.fullscreen)
window_flags |= SDL_WINDOW_FULLSCREEN;
if (in_window_params.borderless)
window_flags |= SDL_WINDOW_BORDERLESS;
if (in_window_params.resizable)
window_flags |= SDL_WINDOW_RESIZABLE;
if (in_window_params.minimized)
window_flags |= SDL_WINDOW_MINIMIZED;
if (in_window_params.maximized)
window_flags |= SDL_WINDOW_MAXIMIZED;
if (in_window_params.hi_dpi)
window_flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
if (in_window_params.always_on_top)
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
// new SDL window
window_ = SDL_CreateWindow(in_window_params.title.c_str(), in_window_params.width, in_window_params.height, window_flags);
if (!window_)
{
spdlog::error("Failed to create SDL window: {}", SDL_GetError());
return;
}
SDL_SetWindowPosition(window_, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
SDL_ShowWindow(window_);
renderer_->init(window_);
renderer_->resize(in_window_params.width, in_window_params.height);
g_is_running = true;
}
int application::run()
{
while (!g_exit_requested)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT)
g_exit_requested = true;
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window_))
g_exit_requested = true;
if (event.type == SDL_EVENT_WINDOW_RESIZED)
{
const int width = event.window.data1;
const int height = event.window.data2;
renderer_->resize(width, height);
}
}
if (g_exit_requested)
break;
renderer_->new_frame();
draw_gui();
renderer_->end_frame();
}
return 0;
}
void application::shutdown()
{
renderer_->shutdown();
ImGui::DestroyContext();
delete renderer_;
}
texture* application::load_texture(const std::string& path) const
{
int width = 0;
int height = 0;
unsigned char* image_data = stbi_load(path.c_str(), &width, &height, nullptr, 4);
if (!image_data)
{
spdlog::error("Failed to load texture: {}", path.c_str());
return nullptr;
}
const auto texture = renderer_->create_texture(image_data, width, height);
stbi_image_free(image_data);
return texture;
}
texture* application::create_texture(const unsigned char* data, const int width, const int height) const
{
return renderer_->create_texture(data, width, height);
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <string>
#include "SDL.h"
#include "imgui.h"
class renderer;
class texture;
extern bool g_is_running;
extern bool g_exit_requested;
struct window_params
{
std::string title;
int width;
int height;
bool fullscreen;
bool borderless;
bool resizable;
bool minimized;
bool maximized;
bool hi_dpi;
bool always_on_top;
};
class CORE_API application
{
public:
application() = default;
virtual ~application();
application(const application&) = delete;
application(application&&) = delete;
virtual void init(window_params in_window_params, int argc, char** argv);
virtual int run();
virtual void shutdown();
virtual void draw_gui() = 0;
virtual void init_imgui(ImGuiContext* in_context) = 0;
texture* load_texture(const std::string& path) const;
texture* create_texture(const unsigned char* data, const int width, const int height) const;
renderer* get_renderer() const { return renderer_; }
SDL_Window* get_window() const { return window_; }
protected:
renderer* renderer_ = nullptr;
SDL_Window* window_ = nullptr;
};

View File

@ -0,0 +1,78 @@
#include "command_line.h"
void command_line::init(int argc, char** argv)
{
// parser argv
args_.clear();
for (int i = 0; i < argc; ++i)
{
std::string arg = argv[i];
if (arg[0] == '-')
{
std::string key = arg.substr(1);
std::string value;
if (i + 1 < argc)
{
std::string next_arg = argv[i + 1];
if (next_arg[0] != '-')
{
value = next_arg;
++i;
}
}
args_[key] = value;
}
}
}
void command_line::get_arg(const std::string& key, std::string& out) const
{
const auto it = args_.find(key);
if (it != args_.end())
{
out = it->second;
}
else
{
out = "";
}
}
void command_line::get_arg(const std::string& key, int& out) const
{
const auto it = args_.find(key);
if (it != args_.end())
{
out = std::stoi(it->second);
}
else
{
out = 0;
}
}
void command_line::get_arg(const std::string& key, float& out) const
{
const auto it = args_.find(key);
if (it != args_.end())
{
out = std::stof(it->second);
}
else
{
out = 0.0f;
}
}
void command_line::get_arg(const std::string& key, bool& out) const
{
const auto it = args_.find(key);
if (it != args_.end())
{
out = it->second != "false";
}
else
{
out = false;
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <map>
#include <string>
class command_line
{
public:
static command_line& instance()
{
static command_line instance;
return instance;
}
void init(int argc, char** argv);
void get_arg(const std::string& key, std::string& out) const;
void get_arg(const std::string& key, int& out) const;
void get_arg(const std::string& key, float& out) const;
void get_arg(const std::string& key, bool& out) const;
private:
std::map<std::string, std::string> args_; // key-value pairs
command_line() = default;
};

9
core/extern.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "spdlog/spdlog.h"
#include "rhi/rhi_defintion.h"
#ifdef core_EXPORTS
#define CORE_API __declspec(dllexport)
#else
#define CORE_API __declspec(dllimport)
#endif

7986
core/filesystem/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
#include "E:/Projects/Arona/build/core/CMakeFiles/core.dir/Debug/cmake_pch.hxx"
#include "ref_counting.h"

207
core/misc/ref_counting.h Normal file
View File

@ -0,0 +1,207 @@
#pragma once
#include <assert.h>
/**
* A smart pointer to an object which implements AddRef/Release.
*/
template<typename ReferencedType>
class ref_count_ptr
{
typedef ReferencedType* reference_type;
public:
ref_count_ptr():
reference_(nullptr)
{ }
explicit ref_count_ptr(ReferencedType* in_reference,bool bAddRef = true)
{
reference_ = in_reference;
if(reference_ && bAddRef)
{
reference_->AddRef();
}
}
ref_count_ptr(const ref_count_ptr& copy)
{
reference_ = copy.reference_;
if(reference_)
{
reference_->AddRef();
}
}
template<typename CopyReferencedType>
explicit ref_count_ptr(const ref_count_ptr<CopyReferencedType>& copy)
{
reference_ = static_cast<ReferencedType*>(copy.get_reference());
if (reference_)
{
reference_->AddRef();
}
}
ref_count_ptr(ref_count_ptr&& move) noexcept
{
reference_ = move.reference_;
move.reference_ = nullptr;
}
template<typename MoveReferencedType>
explicit ref_count_ptr(ref_count_ptr<MoveReferencedType>&& move)
{
reference_ = static_cast<ReferencedType*>(move.get_reference());
move.reference_ = nullptr;
}
~ref_count_ptr()
{
if(reference_)
{
reference_->Release();
}
}
ref_count_ptr& operator=(ReferencedType* in_reference)
{
if (reference_ != in_reference)
{
// Call AddRef before Release, in case the new reference is the same as the old reference.
ReferencedType* old_reference = reference_;
reference_ = in_reference;
if (reference_)
{
reference_->AddRef();
}
if (old_reference)
{
old_reference->Release();
}
}
return *this;
}
ref_count_ptr& operator=(const ref_count_ptr& in_ptr)
{
return *this = in_ptr.reference_;
}
template<typename CopyReferencedType>
ref_count_ptr& operator=(const ref_count_ptr<CopyReferencedType>& in_ptr)
{
return *this = in_ptr.GetReference();
}
ref_count_ptr& operator=(ref_count_ptr&& in_ptr) noexcept
{
if (this != &in_ptr)
{
ReferencedType* old_reference = reference_;
reference_ = in_ptr.reference_;
in_ptr.reference_ = nullptr;
if(old_reference)
{
old_reference->Release();
}
}
return *this;
}
template<typename MoveReferencedType>
ref_count_ptr& operator=(ref_count_ptr<MoveReferencedType>&& in_ptr)
{
// InPtr is a different type (or we would have called the other operator), so we need not test &InPtr != this
ReferencedType* old_reference = reference_;
reference_ = in_ptr.reference_;
in_ptr.reference_ = nullptr;
if (old_reference)
{
old_reference->Release();
}
return *this;
}
ReferencedType* operator->() const
{
return reference_;
}
operator reference_type() const
{
return reference_;
}
ReferencedType** get_init_reference()
{
*this = nullptr;
return &reference_;
}
ReferencedType* get_reference() const
{
return reference_;
}
friend bool is_valid_ref(const ref_count_ptr& in_reference)
{
return in_reference.reference_ != nullptr;
}
bool is_valid() const
{
return reference_ != nullptr;
}
void safe_release()
{
*this = nullptr;
}
unsigned int get_ref_count()
{
unsigned int result = 0;
if (reference_)
{
result = reference_->GetRefCount();
assert(result > 0); // you should never have a zero ref count if there is a live ref counted pointer (*this is live)
}
return result;
}
void swap(ref_count_ptr& in_ptr) noexcept // this does not change the reference count, and so is faster
{
ReferencedType* old_reference = reference_;
reference_ = in_ptr.reference_;
in_ptr.reference_ = old_reference;
}
// void Serialize(FArchive& Ar)
// {
// reference_type PtrReference = Reference;
// Ar << PtrReference;
// if(Ar.IsLoading())
// {
// *this = PtrReference;
// }
// }
private:
ReferencedType* reference_;
template <typename OtherType>
friend class ref_count_ptr;
public:
bool operator==(const ref_count_ptr& b) const
{
return get_reference() == b.get_reference();
}
bool operator==(ReferencedType* b) const
{
return get_reference() == b;
}
};

View File

@ -0,0 +1 @@
#include "render_resource.h"

View File

@ -0,0 +1,13 @@
#pragma once
#include "imgui.h"
class render_resource
{
public:
virtual ~render_resource() = default;
virtual int get_width() const = 0;
virtual int get_height() const = 0;
virtual ImTextureID get_texture_id() = 0;
void draw() { ImGui::Image(get_texture_id(), ImVec2(static_cast<float>(get_width()), static_cast<float>(get_height()))); }
};

View File

@ -0,0 +1 @@
#include "render_target.h"

37
core/rhi/render_target.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include "render_resource.h"
#include "rhi_defintion.h"
enum class lock_state
{
NONE,
WRITE,
READ,
READ_WRITE
};
class render_target : public render_resource
{
public:
int get_height() const override { return height_; }
int get_width() const override { return width_; }
virtual void init(int width, int height, texture_format format) = 0;
virtual void resize(const int width, const int height)
{
if (width_ == width && height_ == height)
return;
width_ = width;
height_ = height;
on_resize(width, height);
}
virtual void* lock(lock_state state) = 0;
virtual void unlock() = 0;
protected:
virtual void on_resize(int width, int height) = 0;
int width_ = 0;
int height_ = 0;
};

0
core/rhi/renderer.cpp Normal file
View File

25
core/rhi/renderer.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <SDL_video.h>
class render_target;
class texture;
class renderer
{
public:
virtual ~renderer() = default;
virtual bool init(SDL_Window* window_handle) = 0;
virtual void shutdown() = 0;
virtual void new_frame() = 0;
virtual void end_frame() = 0;
virtual void resize(int width, int height) = 0;
virtual texture* create_texture(const unsigned char* data, int width, int height) = 0;
virtual render_target* create_render_target(int width, int height, texture_format format) = 0;
virtual bool compile_shader() = 0;
void set_vsync(const bool vsync) { vsync_ = vsync; }
protected:
bool vsync_ = true;
};

8
core/rhi/rhi_defintion.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
enum class texture_format
{
RGBA8,
RGBA16_FLOAT,
RGBA32_FLOAT,
};

1
core/rhi/texture.cpp Normal file
View File

@ -0,0 +1 @@
#include "texture.h"

21
core/rhi/texture.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "imgui.h"
#include <string>
#include "render_resource.h"
class texture : public render_resource
{
public:
texture(): width_(0), height_(0)
{
}
virtual bool init_data(const unsigned char* data, int width, int height) = 0;
[[nodiscard]] virtual bool is_valid() const = 0;
[[nodiscard]] int get_width() const override { return width_; }
[[nodiscard]] int get_height() const override { return height_; }
protected:
int width_;
int height_;
};

View File

@ -0,0 +1,297 @@
#include "find_best_device_dx11.h"
#include <delayimp.h>
#include <cassert>
#include <codecvt>
#include "spdlog/spdlog.h"
bool is_delay_load_exception(PEXCEPTION_POINTERS ExceptionPointers)
{
switch (ExceptionPointers->ExceptionRecord->ExceptionCode)
{
case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND):
return EXCEPTION_EXECUTE_HANDLER;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
const char* get_feature_level_string(D3D_FEATURE_LEVEL feature_level)
{
switch (feature_level)
{
case D3D_FEATURE_LEVEL_9_1: return "9_1";
case D3D_FEATURE_LEVEL_9_2: return "9_2";
case D3D_FEATURE_LEVEL_9_3: return "9_3";
case D3D_FEATURE_LEVEL_10_0: return "10_0";
case D3D_FEATURE_LEVEL_10_1: return "10_1";
case D3D_FEATURE_LEVEL_11_0: return "11_0";
case D3D_FEATURE_LEVEL_11_1: return "11_1";
case D3D_FEATURE_LEVEL_12_0: return "12_0";
case D3D_FEATURE_LEVEL_12_1: return "12_1";
case D3D_FEATURE_LEVEL_12_2: return "12_2";
case D3D_FEATURE_LEVEL_1_0_CORE: return "1_0_CORE";
}
return "X_X";
}
find_best_device_dx11::find_best_device_dx11()
{
chosen_feature_level_ = D3D_FEATURE_LEVEL_1_0_CORE;
gpu_preference_ = DXGI_GPU_PREFERENCE_UNSPECIFIED;
load_settings();
select_adapter();
}
find_best_device_dx11::~find_best_device_dx11()
{
chosen_adapter_.safe_release();
dxgi_factory1_.safe_release();
dxgi_factory6_.safe_release();
}
bool find_best_device_dx11::is_valid() const
{
return chosen_adapter_.is_valid() && chosen_feature_level_ != D3D_FEATURE_LEVEL_1_0_CORE;
}
bool find_best_device_dx11::create_device(HWND in_hwnd, ID3D11Device** out_device, ID3D11DeviceContext** out_device_context, IDXGISwapChain** out_swap_chain)
{
if (!is_valid())
{
return false;
}
unsigned int device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
if (debug_)
{
device_flags |= D3D11_CREATE_DEVICE_DEBUG;
}
// Setup swap chain
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 2;
sd.BufferDesc.Width = 0;
sd.BufferDesc.Height = 0;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = in_hwnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D_FEATURE_LEVEL created_feature_level = D3D_FEATURE_LEVEL_1_0_CORE;
HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, device_flags, &chosen_feature_level_, 1, D3D11_SDK_VERSION, &sd, out_swap_chain, out_device, &created_feature_level, out_device_context);
if (hr == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available.
hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, device_flags, &chosen_feature_level_, 1, D3D11_SDK_VERSION, &sd, out_swap_chain, out_device, &created_feature_level, out_device_context);
if (FAILED(hr))
{
spdlog::error("Failed to create D3D11 device.");
}
assert(created_feature_level == chosen_feature_level_);
return SUCCEEDED(hr);
}
void find_best_device_dx11::load_settings()
{
explicit_adapter_value_ = 0;
prefered_adapter_vendor_ = 0;
allow_software_rendering_ = true;
prefered_minimal_power_ = false;
prefered_high_performance_ = true;
debug_ = false;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&dxgi_factory1_);
if (dxgi_factory1_)
{
dxgi_factory1_->QueryInterface(__uuidof(IDXGIFactory6), (void**)&dxgi_factory6_);
}
if (prefered_minimal_power_)
{
gpu_preference_ = DXGI_GPU_PREFERENCE_MINIMUM_POWER;
}
else
{
gpu_preference_ = DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE;
}
}
void find_best_device_dx11::select_adapter()
{
ref_count_ptr<IDXGIAdapter> first_dxgi_adapter_without_integrated_adapter;
ref_count_ptr<IDXGIAdapter> first_dxgi_adapter_adapter;
D3D_FEATURE_LEVEL first_feature_level_without_integrated_adapter = D3D_FEATURE_LEVEL_1_0_CORE;
D3D_FEATURE_LEVEL first_feature_leve_adapter = D3D_FEATURE_LEVEL_1_0_CORE;
spdlog::info("Selecting D3D11 adapter.");
// Enumerate the DXGIFactory's adapters.
ref_count_ptr<IDXGIAdapter> testing_adapter;
for (unsigned int adapter_index = 0; enumerate_adapters(adapter_index, testing_adapter.get_init_reference()) != DXGI_ERROR_NOT_FOUND; ++adapter_index)
{
DXGI_ADAPTER_DESC adapter_desc;
const HRESULT desc_result = testing_adapter->GetDesc(&adapter_desc);
if (FAILED(desc_result))
{
spdlog::warn("Failed to get description for adapter {}.", adapter_index);
}
else
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::string str = conv.to_bytes(adapter_desc.Description);
spdlog::info("Testing D3D11 adapter: {}. Description: '{}'. VendorId: {:04x}. DeviceId: {:04x}.", adapter_index, str.c_str(), adapter_desc.VendorId, adapter_desc.DeviceId);
}
D3D_FEATURE_LEVEL feature_level;
if (!create_testing_device(testing_adapter, feature_level))
{
spdlog::info("Failed to create test device for adapter {}.", adapter_index);
continue;
}
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::string str = conv.to_bytes(adapter_desc.Description);
spdlog::info(" {}. '{}'. Feature level: {}.", adapter_index, str.c_str(), get_feature_level_string(feature_level));
}
const bool is_microsoft = adapter_desc.VendorId == 0x1414;
const bool is_software = is_microsoft;
const bool skip_software_adapter = is_software && !allow_software_rendering_ && explicit_adapter_value_ < 0;
const bool skip_explicit_adapter = explicit_adapter_value_ >= 0 && adapter_index != explicit_adapter_value_;
const bool skip_adapter = skip_software_adapter || skip_explicit_adapter;
if (skip_adapter)
{
spdlog::info(" Skip adapter.");
continue;
}
bool is_non_local_memory_present = false;
{
ref_count_ptr<IDXGIAdapter3> temp_dxgi_adapter3;
DXGI_QUERY_VIDEO_MEMORY_INFO non_local_video_memory_info;
if (SUCCEEDED(testing_adapter->QueryInterface(_uuidof(IDXGIAdapter3), (void**)temp_dxgi_adapter3.get_init_reference())) &&
temp_dxgi_adapter3.is_valid() && SUCCEEDED(temp_dxgi_adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &non_local_video_memory_info)))
{
is_non_local_memory_present = non_local_video_memory_info.Budget != 0;
}
}
const bool is_integrated = !is_non_local_memory_present;
if (!is_integrated && !first_dxgi_adapter_without_integrated_adapter.is_valid())
{
first_dxgi_adapter_without_integrated_adapter = testing_adapter;
first_feature_level_without_integrated_adapter = feature_level;
}
else if (prefered_adapter_vendor_ == adapter_desc.VendorId && first_dxgi_adapter_without_integrated_adapter.is_valid())
{
first_dxgi_adapter_without_integrated_adapter = testing_adapter;
first_feature_level_without_integrated_adapter = feature_level;
}
if (!first_dxgi_adapter_adapter.is_valid())
{
first_dxgi_adapter_adapter = testing_adapter;
first_feature_leve_adapter = feature_level;
}
else if (prefered_adapter_vendor_ == adapter_desc.VendorId && first_dxgi_adapter_adapter.is_valid())
{
first_dxgi_adapter_adapter = testing_adapter;
first_feature_leve_adapter = feature_level;
}
}
const bool bFavorNonIntegrated = explicit_adapter_value_ == -1;
if (bFavorNonIntegrated)
{
chosen_adapter_ = first_dxgi_adapter_without_integrated_adapter;
chosen_feature_level_ = first_feature_level_without_integrated_adapter;
// We assume Intel is integrated graphics (slower than discrete) than NVIDIA or AMD cards and rather take a different one
if (!chosen_adapter_.is_valid())
{
chosen_adapter_ = first_dxgi_adapter_adapter;
chosen_feature_level_ = first_feature_leve_adapter;
}
}
else
{
chosen_adapter_ = first_dxgi_adapter_adapter;
chosen_feature_level_ = first_feature_leve_adapter;
}
if (chosen_adapter_.is_valid())
{
DXGI_ADAPTER_DESC adapter_desc;
const HRESULT desc_result = chosen_adapter_->GetDesc(&adapter_desc);
if (FAILED(desc_result))
{
spdlog::warn("Failed to get description for selected adapter.");
}
else
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
std::string str = conv.to_bytes(adapter_desc.Description);
spdlog::info("Selected D3D11 adapter: {}. VendorId: {:04x}. DeviceId: {:04x}.", str.c_str(), adapter_desc.VendorId, adapter_desc.DeviceId);
}
}
}
HRESULT find_best_device_dx11::enumerate_adapters(UINT adapter_index, IDXGIAdapter** out_adapter)
{
if (!dxgi_factory6_ || gpu_preference_ == DXGI_GPU_PREFERENCE_UNSPECIFIED)
{
return dxgi_factory1_->EnumAdapters(adapter_index, out_adapter);
}
else
{
return dxgi_factory6_->EnumAdapterByGpuPreference(adapter_index, (DXGI_GPU_PREFERENCE)gpu_preference_, __uuidof(IDXGIAdapter), (void**)out_adapter);
}
}
bool find_best_device_dx11::create_testing_device(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL& out_feature_level)
{
ID3D11Device* D3DDevice = nullptr;
ID3D11DeviceContext* D3DDeviceContext = nullptr;
unsigned int DeviceFlags = D3D11_CREATE_DEVICE_SINGLETHREADED;
if (debug_)
{
DeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
}
constexpr D3D_FEATURE_LEVEL requested_feature_levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 };
out_feature_level = D3D_FEATURE_LEVEL_1_0_CORE;
__try
{
constexpr int NumAllowedFeatureLevels = 2;
HRESULT create_device_result = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, DeviceFlags,
requested_feature_levels, NumAllowedFeatureLevels, D3D11_SDK_VERSION,
&D3DDevice, &out_feature_level, &D3DDeviceContext);
if (SUCCEEDED(create_device_result))
{
D3DDevice->Release();
D3DDeviceContext->Release();
return true;
}
else
{
assert(false);
}
}
__except (is_delay_load_exception(GetExceptionInformation()))
{
// We suppress warning C6322: Empty _except block. Appropriate checks are made upon returning.
}
return false;
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <d3d11.h>
#include "misc/ref_counting.h"
#include <dxgi1_6.h>
struct IDXGIAdapter;
struct IDXGIFactory1;
struct IDXGIFactory6;
class find_best_device_dx11
{
public:
find_best_device_dx11();
~find_best_device_dx11();
bool is_valid() const;
bool create_device(HWND in_hwnd, ID3D11Device** out_device, ID3D11DeviceContext** out_device_context, IDXGISwapChain** out_swap_chain);
private:
void load_settings();
void select_adapter();
HRESULT enumerate_adapters(UINT adapter_index, IDXGIAdapter** out_adapter);
bool create_testing_device(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL& out_feature_level);
private:
ref_count_ptr<IDXGIAdapter> chosen_adapter_;
ref_count_ptr<IDXGIFactory1> dxgi_factory1_;
ref_count_ptr<IDXGIFactory6> dxgi_factory6_;
D3D_FEATURE_LEVEL chosen_feature_level_;
int gpu_preference_;
int explicit_adapter_value_;
unsigned int prefered_adapter_vendor_;
bool allow_software_rendering_;
bool prefered_minimal_power_;
bool prefered_high_performance_;
bool debug_;
};

View File

@ -0,0 +1,177 @@
#include "render_target_dx11.h"
#include <assert.h>
#include "renderer_dx11.h"
#include "rhi/windows/dx_format.h"
render_target_dx11::render_target_dx11() : lock_state_(lock_state::NONE)
{
}
render_target_dx11::~render_target_dx11()
{
}
void render_target_dx11::init(int width, int height, texture_format format)
{
D3D11_TEXTURE2D_DESC texture_desc;
texture_desc.Width = width;
texture_desc.Height = height;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = ToDXFormat(format);
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0;
HRESULT hr = g_d3d11_device->CreateTexture2D(&texture_desc, nullptr, texture_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
rtv_desc.Format = texture_desc.Format;
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv_desc.Texture2D.MipSlice = 0;
hr = g_d3d11_device->CreateRenderTargetView(texture_, &rtv_desc, render_target_view_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
srv_desc.Format = texture_desc.Format;
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = -1;
srv_desc.Texture2D.MostDetailedMip = 0;
hr = g_d3d11_device->CreateShaderResourceView(texture_, &srv_desc, shader_resource_view_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
}
void* render_target_dx11::lock(lock_state state)
{
D3D11_TEXTURE2D_DESC texture_desc;
texture_->GetDesc(&texture_desc);
texture_desc.BindFlags = 0;
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
texture_desc.Usage = D3D11_USAGE_STAGING;
HRESULT hr = g_d3d11_device->CreateTexture2D(&texture_desc, nullptr, lock_texture_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return nullptr;
}
D3D11_MAP map_type;
lock_state_ = state;
switch (state)
{
case lock_state::NONE:
map_type = D3D11_MAP_READ_WRITE;
break;
case lock_state::READ:
map_type = D3D11_MAP_READ;
g_d3d11_device_context->CopyResource(lock_texture_, texture_);
break;
case lock_state::WRITE:
map_type = D3D11_MAP_WRITE;
break;
case lock_state::READ_WRITE:
map_type = D3D11_MAP_READ_WRITE;
break;
default:
assert(false);
return nullptr;
}
D3D11_MAPPED_SUBRESOURCE mapped_resource;
hr = g_d3d11_device_context->Map(lock_texture_, 0, map_type, 0, &mapped_resource);
if (FAILED(hr))
{
assert(false);
return nullptr;
}
return mapped_resource.pData;
}
void render_target_dx11::unlock()
{
switch (lock_state_)
{
case lock_state::READ:
break;
case lock_state::NONE:
case lock_state::WRITE:
case lock_state::READ_WRITE:
{
g_d3d11_device_context->Unmap(lock_texture_, 0);
g_d3d11_device_context->CopyResource(texture_, lock_texture_);
}
default:
break;
}
lock_state_ = lock_state::NONE;
lock_texture_.safe_release();
}
void render_target_dx11::release()
{
assert(!lock_texture_);
texture_.safe_release();
render_target_view_.safe_release();
shader_resource_view_.safe_release();
}
void render_target_dx11::on_resize(int width, int height)
{
D3D11_TEXTURE2D_DESC texture_desc;
texture_->GetDesc(&texture_desc);
texture_desc.Width = width;
texture_desc.Height = height;
release();
HRESULT hr = g_d3d11_device->CreateTexture2D(&texture_desc, nullptr, texture_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
rtv_desc.Format = texture_desc.Format;
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv_desc.Texture2D.MipSlice = 0;
hr = g_d3d11_device->CreateRenderTargetView(texture_, &rtv_desc, render_target_view_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
srv_desc.Format = texture_desc.Format;
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = -1;
srv_desc.Texture2D.MostDetailedMip = 0;
hr = g_d3d11_device->CreateShaderResourceView(texture_, &srv_desc, shader_resource_view_.get_init_reference());
if (FAILED(hr))
{
assert(false);
return;
}
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "rhi/render_target.h"
#include <d3d11.h>
#include "misc/ref_counting.h"
class render_target_dx11 : public render_target
{
public:
render_target_dx11();
~render_target_dx11() override;
void init(int width, int height, texture_format format) override;
ImTextureID get_texture_id() override { return shader_resource_view_; }
void* lock(lock_state state) override;
void unlock() override;
void release();
protected:
void on_resize(int width, int height) override;
private:
ref_count_ptr<ID3D11Texture2D> lock_texture_;
ref_count_ptr<ID3D11Texture2D> texture_;
ref_count_ptr<ID3D11RenderTargetView> render_target_view_;
ref_count_ptr<ID3D11ShaderResourceView> shader_resource_view_;
lock_state lock_state_;
};

View File

@ -0,0 +1,128 @@
#include "renderer_dx11.h"
#include <cassert>
#include "find_best_device_dx11.h"
#include "imgui.h"
#include "imgui_impl_dx11.h"
#include "imgui_impl_sdl3.h"
#include "render_target_dx11.h"
#include "texture_dx11.h"
#include "CompilerHlsl/compileHlsl.hpp"
#include "ShaderWriter/VertexWriter.hpp"
ref_count_ptr<ID3D11Device> g_d3d11_device;
ref_count_ptr<ID3D11DeviceContext> g_d3d11_device_context;
ref_count_ptr<IDXGISwapChain> g_d3d11_swap_chain;
ref_count_ptr<ID3D11RenderTargetView> g_main_render_target_view;
renderer_dx11::renderer_dx11()
{
}
bool renderer_dx11::init(SDL_Window* window_handle)
{
if (has_initialized_)
return true;
const HWND hwnd = static_cast<HWND>(SDL_GetProperty(SDL_GetWindowProperties(window_handle), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
if (!create_device(hwnd))
return false;
ImGui_ImplSDL3_InitForD3D(window_handle);
ImGui_ImplDX11_Init(g_d3d11_device, g_d3d11_device_context);
create_render_target();
has_initialized_ = true;
return true;
}
void renderer_dx11::shutdown()
{
// Cleanup
ImGui_ImplDX11_Shutdown();
ImGui_ImplSDL3_Shutdown();
g_d3d11_device.safe_release();
g_d3d11_device_context.safe_release();
g_d3d11_swap_chain.safe_release();
}
void renderer_dx11::new_frame()
{
// Start the Dear ImGui frame
ImGui_ImplDX11_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
}
void renderer_dx11::end_frame()
{
constexpr ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
constexpr float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w };
ImGui::Render();
ID3D11RenderTargetView* target_view = g_main_render_target_view.get_reference();
g_d3d11_device_context->OMSetRenderTargets(1, &target_view, nullptr);
g_d3d11_device_context->ClearRenderTargetView(g_main_render_target_view, clear_color_with_alpha);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
(void)g_d3d11_swap_chain->Present(vsync_, 0); // Present with vsync
}
void renderer_dx11::resize(int width, int height)
{
g_main_render_target_view.safe_release();
(void)g_d3d11_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
create_render_target();
}
texture* renderer_dx11::create_texture(const unsigned char* data, const int width, const int height)
{
auto out = new texture_dx11();
if (!out->init_data(data, width, height))
{
delete out;
out = nullptr;
}
return out;
}
render_target* renderer_dx11::create_render_target(int width, int height, texture_format format)
{
const auto target_dx11 = new render_target_dx11();
target_dx11->init(width, height, format);
return target_dx11;
}
bool renderer_dx11::compile_shader()
{
return true;
}
void renderer_dx11::create_render_target()
{
ref_count_ptr<ID3D11Texture2D> p_back_buffer;
(void)g_d3d11_swap_chain->GetBuffer(0, IID_PPV_ARGS(p_back_buffer.get_init_reference()));
(void)g_d3d11_device->CreateRenderTargetView(p_back_buffer, nullptr, g_main_render_target_view.get_init_reference());
p_back_buffer.safe_release();
}
bool renderer_dx11::create_device(HWND in_hwnd)
{
bool result = true;
if(!g_d3d11_device.is_valid() || !g_d3d11_device_context.is_valid())
{
find_best_device_dx11 best_device_finder = find_best_device_dx11();
if (best_device_finder.is_valid())
{
result = best_device_finder.create_device(in_hwnd, g_d3d11_device.get_init_reference(), g_d3d11_device_context.get_init_reference(), g_d3d11_swap_chain.get_init_reference());
}
}
assert(result);
return result;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <d3d11.h>
#include "misc/ref_counting.h"
#include "rhi/renderer.h"
extern ref_count_ptr<ID3D11Device> g_d3d11_device;
extern ref_count_ptr<ID3D11DeviceContext> g_d3d11_device_context;
extern ref_count_ptr<IDXGISwapChain> g_d3d11_swap_chain;
extern ref_count_ptr<ID3D11RenderTargetView> g_main_render_target_view;
class renderer_dx11 : public renderer
{
public:
renderer_dx11();
bool init(SDL_Window* window_handle) override;
void shutdown() override;
void new_frame() override;
void end_frame() override;
void resize(int width, int height) override;
texture* create_texture(const unsigned char* data, int width, int height) override;
render_target* create_render_target(int width, int height, texture_format format) override;
bool compile_shader() override;
protected:
void create_render_target();
bool create_device(HWND in_hwnd);
bool has_initialized_ = false;
};

View File

@ -0,0 +1,49 @@
#include "texture_dx11.h"
#include "renderer_dx11.h"
bool texture_dx11::init_data(const unsigned char* data, int width, int height)
{
width_ = width;
height_ = height;
// Create texture
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
ref_count_ptr<ID3D11Texture2D> temp_texture;
D3D11_SUBRESOURCE_DATA sub_resource;
sub_resource.pSysMem = data;
sub_resource.SysMemPitch = desc.Width * 4;
sub_resource.SysMemSlicePitch = 0;
auto hr = g_d3d11_device->CreateTexture2D(&desc, &sub_resource, temp_texture.get_init_reference());
if (FAILED(hr))
{
spdlog::error("Failed to create texture");
return false;
}
// Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
ZeroMemory(&srv_desc, sizeof(srv_desc));
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = desc.MipLevels;
srv_desc.Texture2D.MostDetailedMip = 0;
hr = g_d3d11_device->CreateShaderResourceView(temp_texture, &srv_desc, shader_resource_view_.get_init_reference());
if (FAILED(hr))
{
spdlog::error("Failed to create texture view");
return false;
}
return true;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <d3d11.h>
#include "misc/ref_counting.h"
#include "rhi/texture.h"
class texture_dx11 : public texture
{
public:
ImTextureID get_texture_id() override { return shader_resource_view_; }
bool init_data(const unsigned char* data, int width, int height) override;
[[nodiscard]] bool is_valid() const override { return shader_resource_view_.is_valid(); }
private:
ref_count_ptr<ID3D11ShaderResourceView> shader_resource_view_;
};

View File

@ -0,0 +1,18 @@
#pragma once
#include <dxgiformat.h>
#include "rhi/rhi_defintion.h"
DXGI_FORMAT ToDXFormat(texture_format format)
{
switch (format)
{
case texture_format::RGBA8:
return DXGI_FORMAT_R8G8B8A8_UNORM;
case texture_format::RGBA16_FLOAT:
return DXGI_FORMAT_R16G16B16A16_FLOAT;
case texture_format::RGBA32_FLOAT:
return DXGI_FORMAT_R32G32B32A32_FLOAT;
}
return DXGI_FORMAT_UNKNOWN;
}

1
third_party/HLSLcc vendored Submodule

@ -0,0 +1 @@
Subproject commit 3ea1fcd6bd0ac445bc078de0bf32f0950188577b

55
third_party/imgui/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,55 @@
project(imgui)
set(CMAKE_CXX_STANDARD 23)
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
add_library(${PROJECT_NAME} STATIC
imgui/imgui.cpp
imgui/imgui.h
imgui/imgui_draw.cpp
imgui/imgui_internal.h
imgui/imconfig.h
imgui/imgui_widgets.cpp
imgui/imstb_rectpack.h
imgui/imstb_textedit.h
imgui/imstb_truetype.h
imgui/imgui_tables.cpp
)
if (WIN32)
target_sources(${PROJECT_NAME} PRIVATE
imgui/backends/imgui_impl_sdl3.cpp
imgui/backends/imgui_impl_sdl3.h
imgui/backends/imgui_impl_vulkan.cpp
imgui/backends/imgui_impl_vulkan.h
imgui/backends/imgui_impl_dx11.h
imgui/backends/imgui_impl_dx11.cpp
imgui/backends/imgui_impl_dx12.h
imgui/backends/imgui_impl_dx12.cpp
imgui/backends/imgui_impl_win32.h
imgui/backends/imgui_impl_win32.cpp
)
target_link_libraries(${PROJECT_NAME} PUBLIC opengl32.lib SDL3-shared d3d11 d3dcompiler dxgi d3d12)
elseif(UNIX AND NOT APPLE)
target_sources(${PROJECT_NAME} PRIVATE
imgui/backends/imgui_impl_sdl3.cpp
imgui/backends/imgui_impl_sdl3.h
imgui/backends/imgui_impl_vulkan.cpp
imgui/backends/imgui_impl_vulkan.h
)
target_link_libraries(${PROJECT_NAME} PUBLIC vulkan SDL3-shared)
elseif(APPLE)
target_sources(${PROJECT_NAME} PRIVATE
imgui/backends/imgui_impl_sdl3.cpp
imgui/backends/imgui_impl_sdl3.h
imgui/backends/imgui_impl_metal.h
imgui/backends/imgui_impl_metal.mm
)
target_link_libraries(${PROJECT_NAME} PUBLIC vulkan SDL3-shared)
endif()
include_directories(SDL3-shared)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends)

1
third_party/imgui/imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit 96839b445e32e46d87a44fd43a9cdd60c806f7e1

1
third_party/portaudio vendored Submodule

@ -0,0 +1 @@
Subproject commit daaf637f6f9fce670031221abfd7dfde92e5cce3

1
third_party/sdl vendored Submodule

@ -0,0 +1 @@
Subproject commit 7fbd85ad5cf30d46ef20628a212bbec3c1ffec2b

1
third_party/spdlog vendored Submodule

@ -0,0 +1 @@
Subproject commit 696db97f672e9082e50e50af315d0f4234c82397