Compare commits

..

1 Commits

Author SHA1 Message Date
7a313bf524 (WIP) Added stuff for compiling HLSL to DXIL. 2024-10-09 09:39:30 +02:00
10 changed files with 136 additions and 57 deletions

1
.gitignore vendored
View File

@ -81,3 +81,4 @@ __pycache__/
# Compiled shaders
*.spv
*.dxil

View File

@ -1,48 +0,0 @@
# sdl_gpu_test
Just a little sandbox for me to try out [SDL3](https://github.com/libsdl-org/SDL/)'s SDL_gpu.h. Feel free to do with it whatever you want. Note however that the included assets have their own licenses.
## Compiling
This project uses [SCons](https://scons.org/) and my personal extension "[SCons++](https://git.mewin.de/mewin/scons-plus-plus)" for compilation. After installing SCons it should work out of the box on Linux and Windows 10, anything else hasn't been tested.
On Linux you should be able to get SCons from your repository on any major distribution. On Windows you can either download it from their website (https://scons.org/) or (my recommendation) install it via [Scoop](https://scoop.sh/).
Just make sure to initialise the git submodule for SCons++. Either by cloning recursively:
```shell
git clone --recurse-submodules https://git.mewin.de/mewin/sdl_gpu_test.git
```
or by updating it after cloning:
```shell
git submodule init
git submodule update
```
After that you can compile the project using SCons:
```shell
scons -j<jobs>
```
This will automatically fetch and build dependencies (stored in `~/.cache/spp_cache` on Linux and `%LocalAppData%\spp_cache` on Windows).
Note that as of now the SDL repository needs to be patched in order for the build to work. You first have to run SCons once to update the repo and let the build fail, then apply the patch from `external/scons-plus-plus/recipes/SDL/fix_sdl3_from_worktree.patch`:
```shell
cd <spp_cache_dir>/cloned/git/SDL/b70daef4eb57
git apply <path to fix_sdl3_from_worktree.patch>
```
After that run the build again and everything should work just fine.
## Running
After compiling you can find the executable in `bin/sdl_gpu_test[.exe]`. You can either run it without any arguments to execute the latest iteration of my test application or pass the `--app` parameter to choose another one. You can find the names of the apps in [main.cpp](https://git.mewin.de/mewin/sdl_gpu_test/src/branch/master/private/sdl_gpu_test/main.cpp) or by using `--app` with an invalid value :).
## Further Reading
If you want to learn more about SDL_gpu.h, try the following:
* read the long comment at the beginning of SDL_gpu.h itself: https://github.com/libsdl-org/SDL/blob/main/include/SDL3/SDL_gpu.h
* look at the examples provided here: https://github.com/TheSpydog/SDL_gpu_examples
* read this blog entry about why there is no unified way for distributing shaders: https://moonside.games/posts/layers-all-the-way-down/
* look at this little helper for compiling your shaders for SDL_gpu.h: https://github.com/libsdl-org/SDL_gpu_shadercross (I haven't tested it myself yet)

View File

@ -1,6 +1,6 @@
config = {
'PROJECT_NAME': 'sdl_gpu_test',
'TOOLS': ['glslang']
'TOOLS': ['glslang', 'dxc']
}
env = SConscript('external/scons-plus-plus/SConscript', exports = ['config'])
env.Append(CPPPATH = [Dir('private'), Dir('public')])

@ -1 +1 @@
Subproject commit e3b3fd8f7cb0ff0d1973e8f719a024b81322f7d7
Subproject commit 0a29b416391359a84cb847f57fc391da71a8e3cb

View File

@ -0,0 +1,64 @@
#include "./app.hpp"
namespace sdl_gpu_test
{
void GreenTriangleDXILApp::init(const AppInitArgs& args)
{
mOptions.shaderFormats = {.dxil = true};
Application::init(args);
// create vertex shader
mijin::TypelessBuffer vertexSpv = getFileContentsBinary("shaders/hlsl/triangle.vs.dxil");
sdlpp::GPUShader vertexShader;
vertexShader.create(mDevice, {
.code = {static_cast<const Uint8*>(vertexSpv.data()), vertexSpv.byteSize()},
.format = sdlpp::GPUShaderFormat::DXIL,
.stage = sdlpp::GPUShaderStage::VERTEX
});
// create fragment shader
mijin::TypelessBuffer fragmentSpv = getFileContentsBinary("shaders/hlsl/green.ps.dxil");
sdlpp::GPUShader fragmentShader;
fragmentShader.create(mDevice, {
.code = {static_cast<const Uint8*>(fragmentSpv.data()), fragmentSpv.byteSize()},
.format = sdlpp::GPUShaderFormat::DXIL,
.stage = sdlpp::GPUShaderStage::FRAGMENT
});
// create graphics pipeline
std::array colorTargetsDescs = {
sdlpp::GPUColorTargetDescription{
.format = mDevice.getSwapchainTextureFormat(mWindow)
}
};
mPipeline.create(mDevice, {
.vertexShader = vertexShader,
.fragmentShader = fragmentShader,
.targetInfo = {
.colorTargetDescriptions = colorTargetsDescs
}
});
}
void GreenTriangleDXILApp::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
});
renderPass.bindGraphicsPipeline(mPipeline);
renderPass.drawPrimitives({.numVertices = 3});
renderPass.end();
cmdBuffer.submit();
}
}

View File

@ -0,0 +1,21 @@
#pragma once
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_1_GREEN_TRIANGLE_DXIL_APP_HPP_INCLUDED)
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_1_GREEN_TRIANGLE_DXIL_APP_HPP_INCLUDED 1
#include "../application.hpp"
namespace sdl_gpu_test
{
class GreenTriangleDXILApp : public Application
{
private:
sdlpp::GPUGraphicsPipeline mPipeline;
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_GREEN_TRIANGLE_DXIL_APP_HPP_INCLUDED)

View File

@ -20,7 +20,9 @@ src_files = Split("""
util/texture_atlas.cpp
0_clear_swapchain/app.cpp
0_clear_swapchain_dxil/app.cpp
1_green_triangle/app.cpp
1_green_triangle_dxil/app.cpp
2_triangle_with_texcoords/app.cpp
3_textured_quad/app.cpp
4_textured_cube/app.cpp
@ -30,13 +32,15 @@ src_files = Split("""
8_post_process/app.cpp
""")
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
glsl_files = env.Glob("#assets/shaders/glsl/*.frag") \
+ env.Glob("#assets/shaders/glsl/*.vert") \
+ env.Glob("#assets/shaders/glsl/*.comp")
hlsl_files = env.Glob('#assets/shaders/hlsl/*.ps') \
+ env.Glob('#assets/shaders/hlsl/*.vs')
env.Append(CPPDEFINES = ['GLM_FORCE_DEPTH_ZERO_TO_ONE', 'GLM_FORCE_RADIANS', 'GLM_ENABLE_EXPERIMENTAL'])
prog_app = env.UnityProgram(
name = 'SDL GPU Test',
target = env['BIN_DIR'] + '/sdl_gpu_test',
source = src_files,
dependencies = {
@ -56,10 +60,15 @@ prog_app = env.UnityProgram(
)
env.Default(prog_app)
for shader_file in shader_files:
spv = env.SpirV(source = shader_file, target=f'{shader_file}.spv')
for glsl_file in glsl_files:
spv = env.SpirV(source=glsl_file, target=f'{glsl_file}.spv')
env.Default(spv)
if 'DXC' in env['BUILDERS']:
for hlsl_file in hlsl_files:
dxc = env.DXC(source=hlsl_file, target=f'{hlsl_file}.dxil')
env.Default(dxc)
pack = env.PackTextures(
target = '#assets/bitmaps/ui.png',
source = ['#assets/bitmaps/ui_elements.txt']

View File

@ -3,7 +3,9 @@
#include <mijin/debug/stacktrace.hpp>
#include "./0_clear_swapchain/app.hpp"
#include "./0_clear_swapchain_dxil/app.hpp"
#include "./1_green_triangle/app.hpp"
#include "./1_green_triangle_dxil/app.hpp"
#include "./2_triangle_with_texcoords/app.hpp"
#include "./3_textured_quad/app.hpp"
#include "./4_textured_cube/app.hpp"
@ -36,7 +38,9 @@ AppListEntry makeAppHelper(std::string name) noexcept
const std::array APPS = {
makeAppHelper<sdl_gpu_test::ClearSwapchainApp>("clear_swapchain"),
makeAppHelper<sdl_gpu_test::ClearSwapchainDXILApp>("clear_swapchain_dxil"),
makeAppHelper<sdl_gpu_test::GreenTriangleApp>("green_triangle"),
makeAppHelper<sdl_gpu_test::GreenTriangleDXILApp>("green_triangle_dxil"),
makeAppHelper<sdl_gpu_test::TriangleWithTexcoordsApp>("triangle_with_texcoords"),
makeAppHelper<sdl_gpu_test::TexturedQuadApp>("textured_quad"),
makeAppHelper<sdl_gpu_test::TexturedCubeApp>("textured_cube"),

View File

@ -15,7 +15,6 @@ src_files = Split("""
""")
prog_packer = env.UnityProgram(
name = 'Texture Packer',
target = env['BIN_DIR'] + '/texture_packer',
source = src_files,
dependencies = {

View File

@ -0,0 +1,29 @@
import shutil
from SCons.Script import *
def exists(env: Environment) -> bool:
return shutil.which('dxc.exe') is not None
def generate(env : Environment):
if not exists(env):
return
def _build(target, source, env):
if len(target) != 1:
env.Error('Invalid number of targets for DXC builder, must be 1.')
if len(source) != 1:
env.Error('Invalid number of sources for DXC builder, must be 1.')
ext = source[0].name.split('.')[-1]
profile = {
'vs': 'vs_6_0',
'ps': 'ps_6_0'
}.get(ext.lower())
if not profile:
env.Error(f'Could not detect DXC shader profile from extension: {ext}')
env.Execute(f'"$DXC" -O0 -Zi -E main -T {profile} -Fo "{target[0]}" -Fd "{target[0]}.pdb" "{source[0]}')
dxc_builder = Builder(
action=_build
)
env.AddMethod(_build, 'DXC')
env['DXC'] = shutil.which('dxc.exe')
env.Append(BUILDERS={'DXC': dxc_builder})