mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 14:29:03 +02:00
656 lines
25 KiB
C++
Executable file
656 lines
25 KiB
C++
Executable file
//
|
|
// Texture.h
|
|
// libraries/gpu/src/gpu
|
|
//
|
|
// Created by Sam Gateau on 1/16/2015.
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
#ifndef hifi_gpu_Texture_h
|
|
#define hifi_gpu_Texture_h
|
|
|
|
#include <algorithm> //min max and more
|
|
#include <bitset>
|
|
|
|
#include <QMetaType>
|
|
#include <QUrl>
|
|
|
|
#include <shared/Storage.h>
|
|
|
|
#include "Forward.h"
|
|
#include "Resource.h"
|
|
|
|
const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192;
|
|
|
|
namespace ktx {
|
|
class KTX;
|
|
using KTXUniquePointer = std::unique_ptr<KTX>;
|
|
struct KTXDescriptor;
|
|
using KTXDescriptorPointer = std::unique_ptr<KTXDescriptor>;
|
|
struct Header;
|
|
struct KeyValue;
|
|
using KeyValues = std::list<KeyValue>;
|
|
}
|
|
|
|
namespace gpu {
|
|
|
|
|
|
const std::string SOURCE_HASH_KEY { "hifi.sourceHash" };
|
|
|
|
const uint8 SOURCE_HASH_BYTES = 16;
|
|
|
|
// THe spherical harmonics is a nice tool for cubemap, so if required, the irradiance SH can be automatically generated
|
|
// with the cube texture
|
|
class Texture;
|
|
class SphericalHarmonics {
|
|
public:
|
|
glm::vec3 L00 ; float spare0;
|
|
glm::vec3 L1m1 ; float spare1;
|
|
glm::vec3 L10 ; float spare2;
|
|
glm::vec3 L11 ; float spare3;
|
|
glm::vec3 L2m2 ; float spare4;
|
|
glm::vec3 L2m1 ; float spare5;
|
|
glm::vec3 L20 ; float spare6;
|
|
glm::vec3 L21 ; float spare7;
|
|
glm::vec3 L22 ; float spare8;
|
|
|
|
static const int NUM_COEFFICIENTS = 9;
|
|
|
|
enum Preset {
|
|
OLD_TOWN_SQUARE = 0,
|
|
GRACE_CATHEDRAL,
|
|
EUCALYPTUS_GROVE,
|
|
ST_PETERS_BASILICA,
|
|
UFFIZI_GALLERY,
|
|
GALILEOS_TOMB,
|
|
VINE_STREET_KITCHEN,
|
|
BREEZEWAY,
|
|
CAMPUS_SUNSET,
|
|
FUNSTON_BEACH_SUNSET,
|
|
|
|
NUM_PRESET,
|
|
};
|
|
|
|
void assignPreset(int p);
|
|
|
|
void evalFromTexture(const Texture& texture);
|
|
};
|
|
typedef std::shared_ptr< SphericalHarmonics > SHPointer;
|
|
|
|
class Sampler {
|
|
public:
|
|
|
|
enum Filter {
|
|
FILTER_MIN_MAG_POINT, // top mip only
|
|
FILTER_MIN_POINT_MAG_LINEAR, // top mip only
|
|
FILTER_MIN_LINEAR_MAG_POINT, // top mip only
|
|
FILTER_MIN_MAG_LINEAR, // top mip only
|
|
|
|
FILTER_MIN_MAG_MIP_POINT,
|
|
FILTER_MIN_MAG_POINT_MIP_LINEAR,
|
|
FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
|
|
FILTER_MIN_POINT_MAG_MIP_LINEAR,
|
|
FILTER_MIN_LINEAR_MAG_MIP_POINT,
|
|
FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
|
|
FILTER_MIN_MAG_LINEAR_MIP_POINT,
|
|
FILTER_MIN_MAG_MIP_LINEAR,
|
|
FILTER_ANISOTROPIC,
|
|
|
|
NUM_FILTERS,
|
|
};
|
|
|
|
enum WrapMode {
|
|
WRAP_REPEAT = 0,
|
|
WRAP_MIRROR,
|
|
WRAP_CLAMP,
|
|
WRAP_BORDER,
|
|
WRAP_MIRROR_ONCE,
|
|
|
|
NUM_WRAP_MODES
|
|
};
|
|
|
|
static const uint8 MAX_MIP_LEVEL = 0xFF;
|
|
|
|
class Desc {
|
|
public:
|
|
glm::vec4 _borderColor{ 1.0f };
|
|
uint32 _maxAnisotropy = 16;
|
|
|
|
uint8 _filter = FILTER_MIN_MAG_POINT;
|
|
uint8 _comparisonFunc = ALWAYS;
|
|
|
|
uint8 _wrapModeU = WRAP_REPEAT;
|
|
uint8 _wrapModeV = WRAP_REPEAT;
|
|
uint8 _wrapModeW = WRAP_REPEAT;
|
|
|
|
uint8 _mipOffset = 0;
|
|
uint8 _minMip = 0;
|
|
uint8 _maxMip = MAX_MIP_LEVEL;
|
|
|
|
Desc() {}
|
|
Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {}
|
|
};
|
|
|
|
Sampler() {}
|
|
Sampler(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _desc(filter, wrap) {}
|
|
Sampler(const Desc& desc) : _desc(desc) {}
|
|
~Sampler() {}
|
|
|
|
const glm::vec4& getBorderColor() const { return _desc._borderColor; }
|
|
|
|
uint32 getMaxAnisotropy() const { return _desc._maxAnisotropy; }
|
|
|
|
WrapMode getWrapModeU() const { return WrapMode(_desc._wrapModeU); }
|
|
WrapMode getWrapModeV() const { return WrapMode(_desc._wrapModeV); }
|
|
WrapMode getWrapModeW() const { return WrapMode(_desc._wrapModeW); }
|
|
|
|
Filter getFilter() const { return Filter(_desc._filter); }
|
|
ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); }
|
|
bool doComparison() const { return getComparisonFunction() != ALWAYS; }
|
|
|
|
uint8 getMipOffset() const { return _desc._mipOffset; }
|
|
uint8 getMinMip() const { return _desc._minMip; }
|
|
uint8 getMaxMip() const { return _desc._maxMip; }
|
|
|
|
const Desc& getDesc() const { return _desc; }
|
|
protected:
|
|
Desc _desc;
|
|
};
|
|
|
|
enum class TextureUsageType : uint8 {
|
|
RENDERBUFFER, // Used as attachments to a framebuffer
|
|
RESOURCE, // Resource textures, like materials... subject to memory manipulation
|
|
STRICT_RESOURCE, // Resource textures not subject to manipulation, like the normal fitting texture
|
|
EXTERNAL,
|
|
};
|
|
|
|
class Texture : public Resource {
|
|
static std::atomic<uint32_t> _textureCPUCount;
|
|
static std::atomic<Size> _textureCPUMemoryUsage;
|
|
static std::atomic<Size> _allowedCPUMemoryUsage;
|
|
static std::atomic<bool> _enableSparseTextures;
|
|
static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
|
|
|
public:
|
|
static const uint32_t CUBE_FACE_COUNT { 6 };
|
|
static uint32_t getTextureCPUCount();
|
|
static Size getTextureCPUMemoryUsage();
|
|
static uint32_t getTextureGPUCount();
|
|
static uint32_t getTextureGPUSparseCount();
|
|
static Size getTextureTransferPendingSize();
|
|
static Size getTextureGPUMemoryUsage();
|
|
static Size getTextureGPUVirtualMemoryUsage();
|
|
static Size getTextureGPUFramebufferMemoryUsage();
|
|
static Size getTextureGPUSparseMemoryUsage();
|
|
static uint32_t getTextureGPUTransferCount();
|
|
static Size getAllowedGPUMemoryUsage();
|
|
static void setAllowedGPUMemoryUsage(Size size);
|
|
|
|
static bool getEnableSparseTextures();
|
|
static void setEnableSparseTextures(bool enabled);
|
|
|
|
using ExternalRecycler = std::function<void(uint32, void*)>;
|
|
using ExternalIdAndFence = std::pair<uint32, void*>;
|
|
using ExternalUpdates = std::list<ExternalIdAndFence>;
|
|
|
|
class Usage {
|
|
public:
|
|
enum FlagBit {
|
|
COLOR = 0, // Texture is a color map
|
|
NORMAL, // Texture is a normal map
|
|
ALPHA, // Texture has an alpha channel
|
|
ALPHA_MASK, // Texture alpha channel is a Mask 0/1
|
|
NUM_FLAGS,
|
|
};
|
|
|
|
typedef std::bitset<NUM_FLAGS> Flags;
|
|
|
|
// The key is the Flags
|
|
Flags _flags;
|
|
|
|
Usage() : _flags(0) {}
|
|
Usage(const Flags& flags) : _flags(flags) {}
|
|
|
|
bool operator== (const Usage& rhs) const { return _flags == rhs._flags; }
|
|
bool operator!= (const Usage& rhs) const { return _flags != rhs._flags; }
|
|
|
|
class Builder {
|
|
friend class Usage;
|
|
Flags _flags{ 0 };
|
|
public:
|
|
Builder() {}
|
|
|
|
Usage build() const { return Usage(_flags); }
|
|
|
|
Builder& withColor() { _flags.set(COLOR); return (*this); }
|
|
Builder& withNormal() { _flags.set(NORMAL); return (*this); }
|
|
Builder& withAlpha() { _flags.set(ALPHA); return (*this); }
|
|
Builder& withAlphaMask() { _flags.set(ALPHA_MASK); return (*this); }
|
|
};
|
|
Usage(const Builder& builder) : Usage(builder._flags) {}
|
|
|
|
bool isColor() const { return _flags[COLOR]; }
|
|
bool isNormal() const { return _flags[NORMAL]; }
|
|
|
|
bool isAlpha() const { return _flags[ALPHA]; }
|
|
bool isAlphaMask() const { return _flags[ALPHA_MASK]; }
|
|
|
|
bool operator==(const Usage& usage) { return (_flags == usage._flags); }
|
|
bool operator!=(const Usage& usage) { return (_flags != usage._flags); }
|
|
};
|
|
|
|
enum Type : uint8 {
|
|
TEX_1D = 0,
|
|
TEX_2D,
|
|
TEX_3D,
|
|
TEX_CUBE,
|
|
|
|
NUM_TYPES,
|
|
};
|
|
|
|
// Definition of the cube face name and layout
|
|
enum CubeFace {
|
|
CUBE_FACE_RIGHT_POS_X = 0,
|
|
CUBE_FACE_LEFT_NEG_X,
|
|
CUBE_FACE_TOP_POS_Y,
|
|
CUBE_FACE_BOTTOM_NEG_Y,
|
|
CUBE_FACE_BACK_POS_Z,
|
|
CUBE_FACE_FRONT_NEG_Z,
|
|
|
|
NUM_CUBE_FACES, // Not a valid vace index
|
|
};
|
|
|
|
// Lines of pixels are padded to be a multiple of "PACKING_SIZE" which is 4 bytes
|
|
static const uint32 PACKING_SIZE = 4;
|
|
static uint8 evalPaddingNumBytes(Size byteSize) { return (uint8) (3 - (byteSize + 3) % PACKING_SIZE); }
|
|
static Size evalPaddedSize(Size byteSize) { return byteSize + (Size) evalPaddingNumBytes(byteSize); }
|
|
|
|
|
|
using PixelsPointer = storage::StoragePointer;
|
|
class Storage {
|
|
public:
|
|
Storage() {}
|
|
virtual ~Storage() {}
|
|
|
|
virtual void reset() = 0;
|
|
virtual PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 0;
|
|
virtual Size getMipFaceSize(uint16 level, uint8 face = 0) const = 0;
|
|
virtual void assignMipData(uint16 level, const storage::StoragePointer& storage) = 0;
|
|
virtual void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) = 0;
|
|
virtual bool isMipAvailable(uint16 level, uint8 face = 0) const = 0;
|
|
virtual uint16 minAvailableMipLevel() const { return 0; }
|
|
Texture::Type getType() const { return _type; }
|
|
|
|
Stamp getStamp() const { return _stamp; }
|
|
Stamp bumpStamp() { return ++_stamp; }
|
|
|
|
void setFormat(const Element& format) { _format = format; }
|
|
const Element& getFormat() const { return _format; }
|
|
|
|
private:
|
|
Stamp _stamp { 0 };
|
|
Element _format;
|
|
Texture::Type _type { Texture::TEX_2D }; // The type of texture is needed to know the number of faces to expect
|
|
Texture* _texture { nullptr }; // Points to the parent texture (not owned)
|
|
virtual void assignTexture(Texture* tex); // Texture storage is pointing to ONE corrresponding Texture.
|
|
const Texture* getTexture() const { return _texture; }
|
|
friend class Texture;
|
|
};
|
|
|
|
class MemoryStorage : public Storage {
|
|
public:
|
|
void reset() override;
|
|
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
|
|
Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
|
|
void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
|
|
void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
|
|
bool isMipAvailable(uint16 level, uint8 face = 0) const override;
|
|
|
|
protected:
|
|
bool allocateMip(uint16 level);
|
|
std::vector<std::vector<PixelsPointer>> _mips; // an array of mips, each mip is an array of faces
|
|
};
|
|
|
|
class KtxStorage : public Storage {
|
|
public:
|
|
KtxStorage(const std::string& filename);
|
|
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
|
|
Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
|
|
bool isMipAvailable(uint16 level, uint8 face = 0) const override;
|
|
void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
|
|
void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
|
|
uint16 minAvailableMipLevel() const override;
|
|
|
|
void reset() override { }
|
|
|
|
protected:
|
|
std::shared_ptr<storage::FileStorage> maybeOpenFile();
|
|
|
|
std::mutex _cacheFileCreateMutex;
|
|
std::mutex _cacheFileWriteMutex;
|
|
std::weak_ptr<storage::FileStorage> _cacheFile;
|
|
|
|
std::string _filename;
|
|
std::atomic<uint8_t> _minMipLevelAvailable;
|
|
size_t _offsetToMinMipKV;
|
|
|
|
ktx::KTXDescriptorPointer _ktxDescriptor;
|
|
friend class Texture;
|
|
};
|
|
|
|
uint16 minAvailableMipLevel() const { return _storage->minAvailableMipLevel(); };
|
|
|
|
static const uint16 MAX_NUM_MIPS = 0;
|
|
static const uint16 SINGLE_MIP = 1;
|
|
static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
|
static TexturePointer create2D(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
|
static TexturePointer create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
|
static TexturePointer createCube(const Element& texelFormat, uint16 width, uint16 numMips = 1, const Sampler& sampler = Sampler());
|
|
static TexturePointer createRenderBuffer(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
|
static TexturePointer createStrict(const Element& texelFormat, uint16 width, uint16 height, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler());
|
|
static TexturePointer createExternal(const ExternalRecycler& recycler, const Sampler& sampler = Sampler());
|
|
|
|
// After the texture has been created, it should be defined
|
|
bool isDefined() const { return _defined; }
|
|
|
|
Texture(TextureUsageType usageType);
|
|
Texture(const Texture& buf); // deep copy of the sysmem texture
|
|
Texture& operator=(const Texture& buf); // deep copy of the sysmem texture
|
|
~Texture();
|
|
|
|
Stamp getStamp() const { return _stamp; }
|
|
Stamp getDataStamp() const { return _storage->getStamp(); }
|
|
|
|
// The theoretical size in bytes of data stored in the texture
|
|
// For the master (level) first level of mip
|
|
Size getSize() const override { return _size; }
|
|
|
|
// Size and format
|
|
Type getType() const { return _type; }
|
|
TextureUsageType getUsageType() const { return _usageType; }
|
|
|
|
bool isColorRenderTarget() const;
|
|
bool isDepthStencilRenderTarget() const;
|
|
|
|
const Element& getTexelFormat() const { return _texelFormat; }
|
|
|
|
Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); }
|
|
uint16 getWidth() const { return _width; }
|
|
uint16 getHeight() const { return _height; }
|
|
uint16 getDepth() const { return _depth; }
|
|
|
|
// The number of faces is mostly used for cube map, and maybe for stereo ? otherwise it's 1
|
|
// For cube maps, this means the pixels of the different faces are supposed to be packed back to back in a mip
|
|
// as if the height was NUM_FACES time bigger.
|
|
static uint8 NUM_FACES_PER_TYPE[NUM_TYPES];
|
|
uint8 getNumFaces() const { return NUM_FACES_PER_TYPE[getType()]; }
|
|
|
|
// The texture is an array if the _numSlices is not 0.
|
|
// otherwise, if _numSLices is 0, then the texture is NOT an array
|
|
// The number of slices returned is 1 at the minimum (if not an array) or the actual _numSlices.
|
|
bool isArray() const { return _numSlices > 0; }
|
|
uint16 getNumSlices() const { return (isArray() ? _numSlices : 1); }
|
|
|
|
uint16 getNumSamples() const { return _numSamples; }
|
|
// NumSamples can only have certain values based on the hw
|
|
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
|
|
|
|
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
|
|
// It is defined at creation time (immutable)
|
|
uint16 getMaxMip() const { return _maxMipLevel; }
|
|
uint16 getNumMips() const { return _maxMipLevel + 1; }
|
|
|
|
// Mips size evaluation
|
|
|
|
// The number mips that a dimension could haves
|
|
// = 1 + log2(size)
|
|
static uint16 evalDimMaxNumMips(uint16 size);
|
|
|
|
// The number mips that the texture could have if all existed
|
|
// = 1 + log2(max(width, height, depth))
|
|
uint16 evalMaxNumMips() const;
|
|
static uint16 evalMaxNumMips(const Vec3u& dimensions);
|
|
|
|
// Check a num of mips requested against the maximum possible specified
|
|
// if passing -1 then answer the max
|
|
// simply does (askedNumMips == -1 ? maxMips : (numstd::min(askedNumMips, max))
|
|
static uint16 safeNumMips(uint16 askedNumMips, uint16 maxMips);
|
|
|
|
// Same but applied to this texture's num max mips from evalNumMips()
|
|
uint16 safeNumMips(uint16 askedNumMips) const;
|
|
|
|
// Eval the size that the mips level SHOULD have
|
|
// not the one stored in the Texture
|
|
|
|
Vec3u evalMipDimensions(uint16 level) const;
|
|
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
|
|
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
|
|
uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
|
|
|
|
// The size of a face is a multiple of the padded line = (width * texelFormat_size + alignment padding)
|
|
Size evalMipLineSize(uint16 level) const { return evalPaddedSize(evalMipWidth(level) * getTexelFormat().getSize()); }
|
|
|
|
// Size for each face of a mip at a particular level
|
|
uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
|
|
Size evalMipFaceSize(uint16 level) const { return evalMipLineSize(level) * evalMipHeight(level) * evalMipDepth(level); }
|
|
|
|
// Total size for the mip
|
|
uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); }
|
|
Size evalMipSize(uint16 level) const { return evalMipFaceSize(level) * getNumFaces(); }
|
|
|
|
// Total size for all the mips of the texture
|
|
Size evalTotalSize(uint16 startingMip = 0) const;
|
|
|
|
// Compute the theorical size of the texture elements storage depending on the specified format
|
|
Size evalStoredMipLineSize(uint16 level, const Element& format) const { return evalPaddedSize(evalMipWidth(level) * format.getSize()); }
|
|
Size evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
|
|
Size evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
|
|
|
|
// For convenience assign a source name
|
|
const std::string& source() const { return _source; }
|
|
void setSource(const std::string& source) { _source = source; }
|
|
const std::string& sourceHash() const { return _sourceHash; }
|
|
void setSourceHash(const std::string& sourceHash) { _sourceHash = sourceHash; }
|
|
|
|
// Potentially change the minimum mip (mostly for debugging purpose)
|
|
bool setMinMip(uint16 newMinMip);
|
|
bool incremementMinMip(uint16 count = 1);
|
|
uint16 getMinMip() const { return _minMip; }
|
|
uint16 usedMipLevels() const { return (getNumMips() - _minMip); }
|
|
|
|
// Generate the sub mips automatically for the texture
|
|
// If the storage version is not available (from CPU memory)
|
|
// Only works for the standard formats
|
|
void setAutoGenerateMips(bool enable);
|
|
bool isAutogenerateMips() const { return _autoGenerateMips; }
|
|
|
|
// Managing Storage and mips
|
|
|
|
// Mip storage format is constant across all mips
|
|
void setStoredMipFormat(const Element& format);
|
|
const Element& getStoredMipFormat() const;
|
|
|
|
// Manually allocate the mips down until the specified maxMip
|
|
// this is just allocating the sysmem version of it
|
|
// in case autoGen is on, this doesn't allocate
|
|
// Explicitely assign mip data for a certain level
|
|
// If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
|
|
void assignStoredMip(uint16 level, Size size, const Byte* bytes);
|
|
void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes);
|
|
|
|
void assignStoredMip(uint16 level, storage::StoragePointer& storage);
|
|
void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage);
|
|
|
|
// Access the stored mips and faces
|
|
const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
|
|
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const;
|
|
Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
|
|
Size getStoredMipSize(uint16 level) const;
|
|
Size getStoredSize() const;
|
|
|
|
void setStorage(std::unique_ptr<Storage>& newStorage);
|
|
void setKtxBacking(const std::string& filename);
|
|
|
|
// Usage is a a set of flags providing Semantic about the usage of the Texture.
|
|
void setUsage(const Usage& usage) { _usage = usage; }
|
|
Usage getUsage() const { return _usage; }
|
|
|
|
// For Cube Texture, it's possible to generate the irradiance spherical harmonics and make them availalbe with the texture
|
|
bool generateIrradiance();
|
|
const SHPointer& getIrradiance(uint16 slice = 0) const { return _irradiance; }
|
|
void overrideIrradiance(SHPointer irradiance) { _irradiance = irradiance; }
|
|
bool isIrradianceValid() const { return _isIrradianceValid; }
|
|
|
|
// Own sampler
|
|
void setSampler(const Sampler& sampler);
|
|
const Sampler& getSampler() const { return _sampler; }
|
|
Stamp getSamplerStamp() const { return _samplerStamp; }
|
|
|
|
void setFallbackTexture(const TexturePointer& fallback) { _fallback = fallback; }
|
|
TexturePointer getFallbackTexture() const { return _fallback.lock(); }
|
|
|
|
void setExternalTexture(uint32 externalId, void* externalFence);
|
|
void setExternalRecycler(const ExternalRecycler& recycler);
|
|
ExternalRecycler getExternalRecycler() const;
|
|
|
|
const GPUObjectPointer gpuObject {};
|
|
|
|
ExternalUpdates getUpdates() const;
|
|
|
|
// Serialize a texture into a KTX file
|
|
static ktx::KTXUniquePointer serialize(const Texture& texture);
|
|
|
|
static TexturePointer unserialize(const std::string& ktxFile);
|
|
static TexturePointer unserialize(const std::string& ktxFile, const ktx::KTXDescriptor& descriptor);
|
|
|
|
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
|
|
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
|
|
|
protected:
|
|
const TextureUsageType _usageType;
|
|
|
|
// Should only be accessed internally or by the backend sync function
|
|
mutable Mutex _externalMutex;
|
|
mutable std::list<ExternalIdAndFence> _externalUpdates;
|
|
ExternalRecycler _externalRecycler;
|
|
|
|
|
|
std::weak_ptr<Texture> _fallback;
|
|
// Not strictly necessary, but incredibly useful for debugging
|
|
std::string _source;
|
|
std::string _sourceHash;
|
|
std::unique_ptr< Storage > _storage;
|
|
|
|
Stamp _stamp { 0 };
|
|
|
|
Sampler _sampler;
|
|
Stamp _samplerStamp { 0 };
|
|
|
|
Size _size { 0 };
|
|
Element _texelFormat;
|
|
|
|
uint16 _width { 1 };
|
|
uint16 _height { 1 };
|
|
uint16 _depth { 1 };
|
|
|
|
uint16 _numSamples { 1 };
|
|
|
|
// if _numSlices is 0, the texture is not an "Array", the getNumSlices reported is 1
|
|
uint16 _numSlices { 0 };
|
|
|
|
// valid _maxMipLevel is in the range [ 0 if no sub mips, log2(max(width, height, depth) ]
|
|
// The num of mips returned is _maxMipLevel + 1
|
|
uint16 _maxMipLevel { 0 };
|
|
|
|
uint16 _minMip { 0 };
|
|
|
|
Type _type { TEX_1D };
|
|
|
|
Usage _usage;
|
|
|
|
SHPointer _irradiance;
|
|
bool _autoGenerateMips = false;
|
|
bool _isIrradianceValid = false;
|
|
bool _defined = false;
|
|
|
|
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);
|
|
|
|
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, uint16 numMips);
|
|
};
|
|
|
|
typedef std::shared_ptr<Texture> TexturePointer;
|
|
typedef std::vector< TexturePointer > Textures;
|
|
|
|
// TODO: For now TextureView works with Texture as a place holder for the Texture.
|
|
// The overall logic should be about the same except that the Texture will be a real GL Texture under the hood
|
|
class TextureView {
|
|
public:
|
|
typedef Resource::Size Size;
|
|
|
|
TexturePointer _texture = TexturePointer(NULL);
|
|
uint16 _subresource = 0;
|
|
Element _element = Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
|
|
|
TextureView() {};
|
|
|
|
TextureView(const Element& element) :
|
|
_element(element)
|
|
{};
|
|
|
|
// create the TextureView and own the Texture
|
|
TextureView(Texture* newTexture, const Element& element) :
|
|
_texture(newTexture),
|
|
_subresource(0),
|
|
_element(element)
|
|
{};
|
|
TextureView(const TexturePointer& texture, uint16 subresource, const Element& element) :
|
|
_texture(texture),
|
|
_subresource(subresource),
|
|
_element(element)
|
|
{};
|
|
|
|
TextureView(const TexturePointer& texture, uint16 subresource) :
|
|
_texture(texture),
|
|
_subresource(subresource)
|
|
{};
|
|
|
|
~TextureView() {}
|
|
TextureView(const TextureView& view) = default;
|
|
TextureView& operator=(const TextureView& view) = default;
|
|
|
|
explicit operator bool() const { return bool(_texture); }
|
|
bool operator !() const { return (!_texture); }
|
|
|
|
bool isValid() const { return bool(_texture); }
|
|
};
|
|
typedef std::vector<TextureView> TextureViews;
|
|
|
|
// 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.
|
|
// It provides the mechanism to create a texture using a customizable TextureLoader
|
|
class TextureSource {
|
|
public:
|
|
TextureSource();
|
|
~TextureSource();
|
|
|
|
const QUrl& getUrl() const { return _imageUrl; }
|
|
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
|
|
|
|
void reset(const QUrl& url);
|
|
|
|
void resetTexture(gpu::TexturePointer texture);
|
|
|
|
bool isDefined() const;
|
|
|
|
protected:
|
|
gpu::TexturePointer _gpuTexture;
|
|
QUrl _imageUrl;
|
|
};
|
|
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
|
|
|
|
};
|
|
|
|
Q_DECLARE_METATYPE(gpu::TexturePointer)
|
|
|
|
#endif
|