Skip to content

feat: add image/texture infrastructure for visualization#4

Open
mtao wants to merge 33 commits intofeature/meshdata-quiver-refactorfrom
feature/image-infrastructure
Open

feat: add image/texture infrastructure for visualization#4
mtao wants to merge 33 commits intofeature/meshdata-quiver-refactorfrom
feature/image-infrastructure

Conversation

@mtao
Copy link
Copy Markdown
Owner

@mtao mtao commented Mar 28, 2026

Summary

  • Add complete image/texture infrastructure to balsa's visualization subsystem, implementing Phase 1 and Phase 2 of the art-viewer plan
  • Introduces VulkanTexture (RAII GPU texture with full and partial upload), ImageData (CPU pixel buffer scene graph feature with version-tracked dirty regions), ImagePipelineManager (Vulkan pipeline with fullscreen triangle, descriptor sets, per-frame UBOs), VulkanImageDrawable (syncs ImageData to GPU texture per frame), and ImageScene (orthographic 2D viewer with pan/zoom/fit)
  • Adds HDR tone mapping shaders (exposure/gamma in fragment shader), ImGui controls panel, PPM I/O (P6 binary), and a standalone image_viewer_glfw tool with scroll-zoom and middle-drag pan
  • Make BoundingBox<T, Dim> generic over scalar type T (matching quiver's AABB<T, Dim> from PR mtao/quiver#21), replace ImageData::DirtyRegion struct with BoundingBox<uint32_t, 2>

BoundingBox / DirtyRegion Changes

  • BoundingBox<T, Dim> now takes T first (no default), matching quiver convention
  • Per-axis accessors: min(axis), max(axis), range(axis)
  • Convenience names: width(), height(), depth()
  • 4-arg constructor (x_min, y_min, x_max, y_max) for Dim==2
  • ImageData::DirtyRegion is now using DirtyRegion = geometry::BoundingBox<uint32_t, 2>
  • BVHData uses BVH<double, 3, K> (explicit scalar type)
  • Unified bounding_box.hpp (removed #if BALSA_HAS_QUIVER split)

Dependencies

  • quiver.wrap points to feature/kdop-scalar-type (revert to main after mtao/quiver#21 merges)

New Files (21 files, ~3000 LOC)

Headers

  • visualization/include/balsa/visualization/vulkan/texture.hpp — VulkanTexture RAII wrapper
  • visualization/include/balsa/scene_graph/ImageData.hpp — CPU pixel buffer feature (RGBA8/RGBAF32, dirty tracking)
  • visualization/include/balsa/visualization/vulkan/image_pipeline.hpp — Pipeline manager + UBO structs
  • visualization/include/balsa/visualization/vulkan/vulkan_image_drawable.hpp — Per-frame GPU sync drawable
  • visualization/include/balsa/visualization/vulkan/image_scene.hpp — Orthographic 2D image scene
  • visualization/include/balsa/visualization/vulkan/imgui/image_controls_panel.hpp — ImGui controls
  • visualization/include/balsa/visualization/image_io.hpp — PPM I/O declarations

Implementations

  • visualization/src/vulkan/texture.cpp — Full VulkanTexture (create, upload, update_region, layout transitions)
  • visualization/src/scene_graph/ImageData.cpp — Pixel buffer management with dirty region merging
  • visualization/src/vulkan/image_pipeline.cpp — Descriptor layout, pool, pipeline creation, shader compilation
  • visualization/src/vulkan/vulkan_image_drawable.cpp — Version-tracked sync, partial texture updates
  • visualization/src/vulkan/image_scene.cpp — Scene lifecycle, orthographic projection, pan/zoom
  • visualization/src/vulkan/imgui/image_controls_panel.cpp — Exposure/gamma/channel/zoom/pan controls
  • visualization/src/image_io.cpp — PPM P6 reader/writer (RGB→RGBA expansion)

Shaders

  • visualization/resources/glsl/image.vert — Fullscreen triangle via gl_VertexIndex
  • visualization/resources/glsl/image.frag — HDR tone mapping + channel isolation

Tools

  • visualization/tools/image_viewer_glfw.cpp — Standalone viewer with CLI11, ImGui overlay

Tests

  • 15 new test cases in test_scene_graph.cpp covering ImageData (creation, RGBA8/RGBAF32 pixels, version tracking, partial updates, dirty region merging, display parameters, error cases) and PPM I/O (round-trip, error handling)

Motivation

This lays the foundation for:

  1. ART ray tracer live preview — progressive rendering with partial texture updates
  2. MultiscreenManga comic reader port — image display with pan/zoom

Testing

All 9 balsa test suites pass (44 scene_graph test cases, 312 assertions total).

mtao added 30 commits March 29, 2026 01:46
Convert 8 remaining headers from #pragma once to #if !defined(GUARD)
/ #define GUARD / #endif style. Guard names follow the convention
BALSA_PATH_COMPONENTS_HPP, derived from the header path relative to
each sub-library include root (core, geometry, visualization).
- Remove libqt6opengl6-dev and libqt6openglwidgets6-dev from both
  system-packages.yml and conan.yml (these packages don't exist on
  Ubuntu 24.04; qt6-base-dev already includes the needed headers)
- Add --wrap-mode=forcefallback to meson setup in both workflows so
  all subprojects (including transitive wrap-redirects) are fetched
  before dependency resolution
…n macOS

- Change quiver.wrap from SSH to HTTPS URL
- Add git config step using SUBPROJECT_PAT secret to authenticate
  when cloning private subprojects (quiver) in both workflows
- Add qt@6 to macOS Homebrew packages so Qt-dependent features build
The env.SUBPROJECT_PAT expression evaluated before the step env block
was applied, so the PAT step was always skipped. Use the secrets context
directly which is available at if-expression evaluation time.
Linux: quiver pulls Lua as a subproject which requires libreadline-dev.
macOS: visualization requires shaderc, glfw, and Vulkan (via molten-vk).
…promotes it

With --wrap-mode=forcefallback, spdlog (line 9 of meson.build) needs fmt
as a subproject. quiver's fmt.wrap only gets auto-promoted after quiver
is configured on line 62, which is too late. fmt.wrap must exist at the
top level for spdlog to find it.
- Remove libfmt-dev and libspdlog-dev from apt-get: system fmt pkg-config
  leaks -DFMT_EXPORT into the subproject build, causing FMT_BEGIN_EXPORT
  errors. With --wrap-mode=forcefallback, both are built from subprojects.
- Disable imgui on macOS: the imgui wrapdb patch propagates cpp_std=c++26
  to objcpp_cpp_std, which Apple Clang does not support.
…Qt disable

System-packages:
- Purge libfmt-dev/libspdlog-dev after apt install to prevent FMT_BEGIN_EXPORT leak
- Change cpp_std to 'c++26,vc++latest' for MSVC compatibility

Conan:
- Add shell:bash to git config step (fixes PowerShell on Windows)
- Add compiler native file step to override conan's bare gcc/g++ with gcc-15/g++-15
- Disable Qt and protobuf in conan builds (Qt 6.8.3 INT128 error with GCC 15)

Wraps:
- Point zipper.wrap to fix/msvc-cpp-std, quiver.wrap to fix/mdspan-apple-clang
  (revert both to main after upstream PRs are merged)
spdlog's wrapdb meson.build adds -DFMT_EXPORT to interface compile_args
when built as shared with std::format (GCC 15 with C++26). This breaks
fmt's own headers for any consumer that also links fmt. Building spdlog
as static avoids this code path entirely.

Also removes the now-unnecessary apt-get purge of libfmt-dev since the
root cause was the spdlog wrapdb bug, not system pkg-config.
…er.wrap

- Fix Vulkan debug callback: use C types (VkDebugUtils*) instead of
  Vulkan-Hpp C++ types in PFN_vkDebugUtilsMessengerCallbackEXT —
  GCC 15 rejects the implicit enum conversion with -fpermissive error
- Add libreadline-dev to conan workflow Linux system deps (needed by
  quiver's Lua subproject)
- Fix LD_LIBRARY_PATH: use pkg-config --libs-only-L to resolve
  ${prefix} variables in conan .pc files
- Update quiver.wrap to fix/msvc-compat for MSVC C2244/C2753 fixes
Alembic's conan package does not produce a pkg-config file on Windows,
so meson's dependency() call fails during configure. Disable by default
in the conanfile (already disabled in meson_options.txt).
These cmake subprojects fail to link in CI (collect2 ld errors on Linux,
similar failures on Windows). They default to false in meson_options.txt
already; conanfile.py was overriding to True.
The visualization sub-library hard-requires Qt for shader resource
storage. Since the conan workflow disables Qt (-o qt=False) because
it is installed as a system package on Linux and unavailable on
Windows, visualization must also be disabled to avoid a configure
error.
- json_sink.cpp: use path.string() for spdlog::basic_logger_mt
  (std::filesystem::path not implicitly convertible on MSVC)
- prepend_to_filename.cpp: use filename.string() instead of
  std::string(filename) for MSVC compatibility
- test_iterators.cpp: guard std::views::concat with
  __cpp_lib_ranges_concat feature test macro (not yet in GCC 15)
- CI: add retry loop for Launchpad PPA setup to handle transient
  GPGKeyTemporarilyNotFoundError (HTTP 500) failures
Chocolatey community feed occasionally returns 504 Gateway Timeout
errors. Retry up to 5 times with 10s delay between attempts.
fix(ci): remove missing Qt6 packages, add --wrap-mode=forcefallback
chore: replace #pragma once with old-style include guards
…ndency()

Switch zipper and quiver consumption from subproject().get_variable() to
dependency() with [provide] sections in wrap files. Add
meson.override_dependency() calls for balsaCore, balsaGeometry, and
balsaVisualization so downstream projects can consume them via
dependency(). Fix colormap_shaders.wrap to use variable-based provide
instead of dependency_names. Guard quiver_dep in visualization with
get_option('quiver') check. Remove dead options (eltopo, pngpp, igl).
refactor: modernize meson build to use dependency() and override_dependency()
…te discovery

Replace MeshData's internal data buffers with a shared_ptr<quiver::MeshBase>.
All attributes from the mesh are now enumerable via DiscoveredAttribute and
assignable to visualization roles (positions, normals, scalar field) through
RoleBinding with automatic double-to-float conversion via CachedAttribute.

- MeshData holds shared_ptr<MeshBase>, discovers all attributes on set_mesh()
- RoleBinding provides raw_data() + component_count for GPU upload
- OBJ and MSH loading goes through quiver::io::read_mesh() pipeline
- VulkanMeshDrawable syncs from role bindings instead of raw arrays
- MeshBuffers supports variable component counts (1D/2D/3D positions)
- MeshPipelineManager generates correct VkFormat for component count
- ImGui mesh_controls_panel shows attribute selector combos per role
- Qt mesh_controls_widget has full attribute binding UI with filtering
- BVHData creates quiver::Mesh<1> edge meshes from role bindings
- All tests rewritten with quiver::Mesh<2> objects (65/65 passing)
mtao added 3 commits April 13, 2026 18:21
Add VulkanTexture (RAII GPU texture with full/partial upload),
ImageData (CPU pixel buffer scene graph feature with dirty tracking),
ImagePipelineManager (descriptor sets, UBOs, fullscreen triangle pipeline),
VulkanImageDrawable (per-frame sync from ImageData to GPU texture),
ImageScene (orthographic 2D viewer with pan/zoom/fit-to-window),
image shaders (fullscreen triangle + HDR tone mapping fragment shader),
ImGui image controls panel (exposure/gamma/channel/zoom/pan),
PPM I/O (P6 binary reader/writer, RGB->RGBA expansion),
image_viewer_glfw standalone tool (CLI11, scroll-zoom, middle-drag pan),
and unit tests for ImageData and PPM I/O (15 new test cases).

This lays the foundation for ART ray tracer live preview and
the MultiscreenManga comic reader port.
- BoundingBox<T, Dim> now backed by quiver's AABB<T, Dim> (T first,
  no default), matching quiver's feature/kdop-scalar-type branch
- Add per-axis accessors: min(axis), max(axis), range(axis)
- Add convenience names: width(), height(), depth()
- Add 4-arg constructor (x_min, y_min, x_max, y_max) for Dim==2
- Replace ImageData::DirtyRegion struct with BoundingBox<uint32_t, 2>
- Update BVHData to use BVH<double, 3, K> (explicit scalar type)
- Unify bounding_box.hpp (remove #if BALSA_HAS_QUIVER split)
- Point quiver.wrap to feature/kdop-scalar-type (revert after merge)
@mtao mtao force-pushed the feature/image-infrastructure branch from 42bb6eb to 70ab58d Compare April 13, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant