Shader compilation, uniforms, vertex buffers and notes.
This commit is contained in:
parent
d6745226a1
commit
660a6cedea
3
.gitignore
vendored
3
.gitignore
vendored
@ -72,3 +72,6 @@ __pycache__/
|
|||||||
|
|
||||||
# Backup files
|
# Backup files
|
||||||
*.bak
|
*.bak
|
||||||
|
|
||||||
|
# Compiled shaders
|
||||||
|
*.spv
|
||||||
|
13
NOTES.md
Normal file
13
NOTES.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
Descriptor sets
|
||||||
|
===
|
||||||
|
- hardcoded in SDL_gpu
|
||||||
|
- for graphics pipelines there are always 4 of them:
|
||||||
|
- 0 are vertex resources (first samplers, then storage images, then storage buffers)
|
||||||
|
- 1 are vertex uniform buffers
|
||||||
|
- 2 are fragment resources (again samplers, storage images and storage buffers)
|
||||||
|
- 3 are fragment uniform buffers
|
||||||
|
- compute has 3 sets:
|
||||||
|
- 0 are read-only resources (samplers, storage images, storage buffers)
|
||||||
|
- 1 are write-only resources (storage images and storage buffers)
|
||||||
|
- 2 are uniform buffers
|
@ -1,5 +1,6 @@
|
|||||||
config = {
|
config = {
|
||||||
'PROJECT_NAME': 'sdl_gpu_test'
|
'PROJECT_NAME': 'sdl_gpu_test',
|
||||||
|
'TOOLS': ['glslang']
|
||||||
}
|
}
|
||||||
env = SConscript('external/scons-plus-plus/SConscript', exports = ['config'])
|
env = SConscript('external/scons-plus-plus/SConscript', exports = ['config'])
|
||||||
env.Append(CPPPATH = [Dir('private'), Dir('public')])
|
env.Append(CPPPATH = [Dir('private'), Dir('public')])
|
||||||
|
15
assets/shaders/glsl/color_from_uniform.frag
Normal file
15
assets/shaders/glsl/color_from_uniform.frag
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0)
|
||||||
|
uniform Parameters
|
||||||
|
{
|
||||||
|
vec4 u_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0)
|
||||||
|
out vec4 o_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
o_color = u_color;
|
||||||
|
}
|
8
assets/shaders/glsl/triangles_from_buffer.vert
Normal file
8
assets/shaders/glsl/triangles_from_buffer.vert
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 i_position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(i_position, 0.0, 1.0);
|
||||||
|
}
|
@ -3,28 +3,34 @@ Import('env')
|
|||||||
|
|
||||||
src_files = Split("""
|
src_files = Split("""
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
||||||
glsl_compiler.cpp
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
shader_files = Split("""
|
||||||
|
#assets/shaders/glsl/color_from_uniform.frag
|
||||||
|
#assets/shaders/glsl/green.frag
|
||||||
|
#assets/shaders/glsl/triangle.vert
|
||||||
|
#assets/shaders/glsl/triangles_from_buffer.vert
|
||||||
|
""")
|
||||||
|
|
||||||
|
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS'])
|
||||||
prog_app = env.UnityProgram(
|
prog_app = env.UnityProgram(
|
||||||
target = env['BIN_DIR'] + '/sdl_gpu_test',
|
target = env['BIN_DIR'] + '/sdl_gpu_test',
|
||||||
source = src_files,
|
source = src_files,
|
||||||
dependencies = {
|
dependencies = {
|
||||||
|
'glm': {},
|
||||||
'mijin': {},
|
'mijin': {},
|
||||||
'SDL': {
|
'SDL': {
|
||||||
'options': {
|
'options': {
|
||||||
'ref': '76ce83801ade3ac922ad5ba6fddc49764c24206a'
|
'ref': '76ce83801ade3ac922ad5ba6fddc49764c24206a'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'spdlog': {},
|
'spdlog': {}
|
||||||
'glslang': {
|
|
||||||
'options': {
|
|
||||||
'enable_hlsl': True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
env.Default(prog_app)
|
env.Default(prog_app)
|
||||||
|
|
||||||
|
for shader_file in shader_files:
|
||||||
|
spv = env.SpirV(source = shader_file, target=f'{shader_file}.spv')
|
||||||
|
env.Default(spv)
|
||||||
|
|
||||||
Return('env')
|
Return('env')
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
#include <mijin/util/scope_guard.hpp>
|
#include <mijin/util/scope_guard.hpp>
|
||||||
#include <mijin/util/variant.hpp>
|
#include <mijin/util/variant.hpp>
|
||||||
#include <mijin/virtual_filesystem/filesystem.hpp>
|
#include <mijin/virtual_filesystem/filesystem.hpp>
|
||||||
@ -7,7 +9,6 @@
|
|||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include <mijin/util/winundef.hpp>
|
#include <mijin/util/winundef.hpp>
|
||||||
|
|
||||||
#include "./glsl_compiler.hpp"
|
|
||||||
#include "./sdlpp/event.hpp"
|
#include "./sdlpp/event.hpp"
|
||||||
#include "./sdlpp/gpu.hpp"
|
#include "./sdlpp/gpu.hpp"
|
||||||
#include "./sdlpp/window.hpp"
|
#include "./sdlpp/window.hpp"
|
||||||
@ -21,8 +22,8 @@ void initFileSystem(const fs::path& executablePath) noexcept
|
|||||||
gFileSystem.emplaceAdapter<mijin::RelativeFileSystemAdapter<mijin::OSFileSystemAdapter>>(executablePath.parent_path() / "assets");
|
gFileSystem.emplaceAdapter<mijin::RelativeFileSystemAdapter<mijin::OSFileSystemAdapter>>(executablePath.parent_path() / "assets");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]] [[maybe_unused]]
|
||||||
std::string getFileContents(const fs::path& path)
|
std::string getFileContentsText(const fs::path& path)
|
||||||
{
|
{
|
||||||
std::unique_ptr<mijin::Stream> stream;
|
std::unique_ptr<mijin::Stream> stream;
|
||||||
mijin::throwOnError(gFileSystem.open(path, mijin::FileOpenMode::READ, stream),
|
mijin::throwOnError(gFileSystem.open(path, mijin::FileOpenMode::READ, stream),
|
||||||
@ -31,12 +32,21 @@ std::string getFileContents(const fs::path& path)
|
|||||||
mijin::throwOnError(stream->readAsString(content), "Error reading file contents.");
|
mijin::throwOnError(stream->readAsString(content), "Error reading file contents.");
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
mijin::TypelessBuffer getFileContentsBinary(const fs::path& path)
|
||||||
|
{
|
||||||
|
std::unique_ptr<mijin::Stream> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
using namespace sdl_gpu_test;
|
|
||||||
|
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -54,12 +64,6 @@ int main(int argc, char* argv[])
|
|||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
};
|
};
|
||||||
|
|
||||||
// init glslang
|
|
||||||
initGLSLCompiler();
|
|
||||||
MIJIN_SCOPE_EXIT {
|
|
||||||
cleanupGLSLCompiler();
|
|
||||||
};
|
|
||||||
|
|
||||||
sdlpp::Window window;
|
sdlpp::Window window;
|
||||||
window.create({
|
window.create({
|
||||||
.title = "SDL_gpu Test",
|
.title = "SDL_gpu Test",
|
||||||
@ -75,23 +79,22 @@ int main(int argc, char* argv[])
|
|||||||
gpuDevice.claimWindow(window);
|
gpuDevice.claimWindow(window);
|
||||||
|
|
||||||
// create vertex shader
|
// create vertex shader
|
||||||
const std::string vertexSource = getFileContents("shaders/glsl/triangle.vert");
|
mijin::TypelessBuffer vertexSpv = getFileContentsBinary("shaders/glsl/triangles_from_buffer.vert.spv");
|
||||||
std::vector<std::uint32_t> vertexSpv = compileGLSL(vertexSource, {.stage = ShaderStage::VERTEX});
|
|
||||||
sdlpp::GPUShader vertexShader;
|
sdlpp::GPUShader vertexShader;
|
||||||
vertexShader.create(gpuDevice, {
|
vertexShader.create(gpuDevice, {
|
||||||
.code = {reinterpret_cast<const Uint8*>(vertexSpv.data()), vertexSpv.size() * sizeof(std::uint32_t)},
|
.code = {static_cast<const Uint8*>(vertexSpv.data()), vertexSpv.byteSize()},
|
||||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||||
.stage = sdlpp::GPUShaderStage::VERTEX
|
.stage = sdlpp::GPUShaderStage::VERTEX
|
||||||
});
|
});
|
||||||
|
|
||||||
// create fragment shader
|
// create fragment shader
|
||||||
const std::string fragmentSource = getFileContents("shaders/glsl/green.frag");
|
mijin::TypelessBuffer fragmentSpv = getFileContentsBinary("shaders/glsl/color_from_uniform.frag.spv");
|
||||||
std::vector<std::uint32_t> fragmentSpv = compileGLSL(fragmentSource, {.stage = ShaderStage::FRAGMENT});
|
|
||||||
sdlpp::GPUShader fragmentShader;
|
sdlpp::GPUShader fragmentShader;
|
||||||
fragmentShader.create(gpuDevice, {
|
fragmentShader.create(gpuDevice, {
|
||||||
.code = {reinterpret_cast<const Uint8*>(fragmentSpv.data()), fragmentSpv.size() * sizeof(std::uint32_t)},
|
.code = {static_cast<const Uint8*>(fragmentSpv.data()), fragmentSpv.byteSize()},
|
||||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||||
.stage = sdlpp::GPUShaderStage::FRAGMENT
|
.stage = sdlpp::GPUShaderStage::FRAGMENT,
|
||||||
|
.numUniformBuffers = 1
|
||||||
});
|
});
|
||||||
|
|
||||||
// create graphics pipeline
|
// create graphics pipeline
|
||||||
@ -101,14 +104,71 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
sdlpp::GPUGraphicsPipeline pipeline;
|
sdlpp::GPUGraphicsPipeline pipeline;
|
||||||
|
std::array vertexBindings = {
|
||||||
|
sdlpp::GPUVertexBinding{
|
||||||
|
.index = 0,
|
||||||
|
.pitch = sizeof(glm::vec2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::array vertexAttributes = {
|
||||||
|
sdlpp::GPUVertexAttribute{
|
||||||
|
.location = 0,
|
||||||
|
.bindingIndex = 0,
|
||||||
|
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||||
|
.offset = 0
|
||||||
|
}
|
||||||
|
};
|
||||||
pipeline.create(gpuDevice, {
|
pipeline.create(gpuDevice, {
|
||||||
.vertexShader = vertexShader,
|
.vertexShader = vertexShader,
|
||||||
.fragmentShader = fragmentShader,
|
.fragmentShader = fragmentShader,
|
||||||
|
.vertexInputState = {
|
||||||
|
.vertexBindings = vertexBindings,
|
||||||
|
.vertexAttributes = vertexAttributes
|
||||||
|
},
|
||||||
.targetInfo = {
|
.targetInfo = {
|
||||||
.colorTargetDescriptions = colorTargetsDescs
|
.colorTargetDescriptions = colorTargetsDescs
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::array vertices =
|
||||||
|
{
|
||||||
|
glm::vec2{-1.f, -1.f},
|
||||||
|
glm::vec2{ 1.f, -1.f},
|
||||||
|
glm::vec2{ 0.f, 1.f}
|
||||||
|
};
|
||||||
|
|
||||||
|
// create vertex buffer
|
||||||
|
sdlpp::GPUBuffer vertexBuffer;
|
||||||
|
vertexBuffer.create(gpuDevice, {
|
||||||
|
.usage = {.vertex = true},
|
||||||
|
.size = sizeof(vertices)
|
||||||
|
});
|
||||||
|
{
|
||||||
|
sdlpp::GPUTransferBuffer transferBuffer;
|
||||||
|
transferBuffer.create(gpuDevice, {
|
||||||
|
.usage = sdlpp::GPUTransferBufferUsage::UPLOAD,
|
||||||
|
.size = sizeof(vertices)
|
||||||
|
});
|
||||||
|
void* ptr = transferBuffer.map();
|
||||||
|
std::memcpy(ptr, vertices.data(), sizeof(vertices));
|
||||||
|
transferBuffer.unmap();
|
||||||
|
|
||||||
|
sdlpp::GPUCommandBuffer cmdBuffer = gpuDevice.acquireCommandBuffer();
|
||||||
|
sdlpp::GPUCopyPass copyPass = cmdBuffer.beginCopyPass();
|
||||||
|
copyPass.uploadToGPUBuffer(
|
||||||
|
/* source = */ {
|
||||||
|
.transferBuffer = transferBuffer
|
||||||
|
},
|
||||||
|
/* destination = */ {
|
||||||
|
.buffer = vertexBuffer,
|
||||||
|
.size = sizeof(vertices)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
copyPass.end();
|
||||||
|
cmdBuffer.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while(running)
|
while(running)
|
||||||
{
|
{
|
||||||
@ -132,7 +192,10 @@ int main(int argc, char* argv[])
|
|||||||
sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({
|
sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({
|
||||||
.colorTargetInfos = colorTargets
|
.colorTargetInfos = colorTargets
|
||||||
});
|
});
|
||||||
|
static const glm::vec4 BLUE(0.f, 0.f, 1.f, 1.f);
|
||||||
|
cmdBuffer.pushFragmentUniformData(0, std::span(&BLUE, 1));
|
||||||
renderPass.bindGraphicsPipeline(pipeline);
|
renderPass.bindGraphicsPipeline(pipeline);
|
||||||
|
renderPass.bindVertexBuffer({.buffer = vertexBuffer});
|
||||||
renderPass.drawPrimitives({.numVertices = 3});
|
renderPass.drawPrimitives({.numVertices = 3});
|
||||||
|
|
||||||
renderPass.end();
|
renderPass.end();
|
||||||
|
@ -227,6 +227,12 @@ enum class GPUStoreOp
|
|||||||
DONT_CARE = SDL_GPU_STOREOP_DONT_CARE
|
DONT_CARE = SDL_GPU_STOREOP_DONT_CARE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPUTransferBufferUsage
|
||||||
|
{
|
||||||
|
UPLOAD = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
|
||||||
|
DOWNLOAD = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// bitflags
|
// bitflags
|
||||||
//
|
//
|
||||||
@ -253,6 +259,21 @@ struct GPUColorComponentFlags : mijin::BitFlags<GPUColorComponentFlags>
|
|||||||
bool a : 1 = false;
|
bool a : 1 = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUBufferUsageFlags : mijin::BitFlags<GPUBufferUsageFlags>
|
||||||
|
{
|
||||||
|
bool vertex : 1 = false;
|
||||||
|
bool index : 1 = false;
|
||||||
|
bool indirect : 1 = false;
|
||||||
|
bool graphicsStorageRead : 1 = false;
|
||||||
|
bool computeStorageRead : 1 = false;
|
||||||
|
bool computeStorageWrite : 1 = false;
|
||||||
|
|
||||||
|
explicit operator SDL_GPUBufferUsageFlags() const noexcept
|
||||||
|
{
|
||||||
|
return std::bit_cast<std::uint8_t>(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// structs
|
// structs
|
||||||
//
|
//
|
||||||
@ -396,6 +417,23 @@ struct GPUDepthStencilTargetInfo
|
|||||||
static_assert(sizeof(GPUDepthStencilTargetInfo) == sizeof(SDL_GPUDepthStencilTargetInfo)
|
static_assert(sizeof(GPUDepthStencilTargetInfo) == sizeof(SDL_GPUDepthStencilTargetInfo)
|
||||||
&& alignof(GPUDepthStencilTargetInfo) == alignof(SDL_GPUDepthStencilTargetInfo));
|
&& alignof(GPUDepthStencilTargetInfo) == alignof(SDL_GPUDepthStencilTargetInfo));
|
||||||
|
|
||||||
|
struct GPUTransferBufferLocation
|
||||||
|
{
|
||||||
|
SDL_GPUTransferBuffer* transferBuffer;
|
||||||
|
Uint32 offset = 0;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUTransferBufferLocation) == sizeof(SDL_GPUTransferBufferLocation));
|
||||||
|
|
||||||
|
struct GPUBufferRegion
|
||||||
|
{
|
||||||
|
SDL_GPUBuffer* buffer;
|
||||||
|
Uint32 offset = 0;
|
||||||
|
Uint32 size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUBufferRegion) == sizeof(SDL_GPUBufferRegion));
|
||||||
|
|
||||||
|
using GPUBufferBinding = SDL_GPUBufferBinding;
|
||||||
|
|
||||||
//
|
//
|
||||||
// classes
|
// classes
|
||||||
//
|
//
|
||||||
@ -439,6 +477,21 @@ public:
|
|||||||
SDL_BindGPUGraphicsPipeline(mHandle, pipeline);
|
SDL_BindGPUGraphicsPipeline(mHandle, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bindVertexBuffers(std::span<const GPUBufferBinding> bindings, Uint32 firstBinding = 0) const noexcept
|
||||||
|
{
|
||||||
|
SDL_BindGPUVertexBuffers(
|
||||||
|
/* render_pass = */ mHandle,
|
||||||
|
/* first_binding = */ firstBinding,
|
||||||
|
/* bindings = */ bindings.data(),
|
||||||
|
/* num_bindings = */ static_cast<Uint32>(bindings.size())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindVertexBuffer(const GPUBufferBinding& binding, Uint32 offset = 0) const noexcept
|
||||||
|
{
|
||||||
|
bindVertexBuffers({&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);
|
||||||
@ -447,6 +500,45 @@ public:
|
|||||||
friend class GPUCommandBuffer;
|
friend class GPUCommandBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GPUCopyPass : public Base<SDL_GPUCopyPass, GPUCopyPass>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPUCopyPass() noexcept = default;
|
||||||
|
GPUCopyPass(const GPUCopyPass&) = delete;
|
||||||
|
GPUCopyPass(GPUCopyPass&& other) noexcept : Base(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUCopyPass& operator=(const GPUCopyPass&) = delete;
|
||||||
|
GPUCopyPass& operator=(GPUCopyPass&& other) noexcept
|
||||||
|
{
|
||||||
|
Base::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUCopyPass& other) const noexcept = default;
|
||||||
|
|
||||||
|
void end() noexcept
|
||||||
|
{
|
||||||
|
SDL_EndGPUCopyPass(mHandle);
|
||||||
|
mHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "Copypass has not been ended.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void uploadToGPUBuffer(const GPUTransferBufferLocation& source, const GPUBufferRegion& destination, bool cycle = false)
|
||||||
|
{
|
||||||
|
SDL_UploadToGPUBuffer(
|
||||||
|
/* copy_pass = */ mHandle,
|
||||||
|
/* source = */ std::bit_cast<const SDL_GPUTransferBufferLocation*>(&source),
|
||||||
|
/* destination = */ std::bit_cast<const SDL_GPUBufferRegion*>(&destination),
|
||||||
|
/* cycle = */ cycle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class GPUCommandBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
class GPUTexture : public Base<SDL_GPUTexture, GPUTexture>
|
class GPUTexture : public Base<SDL_GPUTexture, GPUTexture>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -526,6 +618,14 @@ public:
|
|||||||
return renderPass;
|
return renderPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
GPUCopyPass beginCopyPass() const noexcept
|
||||||
|
{
|
||||||
|
GPUCopyPass copyPass;
|
||||||
|
copyPass.mHandle = SDL_BeginGPUCopyPass(mHandle);
|
||||||
|
return copyPass;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
GPUTexture acquireSwapchainTexture(SDL_Window* window, Uint32& outWidth, Uint32& outHeight) noexcept
|
GPUTexture acquireSwapchainTexture(SDL_Window* window, Uint32& outWidth, Uint32& outHeight) noexcept
|
||||||
{
|
{
|
||||||
@ -534,6 +634,17 @@ public:
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TData>
|
||||||
|
void pushFragmentUniformData(Uint32 slotIndex, std::span<const TData> data) const noexcept
|
||||||
|
{
|
||||||
|
SDL_PushGPUFragmentUniformData(
|
||||||
|
/* command_buffer = */ mHandle,
|
||||||
|
/* slot_index = */ slotIndex,
|
||||||
|
/* data = */ data.data(),
|
||||||
|
/* length = */ data.size_bytes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
friend class GPUDevice;
|
friend class GPUDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -752,6 +863,116 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUBufferCreateArgs
|
||||||
|
{
|
||||||
|
GPUBufferUsageFlags usage;
|
||||||
|
Uint32 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUBuffer : public Base<SDL_GPUBuffer, GPUBuffer>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SDL_GPUDevice* mDevice = nullptr;
|
||||||
|
public:
|
||||||
|
GPUBuffer() noexcept = default;
|
||||||
|
GPUBuffer(const GPUBuffer&) = delete;
|
||||||
|
GPUBuffer(GPUBuffer&& other) noexcept : Base(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUBuffer& operator=(const GPUBuffer&) = delete;
|
||||||
|
GPUBuffer& operator=(GPUBuffer&& other) noexcept
|
||||||
|
{
|
||||||
|
Base::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUBuffer& other) const noexcept = default;
|
||||||
|
|
||||||
|
void create(SDL_GPUDevice* device, const GPUBufferCreateArgs& args)
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "GPUBuffer has already been created.");
|
||||||
|
const SDL_GPUBufferCreateInfo createInfo = {
|
||||||
|
.usage = static_cast<SDL_GPUBufferUsageFlags>(args.usage),
|
||||||
|
.size = args.size,
|
||||||
|
.props = 0
|
||||||
|
};
|
||||||
|
mHandle = SDL_CreateGPUBuffer(device, &createInfo);
|
||||||
|
if (mHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
if (mHandle != nullptr)
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUBuffer(mDevice, mHandle);
|
||||||
|
mHandle = nullptr;
|
||||||
|
mDevice = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GPUTransferBufferCreateArgs
|
||||||
|
{
|
||||||
|
GPUTransferBufferUsage usage;
|
||||||
|
Uint32 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUTransferBuffer : public Base<SDL_GPUTransferBuffer, GPUTransferBuffer>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SDL_GPUDevice* mDevice = nullptr;
|
||||||
|
public:
|
||||||
|
GPUTransferBuffer() noexcept = default;
|
||||||
|
GPUTransferBuffer(const GPUTransferBuffer&) = delete;
|
||||||
|
GPUTransferBuffer(GPUTransferBuffer&& other) noexcept : Base(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUTransferBuffer& operator=(const GPUTransferBuffer&) = delete;
|
||||||
|
GPUTransferBuffer& operator=(GPUTransferBuffer&& other) noexcept
|
||||||
|
{
|
||||||
|
Base::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUTransferBuffer& other) const noexcept = default;
|
||||||
|
|
||||||
|
void create(SDL_GPUDevice* device, const GPUTransferBufferCreateArgs& args)
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "GPUTransferBuffer has already been created.");
|
||||||
|
const SDL_GPUTransferBufferCreateInfo createInfo = {
|
||||||
|
.usage = static_cast<SDL_GPUTransferBufferUsage>(args.usage),
|
||||||
|
.size = args.size,
|
||||||
|
.props = 0
|
||||||
|
};
|
||||||
|
mHandle = SDL_CreateGPUTransferBuffer(device, &createInfo);
|
||||||
|
if (mHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
if (mHandle != nullptr)
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUTransferBuffer(mDevice, mHandle);
|
||||||
|
mHandle = nullptr;
|
||||||
|
mDevice = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* map(bool cycle = false) noexcept
|
||||||
|
{
|
||||||
|
return SDL_MapGPUTransferBuffer(mDevice, mHandle, cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap() noexcept
|
||||||
|
{
|
||||||
|
SDL_UnmapGPUTransferBuffer(mDevice, mHandle);
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace sdlpp
|
} // namespace sdlpp
|
||||||
|
|
||||||
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED)
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SDLPP_GPU_HPP_INCLUDED)
|
||||||
|
12
site_scons/site_tools/glslang.py
Normal file
12
site_scons/site_tools/glslang.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
from SCons.Script import *
|
||||||
|
|
||||||
|
def exists(env: Environment) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def generate(env : Environment):
|
||||||
|
glslang_spv_builder = Builder(
|
||||||
|
action = '$GLSLANG -V -o $TARGET $SOURCE'
|
||||||
|
)
|
||||||
|
env['GLSLANG'] = 'glslang'
|
||||||
|
env.Append(BUILDERS={'SpirV': glslang_spv_builder})
|
Loading…
x
Reference in New Issue
Block a user