diff --git a/external/scons-plus-plus b/external/scons-plus-plus index bdf063a..941f94a 160000 --- a/external/scons-plus-plus +++ b/external/scons-plus-plus @@ -1 +1 @@ -Subproject commit bdf063a16c6bafd137f57eee780c83345887c46c +Subproject commit 941f94a7b6ad9242ee1404663dfd855dcf203817 diff --git a/private/sdl_gpu_test/SModule b/private/sdl_gpu_test/SModule index d88fc8d..003958c 100644 --- a/private/sdl_gpu_test/SModule +++ b/private/sdl_gpu_test/SModule @@ -11,8 +11,11 @@ prog_app = env.UnityProgram( dependencies = { 'mijin': {}, 'SDL': { - - } + 'options': { + 'ref': '76ce83801ade3ac922ad5ba6fddc49764c24206a' + } + }, + 'spdlog': {} } ) env.Default(prog_app) diff --git a/private/sdl_gpu_test/main.cpp b/private/sdl_gpu_test/main.cpp index e9ad257..50f65b9 100644 --- a/private/sdl_gpu_test/main.cpp +++ b/private/sdl_gpu_test/main.cpp @@ -1,5 +1,49 @@ +#include +#include +#include +#include + +#include "./sdlpp/event.hpp" +#include "./sdlpp/gpu.hpp" +#include "./sdlpp/window.hpp" + int main(int, char**) { - return 0; + if (SDL_Init(0) != SDL_TRUE) + { + spdlog::error("Error initializing SDL."); + return 1; + } + MIJIN_SCOPE_EXIT { + SDL_Quit(); + }; + + sdlpp::Window window; + window.create({ + .flags = {.vulkan = true} + }); + + sdlpp::GPUDevice gpuDevice; + gpuDevice.create({.formatFlags{.spirv = true}}); + + gpuDevice.claimWindow(window); + + const SDL_GPUTextureFormat texForm = SDL_GetGPUSwapchainTextureFormat(gpuDevice, window); + (void) texForm; + + bool running = true; + while(running) + { + std::optional event; + while ((event = sdlpp::pollEvent()).has_value()) + { + std::visit(mijin::Visitor{ + [&](const sdlpp::QuitEvent&) { running = false; }, + [](const auto&) {} // default handler + }, *event); + } + } + + return 0; } diff --git a/private/sdl_gpu_test/sdlpp/common.hpp b/private/sdl_gpu_test/sdlpp/common.hpp new file mode 100644 index 0000000..511156f --- /dev/null +++ b/private/sdl_gpu_test/sdlpp/common.hpp @@ -0,0 +1,54 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_COMMON_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_COMMON_HPP_INCLUDED 1 + +#include +#include + +#include +#include +#include + +namespace sdlpp +{ +template +class Base +{ +protected: + THandle* mHandle = nullptr; +protected: + Base() noexcept = default; + explicit Base(THandle* handle) noexcept : mHandle(handle) {} + Base(Base&& other) noexcept : mHandle(std::exchange(other.mHandle, nullptr)) {} + + Base& operator=(Base&& other) noexcept + { + if (this != &other) + { + static_cast(*this).destroy(); + mHandle = std::exchange(other.mHandle, nullptr); + } + return *this; + } +public: + Base(const Base&) = delete; + ~Base() noexcept + { + static_cast(*this).destroy(); + } + Base& operator=(const Base&) = delete; + auto operator<=>(const Base& other) const noexcept = default; + + operator THandle*() const noexcept { return mHandle; } +}; + +class SDLError : std::runtime_error +{ +public: + SDLError() : std::runtime_error(SDL_GetError()) {} +}; +} // namespace sdlpp + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_COMMON_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/sdlpp/event.hpp b/private/sdl_gpu_test/sdlpp/event.hpp new file mode 100644 index 0000000..78cc0d1 --- /dev/null +++ b/private/sdl_gpu_test/sdlpp/event.hpp @@ -0,0 +1,52 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_EVENT_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_EVENT_HPP_INCLUDED 1 + +#include +#include + +namespace sdlpp +{ +struct Event +{ + Uint64 timestamp; + + template + explicit Event(const TBase& base) noexcept : timestamp(base.timestamp) {} +}; +struct QuitEvent : Event +{ + explicit QuitEvent(const SDL_QuitEvent& base) noexcept : Event(base) {} +}; +struct WindowEvent : Event +{ + +}; + +using sdl_event_t = std::variant< + WindowEvent, + QuitEvent +>; + +[[nodiscard]] +std::optional pollEvent() noexcept +{ + SDL_Event event; + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_EVENT_QUIT: + return QuitEvent(event.quit); + default: + // can't translate this yet + break; + } + } + return std::nullopt; +} +} // namespace sdlpp + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_EVENT_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/sdlpp/gpu.hpp b/private/sdl_gpu_test/sdlpp/gpu.hpp new file mode 100644 index 0000000..65f746a --- /dev/null +++ b/private/sdl_gpu_test/sdlpp/gpu.hpp @@ -0,0 +1,79 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED 1 + +#include + +#include "./common.hpp" + +namespace sdlpp +{ +struct GpuShaderFormat : mijin::BitFlags +{ + bool private_ : 1 = false; + bool spirv : 1 = false; + bool dxbc : 1 = false; + bool dxil : 1 = false; + bool msl : 1 = false; + bool metallib : 1 = false; + + constexpr operator SDL_GPUShaderFormat() const noexcept + { + return std::bit_cast(*this); + } +}; + +struct GPUDeviceCreateArgs +{ + GpuShaderFormat formatFlags = {}; + bool debugMode = false; + const char* name = nullptr; +}; + +class GPUDevice : public Base +{ +public: + GPUDevice() noexcept = default; + GPUDevice(const GPUDevice&) = delete; + GPUDevice(GPUDevice&& other) noexcept : Base(std::move(other)) {} + + GPUDevice& operator=(const GPUDevice&) = delete; + GPUDevice& operator=(GPUDevice&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const GPUDevice& other) const noexcept = default; + + void create(const GPUDeviceCreateArgs& args = {}) + { + MIJIN_ASSERT(mHandle == nullptr, "GPUDevice has already been created."); + mHandle = SDL_CreateGPUDevice(args.formatFlags, args.debugMode, args.name); + if (mHandle == nullptr) + { + throw SDLError(); + } + } + + void destroy() noexcept + { + if (mHandle != nullptr) + { + SDL_DestroyGPUDevice(mHandle); + mHandle = nullptr; + } + } + + void claimWindow(SDL_Window* window) const + { + if (!SDL_ClaimWindowForGPUDevice(*this, window)) + { + throw SDLError(); + } + } +}; +} // namespace sdlpp + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/sdlpp/window.hpp b/private/sdl_gpu_test/sdlpp/window.hpp new file mode 100644 index 0000000..00d3b81 --- /dev/null +++ b/private/sdl_gpu_test/sdlpp/window.hpp @@ -0,0 +1,96 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_WINDOW_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_WINDOW_HPP_INCLUDED 1 + +#include "./common.hpp" + +namespace sdlpp +{ +struct WindowFlags : mijin::BitFlags +{ + bool fullscreen : 1; // 0x0000000000000001 /**< window is in fullscreen mode */ + bool opengl : 1; // 0x0000000000000002 /**< window usable with OpenGL context */ + bool occluded : 1; // 0x0000000000000004 /**< window is occluded */ + bool hidden : 1; // 0x0000000000000008) /**< window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow( is required for it to become visible */ + bool borderless : 1; // 0x0000000000000010 /**< no window decoration */ + bool resizable : 1; // 0x0000000000000020 /**< window can be resized */ + bool minimized : 1; // 0x0000000000000040 /**< window is minimized */ + bool maximized : 1; // 0x0000000000000080 /**< window is maximized */ + bool mouse_grabbed : 1; // 0x0000000000000100 /**< window has grabbed mouse input */ + bool input_focus : 1; // 0x0000000000000200 /**< window has input focus */ + bool mouse_focus : 1; // 0x0000000000000400 /**< window has mouse focus */ + bool external : 1; // 0x0000000000000800 /**< window not created by SDL */ + bool modal : 1; // 0x0000000000001000 /**< window is modal */ + bool high_pixel_density : 1; // 0x0000000000002000 /**< window uses high pixel density back buffer if possible */ + bool mouse_capture : 1; // 0x0000000000004000) /**< window has mouse captured (unrelated to MOUSE_GRABBED */ + bool mouse_relative_mode : 1; // 0x0000000000008000 /**< window has relative mode enabled */ + bool always_on_top : 1; // 0x0000000000010000 /**< window should always be above others */ + bool utility : 1; // 0x0000000000020000 /**< window should be treated as a utility window, not showing in the task bar and window list */ + bool tooltip : 1; // 0x0000000000040000 /**< window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window */ + bool popup_menu : 1; // 0x0000000000080000 /**< window should be treated as a popup menu, requires a parent window */ + bool keyboard_grabbed : 1; // 0x0000000000100000 /**< window has grabbed keyboard input */ + bool unused0 : 1; // 0x0000000000200000 + bool unused1 : 1; // 0x0000000000400000 + bool unused2 : 1; // 0x0000000000800000 + bool unused3 : 1; // 0x0000000001000000 + bool unused4 : 1; // 0x0000000002000000 + bool unused5 : 1; // 0x0000000004000000 + bool unused6 : 1; // 0x0000000008000000 + bool vulkan : 1; // 0x0000000010000000 /**< window usable for Vulkan surface */ + bool metal : 1; // 0x0000000020000000 /**< window usable for Metal view */ + bool transparent : 1; // 0x0000000040000000 /**< window with transparent buffer */ + bool notFocusable : 1; // 0x0000000080000000 /**< window should not be focusable */ + + constexpr operator SDL_WindowFlags () const noexcept + { + return std::bit_cast(*this); + } +}; + +struct WindowCreateArgs +{ + const char* title = "Window"; + int width = 1280; + int height = 720; + WindowFlags flags = {}; +}; + +class Window : public Base +{ +public: + Window() noexcept = default; + Window(const Window&) = delete; + Window(Window&& other) noexcept : Base(std::move(other)) {} + + Window& operator=(const Window&) = delete; + Window& operator=(Window&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const Window& other) const noexcept = default; + + void create(const WindowCreateArgs& args = {}) + { + MIJIN_ASSERT(mHandle == nullptr, "Window has already been created."); + mHandle = SDL_CreateWindow(args.title, args.width, args.height, args.flags); + if (mHandle == nullptr) + { + throw SDLError(); + } + } + + void destroy() noexcept + { + if (mHandle != nullptr) + { + SDL_DestroyWindow(mHandle); + mHandle = nullptr; + } + } +}; +} // namespace sdlpp + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_WINDOW_HPP_INCLUDED)