Add loading of lower mips to NetworkTexture

This commit is contained in:
Ryan Huffman 2017-04-16 23:16:23 -07:00 committed by Atlante45
parent 39c3fee838
commit ab7099b3eb
7 changed files with 121 additions and 20 deletions

View file

@ -190,6 +190,7 @@ void GL45ResourceTexture::populateTransferQueue() {
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);
continue;
}

View file

@ -476,6 +476,32 @@ void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePoin
}
}
void Texture::requestInterestInMip(uint16 level) {
if (!_storage->isMipAvailable(level, 0)) {
std::lock_guard<std::mutex> lock(_mipInterestListenersMutex);
for (auto& callback : _mipInterestListeners) {
callback->handleMipInterestCallback(level);
}
}
}
bool Texture::isStoredMipFaceAvailable(uint16 level, uint8 face) const {
return _storage->isMipAvailable(level, face);
}
void Texture::registerMipInterestListener(MipInterestListener* listener) {
std::lock_guard<std::mutex> lock(_mipInterestListenersMutex);
_mipInterestListeners.push_back(listener);
}
void Texture::unregisterMipInterestListener(MipInterestListener* listener) {
std::lock_guard<std::mutex> lock(_mipInterestListenersMutex);
auto it = find(_mipInterestListeners.begin(), _mipInterestListeners.end(), listener);
if (it != _mipInterestListeners.end()) {
_mipInterestListeners.erase(it);
}
}
void Texture::setAutoGenerateMips(bool enable) {
bool changed = false;
if (!_autoGenerateMips) {

View file

@ -310,19 +310,22 @@ public:
KtxStorage(const std::string& filename);
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
bool isMipAvailable(uint16 level, uint8 face = 0) const override;
void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
void reset() override { }
protected:
std::shared_ptr<storage::FileStorage> maybeOpenFile();
std::mutex _cacheFileCreateMutex;
std::mutex _cacheFileWriteMutex;
std::weak_ptr<storage::FileStorage> _cacheFile;
std::string _filename;
uint8_t _minMipLevelAvailable;
//storage::FileStorage _cacheFile;
std::atomic<uint8_t> _minMipLevelAvailable;
ktx::KTXDescriptorPointer _ktxDescriptor;
friend class Texture;
};
@ -470,7 +473,7 @@ public:
// Access the stored mips and faces
const PixelsPointer accessStoredMipFace(uint16 level, uint8 face = 0) const { return _storage->getMipFace(level, face); }
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); }
Size getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
Size getStoredMipSize(uint16 level) const;
Size getStoredSize() const;
@ -478,6 +481,17 @@ public:
void setStorage(std::unique_ptr<Storage>& newStorage);
void setKtxBacking(const std::string& filename);
class MipInterestListener {
public:
virtual void handleMipInterestCallback(uint16 level) = 0;
};
void registerMipInterestListener(MipInterestListener* listener);
void unregisterMipInterestListener(MipInterestListener* listener);
std::vector<MipInterestListener*> _mipInterestListeners;
std::mutex _mipInterestListenersMutex;
void requestInterestInMip(uint16 level);
// Usage is a a set of flags providing Semantic about the usage of the Texture.
void setUsage(const Usage& usage) { _usage = usage; }
Usage getUsage() const { return _usage; }

View file

@ -69,6 +69,19 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
}
}
std::shared_ptr<storage::FileStorage> KtxStorage::maybeOpenFile() {
std::shared_ptr<storage::FileStorage> file = _cacheFile.lock();
if (file) {
return file;
}
std::lock_guard<std::mutex> lock { _cacheFileCreateMutex };
file = std::make_shared<storage::FileStorage>(_filename.c_str());
_cacheFile = file;
return file;
}
PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const {
qDebug() << "getMipFace: " << QString::fromStdString(_filename) << ": " << level << " " << face;
storage::StoragePointer result;
@ -86,9 +99,8 @@ Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const {
auto minLevel = _minMipLevelAvailable;
auto avail = level >= minLevel;
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << minLevel << " " << _ktxDescriptor->header.numberOfMipmapLevels;
auto avail = level >= _minMipLevelAvailable;
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << _minMipLevelAvailable << " " << _ktxDescriptor->header.numberOfMipmapLevels;
//return true;
return avail;
}
@ -108,8 +120,9 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
}
auto fileStorage = new storage::FileStorage(_filename.c_str());
ktx::StoragePointer file { fileStorage };
//auto fileStorage = new storage::FileStorage(_filename.c_str());
//ktx::StoragePointer file { fileStorage };
auto file = maybeOpenFile();
auto data = file->mutableData();
data += file->size();
@ -119,8 +132,17 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
data -= 4;
}
data += 4;
memcpy(data, storage->data(), _ktxDescriptor->images[level]._imageSize);
_minMipLevelAvailable = level;
{
std::lock_guard<std::mutex> lock { _cacheFileWriteMutex };
if (level != _minMipLevelAvailable - 1) {
qWarning() << "Invalid level to be stored";
return;
}
memcpy(data, storage->data(), _ktxDescriptor->images[level]._imageSize);
_minMipLevelAvailable = level;
}
}
void KtxStorage::assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) {

View file

@ -70,7 +70,7 @@ end
namespace ktx {
const std::string HIFI_MIN_POPULATED_MIP_KEY = "hifiMinMip";
const std::string HIFI_MIN_POPULATED_MIP_KEY = "hifi.minMip";
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
@ -414,10 +414,10 @@ namespace ktx {
struct ImageHeader {
using FaceOffsets = std::vector<size_t>;
using FaceBytes = std::vector<const Byte*>;
// This is the byte offset from the _start_ of the image region. For example, level 0
// will have a byte offset of 0.
const uint32_t _imageOffset;
const uint32_t _numFaces;
const uint32_t _imageSize;
const uint32_t _faceSize;

View file

@ -244,6 +244,10 @@ gpu::TexturePointer getFallbackTextureForType(image::TextureUsage::Type type) {
return result;
}
NetworkTexture::~NetworkTexture() {
_textureSource->getGPUTexture()->unregisterMipInterestListener(this);
}
/// Returns a texture version of an image file
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::TextureUsage::Type type, QVariantMap options) {
QImage image = QImage(path);
@ -371,6 +375,21 @@ void NetworkTexture::makeRequest() {
startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL);
}
void NetworkTexture::handleMipInterestCallback(uint16_t level) {
QMetaObject::invokeMethod(this, "handleMipInterestLevel", Qt::QueuedConnection, Q_ARG(uint16_t, level));
}
void NetworkTexture::handleMipInterestLevel(uint16_t level) {
_lowestRequestedMipLevel = std::min(level, _lowestRequestedMipLevel);
if (!_ktxMipRequest) {
startRequestForNextMipLevel();
}
}
void NetworkTexture::startRequestForNextMipLevel() {
startMipRangeRequest(std::max(0, _lowestKnownPopulatedMip - 1), std::max(0, _lowestKnownPopulatedMip - 1));
}
// Load mips in the range [low, high] (inclusive)
void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
if (_ktxMipRequest) {
@ -430,6 +449,8 @@ void NetworkTexture::ktxMipRequestFinished() {
if (_ktxMipRequest->getResult() == ResourceRequest::Success) {
if (_initialKtxLoaded) {
assert(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
_lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first;
_textureSource->getGPUTexture()->assignStoredMip(_ktxMipLevelRangeInFlight.first,
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
@ -493,6 +514,7 @@ void NetworkTexture::maybeCreateKTX() {
texture.reset(gpu::Texture::unserialize(_file->getFilepath(), *_ktxDescriptor));
texture->setKtxBacking(file->getFilepath());
texture->setSource(filename);
texture->registerMipInterestListener(this);
auto& images = _ktxDescriptor->images;
size_t imageSizeRemaining = _ktxHighMipData.size();
@ -521,6 +543,15 @@ void NetworkTexture::maybeCreateKTX() {
texture = textureCache->cacheTextureByHash(filename, texture);
}
_lowestKnownPopulatedMip = _ktxDescriptor->header.numberOfMipmapLevels;
for (uint16_t l = 0; l < 200; l++) {
if (texture->isStoredMipFaceAvailable(l)) {
_lowestKnownPopulatedMip = l;
break;
}
}
setImage(texture, header->getPixelWidth(), header->getPixelHeight());
@ -528,7 +559,8 @@ void NetworkTexture::maybeCreateKTX() {
{
QTimer* timer = new QTimer();
connect(timer, &QTimer::timeout, this, [=]() {
startMipRangeRequest(level, level);
//startMipRangeRequest(level, level);
startRequestForNextMipLevel();
});
timer->setSingleShot(true);
timer->setInterval(4000);
@ -538,7 +570,8 @@ void NetworkTexture::maybeCreateKTX() {
{
QTimer* timer = new QTimer();
connect(timer, &QTimer::timeout, this, [=]() {
startMipRangeRequest(level - 1, level - 1);
//startMipRangeRequest(level - 1, level - 1);
startRequestForNextMipLevel();
});
timer->setSingleShot(true);
timer->setInterval(6000);

View file

@ -41,7 +41,7 @@ public:
};
/// A texture loaded from the network.
class NetworkTexture : public Resource, public Texture {
class NetworkTexture : public Resource, public Texture, public gpu::Texture::MipInterestListener {
Q_OBJECT
public:
@ -57,6 +57,9 @@ public:
gpu::TexturePointer getFallbackTexture() const;
void handleMipInterestCallback(uint16_t level) override;
Q_INVOKABLE void handleMipInterestLevel(uint16_t level);
signals:
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
@ -77,6 +80,8 @@ protected:
Q_INVOKABLE void loadContent(const QByteArray& content);
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
void startRequestForNextMipLevel();
void startMipRangeRequest(uint16_t low, uint16_t high);
void maybeCreateKTX();
@ -92,9 +97,7 @@ private:
DONE_LOADING
};
bool _initialKtxLoaded { false };
//KTXLoadState _ktxLoadState;
KTXFilePointer _file;
static const uint16_t NULL_MIP_LEVEL;
bool _sourceIsKTX { false };
@ -102,6 +105,8 @@ private:
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
ResourceRequest* _ktxHeaderRequest { nullptr };
ResourceRequest* _ktxMipRequest { nullptr };
uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };
QByteArray _ktxHeaderData;
QByteArray _ktxHighMipData;