mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +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().updateMyAvatarPos(getPosition());
|
||||||
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
// DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
||||||
|
|
||||||
AnimPose postUpdateRoomPose(_sensorToWorldMatrix);
|
AnimPose postUpdateRoomPose(_sensorToWorldMatrix);
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,7 @@ public:
|
||||||
uint8 getMinMip() const { return _desc._minMip; }
|
uint8 getMinMip() const { return _desc._minMip; }
|
||||||
uint8 getMaxMip() const { return _desc._maxMip; }
|
uint8 getMaxMip() const { return _desc._maxMip; }
|
||||||
|
|
||||||
|
const Desc& getDesc() const { return _desc; }
|
||||||
protected:
|
protected:
|
||||||
Desc _desc;
|
Desc _desc;
|
||||||
};
|
};
|
||||||
|
@ -516,7 +517,7 @@ public:
|
||||||
|
|
||||||
// Textures can be serialized directly to ktx data file, here is how
|
// Textures can be serialized directly to ktx data file, here is how
|
||||||
static ktx::KTXUniquePointer serialize(const Texture& texture);
|
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 evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header);
|
||||||
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
static bool evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,30 @@ using namespace gpu;
|
||||||
using PixelsPointer = Texture::PixelsPointer;
|
using PixelsPointer = Texture::PixelsPointer;
|
||||||
using KtxStorage = Texture::KtxStorage;
|
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) {
|
KtxStorage::KtxStorage(ktx::KTXUniquePointer& ktxData) {
|
||||||
|
|
||||||
// if the source ktx is valid let's config this KtxStorage correctly
|
// 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
|
#if 0
|
||||||
auto expectedMipCount = texture.evalNumMips();
|
auto expectedMipCount = texture.evalNumMips();
|
||||||
assert(expectedMipCount == ktxBuffer->_images.size());
|
assert(expectedMipCount == ktxBuffer->_images.size());
|
||||||
|
@ -146,7 +177,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
||||||
return ktxBuffer;
|
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) {
|
if (!srcData) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +206,12 @@ Texture* Texture::unserialize(Usage usage, TextureUsageType usageType, const ktx
|
||||||
type = TEX_3D;
|
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,
|
type,
|
||||||
texelFormat,
|
texelFormat,
|
||||||
header.getPixelWidth(),
|
header.getPixelWidth(),
|
||||||
|
@ -183,9 +219,9 @@ Texture* Texture::unserialize(Usage usage, TextureUsageType usageType, const ktx
|
||||||
header.getPixelDepth(),
|
header.getPixelDepth(),
|
||||||
1, // num Samples
|
1, // num Samples
|
||||||
header.getNumberOfSlices(),
|
header.getNumberOfSlices(),
|
||||||
sampler);
|
(isGPUKTXPayload ? gpuktxKeyValue._samplerDesc : sampler));
|
||||||
|
|
||||||
tex->setUsage(usage);
|
tex->setUsage((isGPUKTXPayload ? gpuktxKeyValue._usage : usage));
|
||||||
|
|
||||||
// Assing the mips availables
|
// Assing the mips availables
|
||||||
tex->setStoredMipFormat(mipFormat);
|
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) :
|
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),
|
_key(key),
|
||||||
_value(valueByteSize)
|
_value(valueByteSize)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ uint32_t KeyValue::serializedByteSize() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
|
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
|
||||||
size_t keyValuesSize = 0;
|
uint32_t keyValuesSize = 0;
|
||||||
for (auto& keyval : keyValues) {
|
for (auto& keyval : keyValues) {
|
||||||
keyValuesSize += keyval.serializedByteSize();
|
keyValuesSize += keyval.serializedByteSize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,8 +398,8 @@ namespace ktx {
|
||||||
|
|
||||||
uint32_t serializedByteSize() const;
|
uint32_t serializedByteSize() const;
|
||||||
|
|
||||||
static KeyValue parseKeyAndValue(uint32_t keyAndValueByteSize, const Byte* bytes);
|
static KeyValue parseSerializedKeyAndValue(uint32_t srcSize, const Byte* srcBytes);
|
||||||
static KeyValue parseSerializedKeyAndValue(uint32_t byteSizeAhead, const Byte* bytes);
|
static uint32_t writeSerializedKeyAndValue(Byte* destBytes, uint32_t destByteSize, const KeyValue& keyval);
|
||||||
|
|
||||||
using KeyValues = std::list<KeyValue>;
|
using KeyValues = std::list<KeyValue>;
|
||||||
static uint32_t serializedKeyValuesByteSize(const KeyValues& keyValues);
|
static uint32_t serializedKeyValuesByteSize(const KeyValues& keyValues);
|
||||||
|
|
|
@ -56,55 +56,6 @@ namespace ktx {
|
||||||
return true;
|
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) {
|
bool KTX::checkHeaderFromStorage(size_t srcSize, const Byte* srcBytes) {
|
||||||
try {
|
try {
|
||||||
// validation
|
// 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 KTX::parseImages(const Header& header, size_t srcSize, const Byte* srcBytes) {
|
||||||
Images images;
|
Images images;
|
||||||
auto currentPtr = srcBytes;
|
auto currentPtr = srcBytes;
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
//
|
//
|
||||||
#include "KTX.h"
|
#include "KTX.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#define NOEXCEPT noexcept
|
#define NOEXCEPT noexcept
|
||||||
#else
|
#else
|
||||||
|
@ -70,7 +73,7 @@ namespace ktx {
|
||||||
|
|
||||||
// KeyValues
|
// KeyValues
|
||||||
if (!keyValues.empty()) {
|
if (!keyValues.empty()) {
|
||||||
destHeader->bytesOfKeyValueData = writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
|
destHeader->bytesOfKeyValueData = (uint32_t) writeKeyValues(currentDestPtr, destByteSize - sizeof(Header), keyValues);
|
||||||
} else {
|
} else {
|
||||||
// Make sure the header contains the right bytesOfKeyValueData size
|
// Make sure the header contains the right bytesOfKeyValueData size
|
||||||
destHeader->bytesOfKeyValueData = 0;
|
destHeader->bytesOfKeyValueData = 0;
|
||||||
|
@ -84,9 +87,39 @@ namespace ktx {
|
||||||
return destByteSize;
|
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) {
|
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);
|
fclose (file);
|
||||||
|
|
||||||
//then create a new texture out of the ktx
|
//then create a new texture out of the ktx
|
||||||
auto theNewTexure = Texture::unserialize(srcTexture->getUsage(), srcTexture->getUsageType(),
|
auto theNewTexure = Texture::unserialize(ktx::KTX::create(std::static_pointer_cast<storage::Storage>(storage)),
|
||||||
ktx::KTX::create(std::static_pointer_cast<storage::Storage>(storage)), srcTexture->getSampler());
|
srcTexture->getUsageType(), srcTexture->getUsage(), srcTexture->getSampler().getDesc());
|
||||||
|
|
||||||
if (theNewTexure) {
|
if (theNewTexure) {
|
||||||
returnedTexture = theNewTexure;
|
returnedTexture = theNewTexure;
|
||||||
|
|
Loading…
Reference in a new issue