mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-10 09:08:40 +02:00
Add loading of lower mips to NetworkTexture
This commit is contained in:
parent
39c3fee838
commit
ab7099b3eb
7 changed files with 121 additions and 20 deletions
|
@ -190,6 +190,7 @@ void GL45ResourceTexture::populateTransferQueue() {
|
||||||
qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
||||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
||||||
|
const_cast<gpu::Texture&>(_gpuObject).requestInterestInMip(sourceMip);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
void Texture::setAutoGenerateMips(bool enable) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
if (!_autoGenerateMips) {
|
if (!_autoGenerateMips) {
|
||||||
|
|
|
@ -310,19 +310,22 @@ public:
|
||||||
KtxStorage(const std::string& filename);
|
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;
|
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;
|
bool isMipAvailable(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;
|
||||||
|
|
||||||
void reset() override { }
|
void reset() override { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::shared_ptr<storage::FileStorage> maybeOpenFile();
|
||||||
|
|
||||||
|
std::mutex _cacheFileCreateMutex;
|
||||||
|
std::mutex _cacheFileWriteMutex;
|
||||||
|
std::weak_ptr<storage::FileStorage> _cacheFile;
|
||||||
|
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
uint8_t _minMipLevelAvailable;
|
std::atomic<uint8_t> _minMipLevelAvailable;
|
||||||
//storage::FileStorage _cacheFile;
|
|
||||||
ktx::KTXDescriptorPointer _ktxDescriptor;
|
ktx::KTXDescriptorPointer _ktxDescriptor;
|
||||||
friend class Texture;
|
friend class Texture;
|
||||||
};
|
};
|
||||||
|
@ -470,7 +473,7 @@ public:
|
||||||
|
|
||||||
// Access the stored mips and faces
|
// Access the stored mips and faces
|
||||||
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); }
|
||||||
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 getStoredMipFaceSize(uint16 level, uint8 face = 0) const { return _storage->getMipFaceSize(level, face); }
|
||||||
Size getStoredMipSize(uint16 level) const;
|
Size getStoredMipSize(uint16 level) const;
|
||||||
Size getStoredSize() const;
|
Size getStoredSize() const;
|
||||||
|
@ -478,6 +481,17 @@ public:
|
||||||
void setStorage(std::unique_ptr<Storage>& newStorage);
|
void setStorage(std::unique_ptr<Storage>& newStorage);
|
||||||
void setKtxBacking(const std::string& filename);
|
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.
|
// Usage is a a set of flags providing Semantic about the usage of the Texture.
|
||||||
void setUsage(const Usage& usage) { _usage = usage; }
|
void setUsage(const Usage& usage) { _usage = usage; }
|
||||||
Usage getUsage() const { return _usage; }
|
Usage getUsage() const { return _usage; }
|
||||||
|
|
|
@ -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 {
|
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;
|
storage::StoragePointer result;
|
||||||
|
@ -86,9 +99,8 @@ Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
|
||||||
|
|
||||||
|
|
||||||
bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const {
|
bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const {
|
||||||
auto minLevel = _minMipLevelAvailable;
|
auto avail = level >= _minMipLevelAvailable;
|
||||||
auto avail = level >= minLevel;
|
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << _minMipLevelAvailable << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
||||||
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << minLevel << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
|
||||||
//return true;
|
//return true;
|
||||||
return avail;
|
return avail;
|
||||||
}
|
}
|
||||||
|
@ -108,8 +120,9 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto fileStorage = new storage::FileStorage(_filename.c_str());
|
//auto fileStorage = new storage::FileStorage(_filename.c_str());
|
||||||
ktx::StoragePointer file { fileStorage };
|
//ktx::StoragePointer file { fileStorage };
|
||||||
|
auto file = maybeOpenFile();
|
||||||
auto data = file->mutableData();
|
auto data = file->mutableData();
|
||||||
data += file->size();
|
data += file->size();
|
||||||
|
|
||||||
|
@ -119,8 +132,17 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
|
||||||
data -= 4;
|
data -= 4;
|
||||||
}
|
}
|
||||||
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) {
|
void KtxStorage::assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) {
|
||||||
|
|
|
@ -70,7 +70,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
namespace ktx {
|
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) };
|
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
|
||||||
|
@ -414,10 +414,10 @@ namespace ktx {
|
||||||
struct ImageHeader {
|
struct ImageHeader {
|
||||||
using FaceOffsets = std::vector<size_t>;
|
using FaceOffsets = std::vector<size_t>;
|
||||||
using FaceBytes = std::vector<const Byte*>;
|
using FaceBytes = std::vector<const Byte*>;
|
||||||
|
|
||||||
// This is the byte offset from the _start_ of the image region. For example, level 0
|
// This is the byte offset from the _start_ of the image region. For example, level 0
|
||||||
// will have a byte offset of 0.
|
// will have a byte offset of 0.
|
||||||
const uint32_t _imageOffset;
|
const uint32_t _imageOffset;
|
||||||
|
|
||||||
const uint32_t _numFaces;
|
const uint32_t _numFaces;
|
||||||
const uint32_t _imageSize;
|
const uint32_t _imageSize;
|
||||||
const uint32_t _faceSize;
|
const uint32_t _faceSize;
|
||||||
|
|
|
@ -244,6 +244,10 @@ gpu::TexturePointer getFallbackTextureForType(image::TextureUsage::Type type) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkTexture::~NetworkTexture() {
|
||||||
|
_textureSource->getGPUTexture()->unregisterMipInterestListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a texture version of an image file
|
/// Returns a texture version of an image file
|
||||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::TextureUsage::Type type, QVariantMap options) {
|
gpu::TexturePointer TextureCache::getImageTexture(const QString& path, image::TextureUsage::Type type, QVariantMap options) {
|
||||||
QImage image = QImage(path);
|
QImage image = QImage(path);
|
||||||
|
@ -371,6 +375,21 @@ void NetworkTexture::makeRequest() {
|
||||||
startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL);
|
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)
|
// Load mips in the range [low, high] (inclusive)
|
||||||
void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
||||||
if (_ktxMipRequest) {
|
if (_ktxMipRequest) {
|
||||||
|
@ -430,6 +449,8 @@ void NetworkTexture::ktxMipRequestFinished() {
|
||||||
if (_ktxMipRequest->getResult() == ResourceRequest::Success) {
|
if (_ktxMipRequest->getResult() == ResourceRequest::Success) {
|
||||||
if (_initialKtxLoaded) {
|
if (_initialKtxLoaded) {
|
||||||
assert(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
|
assert(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
|
||||||
|
|
||||||
|
_lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first;
|
||||||
|
|
||||||
_textureSource->getGPUTexture()->assignStoredMip(_ktxMipLevelRangeInFlight.first,
|
_textureSource->getGPUTexture()->assignStoredMip(_ktxMipLevelRangeInFlight.first,
|
||||||
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
|
_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.reset(gpu::Texture::unserialize(_file->getFilepath(), *_ktxDescriptor));
|
||||||
texture->setKtxBacking(file->getFilepath());
|
texture->setKtxBacking(file->getFilepath());
|
||||||
texture->setSource(filename);
|
texture->setSource(filename);
|
||||||
|
texture->registerMipInterestListener(this);
|
||||||
|
|
||||||
auto& images = _ktxDescriptor->images;
|
auto& images = _ktxDescriptor->images;
|
||||||
size_t imageSizeRemaining = _ktxHighMipData.size();
|
size_t imageSizeRemaining = _ktxHighMipData.size();
|
||||||
|
@ -521,6 +543,15 @@ void NetworkTexture::maybeCreateKTX() {
|
||||||
texture = textureCache->cacheTextureByHash(filename, texture);
|
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());
|
setImage(texture, header->getPixelWidth(), header->getPixelHeight());
|
||||||
|
|
||||||
|
|
||||||
|
@ -528,7 +559,8 @@ void NetworkTexture::maybeCreateKTX() {
|
||||||
{
|
{
|
||||||
QTimer* timer = new QTimer();
|
QTimer* timer = new QTimer();
|
||||||
connect(timer, &QTimer::timeout, this, [=]() {
|
connect(timer, &QTimer::timeout, this, [=]() {
|
||||||
startMipRangeRequest(level, level);
|
//startMipRangeRequest(level, level);
|
||||||
|
startRequestForNextMipLevel();
|
||||||
});
|
});
|
||||||
timer->setSingleShot(true);
|
timer->setSingleShot(true);
|
||||||
timer->setInterval(4000);
|
timer->setInterval(4000);
|
||||||
|
@ -538,7 +570,8 @@ void NetworkTexture::maybeCreateKTX() {
|
||||||
{
|
{
|
||||||
QTimer* timer = new QTimer();
|
QTimer* timer = new QTimer();
|
||||||
connect(timer, &QTimer::timeout, this, [=]() {
|
connect(timer, &QTimer::timeout, this, [=]() {
|
||||||
startMipRangeRequest(level - 1, level - 1);
|
//startMipRangeRequest(level - 1, level - 1);
|
||||||
|
startRequestForNextMipLevel();
|
||||||
});
|
});
|
||||||
timer->setSingleShot(true);
|
timer->setSingleShot(true);
|
||||||
timer->setInterval(6000);
|
timer->setInterval(6000);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A texture loaded from the network.
|
/// A texture loaded from the network.
|
||||||
class NetworkTexture : public Resource, public Texture {
|
class NetworkTexture : public Resource, public Texture, public gpu::Texture::MipInterestListener {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -57,6 +57,9 @@ public:
|
||||||
|
|
||||||
gpu::TexturePointer getFallbackTexture() const;
|
gpu::TexturePointer getFallbackTexture() const;
|
||||||
|
|
||||||
|
void handleMipInterestCallback(uint16_t level) override;
|
||||||
|
Q_INVOKABLE void handleMipInterestLevel(uint16_t level);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
|
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
|
||||||
|
|
||||||
|
@ -77,6 +80,8 @@ protected:
|
||||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||||
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
|
||||||
|
|
||||||
|
void startRequestForNextMipLevel();
|
||||||
|
|
||||||
void startMipRangeRequest(uint16_t low, uint16_t high);
|
void startMipRangeRequest(uint16_t low, uint16_t high);
|
||||||
void maybeCreateKTX();
|
void maybeCreateKTX();
|
||||||
|
|
||||||
|
@ -92,9 +97,7 @@ private:
|
||||||
DONE_LOADING
|
DONE_LOADING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool _initialKtxLoaded { false };
|
bool _initialKtxLoaded { false };
|
||||||
//KTXLoadState _ktxLoadState;
|
|
||||||
KTXFilePointer _file;
|
KTXFilePointer _file;
|
||||||
static const uint16_t NULL_MIP_LEVEL;
|
static const uint16_t NULL_MIP_LEVEL;
|
||||||
bool _sourceIsKTX { false };
|
bool _sourceIsKTX { false };
|
||||||
|
@ -102,6 +105,8 @@ private:
|
||||||
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
|
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
|
||||||
ResourceRequest* _ktxHeaderRequest { nullptr };
|
ResourceRequest* _ktxHeaderRequest { nullptr };
|
||||||
ResourceRequest* _ktxMipRequest { nullptr };
|
ResourceRequest* _ktxMipRequest { nullptr };
|
||||||
|
uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
|
||||||
|
uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };
|
||||||
QByteArray _ktxHeaderData;
|
QByteArray _ktxHeaderData;
|
||||||
QByteArray _ktxHighMipData;
|
QByteArray _ktxHighMipData;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue