Compare commits

..
Author SHA1 Message Date
Powei Feng ce4199b5f7 Testing rendering to quad 2024-08-27 13:47:43 -07:00
Mathias Agopian 1c2ffc9ed4 new screenshot debug option in gltf_viewer
screenshots are saved in the current directory as 
"screenshotXX.ppm" with XX increasing after each
screenshot.
2024-08-20 22:41:49 -07:00
Sungun Park 574518ea74 Cleanup color pass for multiview (#8062) 2024-08-20 21:44:17 +00:00
Ben Doherty d5a274fa25 Add better glShaderSource fix for IMG devices (#8061) 2024-08-20 12:28:13 -07:00
Mathias Agopian 3351db1178 improve FrameSkipper when disregarding skipping
It is legal for the app to draw a frame even when FrameSkipper 
detects that a frame should be skipped. In that case we used to
overwrite the most recent fence, but this wasn't ideal. We now
proceed as if the fence had signaled, i.e. we destroy it and
move all the fences up, creating a new one at the end of the 
delayed array.
2024-08-20 12:07:59 -07:00
Mathias Agopian b70aa43727 depth clamp cannot work with VSM
This is because the shadowmap doesn't store depth values so it doesn't 
work to "flatten" all casters behind de camera to the near plane.
The bulk of shadowing works but the filtering/edges don't always.

Disable depth-clamping when VSM is enabled.
2024-08-20 12:04:01 -07:00
Sungun Park 1f9a11802d Minor tweak (#8053)
Move the common part outside the loop.
2024-08-20 17:13:55 +00:00
Sungun Park 89835a7a67 Fix a bug for calculating distance (#8058)
This is a missing part from the change
22d99bac3d
2024-08-20 16:28:29 +00:00
68 changed files with 480 additions and 625 deletions
-2
View File
@@ -7,5 +7,3 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Add a `name` API to Filament objects for debugging handle use-after-free assertions
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.54.1'
implementation 'com.google.android.filament:filament-android:1.54.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.54.1'
pod 'Filament', '~> 1.54.0'
```
### Snapshots
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.54.1
VERSION_NAME=1.54.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
-1
View File
@@ -61,7 +61,6 @@ set(SRCS
src/Engine.cpp
src/Exposure.cpp
src/Fence.cpp
src/FilamentBuilder.cpp
src/FrameInfo.cpp
src/FrameSkipper.cpp
src/Froxelizer.cpp
@@ -1058,7 +1058,7 @@ struct RasterState {
bool inverseFrontFaces : 1; // 31
//! padding, must be 0
uint8_t padding : 1; // 32
bool depthClamp : 1; // 32
};
uint32_t u = 0;
};
@@ -162,10 +162,6 @@ DECL_DRIVER_API_0(finish)
// reset state tracking, if the driver does any state tracking (e.g. GL)
DECL_DRIVER_API_0(resetState)
DECL_DRIVER_API_N(setDebugTag,
backend::HandleBase::HandleId, handleId,
utils::CString, tag)
/*
* Creating driver objects
* -----------------------
@@ -309,6 +305,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported)
DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers)
DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize)
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
@@ -20,12 +20,11 @@
#include <backend/Handle.h>
#include <utils/Allocator.h>
#include <utils/CString.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <utils/Panic.h>
#include <tsl/robin_map.h>
@@ -174,10 +173,8 @@ public:
uint8_t const age = (tag & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
auto const pNode = static_cast<typename Allocator::Node*>(p);
uint8_t const expectedAge = pNode[-1].age;
// getHandleTag() is only called if the check fails.
FILAMENT_CHECK_POSTCONDITION(expectedAge == age)
<< "use-after-free of Handle with id=" << handle.getId()
<< ", tag=" << getHandleTag(handle.getId()).c_str_safe();
FILAMENT_CHECK_POSTCONDITION(expectedAge == age) <<
"use-after-free of Handle with id=" << handle.getId();
}
}
@@ -204,34 +201,6 @@ public:
return handle_cast<Dp>(const_cast<Handle<B>&>(handle));
}
void associateTagToHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
// TODO: for now, only pool handles check for use-after-free, so we only keep tags for
// those
if (isPoolHandle(id)) {
// Truncate the tag's age to N bits.
constexpr uint8_t N = 2; // support a history of 4 tags
constexpr uint8_t mask = (1 << N) - 1;
uint8_t const age = (id & HANDLE_AGE_MASK) >> HANDLE_AGE_SHIFT;
uint8_t const newAge = age & mask;
uint32_t const key = (id & ~HANDLE_AGE_MASK) | (newAge << HANDLE_AGE_SHIFT);
// This line is the costly part. In the future, we could potentially use a custom
// allocator.
mDebugTags[key] = std::move(tag);
}
}
utils::CString getHandleTag(HandleBase::HandleId id) const noexcept {
if (!isPoolHandle(id)) {
return "(no tag)";
}
if (auto pos = mDebugTags.find(id); pos != mDebugTags.end()) {
return pos->second;
}
return "(no tag)";
}
private:
template<typename D>
@@ -394,7 +363,6 @@ private:
// Below is only used when running out of space in the HandleArena
mutable utils::Mutex mLock;
tsl::robin_map<HandleBase::HandleId, void*> mOverflowMap;
tsl::robin_map<HandleBase::HandleId, utils::CString> mDebugTags;
HandleBase::HandleId mId = 0;
bool mUseAfterFreeCheckDisabled = false;
};
-3
View File
@@ -80,9 +80,6 @@ HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size,
bool disableUseAfterFreeCheck) noexcept
: mHandleArena(name, size, disableUseAfterFreeCheck),
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) {
// Reserve initial space for debug tags. This prevents excessive calls to malloc when the first
// few tags are set.
mDebugTags.reserve(512);
}
template <size_t P0, size_t P1, size_t P2>
@@ -112,6 +112,7 @@ struct MetalContext {
std::array<BufferState, MAX_SSBO_COUNT> ssboState;
CullModeStateTracker cullModeState;
WindingStateTracker windingState;
DepthClampStateTracker depthClampState;
Handle<HwRenderPrimitive> currentRenderPrimitive;
// State caches.
+11 -4
View File
@@ -834,6 +834,10 @@ bool MetalDriver::isProtectedTexturesSupported() {
return false;
}
bool MetalDriver::isDepthClampSupported() {
return true;
}
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -1751,6 +1755,13 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
[mContext->currentRenderPassEncoder setFrontFacingWinding:winding];
}
// depth clip mode
MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
mContext->depthClampState.updateState(depthClipMode);
if (mContext->depthClampState.stateChanged()) {
[mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode];
}
// Set the depth-stencil state, if a state change is needed.
DepthStencilState depthState;
if (depthAttachment) {
@@ -2061,10 +2072,6 @@ void MetalDriver::enumerateBoundBuffers(BufferObjectBinding bindingType,
void MetalDriver::resetState(int) {
}
void MetalDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
void MetalDriver::runAtNextTick(const std::function<void()>& fn) noexcept {
std::lock_guard<std::mutex> const lock(mTickOpsLock);
mTickOps.push_back(fn);
+1
View File
@@ -382,6 +382,7 @@ using SamplerStateCache = StateCache<SamplerState, id<MTLSamplerState>, SamplerS
using CullModeStateTracker = StateTracker<MTLCullMode>;
using WindingStateTracker = StateTracker<MTLWinding>;
using DepthClampStateTracker = StateTracker<MTLDepthClipMode>;
// Argument encoder
+4 -3
View File
@@ -202,6 +202,10 @@ bool NoopDriver::isProtectedTexturesSupported() {
return true;
}
bool NoopDriver::isDepthClampSupported() {
return false;
}
bool NoopDriver::isWorkaroundNeeded(Workaround) {
return false;
}
@@ -388,7 +392,4 @@ void NoopDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
void NoopDriver::resetState(int) {
}
void NoopDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
}
} // namespace filament
@@ -541,9 +541,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
bugs->delay_fbo_destruction = true;
// PowerVR seems to have no problem with this (which is good for us)
bugs->allow_read_only_ancillary_feedback_loop = true;
// PowerVR doesn't respect lengths passed to glShaderSource, so concatenate them into a
// single string.
bugs->concatenate_shader_strings = true;
} else if (strstr(renderer, "Apple")) {
// Apple GPU
} else if (strstr(renderer, "Tegra") ||
@@ -679,6 +676,7 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor
#ifndef __EMSCRIPTEN__
ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
#endif
ext->EXT_depth_clamp = exts.has("GL_EXT_depth_clamp"sv);
ext->EXT_discard_framebuffer = exts.has("GL_EXT_discard_framebuffer"sv);
#ifndef __EMSCRIPTEN__
ext->EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv);
@@ -749,6 +747,7 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor)
ext->EXT_color_buffer_half_float = true; // Assumes core profile.
ext->EXT_clip_cull_distance = true;
ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
ext->EXT_depth_clamp = true;
ext->EXT_discard_framebuffer = false;
ext->EXT_disjoint_timer_query = true;
ext->EXT_multisampled_render_to_texture = false;
+6 -13
View File
@@ -220,8 +220,9 @@ public:
bool EXT_color_buffer_float;
bool EXT_color_buffer_half_float;
bool EXT_debug_marker;
bool EXT_disjoint_timer_query;
bool EXT_depth_clamp;
bool EXT_discard_framebuffer;
bool EXT_disjoint_timer_query;
bool EXT_multisampled_render_to_texture2;
bool EXT_multisampled_render_to_texture;
bool EXT_protected_textures;
@@ -239,10 +240,10 @@ public:
bool KHR_parallel_shader_compile;
bool KHR_texture_compression_astc_hdr;
bool KHR_texture_compression_astc_ldr;
bool OES_depth_texture;
bool OES_depth24;
bool OES_packed_depth_stencil;
bool OES_EGL_image_external_essl3;
bool OES_depth24;
bool OES_depth_texture;
bool OES_packed_depth_stencil;
bool OES_rgb8_rgba8;
bool OES_standard_derivatives;
bool OES_texture_npot;
@@ -315,12 +316,6 @@ public:
// bugs or performance issues.
bool force_feature_level0;
// Some drivers don't respect the length argument of glShaderSource() and (apparently)
// require each shader source string to be null-terminated. This works around the issue by
// concatenating the strings into a single null-terminated string before passing it to
// glShaderSource().
bool concatenate_shader_strings;
} bugs = {};
// state getters -- as needed.
@@ -567,9 +562,6 @@ private:
{ bugs.force_feature_level0,
"force_feature_level0",
""},
{ bugs.concatenate_shader_strings,
"concatenate_shader_strings",
""},
}};
// this is chosen to minimize code size
@@ -636,6 +628,7 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT
#ifdef BACKEND_OPENGL_VERSION_GL
case GL_PROGRAM_POINT_SIZE: index = 10; break;
#endif
case GL_DEPTH_CLAMP: index = 11; break;
default: break;
}
assert_invariant(index < state.enables.caps.size());
+12 -4
View File
@@ -451,6 +451,14 @@ void OpenGLDriver::setRasterState(RasterState rs) noexcept {
} else {
gl.disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
}
if (gl.ext.EXT_depth_clamp) {
if (rs.depthClamp) {
gl.enable(GL_DEPTH_CLAMP);
} else {
gl.disable(GL_DEPTH_CLAMP);
}
}
}
void OpenGLDriver::setStencilState(StencilState ss) noexcept {
@@ -2119,6 +2127,10 @@ bool OpenGLDriver::isProtectedTexturesSupported() {
return getContext().ext.EXT_protected_textures;
}
bool OpenGLDriver::isDepthClampSupported() {
return getContext().ext.EXT_depth_clamp;
}
bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU:
@@ -2210,10 +2222,6 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
}
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
uint32_t index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
@@ -597,40 +597,30 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
version = "#version 310 es\n";
}
const std::array<const char*, 5> sources = {
version.data(),
prolog.data(),
specializationConstantString.c_str(),
packingFunctions.data(),
body.data()
std::array<std::string_view, 5> sources = {
version,
prolog,
specializationConstantString,
packingFunctions,
{ body.data(), body.size() - 1 } // null-terminated
};
const std::array<GLint, 5> lengths = {
(GLint)version.length(),
(GLint)prolog.length(),
(GLint)specializationConstantString.length(),
(GLint)packingFunctions.length(),
(GLint)body.length() - 1 // null terminated
};
// Some of the sources may be zero-length. Remove them as to avoid passing lengths of
// zero to glShaderSource(). glShaderSource should work with lengths of zero, but some
// drivers instead interpret zero as a sentinel for a null-terminated string.
auto partitionPoint = std::stable_partition(
sources.begin(), sources.end(), [](std::string_view s) { return !s.empty(); });
size_t count = std::distance(sources.begin(), partitionPoint);
std::array<const char*, 5> shaderStrings;
std::array<GLint, 5> lengths;
for (size_t i = 0; i < count; i++) {
shaderStrings[i] = sources[i].data();
lengths[i] = sources[i].size();
}
GLuint const shaderId = glCreateShader(glShaderType);
if (UTILS_UNLIKELY(context.bugs.concatenate_shader_strings)) {
size_t totalSize = 0;
for (size_t i = 0; i < sources.size(); i++) {
totalSize += lengths[i];
}
std::string concatenatedShaderSource;
concatenatedShaderSource.reserve(totalSize);
for (size_t i = 0; i < sources.size(); i++) {
concatenatedShaderSource.append(sources[i], lengths[i]);
}
const GLchar* ptr = concatenatedShaderSource.c_str();
GLint length = concatenatedShaderSource.length();
glShaderSource(shaderId, 1, &ptr, &length);
} else {
glShaderSource(shaderId, sources.size(), sources.data(), lengths.data());
}
glShaderSource(shaderId, count, shaderStrings.data(), lengths.data());
glCompileShader(shaderId);
+6
View File
@@ -201,6 +201,12 @@ using namespace glext;
# define GL_CLIP_DISTANCE1 0x3001
#endif
#if defined(GL_EXT_depth_clamp)
# define GL_DEPTH_CLAMP GL_DEPTH_CLAMP_EXT
#else
# define GL_DEPTH_CLAMP 0x864F
#endif
#if defined(GL_KHR_debug)
# define GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_KHR
# define GL_DEBUG_OUTPUT_SYNCHRONOUS GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR
@@ -125,6 +125,10 @@ public:
return mPhysicalDeviceFeatures.imageCubeArray == VK_TRUE;
}
inline bool isDepthClampSupported() const noexcept {
return mPhysicalDeviceFeatures.depthClamp == VK_TRUE;
}
inline bool isDebugMarkersSupported() const noexcept {
return mDebugMarkersSupported;
}
+6 -4
View File
@@ -944,6 +944,10 @@ bool VulkanDriver::isProtectedTexturesSupported() {
return false;
}
bool VulkanDriver::isDepthClampSupported() {
return mContext.isDepthClampSupported();
}
bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) {
switch (workaround) {
case Workaround::SPLIT_EASU: {
@@ -1816,6 +1820,8 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) {
.dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha),
.colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0),
.rasterizationSamples = rt->getSamples(),
.depthClamp = rasterState.depthClamp,
.reserved = 0,
.colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass),
.colorBlendOp = rasterState.blendEquationRGB,
.alphaBlendOp = rasterState.blendEquationAlpha,
@@ -2032,10 +2038,6 @@ void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, cons
void VulkanDriver::resetState(int) {
}
void VulkanDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
mResourceAllocator.associateHandle(handleId, std::move(tag));
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<VulkanDriver>;
@@ -184,6 +184,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n
vkRaster.polygonMode = VK_POLYGON_MODE_FILL;
vkRaster.cullMode = raster.cullMode;
vkRaster.frontFace = raster.frontFace;
vkRaster.depthClampEnable = raster.depthClamp;
vkRaster.depthBiasEnable = raster.depthBiasEnable;
vkRaster.depthBiasConstantFactor = raster.depthBiasConstantFactor;
vkRaster.depthBiasClamp = 0.0f;
@@ -90,7 +90,9 @@ public:
VkBlendFactor srcAlphaBlendFactor : 5;
VkBlendFactor dstAlphaBlendFactor : 5;
VkColorComponentFlags colorWriteMask : 4;
uint8_t rasterizationSamples; // offset = 4 bytes
uint8_t rasterizationSamples : 4;// offset = 4 bytes
uint8_t depthClamp : 1;
uint8_t reserved : 3;
uint8_t colorTargetCount; // offset = 5 bytes
BlendEquation colorBlendOp : 4; // offset = 6 bytes
BlendEquation alphaBlendOp : 4;
@@ -105,10 +105,6 @@ public:
mHandleAllocatorImpl.deallocate(handle, obj);
}
inline void associateHandle(HandleBase::HandleId id, utils::CString&& tag) noexcept {
mHandleAllocatorImpl.associateTagToHandle(id, std::move(tag));
}
private:
AllocatorImpl mHandleAllocatorImpl;
@@ -325,6 +325,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
// We could simply enable all supported features, but since that may have performance
// consequences let's just enable the features we need.
VkPhysicalDeviceFeatures enabledFeatures{
.depthClamp = features.depthClamp,
.samplerAnisotropy = features.samplerAnisotropy,
.textureCompressionETC2 = features.textureCompressionETC2,
.textureCompressionBC = features.textureCompressionBC,
+1 -16
View File
@@ -54,7 +54,7 @@ public:
using BufferDescriptor = backend::BufferDescriptor;
using BindingType = backend::BufferObjectBinding;
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -78,21 +78,6 @@ public:
*/
Builder& bindingType(BindingType bindingType) noexcept;
/**
* Associate an optional name with this BufferObject for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this BufferObject
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the BufferObject and returns a pointer to it. After creation, the buffer
* object is uninitialized. Use BufferObject::setBuffer() to initialize it.
-17
View File
@@ -19,7 +19,6 @@
#include <utils/compiler.h>
#include <utils/PrivateImplementation.h>
#include <utils/CString.h>
#include <stddef.h>
@@ -55,22 +54,6 @@ public:
template<typename T>
using BuilderBase = utils::PrivateImplementation<T>;
void builderMakeName(utils::CString& outName, const char* name, size_t len) noexcept;
template <typename Builder>
class UTILS_PUBLIC BuilderNameMixin {
public:
Builder& name(const char* name, size_t len) noexcept {
builderMakeName(mName, name, len);
return static_cast<Builder&>(*this);
}
utils::CString const& getName() const noexcept { return mName; }
private:
utils::CString mName;
};
} // namespace filament
#endif // TNT_FILAMENT_FILAMENTAPI_H
+1 -16
View File
@@ -59,7 +59,7 @@ public:
UINT = uint8_t(backend::ElementType::UINT), //!< 32-bit indices
};
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -83,21 +83,6 @@ public:
*/
Builder& bufferType(IndexType indexType) noexcept;
/**
* Associate an optional name with this IndexBuffer for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this IndexBuffer
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the IndexBuffer object and returns a pointer to it. After creation, the index
* buffer is uninitialized. Use IndexBuffer::setBuffer() to initialize the IndexBuffer.
+1 -16
View File
@@ -38,7 +38,7 @@ class UTILS_PUBLIC InstanceBuffer : public FilamentAPI {
struct BuilderDetails;
public:
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
@@ -70,21 +70,6 @@ public:
*/
Builder& localTransforms(math::mat4f const* UTILS_NULLABLE localTransforms) noexcept;
/**
* Associate an optional name with this InstanceBuffer for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this InstanceBuffer
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the InstanceBuffer object and returns a pointer to it.
*/
+1 -16
View File
@@ -39,7 +39,7 @@ class UTILS_PUBLIC MorphTargetBuffer : public FilamentAPI {
struct BuilderDetails;
public:
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -63,21 +63,6 @@ public:
*/
Builder& count(size_t count) noexcept;
/**
* Associate an optional name with this MorphTargetBuffer for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this MorphTargetBuffer
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the MorphTargetBuffer object and returns a pointer to it.
*
+1 -16
View File
@@ -39,7 +39,7 @@ class UTILS_PUBLIC SkinningBuffer : public FilamentAPI {
struct BuilderDetails;
public:
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -69,21 +69,6 @@ public:
*/
Builder& initialize(bool initialize = true) noexcept;
/**
* Associate an optional name with this SkinningBuffer for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this SkinningBuffer
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the SkinningBuffer object and returns a pointer to it.
*
+1 -16
View File
@@ -94,7 +94,7 @@ public:
*
* To create a NATIVE stream, call the <pre>stream</pre> method on the builder.
*/
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -136,21 +136,6 @@ public:
*/
Builder& height(uint32_t height) noexcept;
/**
* Associate an optional name with this Stream for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this Stream
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the Stream object and returns a pointer to it.
*
+1 -16
View File
@@ -112,7 +112,7 @@ public:
//! Use Builder to construct a Texture object instance
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -202,21 +202,6 @@ public:
*/
Builder& swizzle(Swizzle r, Swizzle g, Swizzle b, Swizzle a) noexcept;
/**
* Associate an optional name with this Texture for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this Texture
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the Texture object and returns a pointer to it.
*
+1 -16
View File
@@ -61,7 +61,7 @@ public:
using AttributeType = backend::ElementType;
using BufferDescriptor = backend::BufferDescriptor;
class Builder : public BuilderBase<BuilderDetails>, public BuilderNameMixin<Builder> {
class Builder : public BuilderBase<BuilderDetails> {
friend struct BuilderDetails;
public:
Builder() noexcept;
@@ -158,21 +158,6 @@ public:
*/
Builder& advancedSkinning(bool enabled) noexcept;
/**
* Associate an optional name with this VertexBuffer for debugging purposes.
*
* name will show in error messages and should be kept as short as possible. The name is
* truncated to a maximum of 128 characters.
*
* The name string is copied during this method so clients may free its memory after
* the function returns.
*
* @param name A string to identify this VertexBuffer
* @param len Length of name, should be less than or equal to 128
* @return This Builder, for chaining calls.
*/
// Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; // inherited
/**
* Creates the VertexBuffer object and returns a pointer to it.
*
-31
View File
@@ -1,31 +0,0 @@
/*
* Copyright (C) 2024 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 <filament/FilamentAPI.h>
#include <algorithm>
namespace filament {
void builderMakeName(utils::CString& outName, const char* name, size_t len) noexcept {
if (!name) {
return;
}
size_t const length = std::min(len, size_t { 128u });
outName = utils::CString(name, length);
}
} // namespace filament
+25 -18
View File
@@ -16,16 +16,22 @@
#include "FrameSkipper.h"
#include <utils/Log.h>
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <algorithm>
#include <stddef.h>
namespace filament {
using namespace utils;
using namespace backend;
FrameSkipper::FrameSkipper(size_t latency) noexcept
: mLast(latency - 1) {
: mLast(std::max(latency, MAX_FRAME_LATENCY) - 1) {
assert_invariant(latency <= MAX_FRAME_LATENCY);
}
@@ -41,31 +47,32 @@ void FrameSkipper::terminate(DriverApi& driver) noexcept {
bool FrameSkipper::beginFrame(DriverApi& driver) noexcept {
auto& fences = mDelayedFences;
auto fence = fences.front();
if (fence) {
auto status = driver.getFenceStatus(fence);
if (status == FenceStatus::TIMEOUT_EXPIRED) {
// Sync not ready, skip frame
if (fences.front()) {
// Do we have a latency old fence?
auto status = driver.getFenceStatus(fences.front());
if (UTILS_UNLIKELY(status == FenceStatus::TIMEOUT_EXPIRED)) {
// The fence hasn't signaled yet, skip this frame
return false;
}
assert_invariant(status == FenceStatus::CONDITION_SATISFIED);
driver.destroyFence(fence);
}
// shift all fences down by 1
std::move(fences.begin() + 1, fences.end(), fences.begin());
fences.back() = {};
return true;
}
void FrameSkipper::endFrame(DriverApi& driver) noexcept {
// If the user produced a new frame despite the fact that the previous one wasn't finished
// (i.e. FrameSkipper::beginFrame() returned false), we need to make sure to replace
// a fence that might be here already)
auto& fence = mDelayedFences[mLast];
if (fence) {
driver.destroyFence(fence);
auto& fences = mDelayedFences;
size_t const last = mLast;
// pop the oldest fence and advance the other ones
if (fences.front()) {
driver.destroyFence(fences.front());
}
fence = driver.createFence();
std::move(fences.begin() + 1, fences.end(), fences.begin());
// add a new fence to the end
assert_invariant(!fences[last]);
fences[last] = driver.createFence();
}
} // namespace filament
+4 -1
View File
@@ -22,6 +22,9 @@
#include <array>
#include <stddef.h>
#include <stdint.h>
namespace filament {
/*
@@ -60,7 +63,7 @@ public:
private:
using Container = std::array<backend::Handle<backend::HwFence>, MAX_FRAME_LATENCY>;
mutable Container mDelayedFences{};
size_t mLast;
uint8_t const mLast;
};
} // namespace filament
+4
View File
@@ -34,6 +34,8 @@
#include <math/mat4.h>
#include <utils/Log.h>
namespace filament {
using namespace backend;
@@ -120,6 +122,8 @@ void PerViewUniforms::prepareViewport(
s.resolution = { physical.zw, 1.0f / physical.zw };
s.logicalViewportScale = physical.zw / logical.zw;
s.logicalViewportOffset = -logical.xy / logical.zw;
utils::slog.e << "resolution=" << s.resolution << " logical=" <<
s.logicalViewportScale << " " << s.logicalViewportOffset << utils::io::endl;
}
void PerViewUniforms::prepareTime(FEngine& engine, math::float4 const& userTime) noexcept {
+23 -6
View File
@@ -2455,18 +2455,24 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
const float temporalNoise = mUniformDistribution(mEngine.getRandomEngine());
auto yy = float4{
(float)vp.left / input.width,
(float)vp.bottom / input.height,
(float)vp.width / input.width,
(float)vp.height / input.height
};
mi->setParameter("dithering", colorGradingConfig.dithering);
mi->setParameter("bloom", bloomParameters);
mi->setParameter("vignette", vignetteParameters);
mi->setParameter("vignetteColor", vignetteOptions.color);
mi->setParameter("fxaa", colorGradingConfig.fxaa);
mi->setParameter("temporalNoise", temporalNoise);
mi->setParameter("viewport", float4{
(float)vp.left / input.width,
(float)vp.bottom / input.height,
(float)vp.width / input.width,
(float)vp.height / input.height
});
mi->setParameter("viewport", yy);
utils::slog.e <<"yy------------yy in=" <<
input.width << "x" << input.height << " viewport=" << yy << utils::io::endl;
const uint8_t variant = uint8_t(colorGradingConfig.translucent ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
@@ -2508,6 +2514,17 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
auto xx = float4{
(float)vp.left / inDesc.width,
(float)vp.bottom / inDesc.height,
(float)vp.width / inDesc.width,
(float)vp.height / inDesc.height
};
utils::slog.e <<"xx-----------xx" <<
"in=" << inDesc.width <<"x" << inDesc.height << " vp=" << vp << " viewport=" << xx << utils::io::endl;
mi->setParameter("viewport", float4{
(float)vp.left / inDesc.width,
(float)vp.bottom / inDesc.height,
+10 -3
View File
@@ -419,7 +419,8 @@ RenderPass::Command* RenderPass::instanceify(FEngine& engine,
UTILS_ALWAYS_INLINE // This function exists only to make the code more readable. we want it inlined.
inline // and we don't need it in the compilation unit
void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant,
FMaterialInstance const* const UTILS_RESTRICT mi, bool inverseFrontFaces) noexcept {
FMaterialInstance const* const UTILS_RESTRICT mi,
bool inverseFrontFaces, bool hasDepthClamp) noexcept {
FMaterial const * const UTILS_RESTRICT ma = mi->getMaterial();
variant = Variant::filterVariant(variant, ma->isVariantLit());
@@ -460,6 +461,7 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant,
cmdDraw.info.rasterState.colorWrite = mi->isColorWriteEnabled();
cmdDraw.info.rasterState.depthWrite = mi->isDepthWriteEnabled();
cmdDraw.info.rasterState.depthFunc = mi->getDepthFunc();
cmdDraw.info.rasterState.depthClamp = hasDepthClamp;
cmdDraw.info.materialVariant = variant;
// we keep "RasterState::colorWrite" to the value set by material (could be disabled)
}
@@ -558,6 +560,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
bool const hasInstancedStereo =
renderFlags & IS_INSTANCED_STEREOSCOPIC;
bool const hasDepthClamp =
renderFlags & HAS_DEPTH_CLAMP;
float const cameraPositionDotCameraForward = dot(cameraPosition, cameraForward);
auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data<FScene::WORLD_AABB_CENTER>();
@@ -577,6 +582,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
cmd.info.rasterState.depthWrite = true;
cmd.info.rasterState.depthFunc = RasterState::DepthFunc::GE;
cmd.info.rasterState.alphaToCoverage = false;
cmd.info.rasterState.depthClamp = hasDepthClamp;
}
for (uint32_t i = range.first; i < range.last; ++i) {
@@ -610,7 +616,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
// Here, objects close to the camera (but behind) will be drawn first.
// An alternative that keeps the mathematical ordering is given here:
// distanceBits ^= ((int32_t(distanceBits) >> 31) | 0x80000000u);
float const distance = -dot(soaWorldAABBCenter[i], cameraForward) - cameraPositionDotCameraForward;
float const distance = -(dot(soaWorldAABBCenter[i], cameraForward) - cameraPositionDotCameraForward);
uint32_t const distanceBits = reinterpret_cast<uint32_t const&>(distance);
// calculate the per-primitive face winding order inversion
@@ -691,7 +697,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
cmd.info.morphingOffset = primitive.getMorphingBufferOffset();
if constexpr (isColorPass) {
RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces);
RenderPass::setupColorCommand(cmd, renderableVariant, mi,
inverseFrontFaces, hasDepthClamp);
const bool blendPass = Pass(cmd.key & PASS_MASK) == Pass::BLENDED;
if (blendPass) {
// TODO: at least for transparent objects, AABB should be per primitive
+2 -1
View File
@@ -284,6 +284,7 @@ public:
static constexpr RenderFlags HAS_SHADOWING = 0x01;
static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02;
static constexpr RenderFlags IS_INSTANCED_STEREOSCOPIC = 0x04;
static constexpr RenderFlags HAS_DEPTH_CLAMP = 0x08;
// Arena used for commands
using Arena = utils::Arena<
@@ -444,7 +445,7 @@ private:
uint8_t instancedStereoEyeCount) noexcept;
static void setupColorCommand(Command& cmdDraw, Variant variant,
FMaterialInstance const* mi, bool inverseFrontFaces) noexcept;
FMaterialInstance const* mi, bool inverseFrontFaces, bool hasDepthClamp) noexcept;
static void updateSummedPrimitiveCounts(
FScene::RenderableSoa& renderableData, utils::Range<uint32_t> vr) noexcept;
+1 -5
View File
@@ -75,7 +75,6 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
TargetBufferFlags const clearColorFlags = config.clearFlags & TargetBufferFlags::COLOR;
TargetBufferFlags clearDepthFlags = config.clearFlags & TargetBufferFlags::DEPTH;
TargetBufferFlags clearStencilFlags = config.clearFlags & TargetBufferFlags::STENCIL;
uint8_t layerCount = 1;
data.shadows = blackboard.get<FrameGraphTexture>("shadows");
data.ssao = blackboard.get<FrameGraphTexture>("ssao");
@@ -172,9 +171,6 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
data.color = builder.write(data.color, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.depth = builder.write(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
if (view.hasStereo() && engine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW) {
layerCount = engine.getConfig().stereoscopicEyeCount;
}
/*
* There is a bit of magic happening here regarding the viewport used.
@@ -196,7 +192,7 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
.stencil = data.stencil },
.clearColor = config.clearColor,
.samples = config.msaa,
.layerCount = layerCount,
.layerCount = static_cast<uint8_t>(colorBufferDesc.depth),
.clearFlags = clearColorFlags | clearDepthFlags | clearStencilFlags});
blackboard["depth"] = data.depth;
},
+6 -6
View File
@@ -829,13 +829,13 @@ ShadowMap::Corners ShadowMap::computeFrustumCorners(
Corners const csViewFrustumCorners = {
.vertices = {
{ -1, -1, far },
{ 1, -1, far },
{ -1, 1, far },
{ 1, 1, far },
{ 1, -1, far },
{ -1, 1, far },
{ 1, 1, far },
{ -1, -1, near },
{ 1, -1, near },
{ -1, 1, near },
{ 1, 1, near },
{ 1, -1, near },
{ -1, 1, near },
{ 1, 1, near },
}
};
+26 -5
View File
@@ -66,15 +66,15 @@ namespace filament {
using namespace backend;
using namespace math;
// do this only if depth-clamp is available
static constexpr bool USE_DEPTH_CLAMP = false;
ShadowMapManager::ShadowMapManager(FEngine& engine) {
ShadowMapManager::ShadowMapManager(FEngine& engine)
: mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) {
FDebugRegistry& debugRegistry = engine.getDebugRegistry();
debugRegistry.registerProperty("d.shadowmap.visualize_cascades",
&engine.debug.shadowmap.visualize_cascades);
debugRegistry.registerProperty("d.shadowmap.disable_light_frustum_align",
&engine.debug.shadowmap.disable_light_frustum_align);
debugRegistry.registerProperty("d.shadowmap.depth_clamp",
&engine.debug.shadowmap.depth_clamp);
}
ShadowMapManager::~ShadowMapManager() {
@@ -367,7 +367,22 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// generate and sort the commands for rendering the shadow map
RenderPass::RenderFlags renderPassFlags{};
if (view.isFrontFaceWindingInverted()) {
renderPassFlags |= RenderPass::HAS_INVERSE_FRONT_FACES;
}
bool const canUseDepthClamp =
!view.hasVSM() &&
mIsDepthClampSupported &&
engine.debug.shadowmap.depth_clamp;
if (canUseDepthClamp) {
renderPassFlags |= RenderPass::HAS_DEPTH_CLAMP;
}
RenderPass const pass = passBuilder
.renderFlags(renderPassFlags)
.camera(cameraInfo)
.visibilityMask(entry.visibilityMask)
.geometry(scene->getRenderableData(),
@@ -641,8 +656,14 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
cameraInfo.zf = -nearFarPlanes[i + 1];
updateNearFarPlanes(&cameraInfo.cullingProjection, cameraInfo.zn, cameraInfo.zf);
bool const canUseDepthClamp =
!view.hasVSM() &&
mIsDepthClampSupported &&
engine.debug.shadowmap.depth_clamp;
auto shaderParameters = shadowMap.updateDirectional(engine,
lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, USE_DEPTH_CLAMP);
lightData, 0, cameraInfo, shadowMapInfo, sceneInfo,
canUseDepthClamp);
if (shadowMap.hasVisibleShadows()) {
const size_t shadowIndex = shadowMap.getShadowIndex();
+1
View File
@@ -232,6 +232,7 @@ private:
ShadowMapCacheContainer mShadowMapCache;
uint32_t mDirectionalShadowMapCount = 0;
uint32_t mSpotShadowMapCount = 0;
bool const mIsDepthClampSupported;
bool mInitialized = false;
ShadowMap& getShadowMap(size_t index) noexcept {
@@ -588,9 +588,6 @@ void FRenderableManager::create(
// full size of the UBO.
instances.handle = driver.createBufferObject(sizeof(PerRenderableUib),
BufferObjectBinding::UNIFORM, backend::BufferUsage::DYNAMIC);
if (auto name = instances.buffer->getName(); !name.empty()) {
driver.setDebugTag(instances.handle.getId(), std::move(name));
}
}
const uint32_t boneCount = builder->mSkinningBoneCount;
-5
View File
@@ -20,8 +20,6 @@
#include "FilamentAPI-impl.h"
#include <utils/CString.h>
namespace filament {
struct BufferObject::BuilderDetails {
@@ -58,9 +56,6 @@ FBufferObject::FBufferObject(FEngine& engine, const BufferObject::Builder& build
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createBufferObject(builder->mByteCount, builder->mBindingType,
backend::BufferUsage::STATIC);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
void FBufferObject::terminate(FEngine& engine) {
+8 -16
View File
@@ -28,12 +28,6 @@
#include <string_view>
#include <utility>
#ifndef NDEBUG
# define DEBUG_PROPERTIES_WRITABLE true
#else
# define DEBUG_PROPERTIES_WRITABLE false
#endif
using namespace filament::math;
using namespace utils;
@@ -79,17 +73,15 @@ bool FDebugRegistry::hasProperty(const char* name) const noexcept {
template<typename T>
bool FDebugRegistry::setProperty(const char* name, T v) noexcept {
if constexpr (DEBUG_PROPERTIES_WRITABLE) {
auto info = getPropertyInfo(name);
T* const addr = static_cast<T*>(info.first);
if (addr) {
auto old = *addr;
*addr = v;
if (info.second && old != v) {
info.second();
}
return true;
auto info = getPropertyInfo(name);
T* const addr = static_cast<T*>(info.first);
if (addr) {
auto old = *addr;
*addr = v;
if (info.second && old != v) {
info.second();
}
return true;
}
return false;
}
+1
View File
@@ -600,6 +600,7 @@ public:
bool focus_shadowcasters = true;
bool visualize_cascades = false;
bool disable_light_frustum_align = false;
bool depth_clamp = true;
float dzn = -1.0f;
float dzf = 1.0f;
float display_shadow_texture_scale = 0.25f;
-5
View File
@@ -20,8 +20,6 @@
#include "FilamentAPI-impl.h"
#include <utils/CString.h>
namespace filament {
struct IndexBuffer::BuilderDetails {
@@ -60,9 +58,6 @@ FIndexBuffer::FIndexBuffer(FEngine& engine, const IndexBuffer::Builder& builder)
(backend::ElementType)builder->mIndexType,
uint32_t(builder->mIndexCount),
backend::BufferUsage::STATIC);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
void FIndexBuffer::terminate(FEngine& engine) {
+1 -2
View File
@@ -61,8 +61,7 @@ InstanceBuffer* InstanceBuffer::Builder::build(Engine& engine) {
// ------------------------------------------------------------------------------------------------
FInstanceBuffer::FInstanceBuffer(FEngine& engine, const Builder& builder)
: mName(builder.getName()) {
FInstanceBuffer::FInstanceBuffer(FEngine& engine, const Builder& builder) {
mInstanceCount = builder->mInstanceCount;
mLocalTransforms.reserve(mInstanceCount);
-4
View File
@@ -25,7 +25,6 @@
#include <math/mat4.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
namespace filament {
@@ -47,13 +46,10 @@ public:
void prepare(FEngine& engine, math::mat4f rootTransform, const PerRenderableData& ubo,
backend::Handle<backend::HwBufferObject> handle);
utils::CString const& getName() const noexcept { return mName; }
private:
friend class RenderableManager;
utils::FixedCapacityVector<math::mat4f> mLocalTransforms;
utils::CString mName;
size_t mInstanceCount;
};
-1
View File
@@ -610,7 +610,6 @@ Program FMaterial::getProgramWithVariants(
void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept {
auto program = mEngine.getDriverApi().createProgram(std::move(p));
mEngine.getDriverApi().setDebugTag(program.getId(), mName);
assert_invariant(program);
mCachedPrograms[variant.key] = program;
}
@@ -51,7 +51,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material)
mUniforms = UniformBuffer(material->getUniformInterfaceBlock().getSize());
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, backend::BufferUsage::STATIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
}
if (!material->getSamplerInterfaceBlock().isEmpty()) {
@@ -117,7 +116,6 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
mUniforms.setUniforms(other->getUniformBuffer());
mUbHandle = driver.createBufferObject(mUniforms.getSize(),
BufferObjectBinding::UNIFORM, backend::BufferUsage::DYNAMIC);
driver.setDebugTag(mUbHandle.getId(), material->getName());
}
if (!material->getSamplerInterfaceBlock().isEmpty()) {
@@ -25,8 +25,6 @@
#include <math/mat4.h>
#include <math/norm.h>
#include <utils/CString.h>
namespace filament {
using namespace backend;
@@ -126,11 +124,6 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder)
mCount,
TextureUsage::DEFAULT);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mPbHandle.getId(), name);
driver.setDebugTag(mTbHandle.getId(), std::move(name));
}
// create and update sampler group
mSbHandle = driver.createSamplerGroup(PerRenderPrimitiveMorphingSib::SAMPLER_COUNT,
utils::FixedSizeString<32>("Morph target samplers"));
+30 -1
View File
@@ -597,6 +597,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
bool hasColorGrading = hasPostProcess;
bool hasDithering = view.getDithering() == Dithering::TEMPORAL;
bool hasFXAA = view.getAntiAliasing() == AntiAliasing::FXAA;
// bool hasFXAA = false;//view.getAntiAliasing() == AntiAliasing::FXAA;
float2 scale = view.updateScale(engine, mFrameInfoManager.getLastFrameInfo(), mFrameRateOptions, mDisplayInfo);
auto msaaOptions = view.getMultiSampleAntiAliasingOptions();
auto dsrOptions = view.getDynamicResolutionOptions();
@@ -610,6 +611,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
auto guardBandOptions = view.getGuardBandOptions();
const bool isRenderingMultiview = view.hasStereo() &&
engine.getConfig().stereoscopicType == backend::StereoscopicType::MULTIVIEW;
utils::slog.e <<"hasFXAA=" <<hasFXAA << " view=" << &view << utils::io::endl;
// FIXME: This is to override some settings that are not supported for multiview at the moment.
// Remove this when all features are supported.
if (isRenderingMultiview) {
@@ -703,6 +705,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
const bool noBufferPadding = (colorGradingConfig.asSubpass && !hasFXAA && !scaled)
|| engine.debug.renderer.disable_buffer_padding;
// guardBandOptions.enabled = !noBufferPadding;
// guardBand must be a multiple of 16 to guarantee the same exact rendering up to 4 mip levels.
float const guardBand = guardBandOptions.enabled ? 16.0f : 0.0f;
@@ -719,7 +722,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// the SwapChain, and we might want to keep it this way.
auto round = [](uint32_t x) {
constexpr uint32_t rounding = 16u;
constexpr uint32_t rounding = 256u;
return (x + (rounding - 1u)) & ~(rounding - 1u);
};
@@ -727,6 +730,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
const float width = float(round(svp.width )) + 2.0f * guardBand;
const float height = float(round(svp.height)) + 2.0f * guardBand;
utils::slog.e << "new dim=" << width <<"x" << height <<
" old dim=" << svp.width << "x" << svp.height << utils::io::endl;
// scale the field-of-view up, so it covers exactly the extra pixels
const float3 clipSpaceScaling{
float(svp.width) / width,
@@ -744,9 +750,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
1.0f - clipSpaceScaling.y - 2.0f * guardBand / height
};
utils::slog.e <<"clipspace scaling=" << clipSpaceScaling << utils::io::endl;
utils::slog.e <<"clipspace translation=" << clipSpaceTranslation << utils::io::endl;
mat4f ts = mat4f::scaling(clipSpaceScaling);
ts[3].xy = -clipSpaceTranslation;
utils::slog.e <<"mat=" << ts << utils::io::endl;
// update the camera projection
cameraInfo.projection = highPrecisionMultiply(ts, cameraInfo.projection);
@@ -759,6 +770,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
svp.height = uint32_t(height);
xvp.left = int32_t(guardBand);
xvp.bottom = int32_t(guardBand);
utils::slog.e <<"xvp.left=" << int32_t(guardBand) << utils::io::endl;
}
view.prepare(engine, driver, rootArenaScope, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
@@ -870,6 +882,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
const TextureFormat hdrFormat = getHdrFormat(view, needsAlphaChannel);
utils::slog.e <<"padding=" << !noBufferPadding << " svp=" << svp << utils::io::endl;
utils::slog.e <<"padding=" << !noBufferPadding << " xvp=" << xvp << utils::io::endl;
// the clearFlags and clearColor specified below will only apply when rendering into the
// temporary color buffer. In particular, they won't apply when rendering into the main
// swapchain (imported render target above)
@@ -1074,6 +1089,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
.format = config.hdrFormat
};
utils::slog.e <<"color buffer output=" << colorBufferDesc.width <<"x" << colorBufferDesc.height
<< utils::io::endl;
// Set the depth to the number of layers if we're rendering multiview.
if (isRenderingMultiview) {
colorBufferDesc.depth = engine.getConfig().stereoscopicEyeCount;
@@ -1227,11 +1245,13 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
bloomOptions, vignetteOptions);
// the padded buffer is resolved now
xvp.left = xvp.bottom = 0;
utils::slog.e <<"color grading is resolved" << utils::io::endl;
svp = xvp;
}
}
if (hasFXAA) {
utils::slog.e <<"fxaa=" << xvp << utils::io::endl;
input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat,
!hasColorGrading || needsAlphaChannel);
// the padded buffer is resolved now
@@ -1245,6 +1265,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
.width = viewport.width, .height = viewport.height,
.format = colorGradingConfig.ldrFormat }, SamplerMagFilter::LINEAR);
xvp.left = xvp.bottom = 0;
utils::slog.e <<"scaled" << utils::io::endl;
svp = xvp;
}
}
@@ -1277,6 +1298,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
const bool outputIsSwapChain =
(input == colorPassOutput) && (viewRenderTarget == mRenderTargetHandle);
if (mightNeedFinalBlit) {
utils::slog.e <<"inside might need final blit xvp!=svp=" << (xvp != svp) <<
" xvp=" << xvp << " svp=" << svp <<
utils::io::endl;
if (blendModeTranslucent ||
xvp != svp ||
(outputIsSwapChain &&
@@ -1285,6 +1309,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
hasScreenSpaceRefraction ||
ssReflectionsOptions.enabled))) {
assert_invariant(!scaled);
utils::slog.e <<"doing final blit " << svp << " " << xvp << utils::io::endl;
input = ppm.blit(fg, blendModeTranslucent, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat },
@@ -1314,6 +1339,10 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
fg.forwardResource(fgViewRenderTarget, input);
utils::slog.e <<"present view=" << &view << " scaled=" << scaled << " mightNeedFinalBlit=" <<
mightNeedFinalBlit <<
utils::io::endl;
fg.present(fgViewRenderTarget);
fg.compile();
-7
View File
@@ -27,8 +27,6 @@
#include <math/half.h>
#include <math/mat4.h>
#include <utils/CString.h>
#include <cstring>
namespace filament {
@@ -82,11 +80,6 @@ FSkinningBuffer::FSkinningBuffer(FEngine& engine, const Builder& builder)
BufferObjectBinding::UNIFORM,
BufferUsage::DYNAMIC);
if (auto name = builder.getName(); !name.empty()) {
// TODO: We should also tag the texture created inside createIndicesAndWeightsHandle.
driver.setDebugTag(mHandle.getId(), std::move(name));
}
if (builder->mInitialize) {
// initialize the bones to identity (before rounding up)
auto* out = driver.allocatePod<PerRenderableBoneUib::BoneData>(mBoneCount);
+1 -5
View File
@@ -23,10 +23,10 @@
#include <backend/PixelBufferDescriptor.h>
#include <utils/CString.h>
#include <utils/Panic.h>
#include <filament/Stream.h>
namespace filament {
using namespace backend;
@@ -80,10 +80,6 @@ FStream::FStream(FEngine& engine, const Builder& builder) noexcept
} else {
mStreamHandle = engine.getDriverApi().createStreamAcquired();
}
if (auto name = builder.getName(); !name.empty()) {
engine.getDriverApi().setDebugTag(mStreamHandle.getId(), std::move(name));
}
}
void FStream::terminate(FEngine& engine) noexcept {
-3
View File
@@ -243,9 +243,6 @@ FTexture::FTexture(FEngine& engine, const Builder& builder) {
mHandle = driver.importTexture(builder->mImportedId,
mTarget, mLevelCount, mFormat, mSampleCount, mWidth, mHeight, mDepth, mUsage);
}
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mHandle.getId(), std::move(name));
}
}
// frees driver resources, object becomes invalid
+1 -10
View File
@@ -29,7 +29,6 @@
#include <utils/bitset.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
@@ -260,9 +259,7 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build
mBufferCount, mDeclaredAttributes.count(), mAttributes);
mHandle = driver.createVertexBuffer(mVertexCount, mVertexBufferInfoHandle);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(mHandle.getId(), name);
}
// calculate buffer sizes
size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {};
@@ -290,9 +287,6 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build
if (!mBufferObjects[i]) {
BufferObjectHandle bo = driver.createBufferObject(bufferSizes[i],
backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(bo.getId(), name);
}
driver.setVertexBufferObject(mHandle, i, bo);
mBufferObjects[i] = bo;
}
@@ -309,9 +303,6 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const VertexBuffer::Builder& build
if (!mBufferObjects[i]) {
BufferObjectHandle const bo = driver.createBufferObject(bufferSizes[i],
backend::BufferObjectBinding::VERTEX, backend::BufferUsage::STATIC);
if (auto name = builder.getName(); !name.empty()) {
driver.setDebugTag(bo.getId(), name);
}
driver.setVertexBufferObject(mHandle, i, bo);
mBufferObjects[i] = bo;
}
+3 -3
View File
@@ -190,10 +190,10 @@ void RenderPassNode::resolve() noexcept {
minHeight = std::min(minHeight, h);
maxHeight = std::max(maxHeight, h);
}
// additionally, clear implies discardStart
rt.backend.params.flags.discardStart |= (
rt.descriptor.clearFlags & rt.targetBufferFlags);
}
// additionally, clear implies discardStart
rt.backend.params.flags.discardStart |= (
rt.descriptor.clearFlags & rt.targetBufferFlags);
assert_invariant(minWidth == maxWidth);
assert_invariant(minHeight == maxHeight);
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.54.1"
spec.version = "1.54.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.54.1/filament-v1.54.1-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.54.0/filament-v1.54.0-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -224,6 +224,9 @@ public:
*/
static void exportSettings(const Settings& settings, const char* filename);
static void exportScreenshot(View* view, Renderer* renderer, std::string filename,
bool autoclose, AutomationEngine* automationEngine);
Options getOptions() const { return mOptions; }
bool isRunning() const { return mIsRunning; }
size_t currentTest() const { return mCurrentTest; }
+3 -2
View File
@@ -56,7 +56,7 @@ static void convertRGBAtoRGB(void* buffer, uint32_t width, uint32_t height) {
}
}
static void exportScreenshot(View* view, Renderer* renderer, std::string filename,
void AutomationEngine::exportScreenshot(View* view, Renderer* renderer, std::string filename,
bool autoclose, AutomationEngine* automationEngine) {
const Viewport& vp = view->getViewport();
const size_t byteCount = vp.width * vp.height * 4;
@@ -244,7 +244,8 @@ void AutomationEngine::tick(Engine* engine, const ViewerContent& content, float
}
if (mOptions.exportScreenshots) {
exportScreenshot(content.view, content.renderer, prefix + ".ppm", isLastTest, this);
AutomationEngine::exportScreenshot(
content.view, content.renderer, prefix + ".ppm", isLastTest, this);
}
if (isLastTest) {
+2
View File
@@ -562,6 +562,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, Settings* out)
}
void applySettings(Engine* engine, const ViewSettings& settings, View* dest) {
utils::slog.e << "antialiasing=" << (int) settings.antiAliasing << " view=" << dest
<< utils::io::endl;
dest->setAntiAliasing(settings.antiAliasing);
dest->setTemporalAntiAliasingOptions(settings.taa);
dest->setMultiSampleAntiAliasingOptions(settings.msaa);
+1 -1
View File
@@ -276,7 +276,7 @@ if (NOT ANDROID)
target_link_libraries(hellopbr PRIVATE filameshio suzanne-resources)
target_link_libraries(image_viewer PRIVATE viewer imageio)
target_link_libraries(multiple_windows PRIVATE filameshio suzanne-resources)
target_link_libraries(rendertarget PRIVATE filameshio suzanne-resources)
target_link_libraries(rendertarget PRIVATE gltf-demo-resources filameshio suzanne-resources gltfio viewer)
target_link_libraries(sample_cloth PRIVATE filameshio)
target_link_libraries(sample_normal_map PRIVATE filameshio)
target_link_libraries(suzanne PRIVATE filameshio suzanne-resources)
+23 -4
View File
@@ -61,8 +61,10 @@
#include <algorithm>
#include <array>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include "generated/resources/gltf_demo.h"
@@ -137,6 +139,8 @@ struct App {
AutomationSpec* automationSpec = nullptr;
AutomationEngine* automationEngine = nullptr;
bool screenshot = false;
uint8_t screenshotSeq = 0;
};
static const char* DEFAULT_IBL = "assets/ibl/lightroom_14b";
@@ -877,10 +881,15 @@ int main(int argc, char** argv) {
if (ImGui::CollapsingHeader("Debug")) {
auto& debug = engine->getDebugRegistry();
if (ImGui::Button("Capture frame")) {
bool* captureFrame =
debug.getPropertyAddress<bool>("d.renderer.doFrameCapture");
*captureFrame = true;
if (engine->getBackend() == Engine::Backend::METAL) {
if (ImGui::Button("Capture frame")) {
bool* captureFrame =
debug.getPropertyAddress<bool>("d.renderer.doFrameCapture");
*captureFrame = true;
}
}
if (ImGui::Button("Screenshot")) {
app.screenshot = true;
}
ImGui::Checkbox("Disable buffer padding",
debug.getPropertyAddress<bool>("d.renderer.disable_buffer_padding"));
@@ -896,6 +905,8 @@ int main(int argc, char** argv) {
debug.getPropertyAddress<bool>("d.shadowmap.focus_shadowcasters"));
ImGui::Checkbox("Disable light frustum alignment",
debug.getPropertyAddress<bool>("d.shadowmap.disable_light_frustum_align"));
ImGui::Checkbox("Depth clamp",
debug.getPropertyAddress<bool>("d.shadowmap.depth_clamp"));
bool debugDirectionalShadowmap;
if (debug.getProperty("d.shadowmap.debug_directional_shadowmap",
@@ -1136,6 +1147,14 @@ int main(int argc, char** argv) {
};
auto postRender = [&app](Engine* engine, View* view, Scene*, Renderer* renderer) {
if (app.screenshot) {
std::ostringstream stringStream;
stringStream << "screenshot" << std::setfill('0') << std::setw(2) << +app.screenshotSeq;
AutomationEngine::exportScreenshot(
view, renderer, stringStream.str() + ".ppm", false, app.automationEngine);
++app.screenshotSeq;
app.screenshot = false;
}
if (app.automationEngine->shouldClose()) {
FilamentApp::get().close();
return;
+6 -10
View File
@@ -12,6 +12,8 @@ material {
uv0
],
shadingModel : unlit,
vertexDomain: device,
// vertexDomainDeviceJittered: true,
}
fragment {
@@ -20,17 +22,11 @@ fragment {
if (gl_FrontFacing) {
// Make a lookup into the mirror texture.
vec2 uv = getResolution().zw * gl_FragCoord.xy;
// vec2 uv = getResolution().zw * gl_FragCoord.xy;
vec2 uv = getNormalizedViewportCoord().xy;
material.baseColor.rgb = texture(materialParams_albedo, uv).rgb;
// Add black borders to the mirror.
vec2 st = getUV0();
float minDist0 = min(st.x, st.y);
float minDist1 = min(1.0 - st.x, 1.0 - st.y);
float minDist = min(minDist0, minDist1);
material.baseColor.rgb *= smoothstep(0.0, 0.1, minDist);
} else {
material.baseColor = vec4(1, 0, 0, 1);
}
material.baseColor.a = 1.0;
}
}
+198 -195
View File
@@ -28,10 +28,17 @@
#include <filament/VertexBuffer.h>
#include <filament/View.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/TextureProvider.h>
#include <utils/NameComponentManager.h>
#include <utils/EntityManager.h>
#include <imgui.h>
#include <filagui/ImGuiExtensions.h>
#include <viewer/ViewerGui.h>
#include <filameshio/MeshReader.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
@@ -40,11 +47,16 @@
#include <iostream>
#include "generated/resources/resources.h"
#include "generated/resources/monkey.h"
//#include "generated/resources/monkey.h"
#include "generated/resources/gltf_demo.h"
using namespace filament;
using namespace filamesh;
using namespace filament::math;
using namespace filament::viewer;
using namespace filament::gltfio;
#include <utils/Log.h>
struct Vertex {
float3 position;
@@ -55,8 +67,6 @@ struct App {
utils::Entity lightEntity;
Material* meshMaterial;
MaterialInstance* meshMatInstance;
MeshReader::Mesh monkeyMesh;
utils::Entity reflectedMonkey;
mat4f transform;
Texture* offscreenColorTexture = nullptr;
@@ -66,12 +76,6 @@ struct App {
Scene* offscreenScene = nullptr;
Camera* offscreenCamera = nullptr;
enum class ReflectionMode {
RENDERABLES,
CAMERA,
};
ReflectionMode mode = ReflectionMode::CAMERA;
Config config;
utils::Entity quadEntity;
@@ -80,46 +84,22 @@ struct App {
Material* quadMaterial = nullptr;
MaterialInstance* quadMatInstance = nullptr;
float3 quadCenter;
float3 quadNormal;
MaterialProvider* materials;
AssetLoader* assetLoader;
ResourceLoader* resourceLoader;
FilamentAsset* asset = nullptr;
utils::NameComponentManager* names;
gltfio::TextureProvider* stbDecoder = nullptr;
gltfio::TextureProvider* ktxDecoder = nullptr;
Engine* engine;
ViewerGui* viewer;
utils::Entity rootTransformEntity;
};
static mat4f reflectionMatrix(float4 plane) {
mat4f m;
m[0][0] = -2 * plane.x * plane.x + 1;
m[0][1] = -2 * plane.x * plane.y;
m[0][2] = -2 * plane.x * plane.z;
m[0][3] = -2 * plane.x * plane.w;
m[1][0] = -2 * plane.x * plane.y;
m[1][1] = -2 * plane.y * plane.y + 1;
m[1][2] = -2 * plane.y * plane.z;
m[1][3] = -2 * plane.y * plane.w;
m[2][0] = -2 * plane.z * plane.x;
m[2][1] = -2 * plane.z * plane.y;
m[2][2] = -2 * plane.z * plane.z + 1;
m[2][3] = -2 * plane.z * plane.w;
m[3][0] = 0;
m[3][1] = 0;
m[3][2] = 0;
m[3][3] = 1;
return transpose(m);
}
static void setReflectionMode(App& app, App::ReflectionMode mode) {
switch (mode) {
case App::ReflectionMode::RENDERABLES:
app.offscreenScene->addEntity(app.reflectedMonkey);
app.offscreenScene->remove(app.monkeyMesh.renderable);
app.offscreenView->setFrontFaceWindingInverted(false);
break;
case App::ReflectionMode::CAMERA:
app.offscreenScene->addEntity(app.monkeyMesh.renderable);
app.offscreenScene->remove(app.reflectedMonkey);
app.offscreenView->setFrontFaceWindingInverted(true);
break;
}
app.mode = mode;
}
static const char* DEFAULT_IBL = "assets/ibl/lightroom_14b";
static void printUsage(char* name) {
std::string exec_name(utils::Path(name).getName());
@@ -172,14 +152,6 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
}
break;
case 'm':
if (arg == "camera") {
app->mode = App::ReflectionMode::CAMERA;
} else if (arg == "renderables") {
app->mode = App::ReflectionMode::RENDERABLES;
} else {
std::cerr << "Unrecognized mode. Must be 'camera'|'renderables'.\n";
exit(1);
}
break;
}
}
@@ -189,126 +161,182 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) {
int main(int argc, char** argv) {
App app{};
app.config.title = "rendertarget";
app.config.iblDirectory = FilamentApp::getRootAssetsPath() + DEFAULT_IBL;
handleCommandLineArguments(argc, argv, &app);
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
auto gui = [&app](Engine*, View*) {
app.viewer->updateUserInterface();
FilamentApp::get().setSidebarWidth(app.viewer->getSidebarWidth());
};
auto loadResources = [&app] () {
// Load external textures and buffers.
std::string const gltfPath;
ResourceConfiguration configuration = {};
configuration.engine = app.engine;
configuration.gltfPath = gltfPath.c_str();
configuration.normalizeSkinningWeights = true;
app.resourceLoader = new gltfio::ResourceLoader(configuration);
app.stbDecoder = createStbProvider(app.engine);
app.ktxDecoder = createKtx2Provider(app.engine);
app.resourceLoader->addTextureProvider("image/png", app.stbDecoder);
app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder);
app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder);
if (!app.resourceLoader->loadResources(app.asset)) {
std::cerr << "Unable to start loading resources" << std::endl;
exit(1);
}
app.asset->getInstance()->recomputeBoundingBoxes();
app.asset->releaseSourceData();
// Enable stencil writes on all material instances.
auto instance = app.asset->getInstance();
const size_t matInstanceCount = instance->getMaterialInstanceCount();
MaterialInstance* const* const instances = instance->getMaterialInstances();
for (int mi = 0; mi < matInstanceCount; mi++) {
instances[mi]->setStencilWrite(true);
instances[mi]->setStencilOpDepthStencilPass(MaterialInstance::StencilOperation::INCR);
}
auto ibl = FilamentApp::get().getIBL();
if (ibl) {
app.viewer->setIndirectLight(ibl->getIndirectLight(), ibl->getSphericalHarmonics());
app.viewer->getSettings().view.fogSettings.fogColorTexture = ibl->getFogTexture();
}
};
auto setup = [&app, loadResources](Engine* engine, View* view, Scene* scene) {
app.engine = engine;
auto& em = utils::EntityManager::get();
auto& tcm = engine->getTransformManager();
auto& rcm = engine->getRenderableManager();
auto& em = utils::EntityManager::get();
auto vp = view->getViewport();
// Offscreen view
{
// Instantiate offscreen render target.
app.offscreenView = engine->createView();
app.offscreenScene = engine->createScene();
app.offscreenView->setScene(app.offscreenScene);
// Instantiate offscreen render target.
app.offscreenView = engine->createView();
app.offscreenScene = engine->createScene();
app.offscreenView->setScene(app.offscreenScene);
app.offscreenView->setPostProcessingEnabled(false);
app.offscreenColorTexture = Texture::Builder()
.width(vp.width).height(vp.height).levels(1)
.usage(Texture::Usage::COLOR_ATTACHMENT | Texture::Usage::SAMPLEABLE)
.format(Texture::InternalFormat::RGBA8).build(*engine);
app.offscreenDepthTexture = Texture::Builder()
.width(vp.width).height(vp.height).levels(1)
.usage(Texture::Usage::DEPTH_ATTACHMENT)
.format(Texture::InternalFormat::DEPTH24).build(*engine);
app.offscreenRenderTarget = RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR, app.offscreenColorTexture)
.texture(RenderTarget::AttachmentPoint::DEPTH, app.offscreenDepthTexture)
.build(*engine);
app.offscreenView->setRenderTarget(app.offscreenRenderTarget);
app.offscreenView->setViewport({0, 0, vp.width, vp.height});
app.offscreenCamera = engine->createCamera(em.create());
app.offscreenView->setCamera(app.offscreenCamera);
FilamentApp::get().addOffscreenView(app.offscreenView);
app.viewer = new ViewerGui(engine, app.offscreenScene, app.offscreenView, 410);
app.viewer->setUiCallback([&app, scene, view, engine]() {
if (ImGui::CollapsingHeader("Debug")) {
auto& debug = engine->getDebugRegistry();
ImGui::Checkbox("Disable buffer padding",
debug.getPropertyAddress<bool>("d.renderer.disable_buffer_padding"));
ImGui::Checkbox("Disable sub-passes",
debug.getPropertyAddress<bool>("d.renderer.disable_subpasses"));
}
});
Viewport vp = view->getViewport();
vp.width = vp.width - app.viewer->getSidebarWidth();
// Position and orient the mirror in an interesting way.
float3 c = app.quadCenter = {-2, 0, -5};
float3 n = app.quadNormal = normalize(float3 {1, 0, 2});
float3 u = normalize(cross(app.quadNormal, float3(0, 1, 0)));
float3 v = cross(n, u);
u = 1.5 * u;
v = 1.5 * v;
static Vertex kQuadVertices[4] = { {{}, {1, 0}}, {{}, {0, 0}}, {{}, {1, 1}}, {{}, {0, 1}} };
kQuadVertices[0].position = c - u - v;
kQuadVertices[1].position = c + u - v;
kQuadVertices[2].position = c - u + v;
kQuadVertices[3].position = c + u + v;
app.offscreenColorTexture =
Texture::Builder()
.width(vp.width)
.height(vp.height)
.levels(1)
.usage(Texture::Usage::COLOR_ATTACHMENT | Texture::Usage::SAMPLEABLE)
.format(Texture::InternalFormat::RGBA8)
.build(*engine);
app.offscreenDepthTexture = Texture::Builder()
.width(vp.width)
.height(vp.height)
.levels(1)
.usage(Texture::Usage::DEPTH_ATTACHMENT)
.format(Texture::InternalFormat::DEPTH32F)
.build(*engine);
app.offscreenRenderTarget = RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR,
app.offscreenColorTexture)
.texture(RenderTarget::AttachmentPoint::DEPTH,
app.offscreenDepthTexture)
.build(*engine);
app.offscreenView->setRenderTarget(app.offscreenRenderTarget);
app.offscreenView->setViewport({0, 0, vp.width, vp.height});
app.offscreenCamera = engine->createCamera(em.create());
app.offscreenView->setCamera(app.offscreenCamera);
FilamentApp::get().addOffscreenView(app.offscreenView);
}
// Create quad vertex buffer.
static_assert(sizeof(Vertex) == 20, "Strange vertex size.");
app.quadVb = VertexBuffer::Builder()
.vertexCount(4)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3, 0, 20)
.attribute(VertexAttribute::UV0, 0, VertexBuffer::AttributeType::FLOAT2, 12, 20)
.build(*engine);
app.quadVb->setBufferAt(*engine, 0,
VertexBuffer::BufferDescriptor(kQuadVertices, 80, nullptr));
// damaged helmet gltf
{
app.names = new utils::NameComponentManager(em);
app.materials = createJitShaderProvider(engine, true);
app.assetLoader = AssetLoader::create({engine, app.materials, app.names});
// Create quad index buffer.
static constexpr uint16_t kQuadIndices[6] = { 0, 1, 2, 3, 2, 1 };
app.quadIb = IndexBuffer::Builder()
.indexCount(6)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*engine);
app.quadIb->setBuffer(*engine, IndexBuffer::BufferDescriptor(kQuadIndices, 12, nullptr));
app.asset = app.assetLoader->createAsset(GLTF_DEMO_DAMAGEDHELMET_DATA,
GLTF_DEMO_DAMAGEDHELMET_SIZE);
// Create quad material and renderable.
app.quadMaterial = Material::Builder()
.package(RESOURCES_MIRROR_DATA, RESOURCES_MIRROR_SIZE)
.build(*engine);
app.quadMatInstance = app.quadMaterial->createInstance();
TextureSampler sampler(TextureSampler::MinFilter::LINEAR, TextureSampler::MagFilter::LINEAR);
app.quadMatInstance->setParameter("albedo", app.offscreenColorTexture, sampler);
app.quadEntity = em.create();
RenderableManager::Builder(1)
.boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }})
.material(0, app.quadMatInstance)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.quadVb, app.quadIb, 0, 6)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*engine, app.quadEntity);
scene->addEntity(app.quadEntity);
loadResources();
// Instantiate mesh material.
app.meshMaterial = Material::Builder()
.package(RESOURCES_AIDEFAULTMAT_DATA, RESOURCES_AIDEFAULTMAT_SIZE).build(*engine);
auto mi = app.meshMatInstance = app.meshMaterial->createInstance();
mi->setParameter("baseColor", RgbType::LINEAR, {0.8, 1.0, 1.0});
mi->setParameter("metallic", 0.0f);
mi->setParameter("roughness", 0.4f);
mi->setParameter("reflectance", 0.5f);
app.offscreenScene->addEntities(app.asset->getLightEntities(),
app.asset->getLightEntityCount());
static constexpr int kNumAvailable = 128;
utils::Entity renderables[kNumAvailable];
gltfio::FilamentAsset::SceneMask mask;
mask.set(0);
while (size_t numWritten = app.asset->popRenderables(renderables, kNumAvailable)) {
app.asset->addEntitiesToScene(*app.offscreenScene, renderables, numWritten, mask);
}
// Add monkey into the scene.
app.monkeyMesh = MeshReader::loadMeshFromBuffer(engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, mi);
auto ti = tcm.getInstance(app.monkeyMesh.renderable);
app.transform = mat4f{ mat3f(1), float3(0, 0, -4) } * tcm.getWorldTransform(ti);
rcm.setCastShadows(rcm.getInstance(app.monkeyMesh.renderable), false);
scene->addEntity(app.monkeyMesh.renderable);
app.rootTransformEntity = engine->getEntityManager().create();
tcm.create(app.rootTransformEntity);
TransformManager::Instance const& root = tcm.getInstance(app.rootTransformEntity);
tcm.setParent(tcm.getInstance(app.asset->getRoot()), root);
tcm.setTransform(root, mat4::translation(float3(0, 0, -4)));
}
// Create a reflected monkey, which is used only for App::ReflectionMode::RENDERABLES.
app.reflectedMonkey = em.create();
RenderableManager::Builder(1)
.boundingBox({{ -2, -2, -2 }, { 2, 2, 2 }})
.material(0, mi)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.monkeyMesh.vertexBuffer, app.monkeyMesh.indexBuffer)
.receiveShadows(true)
.castShadows(false)
.build(*engine, app.reflectedMonkey);
setReflectionMode(app, app.mode);
// full-screen quad
{
static Vertex kQuadVertices[4] = {{{1, 1, 0}, {1, 1}}, {{1, -1, 0}, {1, 0}},
{{-1, -1, 0}, {0, 0}}, {{-1, 1, 0}, {0, 1}}};
// Create quad vertex buffer.
static_assert(sizeof(Vertex) == 20, "Strange vertex size.");
app.quadVb = VertexBuffer::Builder()
.vertexCount(4)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0,
VertexBuffer::AttributeType::FLOAT3, 0, 20)
.attribute(VertexAttribute::UV0, 0,
VertexBuffer::AttributeType::FLOAT2, 12, 20)
.build(*engine);
app.quadVb->setBufferAt(*engine, 0,
VertexBuffer::BufferDescriptor(kQuadVertices, 80, nullptr));
// Add light source to both scenes.
// NOTE: this is slightly wrong when the reflection mode is RENDERABLES.
app.lightEntity = em.create();
LightManager::Builder(LightManager::Type::SUN)
.color(Color::toLinear<ACCURATE>(sRGBColor(0.98f, 0.92f, 0.89f)))
.intensity(110000)
.direction({ 0.7, -1, -0.8 })
.sunAngularRadius(1.9f)
.castShadows(false)
.build(*engine, app.lightEntity);
scene->addEntity(app.lightEntity);
app.offscreenScene->addEntity(app.lightEntity);
// Create quad index buffer.
static constexpr uint16_t kQuadIndices[6] = {0, 2, 1, 2, 0, 3};
app.quadIb = IndexBuffer::Builder()
.indexCount(6)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*engine);
app.quadIb->setBuffer(*engine,
IndexBuffer::BufferDescriptor(kQuadIndices, 12, nullptr));
// Create quad material and renderable.
// NOTE: this material is VertexDomain=device
app.quadMaterial = Material::Builder()
.package(RESOURCES_MIRROR_DATA, RESOURCES_MIRROR_SIZE)
.build(*engine);
app.quadMatInstance = app.quadMaterial->createInstance();
TextureSampler sampler(TextureSampler::MinFilter::LINEAR,
TextureSampler::MagFilter::LINEAR);
app.quadMatInstance->setParameter("albedo", app.offscreenColorTexture, sampler);
app.quadEntity = em.create();
RenderableManager::Builder(1)
.boundingBox({{-1, -1, -1}, {1, 1, 1}})
.material(0, app.quadMatInstance)
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.quadVb,
app.quadIb, 0, 6)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*engine, app.quadEntity);
scene->addEntity(app.quadEntity);
}
};
auto cleanup = [&app](Engine* engine, View*, Scene*) {
@@ -318,14 +346,10 @@ int main(int argc, char** argv) {
engine->destroyCameraComponent(camera);
em.destroy(camera);
engine->destroy(app.reflectedMonkey);
engine->destroy(app.lightEntity);
engine->destroy(app.quadEntity);
engine->destroy(app.meshMatInstance);
engine->destroy(app.meshMaterial);
engine->destroy(app.monkeyMesh.renderable);
engine->destroy(app.monkeyMesh.vertexBuffer);
engine->destroy(app.monkeyMesh.indexBuffer);
engine->destroy(app.offscreenColorTexture);
engine->destroy(app.offscreenDepthTexture);
engine->destroy(app.offscreenRenderTarget);
@@ -337,43 +361,22 @@ int main(int argc, char** argv) {
engine->destroy(app.quadMaterial);
};
auto preRender = [&app](Engine*, View*, Scene*, Renderer* renderer) {
auto preRender = [&app](Engine* engine, View* view, Scene*, Renderer* renderer) {
renderer->setClearOptions({.clearColor = {0.1,0.2,0.4,1.0}, .clear = true});
};
FilamentApp::get().animate([&app](Engine* engine, View* view, double now) {
auto& tcm = engine->getTransformManager();
utils::slog.e <<"offscreen view=" << app.offscreenView << " primary view=" <<
view << utils::io::endl;
// Animate the monkey by spinning and sliding back and forth along Z.
auto ti = tcm.getInstance(app.monkeyMesh.renderable);
mat4f xlate = mat4f::translation(float3(0, 0, 0.5 + sin(now)));
mat4f xform = app.transform * xlate * mat4f::rotation(now, float3{ 0, 1, 0 });
tcm.setTransform(ti, xform);
// Generate a reflection matrix from the plane equation Ax + By + Cz + D = 0.
const float3 planeNormal = app.quadNormal;
const float4 planeEquation(planeNormal, -dot(planeNormal, app.quadCenter));
const mat4f reflection = reflectionMatrix(planeEquation);
// Apply the reflection matrix to either the renderable or the camera, depending on mode.
Camera const& camera = view->getCamera();
const auto model = camera.getModelMatrix();
const auto renderingProjection = camera.getProjectionMatrix();
const auto cullingProjection = camera.getCullingProjectionMatrix();
app.offscreenCamera->setCustomProjection(renderingProjection, cullingProjection,
camera.getNear(), camera.getCullingFar());
switch (app.mode) {
case App::ReflectionMode::RENDERABLES:
tcm.setTransform(tcm.getInstance(app.reflectedMonkey), reflection * xform);
app.offscreenCamera->setModelMatrix(model);
break;
case App::ReflectionMode::CAMERA:
app.offscreenCamera->setModelMatrix(reflection * model);
break;
}
});
const auto model = camera.getModelMatrix();
app.offscreenCamera->setModelMatrix(model);
};
FilamentApp::get().run(app.config, setup, cleanup, FilamentApp::ImGuiCallback(), preRender);
FilamentApp::get().run(app.config, setup, cleanup, gui, preRender);
return 0;
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.54.1",
"version": "1.54.0",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",