Merge pull request #10470 from huffman/fix/ktx-cubemaps

Fix progressive loading of KTX cubemaps
This commit is contained in:
Andrew Meadows 2017-05-17 11:23:24 -07:00 committed by GitHub
commit 82c7188376
4 changed files with 25 additions and 14 deletions

View file

@ -238,8 +238,9 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
throw std::runtime_error("Invalid level"); throw std::runtime_error("Invalid level");
} }
if (storage->size() != _ktxDescriptor->images[level]._imageSize) { auto& imageDesc = _ktxDescriptor->images[level];
qWarning() << "Invalid image size: " << storage->size() << ", expected: " << _ktxDescriptor->images[level]._imageSize if (storage->size() != imageDesc._imageSize) {
qWarning() << "Invalid image size: " << storage->size() << ", expected: " << imageDesc._imageSize
<< ", level: " << level << ", filename: " << QString::fromStdString(_filename); << ", level: " << level << ", filename: " << QString::fromStdString(_filename);
return; return;
} }
@ -258,7 +259,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor
return; return;
} }
memcpy(imageData, storage->data(), _ktxDescriptor->images[level]._imageSize); memcpy(imageData, storage->data(), storage->size());
_minMipLevelAvailable = level; _minMipLevelAvailable = level;
if (_offsetToMinMipKV > 0) { if (_offsetToMinMipKV > 0) {
auto minMipKeyData = file->mutableData() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; auto minMipKeyData = file->mutableData() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV;

View file

@ -38,15 +38,15 @@ UInt32 numberOfArrayElements
UInt32 numberOfFaces UInt32 numberOfFaces
UInt32 numberOfMipmapLevels UInt32 numberOfMipmapLevels
UInt32 bytesOfKeyValueData UInt32 bytesOfKeyValueData
for each keyValuePair that fits in bytesOfKeyValueData for each keyValuePair that fits in bytesOfKeyValueData
UInt32 keyAndValueByteSize UInt32 keyAndValueByteSize
Byte keyAndValue[keyAndValueByteSize] Byte keyAndValue[keyAndValueByteSize]
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)] Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
end end
for each mipmap_level in numberOfMipmapLevels* for each mipmap_level in numberOfMipmapLevels*
UInt32 imageSize; UInt32 imageSize;
for each array_element in numberOfArrayElements* for each array_element in numberOfArrayElements*
for each face in numberOfFaces for each face in numberOfFaces
for each z_slice in pixelDepth* for each z_slice in pixelDepth*
@ -269,7 +269,7 @@ namespace ktx {
COMPRESSED_RG11_EAC = 0x9272, COMPRESSED_RG11_EAC = 0x9272,
COMPRESSED_SIGNED_RG11_EAC = 0x9273, COMPRESSED_SIGNED_RG11_EAC = 0x9273,
}; };
enum class GLBaseInternalFormat : uint32_t { enum class GLBaseInternalFormat : uint32_t {
// GL 4.4 Table 8.11 // GL 4.4 Table 8.11
DEPTH_COMPONENT = 0x1902, DEPTH_COMPONENT = 0x1902,
@ -419,9 +419,9 @@ namespace ktx {
using FaceOffsets = std::vector<size_t>; using FaceOffsets = std::vector<size_t>;
using FaceBytes = std::vector<const Byte*>; 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 // 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 _numFaces;
const size_t _imageOffset; const size_t _imageOffset;
const uint32_t _imageSize; const uint32_t _imageSize;
const uint32_t _faceSize; const uint32_t _faceSize;
@ -466,7 +466,7 @@ namespace ktx {
class 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. // actual image / face data available.
struct KTXDescriptor { struct KTXDescriptor {
KTXDescriptor(const Header& header, const KeyValues& keyValues, const ImageDescriptors& imageDescriptors) : header(header), keyValues(keyValues), images(imageDescriptors) {} KTXDescriptor(const Header& header, const KeyValues& keyValues, const ImageDescriptors& imageDescriptors) : header(header), keyValues(keyValues), images(imageDescriptors) {}
@ -495,7 +495,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 // 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 // following two functions
// size_t sizeNeeded = KTX::evalStorageSize(header, images); // size_t sizeNeeded = KTX::evalStorageSize(header, images);
// //
// //allocate a buffer of size "sizeNeeded" or map a file with enough capacity // //allocate a buffer of size "sizeNeeded" or map a file with enough capacity
// Byte* destBytes = new Byte[sizeNeeded]; // Byte* destBytes = new Byte[sizeNeeded];
// //

View file

@ -127,6 +127,7 @@ namespace ktx {
size_t KTX::writeWithoutImages(Byte* destBytes, size_t destByteSize, const Header& header, const ImageDescriptors& descriptors, const KeyValues& keyValues) { 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 // Check again that we have enough destination capacity
if (!destBytes || (destByteSize < evalStorageSize(header, descriptors, keyValues))) { if (!destBytes || (destByteSize < evalStorageSize(header, descriptors, keyValues))) {
qWarning() << "Destination capacity is insufficient to write KTX without images";
return 0; return 0;
} }
@ -149,13 +150,15 @@ namespace ktx {
for (size_t i = 0; i < descriptors.size(); ++i) { for (size_t i = 0; i < descriptors.size(); ++i) {
auto ptr = reinterpret_cast<uint32_t*>(currentDestPtr); auto ptr = reinterpret_cast<uint32_t*>(currentDestPtr);
*ptr = descriptors[i]._imageSize; *ptr = descriptors[i]._imageSize;
ptr++;
#ifdef DEBUG #ifdef DEBUG
ptr++;
for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) { for (size_t k = 0; k < descriptors[i]._imageSize/4; k++) {
*(ptr + k) = 0xFFFFFFFF; *(ptr + k) = 0xFFFFFFFF;
} }
#endif #endif
currentDestPtr += descriptors[i]._imageSize + sizeof(uint32_t); currentDestPtr += sizeof(uint32_t);
currentDestPtr += descriptors[i]._imageSize;
} }
return destByteSize; return destByteSize;

View file

@ -501,12 +501,19 @@ void NetworkTexture::ktxMipRequestFinished() {
if (texture) { if (texture) {
texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, texture->assignStoredMip(_ktxMipLevelRangeInFlight.first,
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data())); _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
_lowestKnownPopulatedMip = _textureSource->getGPUTexture()->minAvailableMipLevel();
if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) {
_lowestKnownPopulatedMip = texture->minAvailableMipLevel();
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
} else {
qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first;
_ktxResourceState = FAILED_TO_LOAD;
}
} else { } else {
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
qWarning(networking) << "Trying to update mips but texture is null"; qWarning(networking) << "Trying to update mips but texture is null";
} }
finishedLoading(true); finishedLoading(true);
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
} else { } else {
finishedLoading(false); finishedLoading(false);
if (handleFailedRequest(_ktxMipRequest->getResult())) { if (handleFailedRequest(_ktxMipRequest->getResult())) {