Pyrogenesis  trunk
TextureManager.h
Go to the documentation of this file.
1 /* Copyright (C) 2022 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_TEXTUREMANAGER
19 #define INCLUDED_TEXTUREMANAGER
20 
21 #include "graphics/Texture.h"
22 #include "lib/file/vfs/vfs.h"
23 #include "lib/tex/tex.h"
27 
28 #include <memory>
29 
30 class CTextureProperties;
32 
33 /**
34  * Texture manager with asynchronous loading and automatic DDS conversion/compression.
35  *
36  * Input textures can be any format. They will be converted to DDS using settings defined
37  * in files named "texture.xml", in the same directory as the texture and in its parent
38  * directories. See CTextureConverter for the XML syntax. The DDS file will be cached
39  * for faster loading in the future.
40  *
41  * Typically the graphics code will initialise many textures at the start of the game,
42  * mostly for off-screen objects, by calling CreateTexture().
43  * Loading texture data may be very slow (especially if it needs to be converted
44  * to DDS), and we don't want the game to become unresponsive.
45  * CreateTexture therefore returns an object immediately, without loading the
46  * texture. If the object is never used then the data will never be loaded.
47  *
48  * Typically, the renderer will call CTexture::Bind() when it wants to use the
49  * texture. This will trigger the loading of the texture data. If it can be loaded
50  * quickly (i.e. there is already a cached DDS version), then it will be loaded before
51  * the function returns, and the texture can be rendered as normal.
52  *
53  * If loading will take a long time, then Bind() binds a default placeholder texture
54  * and starts loading the texture in the background. It will use the correct texture
55  * when the renderer next calls Bind() after the load has finished.
56  *
57  * It is also possible to prefetch textures which are not being rendered yet, but
58  * are expected to be rendered soon (e.g. for off-screen terrain tiles).
59  * These will be loaded in the background, when there are no higher-priority textures
60  * to load.
61  *
62  * The same texture file can be safely loaded multiple times with different backend parameters
63  * (but this should be avoided whenever possible, as it wastes VRAM).
64  *
65  * For release packages, DDS files can be precached by appending ".dds" to their name,
66  * which will be used instead of doing runtime conversion. This means most players should
67  * never experience the slow asynchronous conversion behaviour.
68  * These cache files will typically be packed into an archive for faster loading;
69  * if no archive cache is available then the source file will be converted and stored
70  * as a loose cache file on the user's disk.
71  */
73 {
75 
76 public:
77  /**
78  * Construct texture manager. vfs must be the VFS instance used for all textures
79  * loaded from this object.
80  * highQuality is slower and intended for batch-conversion modes.
81  */
82  CTextureManager(PIVFS vfs, bool highQuality, Renderer::Backend::IDevice* device);
83 
85 
86  /**
87  * Create a texture with the given properties.
88  * The texture data will not be loaded immediately.
89  */
91 
92  /**
93  * Wraps a backend texture.
94  */
96  std::unique_ptr<Renderer::Backend::ITexture> backendTexture);
97 
98  /**
99  * Returns a magenta texture. Use this for highlighting errors
100  * (e.g. missing terrain textures).
101  */
102  const CTexturePtr& GetErrorTexture();
103 
104  /**
105  * Returns a single color RGBA texture with CColor(1.0f, 1.0f, 1.0f, 1.0f).
106  */
107  const CTexturePtr& GetWhiteTexture();
108 
109  /**
110  * Returns a single color RGBA texture with CColor(0.0f, 0.0f, 0.0f, 0.0f).
111  */
113 
114  /**
115  * Returns a white RGBA texture with alpha gradient.
116  */
118 
119  /**
120  * Returns a single color RGBA texture cube with CColor(0.0f, 0.0f, 0.0f, 1.0f).
121  */
123 
124  /**
125  * Work on asynchronous texture loading operations, if any.
126  * Returns true if it did any work.
127  * The caller should typically loop this per frame until it returns
128  * false or exceeds the allocated time for this frame.
129  */
130  bool MakeProgress();
131 
132  /**
133  * Work on asynchronous texture uploading operations, if any.
134  * Returns true if it did any work. Mostly the same as MakeProgress.
135  */
137 
138  /**
139  * Synchronously converts and compresses and saves the texture,
140  * and returns the output path (minus a "cache/" prefix). This
141  * is intended for pre-caching textures in release archives.
142  * @return true on success
143  */
144  bool GenerateCachedTexture(const VfsPath& path, VfsPath& outputPath);
145 
146  /**
147  * Returns true if the given texture exists.
148  * This tests both for the original and converted filename.
149  */
150  bool TextureExists(const VfsPath& path) const;
151 
152  /**
153  * Returns total number of bytes uploaded for all current texture.
154  */
155  size_t GetBytesUploaded() const;
156 
157  /**
158  * Should be called on any quality or anisotropic change.
159  */
160  void OnQualityChanged();
161 
162 private:
164 };
165 
166 /**
167  * Represents the filename and GL parameters of a texture,
168  * for passing to CTextureManager::CreateTexture.
169  */
171 {
172  friend class CTextureManagerImpl;
173  friend struct TextureCacheCmp;
174  friend struct TPequal_to;
175  friend struct TPhash;
176 
177 public:
178  /**
179  * Use the given texture name, and default GL parameters.
180  */
181  explicit CTextureProperties(const VfsPath& path)
182  : m_Path(path)
183  {
184  }
185 
187  const VfsPath& path, const Renderer::Backend::Format formatOverride)
188  : m_Path(path), m_FormatOverride(formatOverride)
189  {
190  }
191 
192  /**
193  * Set sampler address mode.
194  */
196  {
197  m_AddressModeU = m_AddressModeV = addressMode;
198  }
199 
200  /**
201  * Set sampler address mode separately for different coordinates.
202  */
204  const Renderer::Backend::Sampler::AddressMode addressModeU,
205  const Renderer::Backend::Sampler::AddressMode addressModeV)
206  {
207  m_AddressModeU = addressModeU;
208  m_AddressModeV = addressModeV;
209  }
210 
211  /**
212  * The value of max anisotropy is set by options. Though it might make sense
213  * to add an override.
214  */
215  void SetAnisotropicFilter(const bool enabled) { m_AnisotropicFilterEnabled = enabled; }
216 
217  // TODO: rather than this static definition of texture properties
218  // (especially anisotropy), maybe we want something that can be more
219  // easily tweaked in an Options menu? e.g. the caller just specifies
220  // "terrain texture mode" and we combine it with the user's options.
221  // That'd let us dynamically change texture properties easily.
222  //
223  // enum EQualityMode
224  // {
225  // NONE,
226  // TERRAIN,
227  // MODEL,
228  // GUI
229  // }
230  // void SetQuality(EQualityMode mode, float anisotropy, float lodbias, int reducemipmaps, ...);
231  //
232  // or something a bit like that.
233 
234  void SetIgnoreQuality(bool ignore) { m_IgnoreQuality = ignore; }
235 
236 private:
237  // Must update TPhash, TPequal_to when changing these fields
239 
244  bool m_AnisotropicFilterEnabled = false;
245  Renderer::Backend::Format m_FormatOverride =
247  bool m_IgnoreQuality = false;
248 };
249 
250 /**
251  * Represents a texture object.
252  * The texture data may or may not have been loaded yet.
253  * Before it has been loaded, all operations will act on a default
254  * 1x1-pixel grey texture instead.
255  */
256 class CTexture
257 {
259 public:
260  ~CTexture();
261 
262  /**
263  * Returns the width (in pixels) of the current texture.
264  */
265  size_t GetWidth() const;
266 
267  /**
268  * Returns the height (in pixels) of the current texture.
269  */
270  size_t GetHeight() const;
271 
272  /**
273  * Returns whether the current texture has an alpha channel.
274  */
275  bool HasAlpha() const;
276 
277  /**
278  * Returns the ARGB value of the lowest mipmap level (i.e. the
279  * average of the whole texture).
280  * Returns 0 if the texture has no mipmaps.
281  */
282  u32 GetBaseColor() const;
283 
284  /**
285  * Returns total number of bytes uploaded for this texture.
286  */
287  size_t GetUploadedSize() const;
288 
289  /**
290  * Uploads a texture data to a backend texture if successfully loaded.
291  * If the texture data hasn't been loaded yet, this may wait a short while to
292  * load it. If loading takes too long then it will return sooner and the data will
293  * be loaded in a background thread, so this does not guarantee the texture really
294  * will be uploaded.
295  */
296  void UploadBackendTextureIfNeeded(
297  Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
298 
299  /**
300  * Returns a backend texture if successfully uploaded, else fallback.
301  */
302  Renderer::Backend::ITexture* GetBackendTexture();
303  const Renderer::Backend::ITexture* GetBackendTexture() const;
304 
305  /**
306  * Attempt to load the texture data quickly, as with
307  * GetUploadedBackendTextureIfNeeded(). Returns whether the texture data is
308  * currently loaded (but not uploaded).
309  */
310  bool TryLoad();
311 
312  /**
313  * Returns whether the texture data is currently loaded.
314  */
315  bool IsLoaded() const { return m_State == LOADED; }
316 
317  /**
318  * Returns whether the texture data is currently uploaded.
319  */
320  bool IsUploaded() const { return m_State == UPLOADED; }
321 
322  /**
323  * Activate the prefetching optimisation for this texture.
324  * Use this if it is likely the texture will be needed in the near future.
325  * It will be loaded in the background so that it is likely to be ready when
326  * it is used by Bind().
327  */
328  void Prefetch();
329 
330 private:
331  friend class CTextureManagerImpl;
332  friend class CPredefinedTexture;
333  friend struct TextureCacheCmp;
334  friend struct TPequal_to;
335  friend struct TPhash;
336 
337  // Only the texture manager can create these
338  explicit CTexture(
339  std::unique_ptr<Renderer::Backend::ITexture> texture,
340  Renderer::Backend::ITexture* fallback,
341  const CTextureProperties& props, CTextureManagerImpl* textureManager);
342 
343  void ResetBackendTexture(
344  std::unique_ptr<Renderer::Backend::ITexture> backendTexture,
345  Renderer::Backend::ITexture* fallbackBackendTexture);
346 
348 
349  std::unique_ptr<Renderer::Backend::ITexture> m_BackendTexture;
350  // It's possible to m_FallbackBackendTexture references m_BackendTexture.
351  Renderer::Backend::ITexture* m_FallbackBackendTexture = nullptr;
353  std::unique_ptr<Tex> m_TextureData;
354  size_t m_UploadedSize = 0;
355  uint32_t m_BaseLevelOffset = 0;
356 
357  enum
358  {
359  UNLOADED, // loading has not started
360  PREFETCH_NEEDS_LOADING, // was prefetched; currently waiting to try loading from cache
361  PREFETCH_NEEDS_CONVERTING, // was prefetched; currently waiting to be sent to the texture converter
362  PREFETCH_IS_CONVERTING, // was prefetched; currently being processed by the texture converter
363  HIGH_NEEDS_CONVERTING, // high-priority; currently waiting to be sent to the texture converter
364  HIGH_IS_CONVERTING, // high-priority; currently being processed by the texture converter
365  LOADED, // loading texture data has completed (successfully or not)
366  UPLOADED // uploading to backend has completed (successfully or not)
367  } m_State;
368 
370 
371  // Self-reference to let us recover the CTexturePtr for this object.
372  // (weak pointer to avoid cycles)
373  std::weak_ptr<CTexture> m_Self;
374 };
375 
376 #endif // INCLUDED_TEXTUREMANAGER
std::unique_ptr< Tex > m_TextureData
Definition: TextureManager.h:353
const CTexturePtr & GetAlphaGradientTexture()
Returns a white RGBA texture with alpha gradient.
Definition: TextureManager.cpp:1074
const CTexturePtr & GetErrorTexture()
Returns a magenta texture.
Definition: TextureManager.cpp:1059
Definition: TextureManager.h:364
bool GenerateCachedTexture(const VfsPath &path, VfsPath &outputPath)
Synchronously converts and compresses and saves the texture, and returns the output path (minus a "ca...
Definition: TextureManager.cpp:1095
Definition: TextureManager.h:359
void SetAnisotropicFilter(const bool enabled)
The value of max anisotropy is set by options.
Definition: TextureManager.h:215
CTexturePtr CreateTexture(const CTextureProperties &props)
Create a texture with the given properties.
Definition: TextureManager.cpp:1043
CTexturePtr WrapBackendTexture(std::unique_ptr< Renderer::Backend::ITexture > backendTexture)
Wraps a backend texture.
Definition: TextureManager.cpp:1048
Definition: TextureManager.cpp:351
Definition: ITexture.h:33
bool TextureExists(const VfsPath &path) const
Returns true if the given texture exists.
Definition: TextureManager.cpp:1054
Represents the filename and GL parameters of a texture, for passing to CTextureManager::CreateTexture...
Definition: TextureManager.h:170
const CTextureProperties m_Properties
Definition: TextureManager.h:347
NONCOPYABLE(CTextureManager)
std::weak_ptr< CTexture > m_Self
Definition: TextureManager.h:373
std::unique_ptr< Renderer::Backend::ITexture > m_BackendTexture
Definition: TextureManager.h:349
Definition: TextureManager.cpp:309
bool IsLoaded() const
Returns whether the texture data is currently loaded.
Definition: TextureManager.h:315
CTextureManagerImpl * m_TextureManager
Definition: TextureManager.h:369
std::shared_ptr< IVFS > PIVFS
Definition: vfs.h:220
Definition: TextureManager.cpp:332
void OnQualityChanged()
Should be called on any quality or anisotropic change.
Definition: TextureManager.cpp:1105
~CTextureManager()
Definition: TextureManager.cpp:1038
Definition: TextureManager.h:365
Texture manager with asynchronous loading and automatic DDS conversion/compression.
Definition: TextureManager.h:72
Format
Definition: Format.h:27
VfsPath m_Path
Definition: TextureManager.h:238
bool MakeProgress()
Work on asynchronous texture loading operations, if any.
Definition: TextureManager.cpp:1084
uint32_t u32
Definition: types.h:39
const CTexturePtr & GetBlackTextureCube()
Returns a single color RGBA texture cube with CColor(0.0f, 0.0f, 0.0f, 1.0f).
Definition: TextureManager.cpp:1079
Definition: TextureManager.cpp:108
Definition: path.h:79
void SetIgnoreQuality(bool ignore)
Definition: TextureManager.h:234
AddressMode
Definition: Sampler.h:41
u32 m_BaseColor
Definition: TextureManager.h:352
Definition: IDevice.h:47
size_t GetBytesUploaded() const
Returns total number of bytes uploaded for all current texture.
Definition: TextureManager.cpp:1100
Represents a texture object.
Definition: TextureManager.h:256
CTextureProperties(const VfsPath &path)
Use the given texture name, and default GL parameters.
Definition: TextureManager.h:181
Definition: TextureManager.h:363
CTextureManagerImpl * m
Definition: TextureManager.h:163
Definition: TextureManager.h:361
Definition: TextureManager.h:360
const CTexturePtr & GetWhiteTexture()
Returns a single color RGBA texture with CColor(1.0f, 1.0f, 1.0f, 1.0f).
Definition: TextureManager.cpp:1064
Definition: TextureManager.h:362
unsigned int uint32_t
Definition: wposix_types.h:53
Definition: vfs_util.cpp:39
bool IsUploaded() const
Returns whether the texture data is currently uploaded.
Definition: TextureManager.h:320
Definition: IDeviceCommandContext.h:40
void SetAddressMode(const Renderer::Backend::Sampler::AddressMode addressModeU, const Renderer::Backend::Sampler::AddressMode addressModeV)
Set sampler address mode separately for different coordinates.
Definition: TextureManager.h:203
std::shared_ptr< CTexture > CTexturePtr
Definition: Texture.h:22
bool MakeUploadProgress(Renderer::Backend::IDeviceCommandContext *deviceCommandContext)
Work on asynchronous texture uploading operations, if any.
Definition: TextureManager.cpp:1089
CTextureManager(PIVFS vfs, bool highQuality, Renderer::Backend::IDevice *device)
Construct texture manager.
Definition: TextureManager.cpp:1033
void SetAddressMode(const Renderer::Backend::Sampler::AddressMode addressMode)
Set sampler address mode.
Definition: TextureManager.h:195
CTextureProperties(const VfsPath &path, const Renderer::Backend::Format formatOverride)
Definition: TextureManager.h:186
const CTexturePtr & GetTransparentTexture()
Returns a single color RGBA texture with CColor(0.0f, 0.0f, 0.0f, 0.0f).
Definition: TextureManager.cpp:1069