Implement the ktx keyvalue feature for read and write and use it with gpu::Texture to store meat data required for full serialization

This commit is contained in:
sam 2017-03-07 00:58:22 -08:00
parent c267b5cd09
commit 1b036b7225
8 changed files with 131 additions and 66 deletions

View file

@ -1617,8 +1617,8 @@ void MyAvatar::postUpdate(float deltaTime) {
}
}
DebugDraw::getInstance().updateMyAvatarPos(getPosition());
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
// DebugDraw::getInstance().updateMyAvatarPos(getPosition());
// DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
AnimPose postUpdateRoomPose(_sensorToWorldMatrix);

View file

@ -143,6 +143,7 @@ public:
uint8 getMinMip() const { return _desc._minMip; }
uint8 getMaxMip() const { return _desc._maxMip; }
const Desc& getDesc() const { return _desc; }
protected:
Desc _desc;
};
@ -516,7 +517,7 @@ public:
// Textures can be serialized directly to ktx data file, here is how
static ktx::KTXUniquePointer serialize(const Texture& texture);
static Texture* unserialize(Usage usage, TextureUsageType usageType, const ktx::KTXUniquePointer& srcData, const Sampler& sampler = Sampler());
static Texture* unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType = TextureUsageType::RESOURCE, Usage usage = Usage(), const Sampler::Desc& sampler = Sampler::Desc());
static bool evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);

View file

@ -18,6 +18,30 @@ using namespace gpu;
using PixelsPointer = Texture::PixelsPointer;
using KtxStorage = Texture::KtxStorage;
struct GPUKTXPayload {
Sampler::Desc _samplerDesc;
Texture::Usage _usage;
TextureUsageType _usageType;
static std::string KEY;
static bool isGPUKTX(const ktx::KeyValue& val) {
return (val._key.compare(KEY) == 0);
}
static bool findInKeyValues(const ktx::KeyValues& keyValues, GPUKTXPayload& payload) {
auto found = std::find_if(keyValues.begin(), keyValues.end(), isGPUKTX);
if (found != keyValues.end()) {
if ((*found)._value.size() == sizeof(GPUKTXPayload)) {
memcpy(&payload, (*found)._value.data(), sizeof(GPUKTXPayload));
return true;
}
}
return false;
}
};
std::string GPUKTXPayload::KEY { "hifi.gpu" };
KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) {
// if the source ktx is valid let's config this KtxStorage correctly
@ -116,7 +140,14 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
}
}
auto ktxBuffer = ktx::KTX::create(header, images);
GPUKTXPayload keyval;
keyval._samplerDesc = texture.getSampler().getDesc();
keyval._usage = texture.getUsage();
keyval._usageType = texture.getUsageType();
ktx::KeyValues keyValues;
keyValues.emplace_back(ktx::KeyValue(GPUKTXPayload::KEY, sizeof(GPUKTXPayload), (ktx::Byte*) &keyval));
auto ktxBuffer = ktx::KTX::create(header, images, keyValues);
#if 0
auto expectedMipCount = texture.evalNumMips();
assert(expectedMipCount == ktxBuffer->_images.size());
@ -146,7 +177,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
return ktxBuffer;
}
Texture* Texture::unserialize(Usage usage, TextureUsageType usageType, const ktx::KTXUniquePointer& srcData, const Sampler& sampler) {
Texture* Texture::unserialize(const ktx::KTXUniquePointer& srcData, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) {
if (!srcData) {
return nullptr;
}
@ -175,7 +206,12 @@ Texture* Texture::unserialize(Usage usage, TextureUsageType usageType, const ktx
type = TEX_3D;
}
auto tex = Texture::create( usageType,
// If found, use the
GPUKTXPayload gpuktxKeyValue;
bool isGPUKTXPayload = GPUKTXPayload::findInKeyValues(srcData->_keyValues, gpuktxKeyValue);
auto tex = Texture::create( (isGPUKTXPayload ? gpuktxKeyValue._usageType : usageType),
type,
texelFormat,
header.getPixelWidth(),
@ -183,9 +219,9 @@ Texture* Texture::unserialize(Usage usage, TextureUsageType usageType, const ktx
header.getPixelDepth(),
1, // num Samples
header.getNumberOfSlices(),
sampler);
(isGPUKTXPayload ? gpuktxKeyValue._samplerDesc : sampler));
tex->setUsage(usage);
tex->setUsage((isGPUKTXPayload ? gpuktxKeyValue._usage : usage));
// Assing the mips availables
tex->setStoredMipFormat(mipFormat);

View file

@ -72,7 +72,7 @@ size_t Header::evalImageSize(uint32_t level) const {
KeyValue::KeyValue(const std::string& key, uint32_t valueByteSize, const Byte* value) :
_byteSize((uint32_t) key.size() + valueByteSize),
_byteSize((uint32_t) key.size() + 1 + valueByteSize), // keyString size + '\0' ending char + the value size
_key(key),
_value(valueByteSize)
{
@ -92,7 +92,7 @@ uint32_t KeyValue::serializedByteSize() const {
}
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
size_t keyValuesSize = 0;
uint32_t keyValuesSize = 0;
for (auto& keyval : keyValues) {
keyValuesSize += keyval.serializedByteSize();
}

View file

@ -398,8 +398,8 @@ namespace ktx {
uint32_t serializedByteSize() const;
static KeyValue parseKeyAndValue(uint32_t keyAndValueByteSize, const Byte* bytes);
static KeyValue parseSerializedKeyAndValue(uint32_t byteSizeAhead, const Byte* bytes);
static KeyValue parseSerializedKeyAndValue(uint32_t srcSize, const Byte* srcBytes);
static uint32_t writeSerializedKeyAndValue(Byte* destBytes, uint32_t destByteSize, const KeyValue& keyval);
using KeyValues = std::list<KeyValue>;
static uint32_t serializedKeyValuesByteSize(const KeyValues& keyValues);

View file

@ -56,55 +56,6 @@ namespace ktx {
return true;
}
KeyValue KeyValue::parseKeyAndValue(uint32_t keyAndValueByteSize, const Byte* bytes) {
// find the first null character \0
uint32_t keyLength = 0;
while (reinterpret_cast<const char*>(bytes[++keyLength]) != '\0') {
if (keyLength == keyAndValueByteSize) {
// key must be null-terminated, and there must be space for the value
throw ReaderException("invalid key-value " + std::string(reinterpret_cast<const char*>(bytes), keyLength));
}
}
return KeyValue(std::string(reinterpret_cast<const char*>(bytes), keyLength), keyAndValueByteSize - keyLength, bytes + keyLength);
}
static KeyValue parseSerializedKeyAndValue(uint32_t byteSizeAhead, const Byte* bytes) {
uint32_t keyValueByteSize;
memcpy(&keyValueByteSize, bytes, sizeof(uint32_t));
if (keyValueByteSize > byteSizeAhead) {
throw ReaderException("invalid key-value size");
}
auto keyValueBytes = bytes + sizeof(uint32_t);
// parse the key-value
return KeyValue::parseKeyAndValue(keyValueByteSize, keyValueBytes);
}
static KeyValues parseKeyValues(size_t srcSize, const Byte* srcBytes);
KeyValues KTX::parseKeyValues(size_t srcSize, const Byte* src) {
KeyValues keyValues;
try {
uint32_t length = (uint32_t) srcSize;
uint32_t offset = 0;
while (offset < length) {
auto keyValue = parseSerializedKeyAndValue(length - offset, src);
keyValues.emplace_back(keyValue);
// advance offset/src
offset += keyValue.serializedByteSize();
src += keyValue.serializedByteSize();
}
}
catch (const ReaderException& e) {
qWarning() << e.what();
}
return keyValues;
}
bool KTX::checkHeaderFromStorage(size_t srcSize, const Byte* srcBytes) {
try {
// validation
@ -140,6 +91,50 @@ namespace ktx {
}
}
KeyValue KeyValue::parseSerializedKeyAndValue(uint32_t srcSize, const Byte* srcBytes) {
uint32_t keyAndValueByteSize;
memcpy(&keyAndValueByteSize, srcBytes, sizeof(uint32_t));
if (keyAndValueByteSize + sizeof(uint32_t) > srcSize) {
throw ReaderException("invalid key-value size");
}
auto keyValueBytes = srcBytes + sizeof(uint32_t);
// find the first null character \0 and extract the key
uint32_t keyLength = 0;
while (reinterpret_cast<const char*>(keyValueBytes[++keyLength]) != '\0') {
if (keyLength == keyAndValueByteSize) {
// key must be null-terminated, and there must be space for the value
throw ReaderException("invalid key-value " + std::string(reinterpret_cast<const char*>(keyValueBytes), keyLength));
}
}
uint32_t valueStartOffset = keyLength + 1;
// parse the key-value
return KeyValue(std::string(reinterpret_cast<const char*>(keyValueBytes), keyLength),
keyAndValueByteSize - valueStartOffset, keyValueBytes + valueStartOffset);
}
KeyValues KTX::parseKeyValues(size_t srcSize, const Byte* srcBytes) {
KeyValues keyValues;
try {
auto src = srcBytes;
uint32_t length = (uint32_t) srcSize;
uint32_t offset = 0;
while (offset < length) {
auto keyValue = KeyValue::parseSerializedKeyAndValue(length - offset, src);
keyValues.emplace_back(keyValue);
// advance offset/src
offset += keyValue.serializedByteSize();
src += keyValue.serializedByteSize();
}
}
catch (const ReaderException& e) {
qWarning() << e.what();
}
return keyValues;
}
Images KTX::parseImages(const Header& header, size_t srcSize, const Byte* srcBytes) {
Images images;
auto currentPtr = srcBytes;

View file

@ -10,6 +10,9 @@
//
#include "KTX.h"
#include <QtGlobal>
#include <QtCore/QDebug>
#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
@ -70,7 +73,7 @@ namespace ktx {
// KeyValues
if (!keyValues.empty()) {
destHeader->bytesOfKeyValueData = writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
destHeader->bytesOfKeyValueData = (uint32_t) writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
} else {
// Make sure the header contains the right bytesOfKeyValueData size
destHeader->bytesOfKeyValueData = 0;
@ -84,9 +87,39 @@ namespace ktx {
return destByteSize;
}
static size_t writeKeyValues(Byte* destBytes, size_t destByteSize, const KeyValues& keyValues) {
uint32_t KeyValue::writeSerializedKeyAndValue(Byte* destBytes, uint32_t destByteSize, const KeyValue& keyval) {
uint32_t keyvalSize = keyval.serializedByteSize();
if (keyvalSize > destByteSize) {
throw WriterException("invalid key-value size");
}
*((uint32_t*) destBytes) = keyval._byteSize;
auto dest = destBytes + sizeof(uint32_t);
auto keySize = keyval._key.size() + 1; // Add 1 for the '\0' character at the end of the string
memcpy(dest, keyval._key.data(), keySize);
dest += keySize;
memcpy(dest, keyval._value.data(), keyval._value.size());
return keyvalSize;
}
size_t KTX::writeKeyValues(Byte* destBytes, size_t destByteSize, const KeyValues& keyValues) {
size_t writtenByteSize = 0;
try {
auto dest = destBytes;
for (auto& keyval : keyValues) {
size_t keyvalSize = KeyValue::writeSerializedKeyAndValue(dest, (uint32_t) (destByteSize - writtenByteSize), keyval);
writtenByteSize += keyvalSize;
dest += keyvalSize;
}
}
catch (const WriterException& e) {
qWarning() << e.what();
}
return writtenByteSize;
}
Images KTX::writeImages(Byte* destBytes, size_t destByteSize, const Images& srcImages) {

View file

@ -145,8 +145,8 @@ gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bo
fclose (file);
//then create a new texture out of the ktx
auto theNewTexure = Texture::unserialize(srcTexture->getUsage(), srcTexture->getUsageType(),
ktx::KTX::create(std::static_pointer_cast<storage::Storage>(storage)), srcTexture->getSampler());
auto theNewTexure = Texture::unserialize(ktx::KTX::create(std::static_pointer_cast<storage::Storage>(storage)),
srcTexture->getUsageType(), srcTexture->getUsage(), srcTexture->getSampler().getDesc());
if (theNewTexure) {
returnedTexture = theNewTexure;