mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 11:02:24 +02:00
Add compressed KTX size evaluation
This commit is contained in:
parent
b21dc12cc6
commit
20f4d14e07
10 changed files with 220 additions and 143 deletions
|
@ -31,7 +31,7 @@
|
|||
const float METERS_TO_INCHES = 39.3701f;
|
||||
static uint32_t _currentWebCount { 0 };
|
||||
// Don't allow more than 100 concurrent web views
|
||||
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 20;
|
||||
static const uint32_t MAX_CONCURRENT_WEB_VIEWS = 0;
|
||||
// If a web-view hasn't been rendered for 30 seconds, de-allocate the framebuffer
|
||||
static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
|
||||
|
||||
|
@ -71,7 +71,7 @@ RenderableWebEntityItem::~RenderableWebEntityItem() {
|
|||
|
||||
bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer> renderer) {
|
||||
if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) {
|
||||
qWarning() << "Too many concurrent web views to create new view";
|
||||
//qWarning() << "Too many concurrent web views to create new view";
|
||||
return false;
|
||||
}
|
||||
QString javaScriptToInject;
|
||||
|
|
|
@ -181,13 +181,13 @@ void GL45ResourceTexture::populateTransferQueue() {
|
|||
|
||||
const uint8_t maxFace = GLTexture::getFaceCount(_target);
|
||||
uint16_t sourceMip = _populatedMip;
|
||||
qDebug() << "populateTransferQueue info : " << _populatedMip << " " << _maxAllocatedMip << " " << _allocatedMip;
|
||||
//qDebug() << "populateTransferQueue info : " << _populatedMip << " " << _maxAllocatedMip << " " << _allocatedMip;
|
||||
do {
|
||||
--sourceMip;
|
||||
auto targetMip = sourceMip - _allocatedMip;
|
||||
auto mipDimensions = _gpuObject.evalMipDimensions(sourceMip);
|
||||
bool transferQueued = false;
|
||||
qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
||||
//qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
||||
const_cast<gpu::Texture&>(_gpuObject).requestInterestInMip(sourceMip);
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace ktx {
|
|||
|
||||
namespace gpu {
|
||||
|
||||
extern const std::string SOURCE_HASH_KEY;
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
|
||||
#include "Texture.h"
|
||||
#include <qdebug.h>
|
||||
|
||||
#include <ktx/KTX.h>
|
||||
using namespace gpu;
|
||||
|
@ -41,6 +42,7 @@ struct GPUKTXPayload {
|
|||
}
|
||||
};
|
||||
|
||||
const std::string gpu::SOURCE_HASH_KEY { "hifi.sourceHash" };
|
||||
std::string GPUKTXPayload::KEY{ "hifi.gpu" };
|
||||
|
||||
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
||||
|
@ -91,7 +93,7 @@ std::shared_ptr<storage::FileStorage> KtxStorage::maybeOpenFile() {
|
|||
}
|
||||
|
||||
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
|
||||
qDebug() << "getMipFace: " << QString::fromStdString(_filename) << ": " << level << " " << face;
|
||||
//qDebug() << "getMipFace: " << QString::fromStdString(_filename) << ": " << level << " " << face;
|
||||
storage::StoragePointer result;
|
||||
auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face);
|
||||
auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face);
|
||||
|
@ -108,14 +110,14 @@ Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
|||
|
||||
bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const {
|
||||
auto avail = level >= _minMipLevelAvailable;
|
||||
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << _minMipLevelAvailable << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
||||
//qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << _minMipLevelAvailable << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
||||
//return true;
|
||||
return avail;
|
||||
}
|
||||
|
||||
void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) {
|
||||
if (level != _minMipLevelAvailable - 1) {
|
||||
qWarning() << "Invalid level to be stored";
|
||||
qWarning() << "Invalid level to be stored, expected: " << (_minMipLevelAvailable - 1) << ", got: " << level;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,7 +126,10 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
|
|||
}
|
||||
|
||||
if (storage->size() != _ktxDescriptor->images[level]._imageSize) {
|
||||
throw std::runtime_error("Invalid image size for level");
|
||||
qDebug() << "Invalid image size: " << storage->size() << ", expected: " << _ktxDescriptor->images[level]._imageSize
|
||||
<< ", filename: " << QString::fromStdString(_filename);
|
||||
//throw std::runtime_error("Invalid image size for level");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,7 +263,6 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
|||
ktx::KeyValues keyValues;
|
||||
keyValues.emplace_back(ktx::KeyValue(GPUKTXPayload::KEY, sizeof(GPUKTXPayload), (ktx::Byte*) &keyval));
|
||||
|
||||
static const std::string SOURCE_HASH_KEY = "hifi.sourceHash";
|
||||
auto hash = texture.sourceHash();
|
||||
if (!hash.empty()) {
|
||||
keyValues.emplace_back(ktx::KeyValue(SOURCE_HASH_KEY, static_cast<uint32>(hash.size()), (ktx::Byte*) hash.c_str()));
|
||||
|
|
|
@ -34,30 +34,75 @@ uint32_t Header::evalMaxDimension() const {
|
|||
return std::max(getPixelWidth(), std::max(getPixelHeight(), getPixelDepth()));
|
||||
}
|
||||
|
||||
uint32_t Header::evalPixelWidth(uint32_t level) const {
|
||||
return std::max(getPixelWidth() >> level, 1U);
|
||||
uint32_t Header::evalPixelOrBlockWidth(uint32_t level) const {
|
||||
auto pixelWidth = std::max(getPixelWidth() >> level, 1U);
|
||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
||||
return (pixelWidth + 3) / 4;
|
||||
} else {
|
||||
return pixelWidth;
|
||||
}
|
||||
}
|
||||
uint32_t Header::evalPixelHeight(uint32_t level) const {
|
||||
return std::max(getPixelHeight() >> level, 1U);
|
||||
uint32_t Header::evalPixelOrBlockHeight(uint32_t level) const {
|
||||
auto pixelWidth = std::max(getPixelHeight() >> level, 1U);
|
||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
||||
auto format = getGLInternaFormat_Compressed();
|
||||
switch (format) {
|
||||
case GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
|
||||
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
|
||||
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
|
||||
case GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1: // BC4
|
||||
case GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2: // BC5
|
||||
return (pixelWidth + 3) / 4;
|
||||
default:
|
||||
throw std::runtime_error("Unknown format");
|
||||
}
|
||||
} else {
|
||||
return pixelWidth;
|
||||
}
|
||||
}
|
||||
uint32_t Header::evalPixelDepth(uint32_t level) const {
|
||||
uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
|
||||
return std::max(getPixelDepth() >> level, 1U);
|
||||
}
|
||||
|
||||
size_t Header::evalPixelSize() const {
|
||||
return 4;//glTypeSize; // Really we should generate the size from the FOrmat etc
|
||||
size_t Header::evalPixelOrBlockSize() const {
|
||||
if (getGLType() == GLType::COMPRESSED_TYPE) {
|
||||
auto format = getGLInternaFormat_Compressed();
|
||||
if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
|
||||
return 8;
|
||||
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
|
||||
return 8;
|
||||
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
|
||||
return 16;
|
||||
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1) {
|
||||
return 8;
|
||||
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2) {
|
||||
return 16;
|
||||
}
|
||||
} else {
|
||||
auto baseFormat = getGLBaseInternalFormat();
|
||||
if (baseFormat == GLBaseInternalFormat::RED) {
|
||||
return 1;
|
||||
} else if (baseFormat == GLBaseInternalFormat::RG) {
|
||||
return 2;
|
||||
} else if (baseFormat == GLBaseInternalFormat::RGB) {
|
||||
return 3;
|
||||
} else if (baseFormat == GLBaseInternalFormat::RGBA) {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unknown format");
|
||||
}
|
||||
|
||||
size_t Header::evalRowSize(uint32_t level) const {
|
||||
auto pixWidth = evalPixelWidth(level);
|
||||
auto pixSize = evalPixelSize();
|
||||
auto pixWidth = evalPixelOrBlockWidth(level);
|
||||
auto pixSize = evalPixelOrBlockSize();
|
||||
auto netSize = pixWidth * pixSize;
|
||||
auto padding = evalPadding(netSize);
|
||||
return netSize + padding;
|
||||
}
|
||||
size_t Header::evalFaceSize(uint32_t level) const {
|
||||
auto pixHeight = evalPixelHeight(level);
|
||||
auto pixDepth = evalPixelDepth(level);
|
||||
auto pixHeight = evalPixelOrBlockHeight(level);
|
||||
auto pixDepth = evalPixelOrBlockDepth(level);
|
||||
auto rowSize = evalRowSize(level);
|
||||
return pixDepth * pixHeight * rowSize;
|
||||
}
|
||||
|
|
|
@ -336,11 +336,11 @@ namespace ktx {
|
|||
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
|
||||
|
||||
uint32_t evalMaxDimension() const;
|
||||
uint32_t evalPixelWidth(uint32_t level) const;
|
||||
uint32_t evalPixelHeight(uint32_t level) const;
|
||||
uint32_t evalPixelDepth(uint32_t level) const;
|
||||
uint32_t evalPixelOrBlockWidth(uint32_t level) const;
|
||||
uint32_t evalPixelOrBlockHeight(uint32_t level) const;
|
||||
uint32_t evalPixelOrBlockDepth(uint32_t level) const;
|
||||
|
||||
size_t evalPixelSize() const;
|
||||
size_t evalPixelOrBlockSize() const;
|
||||
size_t evalRowSize(uint32_t level) const;
|
||||
size_t evalFaceSize(uint32_t level) const;
|
||||
size_t evalImageSize(uint32_t level) const;
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace ktx {
|
|||
ptr++;
|
||||
#ifdef DEBUG
|
||||
for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) {
|
||||
*(ptr + k) = 0xFFFF00FF;
|
||||
*(ptr + k) = 0xFFFFFFFF;
|
||||
}
|
||||
#endif
|
||||
currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t);
|
||||
|
|
|
@ -245,7 +245,10 @@ gpu::TexturePointer getFallbackTextureForType(image::TextureUsage::Type type) {
|
|||
}
|
||||
|
||||
NetworkTexture::~NetworkTexture() {
|
||||
_textureSource->getGPUTexture()->unregisterMipInterestListener(this);
|
||||
auto texture = _textureSource->getGPUTexture();
|
||||
if (texture) {
|
||||
texture->unregisterMipInterestListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a texture version of an image file
|
||||
|
@ -412,7 +415,6 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
range.fromInclusive = -15000;
|
||||
_ktxMipRequest->setByteRange(range);
|
||||
} else {
|
||||
// TODO: Discover range for other mips
|
||||
ByteRange range;
|
||||
range.fromInclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData
|
||||
+ _originalKtxDescriptor->images[low]._imageOffset + 4;
|
||||
|
@ -431,6 +433,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
void NetworkTexture::ktxHeaderRequestFinished() {
|
||||
assert(!_ktxHeaderLoaded);
|
||||
|
||||
_headerRequestFinished = true;
|
||||
if (_ktxHeaderRequest->getResult() == ResourceRequest::Success) {
|
||||
_ktxHeaderLoaded = true;
|
||||
_ktxHeaderData = _ktxHeaderRequest->getData();
|
||||
|
@ -447,7 +450,7 @@ void NetworkTexture::ktxMipRequestFinished() {
|
|||
&& _ktxMipLevelRangeInFlight.second == NULL_MIP_LEVEL;
|
||||
|
||||
if (_ktxMipRequest->getResult() == ResourceRequest::Success) {
|
||||
if (_initialKtxLoaded) {
|
||||
if (_highMipRequestFinished) {
|
||||
assert(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
|
||||
|
||||
_lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first;
|
||||
|
@ -456,6 +459,7 @@ void NetworkTexture::ktxMipRequestFinished() {
|
|||
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
|
||||
//texture->assignStoredMip(level, image._imageSize, ktxData);
|
||||
} else {
|
||||
_highMipRequestFinished = true;
|
||||
_ktxHighMipData = _ktxMipRequest->getData();
|
||||
maybeCreateKTX();
|
||||
}
|
||||
|
@ -469,118 +473,144 @@ void NetworkTexture::ktxMipRequestFinished() {
|
|||
|
||||
// This is called when the header or top mips have been loaded
|
||||
void NetworkTexture::maybeCreateKTX() {
|
||||
if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) {
|
||||
// create ktx...
|
||||
auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data());
|
||||
if (_headerRequestFinished && _highMipRequestFinished) {
|
||||
ResourceCache::requestCompleted(_self);
|
||||
|
||||
if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) {
|
||||
// create ktx...
|
||||
auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data());
|
||||
|
||||
qDebug() << "Creating KTX";
|
||||
qDebug() << "Identifier:" << QString(QByteArray((char*)header->identifier, 12));
|
||||
qDebug() << "Type:" << header->glType;
|
||||
qDebug() << "TypeSize:" << header->glTypeSize;
|
||||
qDebug() << "numberOfArrayElements:" << header->numberOfArrayElements;
|
||||
qDebug() << "numberOfFaces:" << header->numberOfFaces;
|
||||
qDebug() << "numberOfMipmapLevels:" << header->numberOfMipmapLevels;
|
||||
auto kvSize = header->bytesOfKeyValueData;
|
||||
if (kvSize > _ktxHeaderData.size() - ktx::KTX_HEADER_SIZE) {
|
||||
qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request";
|
||||
return;
|
||||
}
|
||||
|
||||
auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast<const ktx::Byte*>(_ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE);
|
||||
|
||||
auto imageDescriptors = header->generateImageDescriptors();
|
||||
_originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors));
|
||||
|
||||
// Create bare ktx in memory
|
||||
auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool {
|
||||
return val._key.compare(gpu::SOURCE_HASH_KEY) == 0;
|
||||
});
|
||||
std::string filename;
|
||||
if (found == keyValues.end()) {
|
||||
qWarning("Source hash key not found, bailing");
|
||||
filename = "test";
|
||||
//return;
|
||||
|
||||
}
|
||||
else {
|
||||
if (found->_value.size() < 16) {
|
||||
filename = _activeUrl.fileName().toStdString();
|
||||
}
|
||||
else {
|
||||
filename = std::string(reinterpret_cast<char*>(found->_value.data()), 32);
|
||||
}
|
||||
}
|
||||
|
||||
auto memKtx = ktx::KTX::createBare(*header, keyValues);
|
||||
|
||||
auto d = const_cast<uint8_t*>(memKtx->getStorage()->data());
|
||||
///memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size());
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
// Move ktx to file
|
||||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
KTXFilePointer file;
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
qCWarning(modelnetworking) << _url << "file cache failed";
|
||||
return;
|
||||
}
|
||||
else {
|
||||
_file = file;
|
||||
}
|
||||
|
||||
//_ktxDescriptor.reset(new ktx::KTXDescriptor(memKtx->toDescriptor()));
|
||||
auto newKtxDescriptor = memKtx->toDescriptor();
|
||||
|
||||
//auto texture = gpu::Texture::serializeHeader("test.ktx", *header, keyValues);
|
||||
gpu::TexturePointer texture;
|
||||
texture.reset(gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor));
|
||||
texture->setKtxBacking(file->getFilepath());
|
||||
texture->setSource(filename);
|
||||
texture->registerMipInterestListener(this);
|
||||
|
||||
auto& images = _originalKtxDescriptor->images;
|
||||
size_t imageSizeRemaining = _ktxHighMipData.size();
|
||||
uint8_t* ktxData = reinterpret_cast<uint8_t*>(_ktxHighMipData.data());
|
||||
ktxData += _ktxHighMipData.size();
|
||||
// TODO Move image offset calculation to ktx ImageDescriptor
|
||||
int level;
|
||||
for (level = images.size() - 1; level >= 0; --level) {
|
||||
auto& image = images[level];
|
||||
if (image._imageSize > imageSizeRemaining) {
|
||||
break;
|
||||
}
|
||||
qDebug() << "Transferring " << level;
|
||||
ktxData -= image._imageSize;
|
||||
texture->assignStoredMip(level, image._imageSize, ktxData);
|
||||
ktxData -= 4;
|
||||
imageSizeRemaining - image._imageSize - 4;
|
||||
}
|
||||
|
||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
||||
// images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will
|
||||
// be the winner
|
||||
if (textureCache) {
|
||||
texture = textureCache->cacheTextureByHash(filename, texture);
|
||||
}
|
||||
|
||||
|
||||
_lowestKnownPopulatedMip = _originalKtxDescriptor->header.numberOfMipmapLevels;
|
||||
for (uint16_t l = 0; l < 200; l++) {
|
||||
if (texture->isStoredMipFaceAvailable(l)) {
|
||||
_lowestKnownPopulatedMip = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ResourceCache::requestCompleted(_self);
|
||||
|
||||
setImage(texture, header->getPixelWidth(), header->getPixelHeight());
|
||||
|
||||
qDebug() << "Identifier:" << QString(QByteArray((char*)header->identifier, 12));
|
||||
qDebug() << "Type:" << header->glType;
|
||||
qDebug() << "TypeSize:" << header->glTypeSize;
|
||||
qDebug() << "numberOfArrayElements:" << header->numberOfArrayElements;
|
||||
qDebug() << "numberOfFaces:" << header->numberOfFaces;
|
||||
qDebug() << "numberOfMipmapLevels:" << header->numberOfMipmapLevels;
|
||||
auto kvSize = header->bytesOfKeyValueData;
|
||||
if (kvSize > _ktxHeaderData.size() - ktx::KTX_HEADER_SIZE) {
|
||||
qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request";
|
||||
return;
|
||||
}
|
||||
|
||||
auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast<const ktx::Byte*>(_ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE);
|
||||
|
||||
auto imageDescriptors = header->generateImageDescriptors();
|
||||
_originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors));
|
||||
|
||||
// Create bare ktx in memory
|
||||
std::string filename = "test";
|
||||
auto memKtx = ktx::KTX::createBare(*header, keyValues);
|
||||
|
||||
auto d = const_cast<uint8_t*>(memKtx->getStorage()->data());
|
||||
///memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size());
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
// Move ktx to file
|
||||
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
|
||||
size_t length = memKtx->_storage->size();
|
||||
KTXFilePointer file;
|
||||
auto& ktxCache = textureCache->_ktxCache;
|
||||
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
|
||||
qCWarning(modelnetworking) << _url << "file cache failed";
|
||||
} else {
|
||||
_file = file;
|
||||
}
|
||||
|
||||
//_ktxDescriptor.reset(new ktx::KTXDescriptor(memKtx->toDescriptor()));
|
||||
auto newKtxDescriptor = memKtx->toDescriptor();
|
||||
|
||||
//auto texture = gpu::Texture::serializeHeader("test.ktx", *header, keyValues);
|
||||
gpu::TexturePointer texture;
|
||||
texture.reset(gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor));
|
||||
texture->setKtxBacking(file->getFilepath());
|
||||
texture->setSource(filename);
|
||||
texture->registerMipInterestListener(this);
|
||||
|
||||
auto& images = _originalKtxDescriptor->images;
|
||||
size_t imageSizeRemaining = _ktxHighMipData.size();
|
||||
uint8_t* ktxData = reinterpret_cast<uint8_t*>(_ktxHighMipData.data());
|
||||
ktxData += _ktxHighMipData.size();
|
||||
// TODO Move image offset calculation to ktx ImageDescriptor
|
||||
uint16_t level;
|
||||
for (level = images.size() - 1; level >= 0; --level) {
|
||||
auto& image = images[level];
|
||||
if (image._imageSize > imageSizeRemaining) {
|
||||
break;
|
||||
/*
|
||||
// Force load the next two levels
|
||||
{
|
||||
QTimer* timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, this, [=]() {
|
||||
//startMipRangeRequest(level, level);
|
||||
startRequestForNextMipLevel();
|
||||
});
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(4000);
|
||||
timer->start();
|
||||
}
|
||||
qDebug() << "Transferring " << level;
|
||||
ktxData -= image._imageSize;
|
||||
texture->assignStoredMip(level, image._imageSize, ktxData);
|
||||
ktxData -= 4;
|
||||
imageSizeRemaining - image._imageSize - 4;
|
||||
}
|
||||
|
||||
_initialKtxLoaded = true;
|
||||
|
||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
||||
// images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will
|
||||
// be the winner
|
||||
if (textureCache) {
|
||||
texture = textureCache->cacheTextureByHash(filename, texture);
|
||||
}
|
||||
|
||||
|
||||
_lowestKnownPopulatedMip = _originalKtxDescriptor->header.numberOfMipmapLevels;
|
||||
for (uint16_t l = 0; l < 200; l++) {
|
||||
if (texture->isStoredMipFaceAvailable(l)) {
|
||||
_lowestKnownPopulatedMip = l;
|
||||
break;
|
||||
{
|
||||
QTimer* timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, this, [=]() {
|
||||
//startMipRangeRequest(level - 1, level - 1);
|
||||
startRequestForNextMipLevel();
|
||||
});
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(6000);
|
||||
timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
setImage(texture, header->getPixelWidth(), header->getPixelHeight());
|
||||
|
||||
return;
|
||||
|
||||
// Force load the next two levels
|
||||
{
|
||||
QTimer* timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, this, [=]() {
|
||||
//startMipRangeRequest(level, level);
|
||||
startRequestForNextMipLevel();
|
||||
});
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(4000);
|
||||
timer->start();
|
||||
}
|
||||
|
||||
{
|
||||
QTimer* timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, this, [=]() {
|
||||
//startMipRangeRequest(level - 1, level - 1);
|
||||
startRequestForNextMipLevel();
|
||||
});
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(6000);
|
||||
timer->start();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ class NetworkTexture : public Resource, public Texture, public gpu::Texture::Mip
|
|||
|
||||
public:
|
||||
NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels);
|
||||
NetworkTexture::~NetworkTexture() override;
|
||||
|
||||
QString getType() const override { return "NetworkTexture"; }
|
||||
|
||||
|
@ -91,13 +92,6 @@ private:
|
|||
|
||||
image::TextureUsage::Type _type;
|
||||
|
||||
enum KTXLoadState {
|
||||
LOADING_HEADER,
|
||||
LOADING_LOWEST_SIX,
|
||||
DONE_LOADING
|
||||
};
|
||||
|
||||
bool _initialKtxLoaded { false };
|
||||
KTXFilePointer _file;
|
||||
static const uint16_t NULL_MIP_LEVEL;
|
||||
bool _sourceIsKTX { false };
|
||||
|
@ -105,6 +99,8 @@ private:
|
|||
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
|
||||
ResourceRequest* _ktxHeaderRequest { nullptr };
|
||||
ResourceRequest* _ktxMipRequest { nullptr };
|
||||
bool _headerRequestFinished{ false };
|
||||
bool _highMipRequestFinished{ false };
|
||||
uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
|
||||
uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };
|
||||
QByteArray _ktxHeaderData;
|
||||
|
|
|
@ -70,7 +70,7 @@ StoragePointer FileStorage::create(const QString& filename, size_t size, const u
|
|||
// Represents a memory mapped file
|
||||
FileStorage::FileStorage(const QString& filename) : _file(filename) {
|
||||
if (_file.open(QFile::ReadWrite)) {
|
||||
qDebug() << ">>> Opening mmapped file: " << filename;
|
||||
//qDebug() << ">>> Opening mmapped file: " << filename;
|
||||
_mapped = _file.map(0, _file.size());
|
||||
if (_mapped) {
|
||||
_valid = true;
|
||||
|
@ -83,7 +83,7 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) {
|
|||
}
|
||||
|
||||
FileStorage::~FileStorage() {
|
||||
qDebug() << ">>> Closing mmapped file: " << _file.fileName();
|
||||
//qDebug() << ">>> Closing mmapped file: " << _file.fileName();
|
||||
if (_mapped) {
|
||||
if (!_file.unmap(_mapped)) {
|
||||
throw std::runtime_error("Unable to unmap file");
|
||||
|
|
Loading…
Reference in a new issue