From 4768f0a6a0e4957f13bfe9ed79291053e334948b Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Sat, 14 Sep 2024 01:00:51 +0200 Subject: [PATCH] Moved everything into an application so we can easily have multiple apps and switch between them. --- .../0_triangle_with_texcoords/app.cpp | 115 ++++++++++ .../0_triangle_with_texcoords/app.hpp | 22 ++ private/sdl_gpu_test/SModule | 7 +- private/sdl_gpu_test/application.cpp | 74 ++++++ private/sdl_gpu_test/application.hpp | 72 ++++++ private/sdl_gpu_test/main.cpp | 213 ++---------------- private/sdl_gpu_test/sdlpp/common.hpp | 1 + private/sdl_gpu_test/sdlpp/event.hpp | 2 +- 8 files changed, 306 insertions(+), 200 deletions(-) create mode 100644 private/sdl_gpu_test/0_triangle_with_texcoords/app.cpp create mode 100644 private/sdl_gpu_test/0_triangle_with_texcoords/app.hpp create mode 100644 private/sdl_gpu_test/application.cpp create mode 100644 private/sdl_gpu_test/application.hpp diff --git a/private/sdl_gpu_test/0_triangle_with_texcoords/app.cpp b/private/sdl_gpu_test/0_triangle_with_texcoords/app.cpp new file mode 100644 index 0000000..96b8033 --- /dev/null +++ b/private/sdl_gpu_test/0_triangle_with_texcoords/app.cpp @@ -0,0 +1,115 @@ + +#include "./app.hpp" + +#include +#include + +namespace sdl_gpu_test +{ +struct Vertex +{ + glm::vec2 pos; + glm::vec2 texCoord; +}; + +void TriangleWithTexcoordsApp::init(std::span args) +{ + Application::init(args); + + // create vertex shader + mijin::TypelessBuffer vertexSpv = getFileContentsBinary("shaders/glsl/textured_triangles_from_buffer.vert.spv"); + sdlpp::GPUShader vertexShader; + vertexShader.create(mDevice, { + .code = {static_cast(vertexSpv.data()), vertexSpv.byteSize()}, + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::VERTEX + }); + + // create fragment shader + mijin::TypelessBuffer fragmentSpv = getFileContentsBinary("shaders/glsl/color_from_texcoord.frag.spv"); + sdlpp::GPUShader fragmentShader; + fragmentShader.create(mDevice, { + .code = {static_cast(fragmentSpv.data()), fragmentSpv.byteSize()}, + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::FRAGMENT, + .numUniformBuffers = 1 + }); + + // create graphics pipeline + std::array colorTargetsDescs = { + sdlpp::GPUColorTargetDescription{ + .format = mDevice.getSwapchainTextureFormat(mWindow) + } + }; + std::array vertexBindings = { + sdlpp::GPUVertexBinding{ + .index = 0, + .pitch = sizeof(Vertex) + } + }; + std::array vertexAttributes = { + sdlpp::GPUVertexAttribute{ + .location = 0, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT2, + .offset = offsetof(Vertex, pos) + }, + sdlpp::GPUVertexAttribute{ + .location = 1, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT2, + .offset = offsetof(Vertex, texCoord) + } + }; + mPipeline.create(mDevice, { + .vertexShader = vertexShader, + .fragmentShader = fragmentShader, + .vertexInputState = { + .vertexBindings = vertexBindings, + .vertexAttributes = vertexAttributes + }, + .targetInfo = { + .colorTargetDescriptions = colorTargetsDescs + } + }); + + std::array vertices = + { + Vertex{.pos = {-1.f, -1.f}, .texCoord = {0.f, 0.f}}, + Vertex{.pos = { 1.f, -1.f}, .texCoord = {1.f, 0.f}}, + Vertex{.pos = { 0.f, 1.f}, .texCoord = {0.5f, 1.f}} + }; + + // create vertex buffer + mVertexBuffer.create(mDevice, { + .usage = {.vertex = true}, + .size = sizeof(vertices) + }); + uploadVertexData(mVertexBuffer, std::span(vertices.begin(), vertices.end())); +} + +void TriangleWithTexcoordsApp::update() +{ + Application::update(); + + sdlpp::GPUCommandBuffer cmdBuffer = mDevice.acquireCommandBuffer(); + Uint32 swapchainWidth = 0, swapchainHeight = 0; + sdlpp::GPUTexture swapchainTexture = cmdBuffer.acquireSwapchainTexture(mWindow, swapchainWidth, swapchainHeight); + std::array colorTargets = {sdlpp::GPUColorTargetInfo{ + .texture = swapchainTexture, + .clearColor = {.r = 1.f, .g = 0.f, .b = 0.f, .a = 1.f}, + .loadOp = sdlpp::GPULoadOp::CLEAR, + }}; + sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({ + .colorTargetInfos = colorTargets + }); + static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f); + cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1)); + renderPass.bindGraphicsPipeline(mPipeline); + renderPass.bindVertexBuffer({.buffer = mVertexBuffer}); + renderPass.drawPrimitives({.numVertices = 3}); + + renderPass.end(); + cmdBuffer.submit(); +} +} diff --git a/private/sdl_gpu_test/0_triangle_with_texcoords/app.hpp b/private/sdl_gpu_test/0_triangle_with_texcoords/app.hpp new file mode 100644 index 0000000..e3eccf8 --- /dev/null +++ b/private/sdl_gpu_test/0_triangle_with_texcoords/app.hpp @@ -0,0 +1,22 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_0_TRIANGLE_WITH_TEXCOORDS_APP_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_0_TRIANGLE_WITH_TEXCOORDS_APP_HPP_INCLUDED 1 + +#include "../application.hpp" + +namespace sdl_gpu_test +{ +class TriangleWithTexcoordsApp : public Application +{ +private: + sdlpp::GPUBuffer mVertexBuffer; + sdlpp::GPUGraphicsPipeline mPipeline; +public: + void init(std::span args) override; + void update() override; +}; +} // namespace sdl_gpu_test + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_0_TRIANGLE_WITH_TEXCOORDS_APP_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/SModule b/private/sdl_gpu_test/SModule index 8cf9933..c4719ce 100644 --- a/private/sdl_gpu_test/SModule +++ b/private/sdl_gpu_test/SModule @@ -3,6 +3,10 @@ Import('env') src_files = Split(""" main.cpp + + application.cpp + + 0_triangle_with_texcoords/app.cpp """) shader_files = Split(""" @@ -26,7 +30,8 @@ prog_app = env.UnityProgram( 'ref': '76ce83801ade3ac922ad5ba6fddc49764c24206a' } }, - 'spdlog': {} + 'spdlog': {}, + 'stb': {} } ) env.Default(prog_app) diff --git a/private/sdl_gpu_test/application.cpp b/private/sdl_gpu_test/application.cpp new file mode 100644 index 0000000..a515045 --- /dev/null +++ b/private/sdl_gpu_test/application.cpp @@ -0,0 +1,74 @@ + +#include "./application.hpp" + +#include +#include + +namespace sdl_gpu_test +{ +void Application::init(std::span args) +{ + mWindow.create({ + .title = "SDL_gpu Test", + .flags = {.resizable = true} + }); + + mDevice.create({ + .formatFlags{.spirv = true}, + .debugMode = true + }); + mDevice.claimWindow(mWindow); + + fs::path executablePath = fs::absolute(fs::path(args[0])).parent_path(); + mFileSystem.emplaceAdapter>(executablePath.parent_path() / "assets"); +} + +void Application::cleanup() +{ +} + +void Application::update() +{ + +} + +void Application::run(std::span args) +{ + init(args); + while (mRunning) + { + std::optional event; + while ((event = sdlpp::pollEvent()).has_value()) + { + std::visit(mijin::Visitor{ + [&](const sdlpp::QuitEvent&) { mRunning = false; }, + [](const auto&) {} // default handler + }, *event); + } + update(); + } + cleanup(); +} + + +[[nodiscard]] [[maybe_unused]] +std::string Application::getFileContentsText(const fs::path& path) +{ + std::unique_ptr stream; + mijin::throwOnError(mFileSystem.open(path, mijin::FileOpenMode::READ, stream), + "Error opening file for reading."); + std::string content; + mijin::throwOnError(stream->readAsString(content), "Error reading file contents."); + return content; +} + +mijin::TypelessBuffer Application::getFileContentsBinary(const fs::path& path) +{ + std::unique_ptr stream; + mijin::throwOnError(mFileSystem.open(path, mijin::FileOpenMode::READ, stream), + "Error opening file for reading."); + mijin::TypelessBuffer content; + mijin::throwOnError(stream->readRest(content), "Error reading file contents."); + return content; +} +} diff --git a/private/sdl_gpu_test/application.hpp b/private/sdl_gpu_test/application.hpp new file mode 100644 index 0000000..988142b --- /dev/null +++ b/private/sdl_gpu_test/application.hpp @@ -0,0 +1,72 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_APPLICATION_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_APPLICATION_HPP_INCLUDED 1 + +#include + +#include + +#include "./sdlpp/event.hpp" +#include "./sdlpp/gpu.hpp" +#include "./sdlpp/window.hpp" + +namespace sdl_gpu_test +{ +class Application +{ +protected: + sdlpp::Window mWindow; + sdlpp::GPUDevice mDevice; + mijin::StackedFileSystemAdapter mFileSystem; + bool mRunning = true; +public: + virtual ~Application() noexcept = default; + + virtual void init(std::span args); + virtual void cleanup(); + virtual void update(); + + void run(std::span args); + + // utility stuff + [[nodiscard]] + std::string getFileContentsText(const fs::path& path); + + [[nodiscard]] + mijin::TypelessBuffer getFileContentsBinary(const fs::path& path); + + template + void uploadVertexData(const sdlpp::GPUBuffer& vertexBuffer, std::span vertices); +}; + +template +void Application::uploadVertexData(const sdlpp::GPUBuffer& vertexBuffer, std::span vertices) +{ + sdlpp::GPUTransferBuffer transferBuffer; + transferBuffer.create(mDevice, { + .usage = sdlpp::GPUTransferBufferUsage::UPLOAD, + .size = static_cast(vertices.size_bytes()) + }); + void* ptr = transferBuffer.map(); + std::memcpy(ptr, vertices.data(), vertices.size_bytes()); + transferBuffer.unmap(); + + sdlpp::GPUCommandBuffer cmdBuffer = mDevice.acquireCommandBuffer(); + sdlpp::GPUCopyPass copyPass = cmdBuffer.beginCopyPass(); + copyPass.uploadToGPUBuffer( + /* source = */ { + .transferBuffer = transferBuffer + }, + /* destination = */ { + .buffer = vertexBuffer, + .size = static_cast(vertices.size_bytes()) + } + ); + copyPass.end(); + cmdBuffer.submit(); +} +} // namespace sdl_gpu_test + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_APPLICATION_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/main.cpp b/private/sdl_gpu_test/main.cpp index 238c99d..34114da 100644 --- a/private/sdl_gpu_test/main.cpp +++ b/private/sdl_gpu_test/main.cpp @@ -1,83 +1,10 @@ -#include -#include -#include -#include -#include -#include -#include +#include "./0_triangle_with_texcoords/app.hpp" + +#include #include #include -#include "./sdlpp/event.hpp" -#include "./sdlpp/gpu.hpp" -#include "./sdlpp/window.hpp" - -namespace -{ -struct Vertex -{ - glm::vec2 pos; - glm::vec2 texCoord; -}; - -mijin::StackedFileSystemAdapter gFileSystem; - -void initFileSystem(const fs::path& executablePath) noexcept -{ - gFileSystem.emplaceAdapter>(executablePath.parent_path() / "assets"); -} - -[[nodiscard]] [[maybe_unused]] -std::string getFileContentsText(const fs::path& path) -{ - std::unique_ptr stream; - mijin::throwOnError(gFileSystem.open(path, mijin::FileOpenMode::READ, stream), - "Error opening file for reading."); - std::string content; - mijin::throwOnError(stream->readAsString(content), "Error reading file contents."); - return content; -} - -[[nodiscard]] -mijin::TypelessBuffer getFileContentsBinary(const fs::path& path) -{ - std::unique_ptr stream; - mijin::throwOnError(gFileSystem.open(path, mijin::FileOpenMode::READ, stream), - "Error opening file for reading."); - mijin::TypelessBuffer content; - mijin::throwOnError(stream->readRest(content), "Error reading file contents."); - return content; -} - -template -void uploadVertexData(const sdlpp::GPUDevice& gpuDevice, const sdlpp::GPUBuffer& vertexBuffer, std::span vertices) -{ - sdlpp::GPUTransferBuffer transferBuffer; - transferBuffer.create(gpuDevice, { - .usage = sdlpp::GPUTransferBufferUsage::UPLOAD, - .size = static_cast(vertices.size_bytes()) - }); - void* ptr = transferBuffer.map(); - std::memcpy(ptr, vertices.data(), vertices.size_bytes()); - transferBuffer.unmap(); - - sdlpp::GPUCommandBuffer cmdBuffer = gpuDevice.acquireCommandBuffer(); - sdlpp::GPUCopyPass copyPass = cmdBuffer.beginCopyPass(); - copyPass.uploadToGPUBuffer( - /* source = */ { - .transferBuffer = transferBuffer - }, - /* destination = */ { - .buffer = vertexBuffer, - .size = static_cast(vertices.size_bytes()) - } - ); - copyPass.end(); - cmdBuffer.submit(); -} -} - int main(int argc, char* argv[]) { if (argc < 1) @@ -85,137 +12,27 @@ int main(int argc, char* argv[]) return 1; } - initFileSystem(fs::absolute(fs::path(argv[0])).parent_path()); - - // init SDL if (SDL_Init(0) != SDL_TRUE) { - spdlog::error("Error initializing SDL."); - return 1; + throw std::runtime_error("Error initializing SDL."); } - MIJIN_SCOPE_EXIT { - SDL_Quit(); - }; - sdlpp::Window window; - window.create({ - .title = "SDL_gpu Test", - .flags = {.resizable = true} - }); - - sdlpp::GPUDevice gpuDevice; - gpuDevice.create({ - .formatFlags{.spirv = true}, - .debugMode = true - }); - - gpuDevice.claimWindow(window); - - // create vertex shader - mijin::TypelessBuffer vertexSpv = getFileContentsBinary("shaders/glsl/textured_triangles_from_buffer.vert.spv"); - sdlpp::GPUShader vertexShader; - vertexShader.create(gpuDevice, { - .code = {static_cast(vertexSpv.data()), vertexSpv.byteSize()}, - .format = sdlpp::GPUShaderFormat::SPIRV, - .stage = sdlpp::GPUShaderStage::VERTEX - }); - - // create fragment shader - mijin::TypelessBuffer fragmentSpv = getFileContentsBinary("shaders/glsl/color_from_texcoord.frag.spv"); - sdlpp::GPUShader fragmentShader; - fragmentShader.create(gpuDevice, { - .code = {static_cast(fragmentSpv.data()), fragmentSpv.byteSize()}, - .format = sdlpp::GPUShaderFormat::SPIRV, - .stage = sdlpp::GPUShaderStage::FRAGMENT, - .numUniformBuffers = 1 - }); - - // create graphics pipeline - std::array colorTargetsDescs = { - sdlpp::GPUColorTargetDescription{ - .format = gpuDevice.getSwapchainTextureFormat(window) - } - }; - sdlpp::GPUGraphicsPipeline pipeline; - std::array vertexBindings = { - sdlpp::GPUVertexBinding{ - .index = 0, - .pitch = sizeof(Vertex) - } - }; - std::array vertexAttributes = { - sdlpp::GPUVertexAttribute{ - .location = 0, - .bindingIndex = 0, - .format = sdlpp::GPUVertexElementFormat::FLOAT2, - .offset = offsetof(Vertex, pos) - }, - sdlpp::GPUVertexAttribute{ - .location = 1, - .bindingIndex = 0, - .format = sdlpp::GPUVertexElementFormat::FLOAT2, - .offset = offsetof(Vertex, texCoord) - } - }; - pipeline.create(gpuDevice, { - .vertexShader = vertexShader, - .fragmentShader = fragmentShader, - .vertexInputState = { - .vertexBindings = vertexBindings, - .vertexAttributes = vertexAttributes - }, - .targetInfo = { - .colorTargetDescriptions = colorTargetsDescs - } - }); - - std::array vertices = + try { - Vertex{.pos = {-1.f, -1.f}, .texCoord = {0.f, 0.f}}, - Vertex{.pos = { 1.f, -1.f}, .texCoord = {1.f, 0.f}}, - Vertex{.pos = { 0.f, 1.f}, .texCoord = {0.5f, 1.f}} - }; - - // create vertex buffer - sdlpp::GPUBuffer vertexBuffer; - vertexBuffer.create(gpuDevice, { - .usage = {.vertex = true}, - .size = sizeof(vertices) - }); - uploadVertexData(gpuDevice, vertexBuffer, std::span(vertices.begin(), vertices.end())); - - bool running = true; - while(running) + // make sure app is destructed before shutting down SDL + std::unique_ptr app = std::make_unique(); + app->run(std::span(const_cast(argv), argc)); + } + catch (std::exception& exception) { - std::optional event; - while ((event = sdlpp::pollEvent()).has_value()) + spdlog::error("Exception while running application: {}", exception.what()); + mijin::getExceptionStacktrace().then([](const mijin::Stacktrace& stacktrace) { - std::visit(mijin::Visitor{ - [&](const sdlpp::QuitEvent&) { running = false; }, - [](const auto&) {} // default handler - }, *event); - } - - sdlpp::GPUCommandBuffer cmdBuffer = gpuDevice.acquireCommandBuffer(); - Uint32 swapchainWidth = 0, swapchainHeight = 0; - sdlpp::GPUTexture swapchainTexture = cmdBuffer.acquireSwapchainTexture(window, swapchainWidth, swapchainHeight); - std::array colorTargets = {sdlpp::GPUColorTargetInfo{ - .texture = swapchainTexture, - .clearColor = {.r = 1.f, .g = 0.f, .b = 0.f, .a = 1.f}, - .loadOp = sdlpp::GPULoadOp::CLEAR, - }}; - sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({ - .colorTargetInfos = colorTargets + spdlog::error("{}", stacktrace); }); - static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f); - cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1)); - renderPass.bindGraphicsPipeline(pipeline); - renderPass.bindVertexBuffer({.buffer = vertexBuffer}); - renderPass.drawPrimitives({.numVertices = 3}); - - renderPass.end(); - cmdBuffer.submit(); } + SDL_Quit(); + return 0; } diff --git a/private/sdl_gpu_test/sdlpp/common.hpp b/private/sdl_gpu_test/sdlpp/common.hpp index dc88ae2..bac267c 100644 --- a/private/sdl_gpu_test/sdlpp/common.hpp +++ b/private/sdl_gpu_test/sdlpp/common.hpp @@ -4,6 +4,7 @@ #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 diff --git a/private/sdl_gpu_test/sdlpp/event.hpp b/private/sdl_gpu_test/sdlpp/event.hpp index 8f0be20..04c5e46 100644 --- a/private/sdl_gpu_test/sdlpp/event.hpp +++ b/private/sdl_gpu_test/sdlpp/event.hpp @@ -33,7 +33,7 @@ using sdl_event_t = std::variant< >; [[nodiscard]] -std::optional pollEvent() noexcept +inline std::optional pollEvent() noexcept { SDL_Event event; while (SDL_PollEvent(&event))