Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build/
build.em/
external/vcpkg
external/slang/
tools/download
Expand Down
13 changes: 12 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(SGL_MACOS TRUE)
set(SGL_HAS_D3D12 OFF)
set(SGL_HAS_VULKAN ON)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set(SGL_PLATFORM "Emscripten")
set(SGL_EMSCRIPTEN TRUE)
set(SGL_HAS_D3D12 OFF)
set(SGL_HAS_VULKAN OFF)
else()
message(FATAL_ERROR "Unsupported platform!")
endif()
Expand All @@ -119,7 +124,13 @@ endif()
# CUDA
# -----------------------------------------------------------------------------

if(NOT SGL_USE_DYNAMIC_CUDA)
if(SGL_EMSCRIPTEN OR SGL_MACOS)
set(SGL_HAS_CUDA OFF)
else()
set(SGL_HAS_CUDA ON)
endif()

if(SGL_HAS_CUDA AND NOT SGL_USE_DYNAMIC_CUDA)
find_package(CUDAToolkit REQUIRED)
endif()

Expand Down
25 changes: 25 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,19 @@
"VCPKG_TARGET_TRIPLET": "arm64-osx",
"CMAKE_APPLE_SILICON_PROCESSOR": "arm64"
}
},
{
"name": "emscripten",
"description": "Emscripten-based WebAssembly build",
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build.em",
"toolchainFile": "$env{EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake",
"cacheVariables": {
"SGL_BUILD_TESTS": "OFF",
"SGL_BUILD_PYTHON": "OFF",
"CMAKE_CXX_FLAGS_INIT": "-fwasm-exceptions -Os -include cstdlib",
"CMAKE_EXE_LINKER_FLAGS": "-sASSERTIONS -sALLOW_MEMORY_GROWTH -fwasm-exceptions --export=__cpp_exception -sUSE_GLFW=3"
}
}
],
"buildPresets": [
Expand Down Expand Up @@ -325,6 +338,18 @@
"displayName": "Debug",
"configurePreset": "macos-arm64-clang",
"configuration": "Debug"
},
{
"name": "emscripten-release",
"displayName": "Release",
"configurePreset": "emscripten",
"configuration": "Release"
},
{
"name": "emscripten-debug",
"displayName": "Debug",
"configurePreset": "emscripten",
"configuration": "Debug"
}
],
"testPresets": [
Expand Down
5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ add_subdirectory(raytracing)
add_subdirectory(render_pipeline)
add_subdirectory(simple_compute)
add_subdirectory(tinybc)

# WASM example for Emscripten
if(SGL_EMSCRIPTEN)
add_subdirectory(wasm)
endif()
130 changes: 92 additions & 38 deletions examples/render_pipeline/render_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "sgl/sgl.h"
#include "sgl/core/platform.h"
#include "sgl/core/window.h"
#include "sgl/device/device.h"
#include "sgl/device/shader.h"
#include "sgl/device/command.h"
Expand All @@ -11,50 +12,71 @@
#include "sgl/device/agility_sdk.h"
#include "sgl/device/input_layout.h"
#include "sgl/device/pipeline.h"
#include "sgl/utils/tev.h"
#include "sgl/device/surface.h"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

SGL_EXPORT_AGILITY_SDK

#ifdef __EMSCRIPTEN__
static const std::filesystem::path EXAMPLE_DIR(".");
#else
static const std::filesystem::path EXAMPLE_DIR(SGL_EXAMPLE_DIR);
#endif

using namespace sgl;

int main()
{
sgl::static_init();

struct App {
ref<Window> window;
ref<Device> device;
ref<Surface> surface;
ref<Buffer> vertex_buffer;
ref<Buffer> index_buffer;
ref<InputLayout> input_layout;
ref<ShaderProgram> program;
ref<RenderPipeline> pipeline;

App()
{
ref<Device> device = Device::create({
window = Window::create({
.width = 1024,
.height = 1024,
.title = "render_pipeline",
});

device = Device::create({
.enable_debug_layers = true,
.compiler_options = {.include_paths = {EXAMPLE_DIR}},
});

surface = device->create_surface(window);
surface->configure({
.format = surface->info().preferred_format,
.usage = TextureUsage::render_target,
.width = window->width(),
.height = window->height(),
.vsync = true,
});

std::vector<float2> vertices{{-1.f, -1.f}, {1.f, -1.f}, {0.f, 1.f}};
std::vector<uint32_t> indices{0, 1, 2};

ref<Buffer> vertex_buffer = device->create_buffer({
.usage = BufferUsage::shader_resource,
vertex_buffer = device->create_buffer({
.usage = BufferUsage::vertex_buffer,
.label = "vertex_buffer",
.data = vertices.data(),
.data_size = vertices.size() * sizeof(float2),
});

ref<Buffer> index_buffer = device->create_buffer({
.usage = BufferUsage::shader_resource,
index_buffer = device->create_buffer({
.usage = BufferUsage::index_buffer,
.label = "index_buffer",
.data = indices.data(),
.data_size = indices.size() * sizeof(uint32_t),
});

ref<Texture> render_texture = device->create_texture({
.format = Format::rgba32_float,
.width = 1024,
.height = 1024,
.usage = TextureUsage::render_target,
.label = "render_texture",
});

ref<InputLayout> input_layout = device->create_input_layout({
input_layout = device->create_input_layout({
.input_elements{
{
.semantic_name = "POSITION",
Expand All @@ -67,32 +89,64 @@ int main()
},
});

ref<ShaderProgram> program = device->load_program("render_pipeline.slang", {"vertex_main", "fragment_main"});
ref<RenderPipeline> pipeline = device->create_render_pipeline({
program = device->load_program("render_pipeline.slang", {"vertex_main", "fragment_main"});
pipeline = device->create_render_pipeline({
.program = program,
.input_layout = input_layout,
.targets = {{.format = Format::rgba32_float}},
.targets = {{.format = surface->info().preferred_format}},
});
}

ref<CommandEncoder> command_encoder = device->create_command_encoder();
{
auto pass_encoder = command_encoder->begin_render_pass({
.color_attachments = {{.view = render_texture->create_view({})}},
});
pass_encoder->bind_pipeline(pipeline);
pass_encoder->set_render_state({
.viewports = {{Viewport::from_size(float(render_texture->width()), float(render_texture->height()))}},
.scissor_rects = {{ScissorRect::from_size(render_texture->width(), render_texture->height())}},
.vertex_buffers = {vertex_buffer},
});
pass_encoder->draw({.vertex_count = 3});
pass_encoder->end();
void main_loop()
{
window->process_events();

if (!surface->config())
return;

ref<Texture> surface_texture = surface->acquire_next_image();
if (surface_texture) {
ref<CommandEncoder> command_encoder = device->create_command_encoder();
{
auto pass_encoder = command_encoder->begin_render_pass({
.color_attachments = {{.view = surface_texture->create_view({}), .load_op = LoadOp::clear}},
});
pass_encoder->bind_pipeline(pipeline);
pass_encoder->set_render_state({
.viewports
= {{Viewport::from_size(float(surface_texture->width()), float(surface_texture->height()))}},
.scissor_rects = {{ScissorRect::from_size(surface_texture->width(), surface_texture->height())}},
.vertex_buffers = {vertex_buffer},
});
pass_encoder->draw({.vertex_count = 3});
pass_encoder->end();
}
device->submit_command_buffer(command_encoder->finish());

surface->present();
}
device->submit_command_buffer(command_encoder->finish());
}

~App()
{
if (device)
device->close();
}
};

tev::show(render_texture, "render_pipeline");
int main()
{
sgl::static_init();

device->close();
{
App app;

while (!app.window->should_close()) {
app.main_loop();
#ifdef __EMSCRIPTEN__
emscripten_sleep(0);
#endif
}
}

sgl::static_shutdown();
Expand Down
36 changes: 34 additions & 2 deletions examples/render_pipeline/render_pipeline.slang
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifdef __TARGET_WGPU__

struct VertexOutput
{
float4 pos : SV_Position;
float3 barycentrics : BARYCENTRICS;
};

[shader("vertex")]
VertexOutput vertex_main(float2 pos: POSITION, uint vid: SV_VertexID)
{
VertexOutput output;
output.pos = float4(pos, 0.0, 1.0);

// Mimic SV_Barycentrics for backends that don't support it (e.g., WebGPU)
uint id = vid % 3;
output.barycentrics = float3(0, 0, 0);
output.barycentrics[id] = 1.0;

return output;
}

[shader("fragment")]
float4 fragment_main(VertexOutput input) : SV_Target
{
return float4(input.barycentrics, 1.f);
}

#else

[shader("vertex")]
float4 vertex_main(float2 pos: POSITION)
: SV_Position
Expand All @@ -8,8 +38,10 @@ float4 vertex_main(float2 pos: POSITION)
}

[shader("fragment")]
float4 fragment_main(float4 pos: SV_Position, float3 barycentrics: SV_Barycentrics)
float4 fragment_main(float3 bary: SV_Barycentrics)
: SV_Target
{
return float4(barycentrics, 1.f);
return float4(bary, 1.f);
}

#endif
4 changes: 4 additions & 0 deletions examples/simple_compute/simple_compute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

SGL_EXPORT_AGILITY_SDK

#ifdef __EMSCRIPTEN__
static const std::filesystem::path EXAMPLE_DIR(".");
#else
static const std::filesystem::path EXAMPLE_DIR(SGL_EXAMPLE_DIR);
#endif

using namespace sgl;

Expand Down
41 changes: 41 additions & 0 deletions examples/wasm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Render Pipeline Example
add_executable(render-pipeline-wasm
../render_pipeline/render_pipeline.cpp
)

target_compile_features(render-pipeline-wasm PRIVATE cxx_std_20)
target_link_libraries(render-pipeline-wasm PRIVATE sgl)
target_link_options(render-pipeline-wasm PRIVATE
"SHELL:--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../render_pipeline/render_pipeline.slang@render_pipeline.slang"
)
target_compile_definitions(render-pipeline-wasm PRIVATE SGL_EXAMPLE_DIR=".")

add_custom_command(TARGET render-pipeline-wasm POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/../render_pipeline/render_pipeline.slang
$<TARGET_FILE_DIR:render-pipeline-wasm>/render_pipeline.slang
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/render_pipeline.html
$<TARGET_FILE_DIR:render-pipeline-wasm>/render_pipeline.html
)

# Simple Compute Example
add_executable(simple-compute-wasm
../simple_compute/simple_compute.cpp
)

target_compile_features(simple-compute-wasm PRIVATE cxx_std_20)
target_link_libraries(simple-compute-wasm PRIVATE sgl)
target_link_options(simple-compute-wasm PRIVATE
"SHELL:--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../simple_compute/simple_compute.slang@simple_compute.slang"
)
target_compile_definitions(simple-compute-wasm PRIVATE SGL_EXAMPLE_DIR=".")

add_custom_command(TARGET simple-compute-wasm POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/../simple_compute/simple_compute.slang
$<TARGET_FILE_DIR:simple-compute-wasm>/simple_compute.slang
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/simple_compute.html
$<TARGET_FILE_DIR:simple-compute-wasm>/simple_compute.html
)
Loading