Files
yacreader/common/rhi

YACReader Flow RHI Implementation

This directory contains the QRhiWidget-based implementation of the YACReader 3D cover flow, providing cross-platform 3D rendering support for Qt 6.7+.

Overview

The RHI (Rendering Hardware Interface) implementation is a modern replacement for the OpenGL-based flow (yacreader_flow_gl) that:

  • Supports multiple graphics APIs: Vulkan, Metal, Direct3D 11/12, OpenGL
  • Provides native performance on modern platforms (Metal on macOS, D3D on Windows)
  • Maintains 100% API compatibility with the OpenGL version
  • Works seamlessly with Qt 6.7+ while Qt5 continues using OpenGL
  • Enables future-proof rendering infrastructure

Architecture

Class Hierarchy

QRhiWidget (Qt base class)
    └── YACReaderFlow3D (Base implementation)
            ├── YACReaderComicFlow3D (File path-based loading for library)
            └── YACReaderPageFlow3D (Byte array-based loading for viewer)

Files

  • yacreader_flow_rhi.h - Header with class definitions
  • yacreader_flow_rhi.cpp - Implementation
  • shaders/ - GLSL 450 shader source files (compiled to .qsb at build time by qt_add_shaders)
  • README.md - This file

Key Features

Graphics Pipeline

The implementation uses:

  • Instanced rendering for efficient batch drawing
  • Dual-pass rendering (reflections + covers)
  • MSAA (4x by default) for anti-aliasing
  • Depth testing and back-face culling
  • Alpha blending for transparency

Resource Management

QRhi resources managed:

  • QRhiBuffer for vertices, instance data, and uniforms
  • QRhiTexture for cover images, marks, and default texture
  • QRhiSampler for texture filtering
  • QRhiGraphicsPipeline for render state
  • QRhiShaderResourceBindings for uniform/texture bindings

Shader System

Shaders are written in GLSL 4.50 and compiled to .qsb format at build time via qt_add_shaders() in CMake, supporting:

  • OpenGL ES 2.0, 3.0
  • OpenGL 2.1, 3.0+
  • HLSL (Direct3D 11/12)
  • Metal Shading Language (macOS/iOS)

Integration

Qt5 vs Qt6 Selection

The build system automatically selects the appropriate implementation:

Qt 5.x: Uses YACReaderFlowGL (OpenGL-based) Qt 6.0-6.6: Uses YACReaderFlowGL (OpenGL-based) Qt 6.7+: Uses YACReaderFlow3D (RHI-based) if YACREADER_USE_RHI is defined

Type Aliases

Applications use type aliases for seamless switching:

#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) && defined(YACREADER_USE_RHI)
using YACReaderPageFlowImpl = YACReaderPageFlow3D;
using YACReaderComicFlowImpl = YACReaderComicFlow3D;
#else
using YACReaderPageFlowImpl = YACReaderPageFlowGL;
using YACReaderComicFlowImpl = YACReaderComicFlowGL;
#endif

Example Usage (YACReader Viewer)

// goto_flow_gl.cpp
flow = new YACReaderPageFlowImpl(this);
flow->setShowMarks(false);
flow->populate(numPages);
connect(flow, &YACReaderPageFlowImpl::selected, this, &GoToFlowGL::goToPage);

Example Usage (YACReaderLibrary)

// comic_flow_widget.cpp
flow = new YACReaderComicFlowImpl(parent);
flow->setImagePaths(pathsList);
connect(flow, &YACReaderComicFlowImpl::centerIndexChanged,
        this, &ComicFlowWidget::centerIndexChanged);

API Compatibility

All public methods from YACReaderFlowGL are preserved:

Navigation

  • showPrevious(), showNext()
  • setCurrentIndex(int), setCenterIndex(unsigned int)
  • showSlide(int), centerIndex()

Configuration

  • setPreset(const Preset &)
  • setPerformance(Performance)
  • setFlowRightToLeft(bool)
  • setZoom(int), setRotation(int)
  • setCF_RX/RY/RZ(int), setCF_Y/Z(int)
  • setX_Distance(int), setCenter_Distance(int), etc.

Appearance

  • setBackgroundColor(const QColor &)
  • setTextColor(const QColor &)
  • setShadingColor(const QColor &)
  • setShowMarks(bool), setMarks(QVector<...>)

Content Management

  • populate(int), clear(), reset(), reload()
  • insert(), remove(int), add(int), replace()
  • Subclass-specific: setImagePaths(), resortCovers(), etc.

Building

Prerequisites

  1. Qt 6.7 or later (with ShaderTools module)
  2. CMake 3.25+
  3. C++20 compiler

Build YACReader

Shaders are compiled automatically at build time via qt_add_shaders():

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel

No manual shader compilation step is needed.

Graphics API Selection

QRhiWidget auto-selects the best API per platform:

  • macOS/iOS: Metal (native)
  • Windows: Direct3D 11 (default) or Direct3D 12
  • Linux: Vulkan or OpenGL
  • Android: OpenGL ES 3.0 or Vulkan

You can force a specific API via environment variables (for testing):

# Force OpenGL
export QSG_RHI_BACKEND=opengl

# Force Vulkan
export QSG_RHI_BACKEND=vulkan

# Force Direct3D 11 (Windows)
set QSG_RHI_BACKEND=d3d11

Performance

Performance tiers match the OpenGL version:

  • Low: 8 covers loaded, 128px textures (page flow) / 200px (comic flow)
  • Medium: 10 covers, 196px / 256px textures
  • High: 12 covers, 256px / 320px textures
  • Ultra High: 14-16 covers, full resolution textures

Texture loading happens asynchronously via worker threads (ImageLoader3D, ImageLoaderByteArray3D).

Debugging

Enable Validation Layers

For debugging graphics issues, enable validation:

flow->setDebugLayerEnabled(true);  // Call before widget is shown

This activates:

  • Vulkan: VK_LAYER_KHRONOS_validation
  • Direct3D: D3D11 debug layer
  • Metal: Metal API validation

Check Active Graphics API

QRhi *rhi = flow->rhi();
qDebug() << "Backend:" << rhi->backend();
qDebug() << "Driver:" << rhi->driverInfo();

Common Issues

Problem: Shaders fail to load Solution: Ensure Qt ShaderTools module is installed and qt_add_shaders() ran during build

Problem: Black screen on Qt 6.7 Solution: Check if YACREADER_USE_RHI is defined in build

Problem: Crashes on resize/reparent Solution: releaseResources() properly cleans up all QRhi objects

Migration from OpenGL

The RHI version is a drop-in replacement requiring no application code changes beyond the build system.

What's Different (Internal)

OpenGL API QRhi Equivalent
glDrawArraysInstanced() cb->drawIndexed(instanceCount)
glUniform*() Update QRhiBuffer with uniform data
glBindTexture() QRhiShaderResourceBindings
glBlendFunc() QRhiGraphicsPipeline::setTargetBlends()
glEnable(GL_DEPTH_TEST) pipeline->setDepthTest(true)

What's the Same

  • All public API methods and signatures
  • Animation system and timing
  • Preset configurations
  • Event handling (mouse, keyboard, wheel)
  • Worker thread texture loading
  • Performance tiers

Known Limitations

  1. Qt Version: Requires Qt 6.7+ (released April 2024)
  2. QRhi Stability: QRhi APIs may change in minor Qt releases
  3. Mixed Renderers: Only one graphics API per window
  4. Shader Compilation: Shaders are recompiled automatically when source files change

Future Improvements

Potential enhancements:

  • GPU-side frustum culling
  • Compute shader for texture generation
  • HDR/wide color gamut support
  • Ray-traced reflections (via RHI compute)
  • Dynamic LOD based on distance

References

License

Same as YACReader project license.

Author

Generated as part of the YACReader OpenGL modernization initiative.