Added simple post-processing.
This commit is contained in:
parent
559ee5f3c3
commit
16135d8fcd
19
assets/shaders/glsl/post_process.comp
Normal file
19
assets/shaders/glsl/post_process.comp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout(local_size_x = 16, local_size_y = 16, local_size_x = 1) in;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0, rgba8) uniform readonly image2D u_sourceImage;
|
||||||
|
layout(set = 1, binding = 0, rgba8) uniform writeonly image2D u_targetImage;
|
||||||
|
|
||||||
|
float luma(vec4 color)
|
||||||
|
{
|
||||||
|
return dot(color.rgb, vec3(0.299, 0.587, 0.114));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
const ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
|
||||||
|
const vec4 pixel = imageLoad(u_sourceImage, uv);
|
||||||
|
const float lum = luma(pixel);
|
||||||
|
imageStore(u_targetImage, uv, vec4(lum, lum, lum, 1.0));
|
||||||
|
}
|
@ -121,11 +121,7 @@ void InputApp::init(const AppInitArgs& args)
|
|||||||
mSampler.create(mDevice, {});
|
mSampler.create(mDevice, {});
|
||||||
|
|
||||||
// open gamepad
|
// open gamepad
|
||||||
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
mGamepad = openFirstGamepad();
|
||||||
if (!gamepads.empty())
|
|
||||||
{
|
|
||||||
mGamepad.open(gamepads[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputApp::update(const AppUpdateArgs& args)
|
void InputApp::update(const AppUpdateArgs& args)
|
||||||
|
@ -64,11 +64,7 @@ void UIApp::init(const AppInitArgs& args)
|
|||||||
mSampler.create(mDevice, {});
|
mSampler.create(mDevice, {});
|
||||||
|
|
||||||
// open gamepad
|
// open gamepad
|
||||||
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
mGamepad = openFirstGamepad();
|
||||||
if (!gamepads.empty())
|
|
||||||
{
|
|
||||||
mGamepad.open(gamepads[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init the UI
|
// init the UI
|
||||||
mWidgetTree.init({.renderer = &mUIRenderer});
|
mWidgetTree.init({.renderer = &mUIRenderer});
|
||||||
|
@ -43,10 +43,7 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
|
|||||||
|
|
||||||
// open gamepad
|
// open gamepad
|
||||||
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
||||||
if (!gamepads.empty())
|
mGamepad = openFirstGamepad();
|
||||||
{
|
|
||||||
mGamepad.open(gamepads[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// init the UI
|
// init the UI
|
||||||
mWidgetTree.init({.renderer = &mUIRenderer});
|
mWidgetTree.init({.renderer = &mUIRenderer});
|
||||||
@ -57,21 +54,10 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
|
|||||||
.posY = 100,
|
.posY = 100,
|
||||||
.textHeight = 20
|
.textHeight = 20
|
||||||
});
|
});
|
||||||
mButton = mWidgetTree.getRootWidget().emplaceChild<Button>({
|
|
||||||
.text = "Click Me!",
|
|
||||||
.posX = 100,
|
|
||||||
.posY = 500
|
|
||||||
});
|
|
||||||
|
|
||||||
// init the scene
|
// init the scene
|
||||||
mScene.init({.renderer = &mSceneRenderer});
|
mScene.init({.renderer = &mSceneRenderer});
|
||||||
loadScene("scenes/test_scene.yml", mScene);
|
loadScene("scenes/test_scene.yml", mScene);
|
||||||
// mScene.getRootNode().emplaceChild<MeshNode>({.mesh = "meshes/cube.obj", .texture = "meshes/cube.png"});
|
|
||||||
|
|
||||||
mButton->clicked.connect([&]()
|
|
||||||
{
|
|
||||||
mButton->setText("Thanks!");
|
|
||||||
});
|
|
||||||
|
|
||||||
mWindow.setRelativeMouseMode(true);
|
mWindow.setRelativeMouseMode(true);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_7_3D_SCENE_APP_HPP_INCLUDED 1
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_7_3D_SCENE_APP_HPP_INCLUDED 1
|
||||||
|
|
||||||
#include "../application.hpp"
|
#include "../application.hpp"
|
||||||
#include "../gui/button.hpp"
|
|
||||||
#include "../gui/label.hpp"
|
#include "../gui/label.hpp"
|
||||||
#include "../gui/widget.hpp"
|
#include "../gui/widget.hpp"
|
||||||
#include "../gui/ui_renderer.hpp"
|
#include "../gui/ui_renderer.hpp"
|
||||||
@ -27,7 +26,6 @@ private:
|
|||||||
Scene mScene;
|
Scene mScene;
|
||||||
|
|
||||||
Label* mLabel = nullptr;
|
Label* mLabel = nullptr;
|
||||||
Button* mButton = nullptr;
|
|
||||||
|
|
||||||
sdlpp::Gamepad mGamepad;
|
sdlpp::Gamepad mGamepad;
|
||||||
Uint32 mLastSwapchainWidth = 1280;
|
Uint32 mLastSwapchainWidth = 1280;
|
||||||
|
263
private/sdl_gpu_test/8_post_process/app.cpp
Normal file
263
private/sdl_gpu_test/8_post_process/app.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
|
||||||
|
#include "./app.hpp"
|
||||||
|
|
||||||
|
#include <numbers>
|
||||||
|
|
||||||
|
#include <glm/mat4x4.hpp>
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
|
#include "../scene/mesh.hpp"
|
||||||
|
#include "../scene/loader.hpp"
|
||||||
|
#include "../sdlpp/keyboard.hpp"
|
||||||
|
#include "../util/bitmap.hpp"
|
||||||
|
#include "../util/mesh.hpp"
|
||||||
|
#include "../util/spdlog_wrapper.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
inline constexpr float PITCH_MIN = -0.49f * std::numbers::pi_v<float>;
|
||||||
|
inline constexpr float PITCH_MAX = 0.49f * std::numbers::pi_v<float>;
|
||||||
|
inline constexpr Uint16 AXIS_DEADZONE = 5000;
|
||||||
|
inline constexpr sdlpp::GPUTextureFormat COLOR_BUFFER_FORMAT = sdlpp::GPUTextureFormat::R32G32B32A32_FLOAT;
|
||||||
|
inline constexpr sdlpp::GPUTextureFormat POSTPROCESS_BUFFER_FORMAT = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::init(const AppInitArgs& args)
|
||||||
|
{
|
||||||
|
Application::init(args);
|
||||||
|
|
||||||
|
// create color buffer
|
||||||
|
mColorBuffer.create(mDevice, {
|
||||||
|
.format = sdlpp::GPUTextureFormat::R32G32B32A32_FLOAT,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.colorTarget = true, .computeStorageRead = true},
|
||||||
|
.width = 1280,
|
||||||
|
.height = 720
|
||||||
|
});
|
||||||
|
|
||||||
|
// create depth buffer
|
||||||
|
mDepthBuffer.create(mDevice, {
|
||||||
|
.format = sdlpp::GPUTextureFormat::D16_UNORM,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.depthStencilTarget = true},
|
||||||
|
.width = 1280,
|
||||||
|
.height = 720
|
||||||
|
});
|
||||||
|
|
||||||
|
// and the target for the compute pass (SDL_gpu doesn't support using the swapchain in compute shaders)
|
||||||
|
mPostProcessBuffer.create(mDevice, {
|
||||||
|
.format = POSTPROCESS_BUFFER_FORMAT,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.computeStorageWrite = true},
|
||||||
|
.width = 1280,
|
||||||
|
.height = 720
|
||||||
|
});
|
||||||
|
|
||||||
|
// init UI renderer
|
||||||
|
mUIRenderer.init(*this);
|
||||||
|
|
||||||
|
// init scene renderer
|
||||||
|
mSceneRenderer.init(*this, {
|
||||||
|
.colorBufferFormat = COLOR_BUFFER_FORMAT
|
||||||
|
});
|
||||||
|
|
||||||
|
// and the post processor
|
||||||
|
mPostProcessor.init(*this);
|
||||||
|
|
||||||
|
// open gamepad
|
||||||
|
mGamepad = openFirstGamepad();
|
||||||
|
|
||||||
|
// init the UI
|
||||||
|
mWidgetTree.init({.renderer = &mUIRenderer});
|
||||||
|
mLabel = mWidgetTree.getRootWidget().emplaceChild<Label>({
|
||||||
|
.text = "Test-Text!\nSecond $f00line$fff?",
|
||||||
|
.color = glm::vec4(0.f, 1.f, 0.f, 1.f),
|
||||||
|
.posX = 100,
|
||||||
|
.posY = 100,
|
||||||
|
.textHeight = 20
|
||||||
|
});
|
||||||
|
|
||||||
|
// init the scene
|
||||||
|
mScene.init({.renderer = &mSceneRenderer});
|
||||||
|
loadScene("scenes/test_scene.yml", mScene);
|
||||||
|
|
||||||
|
mWindow.setRelativeMouseMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::update(const AppUpdateArgs& args)
|
||||||
|
{
|
||||||
|
Application::update(args);
|
||||||
|
|
||||||
|
processInput(args);
|
||||||
|
mLabel->setText(std::format("Pitch: {:.1f}\nYaw: {:.1f}", mPitch, mYaw));
|
||||||
|
mWidgetTree.revalidateWidgets();
|
||||||
|
|
||||||
|
// begin rendering
|
||||||
|
sdlpp::GPUCommandBuffer cmdBuffer = mDevice.acquireCommandBuffer();
|
||||||
|
Uint32 swapchainWidth = 0, swapchainHeight = 0;
|
||||||
|
const sdlpp::GPUTexture swapchainTexture = cmdBuffer.acquireSwapchainTexture(mWindow, swapchainWidth, swapchainHeight);
|
||||||
|
|
||||||
|
if (swapchainWidth != mLastSwapchainWidth || swapchainHeight != mLastSwapchainHeight)
|
||||||
|
{
|
||||||
|
mColorBuffer.destroy();
|
||||||
|
mColorBuffer.create(mDevice, {
|
||||||
|
.format = COLOR_BUFFER_FORMAT,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.colorTarget = true, .computeStorageRead = true},
|
||||||
|
.width = swapchainWidth,
|
||||||
|
.height = swapchainHeight
|
||||||
|
});
|
||||||
|
mDepthBuffer.destroy();
|
||||||
|
mDepthBuffer.create(mDevice, {
|
||||||
|
.format = sdlpp::GPUTextureFormat::D16_UNORM,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.depthStencilTarget = true},
|
||||||
|
.width = swapchainWidth,
|
||||||
|
.height = swapchainHeight
|
||||||
|
});
|
||||||
|
mPostProcessBuffer.destroy();
|
||||||
|
mPostProcessBuffer.create(mDevice, {
|
||||||
|
.format = POSTPROCESS_BUFFER_FORMAT,
|
||||||
|
.usage = sdlpp::GPUTextureUsageFlags{.computeStorageWrite = true},
|
||||||
|
.width = swapchainWidth,
|
||||||
|
.height = swapchainHeight
|
||||||
|
});
|
||||||
|
mLastSwapchainWidth = swapchainWidth;
|
||||||
|
mLastSwapchainHeight = swapchainHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// render the scene
|
||||||
|
mSceneRenderer.render({
|
||||||
|
.camera = {
|
||||||
|
.position = mPosition,
|
||||||
|
.pitch = mPitch,
|
||||||
|
.yaw = mYaw
|
||||||
|
},
|
||||||
|
.cmdBuffer = &cmdBuffer,
|
||||||
|
.targetTexture = &mColorBuffer,
|
||||||
|
.depthTexture = &mDepthBuffer,
|
||||||
|
.targetTextureWidth = swapchainWidth,
|
||||||
|
.targetTextureHeight = swapchainHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
// do the post processing
|
||||||
|
mPostProcessor.execute({
|
||||||
|
.cmdBuffer = &cmdBuffer,
|
||||||
|
.sourceTexture = &mColorBuffer,
|
||||||
|
.targetTexture = &mPostProcessBuffer,
|
||||||
|
.textureWidth = swapchainWidth,
|
||||||
|
.textureHeight = swapchainHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
// copy the result to the swapchain image
|
||||||
|
sdlpp::GPUCopyPass copyPass = cmdBuffer.beginCopyPass();
|
||||||
|
copyPass.copyTextureToTexture(
|
||||||
|
/* source = */ {.texture = mPostProcessBuffer},
|
||||||
|
/* destination = */ {.texture = swapchainTexture},
|
||||||
|
/* width = */ swapchainWidth,
|
||||||
|
/* height = */ swapchainHeight
|
||||||
|
);
|
||||||
|
copyPass.end();
|
||||||
|
|
||||||
|
// render the "UI"
|
||||||
|
mUIRenderer.render({
|
||||||
|
.cmdBuffer = &cmdBuffer,
|
||||||
|
.targetTexture = &swapchainTexture,
|
||||||
|
.targetTextureWidth = swapchainWidth,
|
||||||
|
.targetTextureHeight = swapchainHeight
|
||||||
|
});
|
||||||
|
|
||||||
|
// finalize
|
||||||
|
cmdBuffer.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::handleKeyboardEvent(const sdlpp::KeyboardEvent& event)
|
||||||
|
{
|
||||||
|
switch (event.key)
|
||||||
|
{
|
||||||
|
case SDLK_Q:
|
||||||
|
if (!event.down)
|
||||||
|
{
|
||||||
|
mRunning = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event)
|
||||||
|
{
|
||||||
|
mWidgetTree.notifyMouseMoved(event);
|
||||||
|
|
||||||
|
mYaw -= 0.002f * event.xrel;
|
||||||
|
mPitch -= 0.002f * event.yrel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::handleMouseButtonEvent(const sdlpp::MouseButtonEvent& event)
|
||||||
|
{
|
||||||
|
mWidgetTree.notifyMouseButton(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessApp::processInput(const AppUpdateArgs& args)
|
||||||
|
{
|
||||||
|
glm::vec2 movement = {0.f, 0.f};
|
||||||
|
const std::span<const SDL_bool> keyboardState = sdlpp::getKeyboardState();
|
||||||
|
if (mGamepad)
|
||||||
|
{
|
||||||
|
Sint16 axisValue = mGamepad.getAxis(sdlpp::GamepadAxis::RIGHTX);
|
||||||
|
if (std::abs(axisValue) > AXIS_DEADZONE)
|
||||||
|
{
|
||||||
|
mYaw -= 0.0001f * args.tickSeconds * static_cast<float>(axisValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
axisValue = mGamepad.getAxis(sdlpp::GamepadAxis::RIGHTY);
|
||||||
|
if (std::abs(axisValue) > AXIS_DEADZONE)
|
||||||
|
{
|
||||||
|
mPitch -= 0.0001f * args.tickSeconds * static_cast<float>(axisValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
axisValue = mGamepad.getAxis(sdlpp::GamepadAxis::LEFTY);
|
||||||
|
if (std::abs(axisValue) > AXIS_DEADZONE)
|
||||||
|
{
|
||||||
|
movement.y -= static_cast<float>(axisValue) / static_cast<float>(std::numeric_limits<Sint16>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
axisValue = mGamepad.getAxis(sdlpp::GamepadAxis::LEFTX);
|
||||||
|
if (std::abs(axisValue) > AXIS_DEADZONE)
|
||||||
|
{
|
||||||
|
movement.x += static_cast<float>(axisValue) / static_cast<float>(std::numeric_limits<Sint16>::max());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboardState[SDL_SCANCODE_W])
|
||||||
|
{
|
||||||
|
movement.y += 1.f;
|
||||||
|
}
|
||||||
|
if (keyboardState[SDL_SCANCODE_S])
|
||||||
|
{
|
||||||
|
movement.y -= 1.f;
|
||||||
|
}
|
||||||
|
if (keyboardState[SDL_SCANCODE_A])
|
||||||
|
{
|
||||||
|
movement.x -= 1.f;
|
||||||
|
}
|
||||||
|
if (keyboardState[SDL_SCANCODE_D])
|
||||||
|
{
|
||||||
|
movement.x += 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glm::length2(movement) > 1.f)
|
||||||
|
{
|
||||||
|
movement = glm::normalize(movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPosition.x -= 2.f * args.tickSeconds * std::sin(mYaw) * movement.y;
|
||||||
|
mPosition.z -= 2.f * args.tickSeconds * std::cos(mYaw) * movement.y;
|
||||||
|
|
||||||
|
mPosition.x += 2.f * args.tickSeconds * std::cos(mYaw) * movement.x;
|
||||||
|
mPosition.z -= 2.f * args.tickSeconds * std::sin(mYaw) * movement.x;
|
||||||
|
|
||||||
|
while (mYaw >= 2.f * std::numbers::pi) { mYaw -= 2.f * std::numbers::pi_v<float>; }
|
||||||
|
while (mYaw < 0.f) { mYaw += 2.f * std::numbers::pi_v<float>; }
|
||||||
|
mPitch = std::clamp(mPitch, PITCH_MIN, PITCH_MAX);
|
||||||
|
}
|
||||||
|
}
|
52
private/sdl_gpu_test/8_post_process/app.hpp
Normal file
52
private/sdl_gpu_test/8_post_process/app.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_8_POST_PROCESS_APP_HPP_INCLUDED)
|
||||||
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_8_POST_PROCESS_APP_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include "../application.hpp"
|
||||||
|
#include "../gui/label.hpp"
|
||||||
|
#include "../gui/widget.hpp"
|
||||||
|
#include "../gui/ui_renderer.hpp"
|
||||||
|
#include "../post_process/post_processor.hpp"
|
||||||
|
#include "../scene/scene.hpp"
|
||||||
|
#include "../scene/scene_renderer.hpp"
|
||||||
|
#include "../sdlpp/gamepad.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
class PostProcessApp : public Application
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
sdlpp::GPUTexture mColorBuffer;
|
||||||
|
sdlpp::GPUTexture mDepthBuffer;
|
||||||
|
sdlpp::GPUTexture mPostProcessBuffer;
|
||||||
|
|
||||||
|
UIRenderer mUIRenderer;
|
||||||
|
WidgetTree mWidgetTree;
|
||||||
|
|
||||||
|
SceneRenderer mSceneRenderer;
|
||||||
|
Scene mScene;
|
||||||
|
|
||||||
|
PostProcessor mPostProcessor;
|
||||||
|
|
||||||
|
Label* mLabel = nullptr;
|
||||||
|
|
||||||
|
sdlpp::Gamepad mGamepad;
|
||||||
|
Uint32 mLastSwapchainWidth = 1280;
|
||||||
|
Uint32 mLastSwapchainHeight = 720;
|
||||||
|
glm::vec3 mPosition = {5.f, 0.f, -7.f};
|
||||||
|
float mYaw = 1.57f;
|
||||||
|
float mPitch = 0.f;
|
||||||
|
public:
|
||||||
|
void init(const AppInitArgs& args) override;
|
||||||
|
void update(const AppUpdateArgs& args) override;
|
||||||
|
void handleKeyboardEvent(const sdlpp::KeyboardEvent& event) override;
|
||||||
|
void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override;
|
||||||
|
void handleMouseButtonEvent(const sdlpp::MouseButtonEvent&) override;
|
||||||
|
private:
|
||||||
|
void processInput(const AppUpdateArgs& args);
|
||||||
|
};
|
||||||
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_8_POST_PROCESS_APP_HPP_INCLUDED)
|
@ -9,6 +9,7 @@ src_files = Split("""
|
|||||||
gui/label.cpp
|
gui/label.cpp
|
||||||
gui/ui_renderer.cpp
|
gui/ui_renderer.cpp
|
||||||
gui/widget.cpp
|
gui/widget.cpp
|
||||||
|
post_process/post_processor.cpp
|
||||||
scene/loader.cpp
|
scene/loader.cpp
|
||||||
scene/mesh.cpp
|
scene/mesh.cpp
|
||||||
scene/scene.cpp
|
scene/scene.cpp
|
||||||
@ -26,10 +27,12 @@ src_files = Split("""
|
|||||||
5_input/app.cpp
|
5_input/app.cpp
|
||||||
6_ui/app.cpp
|
6_ui/app.cpp
|
||||||
7_3d_scene/app.cpp
|
7_3d_scene/app.cpp
|
||||||
|
8_post_process/app.cpp
|
||||||
""")
|
""")
|
||||||
|
|
||||||
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
|
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
|
||||||
+ env.Glob("#assets/shaders/glsl/*.vert")
|
+ env.Glob("#assets/shaders/glsl/*.vert") \
|
||||||
|
+ env.Glob("#assets/shaders/glsl/*.comp")
|
||||||
|
|
||||||
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS', 'GLM_ENABLE_EXPERIMENTAL'])
|
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS', 'GLM_ENABLE_EXPERIMENTAL'])
|
||||||
prog_app = env.UnityProgram(
|
prog_app = env.UnityProgram(
|
||||||
|
@ -114,6 +114,16 @@ sdlpp::GPUShader Application::loadShader(const fs::path& path, sdlpp::GPUShaderC
|
|||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdlpp::GPUComputePipeline Application::loadComputePipeline(const fs::path& path, sdlpp::GPUComputePipelineCreateArgs args)
|
||||||
|
{
|
||||||
|
mijin::TypelessBuffer source = getFileContentsBinary(path);
|
||||||
|
sdlpp::GPUComputePipeline pipeline;
|
||||||
|
args.code = {static_cast<const Uint8*>(source.data()), source.byteSize()};
|
||||||
|
pipeline.create(mDevice, args);
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sdlpp::GPUTexture Application::loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args)
|
sdlpp::GPUTexture Application::loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args)
|
||||||
{
|
{
|
||||||
const Bitmap bitmap = loadBitmap(mFileSystem.getPath(path));
|
const Bitmap bitmap = loadBitmap(mFileSystem.getPath(path));
|
||||||
@ -159,4 +169,26 @@ void Application::uploadTextureData(const sdlpp::GPUTexture& texture, const Bitm
|
|||||||
copyPass.end();
|
copyPass.end();
|
||||||
cmdBuffer.submit();
|
cmdBuffer.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdlpp::Gamepad Application::openFirstGamepad() const
|
||||||
|
{
|
||||||
|
sdlpp::Gamepad gamepad;
|
||||||
|
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
||||||
|
if (!gamepads.empty())
|
||||||
|
{
|
||||||
|
for (SDL_JoystickID gamepadId : gamepads)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gamepad.open(gamepadId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch(std::runtime_error& err)
|
||||||
|
{
|
||||||
|
spdlog::warn("Error opening gamepad: {}.", err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gamepad;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <mijin/virtual_filesystem/stacked.hpp>
|
#include <mijin/virtual_filesystem/stacked.hpp>
|
||||||
|
|
||||||
#include "./sdlpp/event.hpp"
|
#include "./sdlpp/event.hpp"
|
||||||
|
#include "./sdlpp/gamepad.hpp"
|
||||||
#include "./sdlpp/gpu.hpp"
|
#include "./sdlpp/gpu.hpp"
|
||||||
#include "./sdlpp/window.hpp"
|
#include "./sdlpp/window.hpp"
|
||||||
|
|
||||||
@ -74,6 +75,9 @@ 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::GPUComputePipeline loadComputePipeline(const fs::path& path, sdlpp::GPUComputePipelineCreateArgs args);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
sdlpp::GPUTexture loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args);
|
sdlpp::GPUTexture loadTexture(const fs::path& path, sdlpp::GPUTextureCreateArgs& inout_args);
|
||||||
|
|
||||||
@ -81,6 +85,9 @@ public:
|
|||||||
|
|
||||||
void uploadTextureData(const sdlpp::GPUTexture& texture, const struct Bitmap& bitmap) const;
|
void uploadTextureData(const sdlpp::GPUTexture& texture, const struct Bitmap& bitmap) const;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
sdlpp::Gamepad openFirstGamepad() 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;
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
#include "./5_input/app.hpp"
|
#include "./5_input/app.hpp"
|
||||||
#include "./6_ui/app.hpp"
|
#include "./6_ui/app.hpp"
|
||||||
#include "./7_3d_scene/app.hpp"
|
#include "./7_3d_scene/app.hpp"
|
||||||
|
#include "./8_post_process/app.hpp"
|
||||||
#include "./util/spdlog_wrapper.hpp"
|
#include "./util/spdlog_wrapper.hpp"
|
||||||
|
#include "8_post_process/app.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -40,7 +42,8 @@ const std::array APPS = {
|
|||||||
makeAppHelper<sdl_gpu_test::TexturedCubeApp>("textured_cube"),
|
makeAppHelper<sdl_gpu_test::TexturedCubeApp>("textured_cube"),
|
||||||
makeAppHelper<sdl_gpu_test::InputApp>("input"),
|
makeAppHelper<sdl_gpu_test::InputApp>("input"),
|
||||||
makeAppHelper<sdl_gpu_test::UIApp>("ui"),
|
makeAppHelper<sdl_gpu_test::UIApp>("ui"),
|
||||||
makeAppHelper<sdl_gpu_test::ThreeDSceneApp>("3d_scene")
|
makeAppHelper<sdl_gpu_test::ThreeDSceneApp>("3d_scene"),
|
||||||
|
makeAppHelper<sdl_gpu_test::PostProcessApp>("post_process")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
private/sdl_gpu_test/post_process/post_processor.cpp
Normal file
47
private/sdl_gpu_test/post_process/post_processor.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
#include "./post_processor.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
inline constexpr Uint32 LOCAL_SIZE_X = 16;
|
||||||
|
inline constexpr Uint32 LOCAL_SIZE_Y = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessor::init(Application& application)
|
||||||
|
{
|
||||||
|
mApplication = &application;
|
||||||
|
|
||||||
|
createPipeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessor::createPipeline()
|
||||||
|
{
|
||||||
|
mPipeline = mApplication->loadComputePipeline("shaders/glsl/post_process.comp.spv", {
|
||||||
|
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||||
|
.numReadonlyStorageTextures = 1,
|
||||||
|
.numWriteonlyStorageTextures = 1,
|
||||||
|
.threadcountX = LOCAL_SIZE_X,
|
||||||
|
.threadcountY = LOCAL_SIZE_Y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostProcessor::execute(const PostProcessorExecuteArgs& args)
|
||||||
|
{
|
||||||
|
const std::array textueBindings = {
|
||||||
|
sdlpp::GPUStorageTextureWriteOnlyBinding{
|
||||||
|
.texture = *args.targetTexture,
|
||||||
|
.cycle = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sdlpp::GPUComputePass computePass = args.cmdBuffer->beginComputePass({.storageTextureBindings = textueBindings});
|
||||||
|
computePass.bindComputePipeline(mPipeline);
|
||||||
|
computePass.bindStorageTexture(0, *args.sourceTexture);
|
||||||
|
computePass.dispatch(
|
||||||
|
/* groupCountX = */ (args.textureWidth + LOCAL_SIZE_X - 1) / LOCAL_SIZE_X,
|
||||||
|
/* groupCountY = */ (args.textureHeight + LOCAL_SIZE_Y - 1) / LOCAL_SIZE_Y
|
||||||
|
);
|
||||||
|
computePass.end();
|
||||||
|
}
|
||||||
|
}
|
35
private/sdl_gpu_test/post_process/post_processor.hpp
Normal file
35
private/sdl_gpu_test/post_process/post_processor.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_POST_PROCESS_POST_PROCESSOR_HPP_INCLUDED)
|
||||||
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_POST_PROCESS_POST_PROCESSOR_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include "../application.hpp"
|
||||||
|
#include "../sdlpp/gpu.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
struct PostProcessorExecuteArgs
|
||||||
|
{
|
||||||
|
const sdlpp::GPUCommandBuffer* cmdBuffer;
|
||||||
|
const sdlpp::GPUTexture* sourceTexture;
|
||||||
|
const sdlpp::GPUTexture* targetTexture;
|
||||||
|
unsigned textureWidth;
|
||||||
|
unsigned textureHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PostProcessor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Application* mApplication = nullptr;
|
||||||
|
sdlpp::GPUComputePipeline mPipeline;
|
||||||
|
public:
|
||||||
|
void init(Application& application);
|
||||||
|
|
||||||
|
void execute(const PostProcessorExecuteArgs& args);
|
||||||
|
private:
|
||||||
|
void createPipeline();
|
||||||
|
};
|
||||||
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_POST_PROCESS_POST_PROCESSOR_HPP_INCLUDED)
|
@ -24,11 +24,17 @@ struct PerModelParameters
|
|||||||
glm::mat4 modelToWorld;
|
glm::mat4 modelToWorld;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
void SceneRenderer::init(Application& application)
|
void SceneRenderer::init(Application& application, SceneRendererInitArgs args)
|
||||||
{
|
{
|
||||||
mApplication = &application;
|
mApplication = &application;
|
||||||
|
|
||||||
createPipeline();
|
if (args.colorBufferFormat == sdlpp::GPUTextureFormat::INVALID)
|
||||||
|
{
|
||||||
|
// default to render directly to the swapchain
|
||||||
|
args.colorBufferFormat = mApplication->getDevice().getSwapchainTextureFormat(mApplication->getWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
createPipeline(args);
|
||||||
mSampler.create(mApplication->getDevice(), {});
|
mSampler.create(mApplication->getDevice(), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +106,7 @@ void SceneRenderer::render(const SceneRendererRenderArgs& args)
|
|||||||
.texture = *args.targetTexture,
|
.texture = *args.targetTexture,
|
||||||
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
|
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
|
||||||
.loadOp = sdlpp::GPULoadOp::CLEAR,
|
.loadOp = sdlpp::GPULoadOp::CLEAR,
|
||||||
|
.cycle = true
|
||||||
}};
|
}};
|
||||||
sdlpp::GPURenderPass renderPass = args.cmdBuffer->beginRenderPass({
|
sdlpp::GPURenderPass renderPass = args.cmdBuffer->beginRenderPass({
|
||||||
.colorTargetInfos = colorTargets,
|
.colorTargetInfos = colorTargets,
|
||||||
@ -193,7 +200,7 @@ bool SceneRenderer::updateRenderListEntry(mesh_id_t meshId, const RenderListUpda
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneRenderer::createPipeline()
|
void SceneRenderer::createPipeline(const SceneRendererInitArgs& args)
|
||||||
{
|
{
|
||||||
// create shaders
|
// create shaders
|
||||||
const sdlpp::GPUShader vertexShader = mApplication->loadShader("shaders/glsl/scene_renderer.vert.spv", {
|
const sdlpp::GPUShader vertexShader = mApplication->loadShader("shaders/glsl/scene_renderer.vert.spv", {
|
||||||
@ -209,7 +216,7 @@ void SceneRenderer::createPipeline()
|
|||||||
});
|
});
|
||||||
std::array colorTargetsDescs = {
|
std::array colorTargetsDescs = {
|
||||||
sdlpp::GPUColorTargetDescription{
|
sdlpp::GPUColorTargetDescription{
|
||||||
.format = mApplication->getDevice().getSwapchainTextureFormat(mApplication->getWindow()),
|
.format = args.colorBufferFormat,
|
||||||
.blendState = {
|
.blendState = {
|
||||||
.enableBlend = true,
|
.enableBlend = true,
|
||||||
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
||||||
|
@ -37,6 +37,11 @@ struct CameraOptions
|
|||||||
float zFar = 100.f;
|
float zFar = 100.f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SceneRendererInitArgs
|
||||||
|
{
|
||||||
|
sdlpp::GPUTextureFormat colorBufferFormat = sdlpp::GPUTextureFormat::INVALID;
|
||||||
|
};
|
||||||
|
|
||||||
struct SceneRendererRenderArgs
|
struct SceneRendererRenderArgs
|
||||||
{
|
{
|
||||||
CameraOptions camera;
|
CameraOptions camera;
|
||||||
@ -78,7 +83,7 @@ private:
|
|||||||
sdlpp::GPUGraphicsPipeline mPipeline;
|
sdlpp::GPUGraphicsPipeline mPipeline;
|
||||||
sdlpp::GPUSampler mSampler;
|
sdlpp::GPUSampler mSampler;
|
||||||
public:
|
public:
|
||||||
void init(Application& application);
|
void init(Application& application, SceneRendererInitArgs args = {});
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::shared_ptr<SceneMesh> getMesh(const std::string& resourcePath);
|
std::shared_ptr<SceneMesh> getMesh(const std::string& resourcePath);
|
||||||
@ -93,7 +98,7 @@ public:
|
|||||||
|
|
||||||
void render(const SceneRendererRenderArgs& args);
|
void render(const SceneRendererRenderArgs& args);
|
||||||
private:
|
private:
|
||||||
void createPipeline();
|
void createPipeline(const SceneRendererInitArgs& args);
|
||||||
};
|
};
|
||||||
} // namespace sdl_gpu_test
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
@ -475,6 +475,26 @@ 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 GPUStorageTextureWriteOnlyBinding
|
||||||
|
{
|
||||||
|
SDL_GPUTexture* texture = nullptr;
|
||||||
|
Uint32 mipLevel = 0;
|
||||||
|
Uint32 layer = 0;
|
||||||
|
bool cycle = false;
|
||||||
|
std::array<Uint8, 3> padding_;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUStorageTextureWriteOnlyBinding) == sizeof(SDL_GPUStorageTextureWriteOnlyBinding)
|
||||||
|
&& alignof(GPUStorageTextureWriteOnlyBinding) == alignof(SDL_GPUStorageTextureWriteOnlyBinding));
|
||||||
|
|
||||||
|
struct GPUStorageBufferWriteOnlyBinding
|
||||||
|
{
|
||||||
|
SDL_GPUBuffer* buffer = nullptr;
|
||||||
|
bool cycle = false;
|
||||||
|
std::array<Uint8, 3> padding;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUStorageBufferWriteOnlyBinding) == sizeof(SDL_GPUStorageBufferWriteOnlyBinding)
|
||||||
|
&& alignof(GPUStorageBufferWriteOnlyBinding) == alignof(SDL_GPUStorageBufferWriteOnlyBinding));
|
||||||
|
|
||||||
struct GPUTransferBufferLocation
|
struct GPUTransferBufferLocation
|
||||||
{
|
{
|
||||||
SDL_GPUTransferBuffer* transferBuffer;
|
SDL_GPUTransferBuffer* transferBuffer;
|
||||||
@ -513,6 +533,17 @@ struct GPUTextureRegion
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(GPUTextureRegion) == sizeof(SDL_GPUTextureRegion));
|
static_assert(sizeof(GPUTextureRegion) == sizeof(SDL_GPUTextureRegion));
|
||||||
|
|
||||||
|
struct GPUTextureLocation
|
||||||
|
{
|
||||||
|
SDL_GPUTexture* texture = nullptr;
|
||||||
|
Uint32 mipLevel = 0;
|
||||||
|
Uint32 layer = 0;
|
||||||
|
Uint32 x = 0;
|
||||||
|
Uint32 y = 0;
|
||||||
|
Uint32 z = 0;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(GPUTextureLocation) == sizeof(SDL_GPUTextureLocation));
|
||||||
|
|
||||||
using GPUBufferBinding = SDL_GPUBufferBinding;
|
using GPUBufferBinding = SDL_GPUBufferBinding;
|
||||||
|
|
||||||
using GPUTextureSamplerBinding = SDL_GPUTextureSamplerBinding;
|
using GPUTextureSamplerBinding = SDL_GPUTextureSamplerBinding;
|
||||||
@ -598,6 +629,60 @@ public:
|
|||||||
friend class GPUCommandBuffer;
|
friend class GPUCommandBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GPUComputePass : public Base<SDL_GPUComputePass, GPUComputePass>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPUComputePass() noexcept = default;
|
||||||
|
GPUComputePass(const GPUComputePass&) = delete;
|
||||||
|
GPUComputePass(GPUComputePass&& other) noexcept : Base(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUComputePass& operator=(const GPUComputePass&) = delete;
|
||||||
|
GPUComputePass& operator=(GPUComputePass&& other) noexcept
|
||||||
|
{
|
||||||
|
Base::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUComputePass& other) const noexcept = default;
|
||||||
|
|
||||||
|
void end() noexcept
|
||||||
|
{
|
||||||
|
SDL_EndGPUComputePass(mHandle);
|
||||||
|
mHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "Computepass has not been ended.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindComputePipeline(SDL_GPUComputePipeline* computePipeline) const noexcept
|
||||||
|
{
|
||||||
|
SDL_BindGPUComputePipeline(mHandle, computePipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindStorageTextures(Uint32 slotIndex, std::span<SDL_GPUTexture* const> storageTextures) const noexcept
|
||||||
|
{
|
||||||
|
SDL_BindGPUComputeStorageTextures(
|
||||||
|
/* compute_pass = */ mHandle,
|
||||||
|
/* first_slot = */ slotIndex,
|
||||||
|
/* storage_textures = */ storageTextures.data(),
|
||||||
|
/* num_bindings = */ static_cast<Uint32>(storageTextures.size())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindStorageTexture(Uint32 slotIndex, SDL_GPUTexture* storageTexture) const noexcept
|
||||||
|
{
|
||||||
|
bindStorageTextures(slotIndex, {&storageTexture, 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatch(Uint32 groupCountX, Uint32 groupCountY = 1, Uint32 groupCountZ = 1) const noexcept
|
||||||
|
{
|
||||||
|
SDL_DispatchGPUCompute(mHandle, groupCountX, groupCountY, groupCountZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class GPUCommandBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
class GPUCopyPass : public Base<SDL_GPUCopyPass, GPUCopyPass>
|
class GPUCopyPass : public Base<SDL_GPUCopyPass, GPUCopyPass>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -644,6 +729,20 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void copyTextureToTexture(const GPUTextureLocation& source, const GPUTextureLocation& destination, Uint32 width,
|
||||||
|
Uint32 height, Uint32 depth = 1, bool cycle = false) const noexcept
|
||||||
|
{
|
||||||
|
SDL_CopyGPUTextureToTexture(
|
||||||
|
/* copy_pass = */ mHandle,
|
||||||
|
/* source = */ std::bit_cast<const SDL_GPUTextureLocation*>(&source),
|
||||||
|
/* destination = */ std::bit_cast<const SDL_GPUTextureLocation*>(&destination),
|
||||||
|
/* w = */ width,
|
||||||
|
/* h = */ height,
|
||||||
|
/* d = */ depth,
|
||||||
|
/* cycle = */ cycle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
friend class GPUCommandBuffer;
|
friend class GPUCommandBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -787,6 +886,12 @@ struct GPUBeginRenderPassArgs
|
|||||||
std::optional<GPUDepthStencilTargetInfo> depthStencilTargetInfo;
|
std::optional<GPUDepthStencilTargetInfo> depthStencilTargetInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUBeginComputePassArgs
|
||||||
|
{
|
||||||
|
std::span<const GPUStorageTextureWriteOnlyBinding> storageTextureBindings;
|
||||||
|
std::span<const GPUStorageBufferWriteOnlyBinding> storageBufferBindings;
|
||||||
|
};
|
||||||
|
|
||||||
class GPUCommandBuffer : public Base<SDL_GPUCommandBuffer, GPUCommandBuffer>
|
class GPUCommandBuffer : public Base<SDL_GPUCommandBuffer, GPUCommandBuffer>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -826,6 +931,20 @@ public:
|
|||||||
return renderPass;
|
return renderPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
GPUComputePass beginComputePass(const GPUBeginComputePassArgs& args) const noexcept
|
||||||
|
{
|
||||||
|
GPUComputePass computePass;
|
||||||
|
computePass.mHandle = SDL_BeginGPUComputePass(
|
||||||
|
/* command_buffer = */ mHandle,
|
||||||
|
/* storage_texture_bindings = */ std::bit_cast<const SDL_GPUStorageTextureWriteOnlyBinding*>(args.storageTextureBindings.data()),
|
||||||
|
/* num_storage_texture_bindings = */ static_cast<Uint32>(args.storageTextureBindings.size()),
|
||||||
|
/* storage_buffer_bindings = */ std::bit_cast<const SDL_GPUStorageBufferWriteOnlyBinding*>(args.storageBufferBindings.data()),
|
||||||
|
/* num_storage_buffer_bindings = */ static_cast<Uint32>(args.storageBufferBindings.size())
|
||||||
|
);
|
||||||
|
return computePass;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
GPUCopyPass beginCopyPass() const noexcept
|
GPUCopyPass beginCopyPass() const noexcept
|
||||||
{
|
{
|
||||||
@ -1039,6 +1158,73 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GPUComputePipelineCreateArgs
|
||||||
|
{
|
||||||
|
std::span<const Uint8> code;
|
||||||
|
std::string entrypoint = "main";
|
||||||
|
GPUShaderFormat format;
|
||||||
|
Uint32 numReadonlyStorageTextures = 0;
|
||||||
|
Uint32 numReadonlyStorageBuffers = 0;
|
||||||
|
Uint32 numWriteonlyStorageTextures = 0;
|
||||||
|
Uint32 numWriteonlyStorageBuffers = 0;
|
||||||
|
Uint32 numUniformBuffers = 0;
|
||||||
|
Uint32 threadcountX = 1;
|
||||||
|
Uint32 threadcountY = 1;
|
||||||
|
Uint32 threadcountZ = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GPUComputePipeline : public BaseWithDevice<SDL_GPUComputePipeline, GPUComputePipeline>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPUComputePipeline() noexcept = default;
|
||||||
|
GPUComputePipeline(const GPUComputePipeline&) = delete;
|
||||||
|
GPUComputePipeline(GPUComputePipeline&& other) noexcept : BaseWithDevice(std::move(other)) {}
|
||||||
|
|
||||||
|
GPUComputePipeline& operator=(const GPUComputePipeline&) = delete;
|
||||||
|
GPUComputePipeline& operator=(GPUComputePipeline&& other) noexcept
|
||||||
|
{
|
||||||
|
BaseWithDevice::operator=(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto operator<=>(const GPUComputePipeline& other) const noexcept = default;
|
||||||
|
|
||||||
|
void create(SDL_GPUDevice* device, const GPUComputePipelineCreateArgs& args)
|
||||||
|
{
|
||||||
|
MIJIN_ASSERT(mHandle == nullptr, "GPUComputePipeline has already been created.");
|
||||||
|
const SDL_GPUComputePipelineCreateInfo createInfo =
|
||||||
|
{
|
||||||
|
.code_size = args.code.size(),
|
||||||
|
.code = args.code.data(),
|
||||||
|
.entrypoint = args.entrypoint.c_str(),
|
||||||
|
.format = static_cast<SDL_GPUShaderFormat>(args.format),
|
||||||
|
.num_readonly_storage_textures = args.numReadonlyStorageTextures,
|
||||||
|
.num_readonly_storage_buffers = args.numReadonlyStorageBuffers,
|
||||||
|
.num_writeonly_storage_textures = args.numWriteonlyStorageTextures,
|
||||||
|
.num_writeonly_storage_buffers = args.numWriteonlyStorageBuffers,
|
||||||
|
.threadcount_x = args.threadcountX,
|
||||||
|
.threadcount_y = args.threadcountY,
|
||||||
|
.threadcount_z = args.threadcountZ,
|
||||||
|
.props = 0
|
||||||
|
};
|
||||||
|
mHandle = SDL_CreateGPUComputePipeline(device, &createInfo);
|
||||||
|
if (mHandle == nullptr)
|
||||||
|
{
|
||||||
|
throw SDLError();
|
||||||
|
}
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() noexcept
|
||||||
|
{
|
||||||
|
if (mHandle != nullptr)
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUComputePipeline(mDevice, mHandle);
|
||||||
|
mDevice = nullptr;
|
||||||
|
mHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct GPUShaderCreateArgs
|
struct GPUShaderCreateArgs
|
||||||
{
|
{
|
||||||
std::span<const Uint8> code;
|
std::span<const Uint8> code;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user