Elaztek Developer Hub
Blamite Game Engine - blam!  00453.06.08.26.0624.blamite
The core library for the Blamite Game Engine.
texture_storage.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <cstdint>
5 #include <bgfx/bgfx.h>
6 
7 // ---------------------------------------------------------------------------
8 // BlamTextureRef
9 // ---------------------------------------------------------------------------
10 // Opaque handle to a texture managed by the storage system. Materials and
11 // other engine code reference textures via this type rather than via raw
12 // bgfx::TextureHandle. This indirection is what makes it possible to swap
13 // the underlying storage backend (currently: texture arrays grouped by size
14 // class) without rewriting every site that touches a texture.
15 //
16 // Layout is small and trivially copyable. Pass by value.
17 //
18 // Field meanings depend on the active backend:
19 // ARRAY backend (current):
20 // storage_id = index of the size-class array (0=size class 64,
21 // 1=size class 128, ... 6=size class 4096)
22 // layer = layer index within that array
23 // sampler_flags = bgfx sampler flags to use when binding the array
24 // for fragments that sample THIS texture. Stored on
25 // the ref so the material doesn't have to know.
26 //
27 // BINDLESS backend (future):
28 // storage_id = ignored (reserved for backend-specific bookkeeping)
29 // layer = global texture index in the bindless table
30 // sampler_flags = same meaning
31 //
32 // An invalid ref has storage_id == BLAM_TEXTURE_REF_INVALID_STORAGE_ID.
34 {
39 };
40 
41 #define BLAM_TEXTURE_REF_INVALID_STORAGE_ID 0xFFFFFFFFu
42 
43 // Returns true if the ref points to a real texture in storage.
45 {
47 }
48 
49 // Returns an invalid ref. Use for "no texture" / sentinel cases.
51 {
52  BlamTextureRef ref;
54  ref.layer = 0;
55  ref.sampler_flags = 0;
56  ref.reserved = 0;
57  return ref;
58 }
59 
60 // ---------------------------------------------------------------------------
61 // Size classes
62 // ---------------------------------------------------------------------------
63 // Textures are bucketed into one of N size classes at upload time. Each size
64 // class has its own bgfx::Texture2DArray. Per-frame, all active arrays are
65 // bound to the gbuffer pass; per-draw nothing happens for textures.
66 //
67 // 7 classes covering 64x64 through 4096x4096. Anything smaller than 64
68 // gets padded up to 64. Anything larger than 4096 gets refused (with a
69 // log warning) - oversized textures should be downsized at import.
70 //
71 // IMPORTANT: this constant is mirrored in the gbuffer fragment shader as
72 // BLAM_TEXTURE_SIZE_CLASS_COUNT. If you add or remove a size class, update
73 // both. The shader has one SAMPLER2DARRAY per size class.
74 #define BLAM_TEXTURE_SIZE_CLASS_COUNT 7
75 
76 // Edge resolutions per size class. Indexed by storage_id.
78 
79 // Initial layers allocated per array. When a size class fills up, we
80 // allocate a second array of that size class (multi-array support).
81 // Starting at 64 layers gives us 64 * (size class memory) of pre-allocated
82 // VRAM per class. For the 4096 class that's 64 * 4096*4096*4 = 4 GB which
83 // is way too much - we use a smaller starting count for the larger classes.
85 
86 // ---------------------------------------------------------------------------
87 // Storage API
88 // ---------------------------------------------------------------------------
89 namespace Blam
90 {
91  namespace RenderingBGFX
92  {
93  namespace TextureStorage
94  {
95  // Initialize storage. Allocates the size-class arrays. Call once
96  // at engine startup, after bgfx::init.
97  void Initialize();
98 
99  // Tear down storage. Destroys all arrays. Call at engine shutdown,
100  // before bgfx::shutdown.
101  void Shutdown();
102 
103  // Upload a texture into storage. Picks an appropriate size class,
104  // allocates a layer in the matching array, uploads the pixel data,
105  // returns a ref.
106  //
107  // `tag_path` is recorded for invalidation tracking. Callers should
108  // almost never call this directly - go through Textures::GetTextureRefFromTag
109  // which handles tag association and reuse.
110  //
111  // `pixel_data` is COPIED (the array is independent of the source
112  // buffer afterward).
113  //
114  // Returns an invalid ref on failure (texture too big, format
115  // unsupported, etc).
116  BlamTextureRef UploadFromTag(const char* tag_path,
117  int width, int height,
118  bgfx::TextureFormat::Enum format,
119  uint32_t sampler_flags,
120  const void* pixel_data,
121  int pixel_data_size);
122 
123  // Update the pixels of an existing layer. Used for hot-reload:
124  // when the source bitmap tag's pixel data changes, we update
125  // the layer in place rather than reallocating.
126  //
127  // `width` and `height` must match the layer's size class.
128  void UpdateLayer(BlamTextureRef ref,
129  int width, int height,
130  const void* pixel_data,
131  int pixel_data_size);
132 
133  // Free a layer. Invalidates the ref. Subsequent uploads may
134  // reuse the slot.
135  //
136  // Materials/raw-handle holders don't call this directly - it's
137  // called from Textures::OnBitmapTagUnloading via the tag-path
138  // reverse lookup.
139  void Release(BlamTextureRef ref);
140 
141  // Per-frame: bind all active size-class arrays to the given view.
142  // Call once at the start of the gbuffer pass (or any pass that
143  // samples material textures).
144  //
145  // Each array gets bound to a contiguous range of sampler stages
146  // starting at `first_stage`. Stage assignment:
147  // first_stage + 0 -> array for size class 0
148  // first_stage + 1 -> array for size class 1
149  // ...
150  //
151  // The shader expects samplers s_texArray0..s_texArrayN at these
152  // stages. If a size class has no allocated array yet (no textures
153  // of that size loaded), the stage is bound to a 1x1 fallback
154  // to keep the sampler valid.
155  void BindArraysForFrame(uint8_t first_stage);
156 
157  // Number of size classes. Equals BLAM_TEXTURE_SIZE_CLASS_COUNT.
158  // Convenience for callers iterating size classes.
159  int GetSizeClassCount();
160  }
161 
162  namespace Textures
163  {
164  // New API: get the abstract ref for a bitmap tag's texture.
165  // On first call, uploads to array storage. Subsequent calls return
166  // the cached ref. Returns invalid ref if the tag doesn't exist or
167  // the texture can't be uploaded.
168  //
169  // This is the call materials will use during their bake (in Phase 2).
170  // In Phase 1 nothing in the engine calls it yet - it's available
171  // for testing and future use.
172  //
173  // Custom shaders continue to use the existing GetTextureFromTag
174  // (returns raw bgfx::TextureHandle).
175  BlamTextureRef GetTextureRefFromTag(std::string tag_path);
176 
177  // Hook for the tag system. Call this from your tag unload path,
178  // BEFORE the bitmap's pixel data goes away.
179  //
180  // Releases both forms of the texture (raw handle if created,
181  // array ref if created) and removes them from the lookup map.
182  //
183  // Safe to call for any tag - if the tag isn't a bitmap or wasn't
184  // uploaded, this is a no-op.
185  void OnBitmapTagUnloading(std::string tag_path);
186  }
187 
188  // NOTE: Materials::PrewarmMaterials will be added in Phase 2 when
189  // the material bake learns to use BlamTextureRef. In Phase 1 it
190  // would be a no-op so we don't declare it yet.
191  }
192 }
Blam
Namespace surrounding all major engine components.
Definition: api.h:25
BLAM_TEXTURE_INITIAL_LAYERS_PER_CLASS
const int BLAM_TEXTURE_INITIAL_LAYERS_PER_CLASS[BLAM_TEXTURE_SIZE_CLASS_COUNT]
Definition: texture_storage.cpp:37
Blam::RenderingBGFX::TextureStorage::UpdateLayer
void UpdateLayer(BlamTextureRef ref, int width, int height, const void *pixel_data, int pixel_data_size)
Definition: texture_storage.cpp:373
Blam::RenderingBGFX::TextureStorage::BindArraysForFrame
void BindArraysForFrame(uint8_t first_stage)
Definition: texture_storage.cpp:424
uint8_t
unsigned char uint8_t
Definition: stdint.h:15
Blam::RenderingBGFX::TextureStorage::GetSizeClassCount
int GetSizeClassCount()
Definition: texture_storage.cpp:479
BlamTextureRef_MakeInvalid
BlamTextureRef BlamTextureRef_MakeInvalid()
Definition: texture_storage.h:50
uint32_t
unsigned int uint32_t
Definition: stdint.h:17
BlamTextureRef::reserved
uint32_t reserved
Definition: texture_storage.h:38
BLAM_TEXTURE_REF_INVALID_STORAGE_ID
#define BLAM_TEXTURE_REF_INVALID_STORAGE_ID
Definition: texture_storage.h:41
BlamTextureRef_IsValid
bool BlamTextureRef_IsValid(BlamTextureRef ref)
Definition: texture_storage.h:44
Blam::RenderingBGFX::TextureStorage::Release
void Release(BlamTextureRef ref)
Definition: texture_storage.cpp:401
Blam::RenderingBGFX::TextureStorage::Shutdown
void Shutdown()
Definition: texture_storage.cpp:280
Blam::RenderingBGFX::TextureStorage::UploadFromTag
BlamTextureRef UploadFromTag(const char *tag_path, int width, int height, bgfx::TextureFormat::Enum format, uint32_t sampler_flags, const void *pixel_data, int pixel_data_size)
Definition: texture_storage.cpp:307
BLAM_TEXTURE_SIZE_CLASS_COUNT
#define BLAM_TEXTURE_SIZE_CLASS_COUNT
Definition: texture_storage.h:74
Blam::RenderingBGFX::Textures::GetTextureRefFromTag
BlamTextureRef GetTextureRefFromTag(std::string tag_path)
Definition: bitmaps.cpp:566
BlamTextureRef
Definition: texture_storage.h:33
BlamTextureRef::storage_id
uint32_t storage_id
Definition: texture_storage.h:35
Blam::RenderingBGFX::Textures::OnBitmapTagUnloading
void OnBitmapTagUnloading(std::string tag_path)
Definition: bitmaps.cpp:619
BlamTextureRef::layer
uint32_t layer
Definition: texture_storage.h:36
BlamTextureRef::sampler_flags
uint32_t sampler_flags
Definition: texture_storage.h:37
Blam::RenderingBGFX::TextureStorage::Initialize
void Initialize()
Definition: texture_storage.cpp:248
BLAM_TEXTURE_SIZE_CLASS_RESOLUTIONS
const int BLAM_TEXTURE_SIZE_CLASS_RESOLUTIONS[BLAM_TEXTURE_SIZE_CLASS_COUNT]
Definition: texture_storage.cpp:33