Compare commits
25 Commits
ebridgewat
...
ebridgewat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43ab60521c | ||
|
|
b7c685647a | ||
|
|
d45a5cc926 | ||
|
|
361ba2afea | ||
|
|
78419cd992 | ||
|
|
cc7361dba5 | ||
|
|
5c0841ff56 | ||
|
|
10af183756 | ||
|
|
56e0e9a424 | ||
|
|
86a500c846 | ||
|
|
5b3f13fc1d | ||
|
|
1b1dfaa57c | ||
|
|
bf8c84bbe5 | ||
|
|
fb179cabbc | ||
|
|
a80ea743e8 | ||
|
|
97f8106909 | ||
|
|
d455899b93 | ||
|
|
63fe439a5e | ||
|
|
7847220aba | ||
|
|
d76ae4395b | ||
|
|
f994cb58ce | ||
|
|
52eb682498 | ||
|
|
5a5168a191 | ||
|
|
e85dfe75c8 | ||
|
|
6beb40b0a1 |
2
.github/workflows/mac-continuous.yml
vendored
2
.github/workflows/mac-continuous.yml
vendored
@@ -26,4 +26,4 @@ jobs:
|
||||
path: out/filament-release-darwin.tgz
|
||||
- name: Check public headers
|
||||
run: |
|
||||
build/common/check-headers.sh out/release/filament/include
|
||||
test/check-headers/test.sh out/release/filament/include
|
||||
|
||||
6
.github/workflows/presubmit.yml
vendored
6
.github/workflows/presubmit.yml
vendored
@@ -131,7 +131,7 @@ jobs:
|
||||
- name: Prerequisites
|
||||
id: prereqs
|
||||
run: |
|
||||
bash test/utils/get_mesa.sh
|
||||
bash build/common/get-mesa.sh
|
||||
pip install tifffile numpy
|
||||
- name: Run Test
|
||||
run: bash test/renderdiff/test.sh
|
||||
@@ -153,8 +153,8 @@ jobs:
|
||||
- name: Run test
|
||||
run: ./out/cmake-debug/libs/filamat/test_filamat --gtest_filter=MaterialCompiler.Wgsl*
|
||||
|
||||
code-correctness:
|
||||
name: code-correctness
|
||||
test-code-correctness:
|
||||
name: test-code-correctness
|
||||
runs-on: 'macos-14-xlarge'
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -163,6 +163,9 @@ jobs:
|
||||
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
|
||||
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
|
||||
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
|
||||
cd out/android-release/filament
|
||||
tar -czf ../../filament-${TAG}-android-native.tgz .
|
||||
cd ../../..
|
||||
- name: Sign sample-gltf-viewer
|
||||
run: |
|
||||
echo "${APK_KEYSTORE_BASE64}" > filament.jks.base64
|
||||
@@ -184,7 +187,7 @@ jobs:
|
||||
script: |
|
||||
const upload = require('./build/common/upload-release-assets');
|
||||
const { TAG } = process.env;
|
||||
const globber = await glob.create(['out/*.aar', 'out/*.apk'].join('\n'));
|
||||
const globber = await glob.create(['out/*.aar', 'out/*.apk', 'out/*.tgz'].join('\n'));
|
||||
await upload({ github, context }, await globber.glob(), TAG);
|
||||
|
||||
build-ios:
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.59.5'
|
||||
implementation 'com.google.android.filament:filament-android:1.60.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,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.59.5'
|
||||
pod 'Filament', '~> 1.60.0'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,10 +7,15 @@ 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.60.1
|
||||
|
||||
|
||||
## v1.60.0
|
||||
|
||||
- materials: remove dependence on per-view descset layout from filamat. [⚠️ **New Material Version**]
|
||||
- `ColorGrading::Builder::toneMapper` now takes a `shared_ptr<ToneMapper>`
|
||||
- matc non-functional change: Update GLSL postprocessor to
|
||||
isolate calls to SPVRemap from calls to SPIRV-Cross.
|
||||
|
||||
|
||||
## v1.59.5
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/ToneMapper.h>
|
||||
#include <memory>
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
@@ -68,9 +67,8 @@ extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_ColorGrading_nBuilderToneMapper(JNIEnv*, jclass,
|
||||
jlong nativeBuilder, jlong toneMapper_) {
|
||||
ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder;
|
||||
ToneMapper* toneMapper = reinterpret_cast<ToneMapper*>(toneMapper_);
|
||||
std::shared_ptr<ToneMapper> toneMapperCopy(toneMapper->clone());
|
||||
builder->toneMapper(toneMapperCopy);
|
||||
const ToneMapper* toneMapper = (const ToneMapper*) toneMapper_;
|
||||
builder->toneMapper(toneMapper);
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
|
||||
@@ -214,9 +214,9 @@ public class ColorGrading {
|
||||
*
|
||||
* The default tone mapping operator is {@link ToneMapper.ACESLegacy}.
|
||||
*
|
||||
* The copy of the specified tone mapper is set to this builder. It is safe to delete
|
||||
* the original tone mapper object while the copied one is held by the built ColorGrading
|
||||
* object.
|
||||
* The specified tone mapper must have a lifecycle that exceeds the lifetime of
|
||||
* this builder. Since the build(Engine&) method is synchronous, it is safe to
|
||||
* delete the tone mapper object after that finishes executing.
|
||||
*
|
||||
* @param toneMapper The tone mapping operator to apply to the HDR color buffer
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.59.5
|
||||
VERSION_NAME=1.60.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
12
build.sh
12
build.sh
@@ -151,7 +151,7 @@ function print_fgviewer_help {
|
||||
}
|
||||
|
||||
# Unless explicitly specified, NDK version will be selected as highest available version within same major release chain
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | cut -f 1 -d ".")}
|
||||
FILAMENT_NDK_VERSION=${FILAMENT_NDK_VERSION:-$(cat `dirname $0`/build/common/versions | grep GITHUB_NDK_VERSION | sed s/GITHUB_NDK_VERSION=//g | cut -f 1 -d ".")}
|
||||
|
||||
# Requirements
|
||||
CMAKE_MAJOR=3
|
||||
@@ -463,16 +463,6 @@ function ensure_android_build {
|
||||
echo "Error: Android NDK side-by-side version ${FILAMENT_NDK_VERSION} or compatible must be installed, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local cmake_version=$(cmake --version)
|
||||
if [[ "${cmake_version}" =~ ([0-9]+)\.([0-9]+)\.[0-9]+ ]]; then
|
||||
if [[ "${BASH_REMATCH[1]}" -lt "${CMAKE_MAJOR}" ]] || \
|
||||
[[ "${BASH_REMATCH[2]}" -lt "${CMAKE_MINOR}" ]]; then
|
||||
echo "Error: cmake version ${CMAKE_MAJOR}.${CMAKE_MINOR}+ is required," \
|
||||
"${BASH_REMATCH[1]}.${BASH_REMATCH[2]} installed, exiting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function build_android {
|
||||
|
||||
@@ -1023,8 +1023,12 @@ samplerCubemap | Cubemap texture
|
||||
[Table [materialParamsTypes]: Material parameter types]
|
||||
|
||||
Samplers
|
||||
: Sampler types can also specify a `format` which can be either `int` or `float` (defaults to
|
||||
`float`).
|
||||
: Sampler types can specify additional options:
|
||||
|
||||
- `format`: either `int` or `float` (defaults to `float`).
|
||||
- `stages`: array of strings containing the list of shader stages this
|
||||
sampler can be accessed from. Each entry must be either `vertex` or
|
||||
`fragment` (defaults to both).
|
||||
|
||||
Arrays
|
||||
: A parameter can define an array of values by appending `[size]` after the type name, where
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
- [Vulkan](./notes/vulkan_debugging.md)
|
||||
- [SPIR-V](./notes/spirv_debugging.md)
|
||||
- [Running with ASAN and UBSAN](./notes/asan_ubsan.md)
|
||||
- [Using Instruments on macOS](./notes/instruments.md)
|
||||
- [Libraries](./notes/libs.md)
|
||||
- [bluegl](./dup/bluegl.md)
|
||||
- [bluevk](./dup/bluevk.md)
|
||||
|
||||
36
docs_src/src/notes/instruments.md
Normal file
36
docs_src/src/notes/instruments.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Using Instruments on macOS
|
||||
|
||||
When running a binary under Instruments on macOS, you may run into the following issue when
|
||||
launching or attaching to an executable:
|
||||
|
||||
```
|
||||
Failed to gain authorization
|
||||
Recovery Suggestion: Target binary needs to be debuggable and signed with 'get-task-allow'
|
||||
```
|
||||
|
||||
This is a security precaution; the solution is to code sign the binary with the
|
||||
`com.apple.security.get-task-allow` entitlement.
|
||||
|
||||
1. Create an `entitlements.plist` file with the following contents:
|
||||
|
||||
```
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
2. Run the following command:
|
||||
|
||||
```
|
||||
codesign -s - --entitlements entitlements.plist <binary>
|
||||
```
|
||||
|
||||
Replace `<binary>` with the name of the binary, for example: `out/cmake-debug/samples/gltf_viewer`.
|
||||
|
||||
Afterwards, you should be able to successfully launch and attach to the executable using
|
||||
Instruments.
|
||||
@@ -20,10 +20,15 @@
|
||||
#define TNT_FILAMENT_BACKEND_BUFFERDESCRIPTOR_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class CallbackHandler;
|
||||
@@ -89,8 +94,8 @@ public:
|
||||
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
||||
* @param user An opaque user pointer passed to the callback function when it's called
|
||||
*/
|
||||
BufferDescriptor(void const* buffer, size_t size,
|
||||
Callback callback = nullptr, void* user = nullptr) noexcept
|
||||
BufferDescriptor(void const* buffer, size_t const size,
|
||||
Callback const callback = nullptr, void* user = nullptr) noexcept
|
||||
: buffer(const_cast<void*>(buffer)), size(size), mCallback(callback), mUser(user) {
|
||||
}
|
||||
|
||||
@@ -98,11 +103,12 @@ public:
|
||||
* Creates a BufferDescriptor that references a CPU memory-buffer
|
||||
* @param buffer Memory address of the CPU buffer to reference
|
||||
* @param size Size of the CPU buffer in bytes
|
||||
* @param handler A custom handler for the callback
|
||||
* @param callback A callback used to release the CPU buffer from this BufferDescriptor
|
||||
* @param user An opaque user pointer passed to the callback function when it's called
|
||||
*/
|
||||
BufferDescriptor(void const* buffer, size_t size,
|
||||
CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept
|
||||
BufferDescriptor(void const* buffer, size_t const size,
|
||||
CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept
|
||||
: buffer(const_cast<void*>(buffer)), size(size),
|
||||
mCallback(callback), mUser(user), mHandler(handler) {
|
||||
}
|
||||
@@ -116,8 +122,9 @@ public:
|
||||
*
|
||||
* @param buffer Memory address of the CPU buffer to reference
|
||||
* @param size Size of the CPU buffer in bytes
|
||||
* @param data A pointer to the data
|
||||
* @param handler Handler to use to dispatch the callback, or nullptr for the default handler
|
||||
* @return a new BufferDescriptor
|
||||
* @return A new BufferDescriptor
|
||||
*/
|
||||
template<typename T, void(T::*method)(void const*, size_t)>
|
||||
static BufferDescriptor make(void const* buffer, size_t size, T* data,
|
||||
@@ -164,7 +171,7 @@ public:
|
||||
* @param callback The new callback function
|
||||
* @param user An opaque user pointer passed to the callbeck function when it's called
|
||||
*/
|
||||
void setCallback(Callback callback, void* user = nullptr) noexcept {
|
||||
void setCallback(Callback const callback, void* user = nullptr) noexcept {
|
||||
this->mCallback = callback;
|
||||
this->mUser = user;
|
||||
this->mHandler = nullptr;
|
||||
@@ -176,7 +183,7 @@ public:
|
||||
* @param callback The new callback function
|
||||
* @param user An opaque user pointer passed to the callbeck function when it's called
|
||||
*/
|
||||
void setCallback(CallbackHandler* handler, Callback callback, void* user = nullptr) noexcept {
|
||||
void setCallback(CallbackHandler* handler, Callback const callback, void* user = nullptr) noexcept {
|
||||
mCallback = callback;
|
||||
mUser = user;
|
||||
mHandler = handler;
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
|
||||
#include <backend/DriverApiForward.h>
|
||||
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
|
||||
@@ -28,6 +26,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
void* allocateFromCommandStream(DriverApi& driver, size_t size, size_t alignment) noexcept;
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
#include <backend/PresentCallable.h>
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/StaticString.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <math/vec4.h>
|
||||
|
||||
@@ -41,6 +40,10 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
/**
|
||||
* Types and enums used by filament's driver.
|
||||
*
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_HANDLE_H
|
||||
#define TNT_FILAMENT_BACKEND_HANDLE_H
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
#include <utils/ostream.h>
|
||||
#endif
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <type_traits> // FIXME: STL headers are not allowed in public headers
|
||||
@@ -27,6 +24,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct HwBufferObject;
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
//! \privatesection
|
||||
|
||||
@@ -24,11 +24,14 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,12 +20,10 @@
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
@@ -33,6 +31,10 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class Program {
|
||||
|
||||
@@ -19,22 +19,26 @@
|
||||
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/ostream.h>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils::io {
|
||||
class ostream;
|
||||
} // namespace utils::io
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
//! \privatesection
|
||||
|
||||
struct TargetBufferInfo {
|
||||
// note: the parameters of this constructor are not in the order of this structure's fields
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
|
||||
: handle(handle), level(level), layer(layer) {
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level, uint16_t const layer) noexcept
|
||||
: handle(std::move(handle)), level(level), layer(layer) {
|
||||
}
|
||||
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level) noexcept
|
||||
TargetBufferInfo(Handle<HwTexture> handle, uint8_t const level) noexcept
|
||||
: handle(handle), level(level) {
|
||||
}
|
||||
|
||||
@@ -70,11 +74,11 @@ private:
|
||||
TargetBufferInfo mInfos[MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
||||
|
||||
public:
|
||||
TargetBufferInfo const& operator[](size_t i) const noexcept {
|
||||
TargetBufferInfo const& operator[](size_t const i) const noexcept {
|
||||
return mInfos[i];
|
||||
}
|
||||
|
||||
TargetBufferInfo& operator[](size_t i) noexcept {
|
||||
TargetBufferInfo& operator[](size_t const i) noexcept {
|
||||
return mInfos[i];
|
||||
}
|
||||
|
||||
|
||||
@@ -39,18 +39,40 @@ public:
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
int getOSVersion() const noexcept override { return 0; }
|
||||
|
||||
/**
|
||||
* Optionally initializes the Metal platform by acquiring resources necessary for rendering.
|
||||
*
|
||||
* This method attempts to acquire a Metal device and command queue, returning true if both are
|
||||
* successfully obtained, or false otherwise. Typically, these objects are acquired when
|
||||
* the Metal backend is initialized. This method allows clients to check for their availability
|
||||
* earlier.
|
||||
*
|
||||
* Calling initialize() is optional and safe to do so multiple times. After initialize() returns
|
||||
* true, subsequent calls will continue to return true but have no effect.
|
||||
*
|
||||
* initialize() must be called from the main thread.
|
||||
*
|
||||
* @returns true if the device and command queue have been successfully obtained; false
|
||||
* otherwise.
|
||||
*/
|
||||
bool initialize() noexcept;
|
||||
|
||||
/**
|
||||
* Obtain the preferred Metal device object for the backend to use.
|
||||
*
|
||||
* On desktop platforms, there may be multiple GPUs suitable for rendering, and this method is
|
||||
* free to decide which one to use. On mobile systems with a single GPU, implementations should
|
||||
* simply return the result of MTLCreateSystemDefaultDevice();
|
||||
*
|
||||
* createDevice is called by the Metal backend from the backend thread.
|
||||
*/
|
||||
virtual void createDevice(MetalDevice& outDevice) noexcept;
|
||||
|
||||
/**
|
||||
* Create a command submission queue on the Metal device object.
|
||||
*
|
||||
* createCommandQueue is called by the Metal backend from the backend thread.
|
||||
*
|
||||
* @param device The device which was returned from createDevice()
|
||||
*/
|
||||
virtual void createCommandQueue(
|
||||
@@ -60,6 +82,8 @@ public:
|
||||
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
|
||||
* guaranteed to execute before all subsequent command buffers created either by Filament, or
|
||||
* further calls to this method.
|
||||
*
|
||||
* createAndEnqueueCommandBuffer must be called from the main thread.
|
||||
*/
|
||||
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
|
||||
|
||||
@@ -68,6 +92,8 @@ public:
|
||||
*
|
||||
* Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the
|
||||
* completion of each frame. These are limited and provided round-robin style by the system.
|
||||
*
|
||||
* setDrawableFailureBehavior must be called from the main thread.
|
||||
*/
|
||||
enum class DrawableFailureBehavior : uint8_t {
|
||||
/**
|
||||
|
||||
@@ -27,8 +27,11 @@
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "MetalContext.h"
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
|
||||
@@ -721,15 +721,25 @@ const char* toString(DescriptorFlags flags) {
|
||||
|
||||
void MetalDriver::createDescriptorSetLayoutR(
|
||||
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info) {
|
||||
#if FILAMENT_METAL_DEBUG_LOG == 1
|
||||
const char* labelStr = "";
|
||||
std::visit([&labelStr](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, utils::CString> || std::is_same_v<T, utils::StaticString>) {
|
||||
labelStr = arg.c_str();
|
||||
}
|
||||
}, info.label);
|
||||
std::sort(info.bindings.begin(), info.bindings.end(),
|
||||
[](const auto& a, const auto& b) { return a.binding < b.binding; });
|
||||
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = {\n", dslh.getId());
|
||||
DEBUG_LOG("createDescriptorSetLayoutR(dslh = %d, info = { label = %s,\n", dslh.getId(),
|
||||
labelStr);
|
||||
for (size_t i = 0; i < info.bindings.size(); i++) {
|
||||
DEBUG_LOG(" {binding = %d, type = %s, count = %d, stage = %s, flags = %s},\n",
|
||||
info.bindings[i].binding, toString(info.bindings[i].type), info.bindings[i].count,
|
||||
toString(info.bindings[i].stageFlags), toString(info.bindings[i].flags));
|
||||
}
|
||||
DEBUG_LOG("})\n");
|
||||
#endif
|
||||
construct_handle<MetalDescriptorSetLayout>(dslh, std::move(info));
|
||||
}
|
||||
|
||||
|
||||
@@ -1382,6 +1382,9 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arguments.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
return [device newArgumentEncoderWithArguments:arguments];
|
||||
}
|
||||
|
||||
@@ -1442,6 +1445,9 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
||||
|
||||
id<MTLArgumentEncoder> encoder =
|
||||
layout->getArgumentEncoder(context.device, stage, textureTypes);
|
||||
if (!encoder) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
{
|
||||
ScopedAllocationTimer timer("descriptor_set");
|
||||
|
||||
@@ -20,18 +20,19 @@
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
#include "private/backend/Driver.h"
|
||||
#include "backend/Program.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Program.h>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include <memory>
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include <utils/Hash.h>
|
||||
#include <utils/Invocable.h>
|
||||
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
|
||||
@@ -24,14 +24,22 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct PlatformMetalImpl {
|
||||
std::mutex mLock; // locks mDevice and mCommandQueue
|
||||
id<MTLDevice> mDevice = nil;
|
||||
id<MTLCommandQueue> mCommandQueue = nil;
|
||||
|
||||
// read form driver thread, read/written to from client thread
|
||||
std::atomic<PlatformMetal::DrawableFailureBehavior> mDrawableFailureBehavior =
|
||||
PlatformMetal::DrawableFailureBehavior::PANIC;
|
||||
|
||||
// These methods must be called with mLock held
|
||||
void createDeviceImpl(MetalDevice& outDevice);
|
||||
void createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue);
|
||||
};
|
||||
|
||||
Platform* createDefaultMetalPlatform() {
|
||||
@@ -48,7 +56,59 @@ Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::Dri
|
||||
return MetalDriverFactory::create(this, driverConfig);
|
||||
}
|
||||
|
||||
|
||||
bool PlatformMetal::initialize() noexcept {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||
|
||||
MetalDevice device{};
|
||||
pImpl->createDeviceImpl(device);
|
||||
if (device.device == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MetalCommandQueue commandQueue{};
|
||||
pImpl->createCommandQueueImpl(device, commandQueue);
|
||||
if (commandQueue.commandQueue == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||
pImpl->createDeviceImpl(outDevice);
|
||||
}
|
||||
|
||||
void PlatformMetal::createCommandQueue(
|
||||
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||
pImpl->createCommandQueueImpl(device, outCommandQueue);
|
||||
}
|
||||
|
||||
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
|
||||
std::lock_guard<std::mutex> lock(pImpl->mLock);
|
||||
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
||||
[commandBuffer enqueue];
|
||||
outCommandBuffer.commandBuffer = commandBuffer;
|
||||
}
|
||||
|
||||
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
||||
pImpl->mDrawableFailureBehavior = behavior;
|
||||
}
|
||||
|
||||
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
|
||||
return pImpl->mDrawableFailureBehavior;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
void PlatformMetalImpl::createDeviceImpl(MetalDevice& outDevice) {
|
||||
if (mDevice) {
|
||||
outDevice.device = mDevice;
|
||||
return;
|
||||
}
|
||||
|
||||
id<MTLDevice> result;
|
||||
|
||||
#if !defined(FILAMENT_IOS)
|
||||
@@ -74,27 +134,17 @@ void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
||||
<< utils::io::endl;
|
||||
|
||||
outDevice.device = result;
|
||||
mDevice = result;
|
||||
}
|
||||
|
||||
void PlatformMetal::createCommandQueue(
|
||||
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
|
||||
pImpl->mCommandQueue = [device.device newCommandQueue];
|
||||
pImpl->mCommandQueue.label = @"Filament";
|
||||
outCommandQueue.commandQueue = pImpl->mCommandQueue;
|
||||
}
|
||||
|
||||
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
|
||||
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
||||
[commandBuffer enqueue];
|
||||
outCommandBuffer.commandBuffer = commandBuffer;
|
||||
}
|
||||
|
||||
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
||||
pImpl->mDrawableFailureBehavior = behavior;
|
||||
}
|
||||
|
||||
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
|
||||
return pImpl->mDrawableFailureBehavior;
|
||||
void PlatformMetalImpl::createCommandQueueImpl(MetalDevice& device, MetalCommandQueue& outCommandQueue) {
|
||||
if (mCommandQueue) {
|
||||
outCommandQueue.commandQueue = mCommandQueue;
|
||||
return;
|
||||
}
|
||||
mCommandQueue = [device.device newCommandQueue];
|
||||
mCommandQueue.label = @"Filament";
|
||||
outCommandQueue.commandQueue = mCommandQueue;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -542,6 +542,13 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
} else if (strstr(renderer, "Intel")) {
|
||||
// Intel GPU
|
||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||
|
||||
if (strstr(renderer, "Mesa")) {
|
||||
// Mesa Intel driver on Linux/Android
|
||||
// Renderer of the form [Mesa Intel(R) HD Graphics 505 (APL 3)]
|
||||
// b/405252622
|
||||
bugs->disable_invalidate_framebuffer = true;
|
||||
}
|
||||
} else if (strstr(renderer, "PowerVR")) {
|
||||
// PowerVR GPU
|
||||
// On PowerVR (Rogue GE8320) glFlush doesn't seem to do anything, in particular,
|
||||
|
||||
@@ -54,7 +54,7 @@ struct PlatformCocoaGLImpl {
|
||||
CVOpenGLTextureCacheRef mTextureCache = nullptr;
|
||||
std::unique_ptr<CocoaExternalImage::SharedGl> mExternalImageSharedGl;
|
||||
void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView);
|
||||
struct ExternalImageCocoaGL : public Platform::ExternalImage {
|
||||
struct ExternalImageCocoaGL final : public Platform::ExternalImage {
|
||||
CVPixelBufferRef cvBuffer;
|
||||
protected:
|
||||
~ExternalImageCocoaGL() noexcept final;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
@@ -502,7 +503,6 @@ size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
||||
return mEntriesByBindingWithDynamicOffsets.count();
|
||||
}
|
||||
|
||||
// From createTextureR
|
||||
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
uint32_t width, uint32_t height, uint32_t depth, TextureUsage usage,
|
||||
wgpu::Device const& device) noexcept {
|
||||
@@ -516,6 +516,7 @@ WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat forma
|
||||
// First, the texture aspect, starting with the defaults/basic configuration
|
||||
mUsage = fToWGPUTextureUsage(usage);
|
||||
mFormat = fToWGPUTextureFormat(format);
|
||||
mAspect = fToWGPUTextureViewAspect(usage, format);
|
||||
wgpu::TextureDescriptor textureDescriptor{
|
||||
.label = getUserTextureLabel(target),
|
||||
.usage = mUsage,
|
||||
@@ -560,13 +561,12 @@ WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat forma
|
||||
mTexView = makeTextureView(0, levels, target);
|
||||
}
|
||||
|
||||
// From createTextureViewR
|
||||
WGPUTexture::WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept {
|
||||
mTexture = src->mTexture;
|
||||
mTexView = makeTextureView(baseLevel, levelCount, target);
|
||||
}
|
||||
|
||||
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage) {
|
||||
wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(TextureUsage const& fUsage) {
|
||||
wgpu::TextureUsage retUsage = wgpu::TextureUsage::None;
|
||||
|
||||
// Basing this mapping off of VulkanTexture.cpp's getUsage func and suggestions from Gemini
|
||||
@@ -614,8 +614,9 @@ wgpu::TextureUsage WGPUTexture::fToWGPUTextureUsage(const TextureUsage& fUsage)
|
||||
// PROTECTED
|
||||
return retUsage;
|
||||
}
|
||||
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsage) {
|
||||
switch (fUsage) {
|
||||
|
||||
wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFormat) {
|
||||
switch (fFormat) {
|
||||
case filament::backend::TextureFormat::R8:
|
||||
return wgpu::TextureFormat::R8Unorm;
|
||||
case filament::backend::TextureFormat::R8_SNORM:
|
||||
@@ -854,24 +855,57 @@ wgpu::TextureFormat WGPUTexture::fToWGPUTextureFormat(const TextureFormat& fUsag
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::TextureAspect WGPUTexture::fToWGPUTextureViewAspect(TextureUsage const& fUsage,
|
||||
TextureFormat const& fFormat) {
|
||||
|
||||
const bool isDepth = any(fUsage & TextureUsage::DEPTH_ATTACHMENT);
|
||||
const bool isStencil = any(fUsage & TextureUsage::STENCIL_ATTACHMENT);
|
||||
const bool isColor = any(fUsage & TextureUsage::COLOR_ATTACHMENT);
|
||||
const bool isSample = (fUsage == TextureUsage::SAMPLEABLE);
|
||||
|
||||
if (isDepth && !isColor && !isStencil) {
|
||||
return wgpu::TextureAspect::DepthOnly;
|
||||
}
|
||||
|
||||
if (isStencil && !isColor && !isDepth) {
|
||||
return wgpu::TextureAspect::StencilOnly;
|
||||
}
|
||||
|
||||
if (fFormat == filament::backend::TextureFormat::DEPTH32F ||
|
||||
fFormat == filament::backend::TextureFormat::DEPTH24 ||
|
||||
fFormat == filament::backend::TextureFormat::DEPTH16) {
|
||||
return wgpu::TextureAspect::DepthOnly;
|
||||
}
|
||||
|
||||
if (fFormat == filament::backend::TextureFormat::STENCIL8) {
|
||||
return wgpu::TextureAspect::StencilOnly;
|
||||
}
|
||||
|
||||
if (fFormat == filament::backend::TextureFormat::DEPTH24_STENCIL8 ||
|
||||
fFormat == filament::backend::TextureFormat::DEPTH32F_STENCIL8) {
|
||||
if (isSample) {
|
||||
return wgpu::TextureAspect::DepthOnly;
|
||||
}
|
||||
}
|
||||
|
||||
return wgpu::TextureAspect::All;
|
||||
}
|
||||
|
||||
wgpu::TextureView WGPUTexture::makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||
SamplerType target) {
|
||||
// starting with the defaults/basic configuration
|
||||
|
||||
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||
.label = getUserTextureViewLabel(target),
|
||||
.format = mFormat,
|
||||
// dimension depends on target and is set below
|
||||
.baseMipLevel = baseLevel,
|
||||
.mipLevelCount = levelCount,
|
||||
// baseArrayLayer is required, making a guess
|
||||
// TODO: check if this baseArrayLayer assumption is correct
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = mArrayLayerCount,
|
||||
// Have not found an analog to aspect in other drivers, but ALL should be unrestrictive.
|
||||
// TODO Can we make this better?
|
||||
.aspect = wgpu::TextureAspect::All,
|
||||
.aspect = mAspect,
|
||||
.usage = mUsage
|
||||
};
|
||||
// adjust for specific cases
|
||||
|
||||
switch (target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
|
||||
|
||||
@@ -74,8 +74,8 @@ public:
|
||||
|
||||
private:
|
||||
// TODO: can we do better in terms on heap management.
|
||||
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout {};
|
||||
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes {};
|
||||
std::vector<wgpu::VertexBufferLayout> mVertexBufferLayout{};
|
||||
std::vector<std::vector<wgpu::VertexAttribute>> mAttributes{};
|
||||
};
|
||||
|
||||
struct WGPUVertexBuffer : public HwVertexBuffer {
|
||||
@@ -145,8 +145,8 @@ public:
|
||||
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
|
||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
||||
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
||||
private:
|
||||
|
||||
private:
|
||||
static wgpu::Buffer sDummyUniformBuffer;
|
||||
static wgpu::Texture sDummyTexture;
|
||||
static wgpu::TextureView sDummyTextureView;
|
||||
@@ -161,10 +161,10 @@ private:
|
||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
||||
wgpu::BindGroupLayout mLayout = nullptr;
|
||||
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
||||
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding {};
|
||||
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
|
||||
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets {};
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded {};
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets{};
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded{};
|
||||
std::vector<uint32_t> mDynamicOffsets;
|
||||
wgpu::BindGroup mBindGroup = nullptr;
|
||||
};
|
||||
@@ -177,11 +177,14 @@ public:
|
||||
|
||||
WGPUTexture(WGPUTexture* src, uint8_t baseLevel, uint8_t levelCount) noexcept;
|
||||
|
||||
const wgpu::Texture& getTexture() const { return mTexture; }
|
||||
const wgpu::TextureView& getTexView() const { return mTexView; }
|
||||
[[nodiscard]] const wgpu::Texture& getTexture() const { return mTexture; }
|
||||
[[nodiscard]] const wgpu::TextureView& getTexView() const { return mTexView; }
|
||||
|
||||
// Public to allow checking for support of a texture format
|
||||
static wgpu::TextureFormat fToWGPUTextureFormat(const filament::backend::TextureFormat& fUsage);
|
||||
static wgpu::TextureFormat fToWGPUTextureFormat(
|
||||
filament::backend::TextureFormat const& fFormat);
|
||||
static wgpu::TextureAspect fToWGPUTextureViewAspect(
|
||||
filament::backend::TextureUsage const& fUsage,
|
||||
filament::backend::TextureFormat const& fFormat);
|
||||
|
||||
private:
|
||||
wgpu::TextureView makeTextureView(const uint8_t& baseLevel, const uint8_t& levelCount,
|
||||
@@ -192,9 +195,10 @@ private:
|
||||
wgpu::Texture mTexture = nullptr;
|
||||
wgpu::TextureUsage mUsage = wgpu::TextureUsage::None;
|
||||
wgpu::TextureFormat mFormat = wgpu::TextureFormat::Undefined;
|
||||
wgpu::TextureAspect mAspect = wgpu::TextureAspect::Undefined;
|
||||
uint32_t mArrayLayerCount = 1;
|
||||
wgpu::TextureView mTexView = nullptr;
|
||||
wgpu::TextureUsage fToWGPUTextureUsage(const filament::backend::TextureUsage& fUsage);
|
||||
wgpu::TextureUsage fToWGPUTextureUsage(filament::backend::TextureUsage const& fUsage);
|
||||
};
|
||||
|
||||
struct WGPURenderPrimitive : public HwRenderPrimitive {
|
||||
@@ -252,7 +256,7 @@ private:
|
||||
|
||||
Attachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
math::uint2 attachmentSize = {};
|
||||
std::vector<wgpu::RenderPassColorAttachment> colorAttachments {};
|
||||
std::vector<wgpu::RenderPassColorAttachment> colorAttachments{};
|
||||
};
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -211,6 +211,10 @@ uint32_t RenderTargetDump::hash() const {
|
||||
return mInternal->hash();
|
||||
}
|
||||
|
||||
const std::vector<unsigned char>& RenderTargetDump::bytes() const {
|
||||
return mInternal->bytes;
|
||||
}
|
||||
|
||||
bool RenderTargetDump::bytesFilled() const {
|
||||
return mInternal->bytesFilled;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,12 @@ public:
|
||||
* @return The hash of the stored bytes.
|
||||
*/
|
||||
uint32_t hash() const;
|
||||
/**
|
||||
* Gets the bytes of the render target. The hash should usually be preferable for comparisons
|
||||
* but this is available for debugging.
|
||||
* @return The stored bytes.
|
||||
*/
|
||||
const std::vector<unsigned char>& bytes() const;
|
||||
/**
|
||||
* Thread safe as this is backed by an atomic.
|
||||
* Once this returns true it will never return false.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "ShaderGenerator.h"
|
||||
|
||||
#include <GlslangToSpv.h>
|
||||
#include <SPVRemapper.h>
|
||||
|
||||
#include <spirv_glsl.hpp>
|
||||
#include <spirv_msl.hpp>
|
||||
|
||||
@@ -32,13 +32,24 @@ do {
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define NONFATAL_FAIL_IF(skipEnvironment, rationale) \
|
||||
do { \
|
||||
SkipEnvironment skip(skipEnvironment); \
|
||||
if (skip.matches()) { \
|
||||
ADD_FAILURE() \
|
||||
<< "Failing test as the " << skip.describe() << "\n" \
|
||||
<< " This test has a known failure where " \
|
||||
<< rationale; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define FAIL_IF(skipEnvironment, rationale) \
|
||||
do { \
|
||||
SkipEnvironment skip(skipEnvironment); \
|
||||
if (skip.matches()) { \
|
||||
GTEST_FAIL() \
|
||||
<< "Failing test as the " << skip.describe() << "\n" \
|
||||
<< " This test should be able to succeed but it needs to fail early because" \
|
||||
<< " This test should be able to succeed but it needs to fail early because " \
|
||||
<< rationale; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
@@ -116,13 +116,23 @@ if __name__ == "__main__":
|
||||
'Remember to sync CMake after running this to '
|
||||
'move the new expected images to the binary '
|
||||
'directory.')
|
||||
parser.add_argument('-r', '--results_path')
|
||||
parser.add_argument('-s', '--source_expected_path', default="./expected_images")
|
||||
parser.add_argument('-r', '--results_path',
|
||||
help='The path with the generated images directory, which should be where '
|
||||
'the test binary was run.')
|
||||
parser.add_argument('-s', '--source_expected_path', default="./expected_images",
|
||||
help='The directory that updated expected images should be written to, '
|
||||
'which should be the source directory copy.')
|
||||
# The mutually exclusive options for how to process the actual images
|
||||
parser.add_argument('-b', '--batch', action='extend', nargs='*')
|
||||
parser.add_argument('-a', '--all', action='store_true')
|
||||
parser.add_argument('-t', '--tests', action='store_true')
|
||||
parser.add_argument('-c', '--compare', action='extend', nargs='*')
|
||||
parser.add_argument('-b', '--batch', action='extend', nargs='*',
|
||||
help='If true copy all actual images to the source expected image '
|
||||
'directory.')
|
||||
parser.add_argument('-a', '--all', action='store_true',
|
||||
help='If true, visually compare all generated images.')
|
||||
parser.add_argument('-t', '--tests', action='store_true',
|
||||
help='If true use a test_detail.xml file that exists in the results_path '
|
||||
'directory to visually compare all images that failed a test.')
|
||||
parser.add_argument('-c', '--compare', action='extend', nargs='*',
|
||||
help='A list of image names to visually compare (without the .png suffix).')
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.results_path:
|
||||
|
||||
@@ -260,6 +260,8 @@ TEST_F(BlitTest, ColorMinify) {
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, ColorResolve) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Nothing is drawn, see b/417229577");
|
||||
auto& api = getDriverApi();
|
||||
|
||||
constexpr int kSrcTexWidth = 256;
|
||||
@@ -490,7 +492,7 @@ TEST_F(BlitTest, BlitRegion) {
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, BlitRegionToSwapChain) {
|
||||
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment");
|
||||
FAIL_IF(Backend::VULKAN, "Crashes due to not finding color attachment, see b/417481493");
|
||||
auto& api = getDriverApi();
|
||||
mCleanup.addPostCall([&]() { executeCommands(); });
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "SharedShaders.h"
|
||||
#include "Skip.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
namespace test {
|
||||
@@ -159,6 +160,8 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
// This test renders two triangles in two separate draw calls. Between the draw calls, a uniform
|
||||
// buffer object is partially updated.
|
||||
TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"All values including alpha are written as 0, see b/417254943");
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace test {
|
||||
|
||||
TEST_F(BackendTest, FrameScheduledCallback) {
|
||||
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
|
||||
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
@@ -85,6 +86,7 @@ TEST_F(BackendTest, FrameScheduledCallback) {
|
||||
|
||||
TEST_F(BackendTest, FrameCompletedCallback) {
|
||||
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
|
||||
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
@@ -99,6 +99,8 @@ struct MaterialParams {
|
||||
// The problems are caused by both uploading and rendering into the same texture, since the OpenGL
|
||||
// backend's readPixels does not work correctly with textures that have image data uploaded.
|
||||
TEST_F(BackendTest, FeedbackLoops) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Image is unexpectedly darker, see b/417226296");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL),
|
||||
"OpenGL image is upside down due to readPixels failing for texture with uploaded image "
|
||||
"data");
|
||||
|
||||
@@ -212,7 +212,7 @@ static SamplerFormat getSamplerFormat(TextureFormat textureFormat) {
|
||||
}
|
||||
|
||||
TEST_F(LoadImageTest, UpdateImage2D) {
|
||||
FAIL_IF(Backend::VULKAN, "Multiple test cases crash");
|
||||
FAIL_IF(Backend::VULKAN, "Multiple test cases crash, see b/417481434");
|
||||
|
||||
// All of these test cases should result in the same rendered image, and thus the same hash.
|
||||
static const uint32_t expectedHash = 3644679986;
|
||||
@@ -485,6 +485,9 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
|
||||
}
|
||||
|
||||
TEST_F(LoadImageTest, UpdateImage3D) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Checkerboard not drawn, possibly due to using wrong z value of 3d texture, "
|
||||
"see b/417254499");
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
api.startCapture();
|
||||
|
||||
@@ -81,7 +81,8 @@ void main() {
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
|
||||
FAIL_IF(Backend::VULKAN, "Crashing due to no program set when setting push constants");
|
||||
FAIL_IF(Backend::VULKAN,
|
||||
"Crashing due to no program set when setting push constants, see b/417477740");
|
||||
|
||||
auto& api = getDriverApi();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "SharedShaders.h"
|
||||
#include "Skip.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -74,6 +75,8 @@ public:
|
||||
};
|
||||
|
||||
TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Two cases fail, see b/417255941 and b/417255943");
|
||||
// These test scenarios use a known hash of the result pixel buffer to decide pass / fail,
|
||||
// asserting an exact pixel-for-pixel match. So far, rendering on macOS and iPhone have had
|
||||
// deterministic results. Take this test with a grain of salt, however, as other platform / GPU
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Lifetimes.h"
|
||||
#include "Shader.h"
|
||||
#include "SharedShaders.h"
|
||||
#include "Skip.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
@@ -30,6 +31,8 @@ using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Affected area in wrong corner, see b/417229118");
|
||||
auto& api = getDriverApi();
|
||||
|
||||
constexpr int kSrcTexWidth = 1024;
|
||||
|
||||
@@ -117,6 +117,8 @@ public:
|
||||
};
|
||||
|
||||
TEST_F(BasicStencilBufferTest, StencilBuffer) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Stencil not supported, see b/417230776");
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
@@ -139,6 +141,8 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
|
||||
}
|
||||
|
||||
TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Stencil not supported, see b/417230776");
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
@@ -162,6 +166,8 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
|
||||
}
|
||||
|
||||
TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"Stencil not supported, see b/417230776");
|
||||
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL), "Stencil isn't applied");
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
@@ -21,17 +21,13 @@
|
||||
|
||||
#include <filament/FilamentAPI.h>
|
||||
#include <filament/ToneMapper.h>
|
||||
#include <filament/ColorSpace.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <math/mathfwd.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -205,14 +201,15 @@ public:
|
||||
*
|
||||
* The default tone mapping operator is ACESLegacyToneMapper.
|
||||
*
|
||||
* The ownership of the specified tone mapper is shared with the builder and built
|
||||
* ColorGrading object.
|
||||
* The specified tone mapper must have a lifecycle that exceeds the lifetime of
|
||||
* this builder. Since the build(Engine&) method is synchronous, it is safe to
|
||||
* delete the tone mapper object after that finishes executing.
|
||||
*
|
||||
* @param toneMapper The tone mapping operator to apply to the HDR color buffer
|
||||
*
|
||||
* @return This Builder, for chaining calls
|
||||
*/
|
||||
Builder& toneMapper(std::shared_ptr<ToneMapper> toneMapper) noexcept;
|
||||
Builder& toneMapper(ToneMapper const* UTILS_NULLABLE toneMapper) noexcept;
|
||||
|
||||
/**
|
||||
* Selects the tone mapping operator to apply to the HDR color buffer as the last
|
||||
@@ -490,118 +487,7 @@ public:
|
||||
friend class FColorGrading;
|
||||
};
|
||||
|
||||
/** Returns the quality level used to create this ColorGrading object. */
|
||||
QualityLevel getQuality() const noexcept;
|
||||
|
||||
/** Returns the LUT format used to create this ColorGrading object. */
|
||||
LutFormat getLutFormat() const noexcept;
|
||||
|
||||
/** Returns the LUT dimensions used to create this ColorGrading object. */
|
||||
uint8_t getLutDimensions() const noexcept;
|
||||
|
||||
/** Returns the tone mapper used to create this ColorGrading object. */
|
||||
const ToneMapper& getToneMapper() const noexcept;
|
||||
|
||||
/** Returns whether luminance scaling was enabled during creation. */
|
||||
bool isLuminanceScalingEnabled() const noexcept;
|
||||
|
||||
/** Returns whether gamut mapping was enabled during creation. */
|
||||
bool isGamutMappingEnabled() const noexcept;
|
||||
|
||||
/** Returns the exposure value used to create this ColorGrading object. */
|
||||
float getExposure() const noexcept;
|
||||
|
||||
/** Returns the night adaptation value used to create this ColorGrading object. */
|
||||
float getNightAdaptation() const noexcept;
|
||||
|
||||
/** Returns the white balance temperature used to create this ColorGrading object. */
|
||||
float getWhiteBalanceTemperature() const noexcept;
|
||||
|
||||
/** Returns the white balance tint used to create this ColorGrading object. */
|
||||
float getWhiteBalanceTint() const noexcept;
|
||||
|
||||
/** Returns the channel mixer output for the red channel. */
|
||||
math::float3 getChannelMixerOutRed() const noexcept;
|
||||
|
||||
/** Returns the channel mixer output for the green channel. */
|
||||
math::float3 getChannelMixerOutGreen() const noexcept;
|
||||
|
||||
/** Returns the channel mixer output for the blue channel. */
|
||||
math::float3 getChannelMixerOutBlue() const noexcept;
|
||||
|
||||
/** Returns the shadows adjustment used to create this ColorGrading object. */
|
||||
math::float3 getShadows() const noexcept;
|
||||
|
||||
/** Returns the midtones adjustment used to create this ColorGrading object. */
|
||||
math::float3 getMidtones() const noexcept;
|
||||
|
||||
/** Returns the highlights adjustment used to create this ColorGrading object. */
|
||||
math::float3 getHighlights() const noexcept;
|
||||
|
||||
/** Returns the shadow/midtones/highlights ranges used to create this ColorGrading object. */
|
||||
math::float4 getShadowMidtonesHighlightsRanges() const noexcept;
|
||||
|
||||
/** Returns the slope adjustment used to create this ColorGrading object. */
|
||||
math::float3 getSlope() const noexcept;
|
||||
|
||||
/** Returns the offset adjustment used to create this ColorGrading object. */
|
||||
math::float3 getOffset() const noexcept;
|
||||
|
||||
/** Returns the power adjustment used to create this ColorGrading object. */
|
||||
math::float3 getPower() const noexcept;
|
||||
|
||||
/** Returns the contrast value used to create this ColorGrading object. */
|
||||
float getContrast() const noexcept;
|
||||
|
||||
/** Returns the vibrance value used to create this ColorGrading object. */
|
||||
float getVibrance() const noexcept;
|
||||
|
||||
/** Returns the saturation value used to create this ColorGrading object. */
|
||||
float getSaturation() const noexcept;
|
||||
|
||||
/** Returns the shadow gamma curve adjustment used to create this ColorGrading object. */
|
||||
math::float3 getCurvesShadowGamma() const noexcept;
|
||||
|
||||
/** Returns the mid-point curve adjustment used to create this ColorGrading object. */
|
||||
math::float3 getCurvesMidPoint() const noexcept;
|
||||
|
||||
/** Returns the highlight scale curve adjustment used to create this ColorGrading object. */
|
||||
math::float3 getCurvesHighlightScale() const noexcept;
|
||||
|
||||
/** Returns the output color space used to create this ColorGrading object. */
|
||||
const color::ColorSpace& getOutputColorSpace() const noexcept;
|
||||
|
||||
protected :
|
||||
struct Settings {
|
||||
LutFormat lutFormat = LutFormat::INTEGER;
|
||||
uint8_t lutDimensions = 32;
|
||||
std::shared_ptr<ToneMapper> toneMapper = std::make_shared<ACESLegacyToneMapper>();
|
||||
bool luminanceScaling = false;
|
||||
bool gummapMapping = false;
|
||||
float exposure = 0.0f;
|
||||
float nightAdaptation = 0.0f;
|
||||
float whiteBalanceTemperature = 0.0f;
|
||||
float whiteBalanceTint = 0.0f;
|
||||
math::float3 channelMixerOutRed{1.0f, 0.0f, 0.0f};
|
||||
math::float3 channelMixerOutGreen{0.0f, 1.0f, 0.0f};
|
||||
math::float3 channelMixerOutBlue{0.0f, 0.0f, 1.0f};
|
||||
math::float3 shadows{1.0f, 1.0f, 1.0f};
|
||||
math::float3 midtones{1.0f, 1.0f, 1.0f};
|
||||
math::float3 highlights{1.0f, 1.0f, 1.0f};
|
||||
math::float4 ShadowMidtonesHighlightsRanges{0.0f, 0.333f, 0.55f, 1.0f};
|
||||
math::float3 slope{1.0f};
|
||||
math::float3 offset{0.0f};
|
||||
math::float3 power{1.0f};
|
||||
float contrast = 1.0f;
|
||||
float vibrance = 1.0f;
|
||||
float saturation = 1.0f;
|
||||
math::float3 curvesShadowGamma{1.0f, 1.0f, 1.0f};
|
||||
math::float3 curvesMidPoint{1.0f, 1.0f, 1.0f};
|
||||
math::float3 curvesHighlightScale{1.0f, 1.0f, 1.0f};
|
||||
color::ColorSpace colorSpace = color::Rec709 - color::sRGB - color::D65;
|
||||
};
|
||||
Settings mSettings;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~ColorGrading() = default;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <backend/CallbackHandler.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/PresentCallable.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Invocable.h>
|
||||
@@ -35,7 +34,7 @@ class Engine;
|
||||
/**
|
||||
* A swap chain represents an Operating System's *native* renderable surface.
|
||||
*
|
||||
* Typically it's a native window or a view. Because a SwapChain is initialized from a
|
||||
* Typically, it's a native window or a view. Because a SwapChain is initialized from a
|
||||
* native object, it is given to filament as a `void *`, which must be of the proper type
|
||||
* for each platform filament is running on.
|
||||
*
|
||||
@@ -158,7 +157,7 @@ public:
|
||||
/**
|
||||
* Requests a SwapChain with an alpha channel.
|
||||
*/
|
||||
static const uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT;
|
||||
static constexpr uint64_t CONFIG_TRANSPARENT = backend::SWAP_CHAIN_CONFIG_TRANSPARENT;
|
||||
|
||||
/**
|
||||
* This flag indicates that the swap chain may be used as a source surface
|
||||
@@ -168,13 +167,13 @@ public:
|
||||
* @see
|
||||
* Renderer.copyFrame()
|
||||
*/
|
||||
static const uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE;
|
||||
static constexpr uint64_t CONFIG_READABLE = backend::SWAP_CHAIN_CONFIG_READABLE;
|
||||
|
||||
/**
|
||||
* Indicates that the native X11 window is an XCB window rather than an XLIB window.
|
||||
* This is ignored on non-Linux platforms and in builds that support only one X11 API.
|
||||
*/
|
||||
static const uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB;
|
||||
static constexpr uint64_t CONFIG_ENABLE_XCB = backend::SWAP_CHAIN_CONFIG_ENABLE_XCB;
|
||||
|
||||
/**
|
||||
* Indicates that the native window is a CVPixelBufferRef.
|
||||
@@ -186,7 +185,7 @@ public:
|
||||
* Filament. Filament will call CVPixelBufferRetain during Engine::createSwapChain, and
|
||||
* CVPixelBufferRelease when the swap chain is destroyed.
|
||||
*/
|
||||
static const uint64_t CONFIG_APPLE_CVPIXELBUFFER =
|
||||
static constexpr uint64_t CONFIG_APPLE_CVPIXELBUFFER =
|
||||
backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER;
|
||||
|
||||
/**
|
||||
@@ -303,6 +302,7 @@ public:
|
||||
*
|
||||
* @param handler Handler to dispatch the callback or nullptr for the default handler.
|
||||
* @param callback Callback called when the frame is scheduled.
|
||||
* @param flags
|
||||
*
|
||||
* @remark Only Filament's Metal backend supports PresentCallables and frame callbacks. Other
|
||||
* backends ignore the callback (which will never be called) and proceed normally.
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
FrameScheduledCallback&& callback = {}, uint64_t flags = 0);
|
||||
|
||||
/**
|
||||
* Returns whether or not this SwapChain currently has a FrameScheduledCallback set.
|
||||
* Returns whether this SwapChain currently has a FrameScheduledCallback set.
|
||||
*
|
||||
* @return true, if the last call to setFrameScheduledCallback set a callback
|
||||
*
|
||||
|
||||
@@ -54,8 +54,6 @@ namespace filament {
|
||||
struct UTILS_PUBLIC ToneMapper {
|
||||
ToneMapper() noexcept;
|
||||
virtual ~ToneMapper() noexcept;
|
||||
ToneMapper(ToneMapper const&) noexcept;
|
||||
ToneMapper& operator=(ToneMapper const&) noexcept = default;
|
||||
|
||||
/**
|
||||
* Maps an open domain (or "scene referred" values) color value to display
|
||||
@@ -71,13 +69,6 @@ struct UTILS_PUBLIC ToneMapper {
|
||||
*/
|
||||
virtual math::float3 operator()(math::float3 c) const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Creates a copy of this tone mapper instance.
|
||||
*
|
||||
* @return A pointer to a new ToneMapper instance that is a copy of this instance.
|
||||
*/
|
||||
virtual ToneMapper* clone() const noexcept = 0;
|
||||
|
||||
/**
|
||||
* If true, then this function holds that f(x) = vec3(f(x.r), f(x.g), f(x.b))
|
||||
*
|
||||
@@ -101,10 +92,8 @@ struct UTILS_PUBLIC ToneMapper {
|
||||
struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper {
|
||||
LinearToneMapper() noexcept;
|
||||
~LinearToneMapper() noexcept final;
|
||||
LinearToneMapper(LinearToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 c) const noexcept override;
|
||||
LinearToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return true; }
|
||||
bool isLDR() const noexcept override { return true; }
|
||||
};
|
||||
@@ -117,10 +106,8 @@ struct UTILS_PUBLIC LinearToneMapper final : public ToneMapper {
|
||||
struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper {
|
||||
ACESToneMapper() noexcept;
|
||||
~ACESToneMapper() noexcept final;
|
||||
ACESToneMapper(ACESToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 c) const noexcept override;
|
||||
ACESToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return false; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
};
|
||||
@@ -134,10 +121,8 @@ struct UTILS_PUBLIC ACESToneMapper final : public ToneMapper {
|
||||
struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper {
|
||||
ACESLegacyToneMapper() noexcept;
|
||||
~ACESLegacyToneMapper() noexcept final;
|
||||
ACESLegacyToneMapper(ACESLegacyToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 c) const noexcept override;
|
||||
ACESLegacyToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return false; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
};
|
||||
@@ -151,10 +136,8 @@ struct UTILS_PUBLIC ACESLegacyToneMapper final : public ToneMapper {
|
||||
struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
|
||||
FilmicToneMapper() noexcept;
|
||||
~FilmicToneMapper() noexcept final;
|
||||
FilmicToneMapper(FilmicToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 x) const noexcept override;
|
||||
FilmicToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return true; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
};
|
||||
@@ -167,10 +150,8 @@ struct UTILS_PUBLIC FilmicToneMapper final : public ToneMapper {
|
||||
struct UTILS_PUBLIC PBRNeutralToneMapper final : public ToneMapper {
|
||||
PBRNeutralToneMapper() noexcept;
|
||||
~PBRNeutralToneMapper() noexcept final;
|
||||
PBRNeutralToneMapper(PBRNeutralToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 x) const noexcept override;
|
||||
virtual PBRNeutralToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return false; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
};
|
||||
@@ -192,10 +173,8 @@ struct UTILS_PUBLIC AgxToneMapper final : public ToneMapper {
|
||||
*/
|
||||
explicit AgxToneMapper(AgxLook look = AgxLook::NONE) noexcept;
|
||||
~AgxToneMapper() noexcept final;
|
||||
AgxToneMapper(AgxToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 x) const noexcept override;
|
||||
virtual AgxToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return false; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
|
||||
@@ -236,13 +215,12 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
|
||||
) noexcept;
|
||||
~GenericToneMapper() noexcept final;
|
||||
|
||||
GenericToneMapper(GenericToneMapper const& rhs) noexcept;
|
||||
GenericToneMapper& operator=(GenericToneMapper const& rhs) noexcept;
|
||||
GenericToneMapper(GenericToneMapper const&) = delete;
|
||||
GenericToneMapper& operator=(GenericToneMapper const&) = delete;
|
||||
GenericToneMapper(GenericToneMapper&& rhs) noexcept;
|
||||
GenericToneMapper& operator=(GenericToneMapper&& rhs) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 x) const noexcept override;
|
||||
GenericToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return true; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
|
||||
@@ -305,10 +283,8 @@ private:
|
||||
struct UTILS_PUBLIC DisplayRangeToneMapper final : public ToneMapper {
|
||||
DisplayRangeToneMapper() noexcept;
|
||||
~DisplayRangeToneMapper() noexcept override;
|
||||
DisplayRangeToneMapper(DisplayRangeToneMapper const&) noexcept;
|
||||
|
||||
math::float3 operator()(math::float3 c) const noexcept override;
|
||||
DisplayRangeToneMapper* clone() const noexcept override;
|
||||
bool isOneDimensional() const noexcept override { return false; }
|
||||
bool isLDR() const noexcept override { return false; }
|
||||
};
|
||||
|
||||
@@ -16,13 +16,22 @@
|
||||
|
||||
#include "AtlasAllocator.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/QuadTree.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace utils;
|
||||
|
||||
static inline constexpr std::pair<uint8_t, uint8_t> unmorton(uint16_t const m) noexcept {
|
||||
static constexpr std::pair<uint8_t, uint8_t> unmorton(uint16_t const m) noexcept {
|
||||
uint32_t r = (m | (uint32_t(m) << 15u)) & 0x55555555u;
|
||||
r = (r | (r >> 1u)) & 0x33333333u;
|
||||
r = (r | (r >> 2u)) & 0x0f0f0f0fu;
|
||||
@@ -165,8 +174,8 @@ AtlasAllocator::NodeId AtlasAllocator::allocateInLayer(size_t const maxHeight) n
|
||||
NodeId found{ -1, 0 };
|
||||
QuadTree::traverse(candidate.l, candidate.code,
|
||||
[this, n, &found](NodeId const& curr) -> QuadTree::TraversalResult {
|
||||
size_t const i = index(curr.l, curr.code);
|
||||
Node& node = mQuadTree[i];
|
||||
size_t const j = index(curr.l, curr.code);
|
||||
Node& node = mQuadTree[j];
|
||||
if (curr.l == n) {
|
||||
found = curr;
|
||||
assert_invariant(!node.hasChildren());
|
||||
|
||||
@@ -188,8 +188,7 @@ float3 ACES(float3 color, float brightness) noexcept {
|
||||
|
||||
#define DEFAULT_CONSTRUCTORS(A) \
|
||||
A::A() noexcept = default; \
|
||||
A::~A() noexcept = default; \
|
||||
A::A(A const&) noexcept = default;
|
||||
A::~A() noexcept = default;
|
||||
|
||||
DEFAULT_CONSTRUCTORS(ToneMapper)
|
||||
|
||||
@@ -203,10 +202,6 @@ float3 LinearToneMapper::operator()(float3 const v) const noexcept {
|
||||
return saturate(v);
|
||||
}
|
||||
|
||||
LinearToneMapper* LinearToneMapper::clone() const noexcept {
|
||||
return new LinearToneMapper(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ACES tone mappers
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -217,20 +212,12 @@ float3 ACESToneMapper::operator()(float3 const c) const noexcept {
|
||||
return aces::ACES(c, 1.0f);
|
||||
}
|
||||
|
||||
ACESToneMapper* ACESToneMapper::clone() const noexcept {
|
||||
return new ACESToneMapper(*this);
|
||||
}
|
||||
|
||||
DEFAULT_CONSTRUCTORS(ACESLegacyToneMapper)
|
||||
|
||||
float3 ACESLegacyToneMapper::operator()(float3 const c) const noexcept {
|
||||
return aces::ACES(c, 1.0f / 0.6f);
|
||||
}
|
||||
|
||||
ACESLegacyToneMapper* ACESLegacyToneMapper::clone() const noexcept {
|
||||
return new ACESLegacyToneMapper(*this);
|
||||
}
|
||||
|
||||
DEFAULT_CONSTRUCTORS(FilmicToneMapper)
|
||||
|
||||
float3 FilmicToneMapper::operator()(float3 const x) const noexcept {
|
||||
@@ -243,10 +230,6 @@ float3 FilmicToneMapper::operator()(float3 const x) const noexcept {
|
||||
return (x * (a * x + b)) / (x * (c * x + d) + e);
|
||||
}
|
||||
|
||||
FilmicToneMapper* FilmicToneMapper::clone() const noexcept {
|
||||
return new FilmicToneMapper(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PBR Neutral tone mapper
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -273,17 +256,12 @@ float3 PBRNeutralToneMapper::operator()(float3 color) const noexcept {
|
||||
return mix(color, float3(newPeak), g);
|
||||
}
|
||||
|
||||
PBRNeutralToneMapper* PBRNeutralToneMapper::clone() const noexcept {
|
||||
return new PBRNeutralToneMapper(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// AgX tone mapper
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
AgxToneMapper::AgxToneMapper(AgxLook const look) noexcept : look(look) {}
|
||||
AgxToneMapper::~AgxToneMapper() noexcept = default;
|
||||
AgxToneMapper::AgxToneMapper(AgxToneMapper const& rhs) noexcept = default;
|
||||
|
||||
// These matrices taken from Blender's implementation of AgX, which works with Rec.2020 primaries.
|
||||
// https://github.com/EaryChow/AgX_LUT_Gen/blob/main/AgXBaseRec2020.py
|
||||
@@ -378,10 +356,6 @@ float3 AgxToneMapper::operator()(float3 v) const noexcept {
|
||||
return v;
|
||||
}
|
||||
|
||||
AgxToneMapper* AgxToneMapper::clone() const noexcept {
|
||||
return new AgxToneMapper(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Display range tone mapper
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -420,10 +394,6 @@ float3 DisplayRangeToneMapper::operator()(float3 const c) const noexcept {
|
||||
return mix(debugColors[index], debugColors[index + 1], saturate(v - float(index)));
|
||||
}
|
||||
|
||||
DisplayRangeToneMapper* DisplayRangeToneMapper::clone() const noexcept {
|
||||
return new DisplayRangeToneMapper(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Generic tone mapper
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -484,19 +454,7 @@ GenericToneMapper::~GenericToneMapper() noexcept {
|
||||
delete mOptions;
|
||||
}
|
||||
|
||||
GenericToneMapper::GenericToneMapper(GenericToneMapper const& rhs) noexcept {
|
||||
mOptions = new Options(*rhs.mOptions);
|
||||
}
|
||||
|
||||
GenericToneMapper& GenericToneMapper::operator=(GenericToneMapper const& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
delete mOptions;
|
||||
mOptions = new Options(*rhs.mOptions);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
GenericToneMapper::GenericToneMapper(GenericToneMapper&& rhs) noexcept : mOptions(rhs.mOptions) {
|
||||
GenericToneMapper::GenericToneMapper(GenericToneMapper&& rhs) noexcept : mOptions(rhs.mOptions) {
|
||||
rhs.mOptions = nullptr;
|
||||
}
|
||||
|
||||
@@ -511,10 +469,6 @@ float3 GenericToneMapper::operator()(float3 x) const noexcept {
|
||||
return mOptions->outputScale * x / (x + mOptions->inputScale);
|
||||
}
|
||||
|
||||
GenericToneMapper* GenericToneMapper::clone() const noexcept {
|
||||
return new GenericToneMapper(*this);
|
||||
}
|
||||
|
||||
float GenericToneMapper::getContrast() const noexcept { return mOptions->contrast; }
|
||||
float GenericToneMapper::getMidGrayIn() const noexcept { return mOptions->midGrayIn; }
|
||||
float GenericToneMapper::getMidGrayOut() const noexcept { return mOptions->midGrayOut; }
|
||||
|
||||
@@ -49,7 +49,7 @@ using namespace backend;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct ColorGrading::BuilderDetails {
|
||||
std::shared_ptr<ToneMapper> toneMapper = nullptr;
|
||||
const ToneMapper* toneMapper = nullptr;
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
@@ -173,7 +173,7 @@ ColorGrading::Builder& ColorGrading::Builder::dimensions(uint8_t const dim) noex
|
||||
return *this;
|
||||
}
|
||||
|
||||
ColorGrading::Builder& ColorGrading::Builder::toneMapper(std::shared_ptr<ToneMapper> toneMapper) noexcept {
|
||||
ColorGrading::Builder& ColorGrading::Builder::toneMapper(const ToneMapper* toneMapper) noexcept {
|
||||
mImpl->toneMapper = toneMapper;
|
||||
return *this;
|
||||
}
|
||||
@@ -271,110 +271,6 @@ ColorGrading::Builder& ColorGrading::Builder::outputColorSpace(
|
||||
return *this;
|
||||
}
|
||||
|
||||
ColorGrading::LutFormat ColorGrading::getLutFormat() const noexcept {
|
||||
return mSettings.lutFormat;
|
||||
}
|
||||
|
||||
uint8_t ColorGrading::getLutDimensions() const noexcept {
|
||||
return mSettings.lutDimensions;
|
||||
}
|
||||
|
||||
const ToneMapper& ColorGrading::getToneMapper() const noexcept {
|
||||
return *mSettings.toneMapper;
|
||||
}
|
||||
|
||||
bool ColorGrading::isLuminanceScalingEnabled() const noexcept {
|
||||
return mSettings.luminanceScaling;
|
||||
}
|
||||
|
||||
bool ColorGrading::isGamutMappingEnabled() const noexcept {
|
||||
return mSettings.gummapMapping;
|
||||
}
|
||||
|
||||
float ColorGrading::getExposure() const noexcept {
|
||||
return mSettings.exposure;
|
||||
}
|
||||
|
||||
float ColorGrading::getNightAdaptation() const noexcept {
|
||||
return mSettings.nightAdaptation;
|
||||
}
|
||||
|
||||
float ColorGrading::getWhiteBalanceTemperature() const noexcept {
|
||||
return mSettings.whiteBalanceTemperature;
|
||||
}
|
||||
|
||||
float ColorGrading::getWhiteBalanceTint() const noexcept {
|
||||
return mSettings.whiteBalanceTint;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getChannelMixerOutRed() const noexcept {
|
||||
return mSettings.channelMixerOutRed;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getChannelMixerOutGreen() const noexcept {
|
||||
return mSettings.channelMixerOutGreen;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getChannelMixerOutBlue() const noexcept {
|
||||
return mSettings.channelMixerOutBlue;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getShadows() const noexcept {
|
||||
return mSettings.shadows;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getMidtones() const noexcept {
|
||||
return mSettings.midtones;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getHighlights() const noexcept {
|
||||
return mSettings.highlights;
|
||||
}
|
||||
|
||||
math::float4 ColorGrading::getShadowMidtonesHighlightsRanges() const noexcept {
|
||||
return mSettings.ShadowMidtonesHighlightsRanges;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getSlope() const noexcept {
|
||||
return mSettings.slope;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getOffset() const noexcept {
|
||||
return mSettings.offset;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getPower() const noexcept {
|
||||
return mSettings.power;
|
||||
}
|
||||
|
||||
float ColorGrading::getContrast() const noexcept {
|
||||
return mSettings.contrast;
|
||||
}
|
||||
|
||||
float ColorGrading::getVibrance() const noexcept {
|
||||
return mSettings.vibrance;
|
||||
}
|
||||
|
||||
float ColorGrading::getSaturation() const noexcept {
|
||||
return mSettings.saturation;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getCurvesShadowGamma() const noexcept {
|
||||
return mSettings.curvesShadowGamma;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getCurvesMidPoint() const noexcept {
|
||||
return mSettings.curvesMidPoint;
|
||||
}
|
||||
|
||||
math::float3 ColorGrading::getCurvesHighlightScale() const noexcept {
|
||||
return mSettings.curvesHighlightScale;
|
||||
}
|
||||
|
||||
const color::ColorSpace& ColorGrading::getOutputColorSpace() const noexcept {
|
||||
return mSettings.colorSpace;
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
@@ -391,25 +287,30 @@ ColorGrading* ColorGrading::Builder::build(Engine& engine) {
|
||||
if (needToneMapper) {
|
||||
switch (mImpl->toneMapping) {
|
||||
case ToneMapping::LINEAR:
|
||||
mImpl->toneMapper = std::make_shared<LinearToneMapper>();
|
||||
mImpl->toneMapper = new LinearToneMapper();
|
||||
break;
|
||||
case ToneMapping::ACES_LEGACY:
|
||||
mImpl->toneMapper = std::make_shared<ACESLegacyToneMapper>();
|
||||
mImpl->toneMapper = new ACESLegacyToneMapper();
|
||||
break;
|
||||
case ToneMapping::ACES:
|
||||
mImpl->toneMapper = std::make_shared<ACESToneMapper>();
|
||||
mImpl->toneMapper = new ACESToneMapper();
|
||||
break;
|
||||
case ToneMapping::FILMIC:
|
||||
mImpl->toneMapper = std::make_shared<FilmicToneMapper>();
|
||||
mImpl->toneMapper = new FilmicToneMapper();
|
||||
break;
|
||||
case ToneMapping::DISPLAY_RANGE:
|
||||
mImpl->toneMapper = std::make_shared<DisplayRangeToneMapper>();
|
||||
mImpl->toneMapper = new DisplayRangeToneMapper();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FColorGrading* colorGrading = downcast(engine).createColorGrading(*this);
|
||||
|
||||
if (needToneMapper) {
|
||||
delete mImpl->toneMapper;
|
||||
mImpl->toneMapper = nullptr;
|
||||
}
|
||||
|
||||
return colorGrading;
|
||||
}
|
||||
|
||||
@@ -985,9 +886,6 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
data, lutElementCount * elementSize, format, type,
|
||||
[](void* buffer, size_t, void*) { free(buffer); }
|
||||
});
|
||||
|
||||
// Initialize settings from builder
|
||||
initializeSettings(builder, mSettings);
|
||||
}
|
||||
|
||||
FColorGrading::~FColorGrading() noexcept = default;
|
||||
@@ -997,33 +895,4 @@ void FColorGrading::terminate(FEngine& engine) {
|
||||
driver.destroyTexture(mLutHandle);
|
||||
}
|
||||
|
||||
void FColorGrading::initializeSettings(const Builder& builder, Settings& settings) noexcept {
|
||||
settings.lutFormat = builder->format;
|
||||
settings.lutDimensions = builder->dimension;
|
||||
settings.toneMapper = builder->toneMapper;
|
||||
settings.luminanceScaling = builder->luminanceScaling;
|
||||
settings.gummapMapping = builder->gamutMapping;
|
||||
settings.exposure = builder->exposure;
|
||||
settings.nightAdaptation = builder->nightAdaptation;
|
||||
settings.whiteBalanceTemperature = builder->whiteBalance.x;
|
||||
settings.whiteBalanceTint = builder->whiteBalance.y;
|
||||
settings.channelMixerOutRed = builder->outRed;
|
||||
settings.channelMixerOutGreen = builder->outGreen;
|
||||
settings.channelMixerOutBlue = builder->outBlue;
|
||||
settings.shadows = builder->shadows;
|
||||
settings.midtones = builder->midtones;
|
||||
settings.highlights = builder->highlights;
|
||||
settings.ShadowMidtonesHighlightsRanges = builder->tonalRanges;
|
||||
settings.slope = builder->slope;
|
||||
settings.offset = builder->offset;
|
||||
settings.power = builder->power;
|
||||
settings.contrast = builder->contrast;
|
||||
settings.vibrance = builder->vibrance;
|
||||
settings.saturation = builder->saturation;
|
||||
settings.curvesShadowGamma = builder->shadowGamma;
|
||||
settings.curvesMidPoint = builder->midPoint;
|
||||
settings.curvesHighlightScale = builder->highlightScale;
|
||||
settings.colorSpace = builder->outputColorSpace;
|
||||
}
|
||||
|
||||
} //namespace filament
|
||||
|
||||
@@ -51,8 +51,6 @@ private:
|
||||
uint32_t mDimension;
|
||||
bool mIsOneDimensional;
|
||||
bool mIsLDR;
|
||||
|
||||
static void initializeSettings(const Builder& builder, Settings& settings) noexcept;
|
||||
};
|
||||
|
||||
FILAMENT_DOWNCAST(ColorGrading)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.59.5"
|
||||
spec.version = "1.60.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.59.5/filament-v1.59.5-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.60.0/filament-v1.60.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 59;
|
||||
static constexpr size_t MATERIAL_VERSION = 60;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
using Precision = backend::Precision;
|
||||
using SamplerParams = backend::SamplerParams;
|
||||
using Binding = backend::descriptor_binding_t;
|
||||
using ShaderStageFlags = backend::ShaderStageFlags;
|
||||
|
||||
struct SamplerInfo { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
utils::CString name; // name of this sampler
|
||||
@@ -61,6 +62,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample; // multisample capable
|
||||
ShaderStageFlags stages; // stages the sampler can be accessed from
|
||||
};
|
||||
|
||||
using SamplerInfoList = utils::FixedCapacityVector<SamplerInfo>;
|
||||
@@ -82,6 +84,8 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample = false; // multisample capable
|
||||
ShaderStageFlags stages =
|
||||
ShaderStageFlags::ALL_SHADER_STAGE_FLAGS; // shader stages using this sampler
|
||||
};
|
||||
|
||||
// Give a name to this sampler interface block
|
||||
@@ -91,8 +95,8 @@ public:
|
||||
|
||||
// Add a sampler
|
||||
Builder& add(std::string_view samplerName, Binding binding, Type type, Format format,
|
||||
Precision precision = Precision::MEDIUM,
|
||||
bool multisample = false) noexcept;
|
||||
Precision precision = Precision::MEDIUM, bool multisample = false,
|
||||
ShaderStageFlags stages = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) noexcept;
|
||||
|
||||
// Add multiple samplers
|
||||
Builder& add(std::initializer_list<ListEntry> list) noexcept;
|
||||
|
||||
@@ -49,13 +49,13 @@ SamplerInterfaceBlock::Builder::stageFlags(backend::ShaderStageFlags stageFlags)
|
||||
return *this;
|
||||
}
|
||||
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::string_view samplerName, Binding binding, Type type, Format format,
|
||||
Precision precision, bool multisample) noexcept {
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(std::string_view samplerName,
|
||||
Binding binding, Type type, Format format, Precision precision, bool multisample,
|
||||
ShaderStageFlags stages) noexcept {
|
||||
mEntries.push_back({
|
||||
{ samplerName.data(), samplerName.size() }, // name
|
||||
{ }, // uniform name
|
||||
binding, type, format, precision, multisample });
|
||||
binding, type, format, precision, multisample, stages });
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ SamplerInterfaceBlock SamplerInterfaceBlock::Builder::build() {
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::initializer_list<ListEntry> list) noexcept {
|
||||
for (auto& e : list) {
|
||||
add(e.name, e.binding, e.type, e.format, e.precision, e.multisample);
|
||||
add(e.name, e.binding, e.type, e.format, e.precision, e.multisample, e.stages);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -91,6 +91,7 @@ SamplerInterfaceBlock::SamplerInterfaceBlock(Builder const& builder) noexcept
|
||||
size_t const i = std::distance(builder.mEntries.data(), &e);
|
||||
SamplerInfo& info = samplersInfoList[i];
|
||||
info = e;
|
||||
info.stages &= builder.mStageFlags;
|
||||
info.uniformName = generateUniformName(mName.c_str(), e.name.c_str());
|
||||
infoMap[{ info.name.data(), info.name.size() }] = i; // info.name.c_str() guaranteed constant
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ set(PRIVATE_HDRS
|
||||
src/MetalArgumentBuffer.h
|
||||
src/ShaderMinifier.h
|
||||
src/SpirvFixup.h
|
||||
src/SpirvRemapWrapper.h
|
||||
src/sca/ASTHelpers.h
|
||||
src/sca/GLSLTools.h
|
||||
src/sca/builtinResource.h)
|
||||
@@ -71,7 +72,8 @@ set(SRCS
|
||||
src/sca/GLSLTools.cpp
|
||||
src/GLSLPostProcessor.cpp
|
||||
src/ShaderMinifier.cpp
|
||||
src/SpirvFixup.cpp)
|
||||
src/SpirvFixup.cpp
|
||||
src/SpirvRemapWrapper.cpp)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
|
||||
@@ -35,6 +35,7 @@ using OutputTarget = MaterialBuilder::OutputTarget;
|
||||
using OutputQualifier = MaterialBuilder::VariableQualifier;
|
||||
using OutputType = MaterialBuilder::OutputType;
|
||||
using ConstantType = MaterialBuilder::ConstantType;
|
||||
using ShaderStageType = MaterialBuilder::ShaderStageFlags;
|
||||
|
||||
// Convenience methods to convert std::string to Enum and also iterate over Enum values.
|
||||
class Enums {
|
||||
@@ -79,6 +80,7 @@ private:
|
||||
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
|
||||
static std::unordered_map<std::string, OutputType> mStringToOutputType;
|
||||
static std::unordered_map<std::string, ConstantType> mStringToConstantType;
|
||||
static std::unordered_map<std::string, ShaderStageType> mStringToShaderStageType;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -254,6 +254,7 @@ public:
|
||||
using FeatureLevel = filament::backend::FeatureLevel;
|
||||
using StereoscopicType = filament::backend::StereoscopicType;
|
||||
using ShaderStage = filament::backend::ShaderStage;
|
||||
using ShaderStageFlags = filament::backend::ShaderStageFlags;
|
||||
|
||||
enum class VariableQualifier : uint8_t {
|
||||
OUT
|
||||
@@ -322,9 +323,9 @@ public:
|
||||
*/
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format = SamplerFormat::FLOAT,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT,
|
||||
bool multisample = false,
|
||||
const char* transformName = "") noexcept;
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT, bool multisample = false,
|
||||
const char* transformName = "",
|
||||
ShaderStageFlags stages = ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) noexcept;
|
||||
|
||||
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
|
||||
|
||||
@@ -656,8 +657,10 @@ public:
|
||||
Parameter() noexcept: parameterType(INVALID) {}
|
||||
|
||||
// Sampler
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms, const char* tn)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms), transformName(tn) { }
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p,
|
||||
bool ms, const char* tn, ShaderStageFlags s)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f),
|
||||
parameterType(SAMPLER), multisample(ms), transformName(tn), stages(s) { }
|
||||
|
||||
// Uniform
|
||||
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
|
||||
@@ -676,6 +679,7 @@ public:
|
||||
SamplerFormat format;
|
||||
bool multisample;
|
||||
utils::CString transformName;
|
||||
ShaderStageFlags stages;
|
||||
enum {
|
||||
INVALID,
|
||||
UNIFORM,
|
||||
|
||||
@@ -175,4 +175,15 @@ std::unordered_map<std::string, ConstantType>& Enums::getMap<ConstantType>() noe
|
||||
return mStringToConstantType;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, ShaderStageType> Enums::mStringToShaderStageType = {
|
||||
{ "fragment", ShaderStageType::FRAGMENT },
|
||||
{ "vertex", ShaderStageType::VERTEX },
|
||||
{ "compute", ShaderStageType::COMPUTE },
|
||||
};
|
||||
|
||||
template <>
|
||||
std::unordered_map<std::string, ShaderStageType>& Enums::getMap<ShaderStageType>() noexcept {
|
||||
return mStringToShaderStageType;
|
||||
};
|
||||
|
||||
} // namespace filamat
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "GLSLPostProcessor.h"
|
||||
|
||||
#include <GlslangToSpv.h>
|
||||
#include <SPVRemapper.h>
|
||||
#include <spirv-tools/libspirv.hpp>
|
||||
|
||||
#include <spirv_glsl.hpp>
|
||||
@@ -145,12 +144,12 @@ DescriptorSetLayout getPerMaterialDescriptorSet(SamplerInterfaceBlock const& sib
|
||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT,
|
||||
+PerMaterialBindingPoints::MATERIAL_PARAMS, DescriptorFlags::NONE, 0 });
|
||||
|
||||
for (auto const& sampler : samplers) {
|
||||
layout.bindings.push_back(DescriptorSetLayoutBinding {
|
||||
(sampler.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL) ?
|
||||
DescriptorType::SAMPLER_EXTERNAL : DescriptorType::SAMPLER,
|
||||
ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT, sampler.binding,
|
||||
DescriptorFlags::NONE, 0 });
|
||||
for (auto const& sampler: samplers) {
|
||||
layout.bindings.push_back(DescriptorSetLayoutBinding{
|
||||
(sampler.type == SamplerInterfaceBlock::Type::SAMPLER_EXTERNAL)
|
||||
? DescriptorType::SAMPLER_EXTERNAL
|
||||
: DescriptorType::SAMPLER,
|
||||
sampler.stages, sampler.binding, DescriptorFlags::NONE, 0 });
|
||||
}
|
||||
|
||||
return layout;
|
||||
@@ -289,24 +288,8 @@ GLSLPostProcessor::GLSLPostProcessor(MaterialBuilder::Optimization optimization,
|
||||
: mOptimization(optimization),
|
||||
mPrintShaders(flags & PRINT_SHADERS),
|
||||
mGenerateDebugInfo(flags & GENERATE_DEBUG_INFO) {
|
||||
// SPIRV error handler registration needs to occur only once. To avoid a race we do it up here
|
||||
// in the constructor, which gets invoked before MaterialBuilder kicks off jobs.
|
||||
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
|
||||
slog.e << str << io::endl;
|
||||
});
|
||||
|
||||
// Similar to above, we need to do a no-op remap to init a static table in the remapper before
|
||||
// the jobs start using remap().
|
||||
spv::spirvbin_t remapper(0);
|
||||
// We need to provide at least a valid header to not crash.
|
||||
SpirvBlob spirv {
|
||||
0x07230203,// MAGIC
|
||||
0, // VERSION
|
||||
0, // GENERATOR
|
||||
0, // BOUND
|
||||
0 // SCHEMA, must be 0
|
||||
};
|
||||
remapper.remap(spirv, 0);
|
||||
// This should occur only once, to avoid races.
|
||||
SpirvRemapWrapperSetUp();
|
||||
}
|
||||
|
||||
GLSLPostProcessor::~GLSLPostProcessor() = default;
|
||||
@@ -988,8 +971,7 @@ void GLSLPostProcessor::optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv)
|
||||
}
|
||||
|
||||
// Remove dead module-level objects: functions, types, vars
|
||||
spv::spirvbin_t remapper(0);
|
||||
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
|
||||
SpirvRemapWrapperRemap(spirv);
|
||||
}
|
||||
|
||||
void GLSLPostProcessor::fixupClipDistance(
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <private/filament/SamplerInterfaceBlock.h>
|
||||
|
||||
#include "ShaderMinifier.h"
|
||||
#include "SpirvRemapWrapper.h"
|
||||
|
||||
#include <spirv-tools/optimizer.hpp>
|
||||
|
||||
|
||||
@@ -302,7 +302,8 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType const
|
||||
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format, ParameterPrecision precision, bool multisample, const char* transformName) noexcept {
|
||||
SamplerFormat format, ParameterPrecision precision, bool multisample,
|
||||
const char* transformName, ShaderStageFlags stages) noexcept {
|
||||
FILAMENT_CHECK_PRECONDITION(!multisample ||
|
||||
(format != SamplerFormat::SHADOW &&
|
||||
(samplerType == SamplerType::SAMPLER_2D ||
|
||||
@@ -311,7 +312,7 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType sample
|
||||
" as long as type is not SHADOW";
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT) << "Too many parameters";
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample, transformName };
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample, transformName, stages };
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -637,8 +638,8 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
auto const& param = mParameters[i];
|
||||
assert_invariant(!param.isSubpass());
|
||||
if (param.isSampler()) {
|
||||
sbb.add({ param.name.data(), param.name.size() },
|
||||
binding, param.samplerType, param.format, param.precision, param.multisample);
|
||||
sbb.add({ param.name.data(), param.name.size() }, binding, param.samplerType,
|
||||
param.format, param.precision, param.multisample, param.stages);
|
||||
if (!param.transformName.empty()) {
|
||||
ibb.add({{{ param.transformName.data(), param.transformName.size() }, uint8_t(binding),
|
||||
0, UniformType::MAT3, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }});
|
||||
|
||||
54
libs/filamat/src/SpirvRemapWrapper.cpp
Normal file
54
libs/filamat/src/SpirvRemapWrapper.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 "SpirvRemapWrapper.h"
|
||||
|
||||
#include <SPVRemapper.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace filamat {
|
||||
|
||||
void SpirvRemapWrapperSetUp() {
|
||||
// SPIRV error handler registration should occur only once.
|
||||
// Construct this SpirvRemapWrapper object only once.
|
||||
spv::spirvbin_t::registerErrorHandler([](const std::string& str) {
|
||||
utils::slog.e << str << utils::io::endl;
|
||||
});
|
||||
|
||||
// Similar to above, we need to do a no-op remap to init a static
|
||||
// table in the remapper before the jobs start using remap().
|
||||
spv::spirvbin_t remapper(0);
|
||||
// We need to provide at least a valid header to not crash.
|
||||
std::vector<uint32_t> spirv {
|
||||
0x07230203,// MAGIC
|
||||
0, // VERSION
|
||||
0, // GENERATOR
|
||||
0, // BOUND
|
||||
0 // SCHEMA, must be 0
|
||||
};
|
||||
remapper.remap(spirv, 0);
|
||||
}
|
||||
|
||||
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv) {
|
||||
// Remove dead module-level objects: functions, types, vars
|
||||
spv::spirvbin_t remapper(0);
|
||||
remapper.remap(spirv, spv::spirvbin_base_t::DCE_ALL);
|
||||
}
|
||||
|
||||
} // namespace filamat
|
||||
30
libs/filamat/src/SpirvRemapWrapper.h
Normal file
30
libs/filamat/src/SpirvRemapWrapper.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_SPIRVREMAPWRAPPER_H
|
||||
#define TNT_SPIRVREMAPWRAPPER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace filamat {
|
||||
|
||||
void SpirvRemapWrapperSetUp();
|
||||
void SpirvRemapWrapperRemap(std::vector<uint32_t>& spirv);
|
||||
|
||||
} // namespace filamat
|
||||
|
||||
#endif //TNT_SPIRVREMAPWRAPPER_H
|
||||
@@ -233,7 +233,7 @@ void MaterialDescriptorSetLayoutChunk::flatten(Flattener& f) {
|
||||
} else {
|
||||
f.writeUint8(uint8_t(DescriptorType::SAMPLER));
|
||||
}
|
||||
f.writeUint8(uint8_t(ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT));
|
||||
f.writeUint8(uint8_t(entry.stages));
|
||||
f.writeUint8(entry.binding);
|
||||
f.writeUint8(uint8_t(DescriptorFlags::NONE));
|
||||
f.writeUint16(0);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <filamat/MaterialBuilder.h>
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <geometry/TangentSpaceMesh.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/StructureOfArrays.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
using namespace utils;
|
||||
using namespace std::literals;
|
||||
|
||||
@@ -65,6 +65,8 @@ set(SRCS
|
||||
src/CyclicBarrier.cpp
|
||||
src/EntityManager.cpp
|
||||
src/EntityManagerImpl.h
|
||||
src/FixedCapacityVectorBase.cpp
|
||||
src/Invocable.cpp
|
||||
src/JobSystem.cpp
|
||||
src/Log.cpp
|
||||
src/NameComponentManager.cpp
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
// NOTE: this header should not include STL headers
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
@@ -31,6 +31,9 @@
|
||||
#include <string.h>
|
||||
|
||||
namespace utils {
|
||||
namespace io {
|
||||
class ostream;
|
||||
}
|
||||
|
||||
//! \privatesection
|
||||
struct hashCStrings {
|
||||
@@ -38,7 +41,7 @@ struct hashCStrings {
|
||||
typedef size_t result_type;
|
||||
result_type operator()(argument_type cstr) const noexcept {
|
||||
size_t hash = 5381;
|
||||
while (int const c = *cstr++) {
|
||||
while (int const c = static_cast<unsigned char>(*cstr++)) {
|
||||
hash = (hash * 33u) ^ size_t(c);
|
||||
}
|
||||
return hash;
|
||||
@@ -97,11 +100,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CString() noexcept {
|
||||
if (mData) {
|
||||
free(mData - 1);
|
||||
}
|
||||
}
|
||||
~CString() noexcept;
|
||||
|
||||
void swap(CString& other) noexcept {
|
||||
// don't use std::swap(), we don't want an STL dependency in this file
|
||||
@@ -110,8 +109,8 @@ public:
|
||||
other.mCStr = temp;
|
||||
}
|
||||
|
||||
const_pointer c_str() const noexcept { return mCStr; }
|
||||
pointer c_str() noexcept { return mCStr; }
|
||||
const_pointer c_str() const noexcept { return const_cast<CString*>(this)->c_str(); }
|
||||
const_pointer c_str_safe() const noexcept { return mData ? c_str() : ""; }
|
||||
const_pointer data() const noexcept { return c_str(); }
|
||||
pointer data() noexcept { return c_str(); }
|
||||
@@ -119,33 +118,89 @@ public:
|
||||
size_type length() const noexcept { return size(); }
|
||||
bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
iterator begin() noexcept { return mCStr; }
|
||||
iterator begin() noexcept { return c_str(); }
|
||||
iterator end() noexcept { return begin() + length(); }
|
||||
const_iterator begin() const noexcept { return data(); }
|
||||
const_iterator end() const noexcept { return begin() + length(); }
|
||||
const_iterator cbegin() const noexcept { return begin(); }
|
||||
const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
CString& replace(size_type pos, size_type len, const CString& str) noexcept;
|
||||
CString& insert(size_type pos, const CString& str) noexcept { return replace(pos, 0, str); }
|
||||
CString& append(const CString& str) noexcept { return insert(length(), str); }
|
||||
// replace
|
||||
template<size_t N>
|
||||
CString& replace(size_type const pos,
|
||||
size_type const len, const StringLiteral<N>& str) & noexcept {
|
||||
return replace(pos, len, str, N - 1);
|
||||
}
|
||||
|
||||
const_reference operator[](size_type pos) const noexcept {
|
||||
CString& replace(size_type const pos, size_type const len, const CString& str) & noexcept {
|
||||
return replace(pos, len, str.c_str_safe(), str.size());
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& replace(size_type const pos,
|
||||
size_type const len, const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(replace(pos, len, str));
|
||||
}
|
||||
|
||||
CString&& replace(size_type const pos, size_type const len, const CString& str) && noexcept {
|
||||
return std::move(replace(pos, len, str));
|
||||
}
|
||||
|
||||
// insert
|
||||
template<size_t N>
|
||||
CString& insert(size_type const pos, const StringLiteral<N>& str) & noexcept {
|
||||
return replace(pos, 0, str);
|
||||
}
|
||||
|
||||
CString& insert(size_type const pos, const CString& str) & noexcept {
|
||||
return replace(pos, 0, str);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& insert(size_type const pos, const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(*this).replace(pos, 0, str);
|
||||
}
|
||||
|
||||
CString&& insert(size_type const pos, const CString& str) && noexcept {
|
||||
return std::move(*this).replace(pos, 0, str);
|
||||
}
|
||||
|
||||
// append
|
||||
template<size_t N>
|
||||
CString& append(const StringLiteral<N>& str) & noexcept {
|
||||
return insert(length(), str);
|
||||
}
|
||||
|
||||
CString& append(const CString& str) & noexcept {
|
||||
return insert(length(), str);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& append(const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(*this).insert(length(), str);
|
||||
}
|
||||
|
||||
CString&& append(const CString& str) && noexcept {
|
||||
return std::move(*this).insert(length(), str);
|
||||
}
|
||||
|
||||
|
||||
const_reference operator[](size_type const pos) const noexcept {
|
||||
assert(pos < size());
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
reference operator[](size_type pos) noexcept {
|
||||
reference operator[](size_type const pos) noexcept {
|
||||
assert(pos < size());
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
const_reference at(size_type pos) const noexcept {
|
||||
const_reference at(size_type const pos) const noexcept {
|
||||
assert(pos < size());
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
reference at(size_type pos) noexcept {
|
||||
reference at(size_type const pos) noexcept {
|
||||
assert(pos < size());
|
||||
return begin()[pos];
|
||||
}
|
||||
@@ -171,7 +226,7 @@ public:
|
||||
}
|
||||
|
||||
// placement new declared as "throw" to avoid the compiler's null-check
|
||||
inline void* operator new(size_t, void* ptr) {
|
||||
void* operator new(size_t, void* ptr) {
|
||||
assert(ptr);
|
||||
return ptr;
|
||||
}
|
||||
@@ -185,6 +240,8 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
CString& replace(size_type pos, size_type len, char const* str, size_t l) & noexcept;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
friend io::ostream& operator<<(io::ostream& out, const CString& rhs);
|
||||
#endif
|
||||
@@ -225,7 +282,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// implement this for your type for automatic conversion to CString. Failing to do so leads
|
||||
// Implement this for your type for automatic conversion to CString. Failing to do so leads
|
||||
// to a compile-time failure.
|
||||
template<typename T>
|
||||
CString to_string(T value) noexcept;
|
||||
@@ -249,7 +306,7 @@ public:
|
||||
pointer c_str() noexcept { return mData; }
|
||||
|
||||
private:
|
||||
value_type mData[N] = {0};
|
||||
value_type mData[N] = {};
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace utils {
|
||||
namespace io {
|
||||
class ostream;
|
||||
}
|
||||
|
||||
/**
|
||||
* CallStack captures the current's thread call stack.
|
||||
@@ -88,23 +90,23 @@ public:
|
||||
|
||||
bool operator <(const CallStack& rhs) const;
|
||||
|
||||
inline bool operator >(const CallStack& rhs) const {
|
||||
bool operator >(const CallStack& rhs) const {
|
||||
return rhs < *this;
|
||||
}
|
||||
|
||||
inline bool operator !=(const CallStack& rhs) const {
|
||||
bool operator !=(const CallStack& rhs) const {
|
||||
return *this < rhs || rhs < *this;
|
||||
}
|
||||
|
||||
inline bool operator >=(const CallStack& rhs) const {
|
||||
bool operator >=(const CallStack& rhs) const {
|
||||
return !operator <(rhs);
|
||||
}
|
||||
|
||||
inline bool operator <=(const CallStack& rhs) const {
|
||||
bool operator <=(const CallStack& rhs) const {
|
||||
return !operator >(rhs);
|
||||
}
|
||||
|
||||
inline bool operator ==(const CallStack& rhs) const {
|
||||
bool operator ==(const CallStack& rhs) const {
|
||||
return !operator !=(rhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/compressed_pair.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
@@ -40,6 +40,11 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
class FixedCapacityVectorBase {
|
||||
protected:
|
||||
UTILS_NORETURN static void capacityCheckFailed(size_t capacity, size_t size);
|
||||
};
|
||||
|
||||
/**
|
||||
* FixedCapacityVector is (almost) a drop-in replacement for std::vector<> except it has a
|
||||
* fixed capacity decided at runtime. The vector storage is never reallocated unless reserve()
|
||||
@@ -56,7 +61,7 @@ namespace utils {
|
||||
* the optional value argument, e.g. FixedCapacityVector<int>(4, 0) or foo.resize(4, 0).
|
||||
*/
|
||||
template<typename T, typename A = std::allocator<T>, bool CapacityCheck = true>
|
||||
class UTILS_PUBLIC FixedCapacityVector {
|
||||
class UTILS_PUBLIC FixedCapacityVector : protected FixedCapacityVectorBase {
|
||||
public:
|
||||
using allocator_type = A;
|
||||
using value_type = T;
|
||||
@@ -266,7 +271,7 @@ public:
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
void resize(size_type count) {
|
||||
void resize(size_type const count) {
|
||||
assertCapacityForSize(count);
|
||||
if constexpr(std::is_trivially_constructible_v<value_type> &&
|
||||
std::is_trivially_destructible_v<value_type>) {
|
||||
@@ -277,12 +282,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void resize(size_type count, const_reference v) {
|
||||
void resize(size_type const count, const_reference v) {
|
||||
assertCapacityForSize(count);
|
||||
resize_non_trivial(count, v);
|
||||
}
|
||||
|
||||
void swap(FixedCapacityVector& other) {
|
||||
void swap(FixedCapacityVector& other) noexcept {
|
||||
using std::swap;
|
||||
swap(mData, other.mData);
|
||||
swap(mSize, other.mSize);
|
||||
@@ -326,16 +331,16 @@ private:
|
||||
return mCapacityAllocator.second();
|
||||
}
|
||||
|
||||
iterator assertCapacityForSize(size_type s) {
|
||||
iterator assertCapacityForSize(size_type const s) {
|
||||
if constexpr(CapacityCheck || FILAMENT_FORCE_CAPACITY_CHECK) {
|
||||
FILAMENT_CHECK_PRECONDITION(capacity() >= s)
|
||||
<< "capacity exceeded: requested size " << (unsigned long)s
|
||||
<< "u, available capacity " << (unsigned long)capacity() << "u.";
|
||||
if (UTILS_VERY_UNLIKELY(capacity() < s)) {
|
||||
capacityCheckFailed(capacity(), s);
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
inline void construct(iterator first, iterator last) noexcept {
|
||||
void construct(iterator const first, iterator const last) noexcept {
|
||||
// we check for triviality here so that the implementation could be non-inline
|
||||
if constexpr(!std::is_trivially_constructible_v<value_type>) {
|
||||
construct_non_trivial(first, last);
|
||||
@@ -358,7 +363,7 @@ private:
|
||||
}
|
||||
|
||||
|
||||
inline void destroy(iterator first, iterator last) noexcept {
|
||||
void destroy(iterator const first, iterator const last) noexcept {
|
||||
// we check for triviality here so that the implementation could be non-inline
|
||||
if constexpr(!std::is_trivially_destructible_v<value_type>) {
|
||||
destroy_non_trivial(first, last);
|
||||
@@ -419,7 +424,7 @@ private:
|
||||
explicit SizeTypeWrapper(TYPE value) noexcept : value(value) { }
|
||||
SizeTypeWrapper& operator=(TYPE rhs) noexcept { value = rhs; return *this; }
|
||||
SizeTypeWrapper& operator=(SizeTypeWrapper& rhs) noexcept = delete;
|
||||
operator TYPE() const noexcept { return value; }
|
||||
operator TYPE() const noexcept { return value; } // NOLINT(*-explicit-constructor)
|
||||
};
|
||||
|
||||
pointer mData{};
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_UTILS_INVOKABLE_H
|
||||
#define TNT_UTILS_INVOKABLE_H
|
||||
|
||||
#include <utils/ostream.h>
|
||||
#ifndef TNT_UTILS_INVOCABLE_H
|
||||
#define TNT_UTILS_INVOCABLE_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -25,6 +23,9 @@
|
||||
#include <assert.h>
|
||||
|
||||
namespace utils {
|
||||
namespace io {
|
||||
class ostream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invocable is a move-only general purpose function wrapper. Instances can
|
||||
@@ -50,11 +51,16 @@ template<typename Fn, typename R, typename... Args>
|
||||
using EnableIfFnMatchesInvocable = std::enable_if_t<true, int>;
|
||||
#endif
|
||||
|
||||
class InvocableBase {
|
||||
protected:
|
||||
static io::ostream& printInvocable(io::ostream& out, const char* name);
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
class Invocable;
|
||||
|
||||
template<typename R, typename... Args>
|
||||
class Invocable<R(Args...)> {
|
||||
class Invocable<R(Args...)> : protected InvocableBase {
|
||||
public:
|
||||
// Creates an Invocable that does not contain a functor.
|
||||
// Will evaluate to false.
|
||||
@@ -85,7 +91,7 @@ public:
|
||||
private:
|
||||
#if !defined(NDEBUG)
|
||||
friend io::ostream& operator<<(io::ostream& out, const Invocable&) {
|
||||
return out << "Invocable<>"; // TODO: is there a way to do better here?
|
||||
return printInvocable(out, "Invocable<>"); // TODO: is there a way to do better here?
|
||||
}
|
||||
#endif
|
||||
void* mInvocable = nullptr;
|
||||
@@ -156,4 +162,4 @@ Invocable<R(Args...)>::operator bool() const noexcept {
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // TNT_UTILS_INVOKABLE_H
|
||||
#endif // TNT_UTILS_INVOCABLE_H
|
||||
|
||||
@@ -353,7 +353,7 @@ public:
|
||||
* The TPanic<> class implements the std::exception protocol as well as the Panic
|
||||
* interface common to all exceptions thrown by the framework.
|
||||
*/
|
||||
template <typename T>
|
||||
template <typename>
|
||||
class UTILS_PUBLIC TPanic : public Panic {
|
||||
public:
|
||||
// std::exception protocol
|
||||
@@ -398,12 +398,11 @@ public:
|
||||
* @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC
|
||||
* @see setMode()
|
||||
*/
|
||||
static inline void panic(
|
||||
static void panic(
|
||||
char const* function, char const* file, int line, char const* literal,
|
||||
std::string reason) UTILS_NORETURN;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates a Panic with extra information about the error-site.
|
||||
* @param function the name of the function where the error was detected
|
||||
@@ -415,11 +414,14 @@ protected:
|
||||
TPanic(char const* function, char const* file, int line, char const* literal,
|
||||
std::string reason);
|
||||
|
||||
friend class PreconditionPanic;
|
||||
friend class PostconditionPanic;
|
||||
friend class ArithmeticPanic;
|
||||
|
||||
protected:
|
||||
~TPanic() override;
|
||||
|
||||
private:
|
||||
void buildMessage();
|
||||
|
||||
char const* const mFile = nullptr; // file where the panic happened
|
||||
char const* const mFunction = nullptr; // function where the panic happened
|
||||
int const mLine = -1; // line where the panic happened
|
||||
@@ -443,7 +445,7 @@ void panicLog(
|
||||
* ASSERT_PRECONDITION uses this Panic to report a precondition failure.
|
||||
* @see ASSERT_PRECONDITION
|
||||
*/
|
||||
class UTILS_PUBLIC PreconditionPanic : public TPanic<PreconditionPanic> {
|
||||
class UTILS_PUBLIC PreconditionPanic final : public TPanic<PreconditionPanic> {
|
||||
// Programming error, can be avoided
|
||||
// e.g.: invalid arguments
|
||||
using TPanic<PreconditionPanic>::TPanic;
|
||||
@@ -457,9 +459,9 @@ class UTILS_PUBLIC PreconditionPanic : public TPanic<PreconditionPanic> {
|
||||
* ASSERT_POSTCONDITION uses this Panic to report a postcondition failure.
|
||||
* @see ASSERT_POSTCONDITION
|
||||
*/
|
||||
class UTILS_PUBLIC PostconditionPanic : public TPanic<PostconditionPanic> {
|
||||
class UTILS_PUBLIC PostconditionPanic final : public TPanic<PostconditionPanic> {
|
||||
// Usually only detectable at runtime
|
||||
// e.g.: dead-lock would occur, arithmetic errors
|
||||
// e.g.: deadlock would occur, arithmetic errors
|
||||
using TPanic<PostconditionPanic>::TPanic;
|
||||
friend class TPanic<PostconditionPanic>;
|
||||
constexpr static auto type = "Postcondition";
|
||||
@@ -471,7 +473,7 @@ class UTILS_PUBLIC PostconditionPanic : public TPanic<PostconditionPanic> {
|
||||
* ASSERT_ARITHMETIC uses this Panic to report an arithmetic (postcondition) failure.
|
||||
* @see ASSERT_ARITHMETIC
|
||||
*/
|
||||
class UTILS_PUBLIC ArithmeticPanic : public TPanic<ArithmeticPanic> {
|
||||
class UTILS_PUBLIC ArithmeticPanic final : public TPanic<ArithmeticPanic> {
|
||||
// A common case of post-condition error
|
||||
// e.g.: underflow, overflow, internal computations errors
|
||||
using TPanic<ArithmeticPanic>::TPanic;
|
||||
@@ -519,11 +521,11 @@ public:
|
||||
|
||||
PanicStream& operator<<(const void* value) noexcept;
|
||||
|
||||
PanicStream& operator<<(const char* string) noexcept;
|
||||
PanicStream& operator<<(const unsigned char* string) noexcept;
|
||||
PanicStream& operator<<(const char* value) noexcept;
|
||||
PanicStream& operator<<(const unsigned char* value) noexcept;
|
||||
|
||||
PanicStream& operator<<(std::string const& s) noexcept;
|
||||
PanicStream& operator<<(std::string_view const& s) noexcept;
|
||||
PanicStream& operator<<(std::string const& value) noexcept;
|
||||
PanicStream& operator<<(std::string_view const& value) noexcept;
|
||||
|
||||
protected:
|
||||
io::sstream mStream;
|
||||
|
||||
@@ -19,11 +19,8 @@
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
@@ -41,7 +38,7 @@ public:
|
||||
using const_iterator = std::string_view::const_iterator;
|
||||
|
||||
// Constructor from string literal
|
||||
template <size_t M>
|
||||
template<unsigned int M>
|
||||
constexpr StaticString(const char (&str)[M]) noexcept : mString(str, M - 1) {} // NOLINT(*-explicit-constructor)
|
||||
|
||||
constexpr StaticString() noexcept = default;
|
||||
@@ -61,7 +58,7 @@ public:
|
||||
return mString[pos];
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const {
|
||||
constexpr const_reference at(size_type const pos) const {
|
||||
return mString[pos];
|
||||
}
|
||||
|
||||
|
||||
@@ -20,27 +20,30 @@
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace utils {
|
||||
|
||||
UTILS_NOINLINE
|
||||
CString::CString(const char* cstr, size_t length) {
|
||||
CString::CString(const char* cstr, size_t const length) {
|
||||
if (length && cstr) {
|
||||
Data* p = (Data*)malloc(sizeof(Data) + length + 1);
|
||||
p->length = (size_type)length;
|
||||
mCStr = (value_type*)(p + 1);
|
||||
|
||||
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + length + 1));
|
||||
p->length = size_type(length);
|
||||
mCStr = reinterpret_cast<value_type*>(p + 1);
|
||||
// we don't use memcpy here to avoid a call to libc, the generated code is pretty good.
|
||||
std::uninitialized_copy_n(cstr, length, mCStr);
|
||||
mCStr[length] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
CString::CString(size_t length) {
|
||||
CString::CString(size_t const length) {
|
||||
if (length) {
|
||||
Data* p = (Data*)malloc(sizeof(Data) + length + 1);
|
||||
p->length = (size_type)length;
|
||||
mCStr = (value_type*)(p + 1);
|
||||
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + length + 1));
|
||||
p->length = size_type(length);
|
||||
mCStr = reinterpret_cast<value_type*>(p + 1);
|
||||
std::fill_n(mCStr, length, 0);
|
||||
mCStr[length] = '\0';
|
||||
}
|
||||
@@ -58,24 +61,30 @@ CString& CString::operator=(const CString& rhs) {
|
||||
if (this != &rhs) {
|
||||
auto *const p = mData ? mData - 1 : nullptr;
|
||||
new(this) CString(rhs);
|
||||
free(p);
|
||||
std::free(p);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CString& CString::replace(size_type pos, size_type len, const CString& str) noexcept {
|
||||
CString::~CString() noexcept {
|
||||
if (mData) {
|
||||
std::free(mData - 1);
|
||||
}
|
||||
}
|
||||
|
||||
CString& CString::replace(size_type const pos, size_type len, char const* str, size_t const l) & noexcept {
|
||||
assert(pos <= size());
|
||||
|
||||
len = std::min(len, size() - pos);
|
||||
|
||||
// The new size of the string, after the replacement.
|
||||
const size_type newSize = size() - len + str.size();
|
||||
const size_type newSize = size() - len + l;
|
||||
|
||||
// Allocate enough memory to hold the new string.
|
||||
Data* p = (Data*) malloc(sizeof(Data) + newSize + 1);
|
||||
Data* const p = static_cast<Data*>(std::malloc(sizeof(Data) + newSize + 1));
|
||||
assert(p);
|
||||
p->length = newSize;
|
||||
value_type* newStr = (value_type*) (p + 1);
|
||||
value_type* newStr = reinterpret_cast<value_type*>(p + 1);
|
||||
|
||||
const value_type* beginning = mCStr;
|
||||
const value_type* replacementStart = mCStr + pos;
|
||||
@@ -84,7 +93,7 @@ CString& CString::replace(size_type pos, size_type len, const CString& str) noex
|
||||
|
||||
value_type* ptr = newStr;
|
||||
ptr = std::uninitialized_copy(beginning, replacementStart, ptr);
|
||||
ptr = std::uninitialized_copy_n(str.c_str_safe(), str.length(), ptr);
|
||||
ptr = std::uninitialized_copy_n(str, l, ptr);
|
||||
ptr = std::uninitialized_copy(replacementEnd, end, ptr);
|
||||
|
||||
// null-terminator
|
||||
@@ -92,14 +101,14 @@ CString& CString::replace(size_type pos, size_type len, const CString& str) noex
|
||||
|
||||
std::swap(mCStr, newStr);
|
||||
if (newStr) {
|
||||
free((Data*) newStr - 1);
|
||||
std::free(reinterpret_cast<Data*>(newStr) - 1);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
io::ostream& operator<<(io::ostream& out, const utils::CString& rhs) {
|
||||
io::ostream& operator<<(io::ostream& out, const CString& rhs) {
|
||||
return out << rhs.c_str_safe();
|
||||
}
|
||||
#endif
|
||||
|
||||
36
libs/utils/src/FixedCapacityVectorBase.cpp
Normal file
36
libs/utils/src/FixedCapacityVectorBase.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
void FixedCapacityVectorBase::capacityCheckFailed(size_t const capacity, size_t const size) {
|
||||
UTILS_ASSUME(capacity < size);
|
||||
FILAMENT_CHECK_PRECONDITION(capacity >= size)
|
||||
<< "capacity exceeded: requested size " << size
|
||||
<< "u, available capacity " << capacity << "u.";
|
||||
|
||||
// In practice, we will never reach this.
|
||||
abort();
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
24
libs/utils/src/Invocable.cpp
Normal file
24
libs/utils/src/Invocable.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
namespace utils {
|
||||
io::ostream& InvocableBase::printInvocable(io::ostream& out, const char* name) {
|
||||
return out << name;
|
||||
}
|
||||
} // namespace utils
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "ostream_.h"
|
||||
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
@@ -68,7 +69,7 @@ public:
|
||||
getCallback().call(panic);
|
||||
}
|
||||
|
||||
void set(Panic::PanicHandlerCallback handler, void* user) noexcept {
|
||||
void set(Panic::PanicHandlerCallback const handler, void* user) noexcept {
|
||||
std::lock_guard const lock(mLock);
|
||||
mCallBack = { handler, user };
|
||||
}
|
||||
@@ -96,7 +97,7 @@ static std::string sprintfToString(const char* format, va_list args) noexcept {
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline std::string sprintfToString(const char* format, ...) noexcept {
|
||||
static std::string sprintfToString(const char* format, ...) noexcept {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
std::string const s{ sprintfToString(format, args) };
|
||||
@@ -120,14 +121,14 @@ static std::string buildPanicString(
|
||||
|
||||
Panic::~Panic() noexcept = default;
|
||||
|
||||
void Panic::setPanicHandler(PanicHandlerCallback handler, void* user) noexcept {
|
||||
void Panic::setPanicHandler(PanicHandlerCallback const handler, void* user) noexcept {
|
||||
UserPanicHandler::get().set(handler, user);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
TPanic<T>::TPanic(const char* function, const char* file, int line, char const* literal,
|
||||
TPanic<T>::TPanic(const char* function, const char* file, int const line, char const* literal,
|
||||
std::string reason)
|
||||
: mFile(file),
|
||||
mFunction(function),
|
||||
@@ -188,13 +189,13 @@ void TPanic<T>::log() const noexcept {
|
||||
}
|
||||
|
||||
UTILS_ALWAYS_INLINE
|
||||
inline static const char* formatFile(char const* file) noexcept {
|
||||
static const char* formatFile(char const* file) noexcept {
|
||||
const char * p = std::strstr(file, "filament/");
|
||||
return p ? p : file;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TPanic<T>::panic(char const* function, char const* file, int line, char const* literal,
|
||||
void TPanic<T>::panic(char const* function, char const* file, int const line, char const* literal,
|
||||
const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
@@ -233,7 +234,7 @@ void TPanic<T>::panic(char const* function, char const* file, int line, char con
|
||||
|
||||
namespace details {
|
||||
|
||||
void panicLog(char const* function, char const* file, int line, const char* format, ...) noexcept {
|
||||
void panicLog(char const* function, char const* file, int const line, const char* format, ...) noexcept {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
std::string const reason{ sprintfToString(format, args) };
|
||||
@@ -249,79 +250,79 @@ void panicLog(char const* function, char const* file, int line, const char* form
|
||||
PanicStream::PanicStream(
|
||||
char const* function,
|
||||
char const* file,
|
||||
int line,
|
||||
int const line,
|
||||
char const* condition) noexcept
|
||||
: mFunction(function), mFile(file), mLine(line), mLiteral(condition) {
|
||||
}
|
||||
|
||||
PanicStream::~PanicStream() = default;
|
||||
|
||||
PanicStream& PanicStream::operator<<(short value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(short const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(unsigned short value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(unsigned short const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(char value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(char const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(unsigned char value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(unsigned char const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(int value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(int const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(unsigned int value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(unsigned int const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(long value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(long const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(unsigned long value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(unsigned long const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(long long int value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(long long int const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(unsigned long long int value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(unsigned long long int const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(float value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(float const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(double value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(double const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(long double value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(long double const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PanicStream& PanicStream::operator<<(bool value) noexcept {
|
||||
PanicStream& PanicStream::operator<<(bool const value) noexcept {
|
||||
mStream << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#define TNT_UTILS_OSTREAM__H
|
||||
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <utility>
|
||||
#include <mutex>
|
||||
|
||||
namespace utils::io {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Panic.h>
|
||||
|
||||
using namespace utils;
|
||||
|
||||
|
||||
@@ -700,8 +700,7 @@ constexpr ToneMapper* createToneMapper(const ColorGradingSettings& settings) noe
|
||||
}
|
||||
|
||||
ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* engine) {
|
||||
ToneMapper* toneMapperRaw = createToneMapper(settings);
|
||||
std::shared_ptr<ToneMapper> toneMapper(toneMapperRaw);
|
||||
ToneMapper* toneMapper = createToneMapper(settings);
|
||||
ColorGrading *colorGrading = ColorGrading::Builder()
|
||||
.quality(settings.quality)
|
||||
.exposure(settings.exposure)
|
||||
@@ -724,6 +723,7 @@ ColorGrading* createColorGrading(const ColorGradingSettings& settings, Engine* e
|
||||
.gamutMapping(settings.gamutMapping)
|
||||
.outputColorSpace(settings.colorspace)
|
||||
.build(*engine);
|
||||
delete toneMapper;
|
||||
return colorGrading;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ static const Vertex TRIANGLE_VERTICES[3] = {
|
||||
{{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu},
|
||||
};
|
||||
|
||||
static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 };
|
||||
static constexpr uint16_t TRIANGLE_INDICES[4] = { 0, 1, 2 , 0};
|
||||
|
||||
static void printUsage(char* name) {
|
||||
std::string exec_name(utils::Path(name).getName());
|
||||
@@ -147,11 +147,11 @@ int main(int argc, char** argv) {
|
||||
app.vb->setBufferAt(*engine, 0,
|
||||
VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr));
|
||||
app.ib = IndexBuffer::Builder()
|
||||
.indexCount(3)
|
||||
.indexCount(4)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(*engine);
|
||||
app.ib->setBuffer(*engine,
|
||||
IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr));
|
||||
IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 8, nullptr));
|
||||
app.mat = Material::Builder()
|
||||
.package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE)
|
||||
.build(*engine);
|
||||
|
||||
59
test/renderdiff/generate.sh
Executable file
59
test/renderdiff/generate.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
# Copyright (C) 2025 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#!/usr/bin/bash
|
||||
|
||||
source `dirname $0`/src/preamble.sh
|
||||
|
||||
function start_render_() {
|
||||
start_
|
||||
if [[ ! "$GITHUB_WORKFLOW" ]]; then
|
||||
if [ ! -d ${MESA_LIB_DIR} ]; then
|
||||
bash ${BUILD_COMMON_DIR}/get-mesa.sh
|
||||
fi
|
||||
|
||||
# Install python deps
|
||||
python3 -m venv ${VENV_DIR}
|
||||
source ${VENV_DIR}/bin/activate
|
||||
|
||||
NEEDED_PYTHON_DEPS=("numpy" "tifffile")
|
||||
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
|
||||
if ! python3 -m pip show -q "${cmd}"; then
|
||||
python3 -m pip install ${cmd}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
CXX=`which clang++` CC=`which clang` ./build.sh -f -X ${MESA_DIR} -p desktop debug gltf_viewer
|
||||
}
|
||||
|
||||
function end_render_() {
|
||||
if [[ ! "$GITHUB_WORKFLOW" ]]; then
|
||||
deactivate # End python virtual env
|
||||
fi
|
||||
end_
|
||||
}
|
||||
|
||||
# Following steps are taken:
|
||||
# - Get and build mesa
|
||||
# - Build gltf_viewer
|
||||
# - Run a test
|
||||
|
||||
start_render_ && \
|
||||
python3 ${RENDERDIFF_TEST_DIR}/src/render.py \
|
||||
--gltf_viewer="$(pwd)/out/cmake-debug/samples/gltf_viewer" \
|
||||
--test=${RENDERDIFF_TEST_DIR}/tests/presubmit.json \
|
||||
--output_dir=${OUTPUT_DIR} \
|
||||
--opengl_lib=${MESA_LIB_DIR} && \
|
||||
end_render_
|
||||
54
test/renderdiff/src/compare.py
Normal file
54
test/renderdiff/src/compare.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import pprint
|
||||
import json
|
||||
|
||||
from utils import execute, ArgParseImpl, important_print
|
||||
from image_diff import same_image
|
||||
from results import RESULT_OK, RESULT_FAILED, RESULT_MISSING
|
||||
|
||||
def _compare_goldens(base_dir, comparison_dir):
|
||||
render_results = {}
|
||||
base_files = glob.glob(os.path.join(base_dir, "./**/*.tif"))
|
||||
for golden_file in base_files:
|
||||
base_fname = os.path.abspath(golden_file)
|
||||
test_case = base_fname.replace(f'{os.path.abspath(base_dir)}/', '')
|
||||
comp_fname = os.path.abspath(os.path.join(comparison_dir, test_case))
|
||||
if not os.path.exists(comp_fname):
|
||||
print(f'file name not found: {comp_fname}')
|
||||
render_results[test_case] = RESULT_MISSING
|
||||
continue
|
||||
if not same_image(base_fname, comp_fname):
|
||||
render_results[test_case] = RESULT_FAILED
|
||||
else:
|
||||
render_results[test_case] = RESULT_OK
|
||||
return render_results
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgParseImpl()
|
||||
parser.add_argument('--src', help='Directory of the base of the diff.', required=True)
|
||||
parser.add_argument('--dest', help='Directory of the comparison of the diff.')
|
||||
parser.add_argument('--out', help='Directory of output for the result of the diff.')
|
||||
|
||||
args, _ = parser.parse_known_args(sys.argv[1:])
|
||||
|
||||
dest = args.dest
|
||||
if not dest:
|
||||
print('Assume the default renderdiff output folder')
|
||||
dest = os.path.join(os.getcwd(), './out/renderdiff_tests')
|
||||
assert os.path.exists(dest), f"Destination folder={dest} does not exist."
|
||||
|
||||
results = _compare_goldens(args.src, dest)
|
||||
|
||||
if args.out:
|
||||
assert os.path.exists(arg.out), f"Output folder={dest} does not exist."
|
||||
with open(os.path.join(args.out, "compare_results.json", 'w')) as f:
|
||||
f.write(json.dumps(results))
|
||||
|
||||
failed = [f" {k}" for k in results.keys() if results[k] != RESULT_OK]
|
||||
success_count = len(results) - len(failed)
|
||||
important_print(f'Successfully compared {success_count} / {len(results)} images' +
|
||||
('\nFailed:\n' + ('\n'.join(failed)) if len(failed) > 0 else ''))
|
||||
if len(failed) > 0:
|
||||
exit(1)
|
||||
@@ -15,6 +15,7 @@
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
import sys
|
||||
|
||||
from utils import execute, ArgParseImpl, mkdir_p
|
||||
|
||||
@@ -132,12 +133,19 @@ class GoldenManager:
|
||||
rdiff_dir = os.path.join(assets_dir, GOLDENS_DIR)
|
||||
shutil.copytree(rdiff_dir, dest_dir, dirs_exist_ok=True)
|
||||
|
||||
# For testing only
|
||||
# The main entry point will enable download content of a branch to a directory
|
||||
if __name__ == "__main__":
|
||||
parser = ArgParseImpl()
|
||||
parser.add_argument('--branch', type=str, help='Branch of the golden repo', default='main')
|
||||
parser.add_argument('--output', type=str, help='Directory to download to', required=True)
|
||||
|
||||
args, _ = parser.parse_known_args(sys.argv[1:])
|
||||
|
||||
# prepare goldens working directory
|
||||
golden_dir = args.output
|
||||
assert os.path.isdir(golden_dir),\
|
||||
f"Output directory {golden_dir} does not exist"
|
||||
|
||||
# Download the golden repo into the current working directory
|
||||
golden_manager = GoldenManager(os.getcwd())
|
||||
# golden_manager.source_from_and_commit(
|
||||
# os.path.join(os.getcwd(), 'out/renderdiff_tests'),
|
||||
# 'First commit (local)',
|
||||
# branch='branch-test')
|
||||
# golden_manager.merge_to_main('branch-test', push_to_remote=True)
|
||||
# golden_manager.download_to(os.path.join(os.getcwd(), 'tmp/goldens'))
|
||||
golden_manager.download_to(golden_dir, branch=args.branch)
|
||||
|
||||
45
test/renderdiff/src/preamble.sh
Normal file
45
test/renderdiff/src/preamble.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright (C) 2025 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#!/usr/bin/bash
|
||||
|
||||
# Sets up the environment for scripts in test/renderdiff/
|
||||
|
||||
OUTPUT_DIR="$(pwd)/out/renderdiff_tests"
|
||||
RENDERDIFF_TEST_DIR="$(pwd)/test/renderdiff"
|
||||
MESA_DIR="$(pwd)/mesa/out/"
|
||||
VENV_DIR="$(pwd)/venv"
|
||||
BUILD_COMMON_DIR="$(pwd)/build/common"
|
||||
|
||||
os_name=$(uname -s)
|
||||
if [[ "$os_name" == "Linux" ]]; then
|
||||
MESA_LIB_DIR="${MESA_DIR}lib/x86_64-linux-gnu"
|
||||
elif [[ "$os_name" == "Darwin" ]]; then
|
||||
MESA_LIB_DIR="${MESA_DIR}lib"
|
||||
else
|
||||
echo "Unsupported platform for renderdiff tests"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function start_() {
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set -ex
|
||||
fi
|
||||
}
|
||||
|
||||
function end_() {
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set +ex
|
||||
fi
|
||||
}
|
||||
@@ -18,31 +18,18 @@ import json
|
||||
import glob
|
||||
import shutil
|
||||
|
||||
from utils import execute, ArgParseImpl, mkdir_p, mv_f
|
||||
from parse_test_json import parse_test_config_from_path
|
||||
from utils import execute, ArgParseImpl, mkdir_p, mv_f, important_print
|
||||
|
||||
import test_config
|
||||
from golden_manager import GoldenManager
|
||||
from image_diff import same_image
|
||||
from results import RESULT_OK, RESULT_FAILED
|
||||
|
||||
def important_print(msg):
|
||||
lines = msg.split('\n')
|
||||
max_len = max([len(l) for l in lines])
|
||||
print('-' * (max_len + 8))
|
||||
for line in lines:
|
||||
diff = max_len - len(line)
|
||||
information = f'--- {line} ' + (' ' * diff) + '---'
|
||||
print(information)
|
||||
print('-' * (max_len + 8))
|
||||
|
||||
RESULT_OK = 'ok'
|
||||
RESULT_FAILED_TO_RENDER = 'failed-to-render'
|
||||
RESULT_FAILED_IMAGE_DIFF = 'failed-image-diff'
|
||||
RESULT_FAILED_NO_GOLDEN = 'failed-no-golden'
|
||||
|
||||
def run_test(gltf_viewer,
|
||||
test_config,
|
||||
output_dir,
|
||||
opengl_lib=None,
|
||||
vk_icd=None):
|
||||
def _render_test_config(gltf_viewer,
|
||||
test_config,
|
||||
output_dir,
|
||||
opengl_lib=None,
|
||||
vk_icd=None):
|
||||
assert os.path.isdir(output_dir), f"output directory {output_dir} does not exist"
|
||||
assert os.access(gltf_viewer, os.X_OK)
|
||||
|
||||
@@ -86,7 +73,7 @@ def run_test(gltf_viewer,
|
||||
mv_f(f'{test.name}0.tif', out_tif_name)
|
||||
mv_f(f'{test.name}0.json', f'{named_output_dir}/{test.name}.json')
|
||||
else:
|
||||
result = RESULT_FAILED_TO_RENDER
|
||||
result = RESULT_FAILED
|
||||
important_print(f'{test_desc} rendering failed with error={out_code}')
|
||||
|
||||
results.append({
|
||||
@@ -96,23 +83,6 @@ def run_test(gltf_viewer,
|
||||
})
|
||||
return named_output_dir, results
|
||||
|
||||
def compare_goldens(render_results, output_dir, goldens):
|
||||
for result in render_results:
|
||||
if result['result'] != RESULT_OK:
|
||||
continue
|
||||
|
||||
out_tif_basename = f"{result['name']}.tif"
|
||||
out_tif_name = f'{output_dir}/{out_tif_basename}'
|
||||
golden_path = goldens.get(out_tif_basename)
|
||||
if not golden_path:
|
||||
result['result'] = RESULT_FAILED_NO_GOLDEN
|
||||
result['result_code'] = 1
|
||||
elif not same_image(golden_path, out_tif_name):
|
||||
result['result'] = RESULT_FAILED_IMAGE_DIFF
|
||||
result['result_code'] = 1
|
||||
|
||||
return render_results
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = ArgParseImpl()
|
||||
parser.add_argument('--test', help='Configuration of the test', required=True)
|
||||
@@ -120,43 +90,26 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--output_dir', help='Output Directory', required=True)
|
||||
parser.add_argument('--opengl_lib', help='Path to the folder containing OpenGL driver lib (for LD_LIBRARY_PATH)')
|
||||
parser.add_argument('--vk_icd', help='Path to VK ICD file')
|
||||
parser.add_argument('--golden_branch', help='Branch of the golden repo to compare against')
|
||||
|
||||
args, _ = parser.parse_known_args(sys.argv[1:])
|
||||
test = parse_test_config_from_path(args.test)
|
||||
test = test_config.parse_from_path(args.test)
|
||||
|
||||
output_dir, results = \
|
||||
run_test(args.gltf_viewer,
|
||||
test,
|
||||
args.output_dir,
|
||||
opengl_lib=args.opengl_lib,
|
||||
vk_icd=args.vk_icd)
|
||||
_render_test_config(args.gltf_viewer,
|
||||
test,
|
||||
args.output_dir,
|
||||
opengl_lib=args.opengl_lib,
|
||||
vk_icd=args.vk_icd)
|
||||
|
||||
do_compare = False
|
||||
# The presence of this argument indicates comparison against a set of goldens.
|
||||
if args.golden_branch:
|
||||
# prepare goldens working directory
|
||||
tmp_golden_dir = '/tmp/renderdiff-goldens'
|
||||
mkdir_p(tmp_golden_dir)
|
||||
|
||||
# Download the golden repo into the current working directory
|
||||
golden_manager = GoldenManager(os.getcwd())
|
||||
golden_manager.download_to(tmp_golden_dir, branch=args.golden_branch)
|
||||
|
||||
goldens = {
|
||||
os.path.basename(fpath) : fpath for fpath in \
|
||||
glob.glob(f'{os.path.join(tmp_golden_dir, test.name)}/**/*.tif', recursive=True)
|
||||
}
|
||||
results = compare_goldens(results, output_dir, goldens)
|
||||
do_compare = True
|
||||
|
||||
with open(f'{output_dir}/results.json', 'w') as f:
|
||||
with open(f'{output_dir}/render_results.json', 'w') as f:
|
||||
f.write(json.dumps(results))
|
||||
|
||||
shutil.copy2(args.test, f'{output_dir}/test.json')
|
||||
|
||||
failed = [f" {k['name']}" for k in results if k['result'] != RESULT_OK]
|
||||
success_count = len(results) - len(failed)
|
||||
op = 'tested' if do_compare else 'rendered'
|
||||
important_print(f'Successfully {op} {success_count} / {len(results)}' +
|
||||
('\nFailed:\n' + ('\n'.join(failed)) if len(failed) > 0 else ''))
|
||||
important_print(f'Successfully rendered {success_count} / {len(results)} tests' +
|
||||
('\nFailed:\n' + ('\n'.join(failed)) if len(failed) > 0 else ''))
|
||||
|
||||
if len(failed) > 0:
|
||||
exit(1)
|
||||
3
test/renderdiff/src/results.py
Normal file
3
test/renderdiff/src/results.py
Normal file
@@ -0,0 +1,3 @@
|
||||
RESULT_OK = 'ok'
|
||||
RESULT_FAILED = 'failed'
|
||||
RESULT_MISSING = 'missing'
|
||||
@@ -129,7 +129,7 @@ def _remove_comments_from_json_txt(json_txt):
|
||||
res.append(line)
|
||||
return '\n'.join(res)
|
||||
|
||||
def parse_test_config_from_path(config_path):
|
||||
def parse_from_path(config_path):
|
||||
with open(config_path, 'r') as f:
|
||||
json_txt = json.loads(_remove_comments_from_json_txt(f.read()))
|
||||
return RenderTestConfig(json_txt)
|
||||
@@ -90,7 +90,7 @@ def _interactive_mode(base_golden_dir):
|
||||
if prompt_helper(
|
||||
f'Generate the new goldens from your local ' \
|
||||
f'Filament branch? (branch={cur_branch})') == PROMPT_YES:
|
||||
code, res = execute('bash ./test/renderdiff/test.sh generate',
|
||||
code, res = execute('bash ./test/renderdiff/generate.sh',
|
||||
capture_output=False)
|
||||
if code != 0:
|
||||
print('Failed to generate new goldens')
|
||||
|
||||
@@ -106,3 +106,13 @@ def mkdir_p(path_str):
|
||||
def mv_f(src_str, dst_str):
|
||||
src = pathlib.Path(src_str)
|
||||
src.replace(dst_str)
|
||||
|
||||
def important_print(msg):
|
||||
lines = msg.split('\n')
|
||||
max_len = max([len(l) for l in lines])
|
||||
print('-' * (max_len + 8))
|
||||
for line in lines:
|
||||
diff = max_len - len(line)
|
||||
information = f'--- {line} ' + (' ' * diff) + '---'
|
||||
print(information)
|
||||
print('-' * (max_len + 8))
|
||||
|
||||
@@ -14,71 +14,15 @@
|
||||
|
||||
#!/usr/bin/bash
|
||||
|
||||
OUTPUT_DIR="$(pwd)/out/renderdiff_tests"
|
||||
RENDERDIFF_TEST_DIR="$(pwd)/test/renderdiff"
|
||||
TEST_UTILS_DIR="$(pwd)/test/utils"
|
||||
MESA_DIR="$(pwd)/mesa/out/"
|
||||
VENV_DIR="$(pwd)/venv"
|
||||
source `dirname $0`/src/preamble.sh
|
||||
|
||||
os_name=$(uname -s)
|
||||
if [[ "$os_name" == "Linux" ]]; then
|
||||
MESA_LIB_DIR="${MESA_DIR}lib/x86_64-linux-gnu"
|
||||
elif [[ "$os_name" == "Darwin" ]]; then
|
||||
MESA_LIB_DIR="${MESA_DIR}lib"
|
||||
else
|
||||
echo "Unsupported platform for renderdiff tests"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function start_() {
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set -ex
|
||||
else
|
||||
if [ ! -d ${MESA_LIB_DIR} ]; then
|
||||
bash ${TEST_UTILS_DIR}/get_mesa.sh
|
||||
fi
|
||||
|
||||
# Install python deps
|
||||
python3 -m venv ${VENV_DIR}
|
||||
source ${VENV_DIR}/bin/activate
|
||||
|
||||
NEEDED_PYTHON_DEPS=("numpy" "tifffile")
|
||||
for cmd in "${NEEDED_PYTHON_DEPS[@]}"; do
|
||||
if ! python3 -m pip show -q "${cmd}"; then
|
||||
python3 -m pip install ${cmd}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function end_() {
|
||||
if [[ "$GITHUB_WORKFLOW" ]]; then
|
||||
set +ex
|
||||
else
|
||||
deactivate # End python virtual env
|
||||
fi
|
||||
}
|
||||
|
||||
# Following steps are taken:
|
||||
# - Get and build mesa
|
||||
# - Build gltf_viewer
|
||||
# - Run the python script that runs the test
|
||||
# - Zip up the result
|
||||
|
||||
GOLDEN_BRANCH_PARAM='--golden_branch=main'
|
||||
|
||||
if [ "$1" == "generate" ]; then
|
||||
GOLDEN_BRANCH_PARAM=''
|
||||
fi
|
||||
GOLDEN_DIR=$(pwd)/golden_images
|
||||
|
||||
start_ && \
|
||||
mkdir -p ${OUTPUT_DIR} && \
|
||||
CXX=`which clang++` CC=`which clang` ./build.sh -f -X ${MESA_DIR} -p desktop debug gltf_viewer && \
|
||||
python3 ${RENDERDIFF_TEST_DIR}/src/run.py \
|
||||
--gltf_viewer="$(pwd)/out/cmake-debug/samples/gltf_viewer" \
|
||||
--test=${RENDERDIFF_TEST_DIR}/tests/presubmit.json \
|
||||
--output_dir=${OUTPUT_DIR} \
|
||||
--opengl_lib=${MESA_LIB_DIR} \
|
||||
${GOLDEN_BRANCH_PARAM} && \
|
||||
bash `dirname $0`/generate.sh && \
|
||||
mkdir -p ${GOLDEN_DIR} && \
|
||||
python3 ${RENDERDIFF_TEST_DIR}/src/golden_manager.py --output=${GOLDEN_DIR} && \
|
||||
python3 ${RENDERDIFF_TEST_DIR}/src/compare.py \
|
||||
--src=${GOLDEN_DIR} \
|
||||
--dest=${OUTPUT_DIR} && \
|
||||
end_
|
||||
|
||||
@@ -229,10 +229,10 @@ MaybeError ValidateWriteBuffer(const DeviceBase* device,
|
||||
uint64_t size) {
|
||||
DAWN_TRY(device->ValidateObject(buffer));
|
||||
|
||||
// DAWN_INVALID_IF(bufferOffset % 4 != 0, "BufferOffset (%u) is not a multiple of 4.",
|
||||
// bufferOffset);
|
||||
//
|
||||
// DAWN_INVALID_IF(size % 4 != 0, "Size (%u) is not a multiple of 4.", size);
|
||||
DAWN_INVALID_IF(bufferOffset % 4 != 0, "BufferOffset (%u) is not a multiple of 4.",
|
||||
bufferOffset);
|
||||
|
||||
DAWN_INVALID_IF(size % 4 != 0, "Size (%u) is not a multiple of 4.", size);
|
||||
|
||||
uint64_t bufferSize = buffer->GetSize();
|
||||
DAWN_INVALID_IF(bufferOffset > bufferSize || size > (bufferSize - bufferOffset),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user