mirror of
https://github.com/lubosz/overte.git
synced 2025-08-14 05:19:25 +02:00
Add object labels to GL objects and add ktx min mip kv
This commit is contained in:
parent
aca7ad27c6
commit
cf3dc12542
9 changed files with 72 additions and 19 deletions
|
@ -109,6 +109,8 @@ GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
|
||||||
GLuint GL45Texture::allocate(const Texture& texture) {
|
GLuint GL45Texture::allocate(const Texture& texture) {
|
||||||
GLuint result;
|
GLuint result;
|
||||||
glCreateTextures(getGLTextureType(texture), 1, &result);
|
glCreateTextures(getGLTextureType(texture), 1, &result);
|
||||||
|
auto source = texture.source();
|
||||||
|
glObjectLabel(GL_TEXTURE, result, source.length(), source.data());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,16 +41,25 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() {
|
||||||
using GL45ResourceTexture = GL45Backend::GL45ResourceTexture;
|
using GL45ResourceTexture = GL45Backend::GL45ResourceTexture;
|
||||||
|
|
||||||
GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45VariableAllocationTexture(backend, texture) {
|
GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45VariableAllocationTexture(backend, texture) {
|
||||||
|
if (texture.source().find_first_of("box.ktx") != std::string::npos) {
|
||||||
|
qDebug() << "In box.ktx ctor";
|
||||||
|
}
|
||||||
auto mipLevels = texture.getNumMips();
|
auto mipLevels = texture.getNumMips();
|
||||||
_allocatedMip = mipLevels;
|
_allocatedMip = mipLevels;
|
||||||
|
|
||||||
|
_maxAllocatedMip = _populatedMip = mipLevels;
|
||||||
|
|
||||||
uvec3 mipDimensions;
|
uvec3 mipDimensions;
|
||||||
for (uint16_t mip = 0; mip < mipLevels; ++mip) {
|
for (uint16_t mip = 0; mip < mipLevels; ++mip) {
|
||||||
if (glm::all(glm::lessThanEqual(texture.evalMipDimensions(mip), INITIAL_MIP_TRANSFER_DIMENSIONS))) {
|
if (glm::all(glm::lessThanEqual(texture.evalMipDimensions(mip), INITIAL_MIP_TRANSFER_DIMENSIONS))
|
||||||
|
&& texture.isStoredMipFaceAvailable(mip)) {
|
||||||
_maxAllocatedMip = _populatedMip = mip;
|
_maxAllocatedMip = _populatedMip = mip;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//_maxAllocatedMip = _populatedMip = mipLevels;
|
||||||
|
|
||||||
|
//glObjectLabel(GL_TEXTURE, _id, _source.length(), _source.data());
|
||||||
uint16_t allocatedMip = _populatedMip - std::min<uint16_t>(_populatedMip, 2);
|
uint16_t allocatedMip = _populatedMip - std::min<uint16_t>(_populatedMip, 2);
|
||||||
allocateStorage(allocatedMip);
|
allocateStorage(allocatedMip);
|
||||||
copyMipsFromTexture();
|
copyMipsFromTexture();
|
||||||
|
@ -87,6 +96,10 @@ void GL45ResourceTexture::copyMipsFromTexture() {
|
||||||
|
|
||||||
void GL45ResourceTexture::syncSampler() const {
|
void GL45ResourceTexture::syncSampler() const {
|
||||||
Parent::syncSampler();
|
Parent::syncSampler();
|
||||||
|
qDebug() << "glTextureParameteri " << QString::fromStdString(_source) << _populatedMip << _populatedMip - _allocatedMip;
|
||||||
|
if (_source == "test" && _populatedMip == 0) {
|
||||||
|
qDebug() << "here";
|
||||||
|
}
|
||||||
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
|
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +110,7 @@ void GL45ResourceTexture::promote() {
|
||||||
auto oldSize = _size;
|
auto oldSize = _size;
|
||||||
// create new texture
|
// create new texture
|
||||||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||||
|
//glObjectLabel(GL_TEXTURE, _id, _source.length(), _source.data());
|
||||||
uint16_t oldAllocatedMip = _allocatedMip;
|
uint16_t oldAllocatedMip = _allocatedMip;
|
||||||
// allocate storage for new level
|
// allocate storage for new level
|
||||||
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
|
allocateStorage(_allocatedMip - std::min<uint16_t>(_allocatedMip, 2));
|
||||||
|
@ -130,6 +144,7 @@ void GL45ResourceTexture::demote() {
|
||||||
auto oldId = _id;
|
auto oldId = _id;
|
||||||
auto oldSize = _size;
|
auto oldSize = _size;
|
||||||
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
const_cast<GLuint&>(_id) = allocate(_gpuObject);
|
||||||
|
//glObjectLabel(GL_TEXTURE, _id, _source.length(), _source.data());
|
||||||
allocateStorage(_allocatedMip + 1);
|
allocateStorage(_allocatedMip + 1);
|
||||||
_populatedMip = std::max(_populatedMip, _allocatedMip);
|
_populatedMip = std::max(_populatedMip, _allocatedMip);
|
||||||
uint16_t mips = _gpuObject.getNumMips();
|
uint16_t mips = _gpuObject.getNumMips();
|
||||||
|
@ -166,20 +181,24 @@ void GL45ResourceTexture::populateTransferQueue() {
|
||||||
|
|
||||||
const uint8_t maxFace = GLTexture::getFaceCount(_target);
|
const uint8_t maxFace = GLTexture::getFaceCount(_target);
|
||||||
uint16_t sourceMip = _populatedMip;
|
uint16_t sourceMip = _populatedMip;
|
||||||
|
qDebug() << "populateTransferQueue info : " << _populatedMip << " " << _maxAllocatedMip << " " << _allocatedMip;
|
||||||
do {
|
do {
|
||||||
--sourceMip;
|
--sourceMip;
|
||||||
auto targetMip = sourceMip - _allocatedMip;
|
auto targetMip = sourceMip - _allocatedMip;
|
||||||
auto mipDimensions = _gpuObject.evalMipDimensions(sourceMip);
|
auto mipDimensions = _gpuObject.evalMipDimensions(sourceMip);
|
||||||
|
bool transferQueued = false;
|
||||||
|
qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
||||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
qDebug() << "populateTransferQueue " << QString::fromStdString(_gpuObject.source()) << sourceMip << " " << targetMip;
|
|
||||||
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the mip is less than the max transfer size, then just do it in one transfer
|
// If the mip is less than the max transfer size, then just do it in one transfer
|
||||||
if (glm::all(glm::lessThanEqual(mipDimensions, MAX_TRANSFER_DIMENSIONS))) {
|
if (glm::all(glm::lessThanEqual(mipDimensions, MAX_TRANSFER_DIMENSIONS))) {
|
||||||
|
qDebug() << "mip is less than max transfer size";
|
||||||
// Can the mip be transferred in one go
|
// Can the mip be transferred in one go
|
||||||
_pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face));
|
_pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face));
|
||||||
|
transferQueued = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,18 +210,22 @@ void GL45ResourceTexture::populateTransferQueue() {
|
||||||
Q_ASSERT(0 == (mipSize % 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;
|
||||||
|
qDebug() << "queing up single line transfers " << linesPerTransfer << " " << lineOffset;
|
||||||
while (lineOffset < lines) {
|
while (lineOffset < lines) {
|
||||||
uint32_t linesToCopy = std::min<uint32_t>(lines - lineOffset, linesPerTransfer);
|
uint32_t linesToCopy = std::min<uint32_t>(lines - lineOffset, linesPerTransfer);
|
||||||
_pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face, linesToCopy, lineOffset));
|
_pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face, linesToCopy, lineOffset));
|
||||||
lineOffset += linesToCopy;
|
lineOffset += linesToCopy;
|
||||||
|
transferQueued = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue up the sampler and populated mip change for after the transfer has completed
|
// queue up the sampler and populated mip change for after the transfer has completed
|
||||||
_pendingTransfers.emplace(new TransferJob(*this, [=] {
|
if (transferQueued) {
|
||||||
_populatedMip = sourceMip;
|
_pendingTransfers.emplace(new TransferJob(*this, [=] {
|
||||||
syncSampler();
|
_populatedMip = sourceMip;
|
||||||
}));
|
syncSampler();
|
||||||
|
}));
|
||||||
|
}
|
||||||
} while (sourceMip != _allocatedMip);
|
} while (sourceMip != _allocatedMip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _filename;
|
std::string _filename;
|
||||||
|
uint8_t _minMipLevelAvailable;
|
||||||
//storage::FileStorage _cacheFile;
|
//storage::FileStorage _cacheFile;
|
||||||
ktx::KTXDescriptorPointer _ktxDescriptor;
|
ktx::KTXDescriptorPointer _ktxDescriptor;
|
||||||
friend class Texture;
|
friend class Texture;
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct GPUKTXPayload {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool findInKeyValues(const ktx::KeyValues& keyValues, GPUKTXPayload& payload) {
|
static bool findInKeyValues(const ktx::KeyValues& keyValues, GPUKTXPayload& payload) {
|
||||||
auto found = std::find_if(keyValues.begin(), keyValues.end(), isGPUKTX);
|
auto found = std::find_if(keyValues.begin(), keyValues.end(), isGPUKTX);
|
||||||
if (found != keyValues.end()) {
|
if (found != keyValues.end()) {
|
||||||
if ((*found)._value.size() == sizeof(GPUKTXPayload)) {
|
if ((*found)._value.size() == sizeof(GPUKTXPayload)) {
|
||||||
memcpy(&payload, (*found)._value.data(), sizeof(GPUKTXPayload));
|
memcpy(&payload, (*found)._value.data(), sizeof(GPUKTXPayload));
|
||||||
|
@ -41,14 +41,23 @@ struct GPUKTXPayload {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string GPUKTXPayload::KEY { "hifi.gpu" };
|
std::string GPUKTXPayload::KEY{ "hifi.gpu" };
|
||||||
|
|
||||||
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
|
||||||
{
|
{
|
||||||
// We are doing a lot of work here just to get descriptor data
|
// We are doing a lot of work here just to get descriptor data
|
||||||
ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) };
|
ktx::StoragePointer storage{ new storage::FileStorage(_filename.c_str()) };
|
||||||
auto ktxPointer = ktx::KTX::create(storage);
|
auto ktxPointer = ktx::KTX::create(storage);
|
||||||
_ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
|
_ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
|
||||||
|
auto& keyValues = _ktxDescriptor->keyValues;
|
||||||
|
auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool {
|
||||||
|
return val._key.compare(ktx::HIFI_MIN_POPULATED_MIP_KEY) == 0;
|
||||||
|
});
|
||||||
|
if (found != keyValues.end()) {
|
||||||
|
_minMipLevelAvailable = found->_value[0];
|
||||||
|
} else {
|
||||||
|
_minMipLevelAvailable = 4;// _ktxDescriptor->header.numberOfMipmapLevels;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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:
|
||||||
|
@ -76,12 +85,11 @@ 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 numLevels = _ktxDescriptor->header.numberOfMipmapLevels;
|
auto minLevel = _minMipLevelAvailable;
|
||||||
auto minLevel = 7 > numLevels ? 0 : numLevels - 10;
|
|
||||||
auto avail = level >= minLevel;
|
auto avail = level >= minLevel;
|
||||||
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << minLevel << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
qDebug() << "isMipAvailable: " << QString::fromStdString(_filename) << ": " << level << " " << face << avail << minLevel << " " << _ktxDescriptor->header.numberOfMipmapLevels;
|
||||||
//return true;
|
//return true;
|
||||||
return level > _ktxDescriptor->header.numberOfMipmapLevels - 7;
|
return avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) {
|
void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) {
|
||||||
|
|
|
@ -70,6 +70,9 @@ end
|
||||||
|
|
||||||
|
|
||||||
namespace ktx {
|
namespace ktx {
|
||||||
|
const std::string HIFI_MIN_POPULATED_MIP_KEY = "hifiMinMip";
|
||||||
|
|
||||||
|
|
||||||
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
|
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
|
||||||
using Byte = uint8_t;
|
using Byte = uint8_t;
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,19 @@ namespace ktx {
|
||||||
std::unique_ptr<KTX> KTX::createBare(const Header& header, const KeyValues& keyValues) {
|
std::unique_ptr<KTX> KTX::createBare(const Header& header, const KeyValues& keyValues) {
|
||||||
auto descriptors = header.generateImageDescriptors();
|
auto descriptors = header.generateImageDescriptors();
|
||||||
|
|
||||||
|
auto newHeader = header;
|
||||||
|
|
||||||
|
Byte minMip = header.numberOfMipmapLevels - 6;
|
||||||
|
auto newKeyValues = keyValues;
|
||||||
|
//newKeyValues.emplace_back(KeyValue(HIFI_MIN_POPULATED_MIP_KEY, sizeof(Byte), &minMip));
|
||||||
|
//newHeader.bytesOfKeyValueData = KeyValue::serializedKeyValuesByteSize(newKeyValues);
|
||||||
|
|
||||||
StoragePointer storagePointer;
|
StoragePointer storagePointer;
|
||||||
{
|
{
|
||||||
auto storageSize = ktx::KTX::evalStorageSize(header, descriptors, keyValues);
|
auto storageSize = ktx::KTX::evalStorageSize(header, descriptors, newKeyValues);
|
||||||
auto memoryStorage = new storage::MemoryStorage(storageSize);
|
auto memoryStorage = new storage::MemoryStorage(storageSize);
|
||||||
qDebug() << "Memory storage size is: " << storageSize;
|
qDebug() << "Memory storage size is: " << storageSize;
|
||||||
ktx::KTX::writeWithoutImages(memoryStorage->data(), memoryStorage->size(), header, descriptors, keyValues);
|
ktx::KTX::writeWithoutImages(memoryStorage->data(), memoryStorage->size(), header, descriptors, newKeyValues);
|
||||||
storagePointer.reset(memoryStorage);
|
storagePointer.reset(memoryStorage);
|
||||||
}
|
}
|
||||||
return create(storagePointer);
|
return create(storagePointer);
|
||||||
|
@ -132,6 +139,7 @@ namespace ktx {
|
||||||
memcpy(currentDestPtr, &header, sizeof(Header));
|
memcpy(currentDestPtr, &header, sizeof(Header));
|
||||||
currentDestPtr += sizeof(Header);
|
currentDestPtr += sizeof(Header);
|
||||||
|
|
||||||
|
|
||||||
// KeyValues
|
// KeyValues
|
||||||
if (!keyValues.empty()) {
|
if (!keyValues.empty()) {
|
||||||
destHeader->bytesOfKeyValueData = (uint32_t) writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
|
destHeader->bytesOfKeyValueData = (uint32_t) writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
|
||||||
|
@ -145,9 +153,11 @@ namespace ktx {
|
||||||
auto ptr = reinterpret_cast<uint32_t*>(currentDestPtr);
|
auto ptr = reinterpret_cast<uint32_t*>(currentDestPtr);
|
||||||
*ptr = descriptors[i]._imageSize;
|
*ptr = descriptors[i]._imageSize;
|
||||||
ptr++;
|
ptr++;
|
||||||
|
#ifdef DEBUG
|
||||||
for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) {
|
for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) {
|
||||||
*(ptr + k) = 0xFFFF0000;
|
*(ptr + k) = 0xFFFF00FF;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t);
|
currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,7 @@ void NetworkTexture::ktxMipRequestFinished() {
|
||||||
_ktxHighMipData = _ktxMipRequest->getData();
|
_ktxHighMipData = _ktxMipRequest->getData();
|
||||||
maybeCreateKTX();
|
maybeCreateKTX();
|
||||||
} else {
|
} else {
|
||||||
handleFailedRequest(_ktxHeaderRequest->getResult());
|
handleFailedRequest(_ktxMipRequest->getResult());
|
||||||
}
|
}
|
||||||
_ktxMipRequest->deleteLater();
|
_ktxMipRequest->deleteLater();
|
||||||
_ktxMipRequest = nullptr;
|
_ktxMipRequest = nullptr;
|
||||||
|
@ -433,7 +433,6 @@ void NetworkTexture::ktxMipRequestFinished() {
|
||||||
|
|
||||||
// This is called when the header or top mips have been loaded
|
// This is called when the header or top mips have been loaded
|
||||||
void NetworkTexture::maybeCreateKTX() {
|
void NetworkTexture::maybeCreateKTX() {
|
||||||
qDebug() << "Maybe create ktx...";
|
|
||||||
if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) {
|
if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) {
|
||||||
// create ktx...
|
// create ktx...
|
||||||
auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data());
|
auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data());
|
||||||
|
@ -478,6 +477,7 @@ void NetworkTexture::maybeCreateKTX() {
|
||||||
gpu::TexturePointer texture;
|
gpu::TexturePointer texture;
|
||||||
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);
|
||||||
|
|
||||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
// 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
|
// images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will
|
||||||
|
|
|
@ -103,6 +103,11 @@ private:
|
||||||
ResourceRequest* _ktxMipRequest { nullptr };
|
ResourceRequest* _ktxMipRequest { nullptr };
|
||||||
QByteArray _ktxHeaderData;
|
QByteArray _ktxHeaderData;
|
||||||
QByteArray _ktxHighMipData;
|
QByteArray _ktxHighMipData;
|
||||||
|
|
||||||
|
// This is a copy of the original KTX descriptor from the source url.
|
||||||
|
// We need this because the KTX that will be cached will likely include extra data
|
||||||
|
// in its key/value data, and so will not match up with the original, causing
|
||||||
|
// mip offsets to change.
|
||||||
ktx::KTXDescriptorPointer _ktxDescriptor;
|
ktx::KTXDescriptorPointer _ktxDescriptor;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,11 @@ void HTTPResourceRequest::doSend() {
|
||||||
if (_byteRange.isSet()) {
|
if (_byteRange.isSet()) {
|
||||||
QString byteRange;
|
QString byteRange;
|
||||||
if (_byteRange.fromInclusive < 0) {
|
if (_byteRange.fromInclusive < 0) {
|
||||||
auto byteRange = QString("bytes=%1").arg(_byteRange.fromInclusive);
|
byteRange = QString("bytes=%1").arg(_byteRange.fromInclusive);
|
||||||
} else {
|
} else {
|
||||||
auto byteRange = QString("bytes=%1-%2").arg(_byteRange.fromInclusive).arg(_byteRange.toExclusive);
|
byteRange = QString("bytes=%1-%2").arg(_byteRange.fromInclusive).arg(_byteRange.toExclusive);
|
||||||
}
|
}
|
||||||
|
qDebug() << "Setting http range to " << byteRange;
|
||||||
networkRequest.setRawHeader("Range", byteRange.toLatin1());
|
networkRequest.setRawHeader("Range", byteRange.toLatin1());
|
||||||
}
|
}
|
||||||
networkRequest.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
|
networkRequest.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
|
||||||
|
|
Loading…
Reference in a new issue