From 3a42f7cc368ab607a30ced4f86376c4e1807e08b Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Fri, 13 Sep 2024 00:36:29 +0200 Subject: [PATCH] Get swapchain texture and clear it red. --- private/sdl_gpu_test/glsl_compiler.cpp | 8 +- private/sdl_gpu_test/glsl_compiler.hpp | 1 + private/sdl_gpu_test/main.cpp | 20 ++- private/sdl_gpu_test/sdlpp/common.hpp | 3 +- private/sdl_gpu_test/sdlpp/gpu.hpp | 172 ++++++++++++++++++++++++- 5 files changed, 197 insertions(+), 7 deletions(-) diff --git a/private/sdl_gpu_test/glsl_compiler.cpp b/private/sdl_gpu_test/glsl_compiler.cpp index 24419d6..98ab712 100644 --- a/private/sdl_gpu_test/glsl_compiler.cpp +++ b/private/sdl_gpu_test/glsl_compiler.cpp @@ -51,9 +51,9 @@ std::vector compileGLSL(std::string_view source, const CompileGLS int sourceLength = static_cast(source.size()); shader->setStringsWithLengths(&sourcePtr, &sourceLength, 1); shader->setDebugInfo(true); - shader->setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, glslang::EShTargetVulkan_1_3); - shader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_3); - shader->setEnvTarget(glslang::EShTargetLanguage::EshTargetSpv, glslang::EShTargetSpv_1_6); + shader->setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); + shader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); + shader->setEnvTarget(glslang::EShTargetLanguage::EshTargetSpv, glslang::EShTargetSpv_1_0); DirStackFileIncluder includer; std::string preprocessedCode; @@ -110,7 +110,7 @@ std::vector compileGLSL(std::string_view source, const CompileGLS .optimizeSize = false, .disassemble = false, .validate = true, - .emitNonSemanticShaderDebugInfo = true, + .emitNonSemanticShaderDebugInfo = false, // requires SPV_KHR_non_semantic_info .emitNonSemanticShaderDebugSource = false, // maybe? .compileOnly = false }; diff --git a/private/sdl_gpu_test/glsl_compiler.hpp b/private/sdl_gpu_test/glsl_compiler.hpp index 863d0fb..be14620 100644 --- a/private/sdl_gpu_test/glsl_compiler.hpp +++ b/private/sdl_gpu_test/glsl_compiler.hpp @@ -4,6 +4,7 @@ #if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_GLSL_COMPILER_HPP_INCLUDED) #define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_GLSL_COMPILER_HPP_INCLUDED 1 +#include #include #include diff --git a/private/sdl_gpu_test/main.cpp b/private/sdl_gpu_test/main.cpp index ed5c86d..ef4366d 100644 --- a/private/sdl_gpu_test/main.cpp +++ b/private/sdl_gpu_test/main.cpp @@ -56,7 +56,10 @@ int main(int, char**) }); sdlpp::GPUDevice gpuDevice; - gpuDevice.create({.formatFlags{.spirv = true}}); + gpuDevice.create({ + .formatFlags{.spirv = true}, + .debugMode = true + }); gpuDevice.claimWindow(window); @@ -96,6 +99,21 @@ int main(int, char**) [](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 + }); + + renderPass.end(); + cmdBuffer.submit(); } return 0; diff --git a/private/sdl_gpu_test/sdlpp/common.hpp b/private/sdl_gpu_test/sdlpp/common.hpp index 91e9aa8..dc88ae2 100644 --- a/private/sdl_gpu_test/sdlpp/common.hpp +++ b/private/sdl_gpu_test/sdlpp/common.hpp @@ -4,9 +4,10 @@ #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 #include #include diff --git a/private/sdl_gpu_test/sdlpp/gpu.hpp b/private/sdl_gpu_test/sdlpp/gpu.hpp index 5fdf947..09aa304 100644 --- a/private/sdl_gpu_test/sdlpp/gpu.hpp +++ b/private/sdl_gpu_test/sdlpp/gpu.hpp @@ -214,6 +214,19 @@ enum class GPUShaderStage FRAGMENT = SDL_GPU_SHADERSTAGE_FRAGMENT }; +enum class GPULoadOp +{ + LOAD = SDL_GPU_LOADOP_LOAD, + CLEAR = SDL_GPU_LOADOP_CLEAR, + DONT_CARE = SDL_GPU_LOADOP_DONT_CARE +}; + +enum class GPUStoreOp +{ + STORE = SDL_GPU_STOREOP_STORE, + DONT_CARE = SDL_GPU_STOREOP_DONT_CARE +}; + // // bitflags // @@ -354,9 +367,158 @@ struct GPUGraphicsPipelineTargetInfo } }; +using FColor = SDL_FColor; + +struct GPUColorTargetInfo +{ + SDL_GPUTexture* texture = nullptr; + Uint32 mipLevel = 0; + Uint32 layerOrDepthPlane = 0; + FColor clearColor = {.r = 0, .g = 0, .b = 0, .a = 1}; + GPULoadOp loadOp = GPULoadOp::LOAD; + GPUStoreOp storeOp = GPUStoreOp::STORE; + bool cycle = false; +}; +static_assert(sizeof(GPUColorTargetInfo) == sizeof(SDL_GPUColorTargetInfo) + && alignof(GPUColorTargetInfo) == alignof(SDL_GPUColorTargetInfo)); + +struct GPUDepthStencilTargetInfo +{ + SDL_GPUTexture* texture = nullptr; + float clearDepth = 0.f; + GPULoadOp loadOp = GPULoadOp::LOAD; + GPUStoreOp storeOp = GPUStoreOp::STORE; + GPULoadOp stencilLoadOp = GPULoadOp::LOAD; + GPUStoreOp stencilStoreOp = GPUStoreOp::STORE; + bool cycle = false; + Uint8 clearStencil; +}; +static_assert(sizeof(GPUDepthStencilTargetInfo) == sizeof(SDL_GPUDepthStencilTargetInfo) + && alignof(GPUDepthStencilTargetInfo) == alignof(SDL_GPUDepthStencilTargetInfo)); + // // classes // + +class GPURenderPass : public Base +{ +public: + GPURenderPass() noexcept = default; + GPURenderPass(const GPURenderPass&) = delete; + GPURenderPass(GPURenderPass&& other) noexcept : Base(std::move(other)) {} + + GPURenderPass& operator=(const GPURenderPass&) = delete; + GPURenderPass& operator=(GPURenderPass&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const GPURenderPass& other) const noexcept = default; + + void end() noexcept + { + SDL_EndGPURenderPass(mHandle); + mHandle = nullptr; + } + + void destroy() noexcept + { + MIJIN_ASSERT(mHandle == nullptr, "Renderpass has not been ended."); + } + + friend class GPUCommandBuffer; +}; + +class GPUTexture : public Base +{ +private: + SDL_GPUDevice* mDevice = nullptr; +public: + GPUTexture() noexcept = default; + GPUTexture(const GPUTexture&) = delete; + GPUTexture(GPUTexture&& other) noexcept : Base(std::move(other)) {} + + GPUTexture& operator=(const GPUTexture&) = delete; + GPUTexture& operator=(GPUTexture&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const GPUTexture& other) const noexcept = default; + + void destroy() noexcept + { + if (mHandle != nullptr) + { + // if this is not manually created (e.g. a swapchain image), device will be nullptr + if (mDevice != nullptr) + { + SDL_ReleaseGPUTexture(mDevice, mHandle); + } + mHandle = nullptr; + mDevice = nullptr; + } + } + + friend class GPUCommandBuffer; +}; + +struct GPUBeginRenderPassArgs +{ + std::span colorTargetInfos; + std::optional depthStencilTargetInfo; +}; + +class GPUCommandBuffer : public Base +{ +public: + GPUCommandBuffer() noexcept = default; + GPUCommandBuffer(const GPUCommandBuffer&) = delete; + GPUCommandBuffer(GPUCommandBuffer&& other) noexcept : Base(std::move(other)) {} + + GPUCommandBuffer& operator=(const GPUCommandBuffer&) = delete; + GPUCommandBuffer& operator=(GPUCommandBuffer&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const GPUCommandBuffer& other) const noexcept = default; + + void submit() noexcept + { + SDL_SubmitGPUCommandBuffer(mHandle); + mHandle = nullptr; + } + + void destroy() noexcept + { + MIJIN_ASSERT(mHandle == nullptr, "Command buffer has not been submitted."); + } + + [[nodiscard]] + GPURenderPass beginRenderPass(const GPUBeginRenderPassArgs& args) const noexcept + { + GPURenderPass renderPass; + renderPass.mHandle = SDL_BeginGPURenderPass( + /* command_buffer = */ mHandle, + /* color_target_infos = */ std::bit_cast(args.colorTargetInfos.data()), + /* num_color_targets = */ static_cast(args.colorTargetInfos.size()), + /* depth_stencil_target_info = */ args.depthStencilTargetInfo.has_value() ? std::bit_cast(&*args.depthStencilTargetInfo) : nullptr + ); + return renderPass; + } + + [[nodiscard]] + GPUTexture acquireSwapchainTexture(SDL_Window* window, Uint32& outWidth, Uint32& outHeight) noexcept + { + GPUTexture texture; + texture.mHandle = SDL_AcquireGPUSwapchainTexture(mHandle, window, &outWidth, &outHeight); + return texture; + } + + friend class GPUDevice; +}; + struct GPUDeviceCreateArgs { GPUShaderFormatFlags formatFlags = {}; @@ -400,11 +562,19 @@ public: void claimWindow(SDL_Window* window) const { - if (!SDL_ClaimWindowForGPUDevice(*this, window)) + if (!SDL_ClaimWindowForGPUDevice(mHandle, window)) { throw SDLError(); } } + + [[nodiscard]] + GPUCommandBuffer acquireCommandBuffer() const noexcept + { + GPUCommandBuffer cmdBuffer; + cmdBuffer.mHandle = SDL_AcquireGPUCommandBuffer(mHandle); + return cmdBuffer; + } }; struct GPUGraphicsPipelineCreateArgs