Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b0dc7babe | ||
|
|
c4ea6cb1bf | ||
|
|
87ed485b04 | ||
|
|
68ae023108 | ||
|
|
474fe0c96c |
@@ -9,7 +9,7 @@ runs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: mesa
|
||||
key: ${{ runner.os }}-${{ runner.arch }}-mesa-deps-${{ env.GITHUB_MESA_VERSION }}
|
||||
key: ${{ runner.os }}-mesa-deps-${{ env.GITHUB_MESA_VERSION }}
|
||||
- name: Get Mesa
|
||||
run: |
|
||||
bash build/common/get-mesa.sh
|
||||
|
||||
@@ -9,7 +9,7 @@ runs:
|
||||
id: cache-vulkan-sdk
|
||||
with:
|
||||
path: ~/VulkanSDK
|
||||
key: vulkansdk-${{ env.GITHUB_VULKANSDK_VERSION }}-2-${{ runner.os }}-${{ runner.arch }}
|
||||
key: vulkansdk-${{ env.GITHUB_VULKANSDK_VERSION }}-2-${{ runner.os }}
|
||||
- name: Download Vulkan SDK
|
||||
if: steps.cache-vulkan-sdk.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
@@ -23,7 +23,6 @@ runs:
|
||||
unpack_vulkan_installer
|
||||
shell: bash
|
||||
- name: Run Vulkan SDK setup
|
||||
if: runner.os != 'Linux'
|
||||
run: |
|
||||
pushd .
|
||||
cd ~/VulkanSDK/${GITHUB_VULKANSDK_VERSION}
|
||||
|
||||
@@ -11,13 +11,24 @@ runs:
|
||||
echo "set man-db/auto-update false" | sudo debconf-communicate
|
||||
sudo dpkg-reconfigure man-db
|
||||
|
||||
# Install ninja
|
||||
source ./build/common/get-ninja.sh
|
||||
|
||||
# Install CMake
|
||||
mkdir -p cmake
|
||||
cd cmake
|
||||
|
||||
sudo wget https://github.com/Kitware/CMake/releases/download/v$GITHUB_CMAKE_VERSION/cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo chmod +x ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh
|
||||
sudo ./cmake-$GITHUB_CMAKE_VERSION-Linux-x86_64.sh --skip-license > /dev/null
|
||||
sudo update-alternatives --install /usr/bin/cmake cmake $(pwd)/bin/cmake 1000 --force
|
||||
|
||||
cd ..
|
||||
|
||||
sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
sudo apt-get install mesa-common-dev libxi-dev libxxf86vm-dev
|
||||
sudo apt-get install cmake ninja-build
|
||||
|
||||
# For dawn
|
||||
sudo apt-get install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libx11-xcb-dev
|
||||
|
||||
@@ -8,15 +8,9 @@ runs:
|
||||
- uses: ./.github/actions/get-mesa
|
||||
- uses: ./.github/actions/get-vulkan-sdk
|
||||
- name: Prerequisites
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
# Must have at least clang-16 for a webgpu/dawn build.
|
||||
sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
|
||||
# this enforces the gltf_viewer build to use apple clang as oppose the brew clang used for get-mesa
|
||||
echo "CC=/usr/bin/clang" >> $GITHUB_ENV
|
||||
echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
echo "/usr/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
- name: Generate images
|
||||
run: |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12.13
|
||||
FROM python:3.10.4
|
||||
|
||||
RUN pip3 install pygithub==1.55
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: 'Web Prerequisites'
|
||||
name: 'Web Preqrequisites'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -8,7 +8,7 @@ runs:
|
||||
uses: actions/cache@v4 # Use a specific version
|
||||
with:
|
||||
path: emsdk
|
||||
key: ${{ runner.os }}-${{ runner.arch }}-emsdk-${{ env.GITHUB_EMSDK_VERSION }}
|
||||
key: ${{ runner.os }}-emsdk-${{ env.GITHUB_EMSDK_VERSION }}
|
||||
- name: Install Web Prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
# a branch on filament-assets.
|
||||
update-renderdiff-goldens:
|
||||
name: update-renderdiff-goldens
|
||||
runs-on: 'macos-14'
|
||||
runs-on: 'macos-14-xlarge'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
# filament-assets
|
||||
update-sizeguard:
|
||||
name: update-sizeguard
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
|
||||
@@ -12,7 +12,8 @@ jobs:
|
||||
name: build-android
|
||||
# We intentially use a larger runner here to enable larger disk space
|
||||
# (standard linux runner will fail on disk space and faster build time).
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -25,7 +26,8 @@ jobs:
|
||||
|
||||
build-ios:
|
||||
name: build-ios
|
||||
runs-on: 'macos-14'
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -44,7 +46,8 @@ jobs:
|
||||
|
||||
build-linux:
|
||||
name: build-linux
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -55,12 +58,13 @@ jobs:
|
||||
cd build/linux && printf "y" | ./build.sh continuous
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: filament-arm-linux
|
||||
path: out/filament-release-arm-linux.tgz
|
||||
name: filament-linux
|
||||
path: out/filament-release-linux.tgz
|
||||
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: 'macos-14'
|
||||
runs-on: macos-14-xlarge
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -73,10 +77,14 @@ jobs:
|
||||
with:
|
||||
name: filament-mac
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -93,7 +101,7 @@ jobs:
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: 'windows-2022'
|
||||
runs-on: windows-2022-32core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
+17
-178
@@ -8,54 +8,10 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# This will cancel in-flight runs when there is an update to a PR
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# The conditional 'if' on each job is meant to skip presubmit jobs when a commit is pushed to main
|
||||
# and that commit is cryptographically "verified". Typically, a verified commit (like a GitHub UI
|
||||
# squash-and-merge) has already passed through presubmit during the Pull Request phase.
|
||||
# The conditional explicitly checks:
|
||||
# 1. always() && !cancelled(): Ensures the job runs even if 'check-verification' is skipped, but
|
||||
# aborts if the workflow was manually cancelled.
|
||||
# 2. github.event_name == 'pull_request': Presubmits should always run normally on PRs.
|
||||
# 3. github.event_name == 'push' && ...: If it's a push to main, it only runs if the
|
||||
# 'check-verification' job confirmed the commit is NOT verified.
|
||||
|
||||
jobs:
|
||||
check-verification:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
verified: ${{ steps.check.outputs.verified }}
|
||||
steps:
|
||||
- name: Check commit verification
|
||||
id: check
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { data } = await github.rest.repos.getCommit({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: context.sha
|
||||
});
|
||||
core.setOutput('verified', data.commit.verification.verified);
|
||||
|
||||
build-desktop-mac:
|
||||
name: build-mac
|
||||
runs-on: 'macos-14-xlarge'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -64,30 +20,13 @@ jobs:
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/mac && printf "y" | ./build.sh presubmit-with-test
|
||||
- name: Test - material parser
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
- name: Test - public headers
|
||||
run: |
|
||||
# out/cmake-release should have the artifacts ready for installation. Here we install it
|
||||
# to test the public headers
|
||||
ninja -C out/cmake-release install
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
|
||||
build-desktop-linux:
|
||||
name: build-linux
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -96,24 +35,13 @@ jobs:
|
||||
- name: Run build script
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh presubmit
|
||||
- name: Test - material parser
|
||||
- name: Test material parser
|
||||
run: |
|
||||
out/cmake-release/filament/test/test_material_parser
|
||||
|
||||
build-windows:
|
||||
name: build-windows
|
||||
runs-on: 'windows-2022'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: windows-2022-32core
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -125,18 +53,7 @@ jobs:
|
||||
|
||||
build-android:
|
||||
name: build-android
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -163,18 +80,7 @@ jobs:
|
||||
|
||||
build-ios:
|
||||
name: build-iOS
|
||||
runs-on: 'macos-14-xlarge'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -189,18 +95,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -213,18 +108,7 @@ jobs:
|
||||
|
||||
validate-docs:
|
||||
name: validate-docs
|
||||
runs-on: 'ubuntu-24.04'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: 'ubuntu-24.04-4core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -237,18 +121,7 @@ jobs:
|
||||
|
||||
test-renderdiff:
|
||||
name: test-renderdiff
|
||||
runs-on: 'macos-14-xlarge'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -266,10 +139,10 @@ jobs:
|
||||
echo "accept=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
shell: bash
|
||||
- name: Renderdiff generate
|
||||
- name: Renderdiff Generate
|
||||
if: steps.check_accept.outputs.accept != 'true'
|
||||
uses: ./.github/actions/renderdiff-generate
|
||||
- name: Compare rendered images
|
||||
- name: Render and compare
|
||||
if: steps.check_accept.outputs.accept != 'true'
|
||||
id: render_compare
|
||||
env:
|
||||
@@ -301,13 +174,12 @@ jobs:
|
||||
echo "$DELIMITER" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
shell: bash
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: steps.check_accept.outputs.accept != 'true'
|
||||
with:
|
||||
name: presubmit-renderdiff-result
|
||||
path: ./out/renderdiff
|
||||
- name: Check results
|
||||
- name: Compare result
|
||||
if: steps.check_accept.outputs.accept != 'true'
|
||||
run: |
|
||||
ERROR_STR="${{ steps.render_compare.outputs.err }}"
|
||||
@@ -316,20 +188,9 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
build-wgsl-webgpu:
|
||||
validate-wgsl-webgpu:
|
||||
name: validate-wgsl-webgpu
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -343,17 +204,6 @@ jobs:
|
||||
test-code-correctness:
|
||||
name: test-code-correctness
|
||||
runs-on: 'macos-14-xlarge'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
@@ -374,18 +224,7 @@ jobs:
|
||||
|
||||
test-backend:
|
||||
name: test-backend
|
||||
runs-on: 'macos-14-xlarge'
|
||||
needs: [check-verification]
|
||||
if: >
|
||||
always() && !cancelled() &&
|
||||
(
|
||||
github.event_name == 'pull_request' ||
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
needs.check-verification.result == 'success' &&
|
||||
needs.check-verification.outputs.verified == 'false'
|
||||
)
|
||||
)
|
||||
runs-on: macos-14-xlarge
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
|
||||
@@ -63,39 +63,6 @@ jobs:
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
|
||||
build-arm-linux:
|
||||
name: build-arm-linux
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
|
||||
steps:
|
||||
- name: Decide Git ref
|
||||
id: git_ref
|
||||
run: |
|
||||
REF=${RELEASE_TAG:-${GITHUB_REF}}
|
||||
TAG=${REF##*/}
|
||||
echo "ref=${REF}" >> $GITHUB_OUTPUT
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
- uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
ref: ${{ steps.git_ref.outputs.ref }}
|
||||
- uses: ./.github/actions/linux-prereq
|
||||
- name: Run build script
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
run: |
|
||||
cd build/linux && printf "y" | ./build.sh release
|
||||
cd ../..
|
||||
mv out/filament-release-linux.tgz out/filament-${TAG}-arm-linux.tgz
|
||||
- uses: actions/github-script@v6
|
||||
env:
|
||||
TAG: ${{ steps.git_ref.outputs.tag }}
|
||||
with:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create('out/*.tgz');
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
|
||||
build-mac:
|
||||
name: build-mac
|
||||
runs-on: macos-14-xlarge
|
||||
@@ -132,7 +99,7 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: build-web
|
||||
runs-on: 'arm-ubuntu-24.04-16core'
|
||||
runs-on: 'ubuntu-24.04-16core'
|
||||
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
|
||||
|
||||
steps:
|
||||
|
||||
@@ -11,11 +11,14 @@ jobs:
|
||||
name: Verify Release Notes
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
# We *only* need to check out the .github/ directory.
|
||||
# The verify RELEASE_NOTES script uses the GitHub API to verify that RELEASE_NOTES was
|
||||
# modified.
|
||||
- name: Check out action
|
||||
uses: Bhacaz/checkout-files@73e17cfbe8d7e0c6b2672b20cb05a718e20d18d4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
sparse-checkout: |
|
||||
.github
|
||||
files: .github
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Verify release notes
|
||||
uses: ./.github/actions/verify-release-notes
|
||||
with:
|
||||
|
||||
+3
-10
@@ -326,13 +326,11 @@ endif()
|
||||
if (FILAMENT_ENABLE_LTO)
|
||||
include(CheckIPOSupported)
|
||||
|
||||
check_ipo_supported(RESULT IPO_SUPPORT OUTPUT IPO_ERROR)
|
||||
check_ipo_supported(RESULT IPO_SUPPORT)
|
||||
|
||||
if (IPO_SUPPORT)
|
||||
message(STATUS "IPO / LTO is enabled")
|
||||
message(STATUS "LTO support is enabled")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
else()
|
||||
message(WARNING "IPO / LTO is not supported by this architecture: ${IPO_ERROR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -869,12 +867,6 @@ endfunction()
|
||||
# Sub-projects
|
||||
# ==================================================================================================
|
||||
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(getopt_long "getopt.h" HAS_SYSTEM_GETOPT)
|
||||
if (NOT HAS_SYSTEM_GETOPT)
|
||||
add_subdirectory(${EXTERNAL}/getopt)
|
||||
endif()
|
||||
|
||||
# Common to all platforms
|
||||
add_subdirectory(${EXTERNAL}/libgtest/tnt)
|
||||
add_subdirectory(${LIBRARIES}/camutils)
|
||||
@@ -910,6 +902,7 @@ add_subdirectory(${EXTERNAL}/cgltf/tnt)
|
||||
add_subdirectory(${EXTERNAL}/draco/tnt)
|
||||
add_subdirectory(${EXTERNAL}/jsmn/tnt)
|
||||
add_subdirectory(${EXTERNAL}/stb/tnt)
|
||||
add_subdirectory(${EXTERNAL}/getopt)
|
||||
add_subdirectory(${EXTERNAL}/perfetto/tnt)
|
||||
add_subdirectory(${EXTERNAL}/basisu/tnt)
|
||||
|
||||
|
||||
@@ -6,3 +6,5 @@
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- engine: add `MaterialInstance::setConstant()` and `MaterialInstance::getConstant()` methods. These allow for per-material instance specialization constant overrides.
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.70.2'
|
||||
implementation 'com.google.android.filament:filament-android:1.69.5'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.70.2'
|
||||
pod 'Filament', '~> 1.69.5'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,12 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.70.2
|
||||
|
||||
|
||||
## v1.70.1
|
||||
|
||||
|
||||
## v1.70.0
|
||||
|
||||
- engine: fix crash when using variance shadow maps
|
||||
|
||||
@@ -200,7 +200,7 @@ subprojects {
|
||||
google()
|
||||
}
|
||||
|
||||
if (!name.startsWith("sample") && name != "filament-tools" && name != "gradle-plugin") {
|
||||
if (!name.startsWith("sample") && name != "filament-tools") {
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
|
||||
@@ -25,7 +25,7 @@ configured, the corresponding task will be disabled.
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
filament {
|
||||
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("filament-plugin") {
|
||||
id = "filament-plugin"
|
||||
implementationClass = "com.google.android.filament.gradle.FilamentPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.google.gradle:osdetector-gradle-plugin:1.7.3"
|
||||
}
|
||||
+2
-3
@@ -60,10 +60,9 @@ class ToolsLocator {
|
||||
def classifier =
|
||||
project.extensions.getByType(com.google.gradle.osdetector.OsDetector).classifier
|
||||
|
||||
// If com.google.android.filament.tools-dir is set to a non-empty string, we'll use it as
|
||||
// the tool's base path.
|
||||
// If com.google.android.filament.tools-dir is set, we'll use it as the tool's base path.
|
||||
def toolsDirProp = project.providers.gradleProperty("com.google.android.filament.tools-dir")
|
||||
if (toolsDirProp.isPresent() && !toolsDirProp.get().trim().isEmpty()) {
|
||||
if (toolsDirProp.isPresent()) {
|
||||
def toolsDir = toolsDirProp.get()
|
||||
def path = OperatingSystem.current().isWindows() ?
|
||||
"${toolsDir}/bin/${name}.exe" :
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
|
||||
#include "common/CallbackUtils.h"
|
||||
|
||||
#include <math/mat3.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec2.h>
|
||||
@@ -246,6 +248,69 @@ Java_com_google_android_filament_MaterialInstance_nSetFloatParameterArray(JNIEnv
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantBool(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jboolean result = instance->getConstant<bool>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantFloat(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jfloat result = instance->getConstant<float>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetConstantInt(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
jint result = instance->getConstant<int32_t>(name);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantBool(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jboolean x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<bool>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantFloat(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jfloat x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<float>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetConstantInt(JNIEnv *env, jclass,
|
||||
jlong nativeMaterialInstance, jstring name_, jint x) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
const char *name = env->GetStringUTFChars(name_, 0);
|
||||
instance->setConstant<int32_t>(name, x);
|
||||
env->ReleaseStringUTFChars(name_, name);
|
||||
}
|
||||
|
||||
// defined in TextureSampler.cpp
|
||||
namespace filament::JniUtils {
|
||||
TextureSampler from_long(jlong params) noexcept;
|
||||
@@ -580,3 +645,17 @@ Java_com_google_android_filament_MaterialInstance_nGetTransparencyMode(JNIEnv*,
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
return (jint) instance->getTransparencyMode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nCompile(JNIEnv *env, jclass clazz,
|
||||
jlong nativeMaterialInstance, jint priority, jint variants, jobject handler, jobject runnable) {
|
||||
MaterialInstance* materialInstance = (MaterialInstance*) nativeMaterialInstance;
|
||||
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
|
||||
materialInstance->compile(
|
||||
(MaterialInstance::CompilerPriorityQueue) priority,
|
||||
(UserVariantFilterBit) variants,
|
||||
jniCallback->getHandler(), [jniCallback](MaterialInstance*){
|
||||
JniCallback::postToJavaAndDestroy(jniCallback);
|
||||
});
|
||||
}
|
||||
|
||||
+98
@@ -18,6 +18,7 @@ package com.google.android.filament;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Size;
|
||||
|
||||
import com.google.android.filament.proguard.UsedByNative;
|
||||
@@ -142,6 +143,28 @@ public class MaterialInstance {
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously ensures that a subset of this MaterialInstance's variants are compiled.
|
||||
*
|
||||
* <p>This function behaves identically to {@link Material#compile}, but takes into account
|
||||
* the specific constants overridden by {@link #setConstant}.</p>
|
||||
*
|
||||
* @param priority Priority of the compile command.
|
||||
* @param variants Variants to include to the compile command.
|
||||
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
|
||||
* @param callback callback called on the main thread when the compilation is done on
|
||||
* by backend.
|
||||
*
|
||||
* @see Material#compile
|
||||
* @see #setConstant
|
||||
*/
|
||||
public void compile(@NonNull Material.CompilerPriorityQueue priority,
|
||||
int variants,
|
||||
@Nullable Object handler,
|
||||
@Nullable Runnable callback) {
|
||||
nCompile(getNativeObject(), priority.ordinal(), variants, handler, callback);
|
||||
}
|
||||
|
||||
/** @return the name associated with this instance */
|
||||
@NonNull
|
||||
public String getName() {
|
||||
@@ -402,6 +425,69 @@ public class MaterialInstance {
|
||||
nSetParameterFloat4(getNativeObject(), name, color[0], color[1], color[2], color[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, boolean value) {
|
||||
nSetConstantBool(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, float value) {
|
||||
nSetConstantFloat(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides a specialization constant of this material instance.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @param value The value of the constant.
|
||||
* @see Material.Builder#constant
|
||||
*/
|
||||
public void setConstant(@NonNull String name, int value) {
|
||||
nSetConstantInt(getNativeObject(), name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public boolean getConstantBoolean(@NonNull String name) {
|
||||
return nGetConstantBool(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public float getConstantFloat(@NonNull String name) {
|
||||
return nGetConstantFloat(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a specialization constant by name.
|
||||
*
|
||||
* @param name The name of the constant as defined in the material.
|
||||
* @return The value of the constant.
|
||||
*/
|
||||
public int getConstantInt(@NonNull String name) {
|
||||
return nGetConstantInt(getNativeObject(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set-up a custom scissor rectangle; by default it is disabled.
|
||||
*
|
||||
@@ -937,6 +1023,17 @@ public class MaterialInstance {
|
||||
@NonNull String name, int element, @NonNull @Size(min = 1) float[] v,
|
||||
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
|
||||
|
||||
private static native boolean nGetConstantBool(long nativeMaterialInstance, @NonNull String name);
|
||||
private static native float nGetConstantFloat(long nativeMaterialInstance, @NonNull String name);
|
||||
private static native int nGetConstantInt(long nativeMaterialInstance, @NonNull String name);
|
||||
|
||||
private static native void nSetConstantBool(long nativeMaterialInstance,
|
||||
@NonNull String name, boolean x);
|
||||
private static native void nSetConstantFloat(long nativeMaterialInstance,
|
||||
@NonNull String name, float x);
|
||||
private static native void nSetConstantInt(long nativeMaterialInstance,
|
||||
@NonNull String name, int x);
|
||||
|
||||
private static native void nSetParameterTexture(long nativeMaterialInstance,
|
||||
@NonNull String name, long nativeTexture, long sampler);
|
||||
|
||||
@@ -1000,4 +1097,5 @@ public class MaterialInstance {
|
||||
private static native int nGetDepthFunc(long nativeMaterialInstance);
|
||||
private static native void nSetTransparencyMode(long nativeMaterialInstance, int mode);
|
||||
private static native int nGetTransparencyMode(long nativeMaterialInstance);
|
||||
private static native void nCompile(long nativeMaterialInstance, int priority, int variants, Object handler, Runnable callback);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size
|
||||
add_library(filament-utils-jni SHARED
|
||||
src/main/cpp/AutomationEngine.cpp
|
||||
src/main/cpp/Bookmark.cpp
|
||||
src/main/cpp/DeviceUtils.cpp
|
||||
src/main/cpp/HDRLoader.cpp
|
||||
src/main/cpp/IBLPrefilterContext.cpp
|
||||
src/main/cpp/Utils.cpp
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 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 <jni.h>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
using namespace filament;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array<backend::Platform::DeviceInfoType, 3> VULKAN_INFO = {
|
||||
backend::Platform::DeviceInfoType::VULKAN_DEVICE_NAME,
|
||||
backend::Platform::DeviceInfoType::VULKAN_DRIVER_NAME,
|
||||
backend::Platform::DeviceInfoType::VULKAN_DRIVER_INFO,
|
||||
};
|
||||
|
||||
constexpr std::array<backend::Platform::DeviceInfoType, 3> GL_INFO = {
|
||||
backend::Platform::DeviceInfoType::OPENGL_VENDOR,
|
||||
backend::Platform::DeviceInfoType::OPENGL_RENDERER,
|
||||
backend::Platform::DeviceInfoType::OPENGL_VERSION,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_com_google_android_filament_utils_DeviceUtils_nGetGpuDriverInfo(JNIEnv* env, jclass,
|
||||
jlong nativeEngine) {
|
||||
auto emptyStr = [env]() { return env->NewStringUTF(""); };
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
if (!engine) {
|
||||
return emptyStr();
|
||||
}
|
||||
|
||||
backend::Platform* platform = engine->getPlatform();
|
||||
if (!platform) {
|
||||
return emptyStr();
|
||||
}
|
||||
|
||||
std::array<backend::Platform::DeviceInfoType, 3> infoTypes;
|
||||
switch (engine->getBackend()) {
|
||||
case backend::Backend::VULKAN:
|
||||
infoTypes = VULKAN_INFO;
|
||||
break;
|
||||
case backend::Backend::OPENGL:
|
||||
infoTypes = GL_INFO;
|
||||
break;
|
||||
default:
|
||||
return emptyStr();
|
||||
}
|
||||
|
||||
backend::Driver* driver = const_cast<backend::Driver*>(engine->getDriver());
|
||||
utils::CString fullInfo;
|
||||
std::for_each(infoTypes.begin(), infoTypes.end(),
|
||||
[&](backend::Platform::DeviceInfoType infoType) {
|
||||
utils::CString const newInfo = platform->getDeviceInfo(infoType, driver);
|
||||
if (!newInfo.empty()) {
|
||||
if (!fullInfo.empty()) {
|
||||
fullInfo += " | ";
|
||||
}
|
||||
fullInfo += newInfo.c_str();
|
||||
}
|
||||
});
|
||||
return env->NewStringUTF(fullInfo.c_str());
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <imagediff/ImageDiff.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace imagediff;
|
||||
using namespace utils;
|
||||
|
||||
@@ -100,48 +102,30 @@ jobject createResult(JNIEnv* env, ImageDiffResult const& result, bool generateDi
|
||||
|
||||
if (generateDiff && result.diffImage.getWidth() > 0) {
|
||||
jclass bitmapClass = env->FindClass("android/graphics/Bitmap");
|
||||
jmethodID createBitmap = env->GetStaticMethodID(bitmapClass, "createBitmap",
|
||||
jmethodID createBitmap = env->GetStaticMethodID(bitmapClass, "createBitmap",
|
||||
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
|
||||
|
||||
|
||||
jclass configClass = env->FindClass("android/graphics/Bitmap$Config");
|
||||
jfieldID argb8888 = env->GetStaticFieldID(configClass, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
|
||||
jobject configObj = env->GetStaticObjectField(configClass, argb8888);
|
||||
|
||||
uint32_t width = result.diffImage.getWidth();
|
||||
uint32_t height = result.diffImage.getHeight();
|
||||
jobject diffBitmap = env->CallStaticObjectMethod(bitmapClass, createBitmap, (jint) width,
|
||||
(jint) height, configObj);
|
||||
|
||||
jobject diffBitmap = env->CallStaticObjectMethod(bitmapClass, createBitmap, (jint)width, (jint)height, configObj);
|
||||
|
||||
if (diffBitmap) {
|
||||
// We need to transport the bit differences accurately to the java side, so set
|
||||
// premultiplied to false. From the java-side, if the bitmap is used to draw to a
|
||||
// canvas, then client needs to set premultiplied to true again.
|
||||
jmethodID setPremultiplied = env->GetMethodID(bitmapClass, "setPremultiplied", "(Z)V");
|
||||
if (setPremultiplied) {
|
||||
env->CallVoidMethod(diffBitmap, setPremultiplied, JNI_FALSE);
|
||||
}
|
||||
|
||||
void* diffPixels;
|
||||
if (AndroidBitmap_lockPixels(env, diffBitmap, &diffPixels) == 0) {
|
||||
AndroidBitmapInfo info;
|
||||
AndroidBitmap_getInfo(env, diffBitmap, &info);
|
||||
|
||||
float const* src = result.diffImage.getPixelRef();
|
||||
uint8_t* dst = (uint8_t*) diffPixels;
|
||||
uint32_t const channels = result.diffImage.getChannels(); // usually 4
|
||||
|
||||
for (size_t y = 0; y < height; ++y) {
|
||||
uint8_t* row = dst + y * info.stride;
|
||||
for (size_t x = 0; x < width; ++x) {
|
||||
size_t srcIdx = (y * width + x) * channels;
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
float v = 0.0f;
|
||||
if (c < channels) v = src[srcIdx + c];
|
||||
if (c == 3 && channels < 4) v = 1.0f; // Alpha 1.0 if missing
|
||||
|
||||
row[x * 4 + c] = uint8_t(
|
||||
std::min(255.0f, std::max(0.0f, std::round(v * 255.0f))));
|
||||
}
|
||||
uint32_t channels = result.diffImage.getChannels(); // usually 4
|
||||
|
||||
for (size_t i = 0; i < width * height; ++i) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
float v = 0.0f;
|
||||
if (c < channels) v = src[i * channels + c];
|
||||
if (c == 3 && channels < 4) v = 1.0f; // Alpha 1.0 if missing
|
||||
dst[i * 4 + c] = (uint8_t) std::min(255.0f, std::max(0.0f, v * 255.0f));
|
||||
}
|
||||
}
|
||||
AndroidBitmap_unlockPixels(env, diffBitmap);
|
||||
@@ -149,7 +133,7 @@ jobject createResult(JNIEnv* env, ImageDiffResult const& result, bool generateDi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
@@ -163,7 +147,7 @@ Java_com_google_android_filament_utils_ImageDiff_nCompareBasic(JNIEnv* env, jcla
|
||||
BitmapLock maskArg(env, maskBitmap);
|
||||
|
||||
if (!refArg.isValid() || !candArg.isValid()) {
|
||||
ImageDiffResult emptyResult;
|
||||
ImageDiffResult emptyResult;
|
||||
emptyResult.status = ImageDiffResult::Status::SIZE_MISMATCH; // or ERROR
|
||||
return createResult(env, emptyResult, false);
|
||||
}
|
||||
@@ -191,13 +175,13 @@ Java_com_google_android_filament_utils_ImageDiff_nCompareBasic(JNIEnv* env, jcla
|
||||
extern "C" JNIEXPORT jobject JNICALL
|
||||
Java_com_google_android_filament_utils_ImageDiff_nCompareJson(JNIEnv* env, jclass,
|
||||
jobject refBitmap, jobject candBitmap, jstring jsonConfig, jobject maskBitmap) {
|
||||
|
||||
|
||||
BitmapLock refArg(env, refBitmap);
|
||||
BitmapLock candArg(env, candBitmap);
|
||||
BitmapLock maskArg(env, maskBitmap);
|
||||
|
||||
if (!refArg.isValid() || !candArg.isValid()) {
|
||||
ImageDiffResult emptyResult;
|
||||
ImageDiffResult emptyResult;
|
||||
emptyResult.status = ImageDiffResult::Status::SIZE_MISMATCH; // or ERROR
|
||||
return createResult(env, emptyResult, false);
|
||||
}
|
||||
@@ -205,7 +189,7 @@ Java_com_google_android_filament_utils_ImageDiff_nCompareJson(JNIEnv* env, jclas
|
||||
ImageDiffConfig config;
|
||||
const char* nativeJson = env->GetStringUTFChars(jsonConfig, 0);
|
||||
size_t length = env->GetStringUTFLength(jsonConfig);
|
||||
|
||||
|
||||
bool parsed = parseConfig(nativeJson, length, &config);
|
||||
env->ReleaseStringUTFChars(jsonConfig, nativeJson);
|
||||
|
||||
@@ -230,3 +214,4 @@ Java_com_google_android_filament_utils_ImageDiff_nCompareJson(JNIEnv* env, jclas
|
||||
|
||||
return createResult(env, result, generateDiff);
|
||||
}
|
||||
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2026 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.
|
||||
*/
|
||||
|
||||
package com.google.android.filament.utils;
|
||||
|
||||
import com.google.android.filament.Engine;
|
||||
|
||||
public class DeviceUtils {
|
||||
public static String getGpuDriverInfo(Engine engine) {
|
||||
return nGetGpuDriverInfo(engine.getNativeObject());
|
||||
}
|
||||
private static native String nGetGpuDriverInfo(long nativeEngine);
|
||||
}
|
||||
+20
-54
@@ -106,8 +106,8 @@ class ModelViewer(
|
||||
var skyboxCubemap: Texture? = null
|
||||
|
||||
private lateinit var displayHelper: DisplayHelper
|
||||
private var cameraManipulator: Manipulator? = null
|
||||
private var gestureDetector: GestureDetector? = null
|
||||
private lateinit var cameraManipulator: Manipulator
|
||||
private lateinit var gestureDetector: GestureDetector
|
||||
private var surfaceView: SurfaceView? = null
|
||||
private var textureView: TextureView? = null
|
||||
|
||||
@@ -157,13 +157,15 @@ class ModelViewer(
|
||||
surfaceView: SurfaceView,
|
||||
engine: Engine = Engine.create(),
|
||||
uiHelper: UiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK),
|
||||
manipulator: Manipulator? = defaultCameraManipulator(surfaceView.width, surfaceView.height)
|
||||
manipulator: Manipulator? = null
|
||||
) : this(engine, uiHelper) {
|
||||
cameraManipulator = manipulator ?: Manipulator.Builder()
|
||||
.targetPosition(kDefaultObjectPosition.x, kDefaultObjectPosition.y, kDefaultObjectPosition.z)
|
||||
.viewport(surfaceView.width, surfaceView.height)
|
||||
.build(Manipulator.Mode.ORBIT)
|
||||
|
||||
this.surfaceView = surfaceView
|
||||
cameraManipulator = manipulator
|
||||
cameraManipulator?.let { c ->
|
||||
gestureDetector = GestureDetector(surfaceView, c)
|
||||
}
|
||||
gestureDetector = GestureDetector(surfaceView, cameraManipulator)
|
||||
displayHelper = DisplayHelper(surfaceView.context)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
uiHelper.attachTo(surfaceView)
|
||||
@@ -175,14 +177,15 @@ class ModelViewer(
|
||||
textureView: TextureView,
|
||||
engine: Engine = Engine.create(),
|
||||
uiHelper: UiHelper = UiHelper(UiHelper.ContextErrorPolicy.DONT_CHECK),
|
||||
manipulator: Manipulator? = defaultCameraManipulator(textureView.width, textureView.height)
|
||||
manipulator: Manipulator? = null
|
||||
) : this(engine, uiHelper) {
|
||||
cameraManipulator = manipulator
|
||||
cameraManipulator = manipulator ?: Manipulator.Builder()
|
||||
.targetPosition(kDefaultObjectPosition.x, kDefaultObjectPosition.y, kDefaultObjectPosition.z)
|
||||
.viewport(textureView.width, textureView.height)
|
||||
.build(Manipulator.Mode.ORBIT)
|
||||
|
||||
this.textureView = textureView
|
||||
cameraManipulator = manipulator
|
||||
cameraManipulator?.let { c ->
|
||||
gestureDetector = GestureDetector(textureView, c)
|
||||
}
|
||||
gestureDetector = GestureDetector(textureView, cameraManipulator)
|
||||
displayHelper = DisplayHelper(textureView.context)
|
||||
uiHelper.renderCallback = SurfaceCallback()
|
||||
uiHelper.attachTo(textureView)
|
||||
@@ -266,35 +269,6 @@ class ModelViewer(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the model's transform, animation, and camera state to defaults.
|
||||
* Call this when reusing the same model across multiple tests.
|
||||
*/
|
||||
fun resetToDefaultState() {
|
||||
// 1. Reset Camera parameters
|
||||
cameraFocalLength = 28f
|
||||
cameraNear = kNearPlane
|
||||
cameraFar = kFarPlane
|
||||
updateCameraProjection()
|
||||
|
||||
// 2. Reset the manipulator's look-at vectors to initial state
|
||||
cameraManipulator?.let { cm ->
|
||||
cm.jumpToBookmark(cm.homeBookmark)
|
||||
}
|
||||
|
||||
// 3. Reset Animations
|
||||
animator?.let {
|
||||
if (it.animationCount > 0) {
|
||||
it.applyAnimation(0, 0.0f)
|
||||
}
|
||||
it.updateBoneMatrices()
|
||||
}
|
||||
|
||||
// 4. Re-apply the unit cube transform to clear custom scaling/translation
|
||||
clearRootTransform()
|
||||
transformToUnitCube()
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all entities associated with the most recently-loaded model.
|
||||
*/
|
||||
@@ -328,13 +302,11 @@ class ModelViewer(
|
||||
asset?.let { populateScene(it) }
|
||||
|
||||
// Extract the camera basis from the helper and push it to the Filament camera.
|
||||
cameraManipulator?.let { cm ->
|
||||
cm.getLookAt(eyePos, target, upward)
|
||||
camera.lookAt(
|
||||
cameraManipulator.getLookAt(eyePos, target, upward)
|
||||
camera.lookAt(
|
||||
eyePos[0], eyePos[1], eyePos[2],
|
||||
target[0], target[1], target[2],
|
||||
upward[0], upward[1], upward[2])
|
||||
}
|
||||
|
||||
// Render the scene, unless the renderer wants to skip the frame.
|
||||
if (renderer.beginFrame(swapChain!!, frameTimeNanos)) {
|
||||
@@ -426,7 +398,7 @@ class ModelViewer(
|
||||
* Handles a [MotionEvent] to enable one-finger orbit, two-finger pan, and pinch-to-zoom.
|
||||
*/
|
||||
fun onTouchEvent(event: MotionEvent) {
|
||||
gestureDetector?.onTouchEvent(event)
|
||||
gestureDetector.onTouchEvent(event)
|
||||
}
|
||||
|
||||
@SuppressWarnings("ClickableViewAccessibility")
|
||||
@@ -479,7 +451,7 @@ class ModelViewer(
|
||||
|
||||
override fun onResized(width: Int, height: Int) {
|
||||
view.viewport = Viewport(0, 0, width, height)
|
||||
cameraManipulator?.setViewport(width, height)
|
||||
cameraManipulator.setViewport(width, height)
|
||||
updateCameraProjection()
|
||||
synchronizePendingFrames(engine)
|
||||
}
|
||||
@@ -496,11 +468,5 @@ class ModelViewer(
|
||||
|
||||
companion object {
|
||||
private val kDefaultObjectPosition = Float3(0.0f, 0.0f, -4.0f)
|
||||
private fun defaultCameraManipulator(width: Int, height: Int) : Manipulator {
|
||||
return Manipulator.Builder()
|
||||
.targetPosition(kDefaultObjectPosition.x, kDefaultObjectPosition.y, kDefaultObjectPosition.z)
|
||||
.viewport(width, height)
|
||||
.build(Manipulator.Mode.ORBIT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
id 'com.gradle.plugin-publish' version '2.1.0'
|
||||
}
|
||||
|
||||
group = "com.google.android.filament"
|
||||
version = "0.1.0"
|
||||
|
||||
gradlePlugin {
|
||||
website = "https://github.com/google/filament/tree/main/android/gradle-plugin"
|
||||
vcsUrl = "https://github.com/google/filament/tree/main/android/gradle-plugin"
|
||||
|
||||
plugins {
|
||||
create("filament-tools") {
|
||||
id = "com.google.android.filament-tools"
|
||||
displayName = "Filament Tools Gradle Plugin"
|
||||
description = "A plugin that helps integrate Filament into Android projects"
|
||||
tags.addAll('android', 'graphics', 'rendering', 'filament', '3d', 'gltf', 'native')
|
||||
implementationClass = "com.google.android.filament.gradle.FilamentPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.google.gradle:osdetector-gradle-plugin:1.7.3"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.70.2
|
||||
VERSION_NAME=1.69.5
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
"view": {
|
||||
"postProcessingEnabled": true,
|
||||
"dithering": "NONE"
|
||||
},
|
||||
"tolerance": {
|
||||
"maxAbsDiff": 0.1,
|
||||
"maxFailingPixelsFraction": 0.0
|
||||
}
|
||||
},
|
||||
"tolerance": {
|
||||
"maxAbsDiff": 0.1,
|
||||
"maxFailingPixelsFraction": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+8
-237
@@ -66,26 +66,10 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
private lateinit var inputManager: ValidationInputManager
|
||||
private var currentInput: ValidationInputManager.ValidationInput? = null
|
||||
|
||||
private var currentAlphaDiffBitmap: Bitmap? = null
|
||||
private var globalEnhancementFactor: Float = 1.0f
|
||||
|
||||
private data class TestImages(
|
||||
val testName: String,
|
||||
val golden: Bitmap?,
|
||||
val rendered: Bitmap?,
|
||||
val diff: Bitmap?,
|
||||
val alphaDiff: Bitmap?
|
||||
)
|
||||
|
||||
private val diffImageViews = mutableListOf<ImageView>()
|
||||
|
||||
// UI Elements
|
||||
private lateinit var runButton: Button
|
||||
private lateinit var loadButton: Button
|
||||
private lateinit var optionsButton: Button
|
||||
private lateinit var enhancementContainer: LinearLayout
|
||||
private lateinit var enhancementLabel: TextView
|
||||
private lateinit var enhancementSlider: android.widget.SeekBar
|
||||
|
||||
private var resultManager: ValidationResultManager? = null
|
||||
private var validationRunner: ValidationRunner? = null
|
||||
@@ -114,19 +98,6 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
runButton = findViewById(R.id.run_button)
|
||||
loadButton = findViewById(R.id.load_button)
|
||||
optionsButton = findViewById(R.id.options_button)
|
||||
enhancementContainer = findViewById(R.id.enhancement_container)
|
||||
enhancementLabel = findViewById(R.id.enhancement_label)
|
||||
enhancementSlider = findViewById(R.id.enhancement_slider)
|
||||
|
||||
enhancementSlider.setOnSeekBarChangeListener(object : android.widget.SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: android.widget.SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
globalEnhancementFactor = 1.0f + (progress / 100f) * 49.0f
|
||||
enhancementLabel.text = String.format(Locale.US, "Enhancement: %.1fx", globalEnhancementFactor)
|
||||
applyGlobalEnhancement()
|
||||
}
|
||||
override fun onStartTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
||||
override fun onStopTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
||||
})
|
||||
|
||||
// Setup Run Button
|
||||
runButton.setOnClickListener {
|
||||
@@ -149,7 +120,6 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
popup.menu.add(0, 3, 0, "Export Result")
|
||||
popup.menu.add(0, 4, 0, "Test ADB Info")
|
||||
popup.menu.add(0, 5, 0, "Result ADB Info")
|
||||
popup.menu.add(0, 6, 0, "Toggle Enhancement Slider")
|
||||
|
||||
popup.setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
@@ -163,9 +133,6 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
3 -> exportTestResultsAction()
|
||||
4 -> showTestAdbInfo()
|
||||
5 -> showResultAdbInfo()
|
||||
6 -> {
|
||||
enhancementContainer.visibility = if (enhancementContainer.visibility == View.VISIBLE) View.GONE else View.VISIBLE
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -175,7 +142,7 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
choreographer = Choreographer.getInstance()
|
||||
modelViewer = ModelViewer(surfaceView=surfaceView, manipulator=null)
|
||||
modelViewer = ModelViewer(surfaceView)
|
||||
inputManager = ValidationInputManager(this)
|
||||
|
||||
// Initialize IBL
|
||||
@@ -289,7 +256,6 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
|
||||
// Clear existing results UI and state
|
||||
resultsContainer.removeAllViews()
|
||||
diffImageViews.clear()
|
||||
resultManager = null
|
||||
|
||||
val newInput = ValidationInputManager.ValidationInput(
|
||||
@@ -368,29 +334,15 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createResultManager(outputDir: File): ValidationResultManager {
|
||||
val gpuDriverInfo = com.google.android.filament.utils.DeviceUtils.getGpuDriverInfo(modelViewer.engine)
|
||||
return ValidationResultManager(
|
||||
outputDir = outputDir,
|
||||
gpuDriverInfo = gpuDriverInfo,
|
||||
deviceName = android.os.Build.MODEL,
|
||||
deviceCodeName = android.os.Build.DEVICE,
|
||||
androidVersion = android.os.Build.VERSION.RELEASE,
|
||||
androidBuildNumber = android.os.Build.DISPLAY
|
||||
)
|
||||
}
|
||||
|
||||
private fun startValidation(input: ValidationInputManager.ValidationInput) {
|
||||
try {
|
||||
resultsContainer.removeAllViews()
|
||||
diffImageViews.clear()
|
||||
enhancementSlider.isEnabled = false
|
||||
Log.i(TAG, "Starting validation with config: ${input.config.name}")
|
||||
Log.i(TAG, "Output dir: ${input.outputDir.absolutePath}")
|
||||
|
||||
testResultsHeader.text = "${input.config.name}"
|
||||
|
||||
resultManager = createResultManager(input.outputDir)
|
||||
resultManager = ValidationResultManager(input.outputDir)
|
||||
|
||||
validationRunner = ValidationRunner(this, modelViewer, input.config, resultManager!!)
|
||||
validationRunner?.callback = this
|
||||
@@ -468,15 +420,7 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
val imagesRow = LinearLayout(this)
|
||||
imagesRow.orientation = LinearLayout.HORIZONTAL
|
||||
|
||||
val testImages = TestImages(
|
||||
testName = result.testName,
|
||||
golden = currentGoldenBitmap,
|
||||
rendered = currentRenderedBitmap,
|
||||
diff = currentDiffBitmap,
|
||||
alphaDiff = currentAlphaDiffBitmap
|
||||
)
|
||||
|
||||
fun addImage(label: String, bitmap: Bitmap?, isDiff: Boolean) {
|
||||
fun addImage(label: String, bitmap: Bitmap?) {
|
||||
if (bitmap != null) {
|
||||
val container = LinearLayout(this)
|
||||
container.orientation = LinearLayout.VERTICAL
|
||||
@@ -492,29 +436,16 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
iv.layoutParams = LinearLayout.LayoutParams(250, 250) // Smaller thumbnails
|
||||
iv.scaleType = ImageView.ScaleType.FIT_CENTER
|
||||
iv.setBackgroundColor(0xFF404040.toInt())
|
||||
|
||||
if (isDiff) {
|
||||
diffImageViews.add(iv)
|
||||
applyEnhancementToView(iv, globalEnhancementFactor)
|
||||
}
|
||||
|
||||
iv.setOnClickListener {
|
||||
showImageDialog(testImages, label)
|
||||
}
|
||||
|
||||
container.addView(iv)
|
||||
|
||||
imagesRow.addView(container)
|
||||
}
|
||||
}
|
||||
|
||||
addImage("Rendered", currentRenderedBitmap, false)
|
||||
addImage("Golden", currentGoldenBitmap, false)
|
||||
addImage("Rendered", currentRenderedBitmap)
|
||||
addImage("Golden", currentGoldenBitmap)
|
||||
if (!result.passed) {
|
||||
addImage("Diff", currentDiffBitmap, true)
|
||||
}
|
||||
if (currentAlphaDiffBitmap != null) {
|
||||
addImage("Alpha Diff", currentAlphaDiffBitmap, true)
|
||||
addImage("Diff", currentDiffBitmap)
|
||||
}
|
||||
|
||||
resultContainer.addView(imagesRow)
|
||||
@@ -524,14 +455,12 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
currentRenderedBitmap = null
|
||||
currentGoldenBitmap = null
|
||||
currentDiffBitmap = null
|
||||
currentAlphaDiffBitmap = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAllTestsFinished() {
|
||||
runOnUiThread {
|
||||
statusTextView.text = "All tests finished!"
|
||||
enhancementSlider.isEnabled = true
|
||||
Log.i(TAG, "All tests finished " + if (currentInput?.autoExport == true) "Exporting bundle" else "x")
|
||||
|
||||
if (currentInput?.autoExport == true) {
|
||||
@@ -546,7 +475,7 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
private fun exportTestBundleAction() {
|
||||
currentInput?.let { input ->
|
||||
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
|
||||
val rm = resultManager ?: createResultManager(input.outputDir)
|
||||
val rm = resultManager ?: ValidationResultManager(input.outputDir)
|
||||
val zip = rm.exportTestBundle(input.config, timestamp)
|
||||
if (zip != null) {
|
||||
val msg = "Exported Bundle: ${zip.name}"
|
||||
@@ -562,7 +491,7 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
private fun exportTestResultsAction() {
|
||||
currentInput?.let { input ->
|
||||
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
|
||||
val rm = resultManager ?: createResultManager(input.outputDir)
|
||||
val rm = resultManager ?: ValidationResultManager(input.outputDir)
|
||||
val zip = rm.exportTestResults(input.sourceZip, timestamp)
|
||||
if (zip != null) {
|
||||
val msg = "Exported Results: ${zip.name}"
|
||||
@@ -594,165 +523,7 @@ class MainActivity : Activity(), ValidationRunner.Callback {
|
||||
"Diff" -> {
|
||||
currentDiffBitmap = bitmap
|
||||
}
|
||||
"Alpha Diff" -> {
|
||||
currentAlphaDiffBitmap = bitmap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyEnhancementToView(iv: ImageView, factor: Float) {
|
||||
val cm = android.graphics.ColorMatrix()
|
||||
cm.setScale(factor, factor, factor, 1.0f)
|
||||
iv.colorFilter = android.graphics.ColorMatrixColorFilter(cm)
|
||||
}
|
||||
|
||||
private fun applyGlobalEnhancement() {
|
||||
for (iv in diffImageViews) {
|
||||
applyEnhancementToView(iv, globalEnhancementFactor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showImageDialog(images: TestImages, initialLabel: String) {
|
||||
val dialogView = layoutInflater.inflate(R.layout.dialog_image_viewer, null)
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setView(dialogView)
|
||||
.create()
|
||||
|
||||
val titleView = dialogView.findViewById<TextView>(R.id.dialog_title)
|
||||
val typeView = dialogView.findViewById<TextView>(R.id.dialog_image_type)
|
||||
val imageView = dialogView.findViewById<ImageView>(R.id.dialog_image)
|
||||
val btnClose = dialogView.findViewById<View>(R.id.btn_close)
|
||||
val btnReset = dialogView.findViewById<View>(R.id.btn_reset)
|
||||
val btnPrev = dialogView.findViewById<View>(R.id.btn_prev)
|
||||
val btnNext = dialogView.findViewById<View>(R.id.btn_next)
|
||||
|
||||
val enhancementContainer = dialogView.findViewById<View>(R.id.dialog_enhancement_container)
|
||||
val enhancementLabel = dialogView.findViewById<TextView>(R.id.dialog_enhancement_label)
|
||||
val enhancementSlider = dialogView.findViewById<android.widget.SeekBar>(R.id.dialog_enhancement_slider)
|
||||
|
||||
titleView.text = images.testName
|
||||
|
||||
val availableImages = mutableListOf<Pair<String, Bitmap>>()
|
||||
images.rendered?.let { availableImages.add(Pair("Rendered", it)) }
|
||||
images.golden?.let { availableImages.add(Pair("Golden", it)) }
|
||||
images.diff?.let { availableImages.add(Pair("Diff", it)) }
|
||||
images.alphaDiff?.let { availableImages.add(Pair("Alpha Diff", it)) }
|
||||
|
||||
if (availableImages.isEmpty()) return
|
||||
|
||||
var currentIndex = availableImages.indexOfFirst { it.first == initialLabel }
|
||||
if (currentIndex == -1) currentIndex = 0
|
||||
|
||||
var currentDialogEnhancement = globalEnhancementFactor
|
||||
|
||||
val matrix = android.graphics.Matrix()
|
||||
// Save initial values for translation tracking
|
||||
var lastTouchX = 0f
|
||||
var lastTouchY = 0f
|
||||
var isDragging = false
|
||||
|
||||
val scaleDetector = android.view.ScaleGestureDetector(this, object : android.view.ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||
override fun onScale(detector: android.view.ScaleGestureDetector): Boolean {
|
||||
matrix.postScale(detector.scaleFactor, detector.scaleFactor, detector.focusX, detector.focusY)
|
||||
imageView.imageMatrix = matrix
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
imageView.setOnTouchListener { _, event ->
|
||||
scaleDetector.onTouchEvent(event)
|
||||
when (event.actionMasked) {
|
||||
android.view.MotionEvent.ACTION_DOWN -> {
|
||||
lastTouchX = event.x
|
||||
lastTouchY = event.y
|
||||
isDragging = true
|
||||
}
|
||||
android.view.MotionEvent.ACTION_MOVE -> {
|
||||
if (isDragging && !scaleDetector.isInProgress) {
|
||||
val dx = event.x - lastTouchX
|
||||
val dy = event.y - lastTouchY
|
||||
matrix.postTranslate(dx, dy)
|
||||
imageView.imageMatrix = matrix
|
||||
}
|
||||
lastTouchX = event.x
|
||||
lastTouchY = event.y
|
||||
}
|
||||
android.view.MotionEvent.ACTION_UP, android.view.MotionEvent.ACTION_CANCEL -> {
|
||||
isDragging = false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fun updateView() {
|
||||
val (label, bitmap) = availableImages[currentIndex]
|
||||
typeView.text = label
|
||||
imageView.setImageBitmap(bitmap)
|
||||
(imageView.drawable as? android.graphics.drawable.BitmapDrawable)?.setAntiAlias(false)
|
||||
(imageView.drawable as? android.graphics.drawable.BitmapDrawable)?.setFilterBitmap(false)
|
||||
imageView.imageMatrix = matrix
|
||||
|
||||
if (label == "Diff" || label == "Alpha Diff") {
|
||||
enhancementContainer.visibility = View.VISIBLE
|
||||
applyEnhancementToView(imageView, currentDialogEnhancement)
|
||||
} else {
|
||||
enhancementContainer.visibility = View.GONE
|
||||
imageView.colorFilter = null
|
||||
}
|
||||
}
|
||||
|
||||
fun resetMatrix() {
|
||||
val drawable = imageView.drawable ?: return
|
||||
val width = imageView.width.toFloat()
|
||||
val height = imageView.height.toFloat()
|
||||
val dw = drawable.intrinsicWidth.toFloat()
|
||||
val dh = drawable.intrinsicHeight.toFloat()
|
||||
|
||||
val scaleX = width / dw
|
||||
val scaleY = height / dh
|
||||
val scale = Math.min(scaleX, scaleY)
|
||||
|
||||
val dx = (width - dw * scale) / 2f
|
||||
val dy = (height - dh * scale) / 2f
|
||||
|
||||
matrix.reset()
|
||||
matrix.postScale(scale, scale)
|
||||
matrix.postTranslate(dx, dy)
|
||||
imageView.imageMatrix = matrix
|
||||
}
|
||||
|
||||
btnClose.setOnClickListener { dialog.dismiss() }
|
||||
btnReset.setOnClickListener { resetMatrix() }
|
||||
btnPrev.setOnClickListener {
|
||||
currentIndex = (currentIndex - 1 + availableImages.size) % availableImages.size
|
||||
updateView()
|
||||
}
|
||||
btnNext.setOnClickListener {
|
||||
currentIndex = (currentIndex + 1) % availableImages.size
|
||||
updateView()
|
||||
}
|
||||
|
||||
val defaultProgress = ((currentDialogEnhancement - 1.0f) / 49.0f * 100).toInt()
|
||||
val safeProgress = Math.max(0, Math.min(100, defaultProgress))
|
||||
enhancementSlider.progress = safeProgress
|
||||
enhancementLabel.text = String.format(Locale.US, "Enhance: %.1fx", currentDialogEnhancement)
|
||||
|
||||
enhancementSlider.setOnSeekBarChangeListener(object : android.widget.SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: android.widget.SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
currentDialogEnhancement = 1.0f + (progress / 100f) * 49.0f
|
||||
enhancementLabel.text = String.format(Locale.US, "Enhance: %.1fx", currentDialogEnhancement)
|
||||
updateView()
|
||||
}
|
||||
override fun onStartTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
||||
override fun onStopTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
||||
})
|
||||
|
||||
imageView.post {
|
||||
resetMatrix()
|
||||
}
|
||||
|
||||
updateView()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
+9
-28
@@ -31,14 +31,7 @@ data class ValidationResult(
|
||||
val diffMetric: Float = 0f
|
||||
)
|
||||
|
||||
class ValidationResultManager(
|
||||
private val outputDir: File,
|
||||
private val gpuDriverInfo: String,
|
||||
private val deviceName: String,
|
||||
private val deviceCodeName: String,
|
||||
private val androidVersion: String,
|
||||
private val androidBuildNumber: String
|
||||
) {
|
||||
class ValidationResultManager(private val outputDir: File) {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ValidationResultManager"
|
||||
@@ -71,9 +64,9 @@ class ValidationResultManager(
|
||||
return outputDir
|
||||
}
|
||||
|
||||
fun finalizeResults(totalTimeMs: Long): File? {
|
||||
fun finalizeResults(): File? {
|
||||
// Write results JSON
|
||||
writeResultsJson(totalTimeMs)
|
||||
writeResultsJson()
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -110,10 +103,10 @@ class ValidationResultManager(
|
||||
zos.closeEntry()
|
||||
}
|
||||
|
||||
// 3. Add images (only rendered images, exclude diffs)
|
||||
outputDir.listFiles { _, name -> name.endsWith(".png") && !name.endsWith("_diff.png") }?.forEach { imgFile ->
|
||||
zos.putNextEntry(ZipEntry(imgFile.name))
|
||||
imgFile.inputStream().use { it.copyTo(zos) }
|
||||
// 3. Add diff images (any file ending in _diff.png in outputDir)
|
||||
outputDir.listFiles { _, name -> name.endsWith("_diff.png") }?.forEach { diffFile ->
|
||||
zos.putNextEntry(ZipEntry(diffFile.name))
|
||||
diffFile.inputStream().use { it.copyTo(zos) }
|
||||
zos.closeEntry()
|
||||
}
|
||||
}
|
||||
@@ -273,18 +266,7 @@ class ValidationResultManager(
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeResultsJson(totalTimeMs: Long) {
|
||||
val rootObject = JSONObject()
|
||||
|
||||
val metadataObject = JSONObject()
|
||||
metadataObject.put("gpu_driver_info", gpuDriverInfo ?: "")
|
||||
metadataObject.put("total_time_ms", totalTimeMs)
|
||||
metadataObject.put("device_name", deviceName ?: "")
|
||||
metadataObject.put("device_code_name", deviceCodeName ?: "")
|
||||
metadataObject.put("android_version", androidVersion ?: "")
|
||||
metadataObject.put("android_build_number", androidBuildNumber ?: "")
|
||||
rootObject.put("metadata", metadataObject)
|
||||
|
||||
private fun writeResultsJson() {
|
||||
val jsonArray = JSONArray()
|
||||
for (result in results) {
|
||||
val jsonObject = JSONObject()
|
||||
@@ -293,12 +275,11 @@ class ValidationResultManager(
|
||||
jsonObject.put("diff_metric", result.diffMetric)
|
||||
jsonArray.put(jsonObject)
|
||||
}
|
||||
rootObject.put("results", jsonArray)
|
||||
|
||||
val jsonFile = File(outputDir, "results.json")
|
||||
try {
|
||||
FileOutputStream(jsonFile).use { out ->
|
||||
out.write(rootObject.toString(4).toByteArray())
|
||||
out.write(jsonArray.toString(4).toByteArray())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to write results.json", e)
|
||||
|
||||
+9
-64
@@ -42,7 +42,6 @@ class ValidationRunner(
|
||||
private var currentModelName: String? = null
|
||||
|
||||
private var frameCounter = 0
|
||||
private var suiteStartTime: Long = 0
|
||||
|
||||
enum class State {
|
||||
IDLE,
|
||||
@@ -66,7 +65,6 @@ class ValidationRunner(
|
||||
callback?.onAllTestsFinished()
|
||||
return
|
||||
}
|
||||
suiteStartTime = System.currentTimeMillis()
|
||||
currentTestIndex = 0
|
||||
currentModelIndex = 0
|
||||
startTest(config.tests[0])
|
||||
@@ -83,17 +81,6 @@ class ValidationRunner(
|
||||
}
|
||||
|
||||
private fun startModel(modelName: String) {
|
||||
if (currentModelName == modelName) {
|
||||
Log.i("ValidationRunner", "Reusing model $modelName")
|
||||
callback?.onStatusChanged("Reusing $modelName for ${currentTestConfig?.name}")
|
||||
|
||||
modelViewer.resetToDefaultState()
|
||||
|
||||
frameCounter = 0
|
||||
currentState = State.WARMUP
|
||||
return
|
||||
}
|
||||
|
||||
currentModelName = modelName
|
||||
val modelPath = config.models[modelName]
|
||||
if (modelPath == null) {
|
||||
@@ -128,6 +115,10 @@ class ValidationRunner(
|
||||
}
|
||||
|
||||
fun onFrame(frameTimeNanos: Long) {
|
||||
if (frameCounter % 60 == 0) {
|
||||
Log.i("ValidationRunner", "onFrame: $currentState (frame: $frameCounter)")
|
||||
}
|
||||
|
||||
when (currentState) {
|
||||
State.IDLE -> {}
|
||||
State.WAITING_FOR_RESOURCES -> {
|
||||
@@ -145,6 +136,7 @@ class ValidationRunner(
|
||||
}
|
||||
}
|
||||
State.RUNNING_TEST -> {
|
||||
// Log.i("ValidationRunner", "Running test...")
|
||||
currentEngine?.let { engine ->
|
||||
val content = AutomationEngine.ViewerContent()
|
||||
content.view = modelViewer.view
|
||||
@@ -265,54 +257,10 @@ class ValidationRunner(
|
||||
passed = (result.status == ImageDiff.Result.Status.PASSED)
|
||||
diffMetric = result.failingPixelCount.toFloat()
|
||||
|
||||
if (!passed) {
|
||||
if (!passed) {
|
||||
if (result.diffImage != null) {
|
||||
val diffImg = result.diffImage!!
|
||||
val width = diffImg.width
|
||||
val height = diffImg.height
|
||||
val pixels = IntArray(width * height)
|
||||
diffImg.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
|
||||
var hasAlphaDiff = false
|
||||
val alphaPixels = IntArray(width * height)
|
||||
|
||||
for (i in pixels.indices) {
|
||||
val color = pixels[i]
|
||||
|
||||
val a = android.graphics.Color.alpha(color)
|
||||
val r = android.graphics.Color.red(color)
|
||||
val g = android.graphics.Color.green(color)
|
||||
val b = android.graphics.Color.blue(color)
|
||||
|
||||
if (a > 0) {
|
||||
hasAlphaDiff = true
|
||||
}
|
||||
|
||||
// Map alpha diff to grayscale RGB
|
||||
alphaPixels[i] = android.graphics.Color.argb(255, a, a, a)
|
||||
|
||||
// Force main diff image alpha to 255
|
||||
pixels[i] = android.graphics.Color.argb(255, r, g, b)
|
||||
}
|
||||
|
||||
// Apply updated pixels to diff image
|
||||
diffImg.setPixels(pixels, 0, width, 0, 0, width, height)
|
||||
|
||||
// The C++ ImageDiff code sets isPremultiplied to false so Android
|
||||
// doesn't erase RGB diff values when Alpha diff is 0. However, Android's
|
||||
// Canvas will crash if we try to draw a non-premultiplied bitmap.
|
||||
// Since we just forced all alpha values to 255 (fully opaque) in the
|
||||
// loop above, we can safely mark it as premultiplied again here.
|
||||
diffImg.isPremultiplied = true
|
||||
callback?.onImageResult("Diff", diffImg)
|
||||
resultManager.saveImage("${testFullName}_diff", diffImg)
|
||||
|
||||
if (hasAlphaDiff) {
|
||||
val alphaDiffImg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||
alphaDiffImg.setPixels(alphaPixels, 0, width, 0, 0, width, height)
|
||||
callback?.onImageResult("Alpha Diff", alphaDiffImg)
|
||||
resultManager.saveImage("${testFullName}_alpha_diff", alphaDiffImg)
|
||||
}
|
||||
callback?.onImageResult("Diff", result.diffImage!!)
|
||||
resultManager.saveImage("${testFullName}_diff", result.diffImage!!)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -358,10 +306,7 @@ class ValidationRunner(
|
||||
startTest(config.tests[currentTestIndex])
|
||||
} else {
|
||||
currentState = State.IDLE
|
||||
|
||||
val totalTimeMs = System.currentTimeMillis() - suiteStartTime
|
||||
|
||||
resultManager.finalizeResults(totalTimeMs)
|
||||
resultManager.finalizeResults()
|
||||
callback?.onAllTestsFinished()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,33 +81,6 @@
|
||||
android:contentDescription="More Options"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Global Enhancement Controls (Hidden by default) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/enhancement_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/enhancement_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enhancement: 1.0x"
|
||||
android:textSize="12sp"
|
||||
android:minWidth="120dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/enhancement_slider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:max="100"
|
||||
android:progress="0" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#FF202020"
|
||||
android:padding="8dp">
|
||||
|
||||
<!-- Header with title and close button -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Test Result"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
<ImageButton
|
||||
android:id="@+id/btn_close"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@android:drawable/ic_menu_close_clear_cancel" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Subtitle for Image Type -->
|
||||
<TextView
|
||||
android:id="@+id/dialog_image_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:text="Rendered"
|
||||
android:textColor="#BBBBBB"
|
||||
android:textSize="14sp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<!-- Image Area with Arrows -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1">
|
||||
<ImageView
|
||||
android:id="@+id/dialog_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="matrix" />
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- Navigation Arrows -->
|
||||
<LinearLayout
|
||||
android:id="@+id/dialog_arrow_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_prev"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@android:drawable/ic_media_previous"
|
||||
app:tint="#FFFFFF" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_reset"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
app:tint="#FFFFFF" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_next"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@android:drawable/ic_media_next"
|
||||
app:tint="#FFFFFF" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Enhancement Controls (only for diff images) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/dialog_enhancement_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialog_enhancement_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enhance: 1.0x"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"
|
||||
android:minWidth="100dp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/dialog_enhancement_slider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:max="100"
|
||||
android:progress="0" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.android.filament-tools'
|
||||
id 'filament-plugin'
|
||||
}
|
||||
|
||||
project.ext.isSample = true
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
// Filament tools plugin
|
||||
pluginManagement {
|
||||
includeBuild 'gradle-plugin'
|
||||
}
|
||||
|
||||
// Libraries
|
||||
include ':filament-android'
|
||||
include ':filamat-android'
|
||||
|
||||
@@ -54,13 +54,8 @@ if [[ "$OS_NAME" == "Linux" ]]; then
|
||||
# is constantly being updated and sometimes not compatible with the current
|
||||
# linux platform.
|
||||
# Note that we assume this platform is compatible with ubuntu-22.04 x86_64
|
||||
DPKG_ARCH=$(dpkg --print-architecture)
|
||||
EXTRA_PACKAGES=""
|
||||
if [[ "$DPKG_ARCH" == "amd64" ]]; then
|
||||
EXTRA_PACKAGES="lib32gcc-s1 lib32stdc++6 libc6-i386"
|
||||
fi
|
||||
sudo apt-get -y install \
|
||||
autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:${DPKG_ARCH} gettext glslang-tools icu-devtools intltool-debian ${EXTRA_PACKAGES} libarchive-zip-perl libasan6:${DPKG_ARCH} libatomic1:${DPKG_ARCH} libc-dev-bin libc6-dbg:${DPKG_ARCH} libc6-dev:${DPKG_ARCH} libcc1-0:${DPKG_ARCH} libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:${DPKG_ARCH} libdebhelper-perl libdpkg-perl libdrm-amdgpu1:${DPKG_ARCH} libdrm-dev:${DPKG_ARCH} libdrm-intel1:${DPKG_ARCH} libdrm-nouveau2:${DPKG_ARCH} libdrm-radeon1:${DPKG_ARCH} libelf-dev:${DPKG_ARCH} libexpat1-dev:${DPKG_ARCH} libffi-dev:${DPKG_ARCH} libfile-stripnondeterminism-perl libgc1:${DPKG_ARCH} libgcc-11-dev:${DPKG_ARCH} libgl1:${DPKG_ARCH} libgl1-mesa-dri:${DPKG_ARCH} libglapi-mesa:${DPKG_ARCH} libglvnd-core-dev:${DPKG_ARCH} libglvnd0:${DPKG_ARCH} libglx-mesa0:${DPKG_ARCH} libglx0:${DPKG_ARCH} libgomp1:${DPKG_ARCH} libicu-dev:${DPKG_ARCH} libisl23:${DPKG_ARCH} libitm1:${DPKG_ARCH} libllvm14:${DPKG_ARCH} libllvm${GITHUB_CLANG_VERSION}:${DPKG_ARCH} libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:${DPKG_ARCH} libllvmspirvlib${GITHUB_CLANG_VERSION}:${DPKG_ARCH} liblsan0:${DPKG_ARCH} libmpc3:${DPKG_ARCH} libncurses-dev:${DPKG_ARCH} libnsl-dev:${DPKG_ARCH} libobjc-11-dev:${DPKG_ARCH} libobjc4:${DPKG_ARCH} libpciaccess-dev:${DPKG_ARCH} libpciaccess0f:${DPKG_ARCH} libpfm4:${DPKG_ARCH} libpthread-stubs0-dev:${DPKG_ARCH} libquadmath0:${DPKG_ARCH} libsensors-config libsensors-dev:${DPKG_ARCH} libsensors5:${DPKG_ARCH} libset-scalar-perl libstd-rust-1.75:${DPKG_ARCH} libstd-rust-dev:${DPKG_ARCH} libstdc++-11-dev:${DPKG_ARCH} libsub-override-perl libtinfo-dev:${DPKG_ARCH} libtirpc-dev:${DPKG_ARCH} libtool libtsan0:${DPKG_ARCH} libubsan1:${DPKG_ARCH} libva-dev:${DPKG_ARCH} libva-drm2:${DPKG_ARCH} libva-glx2:${DPKG_ARCH} libva-wayland2:${DPKG_ARCH} libva-x11-2:${DPKG_ARCH} libva2:${DPKG_ARCH} libvdpau-dev:${DPKG_ARCH} libvdpau1:${DPKG_ARCH} libvulkan-dev:${DPKG_ARCH} libvulkan1:${DPKG_ARCH} libwayland-bin libwayland-client0:${DPKG_ARCH} libwayland-cursor0:${DPKG_ARCH} libwayland-dev:${DPKG_ARCH} libwayland-egl-backend-dev:${DPKG_ARCH} libwayland-egl1:${DPKG_ARCH} libwayland-server0:${DPKG_ARCH} libx11-dev:${DPKG_ARCH} libx11-xcb-dev:${DPKG_ARCH} libx11-xcb1:${DPKG_ARCH} libxau-dev:${DPKG_ARCH} libxcb-dri2-0:${DPKG_ARCH} libxcb-dri2-0-dev:${DPKG_ARCH} libxcb-dri3-0:${DPKG_ARCH} libxcb-dri3-dev:${DPKG_ARCH} libxcb-glx0:${DPKG_ARCH} libxcb-glx0-dev:${DPKG_ARCH} libxcb-present-dev:${DPKG_ARCH} libxcb-present0:${DPKG_ARCH} libxcb-randr0:${DPKG_ARCH} libxcb-randr0-dev:${DPKG_ARCH} libxcb-render0:${DPKG_ARCH} libxcb-render0-dev:${DPKG_ARCH} libxcb-shape0:${DPKG_ARCH} libxcb-shape0-dev:${DPKG_ARCH} libxcb-shm0:${DPKG_ARCH} libxcb-shm0-dev:${DPKG_ARCH} libxcb-sync-dev:${DPKG_ARCH} libxcb-sync1:${DPKG_ARCH} libxcb-xfixes0:${DPKG_ARCH} libxcb-xfixes0-dev:${DPKG_ARCH} libxcb1-dev:${DPKG_ARCH} libxdmcp-dev:${DPKG_ARCH} libxext-dev:${DPKG_ARCH} libxfixes-dev:${DPKG_ARCH} libxfixes3:${DPKG_ARCH} libxml2-dev:${DPKG_ARCH} libxrandr-dev:${DPKG_ARCH} libxrandr2:${DPKG_ARCH} libxrender-dev:${DPKG_ARCH} libxrender1:${DPKG_ARCH} libxshmfence-dev:${DPKG_ARCH} libxshmfence1:${DPKG_ARCH} libxxf86vm-dev:${DPKG_ARCH} libxxf86vm1:${DPKG_ARCH} libz3-4:${DPKG_ARCH} libz3-dev:${DPKG_ARCH} libzstd-dev:${DPKG_ARCH} linux-libc-dev:${DPKG_ARCH} llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-linker-tools llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools llvm-spirv-${LLVM_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:${DPKG_ARCH} \
|
||||
autoconf automake autopoint autotools-dev bindgen bison build-essential bzip2 cpp cpp-11 debhelper debugedit dh-autoreconf dh-strip-nondeterminism diffstat directx-headers-dev dpkg-dev dwz flex g++ g++-11 gcc gcc-11 gcc-11-base:amd64 gettext glslang-tools icu-devtools intltool-debian lib32gcc-s1 lib32stdc++6 libarchive-zip-perl libasan6:amd64 libatomic1:amd64 libc-dev-bin libc6-dbg:amd64 libc6-dev:amd64 libc6-i386 libcc1-0:amd64 libclang-${GITHUB_CLANG_VERSION}-dev libclang-common-${GITHUB_CLANG_VERSION}-dev libclang-cpp${GITHUB_CLANG_VERSION} libclang-cpp${GITHUB_CLANG_VERSION}-dev libclang1-14 libclang1-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION} libclc-${GITHUB_CLANG_VERSION}-dev libcrypt-dev:amd64 libdebhelper-perl libdpkg-perl libdrm-amdgpu1:amd64 libdrm-dev:amd64 libdrm-intel1:amd64 libdrm-nouveau2:amd64 libdrm-radeon1:amd64 libelf-dev:amd64 libexpat1-dev:amd64 libffi-dev:amd64 libfile-stripnondeterminism-perl libgc1:amd64 libgcc-11-dev:amd64 libgl1:amd64 libgl1-mesa-dri:amd64 libglapi-mesa:amd64 libglvnd-core-dev:amd64 libglvnd0:amd64 libglx-mesa0:amd64 libglx0:amd64 libgomp1:amd64 libicu-dev:amd64 libisl23:amd64 libitm1:amd64 libllvm14:amd64 libllvm${GITHUB_CLANG_VERSION}:amd64 libllvmspirvlib-${GITHUB_CLANG_VERSION}-dev:amd64 libllvmspirvlib${GITHUB_CLANG_VERSION}:amd64 liblsan0:amd64 libmpc3:amd64 libncurses-dev:amd64 libnsl-dev:amd64 libobjc-11-dev:amd64 libobjc4:amd64 libpciaccess-dev:amd64 libpciaccess0f:amd64 libpfm4:amd64 libpthread-stubs0-dev:amd64 libquadmath0:amd64 libsensors-config libsensors-dev:amd64 libsensors5:amd64 libset-scalar-perl libstd-rust-1.75:amd64 libstd-rust-dev:amd64 libstdc++-11-dev:amd64 libsub-override-perl libtinfo-dev:amd64 libtirpc-dev:amd64 libtool libtsan0:amd64 libubsan1:amd64 libva-dev:amd64 libva-drm2:amd64 libva-glx2:amd64 libva-wayland2:amd64 libva-x11-2:amd64 libva2:amd64 libvdpau-dev:amd64 libvdpau1:amd64 libvulkan-dev:amd64 libvulkan1:amd64 libwayland-bin libwayland-client0:amd64 libwayland-cursor0:amd64 libwayland-dev:amd64 libwayland-egl-backend-dev:amd64 libwayland-egl1:amd64 libwayland-server0:amd64 libx11-dev:amd64 libx11-xcb-dev:amd64 libx11-xcb1:amd64 libxau-dev:amd64 libxcb-dri2-0:amd64 libxcb-dri2-0-dev:amd64 libxcb-dri3-0:amd64 libxcb-dri3-dev:amd64 libxcb-glx0:amd64 libxcb-glx0-dev:amd64 libxcb-present-dev:amd64 libxcb-present0:amd64 libxcb-randr0:amd64 libxcb-randr0-dev:amd64 libxcb-render0:amd64 libxcb-render0-dev:amd64 libxcb-shape0:amd64 libxcb-shape0-dev:amd64 libxcb-shm0:amd64 libxcb-shm0-dev:amd64 libxcb-sync-dev:amd64 libxcb-sync1:amd64 libxcb-xfixes0:amd64 libxcb-xfixes0-dev:amd64 libxcb1-dev:amd64 libxdmcp-dev:amd64 libxext-dev:amd64 libxfixes-dev:amd64 libxfixes3:amd64 libxml2-dev:amd64 libxrandr-dev:amd64 libxrandr2:amd64 libxrender-dev:amd64 libxrender1:amd64 libxshmfence-dev:amd64 libxshmfence1:amd64 libxxf86vm-dev:amd64 libxxf86vm1:amd64 libz3-4:amd64 libz3-dev:amd64 libzstd-dev:amd64 linux-libc-dev:amd64 llvm-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev llvm-${LLVM_VERSION}-linker-tools llvm-${LLVM_VERSION}-runtime llvm-${LLVM_VERSION}-tools llvm-spirv-${LLVM_VERSION} lto-disabled-list m4 make meson ninja-build pkg-config po-debconf python3-mako python3-ply python3-pygments quilt rpcsvc-proto rustc spirv-tools valgrind wayland-protocols x11proto-dev xorg-sgml-doctools xtrans-dev zlib1g-dev:amd64 \
|
||||
clang-$GITHUB_CLANG_VERSION libc++-$GITHUB_CLANG_VERSION-dev libc++abi-$GITHUB_CLANG_VERSION-dev
|
||||
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${GITHUB_CLANG_VERSION} 100
|
||||
@@ -85,7 +80,6 @@ elif [[ "$OS_NAME" == "Darwin" ]]; then
|
||||
if command -v brew > /dev/null 2>&1; then
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=true brew install autoconf automake libx11 libxext libxrandr \
|
||||
llvm@${LLVM_VERSION} ninja meson pkg-config libxshmfence
|
||||
brew link --overwrite llvm@${LLVM_VERSION}
|
||||
# For reasons unknown, this is necessary for pkg-config to find homebrew's packages
|
||||
LOCAL_PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
elif command -v port > /dev/null 2>&1; then
|
||||
|
||||
@@ -63,10 +63,6 @@ function _preferred_os_filename() {
|
||||
|
||||
function download_vulkan_installer() {
|
||||
local os=$(_get_os)
|
||||
if [[ "$os" == "linux" ]]; then
|
||||
echo "Linux uses apt to install vulkan dependencies, skipping tarball download." >&2
|
||||
return 0
|
||||
fi
|
||||
local dl_filename=$(_os_filename ${VULKAN_SDK_VERSION})
|
||||
local filename=$(_preferred_os_filename)
|
||||
local url=https://sdk.lunarg.com/sdk/download/$VULKAN_SDK_VERSION/$os/$dl_filename?Human=true
|
||||
@@ -83,22 +79,15 @@ function download_vulkan_installer() {
|
||||
|
||||
function unpack_vulkan_installer() {
|
||||
local os=$(_get_os)
|
||||
if [[ "$os" == "linux" ]]; then
|
||||
install_${os}
|
||||
return 0
|
||||
fi
|
||||
local filename=$(_preferred_os_filename $os)
|
||||
test -f $filename
|
||||
install_${os}
|
||||
}
|
||||
|
||||
function install_linux() {
|
||||
echo "Installing Vulkan dependencies via apt for Linux..." >&2
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y libvulkan-dev vulkan-validationlayers glslang-tools spirv-tools
|
||||
|
||||
# Create a dummy SDK dir to satisfy scripts expecting a VulkanSDK folder structure
|
||||
mkdir -p ~/VulkanSDK/${VULKAN_SDK_VERSION}
|
||||
test -d $VULKAN_SDK_DIR && test -f vulkan_sdk.tar.gz
|
||||
echo "extract just the SDK's prebuilt binaries ($VULKAN_SDK_VERSION/x86_64) from vulkan_sdk.tar.gz into $VULKAN_SDK" >&2
|
||||
tar -C "$VULKAN_SDK_DIR" --strip-components 2 -xf vulkan_sdk.tar.gz $VULKAN_SDK_VERSION/x86_64
|
||||
}
|
||||
|
||||
function install_mac() {
|
||||
|
||||
@@ -46,7 +46,6 @@ list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
get_filename_component(NDK_VERSION ${NDK_VERSION} NAME)
|
||||
set(TOOLCHAIN ${ANDROID_HOME_UNIX}/ndk/${NDK_VERSION}/toolchains/llvm/prebuilt/${HOST_NAME_L}-x86_64)
|
||||
set(CMAKE_ANDROID_NDK_VERSION ${NDK_VERSION})
|
||||
|
||||
# specify the cross compiler
|
||||
set(COMPILER_SUFFIX)
|
||||
|
||||
@@ -47,7 +47,6 @@ list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
get_filename_component(NDK_VERSION ${NDK_VERSION} NAME)
|
||||
set(TOOLCHAIN ${ANDROID_HOME_UNIX}/ndk/${NDK_VERSION}/toolchains/llvm/prebuilt/${HOST_NAME_L}-x86_64)
|
||||
set(CMAKE_ANDROID_NDK_VERSION ${NDK_VERSION})
|
||||
|
||||
# specify the cross compiler
|
||||
set(COMPILER_SUFFIX)
|
||||
|
||||
@@ -46,7 +46,6 @@ list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
get_filename_component(NDK_VERSION ${NDK_VERSION} NAME)
|
||||
set(TOOLCHAIN ${ANDROID_HOME_UNIX}/ndk/${NDK_VERSION}/toolchains/llvm/prebuilt/${HOST_NAME_L}-x86_64)
|
||||
set(CMAKE_ANDROID_NDK_VERSION ${NDK_VERSION})
|
||||
|
||||
# specify the cross compiler
|
||||
set(COMPILER_SUFFIX)
|
||||
|
||||
@@ -46,7 +46,6 @@ list(SORT NDK_VERSIONS)
|
||||
list(GET NDK_VERSIONS -1 NDK_VERSION)
|
||||
get_filename_component(NDK_VERSION ${NDK_VERSION} NAME)
|
||||
set(TOOLCHAIN ${ANDROID_HOME_UNIX}/ndk/${NDK_VERSION}/toolchains/llvm/prebuilt/${HOST_NAME_L}-x86_64)
|
||||
set(CMAKE_ANDROID_NDK_VERSION ${NDK_VERSION})
|
||||
|
||||
# specify the cross compiler
|
||||
set(COMPILER_SUFFIX)
|
||||
|
||||
+2
-2
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.70.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.69.5'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
|
||||
@@ -195,7 +195,7 @@ dependencies {
|
||||
</div>
|
||||
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
|
||||
<p>iOS projects can use CocoaPods to install the latest release:</p>
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.70.0'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.69.5'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -600,7 +600,6 @@ if (FILAMENT_BUILD_TESTING)
|
||||
test/test_CircularBuffer.cpp
|
||||
test/test_CommandBufferQueue.cpp
|
||||
test/test_Template.cpp
|
||||
test/test_Platform.cpp
|
||||
)
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
list(APPEND BACKEND_TEST_SRC
|
||||
@@ -616,6 +615,7 @@ if (FILAMENT_BUILD_TESTING)
|
||||
set(BACKEND_TEST_LIBS
|
||||
absl::str_format
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
imageio
|
||||
filamat
|
||||
@@ -724,9 +724,10 @@ if (FILAMENT_BUILD_TESTING)
|
||||
|
||||
target_link_libraries(metal_utils_test PRIVATE
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
)
|
||||
|
||||
set_target_properties(metal_utils_test PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -216,18 +216,6 @@ public:
|
||||
MULTIVIEW,
|
||||
};
|
||||
|
||||
/**
|
||||
* Types of device/driver information that can be queried from the platform.
|
||||
*/
|
||||
enum class DeviceInfoType {
|
||||
OPENGL_RENDERER, //!< glGetString(GL_RENDERER)
|
||||
OPENGL_VENDOR, //!< glGetString(GL_VENDOR)
|
||||
OPENGL_VERSION, //!< glGetString(GL_VERSION)
|
||||
VULKAN_DEVICE_NAME, //!< VkPhysicalDeviceProperties::deviceName
|
||||
VULKAN_DRIVER_NAME, //!< VkPhysicalDeviceDriverProperties::driverName
|
||||
VULKAN_DRIVER_INFO, //!< VkPhysicalDeviceDriverProperties::driverInfo
|
||||
};
|
||||
|
||||
/**
|
||||
* This controls the priority level for GPU work scheduling, which helps prioritize the
|
||||
* submitted GPU work and enables preemption.
|
||||
@@ -328,7 +316,7 @@ public:
|
||||
*/
|
||||
StereoscopicType stereoscopicType = StereoscopicType::NONE;
|
||||
|
||||
/**
|
||||
/*
|
||||
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
|
||||
* between 1 and Engine::getMaxStereoscopicEyes() (inclusive).
|
||||
*/
|
||||
@@ -389,16 +377,6 @@ public:
|
||||
*/
|
||||
virtual int getOSVersion() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Queries device/driver information of the graphics API.
|
||||
* @param infoType the type of information to query.
|
||||
* @param driver a pointer to the current driver.
|
||||
* @return a CString containing the requested information.
|
||||
*/
|
||||
virtual utils::CString getDeviceInfo(DeviceInfoType infoType,
|
||||
Driver* UTILS_NULLABLE driver) const noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Creates and initializes the low-level API (e.g. an OpenGL context or Vulkan instance),
|
||||
* then creates the concrete Driver.
|
||||
|
||||
@@ -52,9 +52,6 @@ protected:
|
||||
|
||||
~OpenGLPlatform() noexcept override;
|
||||
|
||||
utils::CString getDeviceInfo(DeviceInfoType infoType,
|
||||
Driver* UTILS_NULLABLE driver) const noexcept override;
|
||||
|
||||
public:
|
||||
struct ExternalTexture {
|
||||
unsigned int target; // GLenum target
|
||||
@@ -73,12 +70,6 @@ public:
|
||||
*/
|
||||
static utils::CString getRendererString(Driver const* UTILS_NONNULL driver);
|
||||
|
||||
/**
|
||||
* Return the OpenGL version string of the specified Driver instance.
|
||||
* @return The GL_VERSION string
|
||||
*/
|
||||
static utils::CString getVersionString(Driver const* UTILS_NONNULL driver);
|
||||
|
||||
/**
|
||||
* Called by the driver to destroy the OpenGL context. This should clean up any windows
|
||||
* or buffers from initialization. This is for instance where `eglDestroyContext` would be
|
||||
|
||||
@@ -159,12 +159,6 @@ protected:
|
||||
EGLConfig getEglConfig() const noexcept { return mEGLConfig; }
|
||||
EGLConfig getSuitableConfigForSwapChain(uint64_t flags, bool window, bool pbuffer) const;
|
||||
|
||||
// Sets the EGLDisplay to be used by this platform. This should only be called by derived
|
||||
// classes before invoking createDriver. Calling it after that point will result in
|
||||
// undefined behaviour. This class will take ownership of the display and call eglTerminate
|
||||
// on it during shutdown.
|
||||
void setEglDisplay(EGLDisplay display) noexcept;
|
||||
|
||||
// supported extensions detected at runtime
|
||||
struct {
|
||||
struct {
|
||||
|
||||
@@ -185,7 +185,7 @@ private:
|
||||
};
|
||||
|
||||
int mOSVersion;
|
||||
ExternalStreamManagerAndroid* mExternalStreamManager = nullptr;
|
||||
ExternalStreamManagerAndroid& mExternalStreamManager;
|
||||
AndroidDetails& mAndroidDetails;
|
||||
utils::PerformanceHintManager mPerformanceHintManager;
|
||||
utils::PerformanceHintManager::Session mPerformanceHintSession;
|
||||
|
||||
@@ -38,7 +38,6 @@ public:
|
||||
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) override;
|
||||
int getOSVersion() const noexcept override { return 0; }
|
||||
utils::CString getDeviceInfo(DeviceInfoType, Driver*) const noexcept override { return {}; }
|
||||
|
||||
/**
|
||||
* Optionally initializes the Metal platform by acquiring resources necessary for rendering.
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
|
||||
@@ -68,7 +69,7 @@ public:
|
||||
|
||||
struct ExtensionHashFn {
|
||||
std::size_t operator()(utils::CString const& s) const noexcept {
|
||||
return std::hash<utils::CString>{}(s.data());
|
||||
return std::hash<std::string>{}(s.data());
|
||||
}
|
||||
};
|
||||
// Note: utils::CString::operator== has an edge case that breaks for the extension set.
|
||||
@@ -142,8 +143,6 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
utils::CString getDeviceInfo(DeviceInfoType infoType, Driver* driver) const noexcept override;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ---------- Platform Customization options ----------
|
||||
struct Customization {
|
||||
@@ -176,12 +175,6 @@ public:
|
||||
* presentation. Default is true.
|
||||
*/
|
||||
bool transitionSwapChainImageLayoutForPresent = true;
|
||||
|
||||
/**
|
||||
* The number of frames before an unused framebuffer is evicted from the cache.
|
||||
* Default is 3.
|
||||
*/
|
||||
uint32_t timeBeforeEvictionFbo = 3;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,9 +46,6 @@ public:
|
||||
~WebGPUPlatform() override = default;
|
||||
|
||||
[[nodiscard]] int getOSVersion() const noexcept final { return 0; }
|
||||
[[nodiscard]] utils::CString getDeviceInfo(DeviceInfoType, Driver*) const noexcept override {
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] wgpu::Instance& getInstance() noexcept { return mInstance; }
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
@@ -26,7 +26,6 @@ class PlatformNoop final : public Platform {
|
||||
public:
|
||||
|
||||
int getOSVersion() const noexcept final { return 0; }
|
||||
utils::CString getDeviceInfo(DeviceInfoType, Driver*) const noexcept override { return {}; }
|
||||
|
||||
~PlatformNoop() noexcept override = default;
|
||||
|
||||
|
||||
@@ -341,44 +341,7 @@ void GLDescriptorSet::bind(
|
||||
if (arg.handle) {
|
||||
GLTexture const* const t = handleAllocator.handle_cast<GLTexture*>(arg.handle);
|
||||
gl.bindTexture(unit, t->gl.target, t->gl.id, t->gl.external);
|
||||
SamplerParams params = arg.params;
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
// From https://registry.khronos.org/OpenGL-Refpages/es2.0/
|
||||
// GLES 2.0 will draw mipmapped samplers as black if the following conditions are not met:
|
||||
//
|
||||
// "...if the width or height of a texture image are not powers of two and either the
|
||||
// GL_TEXTURE_MIN_FILTER is set to one of the functions that requires mipmaps or the
|
||||
// GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T is not set to GL_CLAMP_TO_EDGE, then the
|
||||
// texture image unit will return (R, G, B, A) = (0, 0, 0, 1)."
|
||||
//
|
||||
// "If the texture has dimensions w × h , there are [floor(log2(max(w, h))) + 1] mipmap levels.
|
||||
// Level 0 is the original texture; level [floor(log2(max(w, h)))] is the final 1 × 1 mipmap."
|
||||
// "Suppose that a texture is accessed from a fragment shader or vertex shader and has set GL_TEXTURE_MIN_FILTER
|
||||
// to one of the functions that requires mipmaps. If either the dimensions of the texture images currently
|
||||
// defined (with previous calls to glTexImage2D, glCompressedTexImage2D, or glCopyTexImage2D) do not follow
|
||||
// the proper sequence for mipmaps (described above), or there are fewer texture images defined than are needed,
|
||||
// or the set of texture images were defined with different formats or types, then the texture image unit
|
||||
// will return (R, G, B, A) = (0, 0, 0, 1)."
|
||||
//
|
||||
// So we force the sampler to a valid state in those cases.
|
||||
auto isPowerOfTwo = [](uint32_t x) -> bool { return (x & (x - 1)) == 0 && x > 0; };
|
||||
bool textureIsPowerOfTwo = isPowerOfTwo(t->width) && isPowerOfTwo(t->height);
|
||||
|
||||
uint32_t requiredMipLevels = (std::floor(std::log2(std::max(t->width, std::max(t->height, t->depth)))) + 1);
|
||||
bool textureHasRequiredMipLevels = t->levels == requiredMipLevels;
|
||||
|
||||
bool samplerCanBeInvalid = params.filterMin > SamplerMinFilter::LINEAR;
|
||||
if (samplerCanBeInvalid && (!textureIsPowerOfTwo || !textureHasRequiredMipLevels)) {
|
||||
if (params.filterMin == SamplerMinFilter::NEAREST_MIPMAP_NEAREST
|
||||
|| params.filterMin == SamplerMinFilter::LINEAR_MIPMAP_NEAREST) {
|
||||
params.filterMin = SamplerMinFilter::NEAREST;
|
||||
} else {
|
||||
params.filterMin = SamplerMinFilter::LINEAR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SamplerParams const params = arg.params;
|
||||
glTexParameteri(t->gl.target, GL_TEXTURE_MIN_FILTER,
|
||||
(GLint)GLUtils::getTextureFilter(params.filterMin));
|
||||
glTexParameteri(t->gl.target, GL_TEXTURE_MAG_FILTER,
|
||||
|
||||
@@ -222,15 +222,6 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BACKEND_OPENGL_VERSION_GL) || defined(GL_EXT_disjoint_timer_query)
|
||||
if (ext.EXT_disjoint_timer_query) {
|
||||
mGpuTimeSupported = true;
|
||||
} else
|
||||
#endif
|
||||
if (platform.canCreateFence()) {
|
||||
mGpuTimeSupported = true;
|
||||
}
|
||||
|
||||
// in practice KHR_Debug has never been useful, and actually is confusing. We keep this
|
||||
// only for our own debugging, in case we need it some day.
|
||||
#if false && !defined(NDEBUG) && defined(GL_KHR_debug)
|
||||
|
||||
@@ -158,10 +158,8 @@ public:
|
||||
constexpr static inline size_t getIndexForBufferTarget(GLenum target) noexcept;
|
||||
|
||||
ShaderModel getShaderModel() const noexcept { return mShaderModel; }
|
||||
|
||||
|
||||
void resetState() noexcept;
|
||||
|
||||
bool isGpuTimeSupported() const noexcept { return mGpuTimeSupported; }
|
||||
|
||||
inline void useProgram(GLuint program) noexcept;
|
||||
|
||||
@@ -544,8 +542,6 @@ private:
|
||||
|
||||
Platform::DriverConfig const mDriverConfig;
|
||||
|
||||
bool mGpuTimeSupported = false;
|
||||
|
||||
void bindFramebufferResolved(GLenum target, GLuint buffer) noexcept;
|
||||
|
||||
const std::array<std::tuple<bool const&, char const*, char const*>, sizeof(bugs)> mBugDatabase{{
|
||||
|
||||
@@ -467,8 +467,7 @@ void OpenGLDriver::bindTexture(GLuint const unit, GLTexture const* t) noexcept {
|
||||
bool OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
bool success = true;
|
||||
if (mBoundProgram != p) {
|
||||
// compile/link the program if needed and call glUseProgram.
|
||||
// This call may block until the program linking process is complete.
|
||||
// compile/link the program if needed and call glUseProgram
|
||||
success = p->use(this, mContext);
|
||||
assert_invariant(success == p->isValid());
|
||||
if (success) {
|
||||
@@ -717,11 +716,7 @@ Handle<HwSwapChain> OpenGLDriver::createSwapChainHeadlessS() noexcept {
|
||||
}
|
||||
|
||||
Handle<HwTimerQuery> OpenGLDriver::createTimerQueryS() noexcept {
|
||||
Handle<HwTimerQuery> tqh = initHandle<GLTimerQuery>();
|
||||
// The state must be constructed here, as a synchronous call to getTimerQueryValue might happen
|
||||
// before createTimerQueryR is executed on the backend thread.
|
||||
handle_cast<GLTimerQuery*>(tqh)->state = std::make_shared<GLTimerQuery::State>();
|
||||
return tqh;
|
||||
return initHandle<GLTimerQuery>();
|
||||
}
|
||||
|
||||
Handle<HwDescriptorSetLayout> OpenGLDriver::createDescriptorSetLayoutS() noexcept {
|
||||
@@ -2860,7 +2855,7 @@ bool OpenGLDriver::isFrameBufferFetchMultiSampleSupported() {
|
||||
}
|
||||
|
||||
bool OpenGLDriver::isFrameTimeSupported() {
|
||||
return mContext.isGpuTimeSupported();
|
||||
return TimerQueryFactory::isGpuTimeSupported();
|
||||
}
|
||||
|
||||
bool OpenGLDriver::isAutoDepthResolveSupported() {
|
||||
|
||||
@@ -250,10 +250,6 @@ private:
|
||||
return utils::CString{ mContext.state.renderer };
|
||||
}
|
||||
|
||||
utils::CString getVersionString() const noexcept override {
|
||||
return utils::CString{ mContext.state.version };
|
||||
}
|
||||
|
||||
JobQueue* getJobQueue() const noexcept { return mJobQueue.get(); }
|
||||
JobWorker* getJobWorker() const noexcept { return mJobWorker.get(); }
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ protected:
|
||||
public:
|
||||
virtual utils::CString getVendorString() const noexcept = 0;
|
||||
virtual utils::CString getRendererString() const noexcept = 0;
|
||||
virtual utils::CString getVersionString() const noexcept = 0;
|
||||
};
|
||||
|
||||
} // filament::backend
|
||||
|
||||
@@ -45,21 +45,6 @@ Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform,
|
||||
|
||||
OpenGLPlatform::~OpenGLPlatform() noexcept = default;
|
||||
|
||||
utils::CString OpenGLPlatform::getDeviceInfo(DeviceInfoType infoType,
|
||||
Driver* driver) const noexcept {
|
||||
switch (infoType) {
|
||||
case DeviceInfoType::OPENGL_RENDERER:
|
||||
return getRendererString(driver);
|
||||
case DeviceInfoType::OPENGL_VENDOR:
|
||||
return getVendorString(driver);
|
||||
case DeviceInfoType::OPENGL_VERSION:
|
||||
return getVersionString(driver);
|
||||
default:
|
||||
FILAMENT_CHECK_POSTCONDITION(false) << "Unsupported DeviceInfoType for OpenGLPlatform";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
utils::CString OpenGLPlatform::getVendorString(Driver const* driver) {
|
||||
auto const p = static_cast<OpenGLDriverBase const*>(driver);
|
||||
#if UTILS_HAS_RTTI
|
||||
@@ -78,15 +63,6 @@ utils::CString OpenGLPlatform::getRendererString(Driver const* driver) {
|
||||
return p->getRendererString();
|
||||
}
|
||||
|
||||
utils::CString OpenGLPlatform::getVersionString(Driver const* driver) {
|
||||
auto const p = static_cast<OpenGLDriverBase const*>(driver);
|
||||
#if UTILS_HAS_RTTI
|
||||
FILAMENT_CHECK_POSTCONDITION(dynamic_cast<OpenGLDriverBase const*>(driver))
|
||||
<< "Driver* has not been allocated with OpenGLPlatform";
|
||||
#endif
|
||||
return p->getVersionString();
|
||||
}
|
||||
|
||||
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
|
||||
utils::Invocable<void()>, utils::Invocable<void(size_t)>) {
|
||||
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
|
||||
|
||||
@@ -48,7 +48,7 @@ class OpenGLDriver;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
bool TimerQueryFactory::mGpuTimeSupported = false;
|
||||
|
||||
TimerQueryFactoryInterface* TimerQueryFactory::init(
|
||||
OpenGLPlatform& platform, OpenGLContext& context) {
|
||||
@@ -65,14 +65,17 @@ TimerQueryFactoryInterface* TimerQueryFactory::init(
|
||||
} else {
|
||||
impl = new(std::nothrow) TimerQueryNativeFactory(context);
|
||||
}
|
||||
mGpuTimeSupported = true;
|
||||
} else
|
||||
#endif
|
||||
if (platform.canCreateFence()) {
|
||||
// no timer queries, but we can use fences
|
||||
impl = new(std::nothrow) TimerQueryFenceFactory(platform);
|
||||
mGpuTimeSupported = true;
|
||||
} else {
|
||||
// no queries, no fences -- that's a problem
|
||||
impl = new(std::nothrow) TimerQueryFallbackFactory();
|
||||
mGpuTimeSupported = false;
|
||||
}
|
||||
assert_invariant(impl);
|
||||
return impl;
|
||||
@@ -85,14 +88,15 @@ TimerQueryFactoryInterface::~TimerQueryFactoryInterface() = default;
|
||||
// This is a backend synchronous call
|
||||
TimerQueryResult TimerQueryFactoryInterface::getTimerQueryValue(
|
||||
GLTimerQuery* tq, uint64_t* elapsedTime) noexcept {
|
||||
assert_invariant(tq->state);
|
||||
|
||||
int64_t const elapsed = tq->state->elapsed.load(std::memory_order_relaxed);
|
||||
if (elapsed > 0) {
|
||||
*elapsedTime = elapsed;
|
||||
return TimerQueryResult::AVAILABLE;
|
||||
if (UTILS_LIKELY(tq->state)) {
|
||||
int64_t const elapsed = tq->state->elapsed.load(std::memory_order_relaxed);
|
||||
if (elapsed > 0) {
|
||||
*elapsedTime = elapsed;
|
||||
return TimerQueryResult::AVAILABLE;
|
||||
}
|
||||
return TimerQueryResult(elapsed);
|
||||
}
|
||||
return TimerQueryResult(elapsed);
|
||||
return TimerQueryResult::ERROR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -106,8 +110,9 @@ TimerQueryNativeFactory::TimerQueryNativeFactory(OpenGLContext& context)
|
||||
TimerQueryNativeFactory::~TimerQueryNativeFactory() = default;
|
||||
|
||||
void TimerQueryNativeFactory::createTimerQuery(GLTimerQuery* tq) {
|
||||
assert_invariant(tq->state);
|
||||
assert_invariant(!tq->state);
|
||||
|
||||
tq->state = std::make_shared<GLTimerQuery::State>();
|
||||
mContext.procs.genQueries(1u, &tq->state->gl.query);
|
||||
CHECK_GL_ERROR()
|
||||
}
|
||||
@@ -176,7 +181,8 @@ TimerQueryFenceFactory::~TimerQueryFenceFactory() {
|
||||
}
|
||||
|
||||
void TimerQueryFenceFactory::createTimerQuery(GLTimerQuery* tq) {
|
||||
assert_invariant(tq->state);
|
||||
assert_invariant(!tq->state);
|
||||
tq->state = std::make_shared<GLTimerQuery::State>();
|
||||
}
|
||||
|
||||
void TimerQueryFenceFactory::destroyTimerQuery(GLTimerQuery* tq) {
|
||||
@@ -232,7 +238,8 @@ TimerQueryFallbackFactory::TimerQueryFallbackFactory() = default;
|
||||
TimerQueryFallbackFactory::~TimerQueryFallbackFactory() = default;
|
||||
|
||||
void TimerQueryFallbackFactory::createTimerQuery(GLTimerQuery* tq) {
|
||||
assert_invariant(tq->state);
|
||||
assert_invariant(!tq->state);
|
||||
tq->state = std::make_shared<GLTimerQuery::State>();
|
||||
}
|
||||
|
||||
void TimerQueryFallbackFactory::destroyTimerQuery(GLTimerQuery* tq) {
|
||||
|
||||
@@ -61,9 +61,14 @@ struct GLTimerQuery : public HwTimerQuery {
|
||||
*/
|
||||
|
||||
class TimerQueryFactory {
|
||||
static bool mGpuTimeSupported;
|
||||
public:
|
||||
static TimerQueryFactoryInterface* init(
|
||||
OpenGLPlatform& platform, OpenGLContext& context);
|
||||
|
||||
static bool isGpuTimeSupported() noexcept {
|
||||
return mGpuTimeSupported;
|
||||
}
|
||||
};
|
||||
|
||||
class TimerQueryFactoryInterface {
|
||||
|
||||
@@ -117,13 +117,6 @@ struct ShaderCompilerService::OpenGLProgramToken : ProgramToken {
|
||||
cond.wait(l, [this] { return signaled; });
|
||||
}
|
||||
|
||||
// Used in THREAD_POOL mode. Returns true if the token is signaled, meaning it's ready to be
|
||||
// used.
|
||||
bool isReady() const noexcept {
|
||||
std::unique_lock const l(lock);
|
||||
return signaled;
|
||||
}
|
||||
|
||||
// This is invoked upon token completion, which occurs after a successful `gl.program`
|
||||
// population or upon cancellation. In either scenario, the callback handle must be submitted
|
||||
// to notify the caller that resource loading has concluded.
|
||||
@@ -367,15 +360,14 @@ void ShaderCompilerService::compileProgram(
|
||||
<< " failed to link or compile";
|
||||
#endif
|
||||
}
|
||||
// The program blob is cached prior to signaling to ensure data integrity.
|
||||
// Since the receiving thread may immediately modify gl.program (e.g., via
|
||||
// glUniformBlockBinding) upon receipt of the signal, caching must be
|
||||
// finalized first.
|
||||
tryCachingProgram(mBlobCache, mDriver.mPlatform, token);
|
||||
// Now `token->gl.program` must be populated, so we signal the completion
|
||||
// of the linking. We don't need to check the result of the program here
|
||||
// because it'll be done in the engine thread.
|
||||
token->signal();
|
||||
// We try caching the program blob after sending the signal. This allows us
|
||||
// to unblock the engine thread as soon as the token is ready while
|
||||
// performing an expensive caching operation still in the pool.
|
||||
tryCachingProgram(mBlobCache, mDriver.mPlatform, token);
|
||||
// Updates the token's state. If the token is canceled while this function
|
||||
// executes, this update notifies `tick` that GL resource loading is
|
||||
// complete, allowing `tick` to proceed with resource destruction.
|
||||
@@ -532,15 +524,8 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) {
|
||||
}
|
||||
|
||||
void ShaderCompilerService::ensureTokenIsReady(program_token_t const& token) {
|
||||
if (mMode == Mode::THREAD_POOL) {
|
||||
// Check if `token->gl.program` is populated
|
||||
if (token->isReady()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (token->gl.program) {
|
||||
return;
|
||||
}
|
||||
if (token->gl.program) {
|
||||
return;// It's ready.
|
||||
}
|
||||
|
||||
switch (mMode) {
|
||||
@@ -950,7 +935,6 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
return false;
|
||||
}
|
||||
token->retrievedFromBlobCache = true;
|
||||
token->signal(); // notify that `token->gl.program` is ready to use
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,9 +80,6 @@ JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept {
|
||||
|
||||
Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept {
|
||||
// note: This is called on the application thread (not the GL thread)
|
||||
// The application thread *MUST* be attached to the JVM to pass the java 'surfaceTexture' down
|
||||
// to filament natively, so we are guaranteed to get a valid JNIEnv from getThreadEnvironment()
|
||||
// without needing AttachCurrentThread.
|
||||
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
|
||||
if (!env) {
|
||||
return nullptr; // this should not happen
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
@@ -120,41 +119,31 @@ bool PlatformEGL::isOpenGL() const noexcept {
|
||||
|
||||
PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default;
|
||||
|
||||
void PlatformEGL::setEglDisplay(EGLDisplay display) noexcept {
|
||||
FILAMENT_CHECK_PRECONDITION(mEGLDisplay == EGL_NO_DISPLAY)
|
||||
<< "EGL Display has already been set.";
|
||||
FILAMENT_CHECK_PRECONDITION(display != EGL_NO_DISPLAY)
|
||||
<< "Must specify a valid EGL Display.";
|
||||
mEGLDisplay = display;
|
||||
}
|
||||
|
||||
Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) {
|
||||
if (mEGLDisplay == EGL_NO_DISPLAY) {
|
||||
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
||||
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);
|
||||
|
||||
EGLint major, minor;
|
||||
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||
EGLint major, minor;
|
||||
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||
|
||||
if (!initialized) {
|
||||
EGLDeviceEXT eglDevice;
|
||||
EGLint numDevices;
|
||||
PFNEGLQUERYDEVICESEXTPROC const eglQueryDevicesEXT =
|
||||
PFNEGLQUERYDEVICESEXTPROC(eglGetProcAddress("eglQueryDevicesEXT"));
|
||||
if (eglQueryDevicesEXT != nullptr) {
|
||||
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
|
||||
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
|
||||
eglGetProcAddress("eglGetPlatformDisplay"))) {
|
||||
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
|
||||
initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||
}
|
||||
if (!initialized) {
|
||||
EGLDeviceEXT eglDevice;
|
||||
EGLint numDevices;
|
||||
PFNEGLQUERYDEVICESEXTPROC const eglQueryDevicesEXT =
|
||||
PFNEGLQUERYDEVICESEXTPROC(eglGetProcAddress("eglQueryDevicesEXT"));
|
||||
if (eglQueryDevicesEXT != nullptr) {
|
||||
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
|
||||
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
|
||||
eglGetProcAddress("eglGetPlatformDisplay"))) {
|
||||
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, nullptr);
|
||||
initialized = eglInitialize(mEGLDisplay, &major, &minor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(!initialized)) {
|
||||
LOG(ERROR) << "eglInitialize failed";
|
||||
return nullptr;
|
||||
}
|
||||
if (UTILS_UNLIKELY(!initialized)) {
|
||||
LOG(ERROR) << "eglInitialize failed";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(FILAMENT_IMPORT_ENTRY_POINTS)
|
||||
@@ -717,11 +706,10 @@ bool PlatformEGL::setExternalImage(ExternalImageHandleRef externalImage,
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
void PlatformEGL::initializeGlExtensions() noexcept {
|
||||
// We're guaranteed to be on an ES platform, since we're using EGL
|
||||
const char* const extensions = (const char*)glGetString(GL_EXTENSIONS);
|
||||
if (extensions) {
|
||||
GLUtils::unordered_string_set const glExtensions = GLUtils::split(extensions);
|
||||
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
|
||||
}
|
||||
GLUtils::unordered_string_set const glExtensions = GLUtils::split(extensions);
|
||||
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
|
||||
}
|
||||
|
||||
EGLContext PlatformEGL::getContextForType(ContextType const type) const noexcept {
|
||||
|
||||
@@ -120,7 +120,8 @@ struct PlatformEGLAndroid::AndroidDetails {
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
|
||||
: mAndroidDetails(*(new(std::nothrow) AndroidDetails{})) {
|
||||
: mExternalStreamManager(ExternalStreamManagerAndroid::create()),
|
||||
mAndroidDetails(*(new(std::nothrow) AndroidDetails{})) {
|
||||
mOSVersion = android_get_device_api_level();
|
||||
if (mOSVersion < 0) {
|
||||
mOSVersion = __ANDROID_API_FUTURE__;
|
||||
@@ -134,10 +135,7 @@ PlatformEGLAndroid::~PlatformEGLAndroid() noexcept {
|
||||
void PlatformEGLAndroid::terminate() noexcept {
|
||||
mPerformanceHintManager.terminate();
|
||||
mAndroidDetails.androidFrameCallback.terminate();
|
||||
if (mExternalStreamManager) {
|
||||
ExternalStreamManagerAndroid::destroy(mExternalStreamManager);
|
||||
mExternalStreamManager = nullptr;
|
||||
}
|
||||
ExternalStreamManagerAndroid::destroy(&mExternalStreamManager);
|
||||
PlatformEGL::terminate();
|
||||
}
|
||||
|
||||
@@ -227,10 +225,6 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
|
||||
mPerformanceHintSession = PerformanceHintManager::Session{
|
||||
mPerformanceHintManager, &tid, 1, 16'666'667 };
|
||||
|
||||
mExternalStreamManager = &ExternalStreamManagerAndroid::create();
|
||||
FILAMENT_CHECK_POSTCONDITION(mExternalStreamManager)
|
||||
<< "Failed to create ExternalStreamManagerAndroid";
|
||||
|
||||
Driver* driver = PlatformEGL::createDriver(sharedContext, driverConfig);
|
||||
auto const extensions = GLUtils::split(eglQueryString(getEglDisplay(), EGL_EXTENSIONS));
|
||||
|
||||
@@ -617,13 +611,11 @@ void PlatformEGLAndroid::setPresentationTime(int64_t const presentationTimeInNan
|
||||
}
|
||||
|
||||
Platform::Stream* PlatformEGLAndroid::createStream(void* nativeStream) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
return mExternalStreamManager->acquire(static_cast<jobject>(nativeStream));
|
||||
return mExternalStreamManager.acquire(static_cast<jobject>(nativeStream));
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::destroyStream(Stream* stream) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
mExternalStreamManager->release(stream);
|
||||
mExternalStreamManager.release(stream);
|
||||
}
|
||||
|
||||
Platform::Sync* PlatformEGLAndroid::createSync() noexcept {
|
||||
@@ -675,23 +667,19 @@ void PlatformEGLAndroid::destroySync(Sync* sync) noexcept {
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::attach(Stream* stream, intptr_t const tname) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
mExternalStreamManager->attach(stream, tname);
|
||||
mExternalStreamManager.attach(stream, tname);
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::detach(Stream* stream) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
mExternalStreamManager->detach(stream);
|
||||
mExternalStreamManager.detach(stream);
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
mExternalStreamManager->updateTexImage(stream, timestamp);
|
||||
mExternalStreamManager.updateTexImage(stream, timestamp);
|
||||
}
|
||||
|
||||
math::mat3f PlatformEGLAndroid::getTransformMatrix(Stream* stream) noexcept {
|
||||
assert_invariant(mExternalStreamManager);
|
||||
return mExternalStreamManager->getTransformMatrix(stream);
|
||||
return mExternalStreamManager.getTransformMatrix(stream);
|
||||
}
|
||||
|
||||
int PlatformEGLAndroid::getOSVersion() const noexcept {
|
||||
|
||||
@@ -137,14 +137,6 @@ public:
|
||||
return mFenceExportFlags;
|
||||
}
|
||||
|
||||
inline const char* getPhysicalDeviceName() const noexcept {
|
||||
return mPhysicalDeviceProperties.properties.deviceName;
|
||||
}
|
||||
|
||||
inline const char* getDriverName() const noexcept { return mDriverProperties.driverName; }
|
||||
|
||||
inline const char* getDriverInfo() const noexcept { return mDriverProperties.driverInfo; }
|
||||
|
||||
inline bool isImageCubeArraySupported() const noexcept {
|
||||
return mPhysicalDeviceFeatures.features.imageCubeArray == VK_TRUE;
|
||||
}
|
||||
@@ -220,16 +212,11 @@ public:
|
||||
return mGlobalPrioritySupported;
|
||||
}
|
||||
|
||||
inline bool isDriverPropertiesSupported() const noexcept { return mDriverPropertiesSupported; }
|
||||
|
||||
private:
|
||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
};
|
||||
VkPhysicalDeviceDriverProperties mDriverProperties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES,
|
||||
};
|
||||
VkPhysicalDeviceVulkan11Features mPhysicalDeviceVk11Features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
|
||||
};
|
||||
@@ -259,7 +246,6 @@ private:
|
||||
bool mProtectedMemorySupported = false;
|
||||
bool mVertexInputDynamicStateSupported = false;
|
||||
bool mGlobalPrioritySupported = false;
|
||||
bool mDriverPropertiesSupported = false;
|
||||
|
||||
// These are options that can be enabled or disabled at an application level.
|
||||
bool mAsyncPipelineCachePrewarmingEnabled = false;
|
||||
|
||||
@@ -260,8 +260,7 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext& context,
|
||||
mPipelineCache(*this, mPlatform->getDevice(), mContext),
|
||||
mStagePool(mAllocator, &mResourceManager, &mCommands, &mContext.getPhysicalDeviceLimits()),
|
||||
mBufferCache(mContext, mResourceManager, mAllocator),
|
||||
mFramebufferCache(mPlatform->getDevice(),
|
||||
mPlatform->getCustomization().timeBeforeEvictionFbo),
|
||||
mFramebufferCache(mPlatform->getDevice()),
|
||||
mYcbcrConversionCache(mPlatform->getDevice()),
|
||||
mSamplerCache(mPlatform->getDevice()),
|
||||
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "VulkanHandles.h"
|
||||
#include "vulkan/utils/Image.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
// If any VkRenderPass or VkFramebuffer is unused for more than TIME_BEFORE_EVICTION frames, it
|
||||
@@ -63,9 +62,8 @@ bool VulkanFboCache::FboKeyEqualFn::operator()(const FboKey& k1, const FboKey& k
|
||||
return true;
|
||||
}
|
||||
|
||||
VulkanFboCache::VulkanFboCache(VkDevice device, uint32_t timeBeforeEvictionFbo)
|
||||
: mDevice(device),
|
||||
mTimeBeforeEvictionFbo(timeBeforeEvictionFbo) {}
|
||||
VulkanFboCache::VulkanFboCache(VkDevice device)
|
||||
: mDevice(device) {}
|
||||
|
||||
VulkanFboCache::~VulkanFboCache() {
|
||||
FILAMENT_CHECK_POSTCONDITION(mFramebufferCache.empty() && mRenderPassCache.empty())
|
||||
@@ -378,36 +376,31 @@ void VulkanFboCache::gc() noexcept {
|
||||
FVK_SYSTRACE_START("fbocache::gc");
|
||||
|
||||
// If this is one of the first few frames, return early to avoid wrapping unsigned integers.
|
||||
++mCurrentTime;
|
||||
if (++mCurrentTime <= TIME_BEFORE_EVICTION) {
|
||||
return;
|
||||
}
|
||||
const uint32_t evictTime = mCurrentTime - TIME_BEFORE_EVICTION;
|
||||
|
||||
if (UTILS_UNLIKELY(mCurrentTime > mTimeBeforeEvictionFbo)) {
|
||||
const uint32_t evictTimeFbo = mCurrentTime - mTimeBeforeEvictionFbo;
|
||||
for (FboMap::iterator iter = mFramebufferCache.begin(); iter != mFramebufferCache.end();) {
|
||||
const FboVal fbo = iter->second;
|
||||
if (fbo.timestamp < evictTimeFbo && fbo.handle) {
|
||||
mRenderPassRefCount[iter->first.renderPass]--;
|
||||
for (FboMap::iterator iter = mFramebufferCache.begin(); iter != mFramebufferCache.end(); ) {
|
||||
const FboVal fbo = iter->second;
|
||||
if (fbo.timestamp < evictTime && fbo.handle) {
|
||||
mRenderPassRefCount[iter->first.renderPass]--;
|
||||
|
||||
// erase(iterator) returns the iterator to the next element.
|
||||
iter = mFramebufferCache.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
// erase(iterator) returns the iterator to the next element.
|
||||
iter = mFramebufferCache.erase(iter);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(mCurrentTime > TIME_BEFORE_EVICTION)) {
|
||||
const uint32_t evictTimeRp = mCurrentTime - TIME_BEFORE_EVICTION;
|
||||
for (RenderPassMap::iterator iter = mRenderPassCache.begin();
|
||||
iter != mRenderPassCache.end();) {
|
||||
const VkRenderPass handle = iter->second.handle->getVkRenderPass();
|
||||
if (iter->second.timestamp < evictTimeRp && handle &&
|
||||
mRenderPassRefCount[handle] == 0) {
|
||||
// erase(iterator) returns the iterator to the next element.
|
||||
iter = mRenderPassCache.erase(iter);
|
||||
mRenderPassRefCount.erase(handle);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
for (RenderPassMap::iterator iter = mRenderPassCache.begin(); iter != mRenderPassCache.end(); ) {
|
||||
const VkRenderPass handle = iter->second.handle->getVkRenderPass();
|
||||
if (iter->second.timestamp < evictTime && handle && mRenderPassRefCount[handle] == 0) {
|
||||
// erase(iterator) returns the iterator to the next element.
|
||||
iter = mRenderPassCache.erase(iter);
|
||||
mRenderPassRefCount.erase(handle);
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
bool operator()(const FboKey& k1, const FboKey& k2) const;
|
||||
};
|
||||
|
||||
explicit VulkanFboCache(VkDevice device, uint32_t timeBeforeEvictionFbo);
|
||||
explicit VulkanFboCache(VkDevice device);
|
||||
~VulkanFboCache();
|
||||
|
||||
// Retrieves or creates a VkFramebuffer handle.
|
||||
@@ -130,7 +130,6 @@ private:
|
||||
RenderPassMap mRenderPassCache;
|
||||
tsl::robin_map<VkRenderPass, uint32_t> mRenderPassRefCount;
|
||||
uint32_t mCurrentTime = 0;
|
||||
uint32_t mTimeBeforeEvictionFbo;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -704,30 +704,6 @@ VulkanPlatform::VulkanPlatform() = default;
|
||||
|
||||
VulkanPlatform::~VulkanPlatform() = default;
|
||||
|
||||
utils::CString VulkanPlatform::getDeviceInfo(DeviceInfoType infoType,
|
||||
Driver* driver) const noexcept {
|
||||
if (mImpl->mPhysicalDevice == VK_NULL_HANDLE) {
|
||||
return {};
|
||||
}
|
||||
auto& context = mImpl->mContext;
|
||||
switch (infoType) {
|
||||
case DeviceInfoType::VULKAN_DEVICE_NAME: {
|
||||
return utils::CString(context.getPhysicalDeviceName());
|
||||
}
|
||||
case DeviceInfoType::VULKAN_DRIVER_NAME: {
|
||||
return context.isDriverPropertiesSupported() ? utils::CString(context.getDriverName())
|
||||
: utils::CString();
|
||||
}
|
||||
case DeviceInfoType::VULKAN_DRIVER_INFO: {
|
||||
return context.isDriverPropertiesSupported() ? utils::CString(context.getDriverInfo())
|
||||
: utils::CString();
|
||||
}
|
||||
default:
|
||||
FILAMENT_CHECK_POSTCONDITION(false) << "Unsupported DeviceInfoType for VulkanPlatform";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPlatform::SwapChainBundle VulkanPlatform::getSwapChainBundle(SwapChainPtr handle) {
|
||||
return static_cast<VulkanPlatformSwapChainBase*>(handle)->getSwapChainBundle();
|
||||
}
|
||||
@@ -976,11 +952,6 @@ void VulkanPlatform::queryAndSetDeviceFeatures(Platform::DriverConfig const& dri
|
||||
chainStruct(&context.mPhysicalDeviceFeatures, &globalPriorityFeatures);
|
||||
}
|
||||
|
||||
if (vkGetPhysicalDeviceProperties2) {
|
||||
chainStruct(&context.mPhysicalDeviceProperties, &context.mDriverProperties);
|
||||
context.mDriverPropertiesSupported = true;
|
||||
}
|
||||
|
||||
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
||||
// physicalDeviceFeatures.
|
||||
vkGetPhysicalDeviceProperties2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceProperties);
|
||||
|
||||
@@ -192,15 +192,8 @@ void WebGPUDriver::flush(int) {
|
||||
}
|
||||
|
||||
void WebGPUDriver::finish(int /* dummy */) {
|
||||
mReadPixelMapsCounter.waitForAllToFinish();
|
||||
mQueueManager.finish();
|
||||
|
||||
// We use polling to advance webgpu's callback counter until all the read backs have been
|
||||
// processed. Note that blocking with mReadPixelMapsCounter.waitForAllToFinish will only
|
||||
// deadlock since we could not advance the counter.
|
||||
while (!mReadPixelMapsCounter.isIdle()) {
|
||||
mAdapter.GetInstance().ProcessEvents();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
void WebGPUDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
@@ -947,6 +940,10 @@ size_t WebGPUDriver::getUniformBufferOffsetAlignment(){
|
||||
|
||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> indexBufferHandle,
|
||||
BufferDescriptor&& bufferDescriptor, const uint32_t byteOffset) {
|
||||
// make sure command elements (draws, etc.) prior to the buffer update are processed before the
|
||||
// update on the GPU, otherwise the expected data may not be available at the time certain
|
||||
// draw calls are made.
|
||||
flush();
|
||||
handleCast<WebGPUIndexBuffer>(indexBufferHandle)
|
||||
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager, &mStagePool);
|
||||
scheduleDestroy(std::move(bufferDescriptor));
|
||||
@@ -961,6 +958,10 @@ void WebGPUDriver::updateIndexBufferAsyncR(AsyncCallId jobId,
|
||||
|
||||
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> bufferObjectHandle,
|
||||
BufferDescriptor&& bufferDescriptor, const uint32_t byteOffset) {
|
||||
// make sure command elements (draws, etc.) prior to the buffer update are processed before the
|
||||
// update on the GPU, otherwise the expected data may not be available at the time certain
|
||||
// draw calls are made.
|
||||
flush();
|
||||
handleCast<WebGPUBufferObject>(bufferObjectHandle)
|
||||
->updateGPUBuffer(bufferDescriptor, byteOffset, mDevice, &mQueueManager, &mStagePool);
|
||||
scheduleDestroy(std::move(bufferDescriptor));
|
||||
@@ -1007,6 +1008,10 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
|
||||
const uint32_t xoffset, const uint32_t yoffset, const uint32_t zoffset,
|
||||
const uint32_t width, const uint32_t height, const uint32_t depth,
|
||||
PixelBufferDescriptor&& pixelBufferDescriptor) {
|
||||
// one way or another this function writes texture(s), thus any commands (draw calls etc.) should
|
||||
// get submitted prior to these updates so that subsequent commands/draws run with the
|
||||
// image/texture(s) updated as expected.
|
||||
flush();
|
||||
PixelBufferDescriptor* inputData{ &pixelBufferDescriptor };
|
||||
PixelBufferDescriptor reshapedData;
|
||||
if (reshape(pixelBufferDescriptor, reshapedData)) {
|
||||
@@ -1178,6 +1183,11 @@ void WebGPUDriver::generateMipmaps(Handle<HwTexture> textureHandle) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
// make sure command elements (draws, etc.) prior to the texture update are processed before the
|
||||
// update on the GPU.
|
||||
// this ensures subsequent draw calls are run after the mipmaps have been generated as expected
|
||||
flush();
|
||||
|
||||
const auto usage = wgpuTexture.GetUsage();
|
||||
FILAMENT_CHECK_PRECONDITION(usage & wgpu::TextureUsage::TextureBinding)
|
||||
<< "Texture for mipmap generation must have TextureBinding usage.";
|
||||
@@ -1366,9 +1376,6 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> renderTargetHandle,
|
||||
customDepthStencilMsaaSidecarTextureView);
|
||||
|
||||
mRenderPassEncoder = commandEncoder.BeginRenderPass(&renderPassDescriptor);
|
||||
|
||||
// TODO: there's a bug here because the webgpu viewport has the origin at top-left, whereas
|
||||
// filament expects it to be bottom left.
|
||||
mRenderPassEncoder.SetViewport(
|
||||
static_cast<float>(params.viewport.left),
|
||||
static_cast<float>(params.viewport.bottom),
|
||||
@@ -1456,6 +1463,7 @@ void WebGPUDriver::stopCapture(int /* dummy */) {
|
||||
void WebGPUDriver::readPixels(Handle<HwRenderTarget> sourceRenderTargetHandle, const uint32_t x,
|
||||
const uint32_t y, const uint32_t width, const uint32_t height,
|
||||
PixelBufferDescriptor&& pixelBufferDescriptor) {
|
||||
flush();
|
||||
const auto srcTarget{ handleCast<WebGPURenderTarget>(sourceRenderTargetHandle) };
|
||||
assert_invariant(srcTarget);
|
||||
|
||||
@@ -1513,7 +1521,10 @@ void WebGPUDriver::readTextureToBuffer(wgpu::Texture srcTexture, uint32_t level,
|
||||
return;
|
||||
}
|
||||
|
||||
auto commandEncoder = mQueueManager.getCommandEncoder();
|
||||
const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
|
||||
.label = "read_texture_to_buffer_command",
|
||||
};
|
||||
auto commandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(commandEncoder)
|
||||
<< "Failed to create command encoder for readTextureToBuffer?";
|
||||
|
||||
@@ -1635,6 +1646,9 @@ void WebGPUDriver::readTextureToBuffer(wgpu::Texture srcTexture, uint32_t level,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
commandEncoder.CopyTextureToBuffer(&source, &destination, ©Size);
|
||||
wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
|
||||
assert_invariant(commandBuffer);
|
||||
mDevice.GetQueue().Submit(1, &commandBuffer);
|
||||
|
||||
// Map the buffer to read the data
|
||||
struct UserData final {
|
||||
@@ -1655,9 +1669,6 @@ void WebGPUDriver::readTextureToBuffer(wgpu::Texture srcTexture, uint32_t level,
|
||||
});
|
||||
|
||||
mReadPixelMapsCounter.startTask();
|
||||
// We need to flush here before we can readback from the staging buffer since the copy op is
|
||||
// pending to be submitted.
|
||||
mQueueManager.flush();
|
||||
userData->buffer.MapAsync(
|
||||
wgpu::MapMode::Read, 0, bufferSize, wgpu::CallbackMode::AllowSpontaneous,
|
||||
[](wgpu::MapAsyncStatus status, const char* message, UserData* userdata) {
|
||||
@@ -1750,6 +1761,7 @@ void WebGPUDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
const wgpu::Extent2D destinationSize{ static_cast<uint32_t>(destinationViewport.width),
|
||||
static_cast<uint32_t>(destinationViewport.height) };
|
||||
|
||||
mQueueManager.flush();
|
||||
wgpu::CommandEncoder commandEncoder = mQueueManager.getCommandEncoder();
|
||||
const WebGPUBlitter::BlitArgs blitArgs{
|
||||
.source = { .texture = sourceTexture->getTexture(),
|
||||
@@ -1769,6 +1781,8 @@ void WebGPUDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
.filter = filter,
|
||||
};
|
||||
mBlitter.blit(mDevice.GetQueue(), commandEncoder, blitArgs);
|
||||
|
||||
mQueueManager.flush();
|
||||
}
|
||||
|
||||
void WebGPUDriver::resolve(Handle<HwTexture> destinationTextureHandle, const uint8_t sourceLevel,
|
||||
@@ -1808,6 +1822,7 @@ void WebGPUDriver::blit(Handle<HwTexture> destinationTextureHandle, const uint8_
|
||||
Handle<HwTexture> sourceTextureHandle, const uint8_t destinationLevel,
|
||||
const uint8_t destinationLayer, const math::uint2 sourceOrigin, const math::uint2 size) {
|
||||
FWGPU_SYSTRACE_SCOPE();
|
||||
mQueueManager.flush();
|
||||
wgpu::CommandEncoder commandEncoder = mQueueManager.getCommandEncoder();
|
||||
const auto sourceTexture{ handleCast<WebGPUTexture>(sourceTextureHandle) };
|
||||
const auto destinationTexture{ handleCast<WebGPUTexture>(destinationTextureHandle) };
|
||||
@@ -1831,6 +1846,7 @@ void WebGPUDriver::blit(Handle<HwTexture> destinationTextureHandle, const uint8_
|
||||
.filter = SamplerMagFilter::NEAREST,
|
||||
};
|
||||
mBlitter.blit(mDevice.GetQueue(), commandEncoder, blitArgs);
|
||||
mQueueManager.flush();
|
||||
}
|
||||
|
||||
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
|
||||
@@ -1970,19 +1986,9 @@ void WebGPUDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGr
|
||||
//todo
|
||||
}
|
||||
|
||||
void WebGPUDriver::scissor(Viewport scissor) {
|
||||
assert_invariant(mRenderPassEncoder);
|
||||
assert_invariant(mCurrentRenderTarget);
|
||||
|
||||
// The WebGPU scissor starts from the top-left corner
|
||||
assert_invariant(scissor.left >= 0 &&
|
||||
mCurrentRenderTarget->height >= scissor.bottom + scissor.height /*top >= 0*/ &&
|
||||
scissor.width <= mCurrentRenderTarget->width &&
|
||||
scissor.height <= mCurrentRenderTarget->height);
|
||||
|
||||
mRenderPassEncoder.SetScissorRect(scissor.left,
|
||||
mCurrentRenderTarget->height - scissor.bottom - scissor.height /*top*/, scissor.width,
|
||||
scissor.height);
|
||||
void WebGPUDriver::scissor(
|
||||
Viewport scissor) {
|
||||
//todo
|
||||
}
|
||||
|
||||
void WebGPUDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
|
||||
|
||||
@@ -50,9 +50,6 @@ public:
|
||||
|
||||
[[nodiscard]] bool isHeadless() const { return mType == SwapChainType::HEADLESS; }
|
||||
|
||||
[[nodiscard]] uint32_t getWidth() const { return mConfig.width; }
|
||||
[[nodiscard]] uint32_t getHeight() const { return mConfig.height; }
|
||||
|
||||
void present(DriverBase& driver);
|
||||
|
||||
void setFrameScheduledCallback(CallbackHandler* handler, FrameScheduledCallback&& callback) {
|
||||
|
||||
@@ -41,10 +41,5 @@ void AsyncTaskCounter::waitForAllToFinish() {
|
||||
mFinishedCondition.wait(lock, [this] { return mTasksInProgress == 0; });
|
||||
}
|
||||
|
||||
bool AsyncTaskCounter::isIdle() {
|
||||
std::lock_guard<std::mutex> lock{ mMutex };
|
||||
return mTasksInProgress == 0;
|
||||
}
|
||||
|
||||
} // namespace filament::backend::webgpuutils
|
||||
|
||||
|
||||
@@ -51,11 +51,6 @@ public:
|
||||
*/
|
||||
void waitForAllToFinish();
|
||||
|
||||
/**
|
||||
* Check if all tasks have finished (work counter is 0) (thread-safe)
|
||||
*/
|
||||
bool isIdle();
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
std::condition_variable mFinishedCondition;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "PlatformRunner.h"
|
||||
|
||||
#include <utils/getopt.h>
|
||||
#include <getopt/getopt.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -30,18 +30,18 @@ TestArguments parseArguments(int argc, char* argv[]) {
|
||||
// The first colon in OPTSTR turns on silent error reporting. This is important, as the
|
||||
// arguments may also contain gtest parameters we don't know about.
|
||||
static constexpr const char* OPTSTR = ":a:kc";
|
||||
static const utils::getopt::option OPTIONS[] = {
|
||||
{ "api", utils::getopt::required_argument, nullptr, 'a' },
|
||||
{ "headless_only", utils::getopt::no_argument, nullptr, 'k' },
|
||||
{ "ci", utils::getopt::no_argument, nullptr, 'c' },
|
||||
{ nullptr, 0, nullptr, 0 } // termination of the utils::getopt::option list
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ "headless_only", no_argument, nullptr, 'k' },
|
||||
{ "ci", no_argument, nullptr, 'c' },
|
||||
{ nullptr, 0, nullptr, 0 } // termination of the option list
|
||||
};
|
||||
|
||||
int opt;
|
||||
int optionIndex = 0;
|
||||
|
||||
while ((opt = utils::getopt::getopt_long(argc, argv, OPTSTR, OPTIONS, &optionIndex)) >= 0) {
|
||||
std::string arg(utils::getopt::optarg ? utils::getopt::optarg : "");
|
||||
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &optionIndex)) >= 0) {
|
||||
std::string arg(optarg ? optarg : "");
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
if (arg == "opengl") {
|
||||
|
||||
@@ -35,10 +35,9 @@ test::NativeView getNativeView() {
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<test::Backend, 3> const VALID_BACKENDS{
|
||||
test::Backend::OPENGL,
|
||||
test::Backend::VULKAN,
|
||||
test::Backend::WEBGPU
|
||||
std::array<test::Backend, 2> const VALID_BACKENDS{
|
||||
test::Backend::OPENGL,
|
||||
test::Backend::VULKAN,
|
||||
};
|
||||
|
||||
}// namespace
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user