Loading...
Searching...
No Matches
TextureLoader.hpp
1#pragma once
2#include <score_plugin_gfx_export.h>
3
4#include <QImage>
5#include <QString>
6
7#include <cstdint>
8#include <optional>
9#include <unordered_map>
10
11class QRhi;
12class QRhiTexture;
13class QRhiResourceUpdateBatch;
14class QByteArray;
15
16namespace score::gfx
17{
18
19// =============================================================================
20// CPU-side decode result.
21//
22// The default implementation produces RGBA8888 data via QImageReader. The
23// `srgb` flag is metadata only — it does NOT alter the pixel bytes, it just
24// records whether the caller intends those bytes to be interpreted as sRGB
25// when the texture is sampled (set the QRhiTexture format to RGBA8 vs sRGB8A8
26// at upload time accordingly).
27//
28// Future swap-in candidates: OIIO (HDR/EXR), KTX2 (transcoded BCn), AVIF.
29// =============================================================================
31{
32 QImage image; // QImage::Format_RGBA8888 (no premul)
33 QString debug_name; // For QRhiTexture::setName()
34};
35
36// =============================================================================
37// Decode helpers — synchronous, called on the render thread.
38//
39// Both variants decode directly with QImage; cross-output dedup is handled at
40// the TextureCache (per-renderer GPU side) and AssetTable (content-hash
41// keyed) layers. We don't share a CPU-side cache here — reusing
42// Gfx::ImageCache leaks every decoded path for the program lifetime.
43// =============================================================================
44
45SCORE_PLUGIN_GFX_EXPORT
46std::optional<DecodedImage> decodeImageFromPath(const QString& path);
47
48SCORE_PLUGIN_GFX_EXPORT
49std::optional<DecodedImage> decodeImageFromMemory(
50 const QByteArray& bytes, const QString& mime_hint);
51
52// =============================================================================
53// GPU upload — pure RHI, no I/O. Allocates a freshly-sized QRhiTexture
54// (RGBA8 or sRGB8_ALPHA8 depending on `srgb`), records the upload into
55// `batch`. Caller owns the returned pointer (delete via deleteLater()).
56//
57// Returns nullptr on QRhi allocation failure.
58// =============================================================================
59
60SCORE_PLUGIN_GFX_EXPORT
61QRhiTexture* uploadImageToTexture(
62 QRhi& rhi, QRhiResourceUpdateBatch& batch, const QImage& img, bool srgb,
63 const QString& debug_name = {});
64
65// =============================================================================
66// One-shot decode + upload helpers. Convenience for callers that don't need
67// to reuse the decoded CPU bytes.
68// =============================================================================
69
70SCORE_PLUGIN_GFX_EXPORT
71QRhiTexture* loadAndUploadTexture(
72 QRhi& rhi, QRhiResourceUpdateBatch& batch, const QString& path, bool srgb);
73
74SCORE_PLUGIN_GFX_EXPORT
75QRhiTexture* loadAndUploadTexture(
76 QRhi& rhi, QRhiResourceUpdateBatch& batch, const QByteArray& bytes,
77 const QString& mime_hint, bool srgb);
78
79// =============================================================================
80// Per-renderer GPU texture cache.
81//
82// QRhiTexture* is bound to one QRhi instance, so this cache MUST live on the
83// render-side node (e.g. ScenePreprocessorNode), not as a global singleton. Owns
84// the textures it returns; clear() (also runs in the dtor) schedules each via
85// deleteLater().
86//
87// Keys: a file path OR a stable content hash (for embedded glTF/FBX blobs).
88// Two entries with the same origin but different sRGB flags coexist.
89// =============================================================================
90class SCORE_PLUGIN_GFX_EXPORT TextureCache
91{
92public:
93 TextureCache() = default;
95
96 TextureCache(const TextureCache&) = delete;
97 TextureCache& operator=(const TextureCache&) = delete;
98 TextureCache(TextureCache&&) noexcept = default;
99 TextureCache& operator=(TextureCache&&) noexcept = default;
100
101 // First call decodes + uploads via `batch`; later calls hit the cache.
102 // Returns nullptr if the file can't be decoded.
103 QRhiTexture* acquireFromPath(
104 QRhi& rhi, QRhiResourceUpdateBatch& batch, const QString& path, bool srgb);
105
106 // Same, for embedded blobs. `content_hash` is supplied by the caller — its
107 // identity (not its value) is what guards re-upload.
108 QRhiTexture* acquireFromMemory(
109 QRhi& rhi, QRhiResourceUpdateBatch& batch, const QByteArray& bytes,
110 const QString& mime_hint, uint64_t content_hash, bool srgb);
111
112 // Schedule deleteLater() on every owned texture and drop the map.
113 void clear();
114
115 std::size_t size() const noexcept { return m_textures.size(); }
116
117private:
118 struct Key
119 {
120 QString origin; // file path, or "blob:<hash-hex>" for memory blobs
121 bool srgb{};
122 bool operator==(const Key&) const noexcept = default;
123 };
124 struct KeyHash
125 {
126 std::size_t operator()(const Key& k) const noexcept;
127 };
128
129 std::unordered_map<Key, QRhiTexture*, KeyHash> m_textures;
130};
131
132} // namespace score::gfx
Definition TextureLoader.hpp:91
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
Definition TextureLoader.hpp:31
Definition Uniforms.hpp:5