Some initial implementation.

This commit is contained in:
Patrick 2024-09-11 09:02:25 +02:00
parent a8813349a1
commit 31af297bab
7 changed files with 332 additions and 4 deletions

@ -1 +1 @@
Subproject commit bdf063a16c6bafd137f57eee780c83345887c46c Subproject commit 941f94a7b6ad9242ee1404663dfd855dcf203817

View File

@ -11,8 +11,11 @@ prog_app = env.UnityProgram(
dependencies = { dependencies = {
'mijin': {}, 'mijin': {},
'SDL': { 'SDL': {
'options': {
'ref': '76ce83801ade3ac922ad5ba6fddc49764c24206a'
} }
},
'spdlog': {}
} }
) )
env.Default(prog_app) env.Default(prog_app)

View File

@ -1,5 +1,49 @@
#include <mijin/util/scope_guard.hpp>
#include <mijin/util/variant.hpp>
#include <spdlog/spdlog.h>
#include <SDL3/SDL.h>
#include "./sdlpp/event.hpp"
#include "./sdlpp/gpu.hpp"
#include "./sdlpp/window.hpp"
int main(int, char**) int main(int, char**)
{ {
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<sdlpp::sdl_event_t> event;
while ((event = sdlpp::pollEvent()).has_value())
{
std::visit(mijin::Visitor{
[&](const sdlpp::QuitEvent&) { running = false; },
[](const auto&) {} // default handler
}, *event);
}
}
return 0; return 0;
} }

View File

@ -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 <stdexcept>
#include <utility>
#include <mijin/debug/assert.hpp>
#include <mijin/util/bitflags.hpp>
#include <SDL3/SDL.h>
namespace sdlpp
{
template<typename THandle, typename TConcrete>
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<TConcrete&>(*this).destroy();
mHandle = std::exchange(other.mHandle, nullptr);
}
return *this;
}
public:
Base(const Base&) = delete;
~Base() noexcept
{
static_cast<TConcrete&>(*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)

View File

@ -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 <optional>
#include <variant>
namespace sdlpp
{
struct Event
{
Uint64 timestamp;
template<typename TBase>
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<sdl_event_t> 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)

View File

@ -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 <SDL3/SDL_gpu.h>
#include "./common.hpp"
namespace sdlpp
{
struct GpuShaderFormat : mijin::BitFlags<GpuShaderFormat>
{
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<std::uint8_t>(*this);
}
};
struct GPUDeviceCreateArgs
{
GpuShaderFormat formatFlags = {};
bool debugMode = false;
const char* name = nullptr;
};
class GPUDevice : public Base<SDL_GPUDevice, GPUDevice>
{
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)

View File

@ -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<WindowFlags>
{
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<std::uint32_t>(*this);
}
};
struct WindowCreateArgs
{
const char* title = "Window";
int width = 1280;
int height = 720;
WindowFlags flags = {};
};
class Window : public Base<SDL_Window, Window>
{
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)