Overte C++ Documentation
Texture.h
1 //
2 // Texture.h
3 // libraries/gpu/src/gpu
4 //
5 // Created by Sam Gateau on 1/16/2015.
6 // Copyright 2014 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 #ifndef hifi_gpu_Texture_h
12 #define hifi_gpu_Texture_h
13 
14 #include <algorithm> //min max and more
15 #include <bitset>
16 
17 #include <QMetaType>
18 #include <QUrl>
19 
20 #include <functional>
21 #include <shared/Storage.h>
22 #include <shared/FileCache.h>
23 #include <RegisteredMetaTypes.h>
24 #include "Forward.h"
25 #include "Resource.h"
26 #include "Metric.h"
27 
28 const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192;
29 
30 namespace ktx {
31  class KTX;
32  using KTXUniquePointer = std::unique_ptr<KTX>;
33  struct KTXDescriptor;
34  using KTXDescriptorPointer = std::unique_ptr<KTXDescriptor>;
35  struct Header;
36  struct KeyValue;
37  using KeyValues = std::list<KeyValue>;
38 }
39 
40 namespace khronos { namespace gl { namespace texture {
41  enum class InternalFormat: uint32_t;
42 }}}
43 
44 namespace gpu {
45 
46 enum class BackendTarget {
47  GL41,
48  GL45,
49  GLES32
50 };
51 
52 const std::string SOURCE_HASH_KEY { "hifi.sourceHash" };
53 
54 const uint8 SOURCE_HASH_BYTES = 16;
55 
56 // THe spherical harmonics is a nice tool for cubemap, so if required, the irradiance SH can be automatically generated
57 // with the cube texture
58 class Texture;
59 class SphericalHarmonics {
60 public:
61  glm::vec3 L00 ; float spare0;
62  glm::vec3 L1m1 ; float spare1;
63  glm::vec3 L10 ; float spare2;
64  glm::vec3 L11 ; float spare3;
65  glm::vec3 L2m2 ; float spare4;
66  glm::vec3 L2m1 ; float spare5;
67  glm::vec3 L20 ; float spare6;
68  glm::vec3 L21 ; float spare7;
69  glm::vec3 L22 ; float spare8;
70 
71  static const int NUM_COEFFICIENTS = 9;
72 
73  enum Preset {
74  OLD_TOWN_SQUARE = 0,
75  GRACE_CATHEDRAL,
76  EUCALYPTUS_GROVE,
77  ST_PETERS_BASILICA,
78  UFFIZI_GALLERY,
79  GALILEOS_TOMB,
80  VINE_STREET_KITCHEN,
81  BREEZEWAY,
82  CAMPUS_SUNSET,
83  FUNSTON_BEACH_SUNSET,
84 
85  NUM_PRESET,
86  };
87 
88  void assignPreset(int p);
89 
90  void evalFromTexture(const Texture& texture, gpu::BackendTarget target);
91 };
92 typedef std::shared_ptr< SphericalHarmonics > SHPointer;
93 
94 class Sampler {
95 public:
96 
97  enum Filter {
98  FILTER_MIN_MAG_POINT, // top mip only
99  FILTER_MIN_POINT_MAG_LINEAR, // top mip only
100  FILTER_MIN_LINEAR_MAG_POINT, // top mip only
101  FILTER_MIN_MAG_LINEAR, // top mip only
102 
103  FILTER_MIN_MAG_MIP_POINT,
104  FILTER_MIN_MAG_POINT_MIP_LINEAR,
105  FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
106  FILTER_MIN_POINT_MAG_MIP_LINEAR,
107  FILTER_MIN_LINEAR_MAG_MIP_POINT,
108  FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
109  FILTER_MIN_MAG_LINEAR_MIP_POINT,
110  FILTER_MIN_MAG_MIP_LINEAR,
111  FILTER_ANISOTROPIC,
112 
113  NUM_FILTERS,
114  };
115 
116  enum WrapMode {
117  WRAP_REPEAT = 0,
118  WRAP_MIRROR,
119  WRAP_CLAMP,
120  WRAP_BORDER,
121  WRAP_MIRROR_ONCE,
122 
123  NUM_WRAP_MODES
124  };
125 
126  static const uint8 MAX_MIP_LEVEL = 0xFF;
127 
128  class Desc {
129  public:
130  glm::vec4 _borderColor{ 1.0f };
131  uint32 _maxAnisotropy = 16;
132 
133  uint8 _filter = FILTER_MIN_MAG_POINT;
134  uint8 _comparisonFunc = ALWAYS;
135 
136  uint8 _wrapModeU = WRAP_REPEAT;
137  uint8 _wrapModeV = WRAP_REPEAT;
138  uint8 _wrapModeW = WRAP_REPEAT;
139 
140  uint8 _mipOffset = 0;
141  uint8 _minMip = 0;
142  uint8 _maxMip = MAX_MIP_LEVEL;
143 
144  Desc() {}
145  Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {}
146 
147  bool operator==(const Desc& other) const {
148  return _borderColor == other._borderColor &&
149  _maxAnisotropy == other._maxAnisotropy &&
150  _filter == other._filter &&
151  _comparisonFunc == other._comparisonFunc &&
152  _wrapModeU == other._wrapModeU &&
153  _wrapModeV == other._wrapModeV &&
154  _wrapModeW == other._wrapModeW &&
155  _mipOffset == other._mipOffset &&
156  _minMip == other._minMip &&
157  _maxMip == other._maxMip;
158  }
159  };
160 
161  Sampler() {}
162  Sampler(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _desc(filter, wrap) {}
163  Sampler(const Desc& desc) : _desc(desc) {}
164  ~Sampler() {}
165 
166  const glm::vec4& getBorderColor() const { return _desc._borderColor; }
167 
168  uint32 getMaxAnisotropy() const { return _desc._maxAnisotropy; }
169 
170  WrapMode getWrapModeU() const { return WrapMode(_desc._wrapModeU); }
171  WrapMode getWrapModeV() const { return WrapMode(_desc._wrapModeV); }
172  WrapMode getWrapModeW() const { return WrapMode(_desc._wrapModeW); }
173 
174  Filter getFilter() const { return Filter(_desc._filter); }
175  ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); }
176  bool doComparison() const { return getComparisonFunction() != ALWAYS; }
177 
178  uint8 getMipOffset() const { return _desc._mipOffset; }
179  uint8 getMinMip() const { return _desc._minMip; }
180  uint8 getMaxMip() const { return _desc._maxMip; }
181 
182  const Desc& getDesc() const { return _desc; }
183 
184  bool operator==(const Sampler& other) const {
185  return _desc == other._desc;
186  }
187  bool operator!=(const Sampler& other) const {
188  return !(*this == other);
189  }
190 protected:
191  Desc _desc;
192 
193  friend class Deserializer;
194 };
195 
196 enum class TextureUsageType : uint8 {
197  RENDERBUFFER, // Used as attachments to a framebuffer
198  RESOURCE, // Resource textures, like materials... subject to memory manipulation
199  STRICT_RESOURCE, // Resource textures not subject to manipulation, like the normal fitting texture
200  EXTERNAL,
201 };
202 
203 class Texture : public Resource {
204  static ContextMetricCount _textureCPUCount;
205  static ContextMetricSize _textureCPUMemSize;
206 
207  static std::atomic<Size> _allowedCPUMemoryUsage;
208  static std::atomic<bool> _enableSparseTextures;
209  static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
210 
211 public:
212  static const uint32_t CUBE_FACE_COUNT { 6 };
213  static uint32_t getTextureCPUCount();
214  static Size getTextureCPUMemSize();
215 
216  static Size getAllowedGPUMemoryUsage();
217  static void setAllowedGPUMemoryUsage(Size size);
218 
219  static bool getEnableSparseTextures();
220  static void setEnableSparseTextures(bool enabled);
221 
222  using ExternalRecycler = std::function<void(uint32, void*)>;
223  using ExternalIdAndFence = std::pair<uint32, void*>;
224  using ExternalUpdates = std::list<ExternalIdAndFence>;
225 
226  class Usage {
227  public:
228  enum FlagBit {
229  COLOR = 0, // Texture is a color map
230  NORMAL, // Texture is a normal map
231  ALPHA, // Texture has an alpha channel
232  ALPHA_MASK, // Texture alpha channel is a Mask 0/1
233  NUM_FLAGS,
234  };
235 
236  typedef std::bitset<NUM_FLAGS> Flags;
237 
238  // The key is the Flags
239  Flags _flags;
240 
241  Usage() : _flags(0) {}
242  Usage(const Flags& flags) : _flags(flags) {}
243 
244  bool operator== (const Usage& rhs) const { return _flags == rhs._flags; }
245  bool operator!= (const Usage& rhs) const { return _flags != rhs._flags; }
246 
247  class Builder {
248  friend class Usage;
249  Flags _flags{ 0 };
250  public:
251  Builder() {}
252 
253  Usage build() const { return Usage(_flags); }
254 
255  Builder& withColor() { _flags.set(COLOR); return (*this); }
256  Builder& withNormal() { _flags.set(NORMAL); return (*this); }
257  Builder& withAlpha() { _flags.set(ALPHA); return (*this); }
258  Builder& withAlphaMask() { _flags.set(ALPHA_MASK); return (*this); }
259  };
260  Usage(const Builder& builder) : Usage(builder._flags) {}
261 
262  bool isColor() const { return _flags[COLOR]; }
263  bool isNormal() const { return _flags[NORMAL]; }
264 
265  bool isAlpha() const { return _flags[ALPHA]; }
266  bool isAlphaMask() const { return _flags[ALPHA_MASK]; }
267 
268  bool operator==(const Usage& usage) { return (_flags == usage._flags); }
269  bool operator!=(const Usage& usage) { return (_flags != usage._flags); }
270  };
271 
272  enum Type : uint8 {
273  TEX_1D = 0,
274  TEX_2D,
275  TEX_3D,
276  TEX_CUBE,
277 
278  NUM_TYPES,
279  };
280 
281  // Definition of the cube face name and layout
282  enum CubeFace {
283  CUBE_FACE_RIGHT_POS_X = 0,
284  CUBE_FACE_LEFT_NEG_X,
285  CUBE_FACE_TOP_POS_Y,
286  CUBE_FACE_BOTTOM_NEG_Y,
287  CUBE_FACE_BACK_POS_Z,
288  CUBE_FACE_FRONT_NEG_Z,
289 
290  NUM_CUBE_FACES, // Not a valid vace index
291  };
292 
293  // Lines of pixels are padded to be a multiple of "PACKING_SIZE" which is 4 bytes
294  static const uint32 PACKING_SIZE = 4;
295  static uint8 evalPaddingNumBytes(Size byteSize) { return (uint8) (3 - (byteSize + 3) % PACKING_SIZE); }
296  static Size evalPaddedSize(Size byteSize) { return byteSize + (Size) evalPaddingNumBytes(byteSize); }
297 
298 
299  using PixelsPointer = storage::StoragePointer;
300  class Storage {
301  public:
302  Storage() {}
303  virtual ~Storage() {}
304 
305  virtual void reset() = 0;
306  virtual PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 0;
307  virtual Size getMipFaceSize(uint16 level, uint8 face = 0) const = 0;
308  virtual void assignMipData(uint16 level, const storage::StoragePointer& storage) = 0;
309  virtual void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) = 0;
310  virtual bool isMipAvailable(uint16 level, uint8 face = 0) const = 0;
311  virtual uint16 minAvailableMipLevel() const { return 0; }
312  Texture::Type getType() const { return _type; }
313 
314  Stamp getStamp() const { return _stamp; }
315  Stamp bumpStamp() { return ++_stamp; }
316 
317  void setFormat(const Element& format) { _format = format; }
318  Element getFormat() const { return _format; }
319 
320  private:
321  Stamp _stamp { 0 };
322  Element _format;
323  Texture::Type _type { Texture::TEX_2D }; // The type of texture is needed to know the number of faces to expect
324  Texture* _texture { nullptr }; // Points to the parent texture (not owned)
325  virtual void assignTexture(Texture* tex); // Texture storage is pointing to ONE corrresponding Texture.
326  const Texture* getTexture() const { return _texture; }
327  friend class Texture;
328  };
329 
330  class MemoryStorage : public Storage {
331  public:
332  void reset() override;
333  PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
334  Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
335  void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
336  void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
337  bool isMipAvailable(uint16 level, uint8 face = 0) const override;
338 
339  protected:
340  void allocateMip(uint16 level);
341  std::vector<std::vector<PixelsPointer>> _mips; // an array of mips, each mip is an array of faces
342  };
343 
344  class KtxStorage : public Storage {
345  public:
346  KtxStorage(const storage::StoragePointer& storage);
347  KtxStorage(const std::string& filename);
348  KtxStorage(const cache::FilePointer& file);
349  PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
350  Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
351  bool isMipAvailable(uint16 level, uint8 face = 0) const override;
352  void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
353  void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
354  uint16 minAvailableMipLevel() const override;
355 
356  void reset() override { }
357 
358  // Don't keep files open forever. We close them at the beginning of each frame (GLBackend::recycle)
359  static void releaseOpenKtxFiles();
360 
361  protected:
362  std::shared_ptr<storage::FileStorage> maybeOpenFile() const;
363 
364  mutable std::shared_ptr<std::mutex> _cacheFileMutex { std::make_shared<std::mutex>() };
365  mutable std::weak_ptr<storage::FileStorage> _cacheFile;
366 
367  static std::vector<std::pair<std::shared_ptr<storage::FileStorage>, std::shared_ptr<std::mutex>>> _cachedKtxFiles;
368  static std::mutex _cachedKtxFilesMutex;
369 
370  storage::StoragePointer _storage;
371  std::string _filename;
372  cache::FilePointer _cacheEntry;
373  std::atomic<uint8_t> _minMipLevelAvailable;
374  size_t _offsetToMinMipKV;
375 
376  ktx::KTXDescriptorPointer _ktxDescriptor;
377  friend class Texture;
378  friend class Serializer;
379  friend class Deserializer;
380  };
381 
382  uint16 minAvailableMipLevel() const { return _storage->minAvailableMipLevel(); };
383 
384  static const uint16 MAX_NUM_MIPS = 0;
385  static const uint16 SINGLE_MIP = 1;
386  static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
387  static TexturePointer create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
388  static TexturePointer create2DArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
389  static TexturePointer create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
390  static TexturePointer createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler());
391  static TexturePointer createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
392  static TexturePointer createRenderBufferMultisample(const Element& texelFormat, uint16 width, uint16 height, uint16 numSamples, const Sampler& sampler = Sampler());
393  static TexturePointer createRenderBufferArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
394  static TexturePointer createRenderBufferMultisampleArray(const Element& texelFormat, uint16 width, uint16 height, uint16 numSlices, uint16 numSamples, const Sampler& sampler = Sampler());
395  static TexturePointer createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
396  static TexturePointer createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler());
397 
398  // After the texture has been created, it should be defined
399  bool isDefined() const { return _defined; }
400 
401  Texture(TextureUsageType usageType);
402  ~Texture();
403 
404  Stamp getStamp() const { return _stamp; }
405  Stamp getDataStamp() const { return _storage->getStamp(); }
406 
407  // The theoretical size in bytes of data stored in the texture
408  // For the master (level) first level of mip
409  Size getSize() const override { return _size; }
410 
411  // Size and format
412  Type getType() const { return _type; }
413  TextureUsageType getUsageType() const { return _usageType; }
414 
415  bool isColorRenderTarget() const;
416  bool isDepthStencilRenderTarget() const;
417 
418  Element getTexelFormat() const { return _texelFormat; }
419 
420  void setSize(int width, int height);
421  Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); }
422  uint16 getWidth() const { return _width; }
423  uint16 getHeight() const { return _height; }
424  uint16 getDepth() const { return _depth; }
425 
426  void setOriginalSize(int width, int height);
427  int getOriginalWidth() const { return _originalWidth; }
428  int getOriginalHeight() const { return _originalHeight; }
429 
430  // The number of faces is mostly used for cube map, and maybe for stereo ? otherwise it's 1
431  // For cube maps, this means the pixels of the different faces are supposed to be packed back to back in a mip
432  // as if the height was NUM_FACES time bigger.
433  static uint8 NUM_FACES_PER_TYPE[NUM_TYPES];
434  uint8 getNumFaces() const { return NUM_FACES_PER_TYPE[getType()]; }
435 
436  // The texture is an array if the _numSlices is not 0.
437  // otherwise, if _numSLices is 0, then the texture is NOT an array
438  // The number of slices returned is 1 at the minimum (if not an array) or the actual _numSlices.
439  bool isArray() const { return _numSlices > 0; }
440  uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); }
441 
442  uint16 getNumSamples() const { return _numSamples; }
443  // NumSamples can only have certain values based on the hw
444  static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
445  bool isMultisample() const { return _numSamples > 1; }
446 
447  // max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
448  // It is defined at creation time (immutable)
449  uint16 getMaxMip() const { return _maxMipLevel; }
450  uint16 getNumMips() const { return _maxMipLevel + 1; }
451 
452  // Mips size evaluation
453 
454  // The number mips that a dimension could haves
455  // = 1 + log2(size)
456  static uint16 evalDimMaxNumMips(uint16 size);
457 
458  // The number mips that the texture could have if all existed
459  // = 1 + log2(max(width, height, depth))
460  uint16 evalMaxNumMips() const;
461  static uint16 evalMaxNumMips(const Vec3u& dimensions);
462 
463  // Check a num of mips requested against the maximum possible specified
464  // if passing -1 then answer the max
465  // simply does (askedNumMips == -1 ? maxMips : (numstd::min(askedNumMips, max))
466  static uint16 safeNumMips(uint16 askedNumMips, uint16 maxMips);
467 
468  // Same but applied to this texture's num max mips from evalNumMips()
469  uint16 safeNumMips(uint16 askedNumMips) const;
470 
471  // Eval the dimensions & sizes that the mips level SHOULD have
472  // not the one stored in the Texture
473 
474  // Dimensions
475  Vec3u evalMipDimensions(uint16 level) const;
476  uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
477  uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
478  uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
479 
480  // The true size of an image line or surface depends on the format, tiling and padding rules
481  //
482  // Here are the static function to compute the different sizes from parametered dimensions and format
483  // Tile size must be a power of 2
484  static uint16 evalTiledPadding(uint16 length, int tile) { int tileMinusOne = (tile - 1); return (tileMinusOne - (length + tileMinusOne) % tile); }
485  static uint16 evalTiledLength(uint16 length, int tile) { return length / tile + (evalTiledPadding(length, tile) != 0); }
486  static uint16 evalTiledWidth(uint16 width, int tileX) { return evalTiledLength(width, tileX); }
487  static uint16 evalTiledHeight(uint16 height, int tileY) { return evalTiledLength(height, tileY); }
488  static Size evalLineSize(uint16 width, const Element& format) { return evalPaddedSize(evalTiledWidth(width, format.getTile().x) * format.getSize()); }
489  static Size evalSurfaceSize(uint16 width, uint16 height, const Element& format) { return evalLineSize(width, format) * evalTiledHeight(height, format.getTile().x); }
490 
491  // Compute the theorical size of the texture elements storage depending on the specified format
492  Size evalStoredMipLineSize(uint16 level, const Element& format) const { return evalLineSize(evalMipWidth(level), format); }
493  Size evalStoredMipSurfaceSize(uint16 level, const Element& format) const { return evalSurfaceSize(evalMipWidth(level), evalMipHeight(level), format); }
494  Size evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalStoredMipSurfaceSize(level, format) * evalMipDepth(level); }
495  Size evalStoredMipSize(uint16 level, const Element& format) const { return evalStoredMipFaceSize(level, format) * getNumFaces(); }
496 
497  // For this texture's texel format and dimensions, compute the various mem sizes
498  Size evalMipLineSize(uint16 level) const { return evalStoredMipLineSize(level, getTexelFormat()); }
499  Size evalMipSurfaceSize(uint16 level) const { return evalStoredMipSurfaceSize(level, getTexelFormat()); }
500  Size evalMipFaceSize(uint16 level) const { return evalStoredMipFaceSize(level, getTexelFormat()); }
501  Size evalMipSize(uint16 level) const { return evalStoredMipSize(level, getTexelFormat()); }
502 
503  // Total size for all the mips of the texture
504  Size evalTotalSize(uint16 startingMip = 0) const;
505 
506  // Number of texels (not it s not directly proprtional to the size!
507  uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
508  uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); }
509 
510  // For convenience assign a source name
511  const std::string& source() const { return _source; }
512  void setSource(const std::string& source) { _source = source; }
513  const std::string& sourceHash() const { return _sourceHash; }
514  void setSourceHash(const std::string& sourceHash) { _sourceHash = sourceHash; }
515 
516  // Potentially change the minimum mip (mostly for debugging purpose)
517  bool setMinMip(uint16 newMinMip);
518  bool incremementMinMip(uint16 count = 1);
519  uint16 getMinMip() const { return _minMip; }
520  uint16 usedMipLevels() const { return (getNumMips() - _minMip); }
521 
522  // Generate the sub mips automatically for the texture
523  // If the storage version is not available (from CPU memory)
524  // Only works for the standard formats
525  void setAutoGenerateMips(bool enable);
526  bool isAutogenerateMips() const { return _autoGenerateMips; }
527 
528  // Managing Storage and mips
529 
530  // Mip storage format is constant across all mips
531  void setStoredMipFormat(const Element& format);
532  Element getStoredMipFormat() const;
533 
534  // Manually allocate the mips down until the specified maxMip
535  // this is just allocating the sysmem version of it
536  // in case autoGen is on, this doesn't allocate
537  // Explicitely assign mip data for a certain level
538  // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
539  void assignStoredMip(uint16 level, Size size, const Byte* bytes);
540  void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes);
541 
542  void assignStoredMip(uint16 level, storage::StoragePointer& storage);
543  void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage);
544 
545  // Access the stored mips and faces
546  const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
547  bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const;
548  Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
549  Size getStoredMipSize(uint16 level) const;
550  Size getStoredSize() const;
551 
552  void setStorage(std::unique_ptr<Storage>& newStorage);
553  void setKtxBacking(const storage::StoragePointer& storage);
554  void setKtxBacking(const std::string& filename);
555  void setKtxBacking(const cache::FilePointer& cacheEntry);
556 
557  // Usage is a a set of flags providing Semantic about the usage of the Texture.
558  void setUsage(const Usage& usage) { _usage = usage; }
559  Usage getUsage() const { return _usage; }
560 
561  // For Cube Texture, it's possible to generate the irradiance spherical harmonics and make them available with the texture
562  bool generateIrradiance(gpu::BackendTarget target);
563  const SHPointer& getIrradiance(uint16 slice = 0) const { return _irradiance; }
564  void overrideIrradiance(SHPointer irradiance) { _irradiance = irradiance; }
565  bool isIrradianceValid() const { return _isIrradianceValid; }
566 
567  // Own sampler
568  void setSampler(const Sampler& sampler);
569  const Sampler& getSampler() const { return _sampler; }
570  Stamp getSamplerStamp() const { return _samplerStamp; }
571 
572  void setFallbackTexture(const TexturePointer& fallback) { _fallback = fallback; }
573  TexturePointer getFallbackTexture() const { return _fallback.lock(); }
574 
575  void setExternalTexture(uint32 externalId, void* externalFence);
576  void setExternalRecycler(const ExternalRecycler& recycler);
577  ExternalRecycler getExternalRecycler() const;
578 
579  bool getImportant() const { return _important; }
580  void setImportant(bool important) { _important = important; }
581 
582  const GPUObjectPointer gpuObject {};
583 
584  ExternalUpdates getUpdates() const;
585 
586  // Serialize a texture into a KTX file
587  static ktx::KTXUniquePointer serialize(const Texture& texture, const glm::ivec2& originalSize);
588 
589  static std::pair<TexturePointer, glm::ivec2> build(const ktx::KTXDescriptor& descriptor);
590  static std::pair<TexturePointer, glm::ivec2> unserialize(const std::string& ktxFile);
591  static std::pair<TexturePointer, glm::ivec2> unserialize(const cache::FilePointer& cacheEntry, const std::string& source = std::string());
592 
593  static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
594  static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
595  static bool getCompressedFormat(khronos::gl::texture::InternalFormat format, Element& elFormat);
596 
597 protected:
598  const TextureUsageType _usageType;
599 
600  // Should only be accessed internally or by the backend sync function
601  mutable Mutex _externalMutex;
602  mutable std::list<ExternalIdAndFence> _externalUpdates;
603  ExternalRecycler _externalRecycler;
604 
605 
606  std::weak_ptr<Texture> _fallback;
607  // Not strictly necessary, but incredibly useful for debugging
608  std::string _source;
609  std::string _sourceHash;
610  std::unique_ptr< Storage > _storage;
611 
612  Stamp _stamp { 0 };
613 
614  Sampler _sampler;
615  Stamp _samplerStamp { 0 };
616 
617  Size _size { 0 };
618  Element _texelFormat;
619 
620  uint16 _width { 1 };
621  uint16 _height { 1 };
622  uint16 _depth { 1 };
623  int _originalWidth { 0 };
624  int _originalHeight { 0 };
625 
626  uint16 _numSamples { 1 };
627 
628  // if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
629  uint16 _numSlices { 0 };
630 
631  // valid _maxMipLevel is in the range [ 0 if no sub mips, log2(max(width, height, depth) ]
632  // The num of mips returned is _maxMipLevel + 1
633  uint16 _maxMipLevel { 0 };
634 
635  uint16 _minMip { 0 };
636 
637  Type _type { TEX_1D };
638 
639  Usage _usage;
640 
641  SHPointer _irradiance;
642  bool _autoGenerateMips = false;
643  bool _isIrradianceValid = false;
644  bool _defined = false;
645  bool _important = false;
646 
647  static TexturePointer create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips, const Sampler& sampler);
648 
649  Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips);
650 
651  friend class Serializer;
652  friend class Deserializer;
653 };
654 
655 typedef std::shared_ptr<Texture> TexturePointer;
656 typedef std::vector< TexturePointer > Textures;
657 
658  // TODO: For now TextureView works with Texture as a place holder for the Texture.
659  // The overall logic should be about the same except that the Texture will be a real GL Texture under the hood
660 class TextureView {
661 public:
662  typedef Resource::Size Size;
663 
664  TexturePointer _texture = TexturePointer(NULL);
665  uint16 _subresource = 0;
666  Element _element = Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
667 
668  TextureView() {};
669 
670  TextureView(const Element& element) :
671  _element(element)
672  {};
673 
674  // create the TextureView and own the Texture
675  TextureView(Texture* newTexture, const Element& element) :
676  _texture(newTexture),
677  _subresource(0),
678  _element(element)
679  {};
680  TextureView(const TexturePointer& texture, uint16 subresource, const Element& element) :
681  _texture(texture),
682  _subresource(subresource),
683  _element(element)
684  {};
685 
686  TextureView(const TexturePointer& texture, uint16 subresource, std::function<gpu::TexturePointer()> textureOperator = nullptr) :
687  _texture(texture),
688  _subresource(subresource),
689  _textureOperator(textureOperator)
690  {};
691 
692  ~TextureView() {}
693  TextureView(const TextureView& view) = default;
694  TextureView& operator=(const TextureView& view) = default;
695 
696  explicit operator bool() const { return bool(_texture); }
697  bool operator !() const { return (!_texture); }
698 
699  bool isValid() const { return bool(_texture); }
700 
701  bool isReference() const { return (bool)_textureOperator; }
702  std::function<gpu::TexturePointer()> getTextureOperator() const { return _textureOperator; }
703 
704 private:
705  std::function<gpu::TexturePointer()> _textureOperator { nullptr };
706 };
707 typedef std::vector<TextureView> TextureViews;
708 
709 // TextureSource is the bridge between a URL or a a way to produce an image and the final gpu::Texture that will be used to render it.
710 // It provides the mechanism to create a texture using a customizable TextureLoader
711 class TextureSource {
712 public:
713  TextureSource(const QUrl& url, int type = 0) : _imageUrl(url), _type(type) {}
714 
715  void setUrl(const QUrl& url) { _imageUrl = url; }
716  const QUrl& getUrl() const { return _imageUrl; }
717  const gpu::TexturePointer getGPUTexture() const;
718  void setType(int type) { _type = type; }
719  int getType() const { return _type; }
720 
721  void resetTexture(const gpu::TexturePointer& texture);
722  void resetTextureOperator(const std::function<gpu::TexturePointer()>& textureOperator);
723 
724  bool isDefined() const;
725  std::function<gpu::TexturePointer()> getTextureOperator() const { return _gpuTextureOperator; }
726 
727 protected:
728  gpu::TexturePointer _gpuTexture;
729  std::function<gpu::TexturePointer()> _gpuTextureOperator { nullptr };
730  mutable bool _locked { false };
731  QUrl _imageUrl;
732  int _type { 0 };
733 };
734 typedef std::shared_ptr< TextureSource > TextureSourcePointer;
735 
736 };
737 
738 namespace std {
739  template<> struct hash<gpu::Sampler> {
740  size_t operator()(const gpu::Sampler& sampler) const noexcept {
741  size_t result = 0;
742  const auto& desc = sampler.getDesc();
743  hash_combine(result, desc._comparisonFunc, desc._filter, desc._maxAnisotropy, desc._maxMip, desc._minMip, desc._wrapModeU, desc._wrapModeV, desc._wrapModeW);
744  return result;
745  }
746  };
747 }
748 
749 Q_DECLARE_METATYPE(gpu::TexturePointer)
750 
751 #endif
Base class for resources.
Definition: ResourceCache.h:409
A simple object wrapper for an OpenGL texture.
Definition: material-networking/src/material-networking/TextureCache.h:39