mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
Fix progressive loading of cubemaps
In various places we were using the KTX _imageSize as the size of the entire mip level, when it is actually the size of the face for cubemaps.
This commit is contained in:
parent
b36fb81524
commit
bfd1274ed3
4 changed files with 25 additions and 18 deletions
|
@ -238,8 +238,9 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
|
|||
throw std::runtime_error("Invalid level");
|
||||
}
|
||||
|
||||
if (storage->size() != _ktxDescriptor->images[level]._imageSize) {
|
||||
qWarning() << "Invalid image size: " << storage->size() << ", expected: " << _ktxDescriptor->images[level]._imageSize
|
||||
auto& imageDesc = _ktxDescriptor->images[level];
|
||||
if (storage->size() != imageDesc._fullImageSize) {
|
||||
qWarning() << "Invalid image size: " << storage->size() << ", expected: " << imageDesc._fullImageSize
|
||||
<< ", level: " << level << ", filename: " << QString::fromStdString(_filename);
|
||||
return;
|
||||
}
|
||||
|
@ -258,7 +259,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
|
|||
return;
|
||||
}
|
||||
|
||||
memcpy(imageData, storage->data(), _ktxDescriptor->images[level]._imageSize);
|
||||
memcpy(imageData, storage->data(), storage->size());
|
||||
_minMipLevelAvailable = level;
|
||||
if (_offsetToMinMipKV > 0) {
|
||||
auto minMipKeyData = file->mutableData() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV;
|
||||
|
|
|
@ -38,15 +38,15 @@ UInt32 numberOfArrayElements
|
|||
UInt32 numberOfFaces
|
||||
UInt32 numberOfMipmapLevels
|
||||
UInt32 bytesOfKeyValueData
|
||||
|
||||
|
||||
for each keyValuePair that fits in bytesOfKeyValueData
|
||||
UInt32 keyAndValueByteSize
|
||||
Byte keyAndValue[keyAndValueByteSize]
|
||||
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
|
||||
end
|
||||
|
||||
|
||||
for each mipmap_level in numberOfMipmapLevels*
|
||||
UInt32 imageSize;
|
||||
UInt32 imageSize;
|
||||
for each array_element in numberOfArrayElements*
|
||||
for each face in numberOfFaces
|
||||
for each z_slice in pixelDepth*
|
||||
|
@ -269,7 +269,7 @@ namespace ktx {
|
|||
COMPRESSED_RG11_EAC = 0x9272,
|
||||
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
|
||||
};
|
||||
|
||||
|
||||
enum class GLBaseInternalFormat : uint32_t {
|
||||
// GL 4.4 Table 8.11
|
||||
DEPTH_COMPONENT = 0x1902,
|
||||
|
@ -419,17 +419,20 @@ namespace ktx {
|
|||
using FaceOffsets = std::vector<size_t>;
|
||||
using FaceBytes = std::vector<const Byte*>;
|
||||
|
||||
const uint32_t _numFaces;
|
||||
// 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 _numFaces;
|
||||
const size_t _imageOffset;
|
||||
const uint32_t _imageSize;
|
||||
// The full size of this image / mip level. This will be equivalent to _imageSize except when _numFaces > 1
|
||||
const uint32_t _fullImageSize;
|
||||
const uint32_t _faceSize;
|
||||
const uint32_t _padding;
|
||||
ImageHeader(bool cube, size_t imageOffset, uint32_t imageSize, uint32_t padding) :
|
||||
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
|
||||
_imageOffset(imageOffset),
|
||||
_imageSize(imageSize * _numFaces),
|
||||
_imageSize(imageSize),
|
||||
_fullImageSize(imageSize * _numFaces),
|
||||
_faceSize(imageSize),
|
||||
_padding(padding) {
|
||||
}
|
||||
|
@ -466,7 +469,7 @@ namespace ktx {
|
|||
|
||||
class KTX;
|
||||
|
||||
// A KTX descriptor is a lightweight container for all the information about a serialized KTX file, but without the
|
||||
// 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) {}
|
||||
|
@ -495,7 +498,7 @@ namespace ktx {
|
|||
// Instead of creating a full Copy of the src data in a KTX object, the write serialization can be performed with the
|
||||
// following two functions
|
||||
// size_t sizeNeeded = KTX::evalStorageSize(header, images);
|
||||
//
|
||||
//
|
||||
// //allocate a buffer of size "sizeNeeded" or map a file with enough capacity
|
||||
// Byte* destBytes = new Byte[sizeNeeded];
|
||||
//
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace ktx {
|
|||
for (uint32_t l = 0; l < numMips; l++) {
|
||||
if (imageDescriptors.size() > l) {
|
||||
storageSize += sizeof(uint32_t);
|
||||
storageSize += imageDescriptors[l]._imageSize;
|
||||
storageSize += imageDescriptors[l]._fullImageSize;
|
||||
storageSize += Header::evalPadding(imageDescriptors[l]._imageSize);
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ namespace ktx {
|
|||
size_t KTX::writeWithoutImages(Byte* destBytes, size_t destByteSize, const Header& header, const ImageDescriptors& descriptors, const KeyValues& keyValues) {
|
||||
// Check again that we have enough destination capacity
|
||||
if (!destBytes || (destByteSize < evalStorageSize(header, descriptors, keyValues))) {
|
||||
qWarning() << "Destination capacity is insufficient to write KTX without images";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -149,13 +150,15 @@ namespace ktx {
|
|||
for (size_t i = 0; i < descriptors.size(); ++i) {
|
||||
auto ptr = reinterpret_cast<uint32_t*>(currentDestPtr);
|
||||
*ptr = descriptors[i]._imageSize;
|
||||
ptr++;
|
||||
|
||||
#ifdef DEBUG
|
||||
ptr++;
|
||||
for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) {
|
||||
*(ptr + k) = 0xFFFFFFFF;
|
||||
}
|
||||
#endif
|
||||
currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t);
|
||||
currentDestPtr += sizeof(uint32_t);
|
||||
currentDestPtr += descriptors[i]._fullImageSize;
|
||||
}
|
||||
|
||||
return destByteSize;
|
||||
|
|
|
@ -648,13 +648,13 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
|
|||
// TODO Move image offset calculation to ktx ImageDescriptor
|
||||
for (int level = static_cast<int>(images.size()) - 1; level >= 0; --level) {
|
||||
auto& image = images[level];
|
||||
if (image._imageSize > imageSizeRemaining) {
|
||||
if (image._fullImageSize > imageSizeRemaining) {
|
||||
break;
|
||||
}
|
||||
ktxData -= image._imageSize;
|
||||
texture->assignStoredMip(static_cast<gpu::uint16>(level), image._imageSize, ktxData);
|
||||
ktxData -= image._fullImageSize;
|
||||
texture->assignStoredMip(static_cast<gpu::uint16>(level), image._fullImageSize, ktxData);
|
||||
ktxData -= ktx::IMAGE_SIZE_WIDTH;
|
||||
imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH);
|
||||
imageSizeRemaining -= (image._fullImageSize + ktx::IMAGE_SIZE_WIDTH);
|
||||
}
|
||||
|
||||
// We replace the texture with the one stored in the cache. This deals with the possible race condition of two different
|
||||
|
|
Loading…
Reference in a new issue