Added texture and fixed a bunch of stuff.
This commit is contained in:
parent
9095c7e99a
commit
4ad274d637
BIN
assets/bitmaps/sdl.png
Normal file
BIN
assets/bitmaps/sdl.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
21
assets/shaders/glsl/color_from_texture.frag
Normal file
21
assets/shaders/glsl/color_from_texture.frag
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(set = 2, binding = 0)
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0)
|
||||||
|
uniform Parameters
|
||||||
|
{
|
||||||
|
vec4 u_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0)
|
||||||
|
in vec2 i_texCoord;
|
||||||
|
|
||||||
|
layout(location = 0)
|
||||||
|
out vec4 o_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
o_color = texture(u_texture, i_texCoord) * u_color;
|
||||||
|
}
|
135
private/sdl_gpu_test/1_textured_quad/app.cpp
Normal file
135
private/sdl_gpu_test/1_textured_quad/app.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
|
||||||
|
#include "./app.hpp"
|
||||||
|
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
|
#include "../util/bitmap.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
glm::vec2 pos;
|
||||||
|
glm::vec2 texCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array VERTICES =
|
||||||
|
{
|
||||||
|
Vertex{.pos = { 0.7f, -0.7f}, .texCoord = {1.f, 1.f}},
|
||||||
|
Vertex{.pos = { 0.7f, 0.7f}, .texCoord = {1.f, 0.f}},
|
||||||
|
Vertex{.pos = {-0.7f, -0.7f}, .texCoord = {0.f, 1.f}},
|
||||||
|
Vertex{.pos = {-0.7f, 0.7f}, .texCoord = {0.f, 0.f}}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TexturedQuadApp::init(const AppInitArgs& args)
|
||||||
|
{
|
||||||
|
Application::init(args);
|
||||||
|
|
||||||
|
// create shaders
|
||||||
|
sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/textured_triangles_from_buffer.vert.spv", {
|
||||||
|
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||||
|
.stage = sdlpp::GPUShaderStage::VERTEX
|
||||||
|
});
|
||||||
|
sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", {
|
||||||
|
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||||
|
.stage = sdlpp::GPUShaderStage::FRAGMENT,
|
||||||
|
.numSamplers = 1,
|
||||||
|
.numUniformBuffers = 1
|
||||||
|
});
|
||||||
|
|
||||||
|
// create graphics pipeline
|
||||||
|
std::array colorTargetsDescs = {
|
||||||
|
sdlpp::GPUColorTargetDescription{
|
||||||
|
.format = mDevice.getSwapchainTextureFormat(mWindow),
|
||||||
|
.blendState = {
|
||||||
|
.enableBlend = true,
|
||||||
|
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
||||||
|
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||||
|
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
|
||||||
|
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
|
||||||
|
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
|
||||||
|
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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
|
||||||
|
},
|
||||||
|
.primitiveType = sdlpp::GPUPrimitiveType::TRIANGLESTRIP,
|
||||||
|
.rasterizerState = {
|
||||||
|
.cullMode = sdlpp::GPUCullMode::BACK
|
||||||
|
},
|
||||||
|
.targetInfo = {
|
||||||
|
.colorTargetDescriptions = colorTargetsDescs
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// create vertex buffer
|
||||||
|
mVertexBuffer.create(mDevice, {
|
||||||
|
.usage = {.vertex = true},
|
||||||
|
.size = sizeof(VERTICES)
|
||||||
|
});
|
||||||
|
uploadVertexData(mVertexBuffer, std::span(VERTICES.begin(), VERTICES.end()));
|
||||||
|
|
||||||
|
// create texture and sampler
|
||||||
|
sdlpp::GPUTextureCreateArgs textureArgs = {
|
||||||
|
.format = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM_SRGB,
|
||||||
|
.usage = {.sampler = true}
|
||||||
|
};
|
||||||
|
mTexture = loadTexture("bitmaps/sdl.png", textureArgs);
|
||||||
|
mSampler.create(mDevice, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TexturedQuadApp::update(const AppUpdateArgs& args)
|
||||||
|
{
|
||||||
|
Application::update(args);
|
||||||
|
|
||||||
|
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.bindFragmentSampler({.texture = mTexture, .sampler = mSampler});
|
||||||
|
renderPass.bindGraphicsPipeline(mPipeline);
|
||||||
|
renderPass.bindVertexBuffer({.buffer = mVertexBuffer});
|
||||||
|
renderPass.drawPrimitives({.numVertices = VERTICES.size()});
|
||||||
|
renderPass.end();
|
||||||
|
cmdBuffer.submit();
|
||||||
|
}
|
||||||
|
}
|
24
private/sdl_gpu_test/1_textured_quad/app.hpp
Normal file
24
private/sdl_gpu_test/1_textured_quad/app.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_1_TEXTURED_QUAD_APP_HPP_INCLUDED)
|
||||||
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_1_TEXTURED_QUAD_APP_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include "../application.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
class TexturedQuadApp : public Application
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
sdlpp::GPUBuffer mVertexBuffer;
|
||||||
|
sdlpp::GPUGraphicsPipeline mPipeline;
|
||||||
|
sdlpp::GPUTexture mTexture;
|
||||||
|
sdlpp::GPUSampler mSampler;
|
||||||
|
public:
|
||||||
|
void init(const AppInitArgs& args) override;
|
||||||
|
void update(const AppUpdateArgs& args) override;
|
||||||
|
};
|
||||||
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_1_TEXTURED_QUAD_APP_HPP_INCLUDED)
|
@ -5,18 +5,14 @@ src_files = Split("""
|
|||||||
main.cpp
|
main.cpp
|
||||||
|
|
||||||
application.cpp
|
application.cpp
|
||||||
|
util/bitmap.cpp
|
||||||
|
|
||||||
0_triangle_with_texcoords/app.cpp
|
0_triangle_with_texcoords/app.cpp
|
||||||
|
1_textured_quad/app.cpp
|
||||||
""")
|
""")
|
||||||
|
|
||||||
shader_files = Split("""
|
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
|
||||||
#assets/shaders/glsl/color_from_uniform.frag
|
+ env.Glob("#assets/shaders/glsl/*.vert")
|
||||||
#assets/shaders/glsl/color_from_texcoord.frag
|
|
||||||
#assets/shaders/glsl/green.frag
|
|
||||||
#assets/shaders/glsl/triangle.vert
|
|
||||||
#assets/shaders/glsl/triangles_from_buffer.vert
|
|
||||||
#assets/shaders/glsl/textured_triangles_from_buffer.vert
|
|
||||||
""")
|
|
||||||
|
|
||||||
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS'])
|
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS'])
|
||||||
prog_app = env.UnityProgram(
|
prog_app = env.UnityProgram(
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#include <mijin/util/variant.hpp>
|
#include <mijin/util/variant.hpp>
|
||||||
#include <mijin/virtual_filesystem/relative.hpp>
|
#include <mijin/virtual_filesystem/relative.hpp>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <mijin/util/winundef.hpp>
|
||||||
|
|
||||||
|
#include "./util/bitmap.hpp"
|
||||||
|
|
||||||
namespace sdl_gpu_test
|
namespace sdl_gpu_test
|
||||||
{
|
{
|
||||||
@ -19,6 +23,16 @@ void Application::init(const AppInitArgs& args)
|
|||||||
});
|
});
|
||||||
mDevice.claimWindow(mWindow);
|
mDevice.claimWindow(mWindow);
|
||||||
|
|
||||||
|
// setup swapchain
|
||||||
|
if (mDevice.windowSupportsSwapchainComposition(mWindow, sdlpp::GPUSwapchainComposition::SDR_LINEAR))
|
||||||
|
{
|
||||||
|
mDevice.setSwapchainParameters(mWindow, sdlpp::GPUSwapchainComposition::SDR_LINEAR, sdlpp::GPUPresentMode::VSYNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spdlog::warn("Swapchain does not support SRGB, image will not look correct.");
|
||||||
|
}
|
||||||
|
|
||||||
fs::path executablePath = fs::absolute(fs::path(args.programArgs[0])).parent_path();
|
fs::path executablePath = fs::absolute(fs::path(args.programArgs[0])).parent_path();
|
||||||
mFileSystem.emplaceAdapter<mijin::RelativeFileSystemAdapter<mijin::OSFileSystemAdapter>>(executablePath.parent_path() / "assets");
|
mFileSystem.emplaceAdapter<mijin::RelativeFileSystemAdapter<mijin::OSFileSystemAdapter>>(executablePath.parent_path() / "assets");
|
||||||
}
|
}
|
||||||
@ -82,4 +96,45 @@ sdlpp::GPUShader Application::loadShader(const fs::path& path, sdlpp::GPUShaderC
|
|||||||
shader.create(mDevice, args);
|
shader.create(mDevice, args);
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdlpp::GPUTexture Application::loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args)
|
||||||
|
{
|
||||||
|
const Bitmap bitmap = loadBitmap(mFileSystem.getPath(path));
|
||||||
|
inout_args.width = bitmap.width,
|
||||||
|
inout_args.height = bitmap.height;
|
||||||
|
|
||||||
|
sdlpp::GPUTexture texture;
|
||||||
|
texture.create(mDevice, inout_args);
|
||||||
|
uploadTextureData(texture, bitmap);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::uploadTextureData(const sdlpp::GPUTexture& texture, const Bitmap& bitmap) const
|
||||||
|
{
|
||||||
|
sdlpp::GPUTransferBuffer transferBuffer;
|
||||||
|
transferBuffer.create(mDevice, {
|
||||||
|
.usage = sdlpp::GPUTransferBufferUsage::UPLOAD,
|
||||||
|
.size = static_cast<Uint32>(bitmap.pixels.size() * sizeof(Pixel))
|
||||||
|
});
|
||||||
|
void* ptr = transferBuffer.map();
|
||||||
|
std::memcpy(ptr, bitmap.pixels.data(), bitmap.pixels.size() * sizeof(Pixel));
|
||||||
|
transferBuffer.unmap();
|
||||||
|
|
||||||
|
sdlpp::GPUCommandBuffer cmdBuffer = mDevice.acquireCommandBuffer();
|
||||||
|
sdlpp::GPUCopyPass copyPass = cmdBuffer.beginCopyPass();
|
||||||
|
copyPass.uploadToGPUTexture(
|
||||||
|
/* source = */ {
|
||||||
|
.transferBuffer = transferBuffer,
|
||||||
|
.pixelsPerRow = bitmap.width,
|
||||||
|
.rowsPerLayer = bitmap.height
|
||||||
|
},
|
||||||
|
/* destination = */ {
|
||||||
|
.texture = texture,
|
||||||
|
.width = bitmap.width,
|
||||||
|
.height = bitmap.height
|
||||||
|
}
|
||||||
|
);
|
||||||
|
copyPass.end();
|
||||||
|
cmdBuffer.submit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,11 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
sdlpp::GPUShader loadShader(const fs::path& path, sdlpp::GPUShaderCreateArgs args);
|
sdlpp::GPUShader loadShader(const fs::path& path, sdlpp::GPUShaderCreateArgs args);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
sdlpp::GPUTexture loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args);
|
||||||
|
|
||||||
|
void uploadTextureData(const sdlpp::GPUTexture& texture, const struct Bitmap& bitmap) const;
|
||||||
|
|
||||||
template<typename TVertex>
|
template<typename TVertex>
|
||||||
void uploadVertexData(const sdlpp::GPUBuffer& vertexBuffer, std::span<TVertex> vertices) const;
|
void uploadVertexData(const sdlpp::GPUBuffer& vertexBuffer, std::span<TVertex> vertices) const;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include "./0_triangle_with_texcoords/app.hpp"
|
#include "./0_triangle_with_texcoords/app.hpp"
|
||||||
|
#include "./1_textured_quad/app.hpp"
|
||||||
|
|
||||||
#include <mijin/debug/stacktrace.hpp>
|
#include <mijin/debug/stacktrace.hpp>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@ -14,13 +15,15 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (SDL_Init(0) != SDL_TRUE)
|
if (SDL_Init(0) != SDL_TRUE)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Error initializing SDL.");
|
spdlog::error("Error initializing SDL.");
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// make sure app is destructed before shutting down SDL
|
// make sure app is destructed before shutting down SDL
|
||||||
std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TriangleWithTexcoordsApp>();
|
// std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TriangleWithTexcoordsApp>();
|
||||||
|
std::unique_ptr<sdl_gpu_test::Application> app = std::make_unique<sdl_gpu_test::TexturedQuadApp>();
|
||||||
app->run(std::span(const_cast<const char**>(argv), argc));
|
app->run(std::span(const_cast<const char**>(argv), argc));
|
||||||
}
|
}
|
||||||
catch (std::exception& exception)
|
catch (std::exception& exception)
|
||||||
|
@ -49,6 +49,32 @@ public:
|
|||||||
operator THandle*() const noexcept { return mHandle; }
|
operator THandle*() const noexcept { return mHandle; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename THandle, typename TConcrete>
|
||||||
|
class BaseWithDevice : public Base<THandle, TConcrete>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SDL_GPUDevice* mDevice = nullptr;
|
||||||
|
protected:
|
||||||
|
BaseWithDevice() noexcept = default;
|
||||||
|
BaseWithDevice(THandle* handle, SDL_GPUDevice* device) noexcept : Base<THandle, TConcrete>(handle), mDevice(device) {}
|
||||||
|
BaseWithDevice(BaseWithDevice&& other) noexcept : Base<THandle, TConcrete>(std::exchange(other.mHandle, nullptr)),
|
||||||
|
mDevice(std::exchange(other.mDevice, nullptr)){}
|
||||||
|
|
||||||
|
BaseWithDevice& operator=(BaseWithDevice&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
mDevice = std::exchange(other.mDevice, nullptr);
|
||||||
|
Base<THandle, TConcrete>::operator=(std::move(other));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
BaseWithDevice(const BaseWithDevice&) = delete;
|
||||||
|
BaseWithDevice& operator=(const BaseWithDevice&) = delete;
|
||||||
|
auto operator<=>(const BaseWithDevice& other) const noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
class SDLError : public std::runtime_error
|
class SDLError : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace sdlpp
|
namespace sdlpp
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(SDL_bool) == sizeof(bool)); // we assume this in the whole file...
|
||||||
|
|
||||||
//
|
//
|
||||||
// enums
|
// enums
|
||||||
//
|
//
|
||||||
@ -137,6 +139,14 @@ enum class GPUBlendOp
|
|||||||
MAX = SDL_GPU_BLENDOP_MAX
|
MAX = SDL_GPU_BLENDOP_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPUTextureType
|
||||||
|
{
|
||||||
|
TWOD = SDL_GPU_TEXTURETYPE_2D,
|
||||||
|
TWOD_ARRAY = SDL_GPU_TEXTURETYPE_2D_ARRAY,
|
||||||
|
THREED = SDL_GPU_TEXTURETYPE_3D,
|
||||||
|
CUBE = SDL_GPU_TEXTURETYPE_CUBE
|
||||||
|
};
|
||||||
|
|
||||||
enum class GPUTextureFormat
|
enum class GPUTextureFormat
|
||||||
{
|
{
|
||||||
INVALID = SDL_GPU_TEXTUREFORMAT_INVALID,
|
INVALID = SDL_GPU_TEXTUREFORMAT_INVALID,
|
||||||
@ -198,6 +208,25 @@ enum class GPUTextureFormat
|
|||||||
D32_FLOAT_S8_UINT = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT
|
D32_FLOAT_S8_UINT = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPUFilter
|
||||||
|
{
|
||||||
|
NEAREST = SDL_GPU_FILTER_NEAREST,
|
||||||
|
LINEAR = SDL_GPU_FILTER_LINEAR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GPUSamplerMipmapMode
|
||||||
|
{
|
||||||
|
NEAREST = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST,
|
||||||
|
LINEAR = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GPUSamplerAddressMode
|
||||||
|
{
|
||||||
|
REPEAT = SDL_GPU_SAMPLERADDRESSMODE_REPEAT,
|
||||||
|
MIRRORED_REPEAT = SDL_GPU_SAMPLERADDRESSMODE_MIRRORED_REPEAT,
|
||||||
|
CLAMP_TO_EDGE = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE
|
||||||
|
};
|
||||||
|
|
||||||
enum class GPUShaderFormat
|
enum class GPUShaderFormat
|
||||||
{
|
{
|
||||||
PRIVATE = SDL_GPU_SHADERFORMAT_PRIVATE,
|
PRIVATE = SDL_GPU_SHADERFORMAT_PRIVATE,
|
||||||
@ -233,6 +262,21 @@ enum class GPUTransferBufferUsage
|
|||||||
DOWNLOAD = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD
|
DOWNLOAD = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPUSwapchainComposition
|
||||||
|
{
|
||||||
|
SDR = SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
|
||||||
|
SDR_LINEAR = SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR,
|
||||||
|
HDR_EXTENDED_LINEAR = SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR,
|
||||||
|
HDR10_ST2048 = SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2048
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GPUPresentMode
|
||||||
|
{
|
||||||
|
VSYNC = SDL_GPU_PRESENTMODE_VSYNC,
|
||||||
|
IMMEDIATE = SDL_GPU_PRESENTMODE_IMMEDIATE,
|
||||||
|
MAILBOX = SDL_GPU_PRESENTMODE_MAILBOX
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// bitflags
|
// bitflags
|
||||||
//
|
//
|
||||||
@ -274,6 +318,21 @@ struct GPUBufferUsageFlags : mijin::BitFlags<GPUBufferUsageFlags>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUTextureUsageFlags : mijin::BitFlags<GPUTextureUsageFlags>
|
||||||
|
{
|
||||||
|
bool sampler : 1 = false;
|
||||||
|
bool colorTarget : 1 = false;
|
||||||
|
bool depthStencilTarget : 1 = false;
|
||||||
|
bool graphicsStorageRead : 1 = false;
|
||||||
|
bool computeStorageRead : 1 = false;
|
||||||
|
bool computeStorageWrite : 1 = false;
|
||||||
|
|
||||||
|
explicit operator SDL_GPUTextureUsageFlags() const noexcept
|
||||||
|
{
|
||||||
|
return std::bit_cast<std::uint8_t>(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// structs
|
// structs
|
||||||
//
|
//
|
||||||
@ -432,8 +491,33 @@ struct GPUBufferRegion
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(GPUBufferRegion) == sizeof(SDL_GPUBufferRegion));
|
static_assert(sizeof(GPUBufferRegion) == sizeof(SDL_GPUBufferRegion));
|
||||||
|
|
||||||
|
struct GPUTextureTransferInfo
|
||||||
|
{
|
||||||
|
SDL_GPUTransferBuffer* transferBuffer;
|
||||||
|
Uint32 offset = 0;
|
||||||
|
Uint32 pixelsPerRow;
|
||||||
|
Uint32 rowsPerLayer;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUTextureTransferInfo) == sizeof(SDL_GPUTextureTransferInfo));
|
||||||
|
|
||||||
|
struct GPUTextureRegion
|
||||||
|
{
|
||||||
|
SDL_GPUTexture* texture;
|
||||||
|
Uint32 mipLevel = 0;
|
||||||
|
Uint32 layer = 0;
|
||||||
|
Uint32 x = 0;
|
||||||
|
Uint32 y = 0;
|
||||||
|
Uint32 z = 0;
|
||||||
|
Uint32 width;
|
||||||
|
Uint32 height = 1;
|
||||||
|
Uint32 depth = 1;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUTextureRegion) == sizeof(SDL_GPUTextureRegion));
|
||||||
|
|
||||||
using GPUBufferBinding = SDL_GPUBufferBinding;
|
using GPUBufferBinding = SDL_GPUBufferBinding;
|
||||||
|
|
||||||
|
using GPUTextureSamplerBinding = SDL_GPUTextureSamplerBinding;
|
||||||
|
|
||||||
//
|
//
|
||||||
// classes
|
// classes
|
||||||
//
|
//
|
||||||
@ -492,6 +576,21 @@ public:
|
|||||||
bindVertexBuffers({&binding, 1}, offset);
|
bindVertexBuffers({&binding, 1}, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bindFragmentSamplers(std::span<const GPUTextureSamplerBinding> textureSamplerBindings, Uint32 firstSlot = 0) const noexcept
|
||||||
|
{
|
||||||
|
SDL_BindGPUFragmentSamplers(
|
||||||
|
/* render_pass = */ mHandle,
|
||||||
|
/* first_slot = */ firstSlot,
|
||||||
|
/* texture_sampler_bindings = */ textureSamplerBindings.data(),
|
||||||
|
/* num_bindings = */ static_cast<Uint32>(textureSamplerBindings.size())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindFragmentSampler(const GPUTextureSamplerBinding& binding, Uint32 offset = 0) const noexcept
|
||||||
|
{
|
||||||
|
bindFragmentSamplers({&binding, 1}, offset);
|
||||||
|
}
|
||||||
|
|
||||||
void drawPrimitives(const GPUDrawPrimitivesArgs& args) const noexcept
|
void drawPrimitives(const GPUDrawPrimitivesArgs& args) const noexcept
|
||||||
{
|
{
|
||||||
SDL_DrawGPUPrimitives(mHandle, args.numVertices, args.numInstances, args.firstVertex, args.firstInstance);
|
SDL_DrawGPUPrimitives(mHandle, args.numVertices, args.numInstances, args.firstVertex, args.firstInstance);
|
||||||
@ -536,26 +635,67 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uploadToGPUTexture(const GPUTextureTransferInfo& source, const GPUTextureRegion& destination, bool cycle = false)
|
||||||
|
{
|
||||||
|
SDL_UploadToGPUTexture(
|
||||||
|
/* copy_pass = */ mHandle,
|
||||||
|
/* source = */ std::bit_cast<const SDL_GPUTextureTransferInfo*>(&source),
|
||||||
|
/* destination = */ std::bit_cast<const SDL_GPUTextureRegion*>(&destination),
|
||||||
|
/* cycle = */ cycle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
friend class GPUCommandBuffer;
|
friend class GPUCommandBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUTexture : public Base<SDL_GPUTexture, GPUTexture>
|
struct GPUTextureCreateArgs
|
||||||
|
{
|
||||||
|
GPUTextureType type = GPUTextureType::TWOD;
|
||||||
|
GPUTextureFormat format = GPUTextureFormat::R8G8B8A8_UNORM;
|
||||||
|
GPUTextureUsageFlags usage;
|
||||||
|
Uint32 width = 1;
|
||||||
|
Uint32 height = 1;
|
||||||
|
Uint32 layerCountOrDepth = 1;
|
||||||
|
Uint32 numLevels = 1;
|
||||||
|
GPUSampleCount sampleCount = GPUSampleCount::ONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUTexture : public BaseWithDevice<SDL_GPUTexture, GPUTexture>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SDL_GPUDevice* mDevice = nullptr;
|
|
||||||
public:
|
public:
|
||||||
GPUTexture() noexcept = default;
|
GPUTexture() noexcept = default;
|
||||||
GPUTexture(const GPUTexture&) = delete;
|
GPUTexture(const GPUTexture&) = delete;
|
||||||
GPUTexture(GPUTexture&& other) noexcept : Base(std::move(other)) {}
|
GPUTexture(GPUTexture&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
GPUTexture& operator=(const GPUTexture&) = delete;
|
GPUTexture& operator=(const GPUTexture&) = delete;
|
||||||
GPUTexture& operator=(GPUTexture&& other) noexcept
|
GPUTexture& operator=(GPUTexture&& other) noexcept
|
||||||
{
|
{
|
||||||
Base::operator=(std::move(other));
|
BaseWithDevice::operator=(std::move(other));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto operator<=>(const GPUTexture& other) const noexcept = default;
|
auto operator<=>(const GPUTexture& other) const noexcept = default;
|
||||||
|
|
||||||
|
void create(SDL_GPUDevice* device, const GPUTextureCreateArgs& args)
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "GPUTexture has already been created.");
|
||||||
|
const SDL_GPUTextureCreateInfo createInfo = {
|
||||||
|
.type = static_cast<SDL_GPUTextureType>(args.type),
|
||||||
|
.format = static_cast<SDL_GPUTextureFormat>(args.format),
|
||||||
|
.usage = static_cast<SDL_GPUTextureUsageFlags>(args.usage),
|
||||||
|
.width = args.width,
|
||||||
|
.height = args.height,
|
||||||
|
.layer_count_or_depth = args.layerCountOrDepth,
|
||||||
|
.num_levels = args.numLevels,
|
||||||
|
.sample_count = static_cast<SDL_GPUSampleCount>(args.sampleCount)
|
||||||
|
};
|
||||||
|
mHandle = SDL_CreateGPUTexture(device, &createInfo);
|
||||||
|
if (mHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
void destroy() noexcept
|
void destroy() noexcept
|
||||||
{
|
{
|
||||||
if (mHandle != nullptr)
|
if (mHandle != nullptr)
|
||||||
@ -573,6 +713,75 @@ public:
|
|||||||
friend class GPUCommandBuffer;
|
friend class GPUCommandBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUSamplerCreateArgs
|
||||||
|
{
|
||||||
|
GPUFilter minFilter = GPUFilter::NEAREST;
|
||||||
|
GPUFilter magFilter = GPUFilter::LINEAR;
|
||||||
|
GPUSamplerMipmapMode mipmapMode = GPUSamplerMipmapMode::LINEAR;
|
||||||
|
GPUSamplerAddressMode addressModeU = GPUSamplerAddressMode::REPEAT;
|
||||||
|
GPUSamplerAddressMode addressModeV = GPUSamplerAddressMode::REPEAT;
|
||||||
|
GPUSamplerAddressMode addressModeW = GPUSamplerAddressMode::REPEAT;
|
||||||
|
float mipLodBias = 0.f;
|
||||||
|
float maxAnisotropy = 1.f;
|
||||||
|
bool enableAnisotropy = false;
|
||||||
|
bool enableCompare = false;
|
||||||
|
GPUCompareOp compareOp;
|
||||||
|
float minLod = 0.f;
|
||||||
|
float maxLod = 1.f;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUSampler : public BaseWithDevice<SDL_GPUSampler, GPUSampler>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPUSampler() noexcept = default;
|
||||||
|
GPUSampler(const GPUSampler&) = delete;
|
||||||
|
GPUSampler(GPUSampler&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUSampler& operator=(const GPUSampler&) = delete;
|
||||||
|
GPUSampler& operator=(GPUSampler&& other) noexcept
|
||||||
|
{
|
||||||
|
BaseWithDevice::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUSampler& other) const noexcept = default;
|
||||||
|
|
||||||
|
void create(SDL_GPUDevice* device, const GPUSamplerCreateArgs& args)
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "GPUSampler has already been created.");
|
||||||
|
const SDL_GPUSamplerCreateInfo createInfo = {
|
||||||
|
.min_filter = static_cast<SDL_GPUFilter>(args.minFilter),
|
||||||
|
.mag_filter = static_cast<SDL_GPUFilter>(args.magFilter),
|
||||||
|
.mipmap_mode = static_cast<SDL_GPUSamplerMipmapMode>(args.mipmapMode),
|
||||||
|
.address_mode_u = static_cast<SDL_GPUSamplerAddressMode>(args.addressModeU),
|
||||||
|
.address_mode_v = static_cast<SDL_GPUSamplerAddressMode>(args.addressModeV),
|
||||||
|
.address_mode_w = static_cast<SDL_GPUSamplerAddressMode>(args.addressModeW),
|
||||||
|
.mip_lod_bias = args.mipLodBias,
|
||||||
|
.max_anisotropy = args.maxAnisotropy,
|
||||||
|
.enable_anisotropy = args.enableAnisotropy,
|
||||||
|
.enable_compare = args.enableCompare,
|
||||||
|
.compare_op = static_cast<SDL_GPUCompareOp>(args.compareOp),
|
||||||
|
.min_lod = args.minLod,
|
||||||
|
.max_lod = args.maxLod
|
||||||
|
};
|
||||||
|
mHandle = SDL_CreateGPUSampler(device, &createInfo);
|
||||||
|
if (mHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
if (mHandle != nullptr)
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUSampler(mDevice, mHandle);
|
||||||
|
mHandle = nullptr;
|
||||||
|
mDevice = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct GPUBeginRenderPassArgs
|
struct GPUBeginRenderPassArgs
|
||||||
{
|
{
|
||||||
std::span<const GPUColorTargetInfo> colorTargetInfos;
|
std::span<const GPUColorTargetInfo> colorTargetInfos;
|
||||||
@ -697,6 +906,28 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool windowSupportsSwapchainComposition(SDL_Window* window, GPUSwapchainComposition swapchainComposition) const noexcept
|
||||||
|
{
|
||||||
|
return SDL_WindowSupportsGPUSwapchainComposition(mHandle, window, static_cast<SDL_GPUSwapchainComposition>(swapchainComposition));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool windowSupportsPresentMode(SDL_Window* window, GPUPresentMode presentMode) const noexcept
|
||||||
|
{
|
||||||
|
return SDL_WindowSupportsGPUPresentMode(mHandle, window, static_cast<SDL_GPUPresentMode>(presentMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSwapchainParameters(SDL_Window* window, GPUSwapchainComposition swapchainComposition,
|
||||||
|
GPUPresentMode presentMode) const
|
||||||
|
{
|
||||||
|
if (!SDL_SetGPUSwapchainParameters(mHandle, window, static_cast<SDL_GPUSwapchainComposition>(swapchainComposition),
|
||||||
|
static_cast<SDL_GPUPresentMode>(presentMode)))
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
GPUTextureFormat getSwapchainTextureFormat(SDL_Window* window) const
|
GPUTextureFormat getSwapchainTextureFormat(SDL_Window* window) const
|
||||||
{
|
{
|
||||||
@ -724,20 +955,17 @@ struct GPUGraphicsPipelineCreateArgs
|
|||||||
GPUGraphicsPipelineTargetInfo targetInfo;
|
GPUGraphicsPipelineTargetInfo targetInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUGraphicsPipeline : public Base<SDL_GPUGraphicsPipeline, GPUGraphicsPipeline>
|
class GPUGraphicsPipeline : public BaseWithDevice<SDL_GPUGraphicsPipeline, GPUGraphicsPipeline>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SDL_GPUDevice* mDevice = nullptr;
|
|
||||||
public:
|
public:
|
||||||
GPUGraphicsPipeline() noexcept = default;
|
GPUGraphicsPipeline() noexcept = default;
|
||||||
GPUGraphicsPipeline(const GPUGraphicsPipeline&) = delete;
|
GPUGraphicsPipeline(const GPUGraphicsPipeline&) = delete;
|
||||||
GPUGraphicsPipeline(GPUGraphicsPipeline&& other) noexcept : Base(std::move(other)) {}
|
GPUGraphicsPipeline(GPUGraphicsPipeline&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
GPUGraphicsPipeline& operator=(const GPUGraphicsPipeline&) = delete;
|
GPUGraphicsPipeline& operator=(const GPUGraphicsPipeline&) = delete;
|
||||||
GPUGraphicsPipeline& operator=(GPUGraphicsPipeline&& other) noexcept
|
GPUGraphicsPipeline& operator=(GPUGraphicsPipeline&& other) noexcept
|
||||||
{
|
{
|
||||||
Base::operator=(std::move(other));
|
BaseWithDevice::operator=(std::move(other));
|
||||||
mDevice = other.mDevice;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto operator<=>(const GPUGraphicsPipeline& other) const noexcept = default;
|
auto operator<=>(const GPUGraphicsPipeline& other) const noexcept = default;
|
||||||
@ -813,19 +1041,17 @@ struct GPUShaderCreateArgs
|
|||||||
Uint32 numUniformBuffers = 0;
|
Uint32 numUniformBuffers = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUShader : public Base<SDL_GPUShader, GPUShader>
|
class GPUShader : public BaseWithDevice<SDL_GPUShader, GPUShader>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SDL_GPUDevice* mDevice = nullptr;
|
|
||||||
public:
|
public:
|
||||||
GPUShader() noexcept = default;
|
GPUShader() noexcept = default;
|
||||||
GPUShader(const GPUShader&) = delete;
|
GPUShader(const GPUShader&) = delete;
|
||||||
GPUShader(GPUShader&& other) noexcept : Base(std::move(other)) {}
|
GPUShader(GPUShader&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
GPUShader& operator=(const GPUShader&) = delete;
|
GPUShader& operator=(const GPUShader&) = delete;
|
||||||
GPUShader& operator=(GPUShader&& other) noexcept
|
GPUShader& operator=(GPUShader&& other) noexcept
|
||||||
{
|
{
|
||||||
Base::operator=(std::move(other));
|
BaseWithDevice::operator=(std::move(other));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto operator<=>(const GPUShader& other) const noexcept = default;
|
auto operator<=>(const GPUShader& other) const noexcept = default;
|
||||||
@ -870,19 +1096,17 @@ struct GPUBufferCreateArgs
|
|||||||
Uint32 size;
|
Uint32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUBuffer : public Base<SDL_GPUBuffer, GPUBuffer>
|
class GPUBuffer : public BaseWithDevice<SDL_GPUBuffer, GPUBuffer>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SDL_GPUDevice* mDevice = nullptr;
|
|
||||||
public:
|
public:
|
||||||
GPUBuffer() noexcept = default;
|
GPUBuffer() noexcept = default;
|
||||||
GPUBuffer(const GPUBuffer&) = delete;
|
GPUBuffer(const GPUBuffer&) = delete;
|
||||||
GPUBuffer(GPUBuffer&& other) noexcept : Base(std::move(other)) {}
|
GPUBuffer(GPUBuffer&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
GPUBuffer& operator=(const GPUBuffer&) = delete;
|
GPUBuffer& operator=(const GPUBuffer&) = delete;
|
||||||
GPUBuffer& operator=(GPUBuffer&& other) noexcept
|
GPUBuffer& operator=(GPUBuffer&& other) noexcept
|
||||||
{
|
{
|
||||||
Base::operator=(std::move(other));
|
BaseWithDevice::operator=(std::move(other));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto operator<=>(const GPUBuffer& other) const noexcept = default;
|
auto operator<=>(const GPUBuffer& other) const noexcept = default;
|
||||||
@ -920,19 +1144,17 @@ struct GPUTransferBufferCreateArgs
|
|||||||
Uint32 size;
|
Uint32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPUTransferBuffer : public Base<SDL_GPUTransferBuffer, GPUTransferBuffer>
|
class GPUTransferBuffer : public BaseWithDevice<SDL_GPUTransferBuffer, GPUTransferBuffer>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SDL_GPUDevice* mDevice = nullptr;
|
|
||||||
public:
|
public:
|
||||||
GPUTransferBuffer() noexcept = default;
|
GPUTransferBuffer() noexcept = default;
|
||||||
GPUTransferBuffer(const GPUTransferBuffer&) = delete;
|
GPUTransferBuffer(const GPUTransferBuffer&) = delete;
|
||||||
GPUTransferBuffer(GPUTransferBuffer&& other) noexcept : Base(std::move(other)) {}
|
GPUTransferBuffer(GPUTransferBuffer&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
GPUTransferBuffer& operator=(const GPUTransferBuffer&) = delete;
|
GPUTransferBuffer& operator=(const GPUTransferBuffer&) = delete;
|
||||||
GPUTransferBuffer& operator=(GPUTransferBuffer&& other) noexcept
|
GPUTransferBuffer& operator=(GPUTransferBuffer&& other) noexcept
|
||||||
{
|
{
|
||||||
Base::operator=(std::move(other));
|
BaseWithDevice::operator=(std::move(other));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto operator<=>(const GPUTransferBuffer& other) const noexcept = default;
|
auto operator<=>(const GPUTransferBuffer& other) const noexcept = default;
|
||||||
|
@ -13,7 +13,7 @@ struct WindowFlags : mijin::BitFlags<WindowFlags>
|
|||||||
bool fullscreen : 1; // 0x0000000000000001 /**< window is in fullscreen mode */
|
bool fullscreen : 1; // 0x0000000000000001 /**< window is in fullscreen mode */
|
||||||
bool opengl : 1; // 0x0000000000000002 /**< window usable with OpenGL context */
|
bool opengl : 1; // 0x0000000000000002 /**< window usable with OpenGL context */
|
||||||
bool occluded : 1; // 0x0000000000000004 /**< window is occluded */
|
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 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 borderless : 1; // 0x0000000000000010 /**< no window decoration */
|
||||||
bool resizable : 1; // 0x0000000000000020 /**< window can be resized */
|
bool resizable : 1; // 0x0000000000000020 /**< window can be resized */
|
||||||
bool minimized : 1; // 0x0000000000000040 /**< window is minimized */
|
bool minimized : 1; // 0x0000000000000040 /**< window is minimized */
|
||||||
@ -24,7 +24,7 @@ struct WindowFlags : mijin::BitFlags<WindowFlags>
|
|||||||
bool external : 1; // 0x0000000000000800 /**< window not created by SDL */
|
bool external : 1; // 0x0000000000000800 /**< window not created by SDL */
|
||||||
bool modal : 1; // 0x0000000000001000 /**< window is modal */
|
bool modal : 1; // 0x0000000000001000 /**< window is modal */
|
||||||
bool high_pixel_density : 1; // 0x0000000000002000 /**< window uses high pixel density back buffer if possible */
|
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_capture : 1; // 0x0000000000004000 /**< window has mouse captured (unrelated to MOUSE_GRABBED */
|
||||||
bool mouse_relative_mode : 1; // 0x0000000000008000 /**< window has relative mode enabled */
|
bool mouse_relative_mode : 1; // 0x0000000000008000 /**< window has relative mode enabled */
|
||||||
bool always_on_top : 1; // 0x0000000000010000 /**< window should always be above others */
|
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 utility : 1; // 0x0000000000020000 /**< window should be treated as a utility window, not showing in the task bar and window list */
|
||||||
|
78
private/sdl_gpu_test/util/bitmap.cpp
Normal file
78
private/sdl_gpu_test/util/bitmap.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
#include "./bitmap.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
#define STBI_ASSERT(x) MIJIN_ASSERT(x, #x)
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb_image.h>
|
||||||
|
#undef STB_IMAGE_IMPLEMENTATION
|
||||||
|
#undef STBI_ASSERT
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
int stbiReadCallback(void* user, char* data, int size)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
std::size_t bytesRead = 0;
|
||||||
|
const mijin::StreamError error = stream.readRaw(data, size, {.partial = true}, &bytesRead);
|
||||||
|
if (error != mijin::StreamError::SUCCESS)
|
||||||
|
{
|
||||||
|
// TODO: return what?
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<int>(bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stbiSkipCallback(void* user, int bytes)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
(void) stream.seek(bytes, mijin::SeekMode::RELATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stbiEofCallback(void* user)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
return stream.isAtEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap loadBitmap(const mijin::PathReference& path)
|
||||||
|
{
|
||||||
|
std::unique_ptr<mijin::Stream> stream;
|
||||||
|
mijin::throwOnError(path.open(mijin::FileOpenMode::READ, stream));
|
||||||
|
|
||||||
|
const stbi_io_callbacks callbacks = {
|
||||||
|
.read = &stbiReadCallback,
|
||||||
|
.skip = &stbiSkipCallback,
|
||||||
|
.eof = &stbiEofCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
int width, height, components;
|
||||||
|
stbi_uc* data = stbi_load_from_callbacks(
|
||||||
|
/* clbk = */ &callbacks,
|
||||||
|
/* user = */ stream.get(),
|
||||||
|
/* x = */ &width,
|
||||||
|
/* y = */ &height,
|
||||||
|
/* channels_in_file = */ &components,
|
||||||
|
/* desired_channels = */ 4
|
||||||
|
);
|
||||||
|
if (data == nullptr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::format("Could not load bitmap: {}.", stbi_failure_reason()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Pixel> pixels;
|
||||||
|
pixels.resize(static_cast<std::size_t>(width) * height);
|
||||||
|
std::memcpy(pixels.data(), data, pixels.size() * sizeof(Pixel));
|
||||||
|
return {
|
||||||
|
.width = static_cast<unsigned>(width),
|
||||||
|
.height = static_cast<unsigned>(height),
|
||||||
|
.pixels = std::move(pixels)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
32
private/sdl_gpu_test/util/bitmap.hpp
Normal file
32
private/sdl_gpu_test/util/bitmap.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_BITMAP_HPP_INCLUDED)
|
||||||
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_BITMAP_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <mijin/virtual_filesystem/filesystem.hpp>
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
struct Pixel
|
||||||
|
{
|
||||||
|
std::uint8_t r;
|
||||||
|
std::uint8_t g;
|
||||||
|
std::uint8_t b;
|
||||||
|
std::uint8_t a;
|
||||||
|
};
|
||||||
|
struct Bitmap
|
||||||
|
{
|
||||||
|
unsigned width;
|
||||||
|
unsigned height;
|
||||||
|
std::vector<Pixel> pixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Bitmap loadBitmap(const mijin::PathReference& path);
|
||||||
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_BITMAP_HPP_INCLUDED)
|
Loading…
x
Reference in New Issue
Block a user