From e825f439358d2c33ac7054bc5fa54afa816f0e2c Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Fri, 7 Mar 2025 15:54:22 -0800 Subject: [PATCH] matdbg: indicate shader model (#8504) Shader model (desktop or mobile) wasn't really accounted for in the UI. This means that we will get shaders that look like duplicates (same variant). In this work, we pass the current shader model from engine into the frontend and filter out variants of a different shader model. Moreover, for matinfo, we use a specific dbg shader model (matinfo) to indicate it is in that mode. We add UI in matinfo to show the shadermodel. So UI updates as well. --- filament/src/details/Engine.cpp | 3 +- libs/matdbg/include/matdbg/DebugServer.h | 18 ++++- libs/matdbg/include/matdbg/JsonWriter.h | 5 +- libs/matdbg/src/ApiHandler.cpp | 37 +++++----- libs/matdbg/src/DebugServer.cpp | 7 +- libs/matdbg/src/JsonWriter.cpp | 15 +++- libs/matdbg/src/ShaderInfo.cpp | 1 - libs/matdbg/web/api.js | 7 +- libs/matdbg/web/app.js | 90 ++++++++++++++++-------- tools/matinfo/src/main.cpp | 2 +- 10 files changed, 123 insertions(+), 62 deletions(-) diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 01cc8ec9be..741e2b3b62 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -751,7 +751,8 @@ int FEngine::loop() { #endif if (portString != nullptr) { const int port = atoi(portString); - debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), port); + debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), + matdbg::DbgShaderModel((uint8_t) mDriver->getShaderModel()), port); // Sometimes the server can fail to spin up (e.g. if the above port is already in use). // When this occurs, carry onward, developers can look at civetweb.txt for details. diff --git a/libs/matdbg/include/matdbg/DebugServer.h b/libs/matdbg/include/matdbg/DebugServer.h index 86aaa79bd1..272d68ab28 100644 --- a/libs/matdbg/include/matdbg/DebugServer.h +++ b/libs/matdbg/include/matdbg/DebugServer.h @@ -41,6 +41,13 @@ struct MaterialRecord { VariantList activeVariants; }; +// Matches DriverEnums' ShaderModel +enum class DbgShaderModel { + MOBILE = 1, //!< Mobile level functionality + DESKTOP = 2, //!< Desktop level functionality + MATINFO = 10, //!< To indicate debug server is running from matinfo +}; + /** * Server-side material debugger. * @@ -52,7 +59,8 @@ public: static std::string_view const kSuccessHeader; static std::string_view const kErrorHeader; - DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port); + DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, + DbgShaderModel perferredShaderModel, int port); ~DebugServer(); /** @@ -85,10 +93,13 @@ public: bool isReady() const { return mServer; } private: + // called from ApiHandler MaterialRecord const* getRecord(const MaterialKey& key) const; + // called from ApiHandler void updateActiveVariants(); + // called from ApiHandler /** * Replaces the entire content of a particular shader variant. The given shader index uses the * same ordering that the variants have within the package. @@ -96,8 +107,9 @@ private: bool handleEditCommand(const MaterialKey& mat, backend::Backend api, int shaderIndex, const char* newShaderContent, size_t newShaderLength); - const backend::Backend mBackend; - const backend::ShaderLanguage mShaderLanguage; + backend::Backend const mBackend; + backend::ShaderLanguage const mShaderLanguage; + DbgShaderModel const mPreferredShaderModel; CivetServer* mServer; diff --git a/libs/matdbg/include/matdbg/JsonWriter.h b/libs/matdbg/include/matdbg/JsonWriter.h index 4291f6f749..f1ff7f7aae 100644 --- a/libs/matdbg/include/matdbg/JsonWriter.h +++ b/libs/matdbg/include/matdbg/JsonWriter.h @@ -17,6 +17,8 @@ #ifndef MATDBG_JSONWRITER_H #define MATDBG_JSONWRITER_H +#include + #include #include @@ -47,7 +49,8 @@ public: // shader index is an active variant. Each bit in the activeVariants bitmask // represents one of the possible variant combinations. bool writeActiveInfo(const filaflat::ChunkContainer& package, - backend::ShaderLanguage shaderLanguage, VariantList activeVariants); + backend::ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, + VariantList activeVariants); private: utils::CString mJsonString; diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index 3c53265317..fb3c0673aa 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -332,7 +332,8 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return error(__LINE__, uri); } JsonWriter writer; - if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) { + if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, + mServer->mPreferredShaderModel, record.activeVariants)) { return error(__LINE__, uri); } bool const last = (++index) == mServer->mMaterialRecords.size(); @@ -356,6 +357,18 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return true; } + auto writeMaterialRecord = [&](JsonWriter* writer, MaterialRecord const* record) { + ChunkContainer package(record->package, record->packageSize); + if (!package.parse()) { + return error(__LINE__, uri); + } + + if (!writer->writeMaterialInfo(package)) { + return error(__LINE__, uri); + } + return true; + }; + if (uri == "/api/materials") { std::unique_lock const lock(mServer->mMaterialRecordsMutex); mg_printf(conn, kSuccessHeader.data(), "application/json"); @@ -363,17 +376,11 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { int index = 0; for (auto const& record: mServer->mMaterialRecords) { bool const last = (++index) == mServer->mMaterialRecords.size(); - - ChunkContainer package(record.second.package, record.second.packageSize); - if (!package.parse()) { - return error(__LINE__, uri); - } - + auto const& mat = record.second; JsonWriter writer; - if (!writer.writeMaterialInfo(package)) { - return error(__LINE__, uri); + if (!writeMaterialRecord(&writer, &mat)) { + return false; } - mg_printf(conn, "{ \"matid\": \"%8.8x\", %s } %s", record.first, writer.getJsonString(), last ? "" : ","); } @@ -386,15 +393,9 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { if (!result) { return error(__LINE__, uri); } - - ChunkContainer package(result->package, result->packageSize); - if (!package.parse()) { - return error(__LINE__, uri); - } - JsonWriter writer; - if (!writer.writeMaterialInfo(package)) { - return error(__LINE__, uri); + if (!writeMaterialRecord(&writer, result)) { + return false; } mg_printf(conn, kSuccessHeader.data(), "application/json"); mg_printf(conn, "{ %s }", writer.getJsonString()); diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index d75952728b..9285bc38c5 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -122,8 +122,11 @@ private: DebugServer* mServer; }; -DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port) - : mBackend(backend), mShaderLanguage(shaderLanguage) { +DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, + DbgShaderModel perferredShaderModel, int port) + : mBackend(backend), + mShaderLanguage(shaderLanguage), + mPreferredShaderModel(perferredShaderModel) { #if !SERVE_FROM_SOURCE_TREE ASSET_MAP["/index.html"] = { diff --git a/libs/matdbg/src/JsonWriter.cpp b/libs/matdbg/src/JsonWriter.cpp index 2a22eaeae2..7a5409927b 100644 --- a/libs/matdbg/src/JsonWriter.cpp +++ b/libs/matdbg/src/JsonWriter.cpp @@ -232,7 +232,7 @@ size_t JsonWriter::getJsonSize() const { } bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, - ShaderLanguage shaderLanguage, VariantList activeVariants) { + ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, VariantList activeVariants) { vector shaders; ostringstream json; json << "[\""; @@ -260,7 +260,20 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, shaders.resize(getShaderCount(package, chunkType)); getShaderInfo(package, shaders.data(), chunkType); + json << "\", \""; + switch (shaderModel) { + case DbgShaderModel::DESKTOP: + json << toString(ShaderModel::DESKTOP); + break; + case DbgShaderModel::MOBILE: + json << toString(ShaderModel::MOBILE); + break; + case DbgShaderModel::MATINFO: + json << "matinfo"; + break; + } json << "\""; + for (size_t variant = 0; variant < activeVariants.size(); variant++) { if (activeVariants[variant]) { json << ", " << variant; diff --git a/libs/matdbg/src/ShaderInfo.cpp b/libs/matdbg/src/ShaderInfo.cpp index 632c20d711..320e1b383a 100644 --- a/libs/matdbg/src/ShaderInfo.cpp +++ b/libs/matdbg/src/ShaderInfo.cpp @@ -50,7 +50,6 @@ size_t getShaderCount(const ChunkContainer& container, ChunkType type) { return shaderCount; } - bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType chunkType) { if (!container.hasChunk(chunkType)) { return true; diff --git a/libs/matdbg/web/api.js b/libs/matdbg/web/api.js index a6e62f788d..79eedf78bc 100644 --- a/libs/matdbg/web/api.js +++ b/libs/matdbg/web/api.js @@ -72,10 +72,9 @@ async function queryActiveShaders() { const actives = {}; for (matid in activeVariants) { const backend = activeVariants[matid][0]; - const variants = activeVariants[matid].slice(1); - actives[matid] = { - backend, variants - }; + const shaderModel = activeVariants[matid][1]; + const variants = activeVariants[matid].slice(2); + actives[matid] = { backend, shaderModel, variants }; } return actives; } diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index e9bad73a01..56a85d7230 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -59,8 +59,8 @@ const FOREGROUND_COLOR = '#fafafa'; const INACTIVE_COLOR = '#9a9a9a'; const DARKER_INACTIVE_COLOR = '#6f6f6f'; const LIGHTER_INACTIVE_COLOR = '#d9d9d9'; -const UNSELECTED_COLOR = '#dfdfdf'; -const BACKGROUND_COLOR = '#5362e5'; +const UNSELECTED_COLOR = '#d0d0d0'; +const BACKGROUND_COLOR = '#6885c5'; const HOVER_BACKGROUND_COLOR = '#b3c2ff'; const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60; const REGULAR_FONT_SIZE = 12; @@ -343,7 +343,7 @@ class MenuSection extends LitElement { color: ${unsafeCSS(UNSELECTED_COLOR)}; } .section-title { - font-size: 16px; + font-size: 20px; color: ${unsafeCSS(UNSELECTED_COLOR)}; cursor: pointer; } @@ -365,6 +365,9 @@ class MenuSection extends LitElement { align-items: center; justify-content: space-between; } + .expanded-title { + color: ${unsafeCSS(FOREGROUND_COLOR)}; + } `; } @@ -380,9 +383,10 @@ class MenuSection extends LitElement { render() { const expandedIcon = this.showing ? '๏ผ' : '๏ผ‹'; const slot = (() => html``)(); + const epandedTitleClass = this.showing ? 'expanded-title' : ''; return html`
-
+
${this.title} ${expandedIcon}

@@ -460,6 +464,7 @@ class AdvancedOptions extends LitElement { static get properties() { return { currentBackend: {type: String, attribute: 'current-backend'}, + currentShaderModel: {type: String, attribute: 'current-shader-model'}, hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'}, availableBackends: {type: Array, state: true}, }; @@ -478,6 +483,7 @@ class AdvancedOptions extends LitElement { flex-direction: column; justify-content: center; align-items: flex-start; + margin-bottom: 6px; } .borderless { border: 1px solid rgba(0,0,0,0); @@ -570,7 +576,7 @@ class AdvancedOptions extends LitElement { return html`
Current Backend
-
+ ${div}
@@ -578,6 +584,9 @@ class AdvancedOptions extends LitElement { } _hideInactiveVariantsOption() { + if (this.currentShaderModel == 'matinfo') { + return null; + } const onChange = (ev) => { this.dispatchEvent( new CustomEvent( @@ -585,7 +594,7 @@ class AdvancedOptions extends LitElement { {detail: null, bubbles: true, composed: true})); } return html` -
+
${languagesDiv}
`; } - _buildShaderDiv(showAllShaders) { + _buildShaderDiv() { if (!this.variants) { return null; } + const isMatinfo = this.currentShaderModel == 'matinfo'; let variants = this.variants .sort((a, b) => { @@ -798,7 +809,10 @@ class MaterialSidePanel extends LitElement { if (b.active && !a.active) return 1; return 0; }) - .filter((variant) => (!this.hideInactiveVariants || variant.shader.active)) + .filter(variant => (!this.hideInactiveVariants || variant.shader.active)) + .filter(variant => ( + isMatinfo || variant.shader.shaderModel == this.currentShaderModel + )) .map((variant) => { let divClass = 'material_variant_language'; const shaderIndex = +variant.shader.index; @@ -807,7 +821,7 @@ class MaterialSidePanel extends LitElement { if (isVariantSelected) { divClass += ' selected'; } - if (!isActive) { + if (!isActive && !isMatinfo) { divClass += ' inactive'; } const onClickVariant = this._handleVariantClick.bind(this, shaderIndex); @@ -816,11 +830,18 @@ class MaterialSidePanel extends LitElement { if (vstring.length > 0) { vstring = `[${vstring}]`; } + const shaderModelSymbol = { + 'desktop': '๐Ÿ„ณ ', + 'mobile': '๐Ÿ„ผ ', + }; + let languagesDiv = isVariantSelected ? this._buildLanguagesDiv(isActive) : null; - const stage = (isVariantSelected ? 'โ— ' : '') + variant.shader.pipelineStage; + const stage = + (isMatinfo ? shaderModelSymbol[variant.shader.shaderModel] : '') + + (variant.shader.pipelineStage.indexOf('vertex') >=0 ? '๐•ert' : '๐”ฝrag'); return html`
-
${stage} ${vstring}
+
${stage}  ${vstring}
${languagesDiv ?? nothing} ` @@ -829,6 +850,7 @@ class MaterialSidePanel extends LitElement { } render() { + const isMatinfo = this.currentShaderModel == 'matinfo'; const sections = (title, domain) => { const mats = this.materials .filter((m) => m.domain == domain) @@ -844,14 +866,12 @@ class MaterialSidePanel extends LitElement { const isMaterialSelected = mat.matid === this.currentMaterial; if (isMaterialSelected) { divClass += ' selected'; - // If we are looking at an inactive material, show all shaders regardless. - const showAllShaders = !material.active; - shaderDiv = this._buildShaderDiv(showAllShaders); + shaderDiv = this._buildShaderDiv(); } - if (!material.active) { + if (!material.active && !isMatinfo) { divClass += " inactive"; } - const matName = (isMaterialSelected ? 'โ— ' : '') + mat.name; + const matName = mat.name; return html`
${matName} @@ -868,6 +888,7 @@ class MaterialSidePanel extends LitElement { (() => html` `)(); @@ -875,7 +896,7 @@ class MaterialSidePanel extends LitElement { return html`
-
matdbg
+
${isMatinfo ? 'matinfo' : 'matdbg'}
${sections("Surface", "surface") ?? nothing} ${sections("Post-processing", "postpro") ?? nothing} @@ -968,6 +989,7 @@ class MatdbgViewer extends LitElement { this.currentMaterial = null; this.currentLanguage = null; this.currentBackend = null; + this.currentShaderModel = null; this.hideInactiveVariants = false; this.init(); @@ -1038,6 +1060,7 @@ class MatdbgViewer extends LitElement { // Each material has a list of variants compiled for it, this index tracks a position in the list. currentShaderIndex: {type: Number, state: true}, currentBackend: {type: String, state: true}, + currentShaderModel: {type: String, state: true}, codeViewerExpectedWidth: {type: Number, state: true}, codeViewerExpectedHeight: {type: Number, state: true}, @@ -1084,7 +1107,6 @@ class MatdbgViewer extends LitElement { shader.modified = false; this.database = this.database; } - // Size of the editor will be adjusted due to the code being loaded, we try to // fit the editor again by calling the resize signal. setTimeout(this._onResize.bind(this), 700); @@ -1108,22 +1130,29 @@ class MatdbgViewer extends LitElement { } } if (_validDict(this.activeShaders)) { - let backends = {}; + let setBackend = null; + let setShaderModel = null; for (let matid in this.activeShaders) { const backend = this.activeShaders[matid].backend; - if (backend in backends) { - backends[backend] = backends[backend] + 1; - } else { - backends[backend] = 1; + if (!setBackend && backend) { + setBackend = backend; + } + const shaderModel = this.activeShaders[matid].shaderModel; + if (!setShaderModel && shaderModel) { + setShaderModel = shaderModel; } } - let backendList = Object.keys(backends); - if (backendList.length > 0) { - this.currentBackend = backendList[0]; + if (this.currentBackend != setBackend) { + this.currentBackend = setBackend; } - } else if (!this.currentBackend) { + if (this.currentShaderModel != setShaderModel) { + this.currentShaderModel = setShaderModel; + } + + } else if (!this.currentBackend || !this.currentShaderModel) { // Make a guess on the backend if one wasn't from activeShaders. this.currentBackend = guessBackend(); + this.currentShaderModel = 'matinfo'; } this._sidepanel.database = this.database; @@ -1155,6 +1184,7 @@ class MatdbgViewer extends LitElement { current-shader-index="${this.currentShaderIndex}" current-material="${this.currentMaterial}" current-backend="${this.currentBackend}" + current-shader-model="${this.currentShaderModel}" ?hide-inactive-variants="${this.hideInactiveVariants}" >