Merge pull request #10020 from jherico/ktx_refactor

Don't hold KTX files open for longer than transfers require
This commit is contained in:
samcake 2017-03-28 14:06:02 -07:00 committed by GitHub
commit e42cb52bd1
11 changed files with 224 additions and 156 deletions

View file

@ -85,14 +85,16 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip); auto transferDimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
GLenum format; GLenum format;
GLenum type; GLenum type;
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat()); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat());
format = texelFormat.format; format = texelFormat.format;
type = texelFormat.type; type = texelFormat.type;
auto mipSize = _parent._gpuObject.getStoredMipFaceSize(sourceMip, face);
if (0 == lines) { if (0 == lines) {
_transferSize = mipData->getSize(); _transferSize = mipSize;
_bufferingLambda = [=] { _bufferingLambda = [=] {
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
_buffer.resize(_transferSize); _buffer.resize(_transferSize);
memcpy(&_buffer[0], mipData->readData(), _transferSize); memcpy(&_buffer[0], mipData->readData(), _transferSize);
_bufferingCompleted = true; _bufferingCompleted = true;
@ -101,11 +103,11 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
} else { } else {
transferDimensions.y = lines; transferDimensions.y = lines;
auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip); auto dimensions = _parent._gpuObject.evalMipDimensions(sourceMip);
auto mipSize = mipData->getSize();
auto bytesPerLine = (uint32_t)mipSize / dimensions.y; auto bytesPerLine = (uint32_t)mipSize / dimensions.y;
_transferSize = bytesPerLine * lines;
auto sourceOffset = bytesPerLine * lineOffset; auto sourceOffset = bytesPerLine * lineOffset;
_transferSize = bytesPerLine * lines;
_bufferingLambda = [=] { _bufferingLambda = [=] {
auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
_buffer.resize(_transferSize); _buffer.resize(_transferSize);
memcpy(&_buffer[0], mipData->readData() + sourceOffset, _transferSize); memcpy(&_buffer[0], mipData->readData() + sourceOffset, _transferSize);
_bufferingCompleted = true; _bufferingCompleted = true;
@ -585,10 +587,10 @@ void GL45ResourceTexture::populateTransferQueue() {
// break down the transfers into chunks so that no single transfer is // break down the transfers into chunks so that no single transfer is
// consuming more than X bandwidth // consuming more than X bandwidth
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face); auto mipSize = _gpuObject.getStoredMipFaceSize(sourceMip, face);
const auto lines = mipDimensions.y; const auto lines = mipDimensions.y;
auto bytesPerLine = (uint32_t)mipData->getSize() / lines; auto bytesPerLine = mipSize / lines;
Q_ASSERT(0 == (mipData->getSize() % lines)); Q_ASSERT(0 == (mipSize % lines));
uint32_t linesPerTransfer = (uint32_t)(MAX_TRANSFER_SIZE / bytesPerLine); uint32_t linesPerTransfer = (uint32_t)(MAX_TRANSFER_SIZE / bytesPerLine);
uint32_t lineOffset = 0; uint32_t lineOffset = 0;
while (lineOffset < lines) { while (lineOffset < lines) {

View file

@ -149,6 +149,10 @@ PixelsPointer MemoryStorage::getMipFace(uint16 level, uint8 face) const {
return PixelsPointer(); return PixelsPointer();
} }
Size MemoryStorage::getMipFaceSize(uint16 level, uint8 face) const {
return getMipFace(level, face)->getSize();
}
bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const { bool MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
PixelsPointer mipFace = getMipFace(level, face); PixelsPointer mipFace = getMipFace(level, face);
return (mipFace && mipFace->getSize()); return (mipFace && mipFace->getSize());
@ -478,43 +482,39 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) {
} }
uint16 Texture::getStoredMipWidth(uint16 level) const { uint16 Texture::getStoredMipWidth(uint16 level) const {
PixelsPointer mipFace = accessStoredMipFace(level); if (!isStoredMipFaceAvailable(level)) {
if (mipFace && mipFace->getSize()) {
return evalMipWidth(level);
}
return 0; return 0;
}
return evalMipWidth(level);
} }
uint16 Texture::getStoredMipHeight(uint16 level) const { uint16 Texture::getStoredMipHeight(uint16 level) const {
PixelsPointer mip = accessStoredMipFace(level); if (!isStoredMipFaceAvailable(level)) {
if (mip && mip->getSize()) {
return evalMipHeight(level);
}
return 0; return 0;
}
return evalMipHeight(level);
} }
uint16 Texture::getStoredMipDepth(uint16 level) const { uint16 Texture::getStoredMipDepth(uint16 level) const {
PixelsPointer mipFace = accessStoredMipFace(level); if (!isStoredMipFaceAvailable(level)) {
if (mipFace && mipFace->getSize()) {
return evalMipDepth(level);
}
return 0; return 0;
}
return evalMipDepth(level);
} }
uint32 Texture::getStoredMipNumTexels(uint16 level) const { uint32 Texture::getStoredMipNumTexels(uint16 level) const {
PixelsPointer mipFace = accessStoredMipFace(level); if (!isStoredMipFaceAvailable(level)) {
if (mipFace && mipFace->getSize()) {
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
}
return 0; return 0;
}
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
} }
uint32 Texture::getStoredMipSize(uint16 level) const { uint32 Texture::getStoredMipSize(uint16 level) const {
PixelsPointer mipFace = accessStoredMipFace(level); if (!isStoredMipFaceAvailable(level)) {
if (mipFace && mipFace->getSize()) {
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
}
return 0; return 0;
}
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
} }
gpu::Resource::Size Texture::getStoredSize() const { gpu::Resource::Size Texture::getStoredSize() const {

View file

@ -25,6 +25,8 @@
namespace ktx { namespace ktx {
class KTX; class KTX;
using KTXUniquePointer = std::unique_ptr<KTX>; using KTXUniquePointer = std::unique_ptr<KTX>;
struct KTXDescriptor;
using KTXDescriptorPointer = std::unique_ptr<KTXDescriptor>;
struct Header; struct Header;
} }
@ -261,6 +263,7 @@ public:
virtual void reset() = 0; virtual void reset() = 0;
virtual PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 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 assignMipData(uint16 level, const storage::StoragePointer& storage) = 0;
virtual void assignMipFaceData(uint16 level, uint8 face, 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 bool isMipAvailable(uint16 level, uint8 face = 0) const = 0;
@ -286,6 +289,7 @@ public:
public: public:
void reset() override; void reset() override;
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const 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 assignMipData(uint16 level, const storage::StoragePointer& storage) override;
void assignMipFaceData(uint16 level, uint8 face, 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; bool isMipAvailable(uint16 level, uint8 face = 0) const override;
@ -297,8 +301,9 @@ public:
class KtxStorage : public Storage { class KtxStorage : public Storage {
public: public:
KtxStorage(ktx::KTXUniquePointer& ktxData); KtxStorage(const std::string& filename);
PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override; PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
Size getMipFaceSize(uint16 level, uint8 face = 0) const override;
// By convention, all mip levels and faces MUST be populated when using KTX backing // By convention, all mip levels and faces MUST be populated when using KTX backing
bool isMipAvailable(uint16 level, uint8 face = 0) const override { return true; } bool isMipAvailable(uint16 level, uint8 face = 0) const override { return true; }
@ -312,7 +317,8 @@ public:
void reset() override { } void reset() override { }
protected: protected:
ktx::KTXUniquePointer _ktxData; std::string _filename;
ktx::KTXDescriptorPointer _ktxDescriptor;
friend class Texture; friend class Texture;
}; };
@ -475,9 +481,10 @@ public:
// Access the the sub mips // Access the the sub mips
bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); } 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); } const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
void setStorage(std::unique_ptr<Storage>& newStorage); void setStorage(std::unique_ptr<Storage>& newStorage);
void setKtxBacking(ktx::KTXUniquePointer& newBacking); void setKtxBacking(const std::string& filename);
// access sizes for the stored mips // access sizes for the stored mips
uint16 getStoredMipWidth(uint16 level) const; uint16 getStoredMipWidth(uint16 level) const;
@ -515,7 +522,7 @@ public:
// Textures can be serialized directly to ktx data file, here is how // Textures can be serialized directly to ktx data file, here is how
static ktx::KTXUniquePointer serialize(const Texture& texture); static ktx::KTXUniquePointer serialize(const Texture& texture);
static Texture* unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc()); static Texture* unserialize(const std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc());
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header); static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat); static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);

View file

@ -42,30 +42,37 @@ struct GPUKTXPayload {
std::string GPUKTXPayload::KEY { "hifi.gpu" }; std::string GPUKTXPayload::KEY { "hifi.gpu" };
KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) { KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
{
// if the source ktx is valid let's config this KtxStorage correctly ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) };
if (ktxData && ktxData->getHeader()) { auto ktxPointer = ktx::KTX::create(storage);
_ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
}
// now that we know the ktx, let's get the header info to configure this Texture::Storage: // now that we know the ktx, let's get the header info to configure this Texture::Storage:
Format mipFormat = Format::COLOR_BGRA_32; Format mipFormat = Format::COLOR_BGRA_32;
Format texelFormat = Format::COLOR_SRGBA_32; Format texelFormat = Format::COLOR_SRGBA_32;
if (Texture::evalTextureFormat(*ktxData->getHeader(), mipFormat, texelFormat)) { if (Texture::evalTextureFormat(_ktxDescriptor->header, mipFormat, texelFormat)) {
_format = mipFormat; _format = mipFormat;
} }
}
_ktxData.reset(ktxData.release());
} }
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
return _ktxData->getMipFaceTexelsData(level, face); storage::StoragePointer result;
auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face);
auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
if (faceSize != 0 && faceOffset != 0) {
result = std::make_shared<storage::FileStorage>(_filename.c_str())->createView(faceSize, faceOffset)->toMemoryStorage();
}
return result;
} }
void Texture::setKtxBacking(ktx::KTXUniquePointer& ktxBacking) { Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(ktxBacking)); return _ktxDescriptor->getMipFaceTexelsSize(level, face);
}
void Texture::setKtxBacking(const std::string& filename) {
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(filename));
setStorage(newBacking); setStorage(newBacking);
} }
@ -177,11 +184,9 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
return ktxBuffer; return ktxBuffer;
} }
Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) { Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
if (!srcData) { ktx::KTXDescriptor descriptor { ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) })->toDescriptor() };
return nullptr; const auto& header = descriptor.header;
}
const auto& header = *srcData->getHeader();
Format mipFormat = Format::COLOR_BGRA_32; Format mipFormat = Format::COLOR_BGRA_32;
Format texelFormat = Format::COLOR_SRGBA_32; Format texelFormat = Format::COLOR_SRGBA_32;
@ -209,7 +214,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage
// If found, use the // If found, use the
GPUKTXPayload gpuktxKeyValue; GPUKTXPayload gpuktxKeyValue;
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(srcData->_keyValues, gpuktxKeyValue); bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(descriptor.keyValues, gpuktxKeyValue);
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType), auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
type, type,
@ -225,14 +230,7 @@ Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsage
// Assing the mips availables // Assing the mips availables
tex->setStoredMipFormat(mipFormat); tex->setStoredMipFormat(mipFormat);
uint16_t level = 0; tex->setKtxBacking(ktxfile);
for (auto& image : srcData->_images) {
for (uint32_t face = 0; face < image._numFaces; face++) {
tex->assignStoredMipFace(level, face, image._faceSize, image._faceBytes[face]);
}
level++;
}
return tex; return tex;
} }

View file

@ -108,47 +108,39 @@ KTX::~KTX() {
void KTX::resetStorage(const StoragePointer& storage) { void KTX::resetStorage(const StoragePointer& storage) {
_storage = storage; _storage = storage;
if (_storage->size() >= sizeof(Header)) {
memcpy(&_header, _storage->data(), sizeof(Header));
}
} }
const Header* KTX::getHeader() const { const Header& KTX::getHeader() const {
if (!_storage) { return _header;
return nullptr;
}
return reinterpret_cast<const Header*>(_storage->data());
} }
size_t KTX::getKeyValueDataSize() const { size_t KTX::getKeyValueDataSize() const {
if (_storage) { return _header.bytesOfKeyValueData;
return getHeader()->bytesOfKeyValueData;
} else {
return 0;
}
} }
size_t KTX::getTexelsDataSize() const { size_t KTX::getTexelsDataSize() const {
if (_storage) { if (!_storage) {
//return _storage->size() - (sizeof(Header) + getKeyValueDataSize());
return (_storage->data() + _storage->size()) - getTexelsData();
} else {
return 0; return 0;
} }
return (_storage->data() + _storage->size()) - getTexelsData();
} }
const Byte* KTX::getKeyValueData() const { const Byte* KTX::getKeyValueData() const {
if (_storage) { if (!_storage) {
return (_storage->data() + sizeof(Header));
} else {
return nullptr; return nullptr;
} }
return (_storage->data() + sizeof(Header));
} }
const Byte* KTX::getTexelsData() const { const Byte* KTX::getTexelsData() const {
if (_storage) { if (!_storage) {
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
} else {
return nullptr; return nullptr;
} }
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
} }
storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) const { storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) const {
@ -163,3 +155,58 @@ storage::StoragePointer KTX::getMipFaceTexelsData(uint16_t mip, uint8_t face) co
} }
return result; return result;
} }
size_t KTXDescriptor::getMipFaceTexelsSize(uint16_t mip, uint8_t face) const {
size_t result { 0 };
if (mip < images.size()) {
const auto& faces = images[mip];
if (face < faces._numFaces) {
result = faces._faceSize;
}
}
return result;
}
size_t KTXDescriptor::getMipFaceTexelsOffset(uint16_t mip, uint8_t face) const {
size_t result { 0 };
if (mip < images.size()) {
const auto& faces = images[mip];
if (face < faces._numFaces) {
result = faces._faceOffsets[face];
}
}
return result;
}
ImageDescriptor Image::toImageDescriptor(const Byte* baseAddress) const {
FaceOffsets offsets;
offsets.resize(_faceBytes.size());
for (size_t face = 0; face < _numFaces; ++face) {
offsets[face] = _faceBytes[face] - baseAddress;
}
// Note, implicit cast of *this to const ImageHeader&
return ImageDescriptor(*this, offsets);
}
Image ImageDescriptor::toImage(const ktx::StoragePointer& storage) const {
FaceBytes faces;
faces.resize(_faceOffsets.size());
for (size_t face = 0; face < _numFaces; ++face) {
faces[face] = storage->data() + _faceOffsets[face];
}
// Note, implicit cast of *this to const ImageHeader&
return Image(*this, faces);
}
KTXDescriptor KTX::toDescriptor() const {
ImageDescriptors newDescriptors;
auto storageStart = _storage ? _storage->data() : nullptr;
for (size_t i = 0; i < _images.size(); ++i) {
newDescriptors.emplace_back(_images[i].toImageDescriptor(storageStart));
}
return { this->_header, this->_keyValues, newDescriptors };
}
KTX::KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images)
: _header(header), _storage(storage), _keyValues(keyValues), _images(images) {
}

View file

@ -407,43 +407,69 @@ namespace ktx {
}; };
using KeyValues = KeyValue::KeyValues; using KeyValues = KeyValue::KeyValues;
struct ImageHeader {
struct Image { using FaceOffsets = std::vector<size_t>;
using FaceBytes = std::vector<const Byte*>; using FaceBytes = std::vector<const Byte*>;
const uint32_t _numFaces;
uint32_t _numFaces{ 1 }; const uint32_t _imageSize;
uint32_t _imageSize; const uint32_t _faceSize;
uint32_t _faceSize; const uint32_t _padding;
uint32_t _padding; ImageHeader(bool cube, uint32_t imageSize, uint32_t padding) :
FaceBytes _faceBytes; _numFaces(cube ? NUM_CUBEMAPFACES : 1),
_imageSize(imageSize * _numFaces),
Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) :
_numFaces(1),
_imageSize(imageSize),
_faceSize(imageSize), _faceSize(imageSize),
_padding(padding), _padding(padding) {
_faceBytes(1, bytes) {} }
};
struct Image;
struct ImageDescriptor : public ImageHeader {
const FaceOffsets _faceOffsets;
ImageDescriptor(const ImageHeader& header, const FaceOffsets& offsets) : ImageHeader(header), _faceOffsets(offsets) {}
Image toImage(const ktx::StoragePointer& storage) const;
};
using ImageDescriptors = std::vector<ImageDescriptor>;
struct Image : public ImageHeader {
FaceBytes _faceBytes;
Image(const ImageHeader& header, const FaceBytes& faces) : ImageHeader(header), _faceBytes(faces) {}
Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) :
ImageHeader(false, imageSize, padding),
_faceBytes(1, bytes) {}
Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) : Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) :
_numFaces(NUM_CUBEMAPFACES), ImageHeader(true, pageSize, padding)
_imageSize(pageSize * NUM_CUBEMAPFACES),
_faceSize(pageSize),
_padding(padding)
{ {
if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) { if (cubeFaceBytes.size() == NUM_CUBEMAPFACES) {
_faceBytes = cubeFaceBytes; _faceBytes = cubeFaceBytes;
} }
} }
ImageDescriptor toImageDescriptor(const Byte* baseAddress) const;
}; };
using Images = std::vector<Image>; using Images = std::vector<Image>;
class KTX;
// A KTX descriptor is a lightweight container for all the information about a serialized KTX file, but without the
// actual image / face data available.
struct KTXDescriptor {
KTXDescriptor(const Header& header, const KeyValues& keyValues, const ImageDescriptors& imageDescriptors) : header(header), keyValues(keyValues), images(imageDescriptors) {}
const Header header;
const KeyValues keyValues;
const ImageDescriptors images;
size_t getMipFaceTexelsSize(uint16_t mip = 0, uint8_t face = 0) const;
size_t getMipFaceTexelsOffset(uint16_t mip = 0, uint8_t face = 0) const;
};
class KTX { class KTX {
void resetStorage(const StoragePointer& src); void resetStorage(const StoragePointer& src);
KTX(); KTX();
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
public: public:
~KTX(); ~KTX();
// Define a KTX object manually to write it somewhere (in a file on disk?) // Define a KTX object manually to write it somewhere (in a file on disk?)
@ -475,18 +501,23 @@ namespace ktx {
static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes); static Images parseImages(const Header& header, size_t srcSize, const Byte* srcBytes);
// Access raw pointers to the main sections of the KTX // Access raw pointers to the main sections of the KTX
const Header* getHeader() const; const Header& getHeader() const;
const Byte* getKeyValueData() const; const Byte* getKeyValueData() const;
const Byte* getTexelsData() const; const Byte* getTexelsData() const;
storage::StoragePointer getMipFaceTexelsData(uint16_t mip = 0, uint8_t face = 0) const; storage::StoragePointer getMipFaceTexelsData(uint16_t mip = 0, uint8_t face = 0) const;
const StoragePointer& getStorage() const { return _storage; } const StoragePointer& getStorage() const { return _storage; }
KTXDescriptor toDescriptor() const;
size_t getKeyValueDataSize() const; size_t getKeyValueDataSize() const;
size_t getTexelsDataSize() const; size_t getTexelsDataSize() const;
Header _header;
StoragePointer _storage; StoragePointer _storage;
KeyValues _keyValues; KeyValues _keyValues;
Images _images; Images _images;
friend struct KTXDescriptor;
}; };
} }

View file

@ -185,10 +185,10 @@ namespace ktx {
result->resetStorage(src); result->resetStorage(src);
// read metadata // read metadata
result->_keyValues = parseKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); result->_keyValues = parseKeyValues(result->getHeader().bytesOfKeyValueData, result->getKeyValueData());
// populate image table // populate image table
result->_images = parseImages(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); result->_images = parseImages(result->getHeader(), result->getTexelsDataSize(), result->getTexelsData());
return result; return result;
} }

View file

@ -38,10 +38,3 @@ std::unique_ptr<File> KTXCache::createFile(Metadata&& metadata, const std::strin
KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) : KTXFile::KTXFile(Metadata&& metadata, const std::string& filepath) :
cache::File(std::move(metadata), filepath) {} cache::File(std::move(metadata), filepath) {}
std::unique_ptr<ktx::KTX> KTXFile::getKTX() const {
ktx::StoragePointer storage = std::make_shared<storage::FileStorage>(getFilepath().c_str());
if (*storage) {
return ktx::KTX::create(storage);
}
return {};
}

View file

@ -39,9 +39,6 @@ protected:
class KTXFile : public cache::File { class KTXFile : public cache::File {
Q_OBJECT Q_OBJECT
public:
std::unique_ptr<ktx::KTX> getKTX() const;
protected: protected:
friend class KTXCache; friend class KTXCache;

View file

@ -438,18 +438,12 @@ void NetworkTexture::loadContent(const QByteArray& content) {
if (!texture) { if (!texture) {
KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash);
if (ktxFile) { if (ktxFile) {
// Ensure that the KTX deserialization worked texture.reset(gpu::Texture::unserialize(ktxFile->getFilepath()));
auto ktx = ktxFile->getKTX();
if (ktx) {
texture.reset(gpu::Texture::unserialize(ktx));
// Ensure that the texture population worked
if (texture) { if (texture) {
texture->setKtxBacking(ktx);
texture = textureCache->cacheTextureByHash(hash, texture); texture = textureCache->cacheTextureByHash(hash, texture);
} }
} }
} }
}
// If we found the texture either because it's in use or via KTX deserialization, // If we found the texture either because it's in use or via KTX deserialization,
// set the image and return immediately. // set the image and return immediately.
@ -586,10 +580,7 @@ void ImageReader::read() {
qCWarning(modelnetworking) << _url << "file cache failed"; qCWarning(modelnetworking) << _url << "file cache failed";
} else { } else {
resource.staticCast<NetworkTexture>()->_file = file; resource.staticCast<NetworkTexture>()->_file = file;
auto fileKtx = file->getKTX(); texture->setKtxBacking(file->getFilepath());
if (fileKtx) {
texture->setKtxBacking(fileKtx);
}
} }
} }

View file

@ -111,6 +111,7 @@ int main(int argc, char** argv) {
outFile.close(); outFile.close();
} }
{
auto ktxFile = ktx::KTX::create(std::shared_ptr<storage::Storage>(new storage::FileStorage(TEST_IMAGE_KTX))); auto ktxFile = ktx::KTX::create(std::shared_ptr<storage::Storage>(new storage::FileStorage(TEST_IMAGE_KTX)));
{ {
const auto& memStorage = ktxMemory->getStorage(); const auto& memStorage = ktxMemory->getStorage();
@ -142,7 +143,8 @@ int main(int argc, char** argv) {
} }
} }
} }
testTexture->setKtxBacking(ktxFile); }
testTexture->setKtxBacking(TEST_IMAGE_KTX.toStdString());
return 0; return 0;
} }