mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 07:13:57 +02:00
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:
parent
c267b5cd09
commit
1b036b7225
8 changed files with 131 additions and 66 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue