diff --git a/libs/matdbg/CMakeLists.txt b/libs/matdbg/CMakeLists.txt index e5805854808d..566aec3fd31e 100644 --- a/libs/matdbg/CMakeLists.txt +++ b/libs/matdbg/CMakeLists.txt @@ -31,6 +31,8 @@ set(SRCS src/ShaderReplacer.cpp src/ShaderExtractor.cpp src/ShaderInfo.cpp + src/SourceFormatter.cpp + src/SourceFormatter.h src/TextWriter.cpp ) diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index 82e27fa53ac7..c9ef42c0ee0b 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -43,19 +43,6 @@ namespace { auto const& kSuccessHeader = DebugServer::kSuccessHeader; auto const& kErrorHeader = DebugServer::kErrorHeader; -void spirvToAsm(struct mg_connection* conn, uint32_t const* spirv, size_t size) { - auto spirvDisassembly = ShaderExtractor::spirvToText(spirv, size / 4); - mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size()); -} - -void spirvToGlsl(ShaderModel shaderModel, struct mg_connection* conn, uint32_t const* spirv, - size_t size) { - auto glsl = ShaderExtractor::spirvToGLSL(shaderModel, spirv, size / 4); - mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_printf(conn, glsl.c_str(), glsl.size()); -} - } // anonymous using filaflat::ChunkContainer; @@ -145,8 +132,10 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, filaflat::ShaderContent content; extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); + std::string const shader = mFormatter.format((char const*) content.data()); mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, content.data(), content.size() - 1); + mg_write(conn, shader.c_str(), shader.size()); + return true; } @@ -171,12 +160,19 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); if (language == spirv) { - spirvToAsm(conn, (uint32_t const*) content.data(), content.size()); + auto spirvDisassembly = ShaderExtractor::spirvToText((uint32_t const*) content.data(), + content.size() / 4); + mg_printf(conn, kSuccessHeader.data(), "application/txt"); + mg_write(conn, spirvDisassembly.c_str(), spirvDisassembly.size()); return true; } if (language == glsl) { - spirvToGlsl(item.shaderModel, conn, (uint32_t const*) content.data(), content.size()); + auto glsl = ShaderExtractor::spirvToGLSL(item.shaderModel, + (uint32_t const*) content.data(), content.size() / 4); + std::string const shader = mFormatter.format((char const*) glsl.c_str()); + mg_printf(conn, kSuccessHeader.data(), "application/txt"); + mg_printf(conn, shader.c_str(), shader.size()); return true; } @@ -204,8 +200,9 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, extractor.getShader(item.shaderModel, item.variant, item.pipelineStage, content); if (language == msl) { + std::string const shader = mFormatter.format((char const*) content.data()); mg_printf(conn, kSuccessHeader.data(), "application/txt"); - mg_write(conn, content.data(), content.size() - 1); + mg_write(conn, shader.c_str(), shader.size()); return true; } diff --git a/libs/matdbg/src/ApiHandler.h b/libs/matdbg/src/ApiHandler.h index 81aaa7c734c5..353326a7dc7d 100644 --- a/libs/matdbg/src/ApiHandler.h +++ b/libs/matdbg/src/ApiHandler.h @@ -17,6 +17,8 @@ #ifndef MATDBG_APIHANDLER_H #define MATDBG_APIHANDLER_H +#include "SourceFormatter.h" + #include #include #include @@ -63,6 +65,8 @@ class ApiHandler : public CivetHandler { // will always block until statusMaterialId is updated again. The client is expected to keep // calling /api/status (a constant "pull" to simulate a push). std::atomic mCurrentStatus = 0; + + SourceFormatter mFormatter; }; } // filament::matdbg diff --git a/libs/matdbg/src/SourceFormatter.cpp b/libs/matdbg/src/SourceFormatter.cpp new file mode 100644 index 000000000000..c068a34f4b43 --- /dev/null +++ b/libs/matdbg/src/SourceFormatter.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SourceFormatter.h" + +#include + +#include +#include + +namespace filament::matdbg { + +#if defined(__linux__) || defined(__APPLE__) +std::string SourceFormatter::format(char const* source) { + std::string const TMP_FILENAME = "/tmp/matdbg-tmp-src.cpp"; + + std::string original(source); + FILE* fp; + fp = fopen(TMP_FILENAME.c_str(), "w"); + if (!fp) { + return original; + } + fputs(original.c_str(), fp); + fflush(fp); + pclose(fp); + + std::string const CLANG_FORMAT_OPTIONS = + "-style='{" + "BasedOnStyle: Google, " + "IndentWidth: 4, " + "MaxEmptyLinesToKeep: 2" + "}'"; + + fp = popen(("clang-format " + CLANG_FORMAT_OPTIONS + "< " + TMP_FILENAME).c_str(), "r"); + + if (!fp) { + std::call_once(mClangWarningFlag, []() { + utils::slog.w << "[matdbg] unable to run clang-format to format shader file. " + << "Please make sure it's installed."; + }); + return original; + } + + char output[1024]; + std::stringstream outStream; + while (fgets(output, 1024, fp) != NULL) { + outStream << output; + } + + int status = pclose(fp); + if (WEXITSTATUS(status)) { + utils::slog.w << "[matdbg] clang-format failed with code=" << WEXITSTATUS(status) + << utils::io::endl; + } + return outStream.str(); +} +#else +std::string SourceFormatter::format(char const* source) { + std::call_once(mClangWarningFlag, []() { + utils::slog.w <<"[matdbg]: source formatting is not available on this platform" << + utils::io::endl; + }); + return ""; +} +#endif + +} // filament::matdbg diff --git a/libs/matdbg/src/SourceFormatter.h b/libs/matdbg/src/SourceFormatter.h new file mode 100644 index 000000000000..5793474d7168 --- /dev/null +++ b/libs/matdbg/src/SourceFormatter.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MATDBG_SOURCE_FORMATTER_H +#define MATDBG_SOURCE_FORMATTER_H + +#include + +namespace filament::matdbg { + +class SourceFormatter { +public: + SourceFormatter() = default; + ~SourceFormatter() = default; + std::string format(char const* source); + +private: + + std::once_flag mClangWarningFlag; +}; + +} // filament::matdbg + +#endif // MATDBG_SOURCE_FORMATTER_H