Skip to content

Commit a33f8e7

Browse files
authored
Implement and use type-safe command buffer uniform push wrappers (#59)
* Interleave debug scene render between robot render system opaque and transparent passes * core : rename { pushVertexUniform => pushVertexUniformRaw }, same for Fragment uniforms + only for raw-data * core : CommandBuffer : add pushVertexUniform(), pushFragmentUniform() type-safe wrappers * Use type-safe command buffer uniform push wrappers
1 parent 4038898 commit a33f8e7

File tree

12 files changed

+74
-34
lines changed

12 files changed

+74
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- core : add `updateTransparencyClassification()` to tag an entity as opaque or untag it (https://github.com/Simple-Robotics/candlewick/pull/57)
1414
- proper support for transparent objects (https://github.com/Simple-Robotics/candlewick/pull/58)
1515
- shaders : add WBOIT composite shader, PBR transparent shader, `utils.glsl` util module, `pbr_lighting.glsl` (https://github.com/Simple-Robotics/candlewick/pull/58)
16+
- core/`CommandBuffer` : type-safe wrappers for pushing uniforms, add `Raw` suffix to raw methods (https://github.com/Simple-Robotics/candlewick/pull/59)
1617

1718
### Changed
1819

1920
- remove `projMatrix` from PBR shader ubo (https://github.com/Simple-Robotics/candlewick/pull/58)
2021
- multibody/RobotScene : early return if pipeline is nullptr (https://github.com/Simple-Robotics/candlewick/pull/58)
2122
- multibody/RobotScene : reorganize pipelines (accomodate for transparent PBR shader)
2223
- shaders : refactor basic PBR shader (move some functions to new `pbr_lighting.glsl`) (https://github.com/Simple-Robotics/candlewick/pull/58)
24+
- interleave debug scene render between robot render system opaque and transparent passes
2325

2426
## [0.0.6] - 2025-05-14
2527

examples/Ur5WithSystems.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,11 @@ int main(int argc, char **argv) {
467467
renderDepthOnlyPass(command_buffer, depthPassInfo, viewProj, castables);
468468
switch (g_showDebugViz) {
469469
case FULL_RENDER:
470-
robot_scene.render(command_buffer, g_camera);
470+
robot_scene.renderOpaque(command_buffer, g_camera);
471471
debug_scene.render(command_buffer, g_camera);
472472
if (showFrustum)
473473
frustumBoundsDebug.render(command_buffer, g_camera);
474+
robot_scene.renderTransparent(command_buffer, g_camera);
474475
break;
475476
case DEPTH_DEBUG:
476477
renderDepthDebug(renderer, command_buffer, depthDebugPass,

src/candlewick/core/CommandBuffer.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@
44
#include <SDL3/SDL_gpu.h>
55
#include <SDL3/SDL_log.h>
66
#include <utility>
7+
#include <span>
78

89
namespace candlewick {
910

11+
template <typename T>
12+
concept GpuCompatibleData =
13+
std::is_standard_layout_v<T> && !std::is_array_v<T> &&
14+
!std::is_pointer_v<T> &&
15+
(alignof(T) == 4 || alignof(T) == 8 || alignof(T) == 16);
16+
1017
class CommandBuffer {
1118
SDL_GPUCommandBuffer *_cmdBuf;
1219

@@ -59,15 +66,36 @@ class CommandBuffer {
5966
}
6067
}
6168

69+
template <GpuCompatibleData T>
70+
CommandBuffer &pushVertexUniform(Uint32 slot_index, const T &data) {
71+
return pushVertexUniformRaw(slot_index, &data, sizeof(T));
72+
}
73+
74+
template <GpuCompatibleData T>
75+
CommandBuffer &pushFragmentUniform(Uint32 slot_index, const T &data) {
76+
return pushFragmentUniformRaw(slot_index, &data, sizeof(T));
77+
}
78+
79+
template <GpuCompatibleData T>
80+
CommandBuffer &pushVertexUniform(Uint32 slot_index, std::span<const T> data) {
81+
return pushVertexUniformRaw(slot_index, data.data(), data.size_bytes());
82+
}
83+
84+
template <GpuCompatibleData T>
85+
CommandBuffer &pushFragmentUniform(Uint32 slot_index,
86+
std::span<const T> data) {
87+
return pushFragmentUniformRaw(slot_index, data.data(), data.size_bytes());
88+
}
89+
6290
/// \brief Push uniform data to the vertex shader.
63-
CommandBuffer &pushVertexUniform(Uint32 slot_index, const void *data,
64-
Uint32 length) {
91+
CommandBuffer &pushVertexUniformRaw(Uint32 slot_index, const void *data,
92+
Uint32 length) {
6593
SDL_PushGPUVertexUniformData(_cmdBuf, slot_index, data, length);
6694
return *this;
6795
}
6896
/// \brief Push uniform data to the fragment shader.
69-
CommandBuffer &pushFragmentUniform(Uint32 slot_index, const void *data,
70-
Uint32 length) {
97+
CommandBuffer &pushFragmentUniformRaw(Uint32 slot_index, const void *data,
98+
Uint32 length) {
7199
SDL_PushGPUFragmentUniformData(_cmdBuf, slot_index, data, length);
72100
return *this;
73101
}

src/candlewick/core/DebugScene.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ void DebugScene::renderMeshComponents(CommandBuffer &cmdBuf,
6868
}
6969

7070
const GpuMat4 mvp = viewProj * tr;
71-
cmdBuf.pushVertexUniform(TRANSFORM_SLOT, &mvp, sizeof(mvp));
71+
cmdBuf.pushVertexUniform(TRANSFORM_SLOT, mvp);
7272
rend::bindMesh(render_pass, cmd.mesh);
7373
for (size_t i = 0; i < cmd.mesh.numViews(); i++) {
7474
const auto &color = cmd.colors[i];
75-
cmdBuf.pushFragmentUniform(COLOR_SLOT, &color, sizeof(color));
75+
cmdBuf.pushFragmentUniform(COLOR_SLOT, color);
7676
rend::drawView(render_pass, cmd.mesh.view(i));
7777
}
7878
});

src/candlewick/core/DepthAndShadowPass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ void renderDepthOnlyPass(CommandBuffer &cmdBuf, const DepthPassInfo &passInfo,
146146
assert(validateMesh(mesh));
147147
rend::bindMesh(render_pass, mesh);
148148
mvp.noalias() = viewProj * tr;
149-
cmdBuf.pushVertexUniform(DepthPassInfo::TRANSFORM_SLOT, &mvp, sizeof(mvp));
149+
cmdBuf.pushVertexUniform(DepthPassInfo::TRANSFORM_SLOT, mvp);
150150
rend::draw(render_pass, mesh);
151151
}
152152

src/candlewick/core/debug/DepthViz.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ void renderDepthDebug(const Renderer &renderer, CommandBuffer &command_buffer,
8383
cam_param_ubo_t cam_ubo{opts.mode, opts.near, opts.far,
8484
opts.cam_proj == CameraProjection::ORTHOGRAPHIC};
8585

86-
command_buffer.pushFragmentUniform(0, &cam_ubo, sizeof(cam_ubo));
86+
command_buffer.pushFragmentUniform(0, cam_ubo);
8787
SDL_DrawGPUPrimitives(render_pass, 6, 1, 0, 0);
8888

8989
SDL_EndGPURenderPass(render_pass);

src/candlewick/core/debug/Frustum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace frustum_debug {
7070
color,
7171
eyePos,
7272
};
73-
cmdBuf.pushVertexUniform(0, &ubo, sizeof(ubo));
73+
cmdBuf.pushVertexUniform(0, ubo);
7474

7575
SDL_DrawGPUPrimitives(render_pass, NUM_VERTICES, 1, 0, 0);
7676
}

src/candlewick/multibody/RobotScene.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -301,20 +301,27 @@ void RobotScene::collectOpaqueCastables() {
301301
});
302302
}
303303

304-
void RobotScene::render(CommandBuffer &command_buffer, const Camera &camera) {
304+
void RobotScene::renderOpaque(CommandBuffer &command_buffer,
305+
const Camera &camera) {
305306
if (m_config.enable_ssao) {
306307
ssaoPass.render(command_buffer, camera);
307308
}
308309

309310
renderPBRTriangleGeometry(command_buffer, camera, false);
310311

312+
renderOtherGeometry(command_buffer, camera);
313+
}
314+
315+
void RobotScene::renderTransparent(CommandBuffer &command_buffer,
316+
const Camera &camera) {
311317
renderPBRTriangleGeometry(command_buffer, camera, true);
312318

313-
renderOtherGeometry(command_buffer, camera);
319+
compositeTransparencyPass(command_buffer);
320+
}
314321

315-
// transparent triangle pipeline required
316-
if (pipelines.triangleMesh.transparent)
317-
compositeTransparencyPass(command_buffer);
322+
void RobotScene::render(CommandBuffer &command_buffer, const Camera &camera) {
323+
renderOpaque(command_buffer, camera);
324+
renderTransparent(command_buffer, camera);
318325
}
319326

320327
/// Function private to this translation unit.
@@ -381,7 +388,8 @@ enum FragmentSamplerSlots {
381388
};
382389

383390
void RobotScene::compositeTransparencyPass(CommandBuffer &command_buffer) {
384-
if (!pipelines.wboitComposite)
391+
// transparent triangle pipeline required
392+
if (!pipelines.triangleMesh.transparent || !pipelines.wboitComposite)
385393
return;
386394

387395
SDL_GPUColorTargetInfo target;
@@ -451,10 +459,8 @@ void RobotScene::renderPBRTriangleGeometry(CommandBuffer &command_buffer,
451459
.sampler = ssaoPass.texSampler,
452460
}});
453461
int _useSsao = m_config.enable_ssao;
454-
command_buffer
455-
.pushFragmentUniform(FragmentUniformSlots::LIGHTING, &lightUbo,
456-
sizeof(lightUbo))
457-
.pushFragmentUniform(2, &_useSsao, sizeof(_useSsao));
462+
command_buffer.pushFragmentUniform(FragmentUniformSlots::LIGHTING, lightUbo)
463+
.pushFragmentUniform(2, _useSsao);
458464

459465
SDL_BindGPUGraphicsPipeline(render_pass, pipeline);
460466

@@ -472,17 +478,16 @@ void RobotScene::renderPBRTriangleGeometry(CommandBuffer &command_buffer,
472478
.mvp = mvp,
473479
.normalMatrix = math::computeNormalMatrix(modelView),
474480
};
475-
command_buffer.pushVertexUniform(VertexUniformSlots::TRANSFORM, &data,
476-
sizeof(data));
481+
command_buffer.pushVertexUniform(VertexUniformSlots::TRANSFORM, data);
477482
if (enable_shadows) {
478483
Mat4f lightMvp = lightViewProj * tr;
479-
command_buffer.pushVertexUniform(1, &lightMvp, sizeof(lightMvp));
484+
command_buffer.pushVertexUniform(1, lightMvp);
480485
}
481486
rend::bindMesh(render_pass, mesh);
482487
for (size_t j = 0; j < mesh.numViews(); j++) {
483488
const auto material = obj.materials[j];
484489
command_buffer.pushFragmentUniform(FragmentUniformSlots::MATERIAL,
485-
&material, sizeof(material));
490+
material);
486491
rend::drawView(render_pass, mesh.view(j));
487492
}
488493
};
@@ -524,10 +529,8 @@ void RobotScene::renderOtherGeometry(CommandBuffer &command_buffer,
524529
const Mesh &mesh = obj.mesh;
525530
const Mat4f mvp = viewProj * tr;
526531
const auto &color = obj.materials[0].baseColor;
527-
command_buffer
528-
.pushVertexUniform(VertexUniformSlots::TRANSFORM, &mvp, sizeof(mvp))
529-
.pushFragmentUniform(FragmentUniformSlots::MATERIAL, &color,
530-
sizeof(color));
532+
command_buffer.pushVertexUniform(VertexUniformSlots::TRANSFORM, mvp)
533+
.pushFragmentUniform(FragmentUniformSlots::MATERIAL, color);
531534
rend::bindMesh(render_pass, mesh);
532535
rend::draw(render_pass, mesh);
533536
}

src/candlewick/multibody/RobotScene.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ namespace multibody {
206206
/// this function.
207207
void render(CommandBuffer &command_buffer, const Camera &camera);
208208

209+
void renderOpaque(CommandBuffer &command_buffer, const Camera &camera);
210+
211+
void renderTransparent(CommandBuffer &command_buffer, const Camera &camera);
212+
209213
/// \brief Release all resources.
210214
void release();
211215

src/candlewick/multibody/Visualizer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ void Visualizer::render() {
113113
robotScene.worldSpaceBounds);
114114

115115
auto &camera = controller.camera;
116-
robotScene.render(cmdBuf, camera);
116+
robotScene.renderOpaque(cmdBuf, camera);
117117
debugScene.render(cmdBuf, camera);
118+
robotScene.renderTransparent(cmdBuf, camera);
118119
guiSystem.render(cmdBuf);
119120
}
120121

0 commit comments

Comments
 (0)