From f6f84267b67ba6f6015ad82eb07e6736b3c6eb4e Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 7 Feb 2026 18:50:18 +0800 Subject: [PATCH 1/4] [Feat] (workflow): merge two workflows --- .github/workflows/build.yml | 136 ++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..65fa8487 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,136 @@ +name: Build-Test-Benchmark + +on: + push: + branches: + - dev + - Feat/Backend-Direct-GLES + +jobs: + build: + runs-on: ubuntu-latest + env: + BUILD_ROOT: ${{github.workspace}} + BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} + + steps: + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 32 + + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: true + + - name: Get CMake + uses: lukka/get-cmake@latest + + - name: Update glslang external sources + working-directory: ${{env.BUILD_ROOT}}/3rdparty/glslang + run: python update_glslang_sources.py + + - name: Install clang-20 + run: | + sudo apt-get update + sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev + + - name: Show installed toolchain + run: | + clang-20 --version + clang++-20 --version + ld.lld-20 --version || ld.lld --version || true + dpkg -l 'libc++*' || true + + - name: Configure CMake + working-directory: ${{env.BUILD_ROOT}} + run: | + cmake -S . -B build-ci -G Ninja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_ENABLE_TESTING=OFF -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_BENCHMARK=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + + - name: Build + working-directory: ${{env.BUILD_ROOT}}/build-ci + run: cmake --build . + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-ci + path: ${{env.BUILD_ROOT}}/build-ci + + test: + runs-on: ubuntu-latest + needs: build + env: + TEST_ROOT: ${{github.workspace}} + BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} + + steps: + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 32 + + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: true + + - name: Get CMake + uses: lukka/get-cmake@latest + + - name: Install clang-20 + run: | + sudo apt-get update + sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-ci + path: ${{env.TEST_ROOT}}/build-ci + + - name: Test + working-directory: ${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test + run: | + if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" == "true" ]; then + ctest -V + else + ctest + fi + + benchmark: + runs-on: ubuntu-latest + needs: build + env: + BENCH_ROOT: ${{github.workspace}} + BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} + + steps: + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 32 + + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: true + + - name: Get CMake + uses: lukka/get-cmake@latest + + - name: Install clang-20 + run: | + sudo apt-get update + sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-ci + path: ${{env.BENCH_ROOT}}/build-ci + + - name: Benchmark + working-directory: ${{env.BENCH_ROOT}}/build-ci/MobileGL/MG_Benchmark + run: ctest -V -C ${{env.BUILD_TYPE}} From a079e5e6b97dc696c989f1ef53f18dda421543bf Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 7 Feb 2026 19:15:45 +0800 Subject: [PATCH 2/4] [Debug] (workflow): checking inter-job artifact exchange --- .github/workflows/build.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65fa8487..3f34f8bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,12 +92,29 @@ jobs: - name: Test working-directory: ${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test + continue-on-error: true run: | if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" == "true" ]; then ctest -V else ctest fi + echo "CTEST_EXIT=$?" >> $GITHUB_ENV + + - name: Rerun failed tests with output + if: always() + working-directory: ${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test + run: | + ctest --rerun-failed --output-on-failure || true + + - name: Show LastTest.log + if: always() + run: | + cat "${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test/Testing/Temporary/LastTest.log" || true + + - name: Fail if tests failed + if: ${{ env.CTEST_EXIT != '' && env.CTEST_EXIT != '0' }} + run: exit ${{ env.CTEST_EXIT }} benchmark: runs-on: ubuntu-latest From 40333fa84ac19e91ac8cc58a554f6da5bd3554ca Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 7 Feb 2026 20:06:43 +0800 Subject: [PATCH 3/4] [Remove] (workflow): remove combined workflow --- .github/workflows/build.yml | 153 ------------------------------------ 1 file changed, 153 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 3f34f8bf..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,153 +0,0 @@ -name: Build-Test-Benchmark - -on: - push: - branches: - - dev - - Feat/Backend-Direct-GLES - -jobs: - build: - runs-on: ubuntu-latest - env: - BUILD_ROOT: ${{github.workspace}} - BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} - - steps: - - name: Set Swap Space - uses: pierotofy/set-swap-space@master - with: - swap-size-gb: 32 - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: true - - - name: Get CMake - uses: lukka/get-cmake@latest - - - name: Update glslang external sources - working-directory: ${{env.BUILD_ROOT}}/3rdparty/glslang - run: python update_glslang_sources.py - - - name: Install clang-20 - run: | - sudo apt-get update - sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev - - - name: Show installed toolchain - run: | - clang-20 --version - clang++-20 --version - ld.lld-20 --version || ld.lld --version || true - dpkg -l 'libc++*' || true - - - name: Configure CMake - working-directory: ${{env.BUILD_ROOT}} - run: | - cmake -S . -B build-ci -G Ninja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_ENABLE_TESTING=OFF -DMOBILEGL_BUILD_TEST=ON -DMOBILEGL_BUILD_BENCHMARK=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 - - - name: Build - working-directory: ${{env.BUILD_ROOT}}/build-ci - run: cmake --build . - - - name: Upload build artifacts - uses: actions/upload-artifact@v4 - with: - name: build-ci - path: ${{env.BUILD_ROOT}}/build-ci - - test: - runs-on: ubuntu-latest - needs: build - env: - TEST_ROOT: ${{github.workspace}} - BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} - - steps: - - name: Set Swap Space - uses: pierotofy/set-swap-space@master - with: - swap-size-gb: 32 - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: true - - - name: Get CMake - uses: lukka/get-cmake@latest - - - name: Install clang-20 - run: | - sudo apt-get update - sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: build-ci - path: ${{env.TEST_ROOT}}/build-ci - - - name: Test - working-directory: ${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test - continue-on-error: true - run: | - if [ "${{ secrets.ACTIONS_STEP_DEBUG }}" == "true" ]; then - ctest -V - else - ctest - fi - echo "CTEST_EXIT=$?" >> $GITHUB_ENV - - - name: Rerun failed tests with output - if: always() - working-directory: ${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test - run: | - ctest --rerun-failed --output-on-failure || true - - - name: Show LastTest.log - if: always() - run: | - cat "${{env.TEST_ROOT}}/build-ci/MobileGL/MG_Test/Testing/Temporary/LastTest.log" || true - - - name: Fail if tests failed - if: ${{ env.CTEST_EXIT != '' && env.CTEST_EXIT != '0' }} - run: exit ${{ env.CTEST_EXIT }} - - benchmark: - runs-on: ubuntu-latest - needs: build - env: - BENCH_ROOT: ${{github.workspace}} - BUILD_TYPE: ${{ secrets.ACTIONS_STEP_DEBUG == 'true' && 'Debug' || 'Release' }} - - steps: - - name: Set Swap Space - uses: pierotofy/set-swap-space@master - with: - swap-size-gb: 32 - - - name: Checkout repo - uses: actions/checkout@v4 - with: - submodules: true - - - name: Get CMake - uses: lukka/get-cmake@latest - - - name: Install clang-20 - run: | - sudo apt-get update - sudo apt-get install -y clang-20 clang++-20 lld-20 libc++-20-dev libc++abi-20-dev - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: build-ci - path: ${{env.BENCH_ROOT}}/build-ci - - - name: Benchmark - working-directory: ${{env.BENCH_ROOT}}/build-ci/MobileGL/MG_Benchmark - run: ctest -V -C ${{env.BUILD_TYPE}} From b90df42a4558e1b5480635d160d2f6e36525999c Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 7 Feb 2026 23:10:11 +0800 Subject: [PATCH 4/4] [Feat] (MG_Util/Texture, MG_Backend/DirectGLES): implementing BGRA texture readback (WIP) --- MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp | 50 ++++++++++++++++--- .../MG_Util/Texture/PixelStoreProcessor.cpp | 45 +++++++++++------ .../MG_Util/Texture/PixelStoreProcessor.h | 5 +- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 6878eac9..eb26c12b 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace MobileGL::MG_Backend::DirectGLES { enum class DrawSyncBit : Uint32 { @@ -1322,19 +1323,28 @@ namespace MobileGL::MG_Backend::DirectGLES { } void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels) { + DebugImpl::ErrorLopper errorLopper; MGLOG_D("GetTexImage: target=%s level=%d format=%s type=%s pixels=%p", MG_Util::ConvertGLEnumToString(target).c_str(), level, MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(type).c_str(), pixels); - MOBILEGL_ASSERT(format == GL_RGBA || format == GL_RGBA_INTEGER, - "Only GL_RGBA and GL_RGBA_INTEGER are supported currently, while requested %s.", + MOBILEGL_ASSERT(format == GL_RGBA || format == GL_RGBA_INTEGER || format == GL_BGRA, + "Only GL_RGBA, GL_RGBA_INTEGER and GL_BGRA are supported currently, while requested %s.", MG_Util::ConvertGLEnumToString(format).c_str()); MOBILEGL_ASSERT(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT || type == GL_UNSIGNED_INT_2_10_10_10_REV || - type == GL_INT || type == GL_FLOAT, + type == GL_INT || type == GL_FLOAT || + type == GL_UNSIGNED_INT_8_8_8_8 || type == GL_UNSIGNED_INT_8_8_8_8_REV, "Only GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_UNSIGNED_INT_2_10_10_10_REV, " - "GL_INT and GL_FLOAT are supported currently, while requested %s.", + "GL_INT, GL_FLOAT, GL_UNSIGNED_INT_8_8_8_8 and GL_UNSIGNED_INT_8_8_8_8_REV " + "are supported currently, while requested %s.", MG_Util::ConvertGLEnumToString(type).c_str()); + GLenum esFormat = format, esType = type; + if (esFormat == GL_BGRA) + esFormat = GL_RGBA; + if (esType == GL_UNSIGNED_INT_8_8_8_8 || esType == GL_UNSIGNED_INT_8_8_8_8_REV) + esType = GL_UNSIGNED_BYTE; + MGLOG_D("GetTexImage: SyncNeccessaryTextures()"); TextureImpl::SyncNeccessaryTextures(); @@ -1380,14 +1390,21 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } + errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { + MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); + }); + MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)"); TempPixelStoreParameterSync tempPackParamsSync(false); + errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { + MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); + }); + const auto& storageType = textureObject->GetStorageType(); MGLOG_D("GetTexImage: texture storage type = %d", (int)storageType); if (storageType == TextureStorageType::Buffer) { - MGLOG_E("GetTexImage: Texture storage type Buffer is not supported."); MGLOG_E("GetTexImage: Texture storage type Buffer is not supported."); return; } @@ -1432,8 +1449,17 @@ namespace MobileGL::MG_Backend::DirectGLES { usePBO = false; MGLOG_D("GetTexImage: Not using PBO"); } - MGLOG_D("GetTexImage: glReadPixels()"); - MG_External::GLES::glReadPixels(0, 0, size.x(), size.y(), format, type, pixels); + + errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { + MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); + }); + MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(), + MG_Util::ConvertGLEnumToString(esFormat).c_str(), MG_Util::ConvertGLEnumToString(esType).c_str(), pixels); + MG_External::GLES::glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels); + + errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { + MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); + }); if (usePBO) { // pull back to client memory if PBO is used MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory"); @@ -1448,12 +1474,20 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_External::GLES::glUnmapBuffer(GL_PIXEL_PACK_BUFFER); } else { MGLOG_E("ReadPixels: glMapBufferRange returned nullptr"); - MGLOG_E("ReadPixels: glMapBufferRange returned nullptr"); } MGLOG_D("ReadPixels: Restoring previous pixel pack buffer binding %u", prevPixelPackBuffer); MG_External::GLES::glBindBuffer(GL_PIXEL_PACK_BUFFER, prevPixelPackBuffer); + } else { + if (esFormat == GL_RGBA && format == GL_BGRA && esType == GL_UNSIGNED_BYTE && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + MGLOG_D("ReadPixels: ProcessColorSwizzle BGRA (not implemented)"); + + } } + + errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) { + MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str()); + }); MGLOG_D("GetTexImage: finished"); } diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp index 6092914f..74c532fe 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.cpp @@ -72,7 +72,7 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { // assume 8 bit per channel // swizzle.size() == channel count - static void ProcessColorSwizzle(void* data, SizeT pixelCount, const Vector& swizzle) { + void ProcessColorSwizzle(void* data, SizeT pixelCount, const Vector& swizzle) { const auto bpp = swizzle.size(); Uint8* bytes = static_cast(data); Uint8 pixelScratch[4]; @@ -172,22 +172,25 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { return outputPixels; } - void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, + void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, + TextureInternalFormat srcInternalFormat, TexturePixelDataType srcDataType, + TextureInputFormat dstInputFormat, TexturePixelDataType dstDataType, IntVec3 dimension, Bool isBitmap, SizeT& outSize) { - if (pixelSize == 0) { - outSize = 0; - return nullptr; - } + const SizeT pixelSize = MG_Util::GetInternalBytesPerPixel(srcInternalFormat, srcDataType); Int width = dimension.x(); Int height = dimension.y(); Int depth = dimension.z(); - const Int outputWidth = (params.RowLength > 0) ? params.RowLength : width; - const SizeT outputRowStride = CalculateRowStride(outputWidth, pixelSize, params.Alignment); - const SizeT inputRowStride = static_cast(width) * pixelSize; + if (pixelSize == 0) { + outSize = 0; + return nullptr; + } - const Int effectiveHeight = (params.ImageHeight > 0) ? params.ImageHeight : height; + // TODO: take care of PixelStoreParameters + const SizeT outputRowStride = width * pixelSize; + const Int effectiveHeight = height; + const SizeT inputRowStride = outputRowStride; outSize = static_cast(outputRowStride) * static_cast(effectiveHeight) * static_cast(depth); void* outputPixels = malloc(outSize); @@ -201,12 +204,22 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { const Uint8* src = static_cast(inputPixels); Uint8* dst = static_cast(outputPixels); - dst += static_cast(params.SkipImages) * static_cast(effectiveHeight) * outputRowStride; - dst += static_cast(params.SkipRows) * outputRowStride; - dst += static_cast(params.SkipPixels) * pixelSize; - Vector tempRow(static_cast(width) * pixelSize); + bool needSwizzle = false; + static Vector swizzle; + swizzle = { TextureSwizzleParam::Red, TextureSwizzleParam::Green, + TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha }; + if (srcInternalFormat == TextureInternalFormat::RGBA && dstInputFormat == TextureInputFormat::BGRA) { + swizzle = { TextureSwizzleParam::Blue, TextureSwizzleParam::Green, + TextureSwizzleParam::Red, TextureSwizzleParam::Alpha }; + needSwizzle = true; + } + if (dstDataType == TexturePixelDataType::UnsignedInt8888) { + std::reverse(swizzle.begin(), swizzle.end()); + needSwizzle = true; + } + for (Int z = 0; z < depth; ++z) { Uint8* layerDst = dst; const Uint8* layerSrc = src; @@ -222,6 +235,10 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { ProcessLSBFirst(tempRow.data(), static_cast(width), 1); } + if (needSwizzle) { + ProcessColorSwizzle(tempRow.data(), static_cast(width), swizzle); + } + Memcpy(layerDst, tempRow.data(), static_cast(width) * pixelSize); layerSrc += inputRowStride; diff --git a/MobileGL/MG_Util/Texture/PixelStoreProcessor.h b/MobileGL/MG_Util/Texture/PixelStoreProcessor.h index d5fcbca2..32f4ba0d 100644 --- a/MobileGL/MG_Util/Texture/PixelStoreProcessor.h +++ b/MobileGL/MG_Util/Texture/PixelStoreProcessor.h @@ -17,6 +17,9 @@ namespace MobileGL::MG_Util::PixelStoreProcessor { TextureInternalFormat targetInternalFormat, TextureInputFormat textureInputFormat, TexturePixelDataType inputDataType, IntVec3 dimension, Bool isBitmap, SizeT& outSize); - void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, SizeT pixelSize, + void* ProcessTexturePixelsDataPack(const void* inputPixels, const PixelStoreParameters& params, + TextureInternalFormat srcInternalFormat, TexturePixelDataType srcDataType, + TextureInputFormat dstInputFormat, TexturePixelDataType dstDataType, IntVec3 dimension, Bool isBitmap, SizeT& outSize); + void ProcessColorSwizzle(void* data, SizeT pixelCount, const Vector& swizzle); } // namespace MobileGL::MG_Util::PixelStoreProcessor