From 57649811d7813c2a407479baa818b1305f116be3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 27 Sep 2019 09:17:48 +1200 Subject: [PATCH 01/12] Update JSDoc of TabletProxy internal functions --- .../ui/src/ui/TabletScriptingInterface.h | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index bae5eda29e..f09be33d2b 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -293,29 +293,38 @@ public: Q_INVOKABLE void loadQMLSource(const QVariant& path, bool resizable = false); /**jsdoc - * Internal function, do not call from scripts * @function TabletProxy#loadQMLSourceImpl + * @deprecated This function is deprecated and will be removed. */ + // Internal function, do not call from scripts. Q_INVOKABLE void loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext); - /**jsdoc - * Internal function, do not call from scripts + /**jsdoc * @function TabletProxy#loadHTMLSourceImpl + * @deprecated This function is deprecated and will be removed. */ + // Internal function, do not call from scripts. Q_INVOKABLE void loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext); - /**jsdoc - * Internal function, do not call from scripts + /**jsdoc * @function TabletProxy#loadHTMLSourceImpl + * @deprecated This function is deprecated and will be removed. */ + // Internal function, do not call from scripts. Q_INVOKABLE void loadHTMLSourceImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext); - /**jsdoc - * Internal function, do not call from scripts + /**jsdoc * @function TabletProxy#returnToPreviousAppImpl + * @deprecated This function is deprecated and will be removed. */ + // Internal function, do not call from scripts. Q_INVOKABLE void returnToPreviousAppImpl(bool localSafeContext); + /**jsdoc + *@function TabletProxy#loadQMLOnTopImpl + * @deprecated This function is deprecated and will be removed. + */ + // Internal function, do not call from scripts. Q_INVOKABLE void loadQMLOnTopImpl(const QVariant& path, bool localSafeContext); // FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success); From e9d138a96159c60e59544fb2fdd0c9539c31dd30 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 28 Sep 2019 09:29:27 +1200 Subject: [PATCH 02/12] Rename internal function to distinguish signatures and reflect function --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 9 +++------ libraries/ui/src/ui/TabletScriptingInterface.h | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 75b08ba44f..ff2bc5c894 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -869,16 +869,14 @@ void TabletProxy::loadHTMLSourceImpl(const QVariant& url, const QString& injectJ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase) { bool localSafeContext = hifi::scripting::isLocalAccessSafeThread(); if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadHTMLSourceImpl", Q_ARG(QString, url), Q_ARG(QString, injectedJavaScriptUrl), Q_ARG(bool, loadOtherBase), Q_ARG(bool, localSafeContext)); + QMetaObject::invokeMethod(this, "loadHTMLSourceOnTopImpl", Q_ARG(QString, url), Q_ARG(QString, injectedJavaScriptUrl), Q_ARG(bool, loadOtherBase), Q_ARG(bool, localSafeContext)); return; } - - loadHTMLSourceImpl(url, injectedJavaScriptUrl, loadOtherBase, localSafeContext); + loadHTMLSourceOnTopImpl(url, injectedJavaScriptUrl, loadOtherBase, localSafeContext); } -void TabletProxy::loadHTMLSourceImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext) { - +void TabletProxy::loadHTMLSourceOnTopImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext) { QObject* root = nullptr; if (!_toolbarMode && _qmlTabletRoot) { root = _qmlTabletRoot; @@ -911,7 +909,6 @@ void TabletProxy::loadHTMLSourceImpl(const QString& url, const QString& injected _initialWebPathParams.first = injectedJavaScriptUrl; _initialWebPathParams.second = loadOtherBase; _initialScreen = true; - } } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index f09be33d2b..96804a00e8 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -307,11 +307,11 @@ public: Q_INVOKABLE void loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext); /**jsdoc - * @function TabletProxy#loadHTMLSourceImpl + * @function TabletProxy#loadHTMLSourceOnTopImpl * @deprecated This function is deprecated and will be removed. */ // Internal function, do not call from scripts. - Q_INVOKABLE void loadHTMLSourceImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext); + Q_INVOKABLE void loadHTMLSourceOnTopImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext); /**jsdoc * @function TabletProxy#returnToPreviousAppImpl From 2e2d3df26fe14bdec41130fc970395875046aa51 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 28 Sep 2019 09:38:19 +1200 Subject: [PATCH 03/12] Fix loadWebScreenOnTop() --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index ff2bc5c894..7528d766b9 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -827,11 +827,11 @@ void TabletProxy::loadWebScreenOnTop(const QVariant& url) { void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJavaScriptUrl) { bool localSafeContext = hifi::scripting::isLocalAccessSafeThread(); if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "loadHTMLSourceImpl", Q_ARG(QVariant, url), Q_ARG(QString, injectJavaScriptUrl), Q_ARG(bool, localSafeContext)); + QMetaObject::invokeMethod(this, "loadHTMLSourceOnTopImpl", Q_ARG(QString, url.toString()), Q_ARG(QString, injectJavaScriptUrl), Q_ARG(bool, false), Q_ARG(bool, localSafeContext)); return; } - loadHTMLSourceImpl(url, injectJavaScriptUrl, localSafeContext); + loadHTMLSourceOnTopImpl(url.toString(), injectJavaScriptUrl, false, localSafeContext); } From bbf6d3f59571c26bbd89c5d6cde2afc793870d5b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 28 Sep 2019 10:19:00 +1200 Subject: [PATCH 04/12] Remove unused code --- .../ui/src/ui/TabletScriptingInterface.cpp | 32 ------------------- .../ui/src/ui/TabletScriptingInterface.h | 7 ---- 2 files changed, 39 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 7528d766b9..ac4b9edd51 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -834,38 +834,6 @@ void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJ loadHTMLSourceOnTopImpl(url.toString(), injectJavaScriptUrl, false, localSafeContext); } - - -void TabletProxy::loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext) { - if (QThread::currentThread() != thread()) { - qCWarning(uiLogging) << __FUNCTION__ << "may not be called directly by scripts"; - return; - - } - - - QObject* root = nullptr; - if (!_toolbarMode && _qmlTabletRoot) { - root = _qmlTabletRoot; - } else if (_toolbarMode && _desktopWindow) { - root = _desktopWindow->asQuickItem(); - } - - if (root) { - if (localSafeContext) { - hifi::scripting::setLocalAccessSafeThread(true); - } - QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL))); - QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); - if (_toolbarMode && _desktopWindow) { - QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false))); - } - QMetaObject::invokeMethod(root, "loadWebOnTop", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectJavaScriptUrl))); - hifi::scripting::setLocalAccessSafeThread(false); - } - _state = State::Web; -} - void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase) { bool localSafeContext = hifi::scripting::isLocalAccessSafeThread(); if (QThread::currentThread() != thread()) { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 96804a00e8..8c66a3ee1d 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -299,13 +299,6 @@ public: // Internal function, do not call from scripts. Q_INVOKABLE void loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext); - /**jsdoc - * @function TabletProxy#loadHTMLSourceImpl - * @deprecated This function is deprecated and will be removed. - */ - // Internal function, do not call from scripts. - Q_INVOKABLE void loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext); - /**jsdoc * @function TabletProxy#loadHTMLSourceOnTopImpl * @deprecated This function is deprecated and will be removed. From c79581e93fd880e13722ea38535383674d4c60fa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 28 Sep 2019 10:19:29 +1200 Subject: [PATCH 05/12] Update JSDoc --- libraries/ui/src/ui/TabletScriptingInterface.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 8c66a3ee1d..dbd64cec4a 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -273,7 +273,9 @@ public: Q_INVOKABLE void gotoHomeScreen(); /**jsdoc - * Opens a web page or app on the tablet. + * Opens a web app or page in addition to any current app. In tablet mode, the app or page is displayed over the top of the + * current app; in toolbar mode, the app is opened in a new window that replaces any current window open. If in tablet + * mode, the app or page can be closed using {@link TabletProxy#returnToPreviousApp}. * @function TabletProxy#gotoWebScreen * @param {string} url - The URL of the web page or app. * @param {string} [injectedJavaScriptUrl=""] - The URL of JavaScript to inject into the web page. @@ -356,8 +358,8 @@ public: /**jsdoc * Opens a web app or page in addition to any current app. In tablet mode, the app or page is displayed over the top of the - * current app; in toolbar mode, the app is opened in a new window. If in tablet mode, the app or page can be closed using - * {@link TabletProxy#returnToPreviousApp}. + * current app; in toolbar mode, the app is opened in a new window that replaces any current window open. If in tablet + * mode, the app or page can be closed using {@link TabletProxy#returnToPreviousApp}. * @function TabletProxy#loadWebScreenOnTop * @param {string} path - The URL of the web page or HTML app. * @param {string} [injectedJavaScriptURL=""] - The URL of JavaScript to inject into the web page. From 3b9884c76f82fd5510c626d9714e36d00604a211 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 28 Sep 2019 11:42:25 +1200 Subject: [PATCH 06/12] Fix build warning --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index ac4b9edd51..040bb750d0 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -330,7 +330,6 @@ QObject* TabletScriptingInterface::getFlags() { // static const char* TABLET_HOME_SOURCE_URL = "hifi/tablet/TabletHome.qml"; -static const char* WEB_VIEW_SOURCE_URL = "hifi/tablet/TabletWebView.qml"; static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml"; class TabletRootWindow : public QmlWindowClass { From 3c6e98f16b8c73e2f42b9ab5bb7992e2480a7513 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 08:34:06 -0700 Subject: [PATCH 07/12] New format for captured GPU frames --- interface/src/Application.cpp | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 9 +- libraries/gpu/src/gpu/FrameIO.cpp | 129 ++++++++++ libraries/gpu/src/gpu/FrameIO.h | 52 +++- libraries/gpu/src/gpu/FrameIOKeys.h | 238 +++++++++--------- libraries/gpu/src/gpu/FrameReader.cpp | 213 ++++++---------- libraries/gpu/src/gpu/FrameWriter.cpp | 70 ++---- tools/CMakeLists.txt | 40 ++- tools/gpu-frame-converter/CMakeLists.txt | 9 + tools/gpu-frame-converter/src/main.cpp | 104 ++++++++ tools/gpu-frame-player/src/PlayerWindow.cpp | 10 +- tools/gpu-frame-player/src/PlayerWindow.h | 2 +- 12 files changed, 538 insertions(+), 340 deletions(-) create mode 100644 libraries/gpu/src/gpu/FrameIO.cpp create mode 100644 tools/gpu-frame-converter/CMakeLists.txt create mode 100644 tools/gpu-frame-converter/src/main.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b4a37519a6..c9b976cc14 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4441,7 +4441,7 @@ void Application::keyPressEvent(QKeyEvent* event) { static const QString GPU_FRAME_FOLDER = QProcessEnvironment::systemEnvironment().contains(HIFI_FRAMES_FOLDER_VAR) ? QProcessEnvironment::systemEnvironment().value(HIFI_FRAMES_FOLDER_VAR) : "hifiFrames"; - static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}"; + static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}.hfb"; QString fullPath = FileUtils::computeDocumentPath(FileUtils::replaceDateTimeTokens(GPU_FRAME_TEMPLATE)); if (FileUtils::canCreateFile(fullPath)) { getActiveDisplayPlugin()->captureFrame(fullPath.toStdString()); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 74d36101db..e69791e73d 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -480,7 +481,7 @@ void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const { using namespace gpu; auto glBackend = const_cast(*this).getGLBackend(); FramebufferPointer framebuffer{ Framebuffer::create("captureFramebuffer") }; - TextureCapturer captureLambda = [&](const std::string& filename, const gpu::TexturePointer& texture, uint16 layer) { + TextureCapturer captureLambda = [&](std::vector& outputBuffer, const gpu::TexturePointer& texture, uint16 layer) { QImage image; if (texture->getUsageType() == TextureUsageType::STRICT_RESOURCE) { image = QImage{ 1, 1, QImage::Format_ARGB32 }; @@ -498,7 +499,11 @@ void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const { image = QImage{ rect.z, rect.w, QImage::Format_ARGB32 }; glBackend->downloadFramebuffer(framebuffer, rect, image); } - QImageWriter(filename.c_str()).write(image); + QBuffer buffer; + QImageWriter(&buffer, "png").write(image); + const auto& data = buffer.data(); + outputBuffer.resize(data.size()); + memcpy(outputBuffer.data(), data.constData(), data.size()); }; if (_currentFrame) { diff --git a/libraries/gpu/src/gpu/FrameIO.cpp b/libraries/gpu/src/gpu/FrameIO.cpp new file mode 100644 index 0000000000..568ef335ba --- /dev/null +++ b/libraries/gpu/src/gpu/FrameIO.cpp @@ -0,0 +1,129 @@ +// +// Created by Bradley Austin Davis on 2019/10/03 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "FrameIO.h" +#include + +using namespace gpu::hfb; + +static bool skip(const uint8_t*& ptr, size_t& remaining, uint32_t size) { + if (remaining < size) { + return false; + } + ptr += size; + remaining -= size; + return true; +} + +template +static bool read(const uint8_t*& ptr, size_t& remaining, T& output) { + uint32_t readSize = (uint32_t)sizeof(T); + if (remaining < readSize) { + return false; + } + memcpy(&output, ptr, readSize); + return skip(ptr, remaining, readSize); +} + +Descriptor Descriptor::parse(const uint8_t* const data, size_t size) { + const auto* ptr = data; + auto remaining = size; + Descriptor result; + if (!read(ptr, remaining, result.header)) { + return {}; + } + if (!result.header.length == size) { + return {}; + } + + while (remaining != 0) { + result.chunks.emplace_back(); + auto& chunk = result.chunks.back(); + ChunkHeader& chunkHeader = chunk; + if (!read(ptr, remaining, chunkHeader)) { + return {}; + } + chunk.offset = ptr - data; + if (!skip(ptr, remaining, chunk.length)) { + return {}; + } + } + return result; +} + +size_t Chunk::end() const { + size_t result = offset; + result += length; + return result; +} + + +bool Descriptor::getChunkString(std::string& output, size_t chunkIndex, const uint8_t* const data, size_t size) { + if (chunkIndex >= chunks.size()) { + return false; + } + const auto& chunk = chunks[chunkIndex]; + if (chunk.end() > size) { + return false; + } + output = std::string{ (const char*)(data + chunk.offset), chunk.length }; + return true; +} + +bool Descriptor::getChunkBuffer(Buffer& output, size_t chunkIndex, const uint8_t* const data, size_t size) { + if (chunkIndex >= chunks.size()) { + return false; + } + const auto& chunk = chunks[chunkIndex]; + if (chunk.end() > size) { + return false; + } + output.resize(chunk.length); + memcpy(output.data(), data + chunk.offset, chunk.length); + return true; +} + +static void writeUint(uint8_t*& dest, uint32_t value) { + memcpy(dest, &value, sizeof(uint32_t)); + dest += sizeof(uint32_t); +} + +template +static void writeChunk(uint8_t*& dest, uint32_t chunkType, const T& chunkData) { + uint32_t chunkSize = static_cast(chunkData.size()); + writeUint(dest, chunkSize); + writeUint(dest, chunkType); + memcpy(dest, chunkData.data(), chunkSize); + dest += chunkSize; +} + +void gpu::hfb::writeFrame(const std::string& filename, + const std::string& json, + const Buffer& binaryBuffer, + const Buffers& pngBuffers) { + uint32_t strLen = (uint32_t)json.size(); + uint32_t size = gpu::hfb::HEADER_SIZE + gpu::hfb::CHUNK_HEADER_SIZE + strLen; + size += gpu::hfb::CHUNK_HEADER_SIZE + (uint32_t)binaryBuffer.size(); + for (const auto& pngBuffer : pngBuffers) { + size += gpu::hfb::CHUNK_HEADER_SIZE + (uint32_t)pngBuffer.size(); + } + + auto outputConst = storage::FileStorage::create(filename.c_str(), size, nullptr); + auto output = std::const_pointer_cast(outputConst); + auto ptr = output->mutableData(); + writeUint(ptr, gpu::hfb::MAGIC); + writeUint(ptr, gpu::hfb::VERSION); + writeUint(ptr, size); + writeChunk(ptr, gpu::hfb::CHUNK_TYPE_JSON, json); + writeChunk(ptr, gpu::hfb::CHUNK_TYPE_BIN, binaryBuffer); + for (const auto& png : pngBuffers) { + writeChunk(ptr, gpu::hfb::CHUNK_TYPE_PNG, png); + } + auto writeSize = ptr - output->data(); + assert(writeSize == size); +} diff --git a/libraries/gpu/src/gpu/FrameIO.h b/libraries/gpu/src/gpu/FrameIO.h index 4de4cf5fe7..e53d64f22f 100644 --- a/libraries/gpu/src/gpu/FrameIO.h +++ b/libraries/gpu/src/gpu/FrameIO.h @@ -16,13 +16,57 @@ namespace gpu { -using TextureCapturer = std::function; -using TextureLoader = std::function; +using TextureCapturer = std::function&, const TexturePointer&, uint16 layer)>; +using TextureLoader = std::function&, const TexturePointer&, uint16 layer)>; void writeFrame(const std::string& filename, const FramePointer& frame, const TextureCapturer& capturer = nullptr); FramePointer readFrame(const std::string& filename, uint32_t externalTexture, const TextureLoader& loader = nullptr); -using IndexOptimizer = std::function; -void optimizeFrame(const std::string& filename, const IndexOptimizer& optimizer); +namespace hfb { + +constexpr char* EXTENSION{ ".hfb" }; +constexpr uint32_t HEADER_SIZE{ sizeof(uint32_t) * 3 }; +constexpr uint32_t CHUNK_HEADER_SIZE = sizeof(uint32_t) * 2; +constexpr uint32_t MAGIC{ 0x49464948 }; +constexpr uint32_t VERSION{ 0x01 }; +constexpr uint32_t CHUNK_TYPE_JSON{ 0x4E4F534A }; +constexpr uint32_t CHUNK_TYPE_BIN{ 0x004E4942 }; +constexpr uint32_t CHUNK_TYPE_PNG{ 0x00474E50 }; + +using Buffer = std::vector; +using Buffers = std::vector; + +struct Header { + uint32_t magic{ 0 }; + uint32_t version{ 0 }; + uint32_t length{ 0 }; +}; + +struct ChunkHeader { + uint32_t length{ 0 }; + uint32_t type{ 0 }; +}; + +struct Chunk : public ChunkHeader { + uint32_t offset{ 0 }; + + size_t end() const; +}; + +using Chunks = std::vector; + +struct Descriptor { + Header header; + Chunks chunks; + + operator bool() const { return header.magic == MAGIC; } + bool getChunkString(std::string& output, size_t chunk, const uint8_t* const data, size_t size); + bool getChunkBuffer(Buffer& output, size_t chunk, const uint8_t* const data, size_t size); + static Descriptor parse(const uint8_t* const data, size_t size); +}; + +void writeFrame(const std::string& filename, const std::string& json, const Buffer& binaryBuffer, const Buffers& pngBuffers); + +} // namespace hfb } // namespace gpu diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 5d5f8a5bd9..14f7646d4f 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -11,128 +11,130 @@ namespace gpu { namespace keys { -static const char* binary = "binary"; -static const char* L00 = "L00"; -static const char* L1m1 = "L1m1"; -static const char* L10 = "L10"; -static const char* L11 = "L11"; -static const char* L2m2 = "L2m2"; -static const char* L2m1 = "L2m1"; -static const char* L20 = "L20"; -static const char* L21 = "L21"; -static const char* L22 = "L22"; -static const char* eyeProjections = "eyeProjections"; -static const char* eyeViews = "eyeViews"; -static const char* alphaToCoverageEnable = "alphaToCoverageEnable"; -static const char* antialisedLineEnable = "antialisedLineEnable"; -static const char* attributes = "attributes"; -static const char* batches = "batches"; -static const char* blendFunction = "blendFunction"; -static const char* borderColor = "borderColor"; -static const char* bufferMask = "bufferMask"; -static const char* buffers = "buffers"; -static const char* capturedTextures = "capturedTextures"; -static const char* channel = "channel"; -static const char* colorAttachments = "colorAttachments"; -static const char* colorWriteMask = "colorWriteMask"; -static const char* commands = "commands"; -static const char* comparisonFunction = "comparisonFunction"; -static const char* cullMode = "cullMode"; -static const char* data = "data"; -static const char* depth = "depth"; -static const char* depthBias = "depthBias"; -static const char* depthBiasSlopeScale = "depthBiasSlopeScale"; -static const char* depthClampEnable = "depthClampEnable"; -static const char* depthStencilAttachment = "depthStencilAttachment"; -static const char* depthTest = "depthTest"; -static const char* drawCallInfos = "drawCallInfos"; -static const char* drawcallUniform = "drawcallUniform"; -static const char* drawcallUniformReset = "drawcallUniformReset"; -static const char* element = "element"; -static const char* fillMode = "fillMode"; -static const char* filter = "filter"; -static const char* formats = "formats"; -static const char* frameIndex = "frameIndex"; -static const char* framebuffer = "framebuffer"; -static const char* framebuffers = "framebuffers"; -static const char* frequency = "frequency"; -static const char* frontFaceClockwise = "frontFaceClockwise"; -static const char* height = "height"; -static const char* id = "id"; -static const char* ktxFile = "ktxFile"; -static const char* layers = "layers"; -static const char* maxAnisotropy = "maxAnisotropy"; -static const char* maxMip = "maxMip"; -static const char* minMip = "minMip"; -static const char* mipOffset = "mipOffset"; -static const char* mips = "mips"; -static const char* multisampleEnable = "multisampleEnable"; -static const char* name = "name"; -static const char* namedData = "namedData"; -static const char* names = "names"; -static const char* objects = "objects"; -static const char* offset = "offset"; -static const char* pipelines = "pipelines"; -static const char* pose = "pose"; -static const char* profileRanges = "profileRanges"; -static const char* program = "program"; -static const char* programs = "programs"; -static const char* projectionJitter = "projectionJitter"; -static const char* queries = "queries"; -static const char* sampleCount = "sampleCount"; -static const char* sampleMask = "sampleMask"; -static const char* sampler = "sampler"; -static const char* samples = "samples"; -static const char* scissorEnable = "scissorEnable"; -static const char* shaders = "shaders"; -static const char* size = "size"; -static const char* skybox = "skybox"; -static const char* slot = "slot"; -static const char* source = "source"; -static const char* state = "state"; -static const char* stencilActivation = "stencilActivation"; -static const char* stencilTestBack = "stencilTestBack"; -static const char* stencilTestFront = "stencilTestFront"; -static const char* stereo = "stereo"; -static const char* subresource = "subresource"; -static const char* swapchains = "swapchains"; -static const char* texelFormat = "texelFormat"; -static const char* texture = "texture"; -static const char* textureTables = "textureTables"; -static const char* textures = "textures"; -static const char* transforms = "transforms"; -static const char* type = "type"; -static const char* usageType = "usageType"; -static const char* view = "view"; -static const char* width = "width"; -static const char* wrapModeU = "wrapModeU"; -static const char* wrapModeV = "wrapModeV"; -static const char* wrapModeW = "wrapModeW"; +constexpr char* binary = "binary"; +constexpr char* L00 = "L00"; +constexpr char* L1m1 = "L1m1"; +constexpr char* L10 = "L10"; +constexpr char* L11 = "L11"; +constexpr char* L2m2 = "L2m2"; +constexpr char* L2m1 = "L2m1"; +constexpr char* L20 = "L20"; +constexpr char* L21 = "L21"; +constexpr char* L22 = "L22"; + +constexpr char* eyeProjections = "eyeProjections"; +constexpr char* eyeViews = "eyeViews"; +constexpr char* alphaToCoverageEnable = "alphaToCoverageEnable"; +constexpr char* antialisedLineEnable = "antialisedLineEnable"; +constexpr char* attributes = "attributes"; +constexpr char* batches = "batches"; +constexpr char* blendFunction = "blendFunction"; +constexpr char* borderColor = "borderColor"; +constexpr char* bufferMask = "bufferMask"; +constexpr char* buffers = "buffers"; +constexpr char* capturedTextures = "capturedTextures"; +constexpr char* channel = "channel"; +constexpr char* chunk = "chunk"; +constexpr char* colorAttachments = "colorAttachments"; +constexpr char* colorWriteMask = "colorWriteMask"; +constexpr char* commands = "commands"; +constexpr char* comparisonFunction = "comparisonFunction"; +constexpr char* cullMode = "cullMode"; +constexpr char* data = "data"; +constexpr char* depth = "depth"; +constexpr char* depthBias = "depthBias"; +constexpr char* depthBiasSlopeScale = "depthBiasSlopeScale"; +constexpr char* depthClampEnable = "depthClampEnable"; +constexpr char* depthStencilAttachment = "depthStencilAttachment"; +constexpr char* depthTest = "depthTest"; +constexpr char* drawCallInfos = "drawCallInfos"; +constexpr char* drawcallUniform = "drawcallUniform"; +constexpr char* drawcallUniformReset = "drawcallUniformReset"; +constexpr char* element = "element"; +constexpr char* fillMode = "fillMode"; +constexpr char* filter = "filter"; +constexpr char* formats = "formats"; +constexpr char* frameIndex = "frameIndex"; +constexpr char* framebuffer = "framebuffer"; +constexpr char* framebuffers = "framebuffers"; +constexpr char* frequency = "frequency"; +constexpr char* frontFaceClockwise = "frontFaceClockwise"; +constexpr char* height = "height"; +constexpr char* id = "id"; +constexpr char* ktxFile = "ktxFile"; +constexpr char* layers = "layers"; +constexpr char* maxAnisotropy = "maxAnisotropy"; +constexpr char* maxMip = "maxMip"; +constexpr char* minMip = "minMip"; +constexpr char* mipOffset = "mipOffset"; +constexpr char* mips = "mips"; +constexpr char* multisampleEnable = "multisampleEnable"; +constexpr char* name = "name"; +constexpr char* namedData = "namedData"; +constexpr char* names = "names"; +constexpr char* objects = "objects"; +constexpr char* offset = "offset"; +constexpr char* pipelines = "pipelines"; +constexpr char* pose = "pose"; +constexpr char* profileRanges = "profileRanges"; +constexpr char* program = "program"; +constexpr char* programs = "programs"; +constexpr char* projectionJitter = "projectionJitter"; +constexpr char* queries = "queries"; +constexpr char* sampleCount = "sampleCount"; +constexpr char* sampleMask = "sampleMask"; +constexpr char* sampler = "sampler"; +constexpr char* samples = "samples"; +constexpr char* scissorEnable = "scissorEnable"; +constexpr char* shaders = "shaders"; +constexpr char* size = "size"; +constexpr char* skybox = "skybox"; +constexpr char* slot = "slot"; +constexpr char* source = "source"; +constexpr char* state = "state"; +constexpr char* stencilActivation = "stencilActivation"; +constexpr char* stencilTestBack = "stencilTestBack"; +constexpr char* stencilTestFront = "stencilTestFront"; +constexpr char* stereo = "stereo"; +constexpr char* subresource = "subresource"; +constexpr char* swapchains = "swapchains"; +constexpr char* texelFormat = "texelFormat"; +constexpr char* texture = "texture"; +constexpr char* textureTables = "textureTables"; +constexpr char* textures = "textures"; +constexpr char* transforms = "transforms"; +constexpr char* type = "type"; +constexpr char* usageType = "usageType"; +constexpr char* view = "view"; +constexpr char* width = "width"; +constexpr char* wrapModeU = "wrapModeU"; +constexpr char* wrapModeV = "wrapModeV"; +constexpr char* wrapModeW = "wrapModeW"; -static const char* backWriteMask = "backWriteMask"; -static const char* frontWriteMask = "frontWriteMask"; -static const char* reference = "reference"; -static const char* readMask = "readMask"; -static const char* failOp = "failOp"; -static const char* depthFailOp = "depthFailOp"; -static const char* passOp = "passOp"; -static const char* enabled = "enabled"; -static const char* blend = "blend"; -static const char* flags = "flags"; -static const char* writeMask = "writeMask"; -static const char* function = "function"; -static const char* sourceColor = "sourceColor"; -static const char* sourceAlpha = "sourceAlpha"; -static const char* destColor = "destColor"; -static const char* destAlpha = "destAlpha"; -static const char* opColor = "opColor"; -static const char* opAlpha = "opAlpha"; -static const char* enable = "enable"; -static const char* contextDisable = "contextDisable"; +constexpr char* backWriteMask = "backWriteMask"; +constexpr char* frontWriteMask = "frontWriteMask"; +constexpr char* reference = "reference"; +constexpr char* readMask = "readMask"; +constexpr char* failOp = "failOp"; +constexpr char* depthFailOp = "depthFailOp"; +constexpr char* passOp = "passOp"; +constexpr char* enabled = "enabled"; +constexpr char* blend = "blend"; +constexpr char* flags = "flags"; +constexpr char* writeMask = "writeMask"; +constexpr char* function = "function"; +constexpr char* sourceColor = "sourceColor"; +constexpr char* sourceAlpha = "sourceAlpha"; +constexpr char* destColor = "destColor"; +constexpr char* destAlpha = "destAlpha"; +constexpr char* opColor = "opColor"; +constexpr char* opAlpha = "opAlpha"; +constexpr char* enable = "enable"; +constexpr char* contextDisable = "contextDisable"; -static const char* COMMAND_NAMES[] = { +constexpr char* COMMAND_NAMES[] = { "draw", "drawIndexed", "drawInstanced", diff --git a/libraries/gpu/src/gpu/FrameReader.cpp b/libraries/gpu/src/gpu/FrameReader.cpp index 740ec2b26f..1f94828119 100644 --- a/libraries/gpu/src/gpu/FrameReader.cpp +++ b/libraries/gpu/src/gpu/FrameReader.cpp @@ -22,17 +22,11 @@ namespace gpu { using json = nlohmann::json; +using StoragePointer = storage::StoragePointer; +using FileStorage = storage::FileStorage; class Deserializer { public: - static std::string getBaseName(const std::string& filename) { - static const std::string ext{ ".json" }; - if (std::string::npos != filename.rfind(ext)) { - return filename.substr(0, filename.size() - ext.size()); - } - return filename; - } - static std::string getBaseDir(const std::string& filename) { std::string result; if (0 == filename.find("assets:")) { @@ -47,14 +41,17 @@ public: return result; } - Deserializer(const std::string& filename, uint32_t externalTexture, const TextureLoader& loader) : - basename(getBaseName(filename)), basedir(getBaseDir(filename)), externalTexture(externalTexture), textureLoader(loader) { + Deserializer(const std::string& filename_, uint32_t externalTexture = 0, const TextureLoader& loader = {}) : + filename(filename_), basedir(getBaseDir(filename_)), mappedFile(std::make_shared(filename.c_str())), + externalTexture(externalTexture), textureLoader(loader) { + descriptor = hfb::Descriptor::parse(mappedFile->data(), (uint32_t)mappedFile->size()); } - const std::string basename; + const std::string filename; const std::string basedir; - std::string binaryFile; + const StoragePointer mappedFile; const uint32_t externalTexture; + hfb::Descriptor descriptor; TextureLoader textureLoader; std::vector shaders; std::vector programs; @@ -69,10 +66,24 @@ public: std::vector queries; json frameNode; FramePointer readFrame(); - void optimizeFrame(const IndexOptimizer& optimizer); FramePointer deserializeFrame(); + std::string getStringChunk(size_t chunkIndex) { + std::string result; + if (!descriptor.getChunkString(result, chunkIndex, mappedFile->data(), mappedFile->size())) { + return {}; + } + return result; + } + + hfb::Buffer getBufferChunk(size_t chunkIndex) { + hfb::Buffer result; + if (!descriptor.getChunkBuffer(result, chunkIndex, mappedFile->data(), mappedFile->size())) { + return {}; + } + return result; + } void readBuffers(const json& node); @@ -148,12 +159,11 @@ public: } template - static bool readBatchCacheTransformed(typename Batch::Cache::Vector& dest, - const json& node, - const std::string& name, - std::function f = [](const json& node) -> TT { - return node.get(); - }) { + static bool readBatchCacheTransformed( + typename Batch::Cache::Vector& dest, + const json& node, + const std::string& name, + std::function f = [](const json& node) -> TT { return node.get(); }) { if (node.count(name)) { const auto& arrayNode = node[name]; for (const auto& entry : arrayNode) { @@ -234,18 +244,14 @@ FramePointer readFrame(const std::string& filename, uint32_t externalTexture, co return Deserializer(filename, externalTexture, loader).readFrame(); } -void optimizeFrame(const std::string& filename, const IndexOptimizer& optimizer) { - return Deserializer(filename, 0, {}).optimizeFrame(optimizer); -} - } // namespace gpu using namespace gpu; void Deserializer::readBuffers(const json& buffersNode) { - storage::FileStorage mappedFile(binaryFile.c_str()); - const auto mappedSize = mappedFile.size(); - const auto* mapped = mappedFile.data(); + const auto& binaryChunk = descriptor.chunks[1]; + const auto* mapped = mappedFile->data() + binaryChunk.offset; + const auto mappedSize = binaryChunk.length; size_t bufferCount = buffersNode.size(); buffers.reserve(buffersNode.size()); size_t offset = 0; @@ -311,6 +317,8 @@ Sampler Deserializer::readSampler(const json& node) { return result; } +constexpr uint32_t INVALID_CHUNK_INDEX{ (uint32_t)-1 }; + TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { if (node.is_null()) { return nullptr; @@ -319,8 +327,17 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { std::string source; readOptional(source, node, keys::source); + uint32_t chunkIndex = INVALID_CHUNK_INDEX; + readOptional(chunkIndex, node, keys::chunk); + std::string ktxFile; readOptional(ktxFile, node, keys::ktxFile); + if (!ktxFile.empty()) { + if (!QFileInfo(ktxFile.c_str()).exists()) { + qDebug() << "Warning" << ktxFile.c_str() << " not found, ignoring"; + ktxFile = {}; + } + } Element ktxTexelFormat, ktxMipFormat; if (!ktxFile.empty()) { // If we get a texture that starts with ":" we need to re-route it to the resources directory @@ -368,8 +385,15 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { if (QFileInfo(ktxFile.c_str()).isRelative()) { ktxFile = basedir + "/" + ktxFile; } + texture.setSource(ktxFile); texture.setKtxBacking(ktxFile); + } else if (chunkIndex != INVALID_CHUNK_INDEX) { + if (textureLoader) { + texture.setSource("Chunk " + std::to_string(chunkIndex)); + textureLoader(getBufferChunk(chunkIndex), result, 0); + } } + return result; } @@ -405,11 +429,11 @@ ShaderPointer Deserializer::readShader(const json& node) { // FIXME support procedural shaders Shader::Type type = node[keys::type]; std::string name = node[keys::name]; - // Using the serialized ID is bad, because it's generated at - // cmake time, and can change across platforms or when + // Using the serialized ID is bad, because it's generated at + // cmake time, and can change across platforms or when // shaders are added or removed // uint32_t id = node[keys::id]; - + uint32_t id = shadersIdsByName[name]; ShaderPointer result; switch (type) { @@ -555,11 +579,15 @@ StatePointer readState(const json& node) { State::Data data; Deserializer::readOptionalTransformed(data.flags, node, keys::flags, &readStateFlags); - Deserializer::readOptionalTransformed(data.blendFunction, node, keys::blendFunction, &readBlendFunction); + Deserializer::readOptionalTransformed(data.blendFunction, node, keys::blendFunction, + &readBlendFunction); Deserializer::readOptionalTransformed(data.depthTest, node, keys::depthTest, &readDepthTest); - Deserializer::readOptionalTransformed(data.stencilActivation, node, keys::stencilActivation, &readStencilActivation); - Deserializer::readOptionalTransformed(data.stencilTestFront, node, keys::stencilTestFront, &readStencilTest); - Deserializer::readOptionalTransformed(data.stencilTestBack, node, keys::stencilTestBack, &readStencilTest); + Deserializer::readOptionalTransformed(data.stencilActivation, node, keys::stencilActivation, + &readStencilActivation); + Deserializer::readOptionalTransformed(data.stencilTestFront, node, keys::stencilTestFront, + &readStencilTest); + Deserializer::readOptionalTransformed(data.stencilTestBack, node, keys::stencilTestBack, + &readStencilTest); Deserializer::readOptional(data.colorWriteMask, node, keys::colorWriteMask); Deserializer::readOptional(data.cullMode, node, keys::cullMode); Deserializer::readOptional(data.depthBias, node, keys::depthBias); @@ -799,25 +827,15 @@ StereoState readStereoState(const json& node) { FramePointer Deserializer::deserializeFrame() { - { - std::string filename{ basename + ".json" }; - storage::FileStorage mappedFile(filename.c_str()); - frameNode = json::parse(std::string((const char*)mappedFile.data(), mappedFile.size())); + if (!descriptor.operator bool()) { + return {}; } + frameNode = json::parse(getStringChunk(0)); + FramePointer result = std::make_shared(); auto& frame = *result; - if (frameNode[keys::binary].is_string()) { - binaryFile = frameNode[keys::binary]; - if (QFileInfo(binaryFile.c_str()).isRelative()) { - binaryFile = basedir + "/" + binaryFile; - } - } else { - binaryFile = basename + ".bin"; - } - - if (frameNode.count(keys::buffers)) { readBuffers(frameNode[keys::buffers]); } @@ -830,19 +848,7 @@ FramePointer Deserializer::deserializeFrame() { formats = readArray(frameNode, keys::formats, [](const json& node) { return readFormat(node); }); - auto textureReader = [this](const json& node) { return readTexture(node, externalTexture); }; - textures = readArray(frameNode, keys::textures, textureReader); - if (textureLoader) { - std::vector capturedTextures = readNumericVector(frameNode[keys::capturedTextures]); - for (const auto& index : capturedTextures) { - const auto& texturePointer = textures[index]; - uint16 layers = std::max(texturePointer->getNumSlices(), 1); - for (uint16 layer = 0; layer < layers; ++layer) { - std::string filename = basename + "." + std::to_string(index) + "." + std::to_string(layer) + ".png"; - textureLoader(filename, texturePointer, layer); - } - } - } + textures = readArray(frameNode, keys::textures, [this](const json& node) { return readTexture(node, externalTexture); }); // Must come after textures auto textureTableReader = [this](const json& node) { return readTextureTable(node); }; @@ -868,87 +874,22 @@ FramePointer Deserializer::deserializeFrame() { } } + for (uint32_t i = 0; i < textures.size(); ++i) { + const auto& texturePtr = textures[i]; + if (!texturePtr) { + continue; + } + const auto& texture = *texturePtr; + if (texture.getUsageType() == gpu::TextureUsageType::RESOURCE && texture.source().empty()) { + qDebug() << "Empty source "; + } + } + return result; } - - FramePointer Deserializer::readFrame() { auto result = deserializeFrame(); result->finish(); return result; } - -void Deserializer::optimizeFrame(const IndexOptimizer& optimizer) { - auto result = deserializeFrame(); - auto& frame = *result; - - - // optimize the index buffers? - struct CurrentIndexBuffer { - Offset offset{ 0 }; - BufferPointer buffer; - Type type{ gpu::Type::INT32 }; - Primitive primitve{ Primitive::TRIANGLES }; - uint32_t numIndices{ 0 }; - uint32_t startIndex{ 0 }; - }; - - std::vector captured; - for (auto& batch : frame.batches) { - - CurrentIndexBuffer currentIndexBuffer; - batch->forEachCommand([&](Batch::Command cmd, const Batch::Param* params){ - switch(cmd) { - case Batch::Command::COMMAND_setIndexBuffer: - currentIndexBuffer.offset = params[0]._size; - currentIndexBuffer.buffer = batch->_buffers.get(params[1]._int); - currentIndexBuffer.type = (Type)params[2]._int; - break; - - case Batch::Command::COMMAND_drawIndexed: - currentIndexBuffer.startIndex = params[0]._int; - currentIndexBuffer.numIndices = params[1]._int; - currentIndexBuffer.primitve = (Primitive)params[2]._int; - captured.emplace_back(currentIndexBuffer); - break; - - case Batch::Command::COMMAND_drawIndexedInstanced: - currentIndexBuffer.startIndex = params[1]._int; - currentIndexBuffer.numIndices = params[2]._int; - currentIndexBuffer.primitve = (Primitive)params[3]._int; - captured.emplace_back(currentIndexBuffer); - break; - - default: - break; - } - }); - } - - - std::string optimizedBinaryFile = basename + "_optimized.bin"; - QFile(binaryFile.c_str()).copy(optimizedBinaryFile.c_str()); - { - storage::FileStorage mappedFile(optimizedBinaryFile.c_str()); - std::set uniqueBuffers; - for (const auto& capturedIndexData : captured) { - if (uniqueBuffers.count(capturedIndexData.buffer)) { - continue; - } - uniqueBuffers.insert(capturedIndexData.buffer); - auto bufferOffset = bufferOffsets[capturedIndexData.buffer]; - auto& buffer = *capturedIndexData.buffer; - const auto& count = capturedIndexData.numIndices; - auto indices = (uint32_t*)buffer.editData(); - optimizer(capturedIndexData.primitve, count / 3, count, indices); - memcpy(mappedFile.mutableData() + bufferOffset, indices, sizeof(uint32_t) * count); - } - } - frameNode[keys::binary] = optimizedBinaryFile; - { - std::string frameJson = frameNode.dump(); - std::string filename = basename + "_optimized.json"; - storage::FileStorage::create(filename.c_str(), frameJson.size(), (const uint8_t*)frameJson.data()); - } -} diff --git a/libraries/gpu/src/gpu/FrameWriter.cpp b/libraries/gpu/src/gpu/FrameWriter.cpp index f348827385..85397f149a 100644 --- a/libraries/gpu/src/gpu/FrameWriter.cpp +++ b/libraries/gpu/src/gpu/FrameWriter.cpp @@ -20,7 +20,7 @@ using json = nlohmann::json; class Serializer { public: - const std::string basename; + const std::string filename; const TextureCapturer textureCapturer; std::unordered_map shaderMap; std::unordered_map programMap; @@ -32,8 +32,11 @@ public: std::unordered_map framebufferMap; std::unordered_map swapchainMap; std::unordered_map queryMap; + std::unordered_set captureTextures; + hfb::Buffer binaryBuffer; + hfb::Buffers pngBuffers; - Serializer(const std::string& basename, const TextureCapturer& capturer) : basename(basename), textureCapturer(capturer) {} + Serializer(const std::string& basename, const TextureCapturer& capturer) : filename(basename + hfb::EXTENSION), textureCapturer(capturer) {} template static uint32_t getGlobalIndex(const T& value, std::unordered_map& map) { @@ -129,7 +132,7 @@ public: json writeProgram(const ShaderPointer& program); json writeNamedBatchData(const Batch::NamedBatchData& namedData); - json writeCapturableTextures(const Frame& frame); + void findCapturableTextures(const Frame& frame); void writeBinaryBlob(); static std::string toBase64(const std::vector& v); static json writeIrradiance(const SHPointer& irradiance); @@ -146,7 +149,7 @@ public: static json writeTransform(const Transform& t) { return writeMat4(t.getMatrix()); } static json writeCommand(size_t index, const Batch& batch); static json writeSampler(const Sampler& sampler); - static json writeTexture(const TexturePointer& texture); + json writeTexture(const TexturePointer& texture); static json writeFormat(const Stream::FormatPointer& format); static json writeQuery(const QueryPointer& query); static json writeShader(const ShaderPointer& shader); @@ -390,8 +393,12 @@ json Serializer::writeTexture(const TexturePointer& texturePointer) { const auto* ktxStorage = dynamic_cast(storage); if (ktxStorage) { result[keys::ktxFile] = ktxStorage->_filename; - } else { - // TODO serialize the backing storage + } else if (textureCapturer && captureTextures.count(texturePointer) != 0) { + auto layers = std::max(texture.getNumSlices(), 1); + result[keys::chunk] = 2 + pngBuffers.size(); + pngBuffers.push_back({}); + hfb::Buffer& pngBuffer = pngBuffers.back(); + textureCapturer(pngBuffer, texturePointer, 0); } } return result; @@ -673,14 +680,8 @@ json Serializer::writeQuery(const QueryPointer& queryPointer) { return result; } -json Serializer::writeCapturableTextures(const Frame& frame) { - if (!textureCapturer) { - return json::array(); - } - +void Serializer::findCapturableTextures(const Frame& frame) { std::unordered_set writtenRenderbuffers; - std::unordered_set captureTextures; - auto maybeCaptureTexture = [&](const TexturePointer& texture) { // Not a valid texture if (!texture) { @@ -755,20 +756,6 @@ json Serializer::writeCapturableTextures(const Frame& frame) { } } } - - json result = json::array(); - for (const auto& texture : captureTextures) { - if (textureCapturer) { - auto index = textureMap[texture]; - auto layers = std::max(texture->getNumSlices(), 1); - for (uint16 layer = 0; layer < layers; ++layer) { - std::string textureFilename = basename + "." + std::to_string(index) + "." + std::to_string(layer) + ".png"; - textureCapturer(textureFilename, texture, layer); - } - result.push_back(index); - } - } - return result; } void Serializer::writeFrame(const Frame& frame) { @@ -780,7 +767,7 @@ void Serializer::writeFrame(const Frame& frame) { } frameNode[keys::stereo] = writeStereoState(frame.stereoState); - frameNode[keys::capturedTextures] = writeCapturableTextures(frame); + findCapturableTextures(frame); frameNode[keys::frameIndex] = frame.frameIndex; frameNode[keys::view] = writeMat4(frame.view); frameNode[keys::pose] = writeMat4(frame.pose); @@ -797,35 +784,21 @@ void Serializer::writeFrame(const Frame& frame) { // Serialize textures and buffers last, since the maps they use can be populated by some of the above code // Serialize textures - serializeMap(frameNode, keys::textures, textureMap, writeTexture); + serializeMap(frameNode, keys::textures, textureMap, std::bind(&Serializer::writeTexture, this, _1)); // Serialize buffers serializeMap(frameNode, keys::buffers, bufferMap, writeBuffer); - { - std::string frameJson = frameNode.dump(); - std::string filename = basename + ".json"; - storage::FileStorage::create(filename.c_str(), frameJson.size(), (const uint8_t*)frameJson.data()); - } - writeBinaryBlob(); - frameNode[keys::binary] = basename + ".bin"; + + hfb::writeFrame(filename, frameNode.dump(), binaryBuffer, pngBuffers); } void Serializer::writeBinaryBlob() { const auto buffers = mapToVector(bufferMap); auto accumulator = [](size_t total, const BufferPointer& buffer) { return total + (buffer ? buffer->getSize() : 0); }; size_t totalSize = std::accumulate(buffers.begin(), buffers.end(), (size_t)0, accumulator); - - const auto blobFilename = basename + ".bin"; - QFile file(blobFilename.c_str()); - if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) { - throw std::runtime_error("Unable to open file for writing"); - } - if (!file.resize(totalSize)) { - throw std::runtime_error("Unable to resize file"); - } - - auto mapped = file.map(0, totalSize); + binaryBuffer.resize(totalSize); + auto mapped = binaryBuffer.data(); size_t offset = 0; for (const auto& bufferPointer : buffers) { @@ -838,7 +811,4 @@ void Serializer::writeBinaryBlob() { memcpy(mapped + offset, bufferData, bufferSize); offset += bufferSize; } - if (!file.unmap(mapped)) { - throw std::runtime_error("Unable to unmap file"); - } } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index fd74786a5e..f961a19503 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -19,34 +19,24 @@ function(check_test name) endfunction() if (BUILD_TOOLS) + set(ALL_TOOLS + udt-test + vhacd-util + frame-optimizer + gpu-frame-player + gpu-frame-converter + ice-client + ktx-tool + ac-client + skeleton-dump + atp-client + oven + ) + # Allow different tools for stable builds if (STABLE_BUILD) - set(ALL_TOOLS - udt-test - vhacd-util - frame-optimizer - gpu-frame-player - ice-client - ktx-tool - ac-client - skeleton-dump - atp-client - oven - ) else() - set(ALL_TOOLS - udt-test - vhacd-util - frame-optimizer - gpu-frame-player - ice-client - ktx-tool - ac-client - skeleton-dump - atp-client - oven - nitpick - ) + list(APPEND ALL_TOOLS nitpick) endif() foreach(TOOL ${ALL_TOOLS}) diff --git a/tools/gpu-frame-converter/CMakeLists.txt b/tools/gpu-frame-converter/CMakeLists.txt new file mode 100644 index 0000000000..d28a41c278 --- /dev/null +++ b/tools/gpu-frame-converter/CMakeLists.txt @@ -0,0 +1,9 @@ + +set(TARGET_NAME gpu-frame-converter) +setup_memory_debugger() +setup_hifi_project() +set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) +# link in the shared libraries +link_hifi_libraries( shared gpu shaders ) + +package_libraries_for_deployment() diff --git a/tools/gpu-frame-converter/src/main.cpp b/tools/gpu-frame-converter/src/main.cpp new file mode 100644 index 0000000000..15aeafffb5 --- /dev/null +++ b/tools/gpu-frame-converter/src/main.cpp @@ -0,0 +1,104 @@ +// +// Created by Bradley Austin Davis on 2019/10/03 +// Copyright 2013-2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace fs = std::filesystem; +using Json = nlohmann::json; +using Paths = std::vector; + +const char* DEFAULT_SOURCE_PATH{ "D:/Frames" }; +static const std::string OLD_FRAME_EXTENSION{ ".json" }; +static const std::string OLD_BINARY_EXTENSION{ ".bin" }; +static const std::string NEW_EXTENSION{ gpu::hfb::EXTENSION }; + +inline std::string readFileToString(const fs::path& path) { + std::ifstream file(path); + return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); +} + +inline gpu::hfb::Buffer readFile(const fs::path& path) { + std::ifstream file(path, std::ios::binary | std::ios::ate); + size_t size = file.tellg(); + if (!size) { + return {}; + } + file.seekg(0, std::ios::beg); + + gpu::hfb::Buffer result; + result.resize(size); + if (!file.read((char*)result.data(), size)) { + throw std::runtime_error("Failed to read file"); + } + return result; +} + +Paths getFrames(const std::string& sourcePath) { + Paths result; + for (auto& p : fs::directory_iterator(sourcePath)) { + if (!p.is_regular_file()) { + continue; + } + const auto& path = p.path(); + if (path.string().find(".hfb.json") != std::string::npos) { + continue; + } + if (path.extension().string() == OLD_FRAME_EXTENSION) { + result.push_back(path); + } + } + return result; +} + +void convertFrame(const fs::path& path) { + auto name = path.filename().string(); + name = name.substr(0, name.length() - OLD_FRAME_EXTENSION.length()); + + auto frameNode = Json::parse(readFileToString(path)); + auto capturedTexturesNode = frameNode[gpu::keys::capturedTextures]; + + gpu::hfb::Buffer binary = readFile(path.parent_path() / (name + OLD_BINARY_EXTENSION)); + gpu::hfb::Buffers pngs; + for (const auto& capturedTextureIndexNode : capturedTexturesNode) { + int index = capturedTextureIndexNode; + auto imageFile = path.parent_path() / (name + "." + std::to_string(index) + ".0.png"); + frameNode[gpu::keys::textures][index][gpu::keys::chunk] = 2 + pngs.size(); + pngs.push_back(readFile(imageFile)); + } + frameNode.erase(gpu::keys::capturedTextures); + auto outputPath = path.parent_path() / (name + NEW_EXTENSION); + { + auto jsonOutputPath = path.parent_path() / (name + ".hfb.json"); + std::ofstream of(jsonOutputPath); + auto str = frameNode.dump(2); + of.write(str.data(), str.size()); + } + gpu::hfb::writeFrame(outputPath.string(), frameNode.dump(), binary, pngs); + { + auto frameBuffer = readFile(outputPath.string()); + auto descriptor = gpu::hfb::Descriptor::parse(frameBuffer.data(), frameBuffer.size()); + std::cout << descriptor.header.magic << std::endl; + } +} + +int main(int argc, char** argv) { + for (const auto& framePath : getFrames(DEFAULT_SOURCE_PATH)) { + std::cout << framePath << std::endl; + convertFrame(framePath); + } + return 0; +} diff --git a/tools/gpu-frame-player/src/PlayerWindow.cpp b/tools/gpu-frame-player/src/PlayerWindow.cpp index e74caddd5e..db8d8e0f4d 100644 --- a/tools/gpu-frame-player/src/PlayerWindow.cpp +++ b/tools/gpu-frame-player/src/PlayerWindow.cpp @@ -8,6 +8,8 @@ #include "PlayerWindow.h" +#include +#include #include #include #include @@ -55,7 +57,7 @@ void PlayerWindow::loadFrame() { } } - QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), openDir, tr("GPU Frames (*.json)")); + QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open File"), openDir, tr("GPU Frames (*.hfb)")); if (fileName.isNull()) { return; } @@ -104,9 +106,11 @@ void PlayerWindow::resizeEvent(QResizeEvent* ev) { _renderThread.resize(ev->size()); } -void PlayerWindow::textureLoader(const std::string& filename, const gpu::TexturePointer& texture, uint16_t layer) { +void PlayerWindow::textureLoader(const std::vector& imageBytes, const gpu::TexturePointer& texture, uint16_t layer) { QImage image; - QImageReader(filename.c_str()).read(&image); + QByteArray bytes{ (const char*)imageBytes.data(), (int)imageBytes.size() }; + QBuffer bytesBuffer(&bytes); + QImageReader(&bytesBuffer).read(&image); if (layer > 0) { return; } diff --git a/tools/gpu-frame-player/src/PlayerWindow.h b/tools/gpu-frame-player/src/PlayerWindow.h index 4dfbca0855..a519fd9339 100644 --- a/tools/gpu-frame-player/src/PlayerWindow.h +++ b/tools/gpu-frame-player/src/PlayerWindow.h @@ -28,7 +28,7 @@ protected: void loadFrame(const QString& path); private: - static void textureLoader(const std::string& filename, const gpu::TexturePointer& texture, uint16_t layer); + static void textureLoader(const std::vector& filename, const gpu::TexturePointer& texture, uint16_t layer); QSettings _settings; RenderThread _renderThread; }; From cc1be648509b3709d1d19dcec13578dd63ea1360 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 09:20:02 -0700 Subject: [PATCH 08/12] Fixing build issues --- libraries/gpu/src/gpu/FrameIO.cpp | 5 +- libraries/gpu/src/gpu/FrameIO.h | 2 +- libraries/gpu/src/gpu/FrameIOKeys.h | 238 +++++++++++------------ tools/CMakeLists.txt | 1 - tools/frame-optimizer/CMakeLists.txt | 6 - tools/frame-optimizer/src/main.cpp | 39 ---- tools/gpu-frame-converter/CMakeLists.txt | 16 +- 7 files changed, 130 insertions(+), 177 deletions(-) delete mode 100644 tools/frame-optimizer/CMakeLists.txt delete mode 100644 tools/frame-optimizer/src/main.cpp diff --git a/libraries/gpu/src/gpu/FrameIO.cpp b/libraries/gpu/src/gpu/FrameIO.cpp index 568ef335ba..12e07b6e2a 100644 --- a/libraries/gpu/src/gpu/FrameIO.cpp +++ b/libraries/gpu/src/gpu/FrameIO.cpp @@ -37,7 +37,7 @@ Descriptor Descriptor::parse(const uint8_t* const data, size_t size) { if (!read(ptr, remaining, result.header)) { return {}; } - if (!result.header.length == size) { + if (result.header.length != size) { return {}; } @@ -124,6 +124,5 @@ void gpu::hfb::writeFrame(const std::string& filename, for (const auto& png : pngBuffers) { writeChunk(ptr, gpu::hfb::CHUNK_TYPE_PNG, png); } - auto writeSize = ptr - output->data(); - assert(writeSize == size); + assert((ptr - output->data()) == size); } diff --git a/libraries/gpu/src/gpu/FrameIO.h b/libraries/gpu/src/gpu/FrameIO.h index e53d64f22f..bb1dfa0f8c 100644 --- a/libraries/gpu/src/gpu/FrameIO.h +++ b/libraries/gpu/src/gpu/FrameIO.h @@ -23,7 +23,7 @@ FramePointer readFrame(const std::string& filename, uint32_t externalTexture, co namespace hfb { -constexpr char* EXTENSION{ ".hfb" }; +constexpr char* const EXTENSION{ ".hfb" }; constexpr uint32_t HEADER_SIZE{ sizeof(uint32_t) * 3 }; constexpr uint32_t CHUNK_HEADER_SIZE = sizeof(uint32_t) * 2; constexpr uint32_t MAGIC{ 0x49464948 }; diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 14f7646d4f..ba523386e0 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -12,129 +12,129 @@ namespace gpu { namespace keys { -constexpr char* binary = "binary"; -constexpr char* L00 = "L00"; -constexpr char* L1m1 = "L1m1"; -constexpr char* L10 = "L10"; -constexpr char* L11 = "L11"; -constexpr char* L2m2 = "L2m2"; -constexpr char* L2m1 = "L2m1"; -constexpr char* L20 = "L20"; -constexpr char* L21 = "L21"; -constexpr char* L22 = "L22"; +constexpr char* const binary = "binary"; +constexpr char* const L00 = "L00"; +constexpr char* const L1m1 = "L1m1"; +constexpr char* const L10 = "L10"; +constexpr char* const L11 = "L11"; +constexpr char* const L2m2 = "L2m2"; +constexpr char* const L2m1 = "L2m1"; +constexpr char* const L20 = "L20"; +constexpr char* const L21 = "L21"; +constexpr char* const L22 = "L22"; -constexpr char* eyeProjections = "eyeProjections"; -constexpr char* eyeViews = "eyeViews"; -constexpr char* alphaToCoverageEnable = "alphaToCoverageEnable"; -constexpr char* antialisedLineEnable = "antialisedLineEnable"; -constexpr char* attributes = "attributes"; -constexpr char* batches = "batches"; -constexpr char* blendFunction = "blendFunction"; -constexpr char* borderColor = "borderColor"; -constexpr char* bufferMask = "bufferMask"; -constexpr char* buffers = "buffers"; -constexpr char* capturedTextures = "capturedTextures"; -constexpr char* channel = "channel"; -constexpr char* chunk = "chunk"; -constexpr char* colorAttachments = "colorAttachments"; -constexpr char* colorWriteMask = "colorWriteMask"; -constexpr char* commands = "commands"; -constexpr char* comparisonFunction = "comparisonFunction"; -constexpr char* cullMode = "cullMode"; -constexpr char* data = "data"; -constexpr char* depth = "depth"; -constexpr char* depthBias = "depthBias"; -constexpr char* depthBiasSlopeScale = "depthBiasSlopeScale"; -constexpr char* depthClampEnable = "depthClampEnable"; -constexpr char* depthStencilAttachment = "depthStencilAttachment"; -constexpr char* depthTest = "depthTest"; -constexpr char* drawCallInfos = "drawCallInfos"; -constexpr char* drawcallUniform = "drawcallUniform"; -constexpr char* drawcallUniformReset = "drawcallUniformReset"; -constexpr char* element = "element"; -constexpr char* fillMode = "fillMode"; -constexpr char* filter = "filter"; -constexpr char* formats = "formats"; -constexpr char* frameIndex = "frameIndex"; -constexpr char* framebuffer = "framebuffer"; -constexpr char* framebuffers = "framebuffers"; -constexpr char* frequency = "frequency"; -constexpr char* frontFaceClockwise = "frontFaceClockwise"; -constexpr char* height = "height"; -constexpr char* id = "id"; -constexpr char* ktxFile = "ktxFile"; -constexpr char* layers = "layers"; -constexpr char* maxAnisotropy = "maxAnisotropy"; -constexpr char* maxMip = "maxMip"; -constexpr char* minMip = "minMip"; -constexpr char* mipOffset = "mipOffset"; -constexpr char* mips = "mips"; -constexpr char* multisampleEnable = "multisampleEnable"; -constexpr char* name = "name"; -constexpr char* namedData = "namedData"; -constexpr char* names = "names"; -constexpr char* objects = "objects"; -constexpr char* offset = "offset"; -constexpr char* pipelines = "pipelines"; -constexpr char* pose = "pose"; -constexpr char* profileRanges = "profileRanges"; -constexpr char* program = "program"; -constexpr char* programs = "programs"; -constexpr char* projectionJitter = "projectionJitter"; -constexpr char* queries = "queries"; -constexpr char* sampleCount = "sampleCount"; -constexpr char* sampleMask = "sampleMask"; -constexpr char* sampler = "sampler"; -constexpr char* samples = "samples"; -constexpr char* scissorEnable = "scissorEnable"; -constexpr char* shaders = "shaders"; -constexpr char* size = "size"; -constexpr char* skybox = "skybox"; -constexpr char* slot = "slot"; -constexpr char* source = "source"; -constexpr char* state = "state"; -constexpr char* stencilActivation = "stencilActivation"; -constexpr char* stencilTestBack = "stencilTestBack"; -constexpr char* stencilTestFront = "stencilTestFront"; -constexpr char* stereo = "stereo"; -constexpr char* subresource = "subresource"; -constexpr char* swapchains = "swapchains"; -constexpr char* texelFormat = "texelFormat"; -constexpr char* texture = "texture"; -constexpr char* textureTables = "textureTables"; -constexpr char* textures = "textures"; -constexpr char* transforms = "transforms"; -constexpr char* type = "type"; -constexpr char* usageType = "usageType"; -constexpr char* view = "view"; -constexpr char* width = "width"; -constexpr char* wrapModeU = "wrapModeU"; -constexpr char* wrapModeV = "wrapModeV"; -constexpr char* wrapModeW = "wrapModeW"; +constexpr char* const eyeProjections = "eyeProjections"; +constexpr char* const eyeViews = "eyeViews"; +constexpr char* const alphaToCoverageEnable = "alphaToCoverageEnable"; +constexpr char* const antialisedLineEnable = "antialisedLineEnable"; +constexpr char* const attributes = "attributes"; +constexpr char* const batches = "batches"; +constexpr char* const blendFunction = "blendFunction"; +constexpr char* const borderColor = "borderColor"; +constexpr char* const bufferMask = "bufferMask"; +constexpr char* const buffers = "buffers"; +constexpr char* const capturedTextures = "capturedTextures"; +constexpr char* const channel = "channel"; +constexpr char* const chunk = "chunk"; +constexpr char* const colorAttachments = "colorAttachments"; +constexpr char* const colorWriteMask = "colorWriteMask"; +constexpr char* const commands = "commands"; +constexpr char* const comparisonFunction = "comparisonFunction"; +constexpr char* const cullMode = "cullMode"; +constexpr char* const data = "data"; +constexpr char* const depth = "depth"; +constexpr char* const depthBias = "depthBias"; +constexpr char* const depthBiasSlopeScale = "depthBiasSlopeScale"; +constexpr char* const depthClampEnable = "depthClampEnable"; +constexpr char* const depthStencilAttachment = "depthStencilAttachment"; +constexpr char* const depthTest = "depthTest"; +constexpr char* const drawCallInfos = "drawCallInfos"; +constexpr char* const drawcallUniform = "drawcallUniform"; +constexpr char* const drawcallUniformReset = "drawcallUniformReset"; +constexpr char* const element = "element"; +constexpr char* const fillMode = "fillMode"; +constexpr char* const filter = "filter"; +constexpr char* const formats = "formats"; +constexpr char* const frameIndex = "frameIndex"; +constexpr char* const framebuffer = "framebuffer"; +constexpr char* const framebuffers = "framebuffers"; +constexpr char* const frequency = "frequency"; +constexpr char* const frontFaceClockwise = "frontFaceClockwise"; +constexpr char* const height = "height"; +constexpr char* const id = "id"; +constexpr char* const ktxFile = "ktxFile"; +constexpr char* const layers = "layers"; +constexpr char* const maxAnisotropy = "maxAnisotropy"; +constexpr char* const maxMip = "maxMip"; +constexpr char* const minMip = "minMip"; +constexpr char* const mipOffset = "mipOffset"; +constexpr char* const mips = "mips"; +constexpr char* const multisampleEnable = "multisampleEnable"; +constexpr char* const name = "name"; +constexpr char* const namedData = "namedData"; +constexpr char* const names = "names"; +constexpr char* const objects = "objects"; +constexpr char* const offset = "offset"; +constexpr char* const pipelines = "pipelines"; +constexpr char* const pose = "pose"; +constexpr char* const profileRanges = "profileRanges"; +constexpr char* const program = "program"; +constexpr char* const programs = "programs"; +constexpr char* const projectionJitter = "projectionJitter"; +constexpr char* const queries = "queries"; +constexpr char* const sampleCount = "sampleCount"; +constexpr char* const sampleMask = "sampleMask"; +constexpr char* const sampler = "sampler"; +constexpr char* const samples = "samples"; +constexpr char* const scissorEnable = "scissorEnable"; +constexpr char* const shaders = "shaders"; +constexpr char* const size = "size"; +constexpr char* const skybox = "skybox"; +constexpr char* const slot = "slot"; +constexpr char* const source = "source"; +constexpr char* const state = "state"; +constexpr char* const stencilActivation = "stencilActivation"; +constexpr char* const stencilTestBack = "stencilTestBack"; +constexpr char* const stencilTestFront = "stencilTestFront"; +constexpr char* const stereo = "stereo"; +constexpr char* const subresource = "subresource"; +constexpr char* const swapchains = "swapchains"; +constexpr char* const texelFormat = "texelFormat"; +constexpr char* const texture = "texture"; +constexpr char* const textureTables = "textureTables"; +constexpr char* const textures = "textures"; +constexpr char* const transforms = "transforms"; +constexpr char* const type = "type"; +constexpr char* const usageType = "usageType"; +constexpr char* const view = "view"; +constexpr char* const width = "width"; +constexpr char* const wrapModeU = "wrapModeU"; +constexpr char* const wrapModeV = "wrapModeV"; +constexpr char* const wrapModeW = "wrapModeW"; -constexpr char* backWriteMask = "backWriteMask"; -constexpr char* frontWriteMask = "frontWriteMask"; -constexpr char* reference = "reference"; -constexpr char* readMask = "readMask"; -constexpr char* failOp = "failOp"; -constexpr char* depthFailOp = "depthFailOp"; -constexpr char* passOp = "passOp"; -constexpr char* enabled = "enabled"; -constexpr char* blend = "blend"; -constexpr char* flags = "flags"; -constexpr char* writeMask = "writeMask"; -constexpr char* function = "function"; -constexpr char* sourceColor = "sourceColor"; -constexpr char* sourceAlpha = "sourceAlpha"; -constexpr char* destColor = "destColor"; -constexpr char* destAlpha = "destAlpha"; -constexpr char* opColor = "opColor"; -constexpr char* opAlpha = "opAlpha"; -constexpr char* enable = "enable"; -constexpr char* contextDisable = "contextDisable"; +constexpr char* const backWriteMask = "backWriteMask"; +constexpr char* const frontWriteMask = "frontWriteMask"; +constexpr char* const reference = "reference"; +constexpr char* const readMask = "readMask"; +constexpr char* const failOp = "failOp"; +constexpr char* const depthFailOp = "depthFailOp"; +constexpr char* const passOp = "passOp"; +constexpr char* const enabled = "enabled"; +constexpr char* const blend = "blend"; +constexpr char* const flags = "flags"; +constexpr char* const writeMask = "writeMask"; +constexpr char* const function = "function"; +constexpr char* const sourceColor = "sourceColor"; +constexpr char* const sourceAlpha = "sourceAlpha"; +constexpr char* const destColor = "destColor"; +constexpr char* const destAlpha = "destAlpha"; +constexpr char* const opColor = "opColor"; +constexpr char* const opAlpha = "opAlpha"; +constexpr char* const enable = "enable"; +constexpr char* const contextDisable = "contextDisable"; -constexpr char* COMMAND_NAMES[] = { +constexpr char* const COMMAND_NAMES[] = { "draw", "drawIndexed", "drawInstanced", diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f961a19503..72b1ebe7ba 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -22,7 +22,6 @@ if (BUILD_TOOLS) set(ALL_TOOLS udt-test vhacd-util - frame-optimizer gpu-frame-player gpu-frame-converter ice-client diff --git a/tools/frame-optimizer/CMakeLists.txt b/tools/frame-optimizer/CMakeLists.txt deleted file mode 100644 index cc268c5baf..0000000000 --- a/tools/frame-optimizer/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(TARGET_NAME frame-optimizer) - -setup_memory_debugger() -setup_hifi_project(Gui Widgets) -link_hifi_libraries(shared ktx shaders gpu ) -package_libraries_for_deployment() diff --git a/tools/frame-optimizer/src/main.cpp b/tools/frame-optimizer/src/main.cpp deleted file mode 100644 index a4200c3d97..0000000000 --- a/tools/frame-optimizer/src/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Created by Bradley Austin Davis on 2018/10/14 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#ifdef Q_OS_WIN -#include -#endif - -#include -#include -#include - - -gpu::IndexOptimizer optimizer= [](gpu::Primitive primitive, uint32_t faceCount, uint32_t indexCount, uint32_t* indices ) { - // FIXME add a triangle index optimizer here -}; - - -void messageHandler(QtMsgType type, const QMessageLogContext &, const QString & message) { - auto messageStr = message.toStdString(); -#ifdef Q_OS_WIN - OutputDebugStringA(messageStr.c_str()); - OutputDebugStringA("\n"); -#endif - std::cerr << messageStr << std::endl; -} - -int main(int argc, char** argv) { - QCoreApplication app(argc, argv); - qInstallMessageHandler(messageHandler); - gpu::optimizeFrame("D:/Frames/20190112_1647.json", optimizer); - return 0; -} diff --git a/tools/gpu-frame-converter/CMakeLists.txt b/tools/gpu-frame-converter/CMakeLists.txt index d28a41c278..4c2a2f5546 100644 --- a/tools/gpu-frame-converter/CMakeLists.txt +++ b/tools/gpu-frame-converter/CMakeLists.txt @@ -1,9 +1,9 @@ -set(TARGET_NAME gpu-frame-converter) -setup_memory_debugger() -setup_hifi_project() -set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) -# link in the shared libraries -link_hifi_libraries( shared gpu shaders ) - -package_libraries_for_deployment() +if (WIN32) + set(TARGET_NAME gpu-frame-converter) + setup_memory_debugger() + setup_hifi_project() + set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) + link_hifi_libraries( shared gpu shaders ) + package_libraries_for_deployment() +endif() \ No newline at end of file From 88514540d10a2467b3d9c50cfd224c988d30f653 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 09:26:33 -0700 Subject: [PATCH 09/12] Fixing tools build --- tools/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 72b1ebe7ba..6f9145ff7d 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -42,7 +42,9 @@ if (BUILD_TOOLS) check_test(${TOOL}) if (${BUILD_TOOL_RESULT}) add_subdirectory(${TOOL}) - set_target_properties(${TOOL} PROPERTIES FOLDER "Tools") + if (TARGET ${TOOL}) + set_target_properties(${TOOL} PROPERTIES FOLDER "Tools") + endif() endif() endforeach() endif() From 243120b95c99d9c3d555bbb45022d4c33a998ea5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 14:57:39 -0700 Subject: [PATCH 10/12] Even better frame capture --- interface/src/Application.cpp | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 63 +++++++----- libraries/gpu/src/gpu/FrameIO.cpp | 98 ++++++++++--------- libraries/gpu/src/gpu/FrameIO.h | 27 +++-- libraries/gpu/src/gpu/FrameReader.cpp | 59 ++++------- libraries/gpu/src/gpu/FrameWriter.cpp | 20 ++-- libraries/gpu/src/gpu/Texture.h | 3 + libraries/gpu/src/gpu/Texture_ktx.cpp | 85 +++++++++++----- libraries/ktx/src/ktx/KTX.h | 2 +- libraries/shared/src/shared/FileUtils.cpp | 13 +++ libraries/shared/src/shared/FileUtils.h | 7 +- libraries/shared/src/shared/Storage.h | 15 ++- tools/gpu-frame-player/src/PlayerWindow.cpp | 13 +-- 13 files changed, 242 insertions(+), 165 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c9b976cc14..b4a37519a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4441,7 +4441,7 @@ void Application::keyPressEvent(QKeyEvent* event) { static const QString GPU_FRAME_FOLDER = QProcessEnvironment::systemEnvironment().contains(HIFI_FRAMES_FOLDER_VAR) ? QProcessEnvironment::systemEnvironment().value(HIFI_FRAMES_FOLDER_VAR) : "hifiFrames"; - static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}.hfb"; + static QString GPU_FRAME_TEMPLATE = GPU_FRAME_FOLDER + "/{DATE}_{TIME}"; QString fullPath = FileUtils::computeDocumentPath(FileUtils::replaceDateTimeTokens(GPU_FRAME_TEMPLATE)); if (FileUtils::canCreateFile(fullPath)) { getActiveDisplayPlugin()->captureFrame(fullPath.toStdString()); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e69791e73d..6ca11688a2 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -476,34 +477,50 @@ void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) { }); } +ktx::StoragePointer textureToKtx(const gpu::Texture& texture) { + ktx::Header header; + { + auto gpuDims = texture.getDimensions(); + header.pixelWidth = gpuDims.x; + header.pixelHeight = gpuDims.y; + header.pixelDepth = 0; + } + + { + auto gltexelformat = gpu::gl::GLTexelFormat::evalGLTexelFormat(texture.getStoredMipFormat()); + header.glInternalFormat = gltexelformat.internalFormat; + header.glFormat = gltexelformat.format; + header.glBaseInternalFormat = gltexelformat.format; + header.glType = gltexelformat.type; + header.glTypeSize = 1; + header.numberOfMipmapLevels = 1 + texture.getMaxMip(); + } + + auto memKtx = ktx::KTX::createBare(header); + auto storage = memKtx->_storage; + uint32_t faceCount = std::max(header.numberOfFaces, 1u); + uint32_t mipCount = std::max(header.numberOfMipmapLevels, 1u); + for (uint32_t mip = 0; mip < mipCount; ++mip) { + for (uint32_t face = 0; face < faceCount; ++face) { + const auto& image = memKtx->_images[mip]; + auto& faceBytes = const_cast(image._faceBytes[face]); + if (texture.isStoredMipFaceAvailable(mip, face)) { + auto storedImage = texture.accessStoredMipFace(mip, face); + auto storedSize = storedImage->size(); + memcpy(faceBytes, storedImage->data(), storedSize); + } + } + } + return storage; +} + void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const { withOtherThreadContext([&] { using namespace gpu; auto glBackend = const_cast(*this).getGLBackend(); FramebufferPointer framebuffer{ Framebuffer::create("captureFramebuffer") }; - TextureCapturer captureLambda = [&](std::vector& outputBuffer, const gpu::TexturePointer& texture, uint16 layer) { - QImage image; - if (texture->getUsageType() == TextureUsageType::STRICT_RESOURCE) { - image = QImage{ 1, 1, QImage::Format_ARGB32 }; - auto storedImage = texture->accessStoredMipFace(0, 0); - memcpy(image.bits(), storedImage->data(), image.sizeInBytes()); - //if (texture == textureCache->getWhiteTexture()) { - //} else if (texture == textureCache->getBlackTexture()) { - //} else if (texture == textureCache->getBlueTexture()) { - //} else if (texture == textureCache->getGrayTexture()) { - } else { - ivec4 rect = { 0, 0, texture->getWidth(), texture->getHeight() }; - framebuffer->setRenderBuffer(0, texture, layer); - glBackend->syncGPUObject(*framebuffer); - - image = QImage{ rect.z, rect.w, QImage::Format_ARGB32 }; - glBackend->downloadFramebuffer(framebuffer, rect, image); - } - QBuffer buffer; - QImageWriter(&buffer, "png").write(image); - const auto& data = buffer.data(); - outputBuffer.resize(data.size()); - memcpy(outputBuffer.data(), data.constData(), data.size()); + TextureCapturer captureLambda = [&](const gpu::TexturePointer& texture)->storage::StoragePointer { + return textureToKtx(*texture); }; if (_currentFrame) { diff --git a/libraries/gpu/src/gpu/FrameIO.cpp b/libraries/gpu/src/gpu/FrameIO.cpp index 12e07b6e2a..a0f21df881 100644 --- a/libraries/gpu/src/gpu/FrameIO.cpp +++ b/libraries/gpu/src/gpu/FrameIO.cpp @@ -8,6 +8,7 @@ #include "FrameIO.h" #include +#include using namespace gpu::hfb; @@ -30,30 +31,44 @@ static bool read(const uint8_t*& ptr, size_t& remaining, T& output) { return skip(ptr, remaining, readSize); } -Descriptor Descriptor::parse(const uint8_t* const data, size_t size) { - const auto* ptr = data; - auto remaining = size; - Descriptor result; - if (!read(ptr, remaining, result.header)) { - return {}; - } - if (result.header.length != size) { - return {}; - } +Descriptor::Descriptor(const StoragePointer& storage) : storage(storage) { + const auto* const start = storage->data(); + const auto* ptr = storage->data(); + auto remaining = storage->size(); - while (remaining != 0) { - result.chunks.emplace_back(); - auto& chunk = result.chunks.back(); - ChunkHeader& chunkHeader = chunk; - if (!read(ptr, remaining, chunkHeader)) { - return {}; + try { + // Can't parse files more than 4GB + if (remaining > UINT32_MAX) { + throw std::runtime_error("File too large"); } - chunk.offset = ptr - data; - if (!skip(ptr, remaining, chunk.length)) { - return {}; + + if (!read(ptr, remaining, header)) { + throw std::runtime_error("Couldn't read binary header"); } + + if (header.length != storage->size()) { + throw std::runtime_error("Header/Actual size mismatch"); + } + + while (remaining != 0) { + chunks.emplace_back(); + auto& chunk = chunks.back(); + ChunkHeader& chunkHeader = chunk; + if (!read(ptr, remaining, chunkHeader)) { + throw std::runtime_error("Coulnd't read chunk header"); + } + chunk.offset = (uint32_t)(ptr - start); + if (chunk.end() > storage->size()) { + throw std::runtime_error("Chunk too large for file"); + } + if (!skip(ptr, remaining, chunk.length)) { + throw std::runtime_error("Skip chunk data failed"); + } + } + } catch (const std::runtime_error&) { + // LOG somnething + header.magic = 0; } - return result; } size_t Chunk::end() const { @@ -62,30 +77,15 @@ size_t Chunk::end() const { return result; } - -bool Descriptor::getChunkString(std::string& output, size_t chunkIndex, const uint8_t* const data, size_t size) { +StoragePointer Descriptor::getChunk(uint32_t chunkIndex) const { if (chunkIndex >= chunks.size()) { - return false; + return {}; } const auto& chunk = chunks[chunkIndex]; - if (chunk.end() > size) { - return false; + if (chunk.end() > storage->size()) { + return {}; } - output = std::string{ (const char*)(data + chunk.offset), chunk.length }; - return true; -} - -bool Descriptor::getChunkBuffer(Buffer& output, size_t chunkIndex, const uint8_t* const data, size_t size) { - if (chunkIndex >= chunks.size()) { - return false; - } - const auto& chunk = chunks[chunkIndex]; - if (chunk.end() > size) { - return false; - } - output.resize(chunk.length); - memcpy(output.data(), data + chunk.offset, chunk.length); - return true; + return storage->createView(chunk.length, chunk.offset); } static void writeUint(uint8_t*& dest, uint32_t value) { @@ -105,12 +105,15 @@ static void writeChunk(uint8_t*& dest, uint32_t chunkType, const T& chunkData) { void gpu::hfb::writeFrame(const std::string& filename, const std::string& json, const Buffer& binaryBuffer, - const Buffers& pngBuffers) { + const StorageBuilders& ktxBuilders) { uint32_t strLen = (uint32_t)json.size(); uint32_t size = gpu::hfb::HEADER_SIZE + gpu::hfb::CHUNK_HEADER_SIZE + strLen; size += gpu::hfb::CHUNK_HEADER_SIZE + (uint32_t)binaryBuffer.size(); - for (const auto& pngBuffer : pngBuffers) { - size += gpu::hfb::CHUNK_HEADER_SIZE + (uint32_t)pngBuffer.size(); + for (const auto& builder : ktxBuilders) { + auto storage = builder(); + if (storage) { + size += gpu::hfb::CHUNK_HEADER_SIZE + (uint32_t)storage->size(); + } } auto outputConst = storage::FileStorage::create(filename.c_str(), size, nullptr); @@ -121,8 +124,13 @@ void gpu::hfb::writeFrame(const std::string& filename, writeUint(ptr, size); writeChunk(ptr, gpu::hfb::CHUNK_TYPE_JSON, json); writeChunk(ptr, gpu::hfb::CHUNK_TYPE_BIN, binaryBuffer); - for (const auto& png : pngBuffers) { - writeChunk(ptr, gpu::hfb::CHUNK_TYPE_PNG, png); + for (const auto& builder : ktxBuilders) { + static StoragePointer EMPTY_STORAGE{ std::make_shared(0, nullptr) }; + auto storage = builder(); + if (!storage) { + storage = EMPTY_STORAGE; + } + writeChunk(ptr, gpu::hfb::CHUNK_TYPE_KTX, *storage); } assert((ptr - output->data()) == size); } diff --git a/libraries/gpu/src/gpu/FrameIO.h b/libraries/gpu/src/gpu/FrameIO.h index bb1dfa0f8c..77602ef4e8 100644 --- a/libraries/gpu/src/gpu/FrameIO.h +++ b/libraries/gpu/src/gpu/FrameIO.h @@ -12,28 +12,34 @@ #include "Forward.h" #include "Format.h" +#include + #include namespace gpu { -using TextureCapturer = std::function&, const TexturePointer&, uint16 layer)>; -using TextureLoader = std::function&, const TexturePointer&, uint16 layer)>; +using TextureCapturer = std::function; +//using TextureLoader = std::function; void writeFrame(const std::string& filename, const FramePointer& frame, const TextureCapturer& capturer = nullptr); -FramePointer readFrame(const std::string& filename, uint32_t externalTexture, const TextureLoader& loader = nullptr); +FramePointer readFrame(const std::string& filename, uint32_t externalTexture); namespace hfb { +using Storage = storage::Storage; +using StoragePointer = storage::Pointer; +using StorageBuilders = storage::Builders; + constexpr char* const EXTENSION{ ".hfb" }; constexpr uint32_t HEADER_SIZE{ sizeof(uint32_t) * 3 }; constexpr uint32_t CHUNK_HEADER_SIZE = sizeof(uint32_t) * 2; constexpr uint32_t MAGIC{ 0x49464948 }; constexpr uint32_t VERSION{ 0x01 }; constexpr uint32_t CHUNK_TYPE_JSON{ 0x4E4F534A }; +constexpr uint32_t CHUNK_TYPE_KTX{ 0x0058544b }; constexpr uint32_t CHUNK_TYPE_BIN{ 0x004E4942 }; constexpr uint32_t CHUNK_TYPE_PNG{ 0x00474E50 }; using Buffer = std::vector; -using Buffers = std::vector; struct Header { uint32_t magic{ 0 }; @@ -55,16 +61,21 @@ struct Chunk : public ChunkHeader { using Chunks = std::vector; struct Descriptor { + using Pointer = std::shared_ptr; + Header header; Chunks chunks; + StoragePointer storage; + Descriptor(const StoragePointer& storage); operator bool() const { return header.magic == MAGIC; } - bool getChunkString(std::string& output, size_t chunk, const uint8_t* const data, size_t size); - bool getChunkBuffer(Buffer& output, size_t chunk, const uint8_t* const data, size_t size); - static Descriptor parse(const uint8_t* const data, size_t size); + StoragePointer getChunk(uint32_t chunk) const; }; -void writeFrame(const std::string& filename, const std::string& json, const Buffer& binaryBuffer, const Buffers& pngBuffers); +void writeFrame(const std::string& filename, + const std::string& json, + const Buffer& binaryBuffer, + const StorageBuilders& pngBuffers); } // namespace hfb diff --git a/libraries/gpu/src/gpu/FrameReader.cpp b/libraries/gpu/src/gpu/FrameReader.cpp index 1f94828119..d636c6aaca 100644 --- a/libraries/gpu/src/gpu/FrameReader.cpp +++ b/libraries/gpu/src/gpu/FrameReader.cpp @@ -10,9 +10,7 @@ #include #include -#include -#include - +#include #include #include "Frame.h" #include "Batch.h" @@ -33,7 +31,7 @@ public: auto lastSlash = filename.rfind('/'); result = filename.substr(0, lastSlash + 1); } else { - result = QFileInfo(filename.c_str()).absoluteDir().canonicalPath().toStdString(); + result = FileUtils::getParentPath(filename.c_str()).toStdString(); if (*result.rbegin() != '/') { result += '/'; } @@ -41,18 +39,17 @@ public: return result; } - Deserializer(const std::string& filename_, uint32_t externalTexture = 0, const TextureLoader& loader = {}) : + Deserializer(const std::string& filename_, uint32_t externalTexture = 0) : filename(filename_), basedir(getBaseDir(filename_)), mappedFile(std::make_shared(filename.c_str())), - externalTexture(externalTexture), textureLoader(loader) { - descriptor = hfb::Descriptor::parse(mappedFile->data(), (uint32_t)mappedFile->size()); + externalTexture(externalTexture) { + descriptor = std::make_shared(mappedFile); } const std::string filename; const std::string basedir; const StoragePointer mappedFile; const uint32_t externalTexture; - hfb::Descriptor descriptor; - TextureLoader textureLoader; + hfb::Descriptor::Pointer descriptor; std::vector shaders; std::vector programs; std::vector textures; @@ -70,19 +67,8 @@ public: FramePointer deserializeFrame(); std::string getStringChunk(size_t chunkIndex) { - std::string result; - if (!descriptor.getChunkString(result, chunkIndex, mappedFile->data(), mappedFile->size())) { - return {}; - } - return result; - } - - hfb::Buffer getBufferChunk(size_t chunkIndex) { - hfb::Buffer result; - if (!descriptor.getChunkBuffer(result, chunkIndex, mappedFile->data(), mappedFile->size())) { - return {}; - } - return result; + auto storage = descriptor->getChunk((uint32_t)chunkIndex); + return std::string{ (const char*)storage->data(), storage->size() }; } void readBuffers(const json& node); @@ -240,8 +226,8 @@ public: static void readCommand(const json& node, Batch& batch); }; -FramePointer readFrame(const std::string& filename, uint32_t externalTexture, const TextureLoader& loader) { - return Deserializer(filename, externalTexture, loader).readFrame(); +FramePointer readFrame(const std::string& filename, uint32_t externalTexture) { + return Deserializer(filename, externalTexture).readFrame(); } } // namespace gpu @@ -249,7 +235,7 @@ FramePointer readFrame(const std::string& filename, uint32_t externalTexture, co using namespace gpu; void Deserializer::readBuffers(const json& buffersNode) { - const auto& binaryChunk = descriptor.chunks[1]; + const auto& binaryChunk = descriptor->chunks[1]; const auto* mapped = mappedFile->data() + binaryChunk.offset; const auto mappedSize = binaryChunk.length; size_t bufferCount = buffersNode.size(); @@ -333,7 +319,7 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { std::string ktxFile; readOptional(ktxFile, node, keys::ktxFile); if (!ktxFile.empty()) { - if (!QFileInfo(ktxFile.c_str()).exists()) { + if (!FileUtils::exists(ktxFile.c_str())) { qDebug() << "Warning" << ktxFile.c_str() << " not found, ignoring"; ktxFile = {}; } @@ -347,8 +333,8 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { frameReaderPath.replace("libraries/gpu/src/gpu/framereader.cpp", "interface/resources", Qt::CaseInsensitive); ktxFile.replace(0, 1, frameReaderPath.toStdString()); } - if (QFileInfo(ktxFile.c_str()).isRelative()) { - ktxFile = basedir + ktxFile; + if (FileUtils::isRelative(ktxFile.c_str())) { + ktxFile = basedir + "/" + ktxFile; } ktx::StoragePointer ktxStorage{ new storage::FileStorage(ktxFile.c_str()) }; auto ktxObject = ktx::KTX::create(ktxStorage); @@ -381,19 +367,14 @@ TexturePointer Deserializer::readTexture(const json& node, uint32_t external) { auto& texture = *result; readOptional(texture._source, node, keys::source); - if (!ktxFile.empty()) { - if (QFileInfo(ktxFile.c_str()).isRelative()) { - ktxFile = basedir + "/" + ktxFile; - } + + if (chunkIndex != INVALID_CHUNK_INDEX) { + auto ktxChunk = descriptor->getChunk(chunkIndex); + texture.setKtxBacking(ktxChunk); + } else if (!ktxFile.empty()) { texture.setSource(ktxFile); texture.setKtxBacking(ktxFile); - } else if (chunkIndex != INVALID_CHUNK_INDEX) { - if (textureLoader) { - texture.setSource("Chunk " + std::to_string(chunkIndex)); - textureLoader(getBufferChunk(chunkIndex), result, 0); - } - } - + } return result; } diff --git a/libraries/gpu/src/gpu/FrameWriter.cpp b/libraries/gpu/src/gpu/FrameWriter.cpp index 85397f149a..761f37a620 100644 --- a/libraries/gpu/src/gpu/FrameWriter.cpp +++ b/libraries/gpu/src/gpu/FrameWriter.cpp @@ -34,7 +34,7 @@ public: std::unordered_map queryMap; std::unordered_set captureTextures; hfb::Buffer binaryBuffer; - hfb::Buffers pngBuffers; + hfb::StorageBuilders ktxBuilders; Serializer(const std::string& basename, const TextureCapturer& capturer) : filename(basename + hfb::EXTENSION), textureCapturer(capturer) {} @@ -392,13 +392,17 @@ json Serializer::writeTexture(const TexturePointer& texturePointer) { const auto* storage = texture._storage.get(); const auto* ktxStorage = dynamic_cast(storage); if (ktxStorage) { - result[keys::ktxFile] = ktxStorage->_filename; + result[keys::chunk] = 2 + ktxBuilders.size(); + auto filename = ktxStorage->_filename; + ktxBuilders.push_back([=] { + return std::make_shared(filename.c_str()); + }); } else if (textureCapturer && captureTextures.count(texturePointer) != 0) { - auto layers = std::max(texture.getNumSlices(), 1); - result[keys::chunk] = 2 + pngBuffers.size(); - pngBuffers.push_back({}); - hfb::Buffer& pngBuffer = pngBuffers.back(); - textureCapturer(pngBuffer, texturePointer, 0); + result[keys::chunk] = 2 + ktxBuilders.size(); + auto storage = textureCapturer(texturePointer); + ktxBuilders.push_back([=] { + return storage; + }); } } return result; @@ -790,7 +794,7 @@ void Serializer::writeFrame(const Frame& frame) { writeBinaryBlob(); - hfb::writeFrame(filename, frameNode.dump(), binaryBuffer, pngBuffers); + hfb::writeFrame(filename, frameNode.dump(), binaryBuffer, ktxBuilders); } void Serializer::writeBinaryBlob() { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 5e2485941d..debedf02a5 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -343,6 +343,7 @@ public: class KtxStorage : public Storage { public: + KtxStorage(const storage::StoragePointer& storage); KtxStorage(const std::string& filename); KtxStorage(const cache::FilePointer& file); PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override; @@ -366,6 +367,7 @@ public: static std::vector, std::shared_ptr>> _cachedKtxFiles; static std::mutex _cachedKtxFilesMutex; + storage::StoragePointer _storage; std::string _filename; cache::FilePointer _cacheEntry; std::atomic _minMipLevelAvailable; @@ -543,6 +545,7 @@ public: Size getStoredSize() const; void setStorage(std::unique_ptr& newStorage); + void setKtxBacking(const storage::StoragePointer& storage); void setKtxBacking(const std::string& filename); void setKtxBacking(const cache::FilePointer& cacheEntry); diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index f471baf2c7..a5cea3e60e 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -159,7 +159,31 @@ struct IrradianceKTXPayload { }; const std::string IrradianceKTXPayload::KEY{ "hifi.irradianceSH" }; -KtxStorage::KtxStorage(const cache::FilePointer& cacheEntry) : KtxStorage(cacheEntry->getFilepath()) { +KtxStorage::KtxStorage(const storage::StoragePointer& storage) : _storage(storage) { + auto ktxPointer = ktx::KTX::create(storage); + _ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor())); + if (_ktxDescriptor->images.size() < _ktxDescriptor->header.numberOfMipmapLevels) { + qWarning() << "Bad images found in ktx"; + } + + _offsetToMinMipKV = _ktxDescriptor->getValueOffsetForKey(ktx::HIFI_MIN_POPULATED_MIP_KEY); + if (_offsetToMinMipKV) { + auto data = storage->data() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; + _minMipLevelAvailable = *data; + } else { + // Assume all mip levels are available + _minMipLevelAvailable = 0; + } + + // now that we know the ktx, let's get the header info to configure this Texture::Storage: + Format mipFormat = Format::COLOR_BGRA_32; + Format texelFormat = Format::COLOR_SRGBA_32; + if (Texture::evalTextureFormat(_ktxDescriptor->header, mipFormat, texelFormat)) { + _format = mipFormat; + } +} + +KtxStorage::KtxStorage(const cache::FilePointer& cacheEntry) : KtxStorage(cacheEntry->getFilepath()) { _cacheEntry = cacheEntry; } @@ -228,28 +252,31 @@ void KtxStorage::releaseOpenKtxFiles() { PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); + storage::StoragePointer storageView; if (faceSize != 0 && faceOffset != 0) { - std::lock_guard lock(*_cacheFileMutex); - auto file = maybeOpenFile(); - if (file) { - auto storageView = file->createView(faceSize, faceOffset); - if (storageView) { - return storageView->toMemoryStorage(); - } else { - qWarning() << "Failed to get a valid storageView for faceSize=" << faceSize << " faceOffset=" << faceOffset << "out of valid file " << QString::fromStdString(_filename); - } + if (_storage) { + storageView = _storage->createView(faceSize, faceOffset); } else { - qWarning() << "Failed to get a valid file out of maybeOpenFile " << QString::fromStdString(_filename); + std::lock_guard lock(*_cacheFileMutex); + auto file = maybeOpenFile(); + if (file) { + storageView = file->createView(faceSize, faceOffset); + } else { + qWarning() << "Failed to get a valid file out of maybeOpenFile " << QString::fromStdString(_filename); + } } } - return nullptr; + if (!storageView) { + qWarning() << "Failed to get a valid storageView for faceSize=" << faceSize << " faceOffset=" << faceOffset + << "out of valid file " << QString::fromStdString(_filename); + } + return storageView->toMemoryStorage(); } Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const { return _ktxDescriptor->getMipFaceTexelsSize(level, face); } - bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const { return level >= _minMipLevelAvailable; } @@ -271,7 +298,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor auto& imageDesc = _ktxDescriptor->images[level]; 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; } @@ -311,8 +338,7 @@ void KtxStorage::assignMipFaceData(uint16 level, uint8 face, const storage::Stor throw std::runtime_error("Invalid call"); } -bool validKtx(const std::string& filename) { - ktx::StoragePointer storage { new storage::FileStorage(filename.c_str()) }; +bool validKtx(const storage::StoragePointer& storage) { auto ktxPointer = ktx::KTX::create(storage); if (!ktxPointer) { return false; @@ -320,6 +346,21 @@ bool validKtx(const std::string& filename) { return true; } +bool validKtx(const std::string& filename) { + ktx::StoragePointer storage{ new storage::FileStorage(filename.c_str()) }; + return validKtx(storage); +} + +void Texture::setKtxBacking(const storage::StoragePointer& storage) { + // Check the KTX file for validity before using it as backing storage + if (!validKtx(storage)) { + return; + } + + auto newBacking = std::unique_ptr(new KtxStorage(storage)); + setStorage(newBacking); +} + void Texture::setKtxBacking(const std::string& filename) { // Check the KTX file for validity before using it as backing storage if (!validKtx(filename)) { @@ -355,7 +396,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { // Set Dimensions uint32_t numFaces = 1; switch (texture.getType()) { - case TEX_1D: { + case TEX_1D: { if (texture.isArray()) { header.set1DArray(texture.getWidth(), texture.getNumSlices()); } else { @@ -363,7 +404,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } break; } - case TEX_2D: { + case TEX_2D: { if (texture.isArray()) { header.set2DArray(texture.getWidth(), texture.getHeight(), texture.getNumSlices()); } else { @@ -371,7 +412,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } break; } - case TEX_3D: { + case TEX_3D: { if (texture.isArray()) { header.set3DArray(texture.getWidth(), texture.getHeight(), texture.getDepth(), texture.getNumSlices()); } else { @@ -379,7 +420,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } break; } - case TEX_CUBE: { + case TEX_CUBE: { if (texture.isArray()) { header.setCubeArray(texture.getWidth(), texture.getHeight(), texture.getNumSlices()); } else { @@ -388,8 +429,8 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { numFaces = Texture::CUBE_FACE_COUNT; break; } - default: - return nullptr; + default: + return nullptr; } // Number level of mips coming diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index d755a482e3..0165113ec5 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -96,7 +96,7 @@ namespace ktx { using GLBaseInternalFormat = khronos::gl::texture::BaseInternalFormat; using Storage = storage::Storage; - using StoragePointer = std::shared_ptr; + using StoragePointer = std::shared_ptr; struct ImageDescriptor; using ImageDescriptors = std::vector; diff --git a/libraries/shared/src/shared/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp index f2a4925351..164af091de 100644 --- a/libraries/shared/src/shared/FileUtils.cpp +++ b/libraries/shared/src/shared/FileUtils.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -176,3 +177,15 @@ bool FileUtils::canCreateFile(const QString& fullPath) { } return true; } + +QString FileUtils::getParentPath(const QString& fullPath) { + return QFileInfo(fullPath).absoluteDir().canonicalPath(); +} + +bool FileUtils::exists(const QString& fileName) { + return QFileInfo(fileName).exists(); +} + +bool FileUtils::isRelative(const QString& fileName) { + return QFileInfo(fileName).isRelative(); +} diff --git a/libraries/shared/src/shared/FileUtils.h b/libraries/shared/src/shared/FileUtils.h index 2f5e11f005..d4ff819e75 100644 --- a/libraries/shared/src/shared/FileUtils.h +++ b/libraries/shared/src/shared/FileUtils.h @@ -12,20 +12,23 @@ #ifndef hifi_FileUtils_h #define hifi_FileUtils_h -#include -#include +#include + class FileUtils { public: static const QStringList& getFileSelectors(); static QString selectFile(const QString& fileName); static void locateFile(const QString& fileName); + static bool exists(const QString& fileName); + static bool isRelative(const QString& fileName); static QString standardPath(QString subfolder); static QString readFile(const QString& filename); static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts); static QString replaceDateTimeTokens(const QString& path); static QString computeDocumentPath(const QString& path); static bool canCreateFile(const QString& fullPath); + static QString getParentPath(const QString& fullPath); }; #endif // hifi_FileUtils_h diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index 0e5032bb62..6a2cecf8b9 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -10,15 +10,22 @@ #ifndef hifi_Storage_h #define hifi_Storage_h -#include +#include #include #include -#include -#include +#include + +#include +#include namespace storage { class Storage; - using StoragePointer = std::shared_ptr; + using Pointer = std::shared_ptr; + using StoragePointer = Pointer; + // A function that can construct storage, useful for creating a list of + // things that can become storage without requiring that they all be instantiated at once + using Builder = std::function; + using Builders = std::vector; // Abstract class to represent memory that stored _somewhere_ (in system memory or in a file, for example) class Storage : public std::enable_shared_from_this { diff --git a/tools/gpu-frame-player/src/PlayerWindow.cpp b/tools/gpu-frame-player/src/PlayerWindow.cpp index db8d8e0f4d..8e7f730181 100644 --- a/tools/gpu-frame-player/src/PlayerWindow.cpp +++ b/tools/gpu-frame-player/src/PlayerWindow.cpp @@ -106,19 +106,8 @@ void PlayerWindow::resizeEvent(QResizeEvent* ev) { _renderThread.resize(ev->size()); } -void PlayerWindow::textureLoader(const std::vector& imageBytes, const gpu::TexturePointer& texture, uint16_t layer) { - QImage image; - QByteArray bytes{ (const char*)imageBytes.data(), (int)imageBytes.size() }; - QBuffer bytesBuffer(&bytes); - QImageReader(&bytesBuffer).read(&image); - if (layer > 0) { - return; - } - texture->assignStoredMip(0, image.byteCount(), image.constBits()); -} - void PlayerWindow::loadFrame(const QString& path) { - auto frame = gpu::readFrame(path.toStdString(), _renderThread._externalTexture, &PlayerWindow::textureLoader); + auto frame = gpu::readFrame(path.toStdString(), _renderThread._externalTexture); if (frame) { _renderThread.submitFrame(frame); if (!_renderThread.isThreaded()) { From d69a83a2f2985da22fb9aeda0c4619f2d608525f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 18:20:10 -0700 Subject: [PATCH 11/12] fix warnings --- .../display-plugins/OpenGLDisplayPlugin.cpp | 2 - libraries/gpu/src/gpu/FrameIO.h | 2 +- libraries/gpu/src/gpu/FrameIOKeys.h | 238 +++++++++--------- 3 files changed, 120 insertions(+), 122 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 6ca11688a2..55a15dadf0 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -517,8 +517,6 @@ ktx::StoragePointer textureToKtx(const gpu::Texture& texture) { void OpenGLDisplayPlugin::captureFrame(const std::string& filename) const { withOtherThreadContext([&] { using namespace gpu; - auto glBackend = const_cast(*this).getGLBackend(); - FramebufferPointer framebuffer{ Framebuffer::create("captureFramebuffer") }; TextureCapturer captureLambda = [&](const gpu::TexturePointer& texture)->storage::StoragePointer { return textureToKtx(*texture); }; diff --git a/libraries/gpu/src/gpu/FrameIO.h b/libraries/gpu/src/gpu/FrameIO.h index 77602ef4e8..cf653cc4ae 100644 --- a/libraries/gpu/src/gpu/FrameIO.h +++ b/libraries/gpu/src/gpu/FrameIO.h @@ -29,7 +29,7 @@ using Storage = storage::Storage; using StoragePointer = storage::Pointer; using StorageBuilders = storage::Builders; -constexpr char* const EXTENSION{ ".hfb" }; +constexpr const char* const EXTENSION{ ".hfb" }; constexpr uint32_t HEADER_SIZE{ sizeof(uint32_t) * 3 }; constexpr uint32_t CHUNK_HEADER_SIZE = sizeof(uint32_t) * 2; constexpr uint32_t MAGIC{ 0x49464948 }; diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index ba523386e0..1a98d0decd 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -12,129 +12,129 @@ namespace gpu { namespace keys { -constexpr char* const binary = "binary"; -constexpr char* const L00 = "L00"; -constexpr char* const L1m1 = "L1m1"; -constexpr char* const L10 = "L10"; -constexpr char* const L11 = "L11"; -constexpr char* const L2m2 = "L2m2"; -constexpr char* const L2m1 = "L2m1"; -constexpr char* const L20 = "L20"; -constexpr char* const L21 = "L21"; -constexpr char* const L22 = "L22"; +constexpr const char* binary = "binary"; +constexpr const char* L00 = "L00"; +constexpr const char* L1m1 = "L1m1"; +constexpr const char* L10 = "L10"; +constexpr const char* L11 = "L11"; +constexpr const char* L2m2 = "L2m2"; +constexpr const char* L2m1 = "L2m1"; +constexpr const char* L20 = "L20"; +constexpr const char* L21 = "L21"; +constexpr const char* L22 = "L22"; -constexpr char* const eyeProjections = "eyeProjections"; -constexpr char* const eyeViews = "eyeViews"; -constexpr char* const alphaToCoverageEnable = "alphaToCoverageEnable"; -constexpr char* const antialisedLineEnable = "antialisedLineEnable"; -constexpr char* const attributes = "attributes"; -constexpr char* const batches = "batches"; -constexpr char* const blendFunction = "blendFunction"; -constexpr char* const borderColor = "borderColor"; -constexpr char* const bufferMask = "bufferMask"; -constexpr char* const buffers = "buffers"; -constexpr char* const capturedTextures = "capturedTextures"; -constexpr char* const channel = "channel"; -constexpr char* const chunk = "chunk"; -constexpr char* const colorAttachments = "colorAttachments"; -constexpr char* const colorWriteMask = "colorWriteMask"; -constexpr char* const commands = "commands"; -constexpr char* const comparisonFunction = "comparisonFunction"; -constexpr char* const cullMode = "cullMode"; -constexpr char* const data = "data"; -constexpr char* const depth = "depth"; -constexpr char* const depthBias = "depthBias"; -constexpr char* const depthBiasSlopeScale = "depthBiasSlopeScale"; -constexpr char* const depthClampEnable = "depthClampEnable"; -constexpr char* const depthStencilAttachment = "depthStencilAttachment"; -constexpr char* const depthTest = "depthTest"; -constexpr char* const drawCallInfos = "drawCallInfos"; -constexpr char* const drawcallUniform = "drawcallUniform"; -constexpr char* const drawcallUniformReset = "drawcallUniformReset"; -constexpr char* const element = "element"; -constexpr char* const fillMode = "fillMode"; -constexpr char* const filter = "filter"; -constexpr char* const formats = "formats"; -constexpr char* const frameIndex = "frameIndex"; -constexpr char* const framebuffer = "framebuffer"; -constexpr char* const framebuffers = "framebuffers"; -constexpr char* const frequency = "frequency"; -constexpr char* const frontFaceClockwise = "frontFaceClockwise"; -constexpr char* const height = "height"; -constexpr char* const id = "id"; -constexpr char* const ktxFile = "ktxFile"; -constexpr char* const layers = "layers"; -constexpr char* const maxAnisotropy = "maxAnisotropy"; -constexpr char* const maxMip = "maxMip"; -constexpr char* const minMip = "minMip"; -constexpr char* const mipOffset = "mipOffset"; -constexpr char* const mips = "mips"; -constexpr char* const multisampleEnable = "multisampleEnable"; -constexpr char* const name = "name"; -constexpr char* const namedData = "namedData"; -constexpr char* const names = "names"; -constexpr char* const objects = "objects"; -constexpr char* const offset = "offset"; -constexpr char* const pipelines = "pipelines"; -constexpr char* const pose = "pose"; -constexpr char* const profileRanges = "profileRanges"; -constexpr char* const program = "program"; -constexpr char* const programs = "programs"; -constexpr char* const projectionJitter = "projectionJitter"; -constexpr char* const queries = "queries"; -constexpr char* const sampleCount = "sampleCount"; -constexpr char* const sampleMask = "sampleMask"; -constexpr char* const sampler = "sampler"; -constexpr char* const samples = "samples"; -constexpr char* const scissorEnable = "scissorEnable"; -constexpr char* const shaders = "shaders"; -constexpr char* const size = "size"; -constexpr char* const skybox = "skybox"; -constexpr char* const slot = "slot"; -constexpr char* const source = "source"; -constexpr char* const state = "state"; -constexpr char* const stencilActivation = "stencilActivation"; -constexpr char* const stencilTestBack = "stencilTestBack"; -constexpr char* const stencilTestFront = "stencilTestFront"; -constexpr char* const stereo = "stereo"; -constexpr char* const subresource = "subresource"; -constexpr char* const swapchains = "swapchains"; -constexpr char* const texelFormat = "texelFormat"; -constexpr char* const texture = "texture"; -constexpr char* const textureTables = "textureTables"; -constexpr char* const textures = "textures"; -constexpr char* const transforms = "transforms"; -constexpr char* const type = "type"; -constexpr char* const usageType = "usageType"; -constexpr char* const view = "view"; -constexpr char* const width = "width"; -constexpr char* const wrapModeU = "wrapModeU"; -constexpr char* const wrapModeV = "wrapModeV"; -constexpr char* const wrapModeW = "wrapModeW"; +constexpr const char* eyeProjections = "eyeProjections"; +constexpr const char* eyeViews = "eyeViews"; +constexpr const char* alphaToCoverageEnable = "alphaToCoverageEnable"; +constexpr const char* antialisedLineEnable = "antialisedLineEnable"; +constexpr const char* attributes = "attributes"; +constexpr const char* batches = "batches"; +constexpr const char* blendFunction = "blendFunction"; +constexpr const char* borderColor = "borderColor"; +constexpr const char* bufferMask = "bufferMask"; +constexpr const char* buffers = "buffers"; +constexpr const char* capturedTextures = "capturedTextures"; +constexpr const char* channel = "channel"; +constexpr const char* chunk = "chunk"; +constexpr const char* colorAttachments = "colorAttachments"; +constexpr const char* colorWriteMask = "colorWriteMask"; +constexpr const char* commands = "commands"; +constexpr const char* comparisonFunction = "comparisonFunction"; +constexpr const char* cullMode = "cullMode"; +constexpr const char* data = "data"; +constexpr const char* depth = "depth"; +constexpr const char* depthBias = "depthBias"; +constexpr const char* depthBiasSlopeScale = "depthBiasSlopeScale"; +constexpr const char* depthClampEnable = "depthClampEnable"; +constexpr const char* depthStencilAttachment = "depthStencilAttachment"; +constexpr const char* depthTest = "depthTest"; +constexpr const char* drawCallInfos = "drawCallInfos"; +constexpr const char* drawcallUniform = "drawcallUniform"; +constexpr const char* drawcallUniformReset = "drawcallUniformReset"; +constexpr const char* element = "element"; +constexpr const char* fillMode = "fillMode"; +constexpr const char* filter = "filter"; +constexpr const char* formats = "formats"; +constexpr const char* frameIndex = "frameIndex"; +constexpr const char* framebuffer = "framebuffer"; +constexpr const char* framebuffers = "framebuffers"; +constexpr const char* frequency = "frequency"; +constexpr const char* frontFaceClockwise = "frontFaceClockwise"; +constexpr const char* height = "height"; +constexpr const char* id = "id"; +constexpr const char* ktxFile = "ktxFile"; +constexpr const char* layers = "layers"; +constexpr const char* maxAnisotropy = "maxAnisotropy"; +constexpr const char* maxMip = "maxMip"; +constexpr const char* minMip = "minMip"; +constexpr const char* mipOffset = "mipOffset"; +constexpr const char* mips = "mips"; +constexpr const char* multisampleEnable = "multisampleEnable"; +constexpr const char* name = "name"; +constexpr const char* namedData = "namedData"; +constexpr const char* names = "names"; +constexpr const char* objects = "objects"; +constexpr const char* offset = "offset"; +constexpr const char* pipelines = "pipelines"; +constexpr const char* pose = "pose"; +constexpr const char* profileRanges = "profileRanges"; +constexpr const char* program = "program"; +constexpr const char* programs = "programs"; +constexpr const char* projectionJitter = "projectionJitter"; +constexpr const char* queries = "queries"; +constexpr const char* sampleCount = "sampleCount"; +constexpr const char* sampleMask = "sampleMask"; +constexpr const char* sampler = "sampler"; +constexpr const char* samples = "samples"; +constexpr const char* scissorEnable = "scissorEnable"; +constexpr const char* shaders = "shaders"; +constexpr const char* size = "size"; +constexpr const char* skybox = "skybox"; +constexpr const char* slot = "slot"; +constexpr const char* source = "source"; +constexpr const char* state = "state"; +constexpr const char* stencilActivation = "stencilActivation"; +constexpr const char* stencilTestBack = "stencilTestBack"; +constexpr const char* stencilTestFront = "stencilTestFront"; +constexpr const char* stereo = "stereo"; +constexpr const char* subresource = "subresource"; +constexpr const char* swapchains = "swapchains"; +constexpr const char* texelFormat = "texelFormat"; +constexpr const char* texture = "texture"; +constexpr const char* textureTables = "textureTables"; +constexpr const char* textures = "textures"; +constexpr const char* transforms = "transforms"; +constexpr const char* type = "type"; +constexpr const char* usageType = "usageType"; +constexpr const char* view = "view"; +constexpr const char* width = "width"; +constexpr const char* wrapModeU = "wrapModeU"; +constexpr const char* wrapModeV = "wrapModeV"; +constexpr const char* wrapModeW = "wrapModeW"; -constexpr char* const backWriteMask = "backWriteMask"; -constexpr char* const frontWriteMask = "frontWriteMask"; -constexpr char* const reference = "reference"; -constexpr char* const readMask = "readMask"; -constexpr char* const failOp = "failOp"; -constexpr char* const depthFailOp = "depthFailOp"; -constexpr char* const passOp = "passOp"; -constexpr char* const enabled = "enabled"; -constexpr char* const blend = "blend"; -constexpr char* const flags = "flags"; -constexpr char* const writeMask = "writeMask"; -constexpr char* const function = "function"; -constexpr char* const sourceColor = "sourceColor"; -constexpr char* const sourceAlpha = "sourceAlpha"; -constexpr char* const destColor = "destColor"; -constexpr char* const destAlpha = "destAlpha"; -constexpr char* const opColor = "opColor"; -constexpr char* const opAlpha = "opAlpha"; -constexpr char* const enable = "enable"; -constexpr char* const contextDisable = "contextDisable"; +constexpr const char* backWriteMask = "backWriteMask"; +constexpr const char* frontWriteMask = "frontWriteMask"; +constexpr const char* reference = "reference"; +constexpr const char* readMask = "readMask"; +constexpr const char* failOp = "failOp"; +constexpr const char* depthFailOp = "depthFailOp"; +constexpr const char* passOp = "passOp"; +constexpr const char* enabled = "enabled"; +constexpr const char* blend = "blend"; +constexpr const char* flags = "flags"; +constexpr const char* writeMask = "writeMask"; +constexpr const char* function = "function"; +constexpr const char* sourceColor = "sourceColor"; +constexpr const char* sourceAlpha = "sourceAlpha"; +constexpr const char* destColor = "destColor"; +constexpr const char* destAlpha = "destAlpha"; +constexpr const char* opColor = "opColor"; +constexpr const char* opAlpha = "opAlpha"; +constexpr const char* enable = "enable"; +constexpr const char* contextDisable = "contextDisable"; -constexpr char* const COMMAND_NAMES[] = { +constexpr const char* COMMAND_NAMES[] = { "draw", "drawIndexed", "drawInstanced", From b2bcf54b5b0cbcc9f025cfb224df4e9324299b20 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Oct 2019 19:52:55 -0700 Subject: [PATCH 12/12] Removing frame converter --- tools/CMakeLists.txt | 1 - tools/gpu-frame-converter/CMakeLists.txt | 9 -- tools/gpu-frame-converter/src/main.cpp | 104 ----------------------- 3 files changed, 114 deletions(-) delete mode 100644 tools/gpu-frame-converter/CMakeLists.txt delete mode 100644 tools/gpu-frame-converter/src/main.cpp diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6f9145ff7d..4942ecbd63 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -23,7 +23,6 @@ if (BUILD_TOOLS) udt-test vhacd-util gpu-frame-player - gpu-frame-converter ice-client ktx-tool ac-client diff --git a/tools/gpu-frame-converter/CMakeLists.txt b/tools/gpu-frame-converter/CMakeLists.txt deleted file mode 100644 index 4c2a2f5546..0000000000 --- a/tools/gpu-frame-converter/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ - -if (WIN32) - set(TARGET_NAME gpu-frame-converter) - setup_memory_debugger() - setup_hifi_project() - set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17) - link_hifi_libraries( shared gpu shaders ) - package_libraries_for_deployment() -endif() \ No newline at end of file diff --git a/tools/gpu-frame-converter/src/main.cpp b/tools/gpu-frame-converter/src/main.cpp deleted file mode 100644 index 15aeafffb5..0000000000 --- a/tools/gpu-frame-converter/src/main.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -// Created by Bradley Austin Davis on 2019/10/03 -// Copyright 2013-2019 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace fs = std::filesystem; -using Json = nlohmann::json; -using Paths = std::vector; - -const char* DEFAULT_SOURCE_PATH{ "D:/Frames" }; -static const std::string OLD_FRAME_EXTENSION{ ".json" }; -static const std::string OLD_BINARY_EXTENSION{ ".bin" }; -static const std::string NEW_EXTENSION{ gpu::hfb::EXTENSION }; - -inline std::string readFileToString(const fs::path& path) { - std::ifstream file(path); - return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); -} - -inline gpu::hfb::Buffer readFile(const fs::path& path) { - std::ifstream file(path, std::ios::binary | std::ios::ate); - size_t size = file.tellg(); - if (!size) { - return {}; - } - file.seekg(0, std::ios::beg); - - gpu::hfb::Buffer result; - result.resize(size); - if (!file.read((char*)result.data(), size)) { - throw std::runtime_error("Failed to read file"); - } - return result; -} - -Paths getFrames(const std::string& sourcePath) { - Paths result; - for (auto& p : fs::directory_iterator(sourcePath)) { - if (!p.is_regular_file()) { - continue; - } - const auto& path = p.path(); - if (path.string().find(".hfb.json") != std::string::npos) { - continue; - } - if (path.extension().string() == OLD_FRAME_EXTENSION) { - result.push_back(path); - } - } - return result; -} - -void convertFrame(const fs::path& path) { - auto name = path.filename().string(); - name = name.substr(0, name.length() - OLD_FRAME_EXTENSION.length()); - - auto frameNode = Json::parse(readFileToString(path)); - auto capturedTexturesNode = frameNode[gpu::keys::capturedTextures]; - - gpu::hfb::Buffer binary = readFile(path.parent_path() / (name + OLD_BINARY_EXTENSION)); - gpu::hfb::Buffers pngs; - for (const auto& capturedTextureIndexNode : capturedTexturesNode) { - int index = capturedTextureIndexNode; - auto imageFile = path.parent_path() / (name + "." + std::to_string(index) + ".0.png"); - frameNode[gpu::keys::textures][index][gpu::keys::chunk] = 2 + pngs.size(); - pngs.push_back(readFile(imageFile)); - } - frameNode.erase(gpu::keys::capturedTextures); - auto outputPath = path.parent_path() / (name + NEW_EXTENSION); - { - auto jsonOutputPath = path.parent_path() / (name + ".hfb.json"); - std::ofstream of(jsonOutputPath); - auto str = frameNode.dump(2); - of.write(str.data(), str.size()); - } - gpu::hfb::writeFrame(outputPath.string(), frameNode.dump(), binary, pngs); - { - auto frameBuffer = readFile(outputPath.string()); - auto descriptor = gpu::hfb::Descriptor::parse(frameBuffer.data(), frameBuffer.size()); - std::cout << descriptor.header.magic << std::endl; - } -} - -int main(int argc, char** argv) { - for (const auto& framePath : getFrames(DEFAULT_SOURCE_PATH)) { - std::cout << framePath << std::endl; - convertFrame(framePath); - } - return 0; -}