diff --git a/private/sdl_gpu_test/main.cpp b/private/sdl_gpu_test/main.cpp index 50f65b9..a8afc96 100644 --- a/private/sdl_gpu_test/main.cpp +++ b/private/sdl_gpu_test/main.cpp @@ -29,8 +29,7 @@ int main(int, char**) gpuDevice.claimWindow(window); - const SDL_GPUTextureFormat texForm = SDL_GetGPUSwapchainTextureFormat(gpuDevice, window); - (void) texForm; + bool running = true; while(running) diff --git a/private/sdl_gpu_test/sdlpp/common.hpp b/private/sdl_gpu_test/sdlpp/common.hpp index 511156f..f255b1a 100644 --- a/private/sdl_gpu_test/sdlpp/common.hpp +++ b/private/sdl_gpu_test/sdlpp/common.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/private/sdl_gpu_test/sdlpp/gpu.hpp b/private/sdl_gpu_test/sdlpp/gpu.hpp index 65f746a..93a08fa 100644 --- a/private/sdl_gpu_test/sdlpp/gpu.hpp +++ b/private/sdl_gpu_test/sdlpp/gpu.hpp @@ -74,6 +74,400 @@ public: } } }; + +enum class GPUVertexInputRate +{ + VERTEX = SDL_GPU_VERTEXINPUTRATE_VERTEX, + INSTANCE = SDL_GPU_VERTEXINPUTRATE_INSTANCE +}; + +struct GPUVertexBinding +{ + Uint32 index; + Uint32 pitch; + GPUVertexInputRate inputRate = GPUVertexInputRate::VERTEX; + Uint32 instanceStepRate; +}; +static_assert(sizeof(GPUVertexBinding) == sizeof(SDL_GPUVertexBinding) + && alignof(GPUVertexBinding) == alignof(SDL_GPUVertexBinding)); + +enum class GPUVertexElementFormat +{ + INT = SDL_GPU_VERTEXELEMENTFORMAT_INT, + INT2 = SDL_GPU_VERTEXELEMENTFORMAT_INT2, + INT3 = SDL_GPU_VERTEXELEMENTFORMAT_INT3, + INT4 = SDL_GPU_VERTEXELEMENTFORMAT_INT4, + UINT = SDL_GPU_VERTEXELEMENTFORMAT_UINT, + UINT2 = SDL_GPU_VERTEXELEMENTFORMAT_UINT2, + UINT3 = SDL_GPU_VERTEXELEMENTFORMAT_UINT3, + UINT4 = SDL_GPU_VERTEXELEMENTFORMAT_UINT4, + FLOAT = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT, + FLOAT2 = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + FLOAT3 = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + FLOAT4 = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, + BYTE2 = SDL_GPU_VERTEXELEMENTFORMAT_BYTE2, + BYTE4 = SDL_GPU_VERTEXELEMENTFORMAT_BYTE4, + UBYTE2 = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2, + UBYTE4 = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4, + BYTE2_NORM = SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM, + BYTE4_NORM = SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM, + UBYTE2_NORM = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM, + UBYTE4_NORM = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM, + SHORT2 = SDL_GPU_VERTEXELEMENTFORMAT_SHORT2, + SHORT4 = SDL_GPU_VERTEXELEMENTFORMAT_SHORT4, + USHORT2 = SDL_GPU_VERTEXELEMENTFORMAT_USHORT2, + USHORT4 = SDL_GPU_VERTEXELEMENTFORMAT_USHORT4, + SHORT2_NORM = SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM, + SHORT4_NORM = SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM, + USHORT2_NORM = SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM, + USHORT4_NORM = SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM, + HALF2 = SDL_GPU_VERTEXELEMENTFORMAT_HALF2, + HALF4 = SDL_GPU_VERTEXELEMENTFORMAT_HALF4 +}; + +struct GPUVertexAttribute +{ + Uint32 location; + Uint32 bindingIndex; + GPUVertexElementFormat format; + Uint32 offset; +}; +static_assert(sizeof(GPUVertexAttribute) == sizeof(SDL_GPUVertexAttribute) + && alignof(GPUVertexAttribute) == alignof(SDL_GPUVertexAttribute)); + +struct GPUVertexInputState +{ + std::vector vertexBindings; + std::vector vertexAttributes; +}; + +enum class GPUPrimitiveType +{ + POINTLIST = SDL_GPU_PRIMITIVETYPE_POINTLIST, + LINELIST = SDL_GPU_PRIMITIVETYPE_LINELIST, + LINESTRIP = SDL_GPU_PRIMITIVETYPE_LINESTRIP, + TRIANGLELIST = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + TRIANGLESTRIP = SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP +}; + +enum class GPUFillMode +{ + FILL = SDL_GPU_FILLMODE_FILL, + LINE = SDL_GPU_FILLMODE_LINE +}; + +enum class GPUCullMode +{ + NONE = SDL_GPU_CULLMODE_NONE, + FRONT = SDL_GPU_CULLMODE_FRONT, + BACK = SDL_GPU_CULLMODE_BACK +}; + +enum class GPUFrontFace +{ + COUNTER_CLOCKWISE = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, + CLOCKWISE = SDL_GPU_FRONTFACE_CLOCKWISE +}; + +struct GPURasterizerState +{ + GPUFillMode fillMode = GPUFillMode::FILL; + GPUCullMode cullMode = GPUCullMode::NONE; + GPUFrontFace frontFace = GPUFrontFace::COUNTER_CLOCKWISE; + bool enableDepthBias = false; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; +}; + +enum class GPUSampleCount +{ + ONE = SDL_GPU_SAMPLECOUNT_1, + TWO = SDL_GPU_SAMPLECOUNT_2, + FOUR = SDL_GPU_SAMPLECOUNT_4, + EIGHT = SDL_GPU_SAMPLECOUNT_8 +}; + +struct GPUMultisampleState +{ + GPUSampleCount sampleCount = GPUSampleCount::ONE; + Uint32 sampleMask = 0xFFFFFFFF; +}; + +enum class GPUCompareOp +{ + NEVER = SDL_GPU_COMPAREOP_NEVER, + LESS = SDL_GPU_COMPAREOP_LESS, + EQUAL = SDL_GPU_COMPAREOP_EQUAL, + LESS_OR_EQUAL = SDL_GPU_COMPAREOP_LESS_OR_EQUAL, + GREATER = SDL_GPU_COMPAREOP_GREATER, + NOT_EQUAL = SDL_GPU_COMPAREOP_NOT_EQUAL, + GREATER_OR_EQUAL = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, + ALWAYS = SDL_GPU_COMPAREOP_ALWAYS +}; + +enum class GPUStencilOp +{ + KEEP = SDL_GPU_STENCILOP_KEEP, + ZERO = SDL_GPU_STENCILOP_ZERO, + REPLACE = SDL_GPU_STENCILOP_REPLACE, + INCREMENT_AND_CLAMP = SDL_GPU_STENCILOP_INCREMENT_AND_CLAMP, + DECREMENT_AND_CLAMP = SDL_GPU_STENCILOP_DECREMENT_AND_CLAMP, + INVERT = SDL_GPU_STENCILOP_INVERT, + INCREMENT_AND_WRAP = SDL_GPU_STENCILOP_INCREMENT_AND_WRAP, + DECREMENT_AND_WRAP = SDL_GPU_STENCILOP_DECREMENT_AND_WRAP +}; + +struct GPUStencilOpState +{ + GPUStencilOp failOp; + GPUStencilOp passOp; + GPUStencilOp depthFailOp; + GPUCompareOp compareOp; + + explicit operator SDL_GPUStencilOpState() const noexcept + { + return { + .fail_op = static_cast(failOp), + .pass_op = static_cast(passOp), + .depth_fail_op = static_cast(depthFailOp), + .compare_op = static_cast(compareOp), + }; + } +}; + +struct GPUDepthStencilState +{ + bool enableDepthTest = false; + bool enableDepthWrite = false; + bool enableStencilTest = false; + GPUCompareOp compareOp = GPUCompareOp::LESS_OR_EQUAL; + GPUStencilOpState backStencilState; + GPUStencilOpState frontStencilState; + Uint8 compareMask; + Uint8 writeMask; +}; + +enum class GPUBlendFactor +{ + ZERO = SDL_GPU_BLENDFACTOR_ZERO, + ONE = SDL_GPU_BLENDFACTOR_ONE, + SRC_COLOR = SDL_GPU_BLENDFACTOR_SRC_COLOR, + ONE_MINUS_SRC_COLOR = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_COLOR, + DST_COLOR = SDL_GPU_BLENDFACTOR_DST_COLOR, + ONE_MINUS_DST_COLOR = SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_COLOR, + SRC_ALPHA = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + ONE_MINUS_SRC_ALPHA = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + DST_ALPHA = SDL_GPU_BLENDFACTOR_DST_ALPHA, + ONE_MINUS_DST_ALPHA = SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_ALPHA, + CONSTANT_COLOR = SDL_GPU_BLENDFACTOR_CONSTANT_COLOR, + ONE_MINUS_CONSTANT_COLOR = SDL_GPU_BLENDFACTOR_ONE_MINUS_CONSTANT_COLOR, + SRC_ALPHA_SATURATE = SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE +}; + +enum class GPUBlendOp +{ + ADD = SDL_GPU_BLENDOP_ADD, + SUBTRACT = SDL_GPU_BLENDOP_SUBTRACT, + REVERSE_SUBTRACT = SDL_GPU_BLENDOP_REVERSE_SUBTRACT, + MIN = SDL_GPU_BLENDOP_MIN, + MAX = SDL_GPU_BLENDOP_MAX +}; + +struct GPUColorComponentFlags : mijin::BitFlags +{ + bool r : 1 = false; + bool g : 1 = false; + bool b : 1 = false; + bool a : 1 = false; +}; + +struct GPUColorTargetBlendState +{ + bool enableBlend = false; + GPUBlendFactor srcColorBlendfactor; + GPUBlendFactor dstColorBlendfactor; + GPUBlendOp colorBlendOp; + GPUBlendFactor srcAlphaBlendfactor; + GPUBlendFactor dstAlphaBlendfactor; + GPUBlendOp alphaBlendOp; + GPUColorComponentFlags colorWriteMask = {.r = true, .g = true, .b = true, .a = true}; +}; + +enum class GPUTextureFormat +{ + INVALID = SDL_GPU_TEXTUREFORMAT_INVALID, + A8_UNORM = SDL_GPU_TEXTUREFORMAT_A8_UNORM, + R8_UNORM = SDL_GPU_TEXTUREFORMAT_R8_UNORM, + R8G8_UNORM = SDL_GPU_TEXTUREFORMAT_R8G8_UNORM, + R8G8B8A8_UNORM = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + R16_UNORM = SDL_GPU_TEXTUREFORMAT_R16_UNORM, + R16G16_UNORM = SDL_GPU_TEXTUREFORMAT_R16G16_UNORM, + R16G16B16A16_UNORM = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM, + R10G10B10A2_UNORM = SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, + B5G6R5_UNORM = SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM, + B5G5R5A1_UNORM = SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM, + B4G4R4A4_UNORM = SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM, + B8G8R8A8_UNORM = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, + BC1_RGBA_UNORM = SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM, + BC2_RGBA_UNORM = SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM, + BC3_RGBA_UNORM = SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM, + BC4_R_UNORM = SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM, + BC5_RG_UNORM = SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM, + BC7_RGBA_UNORM = SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM, + BC6H_RGB_FLOAT = SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT, + BC6H_RGB_UFLOAT = SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT, + R8_SNORM = SDL_GPU_TEXTUREFORMAT_R8_SNORM, + R8G8_SNORM = SDL_GPU_TEXTUREFORMAT_R8G8_SNORM, + R8G8B8A8_SNORM = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM, + R16_SNORM = SDL_GPU_TEXTUREFORMAT_R16_SNORM, + R16G16_SNORM = SDL_GPU_TEXTUREFORMAT_R16G16_SNORM, + R16G16B16A16_SNORM = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM, + R16_FLOAT = SDL_GPU_TEXTUREFORMAT_R16_FLOAT, + R16G16_FLOAT = SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT, + R16G16B16A16_FLOAT = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, + R32_FLOAT = SDL_GPU_TEXTUREFORMAT_R32_FLOAT, + R32G32_FLOAT = SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT, + R32G32B32A32_FLOAT = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT, + R11G11B10_UFLOAT = SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT, + R8_UINT = SDL_GPU_TEXTUREFORMAT_R8_UINT, + R8G8_UINT = SDL_GPU_TEXTUREFORMAT_R8G8_UINT, + R8G8B8A8_UINT = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT, + R16_UINT = SDL_GPU_TEXTUREFORMAT_R16_UINT, + R16G16_UINT = SDL_GPU_TEXTUREFORMAT_R16G16_UINT, + R16G16B16A16_UINT = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT, + R8_INT = SDL_GPU_TEXTUREFORMAT_R8_INT, + R8G8_INT = SDL_GPU_TEXTUREFORMAT_R8G8_INT, + R8G8B8A8_INT = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_INT, + R16_INT = SDL_GPU_TEXTUREFORMAT_R16_INT, + R16G16_INT = SDL_GPU_TEXTUREFORMAT_R16G16_INT, + R16G16B16A16_INT = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_INT, + R8G8B8A8_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB, + B8G8R8A8_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, + BC1_RGBA_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB, + BC2_RGBA_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB, + BC3_RGBA_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB, + BC7_RGBA_UNORM_SRGB = SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB, + D16_UNORM = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + D24_UNORM = SDL_GPU_TEXTUREFORMAT_D24_UNORM, + D32_FLOAT = SDL_GPU_TEXTUREFORMAT_D32_FLOAT, + D24_UNORM_S8_UINT = SDL_GPU_TEXTUREFORMAT_D24_UNORM_S8_UINT, + D32_FLOAT_S8_UINT = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT +}; + +struct GPUColorTargetDescription +{ + GPUTextureFormat format = GPUTextureFormat::INVALID; + GPUColorTargetBlendState blendState; +}; + +static_assert(sizeof(GPUColorTargetDescription) == sizeof(SDL_GPUColorTargetDescription) + && alignof(GPUColorTargetDescription) == alignof(SDL_GPUColorTargetDescription)); + +struct GPUGraphicsPipelineTargetInfo +{ + std::vector colorTargetDescriptions; + bool hasDepthStencilTarget = false; + GPUTextureFormat depthStencilFormat = GPUTextureFormat::INVALID; + + explicit operator SDL_GpuGraphicsPipelineTargetInfo() const noexcept + { + return { + .color_target_descriptions = std::bit_cast(colorTargetDescriptions.data()), + .num_color_targets = static_cast(colorTargetDescriptions.size()), + .has_depth_stencil_target = hasDepthStencilTarget, + .depth_stencil_format = static_cast(depthStencilFormat) + }; + } +}; + +struct GPUGraphicsPipelineCreateArgs +{ + SDL_GPUShader* vertexShader; + SDL_GPUShader* fragmentShader; + GPUVertexInputState vertexInputState; + GPUPrimitiveType primitiveType = GPUPrimitiveType::TRIANGLELIST; + GPURasterizerState rasterizerState; + GPUMultisampleState multisampleState; + GPUDepthStencilState depthStencilState; + GPUGraphicsPipelineTargetInfo targetInfo; +}; + +class GPUGraphicsPipeline : public Base +{ +private: + SDL_GPUDevice* mDevice = nullptr; +public: + GPUGraphicsPipeline() noexcept = default; + GPUGraphicsPipeline(const GPUGraphicsPipeline&) = delete; + GPUGraphicsPipeline(GPUGraphicsPipeline&& other) noexcept : Base(std::move(other)) {} + + GPUGraphicsPipeline& operator=(const GPUGraphicsPipeline&) = delete; + GPUGraphicsPipeline& operator=(GPUGraphicsPipeline&& other) noexcept + { + Base::operator=(std::move(other)); + return *this; + } + auto operator<=>(const GPUGraphicsPipeline& other) const noexcept = default; + + void create(SDL_GPUDevice* device, const GPUGraphicsPipelineCreateArgs& args) + { + MIJIN_ASSERT(mHandle == nullptr, "GPUGraphicsPipeline has already been created."); + const SDL_GPUGraphicsPipelineCreateInfo createInfo = + { + .vertex_shader = args.vertexShader, + .fragment_shader = args.fragmentShader, + .vertex_input_state = { + .vertex_bindings = std::bit_cast(args.vertexInputState.vertexBindings.data()), + .num_vertex_bindings = static_cast(args.vertexInputState.vertexBindings.size()), + .vertex_attributes = std::bit_cast(args.vertexInputState.vertexAttributes.data()), + .num_vertex_attributes = static_cast(args.vertexInputState.vertexAttributes.size()) + }, + .primitive_type = static_cast(args.primitiveType), + .rasterizer_state = { + .fill_mode = static_cast(args.rasterizerState.fillMode), + .cull_mode = static_cast(args.rasterizerState.cullMode), + .front_face = static_cast(args.rasterizerState.frontFace), + .enable_depth_bias = args.rasterizerState.enableDepthBias, + .depth_bias_constant_factor = args.rasterizerState.depthBiasConstantFactor, + .depth_bias_clamp = args.rasterizerState.depthBiasClamp, + .depth_bias_slope_factor = args.rasterizerState.depthBiasSlopeFactor + }, + .multisample_state = { + .sample_count = static_cast(args.multisampleState.sampleCount), + .sample_mask = args.multisampleState.sampleMask + }, + .depth_stencil_state = { + .enable_depth_test = args.depthStencilState.enableDepthTest, + .enable_depth_write = args.depthStencilState.enableDepthWrite, + .enable_stencil_test = args.depthStencilState.enableStencilTest, + .compare_op = static_cast(args.depthStencilState.compareOp), + .back_stencil_state = static_cast(args.depthStencilState.backStencilState), + .front_stencil_state = static_cast(args.depthStencilState.frontStencilState), + .compare_mask = args.depthStencilState.compareMask, + .write_mask = args.depthStencilState.writeMask + }, + .target_info = static_cast(args.targetInfo), + .props = 0 + }; + mHandle = SDL_CreateGPUGraphicsPipeline(device, &createInfo); + if (mHandle == nullptr) + { + throw SDLError(); + } + mDevice = device; + } + + void destroy() noexcept + { + if (mHandle != nullptr) + { + SDL_ReleaseGPUGraphicsPipeline(mDevice, mHandle); + mDevice = nullptr; + mHandle = nullptr; + } + } +}; } // namespace sdlpp #endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED)