overte/libraries/gpu/src/gpu/Texture.h
2016-01-13 13:51:53 -08:00

464 lines
16 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 "Resource.h"
#include <algorithm> //min max and more
#include <QUrl>
namespace gpu {
// 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; }
protected:
Desc _desc;
};
class Texture : public Resource, public GPUObjectWrapper {
public:
class Pixels {
public:
Pixels() {}
Pixels(const Pixels& pixels) = default;
Pixels(const Element& format, Size size, const Byte* bytes);
~Pixels();
Sysmem _sysmem;
Element _format;
bool _isGPULoaded;
};
typedef std::shared_ptr< Pixels > PixelsPointer;
enum Type {
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
};
class Storage {
public:
Storage() {}
virtual ~Storage() {}
virtual void reset();
virtual PixelsPointer editMipFace(uint16 level, uint8 face = 0);
virtual const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const;
virtual bool allocateMip(uint16 level);
virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes);
virtual bool assignMipFaceData(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face);
virtual bool isMipAvailable(uint16 level, uint8 face = 0) const;
Texture::Type getType() const { return _type; }
Stamp getStamp() const { return _stamp; }
Stamp bumpStamp() { return ++_stamp; }
protected:
Stamp _stamp = 0;
Texture* _texture = nullptr;
Texture::Type _type = Texture::TEX_2D; // The type of texture is needed to know the number of faces to expect
std::vector<std::vector<PixelsPointer>> _mips; // an array of mips, each mip is an array of faces
virtual void assignTexture(Texture* tex); // Texture storage is pointing to ONE corrresponding Texture.
const Texture* getTexture() const { return _texture; }
friend class Texture;
// THis should be only called by the Texture from the Backend to notify the storage that the specified mip face pixels
// have been uploaded to the GPU memory. IT is possible for the storage to free the system memory then
virtual void notifyMipFaceGPULoaded(uint16 level, uint8 face) const;
};
static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler());
static Texture* createCube(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
static Texture* createFromStorage(Storage* storage);
Texture();
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 size in bytes of data stored in the texture
Size getSize() const { return _size; }
// Resize, unless auto mips mode would destroy all the sub mips
Size resize1D(uint16 width, uint16 numSamples);
Size resize2D(uint16 width, uint16 height, uint16 numSamples);
Size resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples);
Size resizeCube(uint16 width, uint16 numSamples);
// Reformat, unless auto mips mode would destroy all the sub mips
Size reformat(const Element& texelFormat);
// Size and format
Type getType() const { return _type; }
bool isColorRenderTarget() const;
bool isDepthStencilRenderTarget() const;
const Element& getTexelFormat() const { return _texelFormat; }
bool hasBorder() const { return false; }
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
uint16 getDepth() const { return _depth; }
uint32 getRowPitch() const { return getWidth() * getTexelFormat().getSize(); }
// 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()]; }
uint32 getNumTexels() const { return _width * _height * _depth * getNumFaces(); }
uint16 getNumSlices() const { return _numSlices; }
uint16 getNumSamples() const { return _numSamples; }
// NumSamples can only have certain values based on the hw
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
// Mips size evaluation
// The number mips that a dimension could haves
// = 1 + log2(size)
static uint16 evalDimNumMips(uint16 size);
// The number mips that the texture could have if all existed
// = 1 + log2(max(width, height, depth))
uint16 evalNumMips() const;
// Eval the size that the mips level SHOULD have
// not the one stored in the Texture
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); }
// Size for each face of a mip at a particular level
uint32 evalMipFaceNumTexels(uint16 level) const { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); }
uint32 evalMipFaceSize(uint16 level) const { return evalMipFaceNumTexels(level) * getTexelFormat().getSize(); }
// Total size for the mip
uint32 evalMipNumTexels(uint16 level) const { return evalMipFaceNumTexels(level) * getNumFaces(); }
uint32 evalMipSize(uint16 level) const { return evalMipNumTexels(level) * getTexelFormat().getSize(); }
uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); }
uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); }
uint32 evalTotalSize() const {
uint32 size = 0;
uint16 minMipLevel = 0;
uint16 maxMipLevel = maxMip();
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
size += evalMipSize(l);
}
return size * getNumSlices();
}
// max mip is in the range [ 1 if no sub mips, log2(max(width, height, depth))]
// if autoGenerateMip is on => will provide the maxMIp level specified
// else provide the deepest mip level provided through assignMip
uint16 maxMip() const;
// Generate the mips automatically
// But the sysmem version is not available
// Only works for the standard formats
// Specify the maximum Mip level available
// 0 is the default one
// 1 is the first level
// ...
// nbMips - 1 is the last mip level
//
// If -1 then all the mips are generated
//
// Return the totalnumber of mips that will be available
uint16 autoGenerateMips(uint16 maxMip);
bool isAutogenerateMips() const { return _autoGenerateMips; }
// Managing Storage and mips
// 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
bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes);
bool assignStoredMipFace(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face);
// Access the the sub mips
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
// access sizes for the stored mips
uint16 getStoredMipWidth(uint16 level) const;
uint16 getStoredMipHeight(uint16 level) const;
uint16 getStoredMipDepth(uint16 level) const;
uint32 getStoredMipNumTexels(uint16 level) const;
uint32 getStoredMipSize(uint16 level) const;
bool isDefined() const { return _defined; }
// 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; }
bool isIrradianceValid() const { return _isIrradianceValid; }
// Own sampler
void setSampler(const Sampler& sampler);
const Sampler& getSampler() const { return _sampler; }
Stamp getSamplerStamp() const { return _samplerStamp; }
// Only callable by the Backend
void notifyMipFaceGPULoaded(uint16 level, uint8 face) const { return _storage->notifyMipFaceGPULoaded(level, face); }
protected:
std::unique_ptr< Storage > _storage;
Stamp _stamp = 0;
Sampler _sampler;
Stamp _samplerStamp;
uint32 _size = 0;
Element _texelFormat;
uint16 _width = 1;
uint16 _height = 1;
uint16 _depth = 1;
uint16 _numSamples = 1;
uint16 _numSlices = 1;
uint16 _maxMip = 0;
Type _type = TEX_1D;
SHPointer _irradiance;
bool _autoGenerateMips = false;
bool _isIrradianceValid = false;
bool _defined = false;
static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler);
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
};
typedef std::shared_ptr<Texture> TexturePointer;
typedef std::vector< TexturePointer > Textures;
// TODO: For now TextureView works with Buffer 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::Texture* texture);
bool isDefined() const;
protected:
gpu::TexturePointer _gpuTexture;
QUrl _imageUrl;
};
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
};
#endif