Removing gl calls for texture from TextureCache

This commit is contained in:
Sam Gateau 2015-01-21 16:53:35 -08:00
parent 33dcbded22
commit 1e84f260a9
6 changed files with 167 additions and 173 deletions

View file

@ -272,7 +272,8 @@ FBXNode parseBinaryFBXNode(QDataStream& in, int& position) {
position += nameLength;
for (quint32 i = 0; i < propertyCount; i++) {
node.properties.append(parseBinaryFBXProperty(in, position));
QVariant var = parseBinaryFBXProperty(in, position);
node.properties.append(var);
}
while (endOffset > position) {

View file

@ -215,6 +215,9 @@ void GLBackend::syncGPUObject(const Texture& texture) {
// Need to update the content of the GPU object from the source sysmem of the texture
needUpdate = true;
}
} else if (!texture.isDefined()) {
// NO texture definition yet so let's avoid thinking
return;
}
// need to have a gpu object?
@ -224,6 +227,7 @@ void GLBackend::syncGPUObject(const Texture& texture) {
CHECK_GL_ERROR();
Backend::setGPUObject(texture, object);
}
// GO through the process of allocating the correct storage and/or update the content
switch (texture.getType()) {
case Texture::TEX_2D: {
@ -292,5 +296,11 @@ void GLBackend::syncGPUObject(const Texture& texture) {
GLuint GLBackend::getTextureID(const Texture& texture) {
GLBackend::syncGPUObject(texture);
return Backend::getGPUObject<GLBackend::GLTexture>(texture)->_texture;
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
if (object) {
return object->_texture;
} else {
return 0;
}
}

View file

@ -23,6 +23,63 @@ Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
Texture::Pixels::~Pixels() {
}
Stamp Texture::Storage::getStamp(uint16 level) const {
PixelsPointer mip = getMip(level);
if (mip) {
return mip->_sysmem.getStamp();
} else {
return 0;
}
}
void Texture::Storage::reset() {
_mips.clear();
}
Texture::PixelsPointer Texture::Storage::editMip(uint16 level) {
if (level > _mips.size()) {
return PixelsPointer();
} else {
return _mips[level];
}
}
const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const {
if (level > _mips.size()) {
return PixelsPointer();
} else {
return _mips[level];
}
}
bool Texture::Storage::isMipAvailable(uint16 level) const {
PixelsPointer mip = getMip(level);
return (mip && mip->_sysmem.getSize());
}
bool Texture::Storage::allocateMip(uint16 level) {
bool changed = false;
if (level >= _mips.size()) {
_mips.resize(level+1, PixelsPointer());
changed = true;
}
if (!_mips[level]) {
_mips[level] = PixelsPointer(new Pixels());
changed = true;
}
return changed;
}
bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) {
// Ok we should be able to do that...
allocateMip(level);
_mips[level]->_format = format;
Size allocated = _mips[level]->_sysmem.setData(size, bytes);
return allocated == size;
}
Texture* Texture::create1D(const Element& texelFormat, uint16 width) {
return create(TEX_1D, texelFormat, width, 1, 1, 1, 1);
}
@ -42,17 +99,25 @@ Texture* Texture::createCube(const Element& texelFormat, uint16 width) {
Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices)
{
Texture* tex = new Texture();
tex->_storage.reset(new Storage());
tex->_storage->_texture = tex;
tex->_type = type;
tex->_texelFormat = texelFormat;
tex->_maxMip = 0;
tex->resize(type, width, height, depth, numSamples, numSlices);
tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices);
return tex;
}
Texture* Texture::createFromStorage(Storage* storage) {
Texture* tex = new Texture();
tex->_storage.reset(storage);
storage->_texture = tex;
return tex;
}
Texture::Texture():
Resource(),
_storage(),
_stamp(0),
_size(0),
_width(1),
@ -61,7 +126,9 @@ Texture::Texture():
_numSamples(1),
_numSlices(1),
_maxMip(0),
_autoGenerateMips(false)
_type(TEX_1D),
_autoGenerateMips(false),
_defined(false)
{
}
@ -69,10 +136,15 @@ Texture::~Texture()
{
}
Texture::Size Texture::resize(Type type, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) {
if (width && height && depth && numSamples && numSlices) {
bool changed = false;
if ( _type != type) {
_type = type;
changed = true;
}
if (_numSlices != numSlices) {
_numSlices = numSlices;
changed = true;
@ -100,50 +172,47 @@ Texture::Size Texture::resize(Type type, uint16 width, uint16 height, uint16 dep
changed = true;
}
// Evaluate the new size with the new format
const int DIM_SIZE[] = {1, 1, 1, 6};
int size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * _texelFormat.getSize();
int size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize();
// If size change then we need to reset
if (changed || (size != getSize())) {
_size = size;
_mips.clear();
_storage->reset();
_stamp++;
}
}
// TexelFormat might have change, but it's mostly interpretation
if (texelFormat != _texelFormat) {
_texelFormat = texelFormat;
_stamp++;
}
// Here the Texture has been fully defined from the gpu point of view (size and format)
_defined = true;
} else {
_stamp++;
}
return _size;
}
Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) {
return resize(TEX_1D, width, 1, 1, numSamples, 1);
return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1);
}
Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) {
return resize(TEX_2D, width, height, 1, numSamples, 1);
return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1);
}
Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) {
return resize(TEX_3D, width, height, depth, numSamples, 1);
return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1);
}
Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) {
return resize(TEX_CUBE, width, 1, 1, numSamples, 1);
return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1);
}
// Reformat, unless auto mips mode would destroy all the sub mips
Texture::Size Texture::reformat(const Element& texelFormat) {
if (texelFormat != _texelFormat) {
_texelFormat = texelFormat;
const int DIM_SIZE[] = {1, 1, 1, 6};
int size = DIM_SIZE[_type] * _width * _height * _depth * _numSamples * _texelFormat.getSize();
if (size != getSize()) {
_size = size;
_mips.clear();
}
_stamp++;
}
return _size;
return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices());
}
bool Texture::isColorRenderTarget() const {
@ -172,19 +241,6 @@ uint16 Texture::maxMip() const {
return _maxMip;
}
void Texture::allocateStoredMip(uint16 level) {
if (level >= _mips.size()) {
_mips.resize(level+1, 0);
_maxMip = level;
_stamp++;
}
if (!_mips[level]) {
_mips[level] = PixelsPointer(new Pixels());
_stamp++;
}
}
bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) {
// Check that level accessed make sense
if (level != 0) {
@ -198,12 +254,8 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co
// THen check that the mem buffer passed make sense with its format
if (size == evalStoredMipSize(level, format)) {
// Ok we should be able to do that...
allocateStoredMip(level);
_mips[level]->_format = format;
_mips[level]->_sysmem.setData(size, bytes);
_storage->assignMipData(level, format, size, bytes);
_stamp++;
return true;
}

View file

@ -31,6 +31,24 @@ public:
};
typedef QSharedPointer< Pixels > PixelsPointer;
class Storage {
Texture* _texture;
std::vector<PixelsPointer> _mips;
public:
Storage() {}
virtual ~Storage() {}
virtual void reset();
virtual PixelsPointer editMip(uint16 level);
virtual const PixelsPointer getMip(uint16 level) const;
virtual Stamp getStamp(uint16 level) const;
virtual bool allocateMip(uint16 level);
virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes);
virtual bool isMipAvailable(uint16 level) const;
friend class Texture;
};
enum Type {
TEX_1D = 0,
TEX_2D,
@ -43,18 +61,14 @@ public:
static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth);
static Texture* createCube(const Element& texelFormat, uint16 width);
static Texture* createFromStorage(Storage* storage);
Texture(const Texture& buf); // deep copy of the sysmem texture
Texture& operator=(const Texture& buf); // deep copy of the sysmem texture
~Texture();
const Stamp getStamp() const { return _stamp; }
const Stamp getDataStamp(uint16 level = 0) const {
PixelsPointer mip = accessStoredMip(level);
if (mip) {
return mip->_sysmem.getStamp();
}
return getStamp();
}
const Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); }
// The size in bytes of data stored in the texture
Size getSize() const { return _size; }
@ -87,7 +101,10 @@ public:
uint16 getNumSlices() const { return _numSlices; }
uint16 getNumSamples() const { return _numSamples; }
// Sub Mips manipulation
// 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)
@ -116,7 +133,6 @@ public:
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
@ -137,6 +153,8 @@ public:
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
@ -144,35 +162,21 @@ public:
// 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 isStoredMipAvailable(uint16 level) const {
const PixelsPointer mip = accessStoredMip(level);
if (mip) {
return mip->_sysmem.isAvailable();
}
return false;
}
// Access the the sub mips
const PixelsPointer Texture::accessStoredMip(uint16 level) const {
if (level > _mips.size()) {
return 0;
} else {
return _mips[level];
}
}
// Access the the sub mips
bool isStoredMipAvailable(uint16 level) const { return _storage->isMipAvailable(level); }
const PixelsPointer accessStoredMip(uint16 level) const { return _storage->getMip(level); }
// 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;
static uint16 evalNumSamplesUsed(uint16 numSamplesTried);
bool isDefined() const { return _defined; }
protected:
std::vector<PixelsPointer> _mips;
std::unique_ptr< Storage > _storage;
Stamp _stamp;
@ -190,23 +194,12 @@ protected:
Type _type;
bool _autoGenerateMips;
bool _defined;
static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
Texture();
Size resize(Type type, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
void allocateStoredMip(uint16 level);
// Access the the sub mips
PixelsPointer Texture::accessStoredMip(uint16 level) {
if (level > _mips.size()) {
return 0;
} else {
return _mips[level];
}
}
Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices);
mutable GPUObject* _gpuObject = NULL;

View file

@ -26,9 +26,7 @@
#include "TextureCache.h"
TextureCache::TextureCache() :
_permutationNormalTextureID(0),
_whiteTextureID(0),
_blueTextureID(0),
_permutationNormalTexture(0),
_whiteTexture(0),
_blueTexture(0),
_primaryDepthTextureID(0),
@ -46,12 +44,7 @@ TextureCache::TextureCache() :
}
TextureCache::~TextureCache() {
if (_permutationNormalTextureID != 0) {
glDeleteTextures(1, &_permutationNormalTextureID);
}
if (_whiteTextureID != 0) {
glDeleteTextures(1, &_whiteTextureID);
}
if (_primaryFramebufferObject) {
glDeleteTextures(1, &_primaryDepthTextureID);
glDeleteTextures(1, &_primaryNormalTextureID);
@ -126,11 +119,9 @@ const int permutation[256] =
#define USE_CHRIS_NOISE 1
GLuint TextureCache::getPermutationNormalTextureID() {
if (_permutationNormalTextureID == 0) {
glGenTextures(1, &_permutationNormalTextureID);
glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID);
const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() {
if (_permutationNormalTexture.isNull()) {
// the first line consists of random permutation offsets
unsigned char data[256 * 2 * 3];
#if (USE_CHRIS_NOISE==1)
@ -150,12 +141,14 @@ GLuint TextureCache::getPermutationNormalTextureID() {
data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f;
data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
_permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2));
_permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
return _permutationNormalTextureID;
return _permutationNormalTexture;
}
const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF };
@ -167,17 +160,7 @@ static void loadSingleColorTexture(const unsigned char* color) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
/*
GLuint TextureCache::getWhiteTextureID() {
if (_whiteTextureID == 0) {
glGenTextures(1, &_whiteTextureID);
glBindTexture(GL_TEXTURE_2D, _whiteTextureID);
loadSingleColorTexture(OPAQUE_WHITE);
glBindTexture(GL_TEXTURE_2D, 0);
}
return _whiteTextureID;
}
*/
const gpu::TexturePointer& TextureCache::getWhiteTexture() {
if (_whiteTexture.isNull()) {
_whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
@ -185,17 +168,6 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() {
}
return _whiteTexture;
}
/*
GLuint TextureCache::getBlueTextureID() {
if (_blueTextureID == 0) {
glGenTextures(1, &_blueTextureID);
glBindTexture(GL_TEXTURE_2D, _blueTextureID);
loadSingleColorTexture(OPAQUE_BLUE);
glBindTexture(GL_TEXTURE_2D, 0);
}
return _blueTextureID;
}
*/
const gpu::TexturePointer& TextureCache::getBlueTexture() {
if (_blueTexture.isNull()) {
@ -554,19 +526,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo
finishedLoading(true);
imageLoaded(image);
/* glBindTexture(GL_TEXTURE_2D, getID());
if (image.hasAlphaChannel()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, image.constBits());
}
// generate mipmaps
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
*/
if (image.hasAlphaChannel()) {
_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), image.width(), image.height()));
_gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), image.byteCount(), image.constBits());
@ -603,20 +563,7 @@ QSharedPointer<Texture> DilatableNetworkTexture::getDilatedTexture(float dilatio
path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius);
painter.fillPath(path, Qt::black);
painter.end();
/*
glBindTexture(GL_TEXTURE_2D, texture->getID());
if (dilatedImage.hasAlphaChannel()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits());
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dilatedImage.width(), dilatedImage.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE, dilatedImage.constBits());
}
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
*/
if (dilatedImage.hasAlphaChannel()) {
texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), dilatedImage.width(), dilatedImage.height()));
texture->_gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), dilatedImage.byteCount(), dilatedImage.constBits());

View file

@ -46,19 +46,12 @@ public:
/// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture
/// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and
/// the second, a set of random unit vectors to be used as noise gradients.
GLuint getPermutationNormalTextureID();
/// Returns the ID of an opaque white texture (useful for a default).
// GLuint getWhiteTextureID();
const gpu::TexturePointer& getPermutationNormalTexture();
/// Returns an opaque white texture (useful for a default).
const gpu::TexturePointer& getWhiteTexture();
/// Returns the ID of a pale blue texture (useful for a normal map).
// GLuint getBlueTextureID();
/// Returns the ID of a pale blue texture (useful for a normal map).
/// Returns an opaque white texture (useful for a default).
/// Returns the a pale blue texture (useful for a normal map).
const gpu::TexturePointer& getBlueTexture();
/// Loads a texture from the specified URL.
@ -108,10 +101,8 @@ private:
friend class DilatableNetworkTexture;
QOpenGLFramebufferObject* createFramebufferObject();
GLuint _permutationNormalTextureID;
GLuint _whiteTextureID;
GLuint _blueTextureID;
gpu::TexturePointer _permutationNormalTexture;
gpu::TexturePointer _whiteTexture;
gpu::TexturePointer _blueTexture;