mirror of
https://github.com/overte-org/overte.git
synced 2025-04-13 16:05:17 +02:00
Merge pull request #10036 from highfidelity/revert-10020-ktx_refactor
Revert "Don't hold KTX files open for longer than transfers require"
This commit is contained in:
commit
78cab8ed5c
11 changed files with 154 additions and 222 deletions
|
@ -85,16 +85,14 @@ 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 = mipSize;
|
_transferSize = mipData->getSize();
|
||||||
_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;
|
||||||
|
@ -103,11 +101,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;
|
||||||
auto sourceOffset = bytesPerLine * lineOffset;
|
|
||||||
_transferSize = bytesPerLine * lines;
|
_transferSize = bytesPerLine * lines;
|
||||||
|
auto sourceOffset = bytesPerLine * lineOffset;
|
||||||
_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;
|
||||||
|
@ -587,10 +585,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 mipSize = _gpuObject.getStoredMipFaceSize(sourceMip, face);
|
auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
|
||||||
const auto lines = mipDimensions.y;
|
const auto lines = mipDimensions.y;
|
||||||
auto bytesPerLine = mipSize / lines;
|
auto bytesPerLine = (uint32_t)mipData->getSize() / lines;
|
||||||
Q_ASSERT(0 == (mipSize % lines));
|
Q_ASSERT(0 == (mipData->getSize() % 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) {
|
||||||
|
|
|
@ -149,10 +149,6 @@ 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());
|
||||||
|
@ -482,39 +478,43 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
uint16 Texture::getStoredMipWidth(uint16 level) const {
|
||||||
if (!isStoredMipFaceAvailable(level)) {
|
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||||
return 0;
|
if (mipFace && mipFace->getSize()) {
|
||||||
|
return evalMipWidth(level);
|
||||||
}
|
}
|
||||||
return evalMipWidth(level);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
uint16 Texture::getStoredMipHeight(uint16 level) const {
|
||||||
if (!isStoredMipFaceAvailable(level)) {
|
PixelsPointer mip = accessStoredMipFace(level);
|
||||||
return 0;
|
if (mip && mip->getSize()) {
|
||||||
|
return evalMipHeight(level);
|
||||||
}
|
}
|
||||||
return evalMipHeight(level);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
uint16 Texture::getStoredMipDepth(uint16 level) const {
|
||||||
if (!isStoredMipFaceAvailable(level)) {
|
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||||
return 0;
|
if (mipFace && mipFace->getSize()) {
|
||||||
|
return evalMipDepth(level);
|
||||||
}
|
}
|
||||||
return evalMipDepth(level);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
uint32 Texture::getStoredMipNumTexels(uint16 level) const {
|
||||||
if (!isStoredMipFaceAvailable(level)) {
|
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||||
return 0;
|
if (mipFace && mipFace->getSize()) {
|
||||||
|
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
||||||
}
|
}
|
||||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Texture::getStoredMipSize(uint16 level) const {
|
uint32 Texture::getStoredMipSize(uint16 level) const {
|
||||||
if (!isStoredMipFaceAvailable(level)) {
|
PixelsPointer mipFace = accessStoredMipFace(level);
|
||||||
return 0;
|
if (mipFace && mipFace->getSize()) {
|
||||||
|
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Resource::Size Texture::getStoredSize() const {
|
gpu::Resource::Size Texture::getStoredSize() const {
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +261,6 @@ 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;
|
||||||
|
@ -289,7 +286,6 @@ 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;
|
||||||
|
@ -301,9 +297,8 @@ public:
|
||||||
|
|
||||||
class KtxStorage : public Storage {
|
class KtxStorage : public Storage {
|
||||||
public:
|
public:
|
||||||
KtxStorage(const std::string& filename);
|
KtxStorage(ktx::KTXUniquePointer& ktxData);
|
||||||
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; }
|
||||||
|
|
||||||
|
@ -317,8 +312,7 @@ public:
|
||||||
void reset() override { }
|
void reset() override { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _filename;
|
ktx::KTXUniquePointer _ktxData;
|
||||||
ktx::KTXDescriptorPointer _ktxDescriptor;
|
|
||||||
friend class Texture;
|
friend class Texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,10 +475,9 @@ 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(const std::string& filename);
|
void setKtxBacking(ktx::KTXUniquePointer& newBacking);
|
||||||
|
|
||||||
// access sizes for the stored mips
|
// access sizes for the stored mips
|
||||||
uint16 getStoredMipWidth(uint16 level) const;
|
uint16 getStoredMipWidth(uint16 level) const;
|
||||||
|
@ -522,7 +515,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 std::string& ktxFile, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc());
|
static Texture* unserialize(const ktx::KTXUniquePointer& srcData, 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);
|
||||||
|
|
||||||
|
|
|
@ -42,37 +42,30 @@ struct GPUKTXPayload {
|
||||||
|
|
||||||
std::string GPUKTXPayload::KEY { "hifi.gpu" };
|
std::string GPUKTXPayload::KEY { "hifi.gpu" };
|
||||||
|
|
||||||
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) {
|
||||||
{
|
|
||||||
ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) };
|
// if the source ktx is valid let's config this KtxStorage correctly
|
||||||
auto ktxPointer = ktx::KTX::create(storage);
|
if (ktxData && ktxData->getHeader()) {
|
||||||
_ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
|
|
||||||
|
// now that we know the ktx, let's get the header info to configure this Texture::Storage:
|
||||||
|
Format mipFormat = Format::COLOR_BGRA_32;
|
||||||
|
Format texelFormat = Format::COLOR_SRGBA_32;
|
||||||
|
if (Texture::evalTextureFormat(*ktxData->getHeader(), mipFormat, texelFormat)) {
|
||||||
|
_format = mipFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that we know the ktx, let's get the header info to configure this Texture::Storage:
|
_ktxData.reset(ktxData.release());
|
||||||
Format mipFormat = Format::COLOR_BGRA_32;
|
|
||||||
Format texelFormat = Format::COLOR_SRGBA_32;
|
|
||||||
if (Texture::evalTextureFormat(_ktxDescriptor->header, mipFormat, texelFormat)) {
|
|
||||||
_format = mipFormat;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
|
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
|
||||||
storage::StoragePointer result;
|
return _ktxData->getMipFaceTexelsData(level, face);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
void Texture::setKtxBacking(ktx::KTXUniquePointer& ktxBacking) {
|
||||||
return _ktxDescriptor->getMipFaceTexelsSize(level, face);
|
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(ktxBacking));
|
||||||
}
|
|
||||||
|
|
||||||
void Texture::setKtxBacking(const std::string& filename) {
|
|
||||||
auto newBacking = std::unique_ptr<Storage>(new KtxStorage(filename));
|
|
||||||
setStorage(newBacking);
|
setStorage(newBacking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +177,11 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
||||||
return ktxBuffer;
|
return ktxBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
|
Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
|
||||||
ktx::KTXDescriptor descriptor { ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) })->toDescriptor() };
|
if (!srcData) {
|
||||||
const auto& header = descriptor.header;
|
return nullptr;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
@ -214,7 +209,7 @@ Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usage
|
||||||
|
|
||||||
// If found, use the
|
// If found, use the
|
||||||
GPUKTXPayload gpuktxKeyValue;
|
GPUKTXPayload gpuktxKeyValue;
|
||||||
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(descriptor.keyValues, gpuktxKeyValue);
|
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(srcData->_keyValues, gpuktxKeyValue);
|
||||||
|
|
||||||
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
|
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
|
||||||
type,
|
type,
|
||||||
|
@ -230,7 +225,14 @@ Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usage
|
||||||
|
|
||||||
// Assing the mips availables
|
// Assing the mips availables
|
||||||
tex->setStoredMipFormat(mipFormat);
|
tex->setStoredMipFormat(mipFormat);
|
||||||
tex->setKtxBacking(ktxfile);
|
uint16_t level = 0;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,39 +108,47 @@ 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 {
|
||||||
return _header;
|
if (!_storage) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<const Header*>(_storage->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t KTX::getKeyValueDataSize() const {
|
size_t KTX::getKeyValueDataSize() const {
|
||||||
return _header.bytesOfKeyValueData;
|
if (_storage) {
|
||||||
|
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 {
|
||||||
|
@ -155,58 +163,3 @@ 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) {
|
|
||||||
}
|
|
|
@ -407,69 +407,43 @@ namespace ktx {
|
||||||
};
|
};
|
||||||
using KeyValues = KeyValue::KeyValues;
|
using KeyValues = KeyValue::KeyValues;
|
||||||
|
|
||||||
struct ImageHeader {
|
|
||||||
using FaceOffsets = std::vector<size_t>;
|
struct Image {
|
||||||
using FaceBytes = std::vector<const Byte*>;
|
using FaceBytes = std::vector<const Byte*>;
|
||||||
const uint32_t _numFaces;
|
|
||||||
const uint32_t _imageSize;
|
|
||||||
const uint32_t _faceSize;
|
|
||||||
const uint32_t _padding;
|
|
||||||
ImageHeader(bool cube, uint32_t imageSize, uint32_t padding) :
|
|
||||||
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
|
|
||||||
_imageSize(imageSize * _numFaces),
|
|
||||||
_faceSize(imageSize),
|
|
||||||
_padding(padding) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Image;
|
uint32_t _numFaces{ 1 };
|
||||||
|
uint32_t _imageSize;
|
||||||
struct ImageDescriptor : public ImageHeader {
|
uint32_t _faceSize;
|
||||||
const FaceOffsets _faceOffsets;
|
uint32_t _padding;
|
||||||
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;
|
FaceBytes _faceBytes;
|
||||||
Image(const ImageHeader& header, const FaceBytes& faces) : ImageHeader(header), _faceBytes(faces) {}
|
|
||||||
|
|
||||||
Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) :
|
Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) :
|
||||||
ImageHeader(false, imageSize, padding),
|
_numFaces(1),
|
||||||
|
_imageSize(imageSize),
|
||||||
|
_faceSize(imageSize),
|
||||||
|
_padding(padding),
|
||||||
_faceBytes(1, bytes) {}
|
_faceBytes(1, bytes) {}
|
||||||
|
|
||||||
Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) :
|
Image(uint32_t pageSize, uint32_t padding, const FaceBytes& cubeFaceBytes) :
|
||||||
ImageHeader(true, pageSize, padding)
|
_numFaces(NUM_CUBEMAPFACES),
|
||||||
|
_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?)
|
||||||
|
@ -501,23 +475,18 @@ 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,3 +38,10 @@ 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 {};
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ 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;
|
||||||
|
|
||||||
|
|
|
@ -438,9 +438,15 @@ 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) {
|
||||||
texture.reset(gpu::Texture::unserialize(ktxFile->getFilepath()));
|
// Ensure that the KTX deserialization worked
|
||||||
if (texture) {
|
auto ktx = ktxFile->getKTX();
|
||||||
texture = textureCache->cacheTextureByHash(hash, texture);
|
if (ktx) {
|
||||||
|
texture.reset(gpu::Texture::unserialize(ktx));
|
||||||
|
// Ensure that the texture population worked
|
||||||
|
if (texture) {
|
||||||
|
texture->setKtxBacking(ktx);
|
||||||
|
texture = textureCache->cacheTextureByHash(hash, texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -580,7 +586,10 @@ 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;
|
||||||
texture->setKtxBacking(file->getFilepath());
|
auto fileKtx = file->getKTX();
|
||||||
|
if (fileKtx) {
|
||||||
|
texture->setKtxBacking(fileKtx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,40 +111,38 @@ 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& fileStorage = ktxFile->getStorage();
|
||||||
const auto& memStorage = ktxMemory->getStorage();
|
Q_ASSERT(memStorage->size() == fileStorage->size());
|
||||||
const auto& fileStorage = ktxFile->getStorage();
|
Q_ASSERT(memStorage->data() != fileStorage->data());
|
||||||
Q_ASSERT(memStorage->size() == fileStorage->size());
|
Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size()));
|
||||||
Q_ASSERT(memStorage->data() != fileStorage->data());
|
Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size());
|
||||||
Q_ASSERT(0 == memcmp(memStorage->data(), fileStorage->data(), memStorage->size()));
|
auto imageCount = ktxFile->_images.size();
|
||||||
Q_ASSERT(ktxFile->_images.size() == ktxMemory->_images.size());
|
auto startMemory = ktxMemory->_storage->data();
|
||||||
auto imageCount = ktxFile->_images.size();
|
auto startFile = ktxFile->_storage->data();
|
||||||
auto startMemory = ktxMemory->_storage->data();
|
for (size_t i = 0; i < imageCount; ++i) {
|
||||||
auto startFile = ktxFile->_storage->data();
|
auto memImages = ktxMemory->_images[i];
|
||||||
for (size_t i = 0; i < imageCount; ++i) {
|
auto fileImages = ktxFile->_images[i];
|
||||||
auto memImages = ktxMemory->_images[i];
|
Q_ASSERT(memImages._padding == fileImages._padding);
|
||||||
auto fileImages = ktxFile->_images[i];
|
Q_ASSERT(memImages._numFaces == fileImages._numFaces);
|
||||||
Q_ASSERT(memImages._padding == fileImages._padding);
|
Q_ASSERT(memImages._imageSize == fileImages._imageSize);
|
||||||
Q_ASSERT(memImages._numFaces == fileImages._numFaces);
|
Q_ASSERT(memImages._faceSize == fileImages._faceSize);
|
||||||
Q_ASSERT(memImages._imageSize == fileImages._imageSize);
|
Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces);
|
||||||
Q_ASSERT(memImages._faceSize == fileImages._faceSize);
|
Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces);
|
||||||
Q_ASSERT(memImages._faceBytes.size() == memImages._numFaces);
|
auto faceCount = fileImages._numFaces;
|
||||||
Q_ASSERT(fileImages._faceBytes.size() == fileImages._numFaces);
|
for (uint32_t face = 0; face < faceCount; ++face) {
|
||||||
auto faceCount = fileImages._numFaces;
|
auto memFace = memImages._faceBytes[face];
|
||||||
for (uint32_t face = 0; face < faceCount; ++face) {
|
auto memOffset = memFace - startMemory;
|
||||||
auto memFace = memImages._faceBytes[face];
|
auto fileFace = fileImages._faceBytes[face];
|
||||||
auto memOffset = memFace - startMemory;
|
auto fileOffset = fileFace - startFile;
|
||||||
auto fileFace = fileImages._faceBytes[face];
|
Q_ASSERT(memOffset % 4 == 0);
|
||||||
auto fileOffset = fileFace - startFile;
|
Q_ASSERT(memOffset == fileOffset);
|
||||||
Q_ASSERT(memOffset % 4 == 0);
|
|
||||||
Q_ASSERT(memOffset == fileOffset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testTexture->setKtxBacking(TEST_IMAGE_KTX.toStdString());
|
testTexture->setKtxBacking(ktxFile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue