Compare commits

..
Author SHA1 Message Date
Benjamin Doherty f3da96d424 Throw an NSException on Apple platforms when panicking 2024-03-27 16:04:49 -07:00
Nimrod Gileadi a068143953 Add semicolons to code snippet in AssetLoader.h (#7717) 2024-03-27 17:24:10 +00:00
Powei Feng 90d90094dc Bump material version to 51 in MaterialEnums.h 2024-03-26 14:37:13 -07:00
Sungun Park 54df4524eb Improve multiview shader replacement (#7706)
Replace the num_views for OpenGL multiviwe only when
- The engine is initialized with multiview stereo
- The variant for the material contains STE flag
- The program is for surface
- It's vertex shader (this is already in)
2024-03-26 21:36:22 +00:00
Powei Feng d70f2e1b81 vk: delete instead of ref-count EmptyTexture (#7711) 2024-03-26 13:35:50 -07:00
Powei Feng 2f359b73a4 Add missing include to Platform.h (#7709) 2024-03-26 19:51:57 +00:00
Sungun Park abb0cbc98e Add FILAMENT_ENABLE_MULTIVIEW option (#7707)
This allows the engine to include multiview shader code for default
materials.
2024-03-25 21:43:04 +00:00
Jacob Su 2763931b47 fix install android samples apk error. (#7230) 2024-03-22 23:05:01 -07:00
Sungun Park 0ead96b606 Replace value of num_views with engine's eye count (#7696)
For OpenGL multiview, it honors the qualifier `layout(num_views = X)`
specified in shader files to determine the number of views for
multiview.

We cannot recompile materials everytime the value changes. So replace
the value of num_views with the engine's eye count when shaders compile.
2024-03-22 21:45:58 +00:00
Ben Doherty 317c1bb7ea Metal: track buffer allocations (#7556) 2024-03-22 12:47:56 -07:00
Ben Doherty 9aaaad9271 Improve Skybox eyeDirection precision (#7685) 2024-03-22 12:03:06 -07:00
Mathias Agopian d2ce714e73 fix use-after-free disable option 2024-03-22 11:27:30 -07:00
Mathias Agopian 8398175d9c Add an option to disable use-after-free checks in the backend
BUGS=330403836
2024-03-22 10:24:29 -07:00
Sungun Park 26258a4718 Facilitate four views for multiview (#7694)
This change allows the combine function for multiview to be able to
combine more than two views side-by-side.
2024-03-22 17:09:08 +00:00
Mathias Agopian 3644e7f808 Fixes IBL prefilter has floor and ceiling flipped
FIXES=[330603077]
2024-03-21 13:28:24 -07:00
Powei Feng 4d774820d9 gl: Don't reference swapchain obj on Web
Fixes #7693
2024-03-21 13:27:45 -07:00
Eliza Velasquez aad45d9119 Fix typo 2024-03-21 19:59:47 +00:00
Eliza Velasquez 5389b37002 Incorporate feedback 2024-03-21 19:59:47 +00:00
Eliza Velasquez d5fe9e236f Allow rendering thread to pause
This PR adds a new `pause()` option to the `Engine` `Builder` and a new function
`setPaused()` to the `Engine`. While paused, the rendering thread will pause
indefinitely for commands as if none are available. As soon as the rendering
thread is unpaused, the commands are immediately executed.
2024-03-21 19:59:47 +00:00
Mathias Agopian 59890ac85a PlatformEGL::createSwapChain never returns a nullptr anymore
in case the swapchain creation fails, it will now return a swapchain
with an EGL_NO_SURFACE handle. this will avoid having to nullptr check
the pointer in various places and will revert to the previous behavior
on failure.

FIXES=[329659681]
2024-03-20 16:07:02 -07:00
Mathias Agopian 435969f565 attempt to detect buffer overflows in Texture::setImage()
We verify that the buffer given to setImage() is at least as large
as needed for the given region to transfer; at least based on the
size given.

This might help catch b/330407429.

BUGS=330407429
2024-03-20 16:06:43 -07:00
Ben Doherty e3db39105f iOS: fix gltf-viewer crash while destruction ResourceLoader (#7684) 2024-03-19 16:14:45 -07:00
Powei Feng dfa821d351 vk: fix broken gltf renderings (#7680)
This is due to color attachments being set to store=discard when
they are multi-sampled. It's unclear why that condition exists. For
now, removing it will fix the rendering issues with transparent
object + MSAA. We'll keep it as such until an issue surfaces.

Fixes #7674
2024-03-19 22:38:52 +00:00
Powei Feng 1ab223c965 vk: minor fixes (#7682)
- Add description to a few debug options
- Set correct usage flag for blit-src/dest images
- Correctly initialize a debug-only field in VulkanProgram
2024-03-19 13:59:52 -07:00
Mathias Agopian 29bb60cd94 fix typo that caused a wrong assertion 2024-03-19 13:13:12 -07:00
Mathias Agopian 93b15dac87 The type of geometry of a renderable can now be specified
- dynamic (default) no restriction apply
- static bounds: bounds and world transform can't be changed
- static: additionaly morphing/skinning and vertex/index buffers are
  immutable.

This will allow some optimizations in the future. Currently, we just
store the type but don't do anything with it.
2024-03-19 11:12:25 -07:00
Romain Guy a8fda9b4d0 Make PBR Neutral invertible (#7677)
Based on model-viewer's change at
https://github.com/google/model-viewer/pull/4716
2024-03-19 11:11:44 -07:00
Benjamin Doherty ba9cb2fe43 Release Filament 1.51.0 2024-03-17 13:12:32 -07:00
Sungun Park 0f7cffc407 Connect multiview components together (#7671)
Plumb through multiview configurations to the pipeline so that the
engine draws scenes using multiview extension. Users need to prepare
shaders compiled with the `multiview` param and set the
`stereoscopicType` flag to MULTIVIEW in the Engine::Config to enable
multiview feature.

In this change, postprocessings for multiview are not yet supported. So
we all disable them until they're supported.

The debug option `combineMultiviewImages` combines layers as one image,
which allows us to check the final result.
2024-03-15 22:01:38 +00:00
Mathias Agopian dace5fd695 minor fixes and cleanup to Primitive and BufferInfo factories
- both files use consistent names
- enforce that the keys are not moved around
- don't pass the value (which is 4 bytes) by reference
2024-03-15 11:26:47 -07:00
Powei Feng b23ee1bce4 gltfio: add extended tangents job (#7666)
- TangentsJobExtended extracts data from cgltf accessor and
   runs geometry::TangentSpaceMesh on the attributes and computes
   the tangent space.
 - The /extended folder is meant for running this process. Note that
   this API might remesh the input and will require corresponding
   changes that might break previous assumptions.
 - The general flow of the code is modeled after src/TangentsJob.h
 - This is not hooked into current code and should have no
   practical effect on gltfio.
2024-03-15 17:46:08 +00:00
Mathias Agopian 25f017b883 fix missing headers 2024-03-14 16:41:21 -07:00
Sungun Park 0def77eaa8 Add layerCount to createRenderTarget (#7660)
This new parameter indicates whether the render target will be created
for multiview.

If the value is greater than 1, it tells the render target should be
created for multiview. Otherwise, 1 or 0, it creates a single layer
render target.
2024-03-14 00:38:34 +00:00
Powei Feng 3c25dab22f vk: clean-up initialization of classes (#7667)
Instead of holding pointers to class instances in VulkanDriver,
we standardize by making the relevant classes have proper
constructors and initialize in VulkanDriver's constructor
initializer list.
2024-03-13 23:51:22 +00:00
Mathias Agopian 93a80fd084 More Platform improvements for protected contexts
- `isSwapChainProtected()` is now virtual
- `createDefaultRenderTarget()` is renamed to `getDefaultFramebufferObject()`
- new `getCurrentContextType()` returns the current context type
- `makeCurrent` now takes an additional `ContextType`
- `PlatformEGL::getContextForType()` to retrieve the `EGLContext` for
   a given type.
- `PlatformEGL::makeCurrent` non-virtual utilities to set only the
  context or swapchains.
2024-03-13 16:13:34 -07:00
Mathias Agopian 963e097bdc handle non-0 default FBO with protected contextes 2024-03-13 16:13:34 -07:00
Mathias Agopian 86479781a5 assert when swapchain creation fails
This is better than risking a null-pointer dereference later.
2024-03-13 16:13:34 -07:00
Hanno J. Gödecke 4ea5872b26 fix: applyCrossFade use correct instance 2024-03-13 16:13:01 -07:00
Hanno J. Gödecke f27f0ef4fc fix: apply stashCrossFade to correct entity 2024-03-13 16:13:01 -07:00
Ben Doherty 348454781f Remove erroneous assertion (#7661) 2024-03-12 14:29:49 -07:00
Sungun Park bb6c8ef1c8 Add option FILAMENT_SAMPLES_STEREO_TYPE for samples/gltfio (#7658)
This option can be either "instanced" or "multiview", indicating what
stereoscopic rendering type shaders in samples/gltfio should be built
for.
2024-03-12 13:49:00 -07:00
Powei Feng fa6b4ebd04 gltfio: refactor for clarity (#7652)
- Pull certain utility functions in a separate header and cpp
- Refactor ResourceLoader::loadeResources into smaller methods
2024-03-12 20:31:19 +00:00
Ben Doherty 9aad4df441 Metal: respect disableParallelShaderCompile config (#7659) 2024-03-12 13:06:43 -07:00
Ben Doherty 2e581be8fd Move SwapChain flags into separate file (#7654) 2024-03-12 12:10:43 -07:00
Sungun Park 6d7eaf31d3 Add multiview filamat for default materials (#7644)
Add prebuilt materials for the engine default materials. They'll be
selected for multiview stereoscopic implementation.
2024-03-12 02:50:54 +00:00
Powei Feng dea345d28e geometry: fix mikktspace wrapper (#7651)
- Fix missing attributes in TangentSpaceMesh
- Fix missing reference in MikktspaceImpl.cpp
2024-03-11 22:27:46 +00:00
144 changed files with 3281 additions and 1007 deletions
+17
View File
@@ -45,6 +45,8 @@ option(FILAMENT_ENABLE_TSAN "Enable Thread Sanitizer" OFF)
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
option(FILAMENT_ENABLE_MULTIVIEW "Enable multiview for Filament" OFF)
set(FILAMENT_NDK_VERSION "" CACHE STRING
"Android NDK version or version prefix to be used when building for Android."
)
@@ -531,6 +533,21 @@ else()
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" ON)
endif()
# This only affects the prebuilt shader files in gltfio and samples, not filament library.
# The value can be either "instanced" or "multiview".
set(FILAMENT_SAMPLES_STEREO_TYPE "instanced" CACHE STRING
"Stereoscopic type that shader files in gltfio and samples are built for."
)
string(TOLOWER "${FILAMENT_SAMPLES_STEREO_TYPE}" FILAMENT_SAMPLES_STEREO_TYPE)
if (NOT FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "instanced" AND NOT FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "multiview")
message(FATAL_ERROR "Invalid stereo type: \"${FILAMENT_SAMPLES_STEREO_TYPE}\" choose either \"instanced\" or \"multiview\" ")
endif ()
# Compiling samples for multiview implies enabling multiview feature as well.
if (FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "multiview")
set(FILAMENT_ENABLE_MULTIVIEW ON)
endif ()
# ==================================================================================================
# Material compilation flags
# ==================================================================================================
+2
View File
@@ -7,3 +7,5 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- engine: Add experimental APIs `Engine::builder::paused()` and `Engine::setPaused()`
+3
View File
@@ -7,6 +7,9 @@ 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.51.1
## v1.51.0
- materials: add support for post-lighting mix factor (b/328498606) [⚠️ **New Material Version**]
@@ -391,6 +391,13 @@ Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
engine->flush();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Engine_nSetPaused(JNIEnv*, jclass,
jlong nativeEngine, jboolean paused) {
Engine* engine = (Engine*) nativeEngine;
engine->setPaused(paused);
}
// Managers...
extern "C" JNIEXPORT jlong JNICALL
@@ -487,7 +494,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
jlong jobSystemThreadCount,
jlong textureUseAfterFreePoolSize, jboolean disableParallelShaderCompile,
jint stereoscopicType, jlong stereoscopicEyeCount,
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge) {
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge,
jboolean disableHandleUseAfterFreeCheck) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
Engine::Config config = {
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
@@ -502,6 +510,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
.stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount,
.resourceAllocatorCacheSizeMB = (uint32_t) resourceAllocatorCacheSizeMB,
.resourceAllocatorCacheMaxAge = (uint8_t) resourceAllocatorCacheMaxAge,
.disableHandleUseAfterFreeCheck = (bool) disableHandleUseAfterFreeCheck,
};
builder->config(&config);
}
@@ -518,6 +527,12 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
builder->sharedContext((void*) sharedContext);
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderPaused(
JNIEnv*, jclass, jlong nativeBuilder, jboolean paused) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
builder->paused((bool) paused);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
@@ -104,6 +104,14 @@ Java_com_google_android_filament_RenderableManager_nBuilderGeometry__JIIJJIIII(J
(size_t) count);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nBuilderGeometryType(JNIEnv*, jclass,
jlong nativeBuilder, int type) {
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
builder->geometryType((RenderableManager::Builder::GeometryType)type);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nBuilderMaterial(JNIEnv*, jclass,
@@ -224,7 +224,8 @@ public class Engine {
config.jobSystemThreadCount,
config.textureUseAfterFreePoolSize, config.disableParallelShaderCompile,
config.stereoscopicType.ordinal(), config.stereoscopicEyeCount,
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge);
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge,
config.disableHandleUseAfterFreeCheck);
return this;
}
@@ -239,6 +240,20 @@ public class Engine {
return this;
}
/**
* Sets the initial paused state of the rendering thread.
*
* <p>Warning: This is an experimental API. See {@link Engine#setPaused(boolean)} for
* caveats.
*
* @param paused Whether to start the rendering thread paused.
* @return A reference to this Builder for chaining calls.
*/
public Builder paused(boolean paused) {
nSetBuilderPaused(mNativeBuilder, paused);
return this;
}
/**
* Creates an instance of Engine
*
@@ -408,6 +423,11 @@ public class Engine {
* This value determines for how many frames are texture entries kept in the cache.
*/
public long resourceAllocatorCacheMaxAge = 2;
/*
* Disable backend handles use-after-free checks.
*/
public boolean disableHandleUseAfterFreeCheck = false;
}
private Engine(long nativeEngine, Config config) {
@@ -1189,6 +1209,22 @@ public class Engine {
nFlush(getNativeObject());
}
/**
* Pause or resume the rendering thread.
*
* <p>Warning: This is an experimental API. In particular, note the following caveats.
*
* <ul><li>
* Buffer callbacks will never be called as long as the rendering thread is paused.
* Do not rely on a buffer callback to unpause the thread.
* </li><li>
* While the rendering thread is paused, rendering commands will continue to be queued until the
* buffer limit is reached. When the limit is reached, the program will abort.
* </li></ul>
*/
public void setPaused(boolean paused) {
nSetPaused(getNativeObject(), paused);
}
@UsedByReflection("TextureHelper.java")
public long getNativeObject() {
@@ -1263,6 +1299,7 @@ public class Engine {
private static native void nDestroyEntity(long nativeEngine, int entity);
private static native void nFlushAndWait(long nativeEngine);
private static native void nFlush(long nativeEngine);
private static native void nSetPaused(long nativeEngine, boolean paused);
private static native long nGetTransformManager(long nativeEngine);
private static native long nGetLightManager(long nativeEngine);
private static native long nGetRenderableManager(long nativeEngine);
@@ -1283,8 +1320,10 @@ public class Engine {
long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount,
long textureUseAfterFreePoolSize, boolean disableParallelShaderCompile,
int stereoscopicType, long stereoscopicEyeCount,
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge);
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge,
boolean disableHandleUseAfterFreeCheck);
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
private static native void nSetBuilderPaused(long nativeBuilder, boolean paused);
private static native long nBuilderBuild(long nativeBuilder);
}
@@ -175,6 +175,32 @@ public class RenderableManager {
return this;
}
/**
* Type of geometry for a Renderable
*/
public enum GeometryType {
/** dynamic gemoetry has no restriction */
DYNAMIC,
/** bounds and world space transform are immutable */
STATIC_BOUNDS,
/** skinning/morphing not allowed and Vertex/IndexBuffer immutables */
STATIC
}
/**
* Specify whether this renderable has static bounds. In this context his means that
* the renderable's bounding box cannot change and that the renderable's transform is
* assumed immutable. Changing the renderable's transform via the TransformManager
* can lead to corrupted graphics. Note that skinning and morphing are not forbidden.
* Disabled by default.
* @param enable whether this renderable has static bounds. false by default.
*/
@NonNull
public Builder geometryType(GeometryType type) {
nBuilderGeometryType(mNativeBuilder, type.ordinal());
return this;
}
/**
* Binds a material instance to the specified primitive.
*
@@ -964,6 +990,7 @@ public class RenderableManager {
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer);
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int count);
private static native void nBuilderGeometry(long nativeBuilder, int index, int value, long nativeVertexBuffer, long nativeIndexBuffer, int offset, int minIndex, int maxIndex, int count);
private static native void nBuilderGeometryType(long nativeBuilder, int type);
private static native void nBuilderMaterial(long nativeBuilder, int index, long nativeMaterialInstance);
private static native void nBuilderBlendOrder(long nativeBuilder, int index, int blendOrder);
private static native void nBuilderGlobalBlendOrderEnabled(long nativeBuilder, int index, boolean enabled);
+8
View File
@@ -81,9 +81,17 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/TangentsJob.h
${GLTFIO_DIR}/src/UbershaderProvider.cpp
${GLTFIO_DIR}/src/Utility.cpp
${GLTFIO_DIR}/src/Utility.h
${GLTFIO_DIR}/src/Wireframe.cpp
${GLTFIO_DIR}/src/Wireframe.h
${GLTFIO_DIR}/src/downcast.h
${GLTFIO_DIR}/src/extended/AssetLoaderExtended.h
${GLTFIO_DIR}/src/extended/TangentsJobExtended.cpp
${GLTFIO_DIR}/src/extended/TangentsJobExtended.h
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.cpp
${GLTFIO_DIR}/src/extended/TangentSpaceMeshWrapper.h
src/main/cpp/Animator.cpp
src/main/cpp/AssetLoader.cpp
+1 -1
View File
@@ -516,7 +516,7 @@ function build_android {
if [[ "${BUILD_ANDROID_SAMPLES}" == "true" ]]; then
for sample in ${ANDROID_SAMPLES}; do
echo "Installing out/${sample}-debug.apk"
cp samples/${sample}/build/outputs/apk/debug/${sample}-debug-unsigned.apk \
cp samples/${sample}/build/outputs/apk/debug/${sample}-debug.apk \
../out/${sample}-debug.apk
done
fi
+36 -15
View File
@@ -256,6 +256,11 @@ set(MATERIAL_FL0_SRCS
src/materials/skybox.mat
)
set(MATERIAL_MULTIVIEW_SRCS
src/materials/defaultMaterial.mat
src/materials/skybox.mat
)
# Embed the binary resource blob for materials.
get_resgen_vars(${RESOURCE_DIR} materials)
list(APPEND PRIVATE_HDRS ${RESGEN_HEADER})
@@ -285,6 +290,11 @@ if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
add_definitions(-DFILAMENT_ENABLE_FEATURE_LEVEL_0)
endif()
# Whether to include MULTIVIEW materials.
if (FILAMENT_ENABLE_MULTIVIEW)
add_definitions(-DFILAMENT_ENABLE_MULTIVIEW)
endif()
# ==================================================================================================
# Definitions
# ==================================================================================================
@@ -315,30 +325,41 @@ foreach (mat_src ${MATERIAL_SRCS})
get_filename_component(localname "${mat_src}" NAME_WE)
get_filename_component(fullname "${mat_src}" ABSOLUTE)
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
add_custom_command(
OUTPUT ${output_path}
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
MAIN_DEPENDENCY ${fullname}
DEPENDS matc
COMMENT "Compiling material ${fullname} to ${output_path}"
)
list(APPEND MATERIAL_BINS ${output_path})
list(FIND MATERIAL_FL0_SRCS ${mat_src} index)
if (${index} GREATER -1 AND FILAMENT_ENABLE_FEATURE_LEVEL_0)
string(REGEX REPLACE "[.]filamat$" "0.filamat" output_path0 ${output_path})
string(REGEX REPLACE "[.]filamat$" "_fl0.filamat" output_path_fl0 ${output_path})
add_custom_command(
OUTPUT ${output_path} ${output_path0}
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
COMMAND matc ${MATC_BASE_FLAGS} -PfeatureLevel=0 -o ${output_path0} ${fullname}
OUTPUT ${output_path_fl0}
COMMAND matc ${MATC_BASE_FLAGS} -PfeatureLevel=0 -o ${output_path_fl0} ${fullname}
MAIN_DEPENDENCY ${fullname}
DEPENDS matc
COMMENT "Compiling material ${fullname} to ${output_path} and ${output_path0}"
)
list(APPEND MATERIAL_BINS ${output_path0})
else ()
add_custom_command(
OUTPUT ${output_path}
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
MAIN_DEPENDENCY ${fullname}
DEPENDS matc
COMMENT "Compiling material ${fullname} to ${output_path}"
COMMENT "Compiling material ${fullname} to ${output_path_fl0}"
)
list(APPEND MATERIAL_BINS ${output_path_fl0})
endif ()
list(FIND MATERIAL_MULTIVIEW_SRCS ${mat_src} index)
if (${index} GREATER -1 AND FILAMENT_ENABLE_MULTIVIEW)
string(REGEX REPLACE "[.]filamat$" "_multiview.filamat" output_path_multiview ${output_path})
add_custom_command(
OUTPUT ${output_path_multiview}
COMMAND matc ${MATC_BASE_FLAGS} -PstereoscopicType=multiview -o ${output_path_multiview} ${fullname}
MAIN_DEPENDENCY ${fullname}
DEPENDS matc
COMMENT "Compiling material ${fullname} to ${output_path_multiview}"
)
list(APPEND MATERIAL_BINS ${output_path_multiview})
endif ()
list(APPEND MATERIAL_BINS ${output_path})
endforeach()
# Additional dependencies on included files for materials
@@ -23,6 +23,7 @@
#include <utils/Invocable.h>
#include <stddef.h>
#include <stdint.h>
namespace filament::backend {
@@ -59,6 +60,11 @@ public:
* Currently only honored by the GL and Metal backends.
*/
bool disableParallelShaderCompile = false;
/**
* Disable backend handles use-after-free checks.
*/
bool disableHandleUseAfterFreeCheck = false;
};
Platform() noexcept;
@@ -188,9 +194,40 @@ public:
size_t retrieveBlob(const void* UTILS_NONNULL key, size_t keySize,
void* UTILS_NONNULL value, size_t valueSize);
using DebugUpdateStatFunc = utils::Invocable<void(const char* UTILS_NONNULL key, uint64_t value)>;
/**
* Sets the callback function that the backend can use to update backend-specific statistics
* to aid with debugging. This callback is guaranteed to be called on the Filament driver
* thread.
*
* @param debugUpdateStat an Invocable that updates debug statistics
*/
void setDebugUpdateStatFunc(DebugUpdateStatFunc&& debugUpdateStat) noexcept;
/**
* @return true if debugUpdateStat is valid.
*/
bool hasDebugUpdateStatFunc() const noexcept;
/**
* To track backend-specific statistics, the backend implementation can call the
* application-provided callback function debugUpdateStatFunc to associate or update a value
* with a given key. It is possible for this function to be called multiple times with the
* same key, in which case newer values should overwrite older values.
*
* This function is guaranteed to be called only on a single thread, the Filament driver
* thread.
*
* @param key a null-terminated C-string with the key of the debug statistic
* @param value the updated value of key
*/
void debugUpdateStat(const char* UTILS_NONNULL key, uint64_t value);
private:
InsertBlobFunc mInsertBlob;
RetrieveBlobFunc mRetrieveBlob;
DebugUpdateStatFunc mDebugUpdateStat;
};
} // namespace filament
@@ -116,6 +116,8 @@ public:
Program& cacheId(uint64_t cacheId) noexcept;
Program& multiview(bool multiview) noexcept;
ShaderSource const& getShadersSource() const noexcept { return mShadersSource; }
ShaderSource& getShadersSource() noexcept { return mShadersSource; }
@@ -143,6 +145,8 @@ public:
uint64_t getCacheId() const noexcept { return mCacheId; }
bool isMultiview() const noexcept { return mMultiview; }
CompilerPriorityQueue getPriorityQueue() const noexcept { return mPriorityQueue; }
private:
@@ -158,6 +162,11 @@ private:
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> mAttributes;
std::array<UniformInfo, Program::UNIFORM_BINDING_COUNT> mBindingUniformInfo;
CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH;
// Indicates the current engine was initialized with multiview stereo, and the variant for this
// program contains STE flag. This will be referred later for the OpenGL shader compiler to
// determine whether shader code replacement for the num_views should be performed.
// This variable could be promoted as a more generic variable later if other similar needs occur.
bool mMultiview = false;
};
} // namespace filament::backend
@@ -32,6 +32,10 @@ struct TargetBufferInfo {
// texture to be used as render target
Handle<HwTexture> handle;
// starting layer index for multiview. This value is only used when the `layerCount` for the
// render target is greater than 1.
uint8_t baseViewIndex = 0;
// level to be used
uint8_t level = 0;
@@ -80,7 +84,7 @@ public:
// this is here for backward compatibility
MRT(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: mInfos{{ handle, level, layer }} {
: mInfos{{ handle, 0, level, layer }} {
}
};
@@ -89,7 +89,7 @@ public:
* @return The driver's SwapChain object.
*
*/
virtual SwapChain* UTILS_NONNULL createSwapChain(
virtual SwapChain* UTILS_NULLABLE createSwapChain(
void* UTILS_NULLABLE nativeWindow, uint64_t flags) noexcept = 0;
/**
@@ -126,29 +126,59 @@ public:
virtual TargetBufferFlags getPreservedFlags(SwapChain* UTILS_NONNULL swapChain) noexcept;
/**
* Called by the driver to establish the default FBO. The default implementation returns 0.
* @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object.
* Returns true if the swapchain is protected
*/
virtual uint32_t createDefaultRenderTarget() noexcept;
virtual bool isSwapChainProtected(Platform::SwapChain* UTILS_NONNULL swapChain) noexcept;
/**
* Called by the driver to make the OpenGL context active on the calling thread and bind
* the drawSwapChain to the default render target (FBO) created with createDefaultRenderTarget.
* Called by the driver to establish the default FBO. The default implementation returns 0.
*
* This method can be called either on the regular or protected OpenGL contexts and can return
* a different or identical name, since these names exist in different namespaces.
*
* @return a GLuint casted to a uint32_t that is an OpenGL framebuffer object.
*/
virtual uint32_t getDefaultFramebufferObject() noexcept;
/**
* Type of contexts available
*/
enum class ContextType {
NONE, //!< No current context
UNPROTECTED, //!< current context is unprotected
PROTECTED //!< current context supports protected content
};
/**
* Returns the type of the context currently in use. This value is updated by makeCurrent()
* and therefore can be cached between calls. ContextType::PROTECTED can only be returned
* if isProtectedContextSupported() is true.
* @return ContextType
*/
virtual ContextType getCurrentContextType() const noexcept;
/**
* Binds the requested context to the current thread and drawSwapChain to the default FBO
* returned by getDefaultFramebufferObject().
*
* @param type type of context to bind to the current thread.
* @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO.
* @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`)
* @return true on success, false on error.
*/
virtual void makeCurrent(
virtual bool makeCurrent(ContextType type,
SwapChain* UTILS_NONNULL drawSwapChain,
SwapChain* UTILS_NONNULL readSwapChain) noexcept = 0;
/**
* Called by the driver to make the OpenGL context active on the calling thread and bind
* the drawSwapChain to the default render target (FBO) created with createDefaultRenderTarget.
* the drawSwapChain to the default FBO returned by getDefaultFramebufferObject().
* The context used is either the default context or the protected context. When a context
* change is necessary, the preContextChange and postContextChange callbacks are called,
* before and after the context change respectively. postContextChange is given the index
* of the new context (0 for default and 1 for protected).
* The default implementation just calls makeCurrent(SwapChain*, SwapChain*).
* The default implementation just calls makeCurrent(getCurrentContextType(), SwapChain*, SwapChain*).
*
* @param drawSwapChain SwapChain to draw to. It must be bound to the default FBO.
* @param readSwapChain SwapChain to read from (for operation like `glBlitFramebuffer`)
@@ -57,7 +57,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
void destroyExternalImage(ExternalTexture* texture) noexcept override;
@@ -45,7 +45,7 @@ public:
void terminate() noexcept override;
uint32_t createDefaultRenderTarget() noexcept override;
uint32_t getDefaultFramebufferObject() noexcept override;
bool isExtraContextSupported() const noexcept override;
void createContext(bool shared) override;
@@ -53,7 +53,7 @@ public:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override;
@@ -99,11 +99,18 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
bool isSwapChainProtected(SwapChain* swapChain) noexcept override;
ContextType getCurrentContextType() const noexcept override;
bool makeCurrent(ContextType type,
SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
bool canCreateFence() noexcept override;
@@ -132,21 +139,25 @@ protected:
/**
* Always use this instead of eglMakeCurrent(), as it tracks some state.
*/
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept;
/**
* Returns true if the swapchain is protected
*/
static bool isSwapChainProtected(Platform::SwapChain const* swapChain) noexcept;
EGLContext getContextForType(ContextType type) const noexcept;
// makes the draw and read surface current without changing the current context
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
return egl.makeCurrent(drawSurface, readSurface);
}
// makes context current and set draw and read surfaces to EGL_NO_SURFACE
EGLBoolean makeCurrent(EGLContext context) noexcept {
return egl.makeCurrent(context, mEGLDummySurface, mEGLDummySurface);
}
// TODO: this should probably use getters instead.
EGLDisplay mEGLDisplay = EGL_NO_DISPLAY;
EGLContext mEGLContext = EGL_NO_CONTEXT;
EGLContext mEGLContextProtected = EGL_NO_CONTEXT;
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
EGLContext mCurrentContext = EGL_NO_CONTEXT;
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
ContextType mCurrentContextType = ContextType::NONE;
// mEGLConfig is valid only if ext.egl.KHR_no_config_context is false
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
Config mContextAttribs;
@@ -181,8 +192,20 @@ protected:
EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const;
private:
EGLBoolean makeCurrent(EGLContext context,
EGLSurface drawSurface, EGLSurface readSurface) noexcept;
class EGL {
EGLDisplay& mEGLDisplay;
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
EGLContext mCurrentContext = EGL_NO_CONTEXT;
public:
explicit EGL(EGLDisplay& dpy) : mEGLDisplay(dpy) {}
EGLBoolean makeCurrent(EGLContext context,
EGLSurface drawSurface, EGLSurface readSurface) noexcept;
EGLBoolean makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
return makeCurrent(mCurrentContext, drawSurface, readSurface);
}
} egl{ mEGLDisplay };
};
} // namespace filament::backend
@@ -51,7 +51,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
private:
@@ -53,7 +53,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
protected:
@@ -46,7 +46,7 @@ protected:
SwapChain* createSwapChain(void* nativewindow, uint64_t flags) noexcept override;
SwapChain* createSwapChain(uint32_t width, uint32_t height, uint64_t flags) noexcept override;
void destroySwapChain(SwapChain* swapChain) noexcept override;
void makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override;
void commit(SwapChain* swapChain) noexcept override;
};
@@ -50,12 +50,13 @@ class CommandBufferQueue {
size_t mFreeSpace = 0;
size_t mHighWatermark = 0;
uint32_t mExitRequested = 0;
bool mPaused = false;
static constexpr uint32_t EXIT_REQUESTED = 0x31415926;
public:
// requiredSize: guaranteed available space after flush()
CommandBufferQueue(size_t requiredSize, size_t bufferSize);
CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused);
~CommandBufferQueue();
CircularBuffer& getCircularBuffer() noexcept { return mCircularBuffer; }
@@ -80,6 +81,9 @@ public:
// returns from waitForCommands() immediately.
void requestExit();
// suspend or unsuspend the queue.
void setPaused(bool paused);
bool isExitRequested() const;
};
@@ -239,6 +239,7 @@ DECL_DRIVER_API_R_N(backend::RenderTargetHandle, createRenderTarget,
uint32_t, width,
uint32_t, height,
uint8_t, samples,
uint8_t, layerCount,
backend::MRT, color,
backend::TargetBufferInfo, depth,
backend::TargetBufferInfo, stencil)
@@ -49,7 +49,7 @@ namespace filament::backend {
template<size_t P0, size_t P1, size_t P2>
class HandleAllocator {
public:
HandleAllocator(const char* name, size_t size) noexcept;
HandleAllocator(const char* name, size_t size, bool disableUseAfterFreeCheck) noexcept;
HandleAllocator(HandleAllocator const& rhs) = delete;
HandleAllocator& operator=(HandleAllocator const& rhs) = delete;
~HandleAllocator();
@@ -169,11 +169,13 @@ public:
if (isPoolHandle(handle.getId())) {
// check for use after free
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;
ASSERT_POSTCONDITION(expectedAge == age,
"use-after-free of Handle with id=%d", handle.getId());
if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) {
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;
ASSERT_POSTCONDITION(expectedAge == age,
"use-after-free of Handle with id=%d", handle.getId());
}
}
return static_cast<Dp>(p);
@@ -187,7 +189,6 @@ public:
return handle_cast<Dp>(const_cast<Handle<B>&>(handle));
}
private:
template<typename D>
@@ -210,8 +211,9 @@ private:
Pool<P1> mPool1;
Pool<P2> mPool2;
UTILS_UNUSED_IN_RELEASE const utils::AreaPolicy::HeapArea& mArea;
bool mUseAfterFreeCheckDisabled;
public:
explicit Allocator(const utils::AreaPolicy::HeapArea& area);
explicit Allocator(const utils::AreaPolicy::HeapArea& area, bool disableUseAfterFreeCheck);
static constexpr size_t getAlignment() noexcept { return MIN_ALIGNMENT; }
@@ -237,8 +239,10 @@ private:
// check for double-free
Node* const pNode = static_cast<Node*>(p);
uint8_t& expectedAge = pNode[-1].age;
ASSERT_POSTCONDITION(expectedAge == age,
"double-free of Handle of size %d at %p", size, p);
if (UTILS_UNLIKELY(!mUseAfterFreeCheckDisabled)) {
ASSERT_POSTCONDITION(expectedAge == age,
"double-free of Handle of size %d at %p", size, p);
}
expectedAge = (expectedAge + 1) & 0xF; // fixme
if (size <= mPool0.getSize()) { mPool0.free(p); return; }
@@ -348,6 +352,7 @@ private:
mutable utils::Mutex mLock;
tsl::robin_map<HandleBase::HandleId, void*> mOverflowMap;
HandleBase::HandleId mId = 0;
bool mUseAfterFreeCheckDisabled = false;
};
} // namespace filament::backend
+17 -3
View File
@@ -39,10 +39,11 @@ using namespace utils;
namespace filament::backend {
CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize)
CommandBufferQueue::CommandBufferQueue(size_t requiredSize, size_t bufferSize, bool paused)
: mRequiredSize((requiredSize + (CircularBuffer::getBlockSize() - 1u)) & ~(CircularBuffer::getBlockSize() -1u)),
mCircularBuffer(bufferSize),
mFreeSpace(mCircularBuffer.size()) {
mFreeSpace(mCircularBuffer.size()),
mPaused(paused) {
assert_invariant(mCircularBuffer.size() > requiredSize);
}
@@ -56,6 +57,16 @@ void CommandBufferQueue::requestExit() {
mCondition.notify_one();
}
void CommandBufferQueue::setPaused(bool paused) {
std::lock_guard<utils::Mutex> const lock(mLock);
if (paused) {
mPaused = true;
} else {
mPaused = false;
mCondition.notify_one();
}
}
bool CommandBufferQueue::isExitRequested() const {
std::lock_guard<utils::Mutex> const lock(mLock);
ASSERT_PRECONDITION( mExitRequested == 0 || mExitRequested == EXIT_REQUESTED,
@@ -115,6 +126,9 @@ void CommandBufferQueue::flush() noexcept {
#endif
SYSTRACE_NAME("waiting: CircularBuffer::flush()");
ASSERT_POSTCONDITION(!mPaused,
"CommandStream is full, but since the rendering thread is paused, "
"the buffer cannot flush and we will deadlock. Instead, abort.");
mCondition.wait(lock, [this, requiredSize]() -> bool {
// TODO: on macOS, we need to call pumpEvents from time to time
return mFreeSpace >= requiredSize;
@@ -127,7 +141,7 @@ std::vector<CommandBufferQueue::Range> CommandBufferQueue::waitForCommands() con
return std::move(mCommandBuffersToExecute);
}
std::unique_lock<utils::Mutex> lock(mLock);
while (mCommandBuffersToExecute.empty() && !mExitRequested) {
while ((mCommandBuffersToExecute.empty() || mPaused) && !mExitRequested) {
mCondition.wait(lock);
}
+8 -4
View File
@@ -39,8 +39,10 @@ using namespace utils;
template <size_t P0, size_t P1, size_t P2>
UTILS_NOINLINE
HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& area)
: mArea(area) {
HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& area,
bool disableUseAfterFreeCheck)
: mArea(area),
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) {
// The largest handle this allocator can generate currently depends on the architecture's
// min alignment, typically 8 or 16 bytes.
@@ -74,8 +76,10 @@ HandleAllocator<P0, P1, P2>::Allocator::Allocator(AreaPolicy::HeapArea const& ar
// ------------------------------------------------------------------------------------------------
template <size_t P0, size_t P1, size_t P2>
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size) noexcept
: mHandleArena(name, size) {
HandleAllocator<P0, P1, P2>::HandleAllocator(const char* name, size_t size,
bool disableUseAfterFreeCheck) noexcept
: mHandleArena(name, size, disableUseAfterFreeCheck),
mUseAfterFreeCheckDisabled(disableUseAfterFreeCheck) {
}
template <size_t P0, size_t P1, size_t P2>
+14
View File
@@ -53,4 +53,18 @@ size_t Platform::retrieveBlob(void const* key, size_t keySize, void* value, size
return 0;
}
void Platform::setDebugUpdateStatFunc(DebugUpdateStatFunc&& debugUpdateStat) noexcept {
mDebugUpdateStat = std::move(debugUpdateStat);
}
bool Platform::hasDebugUpdateStatFunc() const noexcept {
return bool(mDebugUpdateStat);
}
void Platform::debugUpdateStat(const char* key, uint64_t value) {
if (mDebugUpdateStat) {
mDebugUpdateStat(key, value);
}
}
} // namespace filament::backend
+5
View File
@@ -91,6 +91,11 @@ Program& Program::cacheId(uint64_t cacheId) noexcept {
return *this;
}
Program& Program::multiview(bool multiview) noexcept {
mMultiview = multiview;
return *this;
}
io::ostream& operator<<(io::ostream& out, const Program& builder) {
out << "Program{";
builder.mLogger(out);
+47 -7
View File
@@ -18,7 +18,6 @@
#define TNT_FILAMENT_DRIVER_METALBUFFER_H
#include "MetalContext.h"
#include "MetalBufferPool.h"
#include <backend/DriverEnums.h>
@@ -28,9 +27,50 @@
#include <utility>
#include <memory>
#include <atomic>
namespace filament::backend {
class TrackedMetalBuffer {
public:
TrackedMetalBuffer() noexcept : mBuffer(nil) {}
TrackedMetalBuffer(id<MTLBuffer> buffer) noexcept : mBuffer(buffer) {
if (buffer) {
aliveBuffers++;
}
}
~TrackedMetalBuffer() {
if (mBuffer) {
aliveBuffers--;
}
}
TrackedMetalBuffer(TrackedMetalBuffer&&) = delete;
TrackedMetalBuffer(TrackedMetalBuffer const&) = delete;
TrackedMetalBuffer& operator=(TrackedMetalBuffer const&) = delete;
TrackedMetalBuffer& operator=(TrackedMetalBuffer&& rhs) noexcept {
swap(rhs);
return *this;
}
id<MTLBuffer> get() const noexcept { return mBuffer; }
operator bool() const noexcept { return bool(mBuffer); }
static uint64_t getAliveBuffers() { return aliveBuffers; }
private:
void swap(TrackedMetalBuffer& other) noexcept {
id<MTLBuffer> temp = mBuffer;
mBuffer = other.mBuffer;
other.mBuffer = temp;
}
id<MTLBuffer> mBuffer;
static std::atomic<uint64_t> aliveBuffers;
};
class MetalBuffer {
public:
@@ -82,7 +122,7 @@ public:
private:
id<MTLBuffer> mBuffer = nil;
TrackedMetalBuffer mBuffer;
size_t mBufferSize = 0;
void* mCpuBuffer = nullptr;
MetalContext& mContext;
@@ -151,7 +191,7 @@ public:
// finishes executing.
mAuxBuffer = [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions];
assert_invariant(mAuxBuffer);
return {mAuxBuffer, 0};
return {mAuxBuffer.get(), 0};
}
mCurrentSlot = (mCurrentSlot + 1) % mSlotCount;
mOccupiedSlots->fetch_add(1, std::memory_order_relaxed);
@@ -180,9 +220,9 @@ public:
*/
std::pair<id<MTLBuffer>, NSUInteger> getCurrentAllocation() const {
if (UTILS_UNLIKELY(mAuxBuffer)) {
return { mAuxBuffer, 0 };
return { mAuxBuffer.get(), 0 };
}
return { mBuffer, mCurrentSlot * mSlotSizeBytes };
return { mBuffer.get(), mCurrentSlot * mSlotSizeBytes };
}
bool canAccomodateLayout(MTLSizeAndAlign layout) const {
@@ -191,8 +231,8 @@ public:
private:
id<MTLDevice> mDevice;
id<MTLBuffer> mBuffer;
id<MTLBuffer> mAuxBuffer;
TrackedMetalBuffer mBuffer;
TrackedMetalBuffer mAuxBuffer;
MTLResourceOptions mBufferOptions;
+7 -4
View File
@@ -15,12 +15,15 @@
*/
#include "MetalBuffer.h"
#include "MetalBufferPool.h"
#include "MetalContext.h"
namespace filament {
namespace backend {
std::atomic<uint64_t> TrackedMetalBuffer::aliveBuffers = 0;
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
// If the buffer is less than 4K in size and is updated frequently, we don't use an explicit
@@ -61,7 +64,7 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
// Acquire a staging buffer to hold the contents of this update.
MetalBufferPool* bufferPool = mContext.bufferPool;
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
memcpy(staging->buffer.contents, src, size);
memcpy(staging->buffer.get().contents, src, size);
// The blit below requires that byteOffset be a multiple of 4.
ASSERT_PRECONDITION(!(byteOffset & 0x3u), "byteOffset must be a multiple of 4");
@@ -70,9 +73,9 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @"Buffer upload blit";
[blitEncoder copyFromBuffer:staging->buffer
[blitEncoder copyFromBuffer:staging->buffer.get()
sourceOffset:0
toBuffer:mBuffer
toBuffer:mBuffer.get()
destinationOffset:byteOffset
size:size];
[blitEncoder endEncoding];
@@ -93,7 +96,7 @@ id<MTLBuffer> MetalBuffer::getGpuBufferForDraw(id<MTLCommandBuffer> cmdBuffer) n
return nil;
}
assert_invariant(mBuffer);
return mBuffer;
return mBuffer.get();
}
void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncoder> encoder,
+3 -1
View File
@@ -19,6 +19,8 @@
#include <Metal/Metal.h>
#include "MetalBuffer.h"
#include <map>
#include <mutex>
#include <unordered_set>
@@ -30,7 +32,7 @@ struct MetalContext;
// Immutable POD representing a shared CPU-GPU buffer.
struct MetalBufferPoolEntry {
id<MTLBuffer> buffer;
TrackedMetalBuffer buffer;
size_t capacity;
mutable uint64_t lastAccessed;
mutable uint32_t referenceCount;
@@ -45,12 +45,12 @@ MetalBufferPoolEntry const* MetalBufferPool::acquireBuffer(size_t numBytes) {
id<MTLBuffer> buffer = [mContext.device newBufferWithLength:numBytes
options:MTLResourceStorageModeShared];
ASSERT_POSTCONDITION(buffer, "Could not allocate Metal staging buffer of size %zu.", numBytes);
MetalBufferPoolEntry* stage = new MetalBufferPoolEntry({
MetalBufferPoolEntry* stage = new MetalBufferPoolEntry {
.buffer = buffer,
.capacity = numBytes,
.lastAccessed = mCurrentFrame,
.referenceCount = 1
});
};
mUsedStages.insert(stage);
return stage;
+9 -2
View File
@@ -20,6 +20,7 @@
#include "metal/MetalDriver.h"
#include "MetalBlitter.h"
#include "MetalBufferPool.h"
#include "MetalContext.h"
#include "MetalDriverFactory.h"
#include "MetalEnums.h"
@@ -36,6 +37,7 @@
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/sstream.h>
#include <algorithm>
@@ -98,7 +100,9 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
: mPlatform(*platform),
mContext(new MetalContext(driverConfig.textureUseAfterFreePoolSize)),
mHandleAllocator("Handles", driverConfig.handleArenaSize) {
mHandleAllocator("Handles",
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck) {
mContext->driver = this;
mContext->device = mPlatform.createDevice();
@@ -212,6 +216,9 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
#if defined(FILAMENT_METAL_PROFILING)
os_signpost_interval_begin(mContext->log, mContext->signpostId, "Frame encoding", "%{public}d", frameId);
#endif
if (mPlatform.hasDebugUpdateStatFunc()) {
mPlatform.debugUpdateStat("filament.metal.alive_buffers", TrackedMetalBuffer::getAliveBuffers());
}
}
void MetalDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
@@ -376,7 +383,7 @@ void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dum
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, MRT color,
uint8_t samples, uint8_t layerCount, MRT color,
TargetBufferInfo depth, TargetBufferInfo stencil) {
ASSERT_PRECONDITION(!isInRenderPass(mContext),
"createRenderTarget must be called outside of a render pass.");
+3 -2
View File
@@ -19,6 +19,7 @@
#include "MetalBlitter.h"
#include "MetalEnums.h"
#include "MetalUtils.h"
#include "MetalBufferPool.h"
#include <filament/SwapChain.h>
@@ -770,13 +771,13 @@ void MetalTexture::loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion
PixelBufferDescriptor const& data, const PixelBufferShape& shape) {
const size_t stagingBufferSize = shape.totalBytes;
auto entry = context.bufferPool->acquireBuffer(stagingBufferSize);
memcpy(entry->buffer.contents,
memcpy(entry->buffer.get().contents,
static_cast<uint8_t*>(data.buffer) + shape.sourceOffset,
stagingBufferSize);
id<MTLCommandBuffer> blitCommandBuffer = getPendingCommandBuffer(&context);
id<MTLBlitCommandEncoder> blitCommandEncoder = [blitCommandBuffer blitCommandEncoder];
blitCommandEncoder.label = @"Texture upload buffer blit";
[blitCommandEncoder copyFromBuffer:entry->buffer
[blitCommandEncoder copyFromBuffer:entry->buffer.get()
sourceOffset:0
sourceBytesPerRow:shape.bytesPerRow
sourceBytesPerImage:shape.bytesPerSlice
+64 -1
View File
@@ -16,11 +16,25 @@
#include "OpenGLContext.h"
#include "GLUtils.h"
#include "OpenGLTimerQuery.h"
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Log.h>
#include <utils/ostream.h>
#include <functional>
#include <string_view>
#include <utility>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
// change to true to display all GL extensions in the console on start-up
#define DEBUG_PRINT_EXTENSIONS false
@@ -49,7 +63,8 @@ bool OpenGLContext::queryOpenGLVersion(GLint* major, GLint* minor) noexcept {
#endif
}
OpenGLContext::OpenGLContext(OpenGLPlatform& platform) noexcept {
OpenGLContext::OpenGLContext(OpenGLPlatform& platform) noexcept
: mPlatform(platform) {
state.vao.p = &mDefaultVAO;
@@ -270,6 +285,9 @@ void OpenGLContext::synchronizeStateAndCache(size_t index) noexcept {
}
}
// the default FBO could be invalid
mDefaultFbo[index].reset();
contextIndex = index;
resetState();
}
@@ -751,6 +769,51 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor)
#endif // BACKEND_OPENGL_VERSION_GL
GLuint OpenGLContext::bindFramebuffer(GLenum target, GLuint buffer) noexcept {
if (UTILS_UNLIKELY(buffer == 0)) {
// we're binding the default frame buffer, resolve its actual name
auto& defaultFboForThisContext = mDefaultFbo[contextIndex];
if (UTILS_UNLIKELY(!defaultFboForThisContext.has_value())) {
defaultFboForThisContext = GLuint(mPlatform.getDefaultFramebufferObject());
}
buffer = defaultFboForThisContext.value();
}
bindFramebufferResolved(target, buffer);
return buffer;
}
void OpenGLContext::unbindFramebuffer(GLenum target) noexcept {
bindFramebufferResolved(target, 0);
}
void OpenGLContext::bindFramebufferResolved(GLenum target, GLuint buffer) noexcept {
switch (target) {
case GL_FRAMEBUFFER:
if (state.draw_fbo != buffer || state.read_fbo != buffer) {
state.draw_fbo = state.read_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
case GL_DRAW_FRAMEBUFFER:
if (state.draw_fbo != buffer) {
state.draw_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
case GL_READ_FRAMEBUFFER:
if (state.read_fbo != buffer) {
state.read_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
#endif
default:
break;
}
}
void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
if (target == GL_ELEMENT_ARRAY_BUFFER) {
constexpr size_t targetIndex = getIndexForBufferTarget(GL_ELEMENT_ARRAY_BUFFER);
+22 -37
View File
@@ -17,24 +17,32 @@
#ifndef TNT_FILAMENT_BACKEND_OPENGLCONTEXT_H
#define TNT_FILAMENT_BACKEND_OPENGLCONTEXT_H
#include <math/vec4.h>
#include "OpenGLTimerQuery.h"
#include <utils/CString.h>
#include <utils/debug.h>
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include "GLUtils.h"
#include "gl_headers.h"
#include <utils/compiler.h>
#include <utils/bitset.h>
#include <utils/debug.h>
#include <math/vec2.h>
#include <math/vec4.h>
#include <array>
#include <functional>
#include <set>
#include <optional>
#include <tuple>
#include <utility>
#include <vector>
#include <stddef.h>
#include <stdint.h>
namespace filament::backend {
class OpenGLPlatform;
@@ -82,7 +90,7 @@ public:
static bool queryOpenGLVersion(GLint* major, GLint* minor) noexcept;
explicit OpenGLContext(OpenGLPlatform& platform) noexcept;
~OpenGLContext() noexcept;
~OpenGLContext() noexcept final;
// TimerQueryInterface ------------------------------------------------------------------------
@@ -148,7 +156,8 @@ public:
inline void bindBufferRange(GLenum target, GLuint index, GLuint buffer,
GLintptr offset, GLsizeiptr size) noexcept;
inline void bindFramebuffer(GLenum target, GLuint buffer) noexcept;
GLuint bindFramebuffer(GLenum target, GLuint buffer) noexcept;
void unbindFramebuffer(GLenum target) noexcept;
inline void enableVertexAttribArray(RenderPrimitive const* rp, GLuint index) noexcept;
inline void disableVertexAttribArray(RenderPrimitive const* rp, GLuint index) noexcept;
@@ -460,10 +469,15 @@ public:
void synchronizeStateAndCache(size_t index) noexcept;
private:
OpenGLPlatform& mPlatform;
ShaderModel mShaderModel = ShaderModel::MOBILE;
FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1;
TimerQueryFactoryInterface* mTimerQueryFactory = nullptr;
std::vector<std::function<void(OpenGLContext&)>> mDestroyWithNormalContext;
RenderPrimitive mDefaultVAO;
std::optional<GLuint> mDefaultFbo[2];
void bindFramebufferResolved(GLenum target, GLuint buffer) noexcept;
const std::array<std::tuple<bool const&, char const*, char const*>, sizeof(bugs)> mBugDatabase{{
{ bugs.disable_glFlush,
@@ -516,8 +530,6 @@ private:
""},
}};
RenderPrimitive mDefaultVAO;
// this is chosen to minimize code size
#if defined(BACKEND_OPENGL_VERSION_GLES)
static void initExtensionsGLES(Extensions* ext, GLint major, GLint minor) noexcept;
@@ -732,33 +744,6 @@ void OpenGLContext::bindBufferRange(GLenum target, GLuint index, GLuint buffer,
#endif
}
void OpenGLContext::bindFramebuffer(GLenum target, GLuint buffer) noexcept {
switch (target) {
case GL_FRAMEBUFFER:
if (state.draw_fbo != buffer || state.read_fbo != buffer) {
state.draw_fbo = state.read_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
case GL_DRAW_FRAMEBUFFER:
if (state.draw_fbo != buffer) {
state.draw_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
case GL_READ_FRAMEBUFFER:
if (state.read_fbo != buffer) {
state.read_fbo = buffer;
glBindFramebuffer(target, buffer);
}
break;
#endif
default:
break;
}
}
void OpenGLContext::bindTexture(GLuint unit, GLuint target, GLuint texId, size_t targetIndex) noexcept {
assert_invariant(targetIndex == getIndexForTextureTarget(target));
assert_invariant(targetIndex < TEXTURE_TARGET_COUNT);
+114 -55
View File
@@ -16,21 +16,54 @@
#include "OpenGLDriver.h"
#include "private/backend/DriverApi.h"
#include "CommandStreamDispatcher.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include "OpenGLDriverFactory.h"
#include "OpenGLProgram.h"
#include "OpenGLTimerQuery.h"
#include "gl_headers.h"
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/SamplerDescriptor.h>
#include <utils/compiler.h>
#include <backend/BufferDescriptor.h>
#include <backend/CallbackHandler.h>
#include <backend/DriverApiForward.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/Platform.h>
#include <backend/Program.h>
#include <backend/SamplerDescriptor.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/Dispatcher.h"
#include "private/backend/DriverApi.h"
#include <utils/BitmaskEnum.h>
#include <utils/CString.h>
#include <utils/Log.h>
#include <utils/Panic.h>
#include <utils/Systrace.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <algorithm>
#include <chrono>
#include <functional>
#include <limits>
#include <memory>
#include <mutex>
#include <new>
#include <utility>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
@@ -172,7 +205,9 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
: mPlatform(*platform),
mContext(mPlatform),
mShaderCompilerService(*this),
mHandleAllocator("Handles", driverConfig.handleArenaSize),
mHandleAllocator("Handles",
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck),
mSamplerMap(32),
mDriverConfig(driverConfig) {
@@ -730,23 +765,23 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
// we can't be here -- doesn't matter what we do
case SamplerType::SAMPLER_2D:
t->gl.target = GL_TEXTURE_2D;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_2D);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D);
break;
case SamplerType::SAMPLER_3D:
t->gl.target = GL_TEXTURE_3D;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_3D);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_3D);
break;
case SamplerType::SAMPLER_2D_ARRAY:
t->gl.target = GL_TEXTURE_2D_ARRAY;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_2D_ARRAY);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D_ARRAY);
break;
case SamplerType::SAMPLER_CUBEMAP:
t->gl.target = GL_TEXTURE_CUBE_MAP;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP);
break;
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
t->gl.target = GL_TEXTURE_CUBE_MAP_ARRAY;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP_ARRAY);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP_ARRAY);
break;
}
@@ -758,7 +793,7 @@ void OpenGLDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
// multi-sample texture on GL 3.2 / GLES 3.1 and above
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
t->gl.targetIndex = (uint8_t)
gl.getIndexForTextureTarget(GL_TEXTURE_2D_MULTISAMPLE);
OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D_MULTISAMPLE);
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
@@ -829,27 +864,27 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
switch (target) {
case SamplerType::SAMPLER_EXTERNAL:
t->gl.target = GL_TEXTURE_EXTERNAL_OES;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_EXTERNAL_OES);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_EXTERNAL_OES);
break;
case SamplerType::SAMPLER_2D:
t->gl.target = GL_TEXTURE_2D;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_2D);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D);
break;
case SamplerType::SAMPLER_3D:
t->gl.target = GL_TEXTURE_3D;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_3D);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_3D);
break;
case SamplerType::SAMPLER_2D_ARRAY:
t->gl.target = GL_TEXTURE_2D_ARRAY;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_2D_ARRAY);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D_ARRAY);
break;
case SamplerType::SAMPLER_CUBEMAP:
t->gl.target = GL_TEXTURE_CUBE_MAP;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP);
break;
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
t->gl.target = GL_TEXTURE_CUBE_MAP_ARRAY;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP_ARRAY);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_CUBE_MAP_ARRAY);
break;
}
@@ -860,7 +895,7 @@ void OpenGLDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
if (gl.features.multisample_texture) {
// multi-sample texture on GL 3.2 / GLES 3.1 and above
t->gl.target = GL_TEXTURE_2D_MULTISAMPLE;
t->gl.targetIndex = (uint8_t)gl.getIndexForTextureTarget(GL_TEXTURE_2D_MULTISAMPLE);
t->gl.targetIndex = OpenGLContext::getIndexForTextureTarget(GL_TEXTURE_2D_MULTISAMPLE);
} else {
// Turn off multi-sampling for that texture. It's just not supported.
}
@@ -901,7 +936,7 @@ void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer
gl.bindBuffer(GL_ARRAY_BUFFER, vb->gl.buffers[bi]);
GLuint const index = i;
GLint const size = getComponentCount(attribute.type);
GLint const size = (GLint)getComponentCount(attribute.type);
GLenum const type = getComponentType(attribute.type);
GLboolean const normalized = getNormalization(attribute.flags & Attribute::FLAG_NORMALIZED);
GLsizei const stride = attribute.stride;
@@ -956,7 +991,7 @@ void OpenGLDriver::updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer
}
void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
GLRenderTarget const* rt, GLenum attachment) noexcept {
GLRenderTarget const* rt, GLenum attachment, uint8_t layerCount) noexcept {
#if !defined(NDEBUG)
// Only used by assert_invariant() checks below
@@ -1094,9 +1129,20 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
// TODO: support multiview for iOS and WebGL
#if !defined(__EMSCRIPTEN__) && !defined(IOS)
if (layerCount > 1) {
// if layerCount > 1, it means we use the multiview extension.
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, attachment,
t->gl.id, 0, binfo.baseViewIndex, layerCount);
} else
#endif // !defined(__EMSCRIPTEN__) && !defined(IOS)
{
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
t->gl.id, binfo.level, binfo.layer);
}
#endif
break;
default:
@@ -1257,11 +1303,9 @@ void OpenGLDriver::createDefaultRenderTargetR(
construct<GLRenderTarget>(rth, 0, 0); // FIXME: we don't know the width/height
uint32_t const framebuffer = mPlatform.createDefaultRenderTarget();
GLRenderTarget* rt = handle_cast<GLRenderTarget*>(rth);
rt->gl.isDefault = true;
rt->gl.fbo = framebuffer;
rt->gl.fbo = 0; // the actual id is resolved at binding time
rt->gl.samples = 1;
// FIXME: these flags should reflect the actual attachments present
rt->targets = TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH;
@@ -1272,6 +1316,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
uint32_t width,
uint32_t height,
uint8_t samples,
uint8_t layerCount,
MRT color,
TargetBufferInfo depth,
TargetBufferInfo stencil) {
@@ -1338,7 +1383,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
if (any(targets & getTargetBufferFlagsAt(i))) {
assert_invariant(color[i].handle);
rt->gl.color[i] = handle_cast<GLTexture*>(color[i].handle);
framebufferTexture(color[i], rt, GL_COLOR_ATTACHMENT0 + i);
framebufferTexture(color[i], rt, GL_COLOR_ATTACHMENT0 + i, layerCount);
bufs[i] = GL_COLOR_ATTACHMENT0 + i;
checkDimensions(rt->gl.color[i], color[i].level);
}
@@ -1360,7 +1405,7 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
// either we supplied only the depth handle or both depth/stencil are identical and not null
if (depth.handle && (stencil.handle == depth.handle || !stencil.handle)) {
rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
framebufferTexture(depth, rt, GL_DEPTH_STENCIL_ATTACHMENT);
framebufferTexture(depth, rt, GL_DEPTH_STENCIL_ATTACHMENT, layerCount);
specialCased = true;
checkDimensions(rt->gl.depth, depth.level);
}
@@ -1371,13 +1416,13 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
if (any(targets & TargetBufferFlags::DEPTH)) {
assert_invariant(depth.handle);
rt->gl.depth = handle_cast<GLTexture*>(depth.handle);
framebufferTexture(depth, rt, GL_DEPTH_ATTACHMENT);
framebufferTexture(depth, rt, GL_DEPTH_ATTACHMENT, layerCount);
checkDimensions(rt->gl.depth, depth.level);
}
if (any(targets & TargetBufferFlags::STENCIL)) {
assert_invariant(stencil.handle);
rt->gl.stencil = handle_cast<GLTexture*>(stencil.handle);
framebufferTexture(stencil, rt, GL_STENCIL_ATTACHMENT);
framebufferTexture(stencil, rt, GL_STENCIL_ATTACHMENT, layerCount);
checkDimensions(rt->gl.stencil, stencil.level);
}
}
@@ -1419,6 +1464,13 @@ void OpenGLDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
sc->swapChain = mPlatform.createSwapChain(nativeWindow, flags);
#if !defined(__EMSCRIPTEN__)
// note: in practice this should never happen on Android
ASSERT_POSTCONDITION(sc->swapChain,
"createSwapChain(%p, 0x%lx) failed. See logs for details.",
nativeWindow, flags);
#endif
// See if we need the emulated rec709 output conversion
if (UTILS_UNLIKELY(mContext.isES2())) {
sc->rec709 = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE &&
@@ -1433,6 +1485,13 @@ void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
GLSwapChain* sc = handle_cast<GLSwapChain*>(sch);
sc->swapChain = mPlatform.createSwapChain(width, height, flags);
#if !defined(__EMSCRIPTEN__)
// note: in practice this should never happen on Android
ASSERT_POSTCONDITION(sc->swapChain,
"createSwapChainHeadless(%u, %u, 0x%lx) failed. See logs for details.",
width, height, flags);
#endif
// See if we need the emulated rec709 output conversion
if (UTILS_UNLIKELY(mContext.isES2())) {
sc->rec709 = (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE &&
@@ -1575,11 +1634,11 @@ void OpenGLDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
GLRenderTarget* rt = handle_cast<GLRenderTarget*>(rth);
if (rt->gl.fbo) {
// first unbind this framebuffer if needed
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.unbindFramebuffer(GL_FRAMEBUFFER);
}
if (rt->gl.fbo_read) {
// first unbind this framebuffer if needed
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
gl.unbindFramebuffer(GL_FRAMEBUFFER);
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
@@ -2413,7 +2472,9 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
size_t const stride = p.stride ? p.stride : width;
size_t const bpp = PBD::computeDataSize(p.format, p.type, 1, 1, 1);
size_t const bpr = PBD::computeDataSize(p.format, p.type, stride, 1, p.alignment);
void const* const buffer = static_cast<char const*>(p.buffer) + p.left * bpp + bpr * p.top;
size_t const bpl = bpr * height; // TODO: PBD should have a "layer stride"
void const* const buffer = static_cast<char const*>(p.buffer)
+ bpp* p.left + bpr * p.top + bpl * 0; // TODO: PBD should have a p.depth
switch (t->target) {
case SamplerType::SAMPLER_EXTERNAL:
@@ -2478,7 +2539,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
if (!gl.isES2()) {
// update the base/max LOD, so we don't access undefined LOD. this allows the app to
// Update the base/max LOD, so we don't access undefined LOD. this allows the app to
// specify levels as they become available.
if (int8_t(level) < t->gl.baseLevel) {
t->gl.baseLevel = int8_t(level);
@@ -2579,7 +2640,7 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
if (!gl.isES2()) {
// update the base/max LOD, so we don't access undefined LOD. this allows the app to
// Update the base/max LOD, so we don't access undefined LOD. this allows the app to
// specify levels as they become available.
if (int8_t(level) < t->gl.baseLevel) {
t->gl.baseLevel = int8_t(level);
@@ -2732,7 +2793,7 @@ TimerQueryResult OpenGLDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
return TimerQueryFactoryInterface::getTimerQueryValue(tq, elapsedTime);
}
void OpenGLDriver::compilePrograms(CompilerPriorityQueue priority,
void OpenGLDriver::compilePrograms(CompilerPriorityQueue,
CallbackHandler* handler, CallbackHandler::Callback callback, void* user) {
if (callback) {
getShaderCompilerService().notifyWhenAllProgramsAreReady(handler, callback, user);
@@ -2760,13 +2821,13 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
const TargetBufferFlags clearFlags = params.flags.clear & rt->targets;
TargetBufferFlags discardFlags = params.flags.discardStart & rt->targets;
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
GLuint const fbo = gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
if (gl.ext.EXT_discard_framebuffer
&& !gl.bugs.disable_invalidate_framebuffer) {
AttachmentArray attachments; // NOLINT
GLsizei const attachmentCount = getAttachments(attachments, rt, discardFlags);
GLsizei const attachmentCount = getAttachments(attachments, discardFlags, !fbo);
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
@@ -2854,9 +2915,9 @@ void OpenGLDriver::endRenderPass(int) {
}
if (!gl.bugs.disable_invalidate_framebuffer) {
// we wouldn't have to bind the framebuffer if we had glInvalidateNamedFramebuffer()
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
GLuint const fbo = gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
AttachmentArray attachments; // NOLINT
GLsizei const attachmentCount = getAttachments(attachments, rt, effectiveDiscardFlags);
GLsizei const attachmentCount = getAttachments(attachments, effectiveDiscardFlags, !fbo);
if (attachmentCount) {
gl.procs.invalidateFramebuffer(GL_FRAMEBUFFER, attachmentCount, attachments.data());
}
@@ -2918,50 +2979,48 @@ void OpenGLDriver::resolvePass(ResolveAction action, GLRenderTarget const* rt,
}
GLsizei OpenGLDriver::getAttachments(AttachmentArray& attachments,
GLRenderTarget const* rt, TargetBufferFlags buffers) noexcept {
assert_invariant(buffers <= rt->targets);
TargetBufferFlags buffers, bool isDefaultFramebuffer) noexcept {
GLsizei attachmentCount = 0;
// the default framebuffer uses different constants!!!
const bool defaultFramebuffer = (rt->gl.fbo == 0);
if (any(buffers & TargetBufferFlags::COLOR0)) {
attachments[attachmentCount++] = defaultFramebuffer ? GL_COLOR : GL_COLOR_ATTACHMENT0;
attachments[attachmentCount++] = isDefaultFramebuffer ? GL_COLOR : GL_COLOR_ATTACHMENT0;
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
if (any(buffers & TargetBufferFlags::COLOR1)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT1;
}
if (any(buffers & TargetBufferFlags::COLOR2)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT2;
}
if (any(buffers & TargetBufferFlags::COLOR3)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT3;
}
if (any(buffers & TargetBufferFlags::COLOR4)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT4;
}
if (any(buffers & TargetBufferFlags::COLOR5)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT5;
}
if (any(buffers & TargetBufferFlags::COLOR6)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT6;
}
if (any(buffers & TargetBufferFlags::COLOR7)) {
assert_invariant(!defaultFramebuffer);
assert_invariant(!isDefaultFramebuffer);
attachments[attachmentCount++] = GL_COLOR_ATTACHMENT7;
}
#endif
if (any(buffers & TargetBufferFlags::DEPTH)) {
attachments[attachmentCount++] = defaultFramebuffer ? GL_DEPTH : GL_DEPTH_ATTACHMENT;
attachments[attachmentCount++] = isDefaultFramebuffer ? GL_DEPTH : GL_DEPTH_ATTACHMENT;
}
if (any(buffers & TargetBufferFlags::STENCIL)) {
attachments[attachmentCount++] = defaultFramebuffer ? GL_STENCIL : GL_STENCIL_ATTACHMENT;
attachments[attachmentCount++] = isDefaultFramebuffer ? GL_STENCIL : GL_STENCIL_ATTACHMENT;
}
return attachmentCount;
}
@@ -3681,8 +3740,8 @@ void OpenGLDriver::blit(
mask, GL_NEAREST);
CHECK_GL_ERROR(utils::slog.e)
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
gl.unbindFramebuffer(GL_DRAW_FRAMEBUFFER);
gl.unbindFramebuffer(GL_READ_FRAMEBUFFER);
glDeleteFramebuffers(2, fbo);
if (any(d->usage & TextureUsage::SAMPLEABLE)) {
+24 -12
View File
@@ -18,31 +18,41 @@
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVER_H
#include "DriverBase.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include "OpenGLTimerQuery.h"
#include "ShaderCompilerService.h"
#include "private/backend/Driver.h"
#include "private/backend/HandleAllocator.h"
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/AcquiredImage.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/Platform.h>
#include <backend/Program.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/Driver.h"
#include "private/backend/HandleAllocator.h"
#include <utils/FixedCapacityVector.h>
#include <utils/compiler.h>
#include <utils/Allocator.h>
#include <utils/debug.h>
#include <math/vec4.h>
#include <tsl/robin_map.h>
#include <atomic>
#include <array>
#include <condition_variable>
#include <functional>
#include <memory>
#include <set>
#include <mutex>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <stddef.h>
#include <stdint.h>
#ifndef FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB
@@ -59,12 +69,14 @@ class OpenGLProgram;
class TimerQueryFactoryInterface;
class OpenGLDriver final : public DriverBase {
inline explicit OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept;
inline explicit OpenGLDriver(OpenGLPlatform* platform,
const Platform::DriverConfig& driverConfig) noexcept;
~OpenGLDriver() noexcept final;
Dispatcher getDispatcher() const noexcept final;
public:
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept;
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext,
const Platform::DriverConfig& driverConfig) noexcept;
class DebugMarker {
OpenGLDriver& driver;
@@ -302,7 +314,7 @@ private:
void updateVertexArrayObject(GLRenderPrimitive* rp, GLVertexBuffer const* vb);
void framebufferTexture(TargetBufferInfo const& binfo,
GLRenderTarget const* rt, GLenum attachment) noexcept;
GLRenderTarget const* rt, GLenum attachment, uint8_t layerCount) noexcept;
void setRasterState(RasterState rs) noexcept;
@@ -357,8 +369,8 @@ private:
}
using AttachmentArray = std::array<GLenum, MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + 2>;
static GLsizei getAttachments(AttachmentArray& attachments,
GLRenderTarget const* rt, TargetBufferFlags buffers) noexcept;
static GLsizei getAttachments(AttachmentArray& attachments, TargetBufferFlags buffers,
bool isDefaultFramebuffer) noexcept;
// state required to represent the current render pass
Handle<HwRenderTarget> mRenderPassTarget;
+11 -3
View File
@@ -40,7 +40,7 @@ OpenGLPlatform::~OpenGLPlatform() noexcept = default;
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
makeCurrent(drawSwapChain, readSwapChain);
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
}
bool OpenGLPlatform::isProtectedContextSupported() const noexcept {
@@ -51,10 +51,14 @@ bool OpenGLPlatform::isSRGBSwapChainSupported() const noexcept {
return false;
}
uint32_t OpenGLPlatform::createDefaultRenderTarget() noexcept {
uint32_t OpenGLPlatform::getDefaultFramebufferObject() noexcept {
return 0;
}
OpenGLPlatform::ContextType OpenGLPlatform::getCurrentContextType() const noexcept {
return ContextType::UNPROTECTED;
}
void OpenGLPlatform::setPresentationTime(
UTILS_UNUSED int64_t presentationTimeInNanosecond) noexcept {
}
@@ -125,10 +129,14 @@ AcquiredImage OpenGLPlatform::transformAcquiredImage(AcquiredImage source) noexc
return source;
}
TargetBufferFlags OpenGLPlatform::getPreservedFlags(UTILS_UNUSED SwapChain* swapChain) noexcept {
TargetBufferFlags OpenGLPlatform::getPreservedFlags(UTILS_UNUSED SwapChain*) noexcept {
return TargetBufferFlags::NONE;
}
bool OpenGLPlatform::isSwapChainProtected(UTILS_UNUSED SwapChain*) noexcept {
return false;
}
bool OpenGLPlatform::isExtraContextSupported() const noexcept {
return false;
}
+11 -2
View File
@@ -16,16 +16,25 @@
#include "OpenGLProgram.h"
#include "BlobCacheKey.h"
#include "GLUtils.h"
#include "OpenGLDriver.h"
#include "ShaderCompilerService.h"
#include <backend/Program.h>
#include <private/backend/BackendUtils.h>
#include <utils/debug.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/Systrace.h>
#include <private/backend/BackendUtils.h>
#include <array>
#include <string_view>
#include <utility>
#include <new>
#include <stddef.h>
namespace filament::backend {
@@ -28,6 +28,9 @@
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <array>
#include <limits>
#include <stddef.h>
#include <stdint.h>
@@ -30,6 +30,7 @@
#include <utils/Log.h>
#include <utils/Systrace.h>
#include <cctype>
#include <chrono>
#include <string>
#include <string_view>
@@ -264,6 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
compileShaders(gl,
std::move(program.getShadersSource()),
program.getSpecializationConstants(),
program.isMultiview(),
shaders,
token->shaderSourceCode);
@@ -299,6 +301,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
compileShaders(gl,
std::move(program.getShadersSource()),
program.getSpecializationConstants(),
program.isMultiview(),
token->gl.shaders,
token->shaderSourceCode);
@@ -501,6 +504,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
void ShaderCompilerService::compileShaders(OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
bool multiview,
std::array<GLuint, Program::SHADER_TYPE_COUNT>& outShaders,
UTILS_UNUSED_IN_RELEASE std::array<CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept {
@@ -514,8 +518,16 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
};
std::string specializationConstantString;
int32_t numViews = 2;
for (auto const& sc : specializationConstants) {
appendSpecConstantString(specializationConstantString, sc);
if (sc.id == 8) {
// This constant must match
// ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT
// which we can't use here because it's defined in EngineEnums.h.
// (we're breaking layering here, but it's for the good cause).
numViews = std::get<int32_t>(sc.value);
}
}
if (!specializationConstantString.empty()) {
specializationConstantString += '\n';
@@ -544,17 +556,23 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
if (UTILS_LIKELY(!shadersSource[i].empty())) {
Program::ShaderBlob& shader = shadersSource[i];
char* shader_src = reinterpret_cast<char*>(shader.data());
size_t shader_len = shader.size();
// remove GOOGLE_cpp_style_line_directive
std::string_view const source = process_GOOGLE_cpp_style_line_directive(context,
reinterpret_cast<char*>(shader.data()), shader.size());
process_GOOGLE_cpp_style_line_directive(context, shader_src, shader_len);
// replace the value of layout(num_views = X) for multiview extension
if (multiview && stage == ShaderStage::VERTEX) {
process_OVR_multiview2(context, numViews, shader_src, shader_len);
}
// add support for ARB_shading_language_packing if needed
auto const packingFunctions = process_ARB_shading_language_packing(context);
// split shader source, so we can insert the specialization constants and the packing
// functions
auto const [prolog, body] = splitShaderSource(source);
auto const [prolog, body] = splitShaderSource({ shader_src, shader_len });
const std::array<const char*, 4> sources = {
prolog.data(),
@@ -577,7 +595,7 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
#ifndef NDEBUG
// for debugging we return the original shader source (without the modifications we
// made here), otherwise the line numbers wouldn't match.
outShaderSourceCode[i] = { source.data(), source.length() };
outShaderSourceCode[i] = { shader_src, shader_len };
#endif
outShaders[i] = shaderId;
@@ -586,15 +604,59 @@ void ShaderCompilerService::compileShaders(OpenGLContext& context,
}
// If usages of the Google-style line directive are present, remove them, as some
// drivers don't allow the quotation marks. This happens in-place.
std::string_view ShaderCompilerService::process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
// drivers don't allow the quotation marks. This source modification happens in-place.
void ShaderCompilerService::process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
char* source, size_t len) noexcept {
if (!context.ext.GOOGLE_cpp_style_line_directive) {
if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension({ source, len }))) {
removeGoogleLineDirectives(source, len); // length is unaffected
}
}
return { source, len };
}
// Look up the `source` to replace the number of eyes for multiview with the given number. This is
// necessary for OpenGL because OpenGL relies on the number specified in shader files to determine
// the number of views, which is assumed as a single digit, for multiview.
// This source modification happens in-place.
void ShaderCompilerService::process_OVR_multiview2(OpenGLContext& context,
int32_t eyeCount, char* source, size_t len) noexcept {
// We don't use regular expression in favor of performance.
if (context.ext.OVR_multiview2) {
const std::string_view shader{ source, len };
const std::string_view layout = "layout";
const std::string_view num_views = "num_views";
size_t found = 0;
while (true) {
found = shader.find(layout, found);
if (found == std::string_view::npos) {
break;
}
found = shader.find_first_not_of(' ', found + layout.size());
if (found == std::string_view::npos || shader[found] != '(') {
continue;
}
found = shader.find_first_not_of(' ', found + 1);
if (found == std::string_view::npos) {
continue;
}
if (shader.compare(found, num_views.size(), num_views) != 0) {
continue;
}
found = shader.find_first_not_of(' ', found + num_views.size());
if (found == std::string_view::npos || shader[found] != '=') {
continue;
}
found = shader.find_first_not_of(' ', found + 1);
if (found == std::string_view::npos) {
continue;
}
// We assume the value should be one-digit number.
assert_invariant(eyeCount < 10);
assert_invariant(!::isdigit(source[found + 1]));
source[found] = '0' + eyeCount;
break;
}
}
}
// Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 (appeared in 4.2) and
@@ -134,10 +134,14 @@ private:
OpenGLContext& context,
Program::ShaderSource shadersSource,
utils::FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
bool multiview,
std::array<GLuint, Program::SHADER_TYPE_COUNT>& outShaders,
std::array<utils::CString, Program::SHADER_TYPE_COUNT>& outShaderSourceCode) noexcept;
static std::string_view process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
static void process_GOOGLE_cpp_style_line_directive(OpenGLContext& context,
char* source, size_t len) noexcept;
static void process_OVR_multiview2(OpenGLContext& context, int32_t eyeCount,
char* source, size_t len) noexcept;
static std::string_view process_ARB_shading_language_packing(OpenGLContext& context) noexcept;
+6 -2
View File
@@ -67,12 +67,14 @@ PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
#ifdef GL_KHR_parallel_shader_compile
PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#endif
#ifdef GL_OVR_multiview
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
// On Android, If we want to support a build system less than ANDROID_API 21, we need to
// use getProcAddress for ES3.1 and above entry points.
PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
static std::once_flag sGlExtInitialized;
#endif // __EMSCRIPTEN__
@@ -118,9 +120,11 @@ void importGLESExtensionsEntryPoints() {
#ifdef GL_KHR_parallel_shader_compile
getProcAddress(glMaxShaderCompilerThreadsKHR, "glMaxShaderCompilerThreadsKHR");
#endif
#ifdef GL_OVR_multiview
getProcAddress(glFramebufferTextureMultiviewOVR, "glFramebufferTextureMultiviewOVR");
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
getProcAddress(glDispatchCompute, "glDispatchCompute");
getProcAddress(glFramebufferTextureMultiviewOVR, "glFramebufferTextureMultiviewOVR");
#endif
});
#endif // __EMSCRIPTEN__
+3 -1
View File
@@ -151,9 +151,11 @@ extern PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
#ifdef GL_KHR_parallel_shader_compile
extern PFNGLMAXSHADERCOMPILERTHREADSKHRPROC glMaxShaderCompilerThreadsKHR;
#endif
#ifdef GL_OVR_multiview
extern PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#if defined(__ANDROID__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
extern PFNGLDISPATCHCOMPUTEPROC glDispatchCompute;
extern PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
#endif
#endif // __EMSCRIPTEN__
} // namespace glext
@@ -247,8 +247,8 @@ void PlatformCocoaGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept
delete cocoaSwapChain;
}
void PlatformCocoaGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain) noexcept {
bool PlatformCocoaGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"ContextManagerCocoa does not support using distinct draw/read swap chains.");
CocoaGLSwapChain* swapChain = (CocoaGLSwapChain*)drawSwapChain;
@@ -287,6 +287,7 @@ void PlatformCocoaGL::makeCurrent(Platform::SwapChain* drawSwapChain,
swapChain->previousBounds = currentBounds;
swapChain->previousWindowFrame = currentWindowFrame;
return true;
}
void PlatformCocoaGL::commit(Platform::SwapChain* swapChain) noexcept {
@@ -143,11 +143,12 @@ void PlatformCocoaTouchGL::destroySwapChain(Platform::SwapChain* swapChain) noex
}
}
uint32_t PlatformCocoaTouchGL::createDefaultRenderTarget() noexcept {
uint32_t PlatformCocoaTouchGL::getDefaultFramebufferObject() noexcept {
return pImpl->mDefaultFramebuffer;
}
void PlatformCocoaTouchGL::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept {
bool PlatformCocoaTouchGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformCocoaTouchGL does not support using distinct draw/read swap chains.");
CAEAGLLayer* const glLayer = (__bridge CAEAGLLayer*) drawSwapChain;
@@ -182,6 +183,7 @@ void PlatformCocoaTouchGL::makeCurrent(SwapChain* drawSwapChain, SwapChain* read
ASSERT_POSTCONDITION(status == GL_FRAMEBUFFER_COMPLETE, "Incomplete framebuffer.");
glBindFramebuffer(GL_FRAMEBUFFER, oldFramebuffer);
}
return true;
}
void PlatformCocoaTouchGL::commit(Platform::SwapChain* swapChain) noexcept {
@@ -25,8 +25,9 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#if defined(__ANDROID__)
#include <EGL/eglplatform.h>
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#endif
#include <utils/compiler.h>
@@ -282,12 +283,14 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
}
}
if (UTILS_UNLIKELY(makeCurrent(mEGLContext, mEGLDummySurface, mEGLDummySurface) == EGL_FALSE)) {
if (UTILS_UNLIKELY(
egl.makeCurrent(mEGLContext, mEGLDummySurface, mEGLDummySurface) == EGL_FALSE)) {
// eglMakeCurrent failed
logEglError("eglMakeCurrent");
goto error;
}
mCurrentContextType = ContextType::UNPROTECTED;
mContextAttribs = std::move(contextAttribs);
initializeGlExtensions();
@@ -362,26 +365,6 @@ void PlatformEGL::releaseContext() noexcept {
eglReleaseThread();
}
EGLBoolean PlatformEGL::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) noexcept {
return makeCurrent(mCurrentContext, drawSurface, readSurface);
}
EGLBoolean PlatformEGL::makeCurrent(EGLContext context,
EGLSurface drawSurface, EGLSurface readSurface) noexcept {
if (UTILS_UNLIKELY((mCurrentContext != context ||
drawSurface != mCurrentDrawSurface || readSurface != mCurrentReadSurface))) {
EGLBoolean const success = eglMakeCurrent(
mEGLDisplay, drawSurface, readSurface, context);
if (success) {
mCurrentDrawSurface = drawSurface;
mCurrentReadSurface = readSurface;
mCurrentContext = context;
}
return success;
}
return EGL_TRUE;
}
void PlatformEGL::terminate() noexcept {
// it's always allowed to use EGL_NO_SURFACE, EGL_NO_CONTEXT
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -468,30 +451,10 @@ bool PlatformEGL::isSRGBSwapChainSupported() const noexcept {
return ext.egl.KHR_gl_colorspace;
}
bool PlatformEGL::isSwapChainProtected(Platform::SwapChain const* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
}
return false;
}
Platform::SwapChain* PlatformEGL::createSwapChain(
void* nativeWindow, uint64_t flags) noexcept {
EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags, true, false);
} else {
config = mEGLConfig;
}
if (UTILS_UNLIKELY(config == EGL_NO_CONFIG_KHR)) {
return nullptr;
}
Config attribs;
if (ext.egl.KHR_gl_colorspace) {
if (flags & SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) {
attribs[EGL_GL_COLORSPACE_KHR] = EGL_GL_COLORSPACE_SRGB_KHR;
@@ -508,16 +471,27 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
flags &= ~SWAP_CHAIN_CONFIG_PROTECTED_CONTENT;
}
EGLSurface sur = eglCreateWindowSurface(mEGLDisplay, config,
(EGLNativeWindowType)nativeWindow, attribs.data());
if (UTILS_UNLIKELY(sur == EGL_NO_SURFACE)) {
logEglError("eglCreateWindowSurface");
return nullptr;
EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags, true, false);
} else {
config = mEGLConfig;
}
// this is not fatal
eglSurfaceAttrib(mEGLDisplay, sur, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
EGLSurface sur = EGL_NO_SURFACE;
if (UTILS_LIKELY(config != EGL_NO_CONFIG_KHR)) {
sur = eglCreateWindowSurface(mEGLDisplay, config,
(EGLNativeWindowType)nativeWindow, attribs.data());
if (UTILS_LIKELY(sur != EGL_NO_SURFACE)) {
// this is not fatal
eglSurfaceAttrib(mEGLDisplay, sur, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
} else {
logEglError("PlatformEGL::createSwapChain: eglCreateWindowSurface");
}
} else {
// error already logged
}
SwapChainEGL* const sc = new(std::nothrow) SwapChainEGL({
.sur = sur,
@@ -532,17 +506,6 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
Platform::SwapChain* PlatformEGL::createSwapChain(
uint32_t width, uint32_t height, uint64_t flags) noexcept {
EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags, false, true);
} else {
config = mEGLConfig;
}
if (UTILS_UNLIKELY(config == EGL_NO_CONFIG_KHR)) {
return nullptr;
}
Config attribs = {
{ EGL_WIDTH, EGLint(width) },
{ EGL_HEIGHT, EGLint(height) },
@@ -564,17 +527,28 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
flags &= ~SWAP_CHAIN_CONFIG_PROTECTED_CONTENT;
}
EGLSurface sur = eglCreatePbufferSurface(mEGLDisplay, config, attribs.data());
EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags, true, false);
} else {
config = mEGLConfig;
}
if (UTILS_UNLIKELY(sur == EGL_NO_SURFACE)) {
logEglError("eglCreatePbufferSurface");
return nullptr;
EGLSurface sur = EGL_NO_SURFACE;
if (UTILS_LIKELY(config != EGL_NO_CONFIG_KHR)) {
sur = eglCreatePbufferSurface(mEGLDisplay, config, attribs.data());
if (UTILS_UNLIKELY(sur == EGL_NO_SURFACE)) {
logEglError("PlatformEGL::createSwapChain: eglCreatePbufferSurface");
}
} else {
// error already logged
}
SwapChainEGL* const sc = new(std::nothrow) SwapChainEGL({
.sur = sur,
.attribs = std::move(attribs),
.config = config
.config = config,
.flags = flags
});
return sc;
}
@@ -583,29 +557,45 @@ void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
if (sc->sur != EGL_NO_SURFACE) {
makeCurrent(mCurrentContext, mEGLDummySurface, mEGLDummySurface);
egl.makeCurrent(mEGLDummySurface, mEGLDummySurface);
eglDestroySurface(mEGLDisplay, sc->sur);
delete sc;
}
}
}
void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain) noexcept {
bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept {
if (swapChain) {
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
}
return false;
}
OpenGLPlatform::ContextType PlatformEGL::getCurrentContextType() const noexcept {
return mCurrentContextType;
}
bool PlatformEGL::makeCurrent(ContextType type,
SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept {
SwapChainEGL const* const dsc = static_cast<SwapChainEGL const*>(drawSwapChain);
SwapChainEGL const* const rsc = static_cast<SwapChainEGL const*>(readSwapChain);
makeCurrent(mEGLContext, dsc->sur, rsc->sur);
EGLContext context = getContextForType(type);
EGLBoolean const success = egl.makeCurrent(context, dsc->sur, rsc->sur);
return success == EGL_TRUE ? true : false;
}
void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain,
utils::Invocable<void()> preContextChange,
utils::Invocable<void(size_t index)> postContextChange) noexcept {
SwapChainEGL const* const dsc = static_cast<SwapChainEGL const*>(drawSwapChain);
SwapChainEGL const* const rsc = static_cast<SwapChainEGL const*>(readSwapChain);
EGLContext context = mEGLContext;
assert_invariant(drawSwapChain);
assert_invariant(readSwapChain);
ContextType type = ContextType::UNPROTECTED;
if (ext.egl.EXT_protected_content) {
bool const swapChainProtected = PlatformEGL::isSwapChainProtected(dsc);
bool const swapChainProtected = isSwapChainProtected(drawSwapChain);
if (UTILS_UNLIKELY(swapChainProtected)) {
// we need a protected context
if (UTILS_UNLIKELY(mEGLContextProtected == EGL_NO_CONTEXT)) {
@@ -622,34 +612,36 @@ void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
goto error;
}
}
context = mEGLContextProtected;
type = ContextType::PROTECTED;
error: ;
}
bool const contextChange = context != mCurrentContext;
bool const contextChange = type != mCurrentContextType;
mCurrentContextType = type;
if (UTILS_UNLIKELY(contextChange)) {
preContextChange();
EGLBoolean const success = makeCurrent(context, dsc->sur, rsc->sur);
bool const success = makeCurrent(mCurrentContextType, drawSwapChain, readSwapChain);
if (UTILS_UNLIKELY(!success)) {
logEglError("PlatformEGL::makeCurrent");
if (mEGLContextProtected != EGL_NO_CONTEXT) {
eglDestroyContext(mEGLDisplay, mEGLContextProtected);
mEGLContextProtected = EGL_NO_CONTEXT;
}
context = mEGLContext;
mCurrentContextType = ContextType::UNPROTECTED;
}
if (UTILS_LIKELY(!swapChainProtected && mEGLContextProtected != EGL_NO_CONTEXT)) {
// We don't need the protected context anymore, unbind and destroy right away.
eglDestroyContext(mEGLDisplay, mEGLContextProtected);
mEGLContextProtected = EGL_NO_CONTEXT;
}
size_t const contextIndex = (context == mEGLContext) ? 0 : 1;
size_t const contextIndex = (mCurrentContextType == ContextType::PROTECTED) ? 1 : 0;
postContextChange(contextIndex);
return;
}
}
EGLBoolean const success = makeCurrent(context, dsc->sur, rsc->sur);
bool const success = makeCurrent(mCurrentContextType, drawSwapChain, readSwapChain);
if (UTILS_UNLIKELY(!success)) {
logEglError("PlatformEGL::makeCurrent");
}
@@ -746,6 +738,17 @@ void PlatformEGL::initializeGlExtensions() noexcept {
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
}
EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept {
switch (type) {
case ContextType::NONE:
return EGL_NO_CONTEXT;
case ContextType::UNPROTECTED:
return mEGLContext;
case ContextType::PROTECTED:
return mEGLContextProtected;
}
}
// ---------------------------------------------------------------------------------------------
PlatformEGL::Config::Config() = default;
@@ -782,4 +785,23 @@ void PlatformEGL::Config::erase(EGLint name) noexcept {
}
}
// ------------------------------------------------------------------------------------------------
EGLBoolean PlatformEGL::EGL::makeCurrent(EGLContext context, EGLSurface drawSurface,
EGLSurface readSurface) noexcept {
if (UTILS_UNLIKELY((
mCurrentContext != context ||
drawSurface != mCurrentDrawSurface || readSurface != mCurrentReadSurface))) {
EGLBoolean const success = eglMakeCurrent(
mEGLDisplay, drawSurface, readSurface, context);
if (success) {
mCurrentDrawSurface = drawSurface;
mCurrentReadSurface = readSurface;
mCurrentContext = context;
}
return success;
}
return EGL_TRUE;
}
} // namespace filament::backend
@@ -142,11 +142,12 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext,
}
void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept {
if (mCurrentDrawSurface != EGL_NO_SURFACE) {
EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
if (currentDrawSurface != EGL_NO_SURFACE) {
if (eglPresentationTimeANDROID) {
eglPresentationTimeANDROID(
mEGLDisplay,
mCurrentDrawSurface,
currentDrawSurface,
presentationTimeInNanosecond);
}
}
@@ -265,10 +265,11 @@ void PlatformGLX::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
}
void PlatformGLX::makeCurrent(
Platform::SwapChain* drawSwapChain, Platform::SwapChain* readSwapChain) noexcept {
bool PlatformGLX::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
g_glx.setCurrentContext(mGLXDisplay,
(GLXDrawable)drawSwapChain, (GLXDrawable)readSwapChain, mGLXContext);
return true;
}
void PlatformGLX::commit(Platform::SwapChain* swapChain) noexcept {
@@ -255,8 +255,8 @@ void PlatformWGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
wglMakeCurrent(mWhdc, mContext);
}
void PlatformWGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain) noexcept {
bool PlatformWGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
ASSERT_PRECONDITION_NON_FATAL(drawSwapChain == readSwapChain,
"PlatformWGL does not support distinct draw/read swap chains.");
@@ -269,6 +269,7 @@ void PlatformWGL::makeCurrent(Platform::SwapChain* drawSwapChain,
wglMakeCurrent(0, NULL);
}
}
return true;
}
void PlatformWGL::commit(Platform::SwapChain* swapChain) noexcept {
@@ -46,8 +46,9 @@ Platform::SwapChain* PlatformWebGL::createSwapChain(
void PlatformWebGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
}
void PlatformWebGL::makeCurrent(Platform::SwapChain* drawSwapChain,
Platform::SwapChain* readSwapChain) noexcept {
bool PlatformWebGL::makeCurrent(ContextType type, SwapChain* drawSwapChain,
SwapChain* readSwapChain) noexcept {
return true;
}
void PlatformWebGL::commit(Platform::SwapChain* swapChain) noexcept {
@@ -154,15 +154,9 @@ struct BlitterUniforms {
}// anonymous namespace
VulkanBlitter::VulkanBlitter() noexcept = default;
void VulkanBlitter::initialize(VkPhysicalDevice physicalDevice, VkDevice device,
VmaAllocator allocator, VulkanCommands* commands) noexcept {
mPhysicalDevice = physicalDevice;
mDevice = device;
mAllocator = allocator;
mCommands = commands;
}
VulkanBlitter::VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept
: mPhysicalDevice(physicalDevice),
mCommands(commands) {}
void VulkanBlitter::resolve(VulkanAttachment dst, VulkanAttachment src) {
+1 -6
View File
@@ -32,10 +32,7 @@ struct VulkanProgram;
class VulkanBlitter {
public:
VulkanBlitter() noexcept;
void initialize(VkPhysicalDevice physicalDevice, VkDevice device,
VmaAllocator allocator, VulkanCommands* commands) noexcept;
VulkanBlitter(VkPhysicalDevice physicalDevice, VulkanCommands* commands) noexcept;
void blit(VkFilter filter,
VulkanAttachment dst, const VkOffset3D* dstRectPair,
@@ -47,8 +44,6 @@ public:
private:
UTILS_UNUSED VkPhysicalDevice mPhysicalDevice;
VkDevice mDevice;
VmaAllocator mAllocator;
VulkanCommands* mCommands;
};
@@ -155,7 +155,7 @@ VulkanCommands::VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFam
#endif
}
VulkanCommands::~VulkanCommands() {
void VulkanCommands::terminate() {
wait();
gc();
vkDestroyCommandPool(mDevice, mPool, VKALLOC);
+48 -47
View File
@@ -139,71 +139,72 @@ public:
// - We do this because vkGetFenceStatus must be called from the rendering thread.
//
class VulkanCommands {
public:
VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex,
VulkanContext* context, VulkanResourceAllocator* allocator);
~VulkanCommands();
public:
VulkanCommands(VkDevice device, VkQueue queue, uint32_t queueFamilyIndex,
VulkanContext* context, VulkanResourceAllocator* allocator);
// Creates a "current" command buffer if none exists, otherwise returns the current one.
VulkanCommandBuffer& get();
void terminate();
// Submits the current command buffer if it exists, then sets "current" to null.
// If there are no outstanding commands then nothing happens and this returns false.
bool flush();
// Creates a "current" command buffer if none exists, otherwise returns the current one.
VulkanCommandBuffer& get();
// Returns the "rendering finished" semaphore for the most recent flush and removes
// it from the existing dependency chain. This is especially useful for setting up
// vkQueuePresentKHR.
VkSemaphore acquireFinishedSignal();
// Submits the current command buffer if it exists, then sets "current" to null.
// If there are no outstanding commands then nothing happens and this returns false.
bool flush();
// Takes a semaphore that signals when the next flush can occur. Only one injected
// semaphore is allowed per flush. Useful after calling vkAcquireNextImageKHR.
void injectDependency(VkSemaphore next);
// Returns the "rendering finished" semaphore for the most recent flush and removes
// it from the existing dependency chain. This is especially useful for setting up
// vkQueuePresentKHR.
VkSemaphore acquireFinishedSignal();
// Destroys all command buffers that are no longer in use.
void gc();
// Takes a semaphore that signals when the next flush can occur. Only one injected
// semaphore is allowed per flush. Useful after calling vkAcquireNextImageKHR.
void injectDependency(VkSemaphore next);
// Waits for all outstanding command buffers to finish.
void wait();
// Destroys all command buffers that are no longer in use.
void gc();
// Updates the atomic "status" variable in every extant fence.
void updateFences();
// Waits for all outstanding command buffers to finish.
void wait();
// Sets an observer who is notified every time a new command buffer has been made "current".
// The observer's event handler can only be called during get().
void setObserver(CommandBufferObserver* observer) { mObserver = observer; }
// Updates the atomic "status" variable in every extant fence.
void updateFences();
// Sets an observer who is notified every time a new command buffer has been made "current".
// The observer's event handler can only be called during get().
void setObserver(CommandBufferObserver* observer) { mObserver = observer; }
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
void pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp = {});
void pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp = {});
void popGroupMarker();
void popGroupMarker();
void insertEventMarker(char const* string, uint32_t len);
void insertEventMarker(char const* string, uint32_t len);
std::string getTopGroupMarker() const;
std::string getTopGroupMarker() const;
#endif
private:
static constexpr int CAPACITY = FVK_MAX_COMMAND_BUFFERS;
VkDevice const mDevice;
VkQueue const mQueue;
VkCommandPool const mPool;
VulkanContext const* mContext;
private:
static constexpr int CAPACITY = FVK_MAX_COMMAND_BUFFERS;
VkDevice const mDevice;
VkQueue const mQueue;
VkCommandPool const mPool;
VulkanContext const* mContext;
// int8 only goes up to 127, therefore capacity must be less than that.
static_assert(CAPACITY < 128);
int8_t mCurrentCommandBufferIndex = -1;
VkSemaphore mSubmissionSignal = {};
VkSemaphore mInjectedSignal = {};
utils::FixedCapacityVector<std::unique_ptr<VulkanCommandBuffer>> mStorage;
VkFence mFences[CAPACITY] = {};
VkSemaphore mSubmissionSignals[CAPACITY] = {};
uint8_t mAvailableBufferCount = CAPACITY;
CommandBufferObserver* mObserver = nullptr;
// int8 only goes up to 127, therefore capacity must be less than that.
static_assert(CAPACITY < 128);
int8_t mCurrentCommandBufferIndex = -1;
VkSemaphore mSubmissionSignal = {};
VkSemaphore mInjectedSignal = {};
utils::FixedCapacityVector<std::unique_ptr<VulkanCommandBuffer>> mStorage;
VkFence mFences[CAPACITY] = {};
VkSemaphore mSubmissionSignals[CAPACITY] = {};
uint8_t mAvailableBufferCount = CAPACITY;
CommandBufferObserver* mObserver = nullptr;
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
std::unique_ptr<VulkanGroupMarkers> mGroupMarkers;
std::unique_ptr<VulkanGroupMarkers> mCarriedOverMarkers;
std::unique_ptr<VulkanGroupMarkers> mGroupMarkers;
std::unique_ptr<VulkanGroupMarkers> mCarriedOverMarkers;
#endif
};
@@ -43,9 +43,12 @@
// Enables Android systrace
#define FVK_DEBUG_SYSTRACE 0x00000001
// Group markers are used to denote collection of GPU commands. It is typically at the granualarity
// of a renderpass.
#define FVK_DEBUG_GROUP_MARKERS 0x00000002
// Group markers are used to denote collections of GPU commands. It is typically at the
// granualarity of a renderpass. You can enable this along with FVK_DEBUG_DEBUG_UTILS to take
// advantage of vkCmdBegin/EndDebugUtilsLabelEXT. You can also just enable this with
// FVK_DEBUG_PRINT_GROUP_MARKERS to print the current marker to stdout.
#define FVK_DEBUG_GROUP_MARKERS 0x00000002
#define FVK_DEBUG_TEXTURE 0x00000004
#define FVK_DEBUG_LAYOUT_TRANSITION 0x00000008
#define FVK_DEBUG_COMMAND_BUFFER 0x00000010
@@ -63,9 +66,11 @@
// Enable the debug utils extension if it is available.
#define FVK_DEBUG_DEBUG_UTILS 0x00008000
// Use this to debug potential Handle/Resource leakage. It will print out reference counts for all
// the currently active resources.
#define FVK_DEBUG_RESOURCE_LEAK 0x00010000
// Usefaul default combinations
// Useful default combinations
#define FVK_DEBUG_EVERYTHING 0xFFFFFFFF
#define FVK_DEBUG_PERFORMANCE \
FVK_DEBUG_SYSTRACE
+48 -49
View File
@@ -209,10 +209,16 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mAllocator(createAllocator(mPlatform->getInstance(), mPlatform->getPhysicalDevice(),
mPlatform->getDevice())),
mContext(context),
mResourceAllocator(driverConfig.handleArenaSize),
mResourceAllocator(driverConfig.handleArenaSize, driverConfig.disableHandleUseAfterFreeCheck),
mResourceManager(&mResourceAllocator),
mThreadSafeResourceManager(&mResourceAllocator),
mCommands(mPlatform->getDevice(), mPlatform->getGraphicsQueue(),
mPlatform->getGraphicsQueueFamilyIndex(), &mContext, &mResourceAllocator),
mPipelineCache(&mResourceAllocator),
mStagePool(mAllocator, &mCommands),
mFramebufferCache(mPlatform->getDevice()),
mSamplerCache(mPlatform->getDevice()),
mBlitter(mPlatform->getPhysicalDevice(), &mCommands),
mReadPixels(mPlatform->getDevice()),
mIsSRGBSwapChainSupported(mPlatform->getCustomization().isSRGBSwapChainSupported) {
@@ -237,23 +243,13 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
#endif
mTimestamps = std::make_unique<VulkanTimestamps>(mPlatform->getDevice());
mCommands = std::make_unique<VulkanCommands>(mPlatform->getDevice(),
mPlatform->getGraphicsQueue(), mPlatform->getGraphicsQueueFamilyIndex(), &mContext,
&mResourceAllocator);
mCommands->setObserver(&mPipelineCache);
mCommands.setObserver(&mPipelineCache);
mPipelineCache.setDevice(mPlatform->getDevice(), mAllocator);
// TOOD: move them all to be initialized by constructor
mStagePool.initialize(mAllocator, mCommands.get());
mFramebufferCache.initialize(mPlatform->getDevice());
mSamplerCache.initialize(mPlatform->getDevice());
mEmptyTexture.reset(createEmptyTexture(mPlatform->getDevice(), mPlatform->getPhysicalDevice(),
mContext, mAllocator, mCommands.get(), mStagePool));
mEmptyTexture = createEmptyTexture(mPlatform->getDevice(), mPlatform->getPhysicalDevice(),
mContext, mAllocator, &mCommands, mStagePool);
mPipelineCache.setDummyTexture(mEmptyTexture->getPrimaryImageView());
mBlitter.initialize(mPlatform->getPhysicalDevice(), mPlatform->getDevice(), mAllocator,
mCommands.get());
}
VulkanDriver::~VulkanDriver() noexcept = default;
@@ -316,8 +312,11 @@ ShaderModel VulkanDriver::getShaderModel() const noexcept {
void VulkanDriver::terminate() {
// Command buffers should come first since it might have commands depending on resources that
// are about to be destroyed.
mCommands.reset();
mEmptyTexture.reset();
mCommands.terminate();
delete mEmptyTexture;
mResourceManager.clear();
mTimestamps.reset();
mBlitter.terminate();
@@ -346,7 +345,7 @@ void VulkanDriver::terminate() {
}
void VulkanDriver::tick(int) {
mCommands->updateFences();
mCommands.updateFences();
}
// Garbage collection should not occur too frequently, only about once per frame. Internally, the
@@ -358,7 +357,7 @@ void VulkanDriver::collectGarbage() {
FVK_SYSTRACE_START("gc");
// Command buffers need to be submitted and completed before other resources can be gc'd. And
// its gc() function carrys out the *wait*.
mCommands->gc();
mCommands.gc();
mStagePool.gc();
mFramebufferCache.gc();
@@ -386,7 +385,7 @@ void VulkanDriver::setPresentationTime(int64_t monotonic_clock_ns) {
void VulkanDriver::endFrame(uint32_t frameId) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("endframe");
mCommands->flush();
mCommands.flush();
collectGarbage();
FVK_SYSTRACE_END();
}
@@ -394,7 +393,7 @@ void VulkanDriver::endFrame(uint32_t frameId) {
void VulkanDriver::flush(int) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("flush");
mCommands->flush();
mCommands.flush();
FVK_SYSTRACE_END();
}
@@ -402,8 +401,8 @@ void VulkanDriver::finish(int dummy) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("finish");
mCommands->flush();
mCommands->wait();
mCommands.flush();
mCommands.wait();
mReadPixels.runUntilComplete();
FVK_SYSTRACE_END();
@@ -500,7 +499,7 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage) {
auto vktexture = mResourceAllocator.construct<VulkanTexture>(th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, mCommands.get(), target, levels,
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, target, levels,
format, samples, w, h, depth, usage, mStagePool);
mResourceManager.acquire(vktexture);
}
@@ -512,7 +511,7 @@ void VulkanDriver::createTextureSwizzledR(Handle<HwTexture> th, SamplerType targ
TextureSwizzle swizzleArray[] = {r, g, b, a};
const VkComponentMapping swizzleMap = getSwizzleMap(swizzleArray);
auto vktexture = mResourceAllocator.construct<VulkanTexture>(th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, mCommands.get(), target, levels,
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, target, levels,
format, samples, w, h, depth, usage, mStagePool, false /*heap allocated */, swizzleMap);
mResourceManager.acquire(vktexture);
}
@@ -555,7 +554,7 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples,
MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) {
uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil) {
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = {std::numeric_limits<uint32_t>::max()};
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = {0};
UTILS_UNUSED_IN_RELEASE size_t attachmentCount = 0;
@@ -607,7 +606,7 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
assert_invariant(tmin.x >= width && tmin.y >= height);
auto renderTarget = mResourceAllocator.construct<VulkanRenderTarget>(rth, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, mCommands.get(), width, height,
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, width, height,
samples, colorTargets, depthStencil, mStagePool);
mResourceManager.acquire(renderTarget);
}
@@ -625,7 +624,7 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
}
void VulkanDriver::createFenceR(Handle<HwFence> fh, int) {
VulkanCommandBuffer const& commandBuffer = mCommands->get();
VulkanCommandBuffer const& commandBuffer = mCommands.get();
mResourceAllocator.construct<VulkanFence>(fh, commandBuffer.fence);
}
@@ -636,7 +635,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
}
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
mAllocator, mCommands.get(), mStagePool, nativeWindow, flags);
mAllocator, &mCommands, mStagePool, nativeWindow, flags);
mResourceManager.acquire(swapChain);
}
@@ -649,7 +648,7 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
}
assert_invariant(width > 0 && height > 0 && "Vulkan requires non-zero swap chain dimensions.");
auto swapChain = mResourceAllocator.construct<VulkanSwapChain>(sch, mPlatform, mContext,
mAllocator, mCommands.get(), mStagePool, nullptr, flags, VkExtent2D{width, height});
mAllocator, &mCommands, mStagePool, nullptr, flags, VkExtent2D{width, height});
mResourceManager.acquire(swapChain);
}
@@ -994,7 +993,7 @@ void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands->get();
VulkanCommandBuffer& commands = mCommands.get();
auto ib = mResourceAllocator.handle_cast<VulkanIndexBuffer*>(ibh);
commands.acquire(ib);
ib->buffer.loadFromCpu(commands.buffer(), p.buffer, byteOffset, p.size);
@@ -1004,7 +1003,7 @@ void VulkanDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor
void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& bd,
uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands->get();
VulkanCommandBuffer& commands = mCommands.get();
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
commands.acquire(bo);
@@ -1015,7 +1014,7 @@ void VulkanDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescript
void VulkanDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset) {
VulkanCommandBuffer& commands = mCommands->get();
VulkanCommandBuffer& commands = mCommands.get();
auto bo = mResourceAllocator.handle_cast<VulkanBufferObject*>(boh);
commands.acquire(bo);
// TODO: implement unsynchronized version
@@ -1180,7 +1179,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
// If that's the case, we need to change the layout of the texture to DEPTH_SAMPLER, which is a
// more general layout. Otherwise, we prefer the DEPTH_ATTACHMENT layout, which is optimal for
// the non-sampling case.
VulkanCommandBuffer& commands = mCommands->get();
VulkanCommandBuffer& commands = mCommands.get();
VkCommandBuffer const cmdbuffer = commands.buffer();
UTILS_NOUNROLL
@@ -1307,7 +1306,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
// Assign a label to the framebuffer for debugging purposes.
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS | FVK_DEBUG_DEBUG_UTILS)
auto const topMarker = mCommands->getTopGroupMarker();
auto const topMarker = mCommands.getTopGroupMarker();
if (!topMarker.empty()) {
DebugUtils::setName(VK_OBJECT_TYPE_FRAMEBUFFER, reinterpret_cast<uint64_t>(vkfb),
topMarker.c_str());
@@ -1396,7 +1395,7 @@ void VulkanDriver::endRenderPass(int) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("endRenderPass");
VulkanCommandBuffer& commands = mCommands->get();
VulkanCommandBuffer& commands = mCommands.get();
VkCommandBuffer cmdbuffer = commands.buffer();
vkCmdEndRenderPass(cmdbuffer);
@@ -1449,7 +1448,7 @@ void VulkanDriver::nextSubpass(int) {
assert_invariant(renderTarget);
assert_invariant(mCurrentRenderPass.params.subpassMask);
vkCmdNextSubpass(mCommands->get().buffer(), VK_SUBPASS_CONTENTS_INLINE);
vkCmdNextSubpass(mCommands.get().buffer(), VK_SUBPASS_CONTENTS_INLINE);
mPipelineCache.bindRenderPass(mCurrentRenderPass.renderPass,
++mCurrentRenderPass.currentSubpass);
@@ -1530,14 +1529,14 @@ void VulkanDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
void VulkanDriver::insertEventMarker(char const* string, uint32_t len) {
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
mCommands->insertEventMarker(string, len);
mCommands.insertEventMarker(string, len);
#endif
}
void VulkanDriver::pushGroupMarker(char const* string, uint32_t) {
// Turns out all the markers are 0-terminated, so we can just pass it without len.
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
mCommands->pushGroupMarker(string);
mCommands.pushGroupMarker(string);
#endif
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START(string);
@@ -1545,7 +1544,7 @@ void VulkanDriver::pushGroupMarker(char const* string, uint32_t) {
void VulkanDriver::popGroupMarker(int) {
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
mCommands->popGroupMarker();
mCommands.popGroupMarker();
#endif
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_END();
@@ -1558,7 +1557,7 @@ void VulkanDriver::stopCapture(int) {}
void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y, uint32_t width,
uint32_t height, PixelBufferDescriptor&& pbd) {
VulkanRenderTarget* srcTarget = mResourceAllocator.handle_cast<VulkanRenderTarget*>(src);
mCommands->flush();
mCommands.flush();
mReadPixels.run(
srcTarget, x, y, width, height, mPlatform->getGraphicsQueueFamilyIndex(),
std::move(pbd),
@@ -1715,7 +1714,7 @@ void VulkanDriver::bindPipeline(PipelineState pipelineState) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("draw");
VulkanCommandBuffer* commands = &mCommands->get();
VulkanCommandBuffer* commands = &mCommands.get();
const VulkanVertexBufferInfo& vbi =
*mResourceAllocator.handle_cast<VulkanVertexBufferInfo*>(pipelineState.vertexBufferInfo);
@@ -1814,7 +1813,7 @@ void VulkanDriver::bindPipeline(PipelineState pipelineState) {
utils::slog.w << " in material '" << program->name.c_str() << "'";
utils::slog.w << " at binding point " << +binding << utils::io::endl;
#endif
texture = mEmptyTexture.get();
texture = mEmptyTexture;
}
SamplerParams const& samplerParams = boundSampler->s;
@@ -1861,7 +1860,7 @@ void VulkanDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("bindRenderPrimitive");
VulkanCommandBuffer* commands = &mCommands->get();
VulkanCommandBuffer* commands = &mCommands.get();
VkCommandBuffer cmdbuffer = commands->buffer();
const VulkanRenderPrimitive& prim = *mResourceAllocator.handle_cast<VulkanRenderPrimitive*>(rph);
commands->acquire(prim.indexBuffer);
@@ -1890,8 +1889,8 @@ void VulkanDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t ins
FVK_SYSTRACE_CONTEXT();
FVK_SYSTRACE_START("draw2");
VulkanCommandBuffer* commands = &mCommands->get();
VkCommandBuffer cmdbuffer = commands->buffer();
VulkanCommandBuffer& commands = mCommands.get();
VkCommandBuffer cmdbuffer = commands.buffer();
// Bind new descriptor sets if they need to change.
// If descriptor set allocation failed, skip the draw call and bail. No need to emit an error
@@ -1925,8 +1924,8 @@ void VulkanDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGr
}
void VulkanDriver::scissor(Viewport scissorBox) {
VulkanCommandBuffer* commands = &mCommands->get();
VkCommandBuffer cmdbuffer = commands->buffer();
VulkanCommandBuffer& commands = mCommands.get();
VkCommandBuffer cmdbuffer = commands.buffer();
// Set scissoring.
// clamp left-bottom to 0,0 and avoid overflows
@@ -1953,12 +1952,12 @@ void VulkanDriver::scissor(Viewport scissorBox) {
void VulkanDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
VulkanTimerQuery* vtq = mResourceAllocator.handle_cast<VulkanTimerQuery*>(tqh);
mTimestamps->beginQuery(&(mCommands->get()), vtq);
mTimestamps->beginQuery(&(mCommands.get()), vtq);
}
void VulkanDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
VulkanTimerQuery* vtq = mResourceAllocator.handle_cast<VulkanTimerQuery*>(tqh);
mTimestamps->endQuery(&(mCommands->get()), vtq);
mTimestamps->endQuery(&(mCommands.get()), vtq);
}
void VulkanDriver::debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
+3 -2
View File
@@ -104,9 +104,9 @@ private:
void collectGarbage();
VulkanPlatform* mPlatform = nullptr;
std::unique_ptr<VulkanCommands> mCommands;
std::unique_ptr<VulkanTimestamps> mTimestamps;
std::unique_ptr<VulkanTexture> mEmptyTexture;
VulkanTexture* mEmptyTexture;
VulkanSwapChain* mCurrentSwapChain = nullptr;
VulkanRenderTarget* mDefaultRenderTarget = nullptr;
@@ -122,6 +122,7 @@ private:
// thread.
VulkanThreadSafeResourceManager mThreadSafeResourceManager;
VulkanCommands mCommands;
VulkanPipelineCache mPipelineCache;
VulkanStagePool mStagePool;
VulkanFboCache mFramebufferCache;
@@ -64,7 +64,8 @@ bool VulkanFboCache::FboKeyEqualFn::operator()(const FboKey& k1, const FboKey& k
return true;
}
void VulkanFboCache::initialize(VkDevice device) noexcept { mDevice = device; }
VulkanFboCache::VulkanFboCache(VkDevice device)
: mDevice(device) {}
VulkanFboCache::~VulkanFboCache() {
ASSERT_POSTCONDITION(mFramebufferCache.empty() && mRenderPassCache.empty(),
@@ -238,7 +239,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
.format = config.colorFormat[i],
.samples = (VkSampleCountFlagBits) config.samples,
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
.storeOp = config.samples == 1 ? kEnableStore : kDisableStore,
.storeOp = kEnableStore,
.stencilLoadOp = kDontCare,
.stencilStoreOp = kDisableStore,
.initialLayout = ((!discard && config.initialColorLayoutMask & (1 << i)) || clear)
+1 -2
View File
@@ -104,10 +104,9 @@ public:
bool operator()(const FboKey& k1, const FboKey& k2) const;
};
explicit VulkanFboCache(VkDevice device);
~VulkanFboCache();
void initialize(VkDevice device) noexcept;
// Retrieves or creates a VkFramebuffer handle.
VkFramebuffer getFramebuffer(FboKey config) noexcept;
+5 -1
View File
@@ -77,7 +77,11 @@ private:
struct PipelineInfo {
PipelineInfo()
: bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff) {}
: bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff)
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
, bindingToName(MAX_SAMPLER_COUNT, "")
#endif
{}
// This bitset maps to each of the sampler in the sampler groups associated with this
// program, and whether each sampler is used in which shader (i.e. vert, frag, compute).
@@ -51,8 +51,8 @@ namespace filament::backend {
class VulkanResourceAllocator {
public:
VulkanResourceAllocator(size_t arenaSize)
: mHandleAllocatorImpl("Handles", arenaSize)
VulkanResourceAllocator(size_t arenaSize, bool disableUseAfterFreeCheck)
: mHandleAllocatorImpl("Handles", arenaSize, disableUseAfterFreeCheck)
#if DEBUG_RESOURCE_LEAKS
, mDebugOnlyResourceCount(RESOURCE_TYPE_COUNT) {
std::memset(mDebugOnlyResourceCount.data(), 0, sizeof(size_t) * RESOURCE_TYPE_COUNT);
@@ -95,7 +95,8 @@ constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept {
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
}
void VulkanSamplerCache::initialize(VkDevice device) { mDevice = device; }
VulkanSamplerCache::VulkanSamplerCache(VkDevice device)
: mDevice(device) {}
VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept {
auto iter = mCache.find(params);
@@ -27,7 +27,7 @@ namespace filament::backend {
// Simple manager for VkSampler objects.
class VulkanSamplerCache {
public:
void initialize(VkDevice device);
explicit VulkanSamplerCache(VkDevice device);
VkSampler getSampler(SamplerParams params) noexcept;
void terminate() noexcept;
private:
@@ -26,10 +26,9 @@ static constexpr uint32_t TIME_BEFORE_EVICTION = FVK_MAX_COMMAND_BUFFERS;
namespace filament::backend {
void VulkanStagePool::initialize(VmaAllocator allocator, VulkanCommands* commands) noexcept {
mAllocator = allocator;
mCommands = commands;
}
VulkanStagePool::VulkanStagePool(VmaAllocator allocator, VulkanCommands* commands)
: mAllocator(allocator),
mCommands(commands) {}
VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) {
// First check if a stage exists whose capacity is greater than or equal to the requested size.
@@ -45,7 +45,7 @@ struct VulkanStageImage {
// This class manages two types of host-mappable staging areas: buffer stages and image stages.
class VulkanStagePool {
public:
void initialize(VmaAllocator allocator, VulkanCommands* commands) noexcept;
VulkanStagePool(VmaAllocator allocator, VulkanCommands* commands);
// Finds or creates a stage whose capacity is at least the given number of bytes.
// The stage is automatically released back to the pool after TIME_BEFORE_EVICTION frames.
@@ -18,10 +18,10 @@
#include "VulkanTexture.h"
#include "VulkanUtility.h"
#include <DataReshaper.h>
#include <backend/DriverEnums.h>
#include <private/backend/BackendUtils.h>
#include "DataReshaper.h"
#include <utils/Panic.h>
using namespace bluevk;
@@ -100,9 +100,13 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
// Filament expects blit() to work with any texture, so we almost always set these usage flags.
// TODO: investigate performance implications of setting these flags.
const VkImageUsageFlags blittable = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
constexpr VkImageUsageFlags blittable = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (any(usage & (TextureUsage::BLIT_DST | TextureUsage::BLIT_SRC))) {
imageInfo.usage |= blittable;
}
if (any(usage & TextureUsage::SAMPLEABLE)) {
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
+1 -1
View File
@@ -51,7 +51,7 @@ void BackendTest::init(Backend backend, bool isMobilePlatform) {
}
BackendTest::BackendTest() : commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE,
CONFIG_COMMAND_BUFFERS_SIZE) {
CONFIG_COMMAND_BUFFERS_SIZE, /*mPaused=*/false) {
initializeDriver();
}
+2 -1
View File
@@ -46,7 +46,8 @@ void ComputeTest::init(Backend backend) {
}
ComputeTest::ComputeTest()
: commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE, CONFIG_COMMAND_BUFFERS_SIZE) {
: commandBufferQueue(CONFIG_MIN_COMMAND_BUFFERS_SIZE, CONFIG_COMMAND_BUFFERS_SIZE,
/*paused=*/false) {
}
ComputeTest::~ComputeTest() = default;
+11 -11
View File
@@ -226,9 +226,9 @@ TEST_F(BackendTest, ColorMagnify) {
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
for (uint8_t level = 0; level < kNumLevels; level++) {
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, 0 }, {}, {});
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kDstTexWidth >> level, kDstTexHeight >> level, 1, { dstTexture, level, 0 }, {}, {});
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
}
// Do a "magnify" blit from level 1 of the source RT to the level 0 of the destination RT.
@@ -301,9 +301,9 @@ TEST_F(BackendTest, ColorMinify) {
Handle<HwRenderTarget> dstRenderTargets[kNumLevels];
for (uint8_t level = 0; level < kNumLevels; level++) {
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, 0 }, {}, {});
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
dstRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kDstTexWidth >> level, kDstTexHeight >> level, 1, { dstTexture, level, 0 }, {}, {});
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, 0 }, {}, {});
}
// Do a "minify" blit from level 1 of the source RT to the level 0 of the destination RT.
@@ -369,12 +369,12 @@ TEST_F(BackendTest, ColorResolve) {
// Create a 4-sample render target with the 4-sample texture.
Handle<HwRenderTarget> const srcRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount,
TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount, 0,
{{ srcColorTexture }}, {}, {});
// Create a 1-sample render target with the 1-sample texture.
Handle<HwRenderTarget> const dstRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1,
TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, 0,
{{ dstColorTexture }}, {}, {});
// Prep for rendering.
@@ -473,9 +473,9 @@ TEST_F(BackendTest, Blit2DTextureArray) {
// Create two RenderTargets.
const int level = 0;
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, kSrcTexLayer }, {}, {});
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, kSrcTexLayer }, {}, {});
Handle<HwRenderTarget> dstRenderTarget = api.createRenderTarget( TargetBufferFlags::COLOR,
kDstTexWidth >> level, kDstTexHeight >> level, 1, { dstTexture, level, kDstTexLayer }, {}, {});
kDstTexWidth >> level, kDstTexHeight >> level, 1, 0, { dstTexture, level, kDstTexLayer }, {}, {});
// Do a blit from kSrcTexLayer of the source RT to kDstTexLayer of the destination RT.
const int srcLevel = 0;
@@ -565,10 +565,10 @@ TEST_F(BackendTest, BlitRegion) {
// that this case is handled correctly.
Handle<HwRenderTarget> srcRenderTarget =
api.createRenderTarget(TargetBufferFlags::COLOR, srcRect.width,
srcRect.height, 1, {srcTexture, kSrcLevel, 0}, {}, {});
srcRect.height, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {});
Handle<HwRenderTarget> dstRenderTarget =
api.createRenderTarget(TargetBufferFlags::COLOR, kDstTexWidth >> kDstLevel,
kDstTexHeight >> kDstLevel, 1, {dstTexture, kDstLevel, 0}, {}, {});
kDstTexHeight >> kDstLevel, 1, 0, {dstTexture, kDstLevel, 0}, {}, {});
api.blitDEPRECATED(TargetBufferFlags::COLOR0, dstRenderTarget, dstRect, srcRenderTarget, srcRect,
SamplerMagFilter::LINEAR);
@@ -637,7 +637,7 @@ TEST_F(BackendTest, BlitRegionToSwapChain) {
Handle<HwRenderTarget> srcRenderTargets[kNumLevels];
for (uint8_t level = 0; level < kNumLevels; level++) {
srcRenderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, { srcTexture, level, 0 }, {}, {});
kSrcTexWidth >> level, kSrcTexHeight >> level, 1, 0, { srcTexture, level, 0 }, {}, {});
}
// Blit one-quarter of src level 1 to dst level 0.
+1 -1
View File
@@ -216,7 +216,7 @@ TEST_F(BackendTest, BufferObjectUpdateWithOffset) {
auto colorTexture = getDriverApi().createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT);
auto renderTarget = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR0, 512, 512, 1, {{colorTexture}}, {}, {});
TargetBufferFlags::COLOR0, 512, 512, 1, 0, {{colorTexture}}, {}, {});
// Upload uniforms for the first triangle.
{
+1 -1
View File
@@ -160,7 +160,7 @@ TEST_F(BackendTest, FeedbackLoops) {
slog.i << "Level " << int(level) << ": " <<
(kTexWidth >> level) << "x" << (kTexHeight >> level) << io::endl;
renderTargets[level] = api.createRenderTarget( TargetBufferFlags::COLOR,
kTexWidth >> level, kTexHeight >> level, 1, { texture, level, 0 }, {}, {});
kTexWidth >> level, kTexHeight >> level, 1, 0, { texture, level, 0 }, {}, {});
}
// Fill the base level of the texture with interesting colors.
+2 -1
View File
@@ -105,7 +105,8 @@ TEST_F(BackendTest, MRT) {
512, // width
512, // height
1, // samples
{{textureA },{textureB }}, // color
0, // layerCount
{{textureA },{textureB }}, // color
{}, // depth
{}); // stencil
+1 -1
View File
@@ -155,7 +155,7 @@ TEST_F(BackendTest, SetMinMaxLevel) {
// Render a white triangle into level 2.
// We specify mip level 2, because minMaxLevels has no effect when rendering into a texture.
Handle<HwRenderTarget> renderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR, 32, 32, 1,
TargetBufferFlags::COLOR, 32, 32, 1, 0,
{texture, 2 /* level */, 0 /* layer */}, {}, {});
{
RenderPassParams params = {};
+4 -4
View File
@@ -279,7 +279,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// level (at least for OpenGL).
renderTarget = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR, t.getRenderTargetSize(),
t.getRenderTargetSize(), t.samples, {{ texture, uint8_t(t.mipLevel) }}, {},
t.getRenderTargetSize(), t.samples, 0, {{ texture, uint8_t(t.mipLevel) }}, {},
{});
}
@@ -318,9 +318,8 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// correct mip.
RenderPassParams p = params;
Handle<HwRenderTarget> mipLevelOneRT = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR, renderTargetBaseSize, renderTargetBaseSize, 1,
{{ texture }}, {},
{});
TargetBufferFlags::COLOR, renderTargetBaseSize, renderTargetBaseSize, 1, 0,
{{ texture }}, {}, {});
p.clearColor = {1.f, 0.f, 0.f, 1.f};
getDriverApi().beginRenderPass(mipLevelOneRT, p);
getDriverApi().endRenderPass();
@@ -402,6 +401,7 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
renderTargetSize, // width
renderTargetSize, // height
1, // samples
0, // layerCount
{{ texture }}, // color
{}, // depth
{}); // stencil
+3 -3
View File
@@ -113,11 +113,11 @@ TEST_F(BackendTest, ScissorViewportRegion) {
// We purposely set the render target width and height to smaller than the texture, to check
// that this case is handled correctly.
Handle<HwRenderTarget> srcRenderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1,
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1, 0,
{srcTexture, kSrcLevel, 0}, {depthTexture, 0, 0}, {});
Handle<HwRenderTarget> fullRenderTarget = api.createRenderTarget(TargetBufferFlags::COLOR,
kSrcTexHeight >> kSrcLevel, kSrcTexWidth >> kSrcLevel, 1,
kSrcTexHeight >> kSrcLevel, kSrcTexWidth >> kSrcLevel, 1, 0,
{srcTexture, kSrcLevel, 0}, {}, {});
TrianglePrimitive triangle(api);
@@ -208,7 +208,7 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
(uint32_t)std::numeric_limits<int32_t>::max()};
Handle<HwRenderTarget> renderTarget = api.createRenderTarget(
TargetBufferFlags::COLOR, 512, 512, 1,
TargetBufferFlags::COLOR, 512, 512, 1, 0,
{srcTexture, 0, 0}, {}, {});
TrianglePrimitive triangle(api);
+5 -5
View File
@@ -150,7 +150,7 @@ TEST_F(BasicStencilBufferTest, StencilBuffer) {
auto stencilTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT);
auto renderTarget = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1,
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1, 0,
{{colorTexture}}, {}, {{stencilTexture}});
RunTest(renderTarget);
@@ -174,7 +174,7 @@ TEST_F(BasicStencilBufferTest, DepthAndStencilBuffer) {
auto depthStencilTexture = api.createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::DEPTH24_STENCIL8, 1, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT);
auto renderTarget = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1,
TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL, 512, 512, 1, 0,
{{colorTexture}}, {depthStencilTexture}, {{depthStencilTexture}});
RunTest(renderTarget);
@@ -202,10 +202,10 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
auto depthStencilTextureMSAA = api.createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::DEPTH24_STENCIL8, 4, 512, 512, 1, TextureUsage::STENCIL_ATTACHMENT | TextureUsage::DEPTH_ATTACHMENT);
auto renderTarget0 = getDriverApi().createRenderTarget(
TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4,
TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4, 0,
{{}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA});
auto renderTarget1 = getDriverApi().createRenderTarget(
TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4,
TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH_AND_STENCIL, 512, 512, 4, 0,
{{colorTexture}}, {depthStencilTextureMSAA}, {depthStencilTextureMSAA});
api.startCapture(0);
@@ -273,4 +273,4 @@ TEST_F(BasicStencilBufferTest, StencilBufferMSAA) {
api.destroyRenderTarget(renderTarget1);
}
} // namespace test
} // namespace test
+28
View File
@@ -335,6 +335,11 @@ public:
* This value determines for how many frames are texture entries kept in the cache.
*/
uint32_t resourceAllocatorCacheMaxAge = 2;
/*
* Disable backend handles use-after-free checks.
*/
bool disableHandleUseAfterFreeCheck = false;
};
@@ -402,6 +407,14 @@ public:
*/
Builder& featureLevel(FeatureLevel featureLevel) noexcept;
/**
* Warning: This is an experimental API. See Engine::setPaused(bool) for caveats.
*
* @param paused Whether to start the rendering thread paused.
* @return A reference to this Builder for chaining calls.
*/
Builder& paused(bool paused) noexcept;
#if UTILS_HAS_THREADING
/**
* Creates the filament Engine asynchronously.
@@ -827,6 +840,21 @@ public:
*/
void flush();
/**
* Pause or resume rendering thread.
*
* <p>Warning: This is an experimental API. In particular, note the following caveats.
*
* <ul><li>
* Buffer callbacks will never be called as long as the rendering thread is paused.
* Do not rely on a buffer callback to unpause the thread.
* </li><li>
* While the rendering thread is paused, rendering commands will continue to be queued until the
* buffer limit is reached. When the limit is reached, the program will abort.
* </li></ul>
*/
void setPaused(bool paused);
/**
* Drains the user callback message queue and immediately execute all pending callbacks.
*
+22 -1
View File
@@ -156,6 +156,15 @@ public:
*/
static constexpr uint8_t DEFAULT_CHANNEL = 2u;
/**
* Type of geometry for a Renderable
*/
enum class GeometryType : uint8_t {
DYNAMIC, //!< dynamic gemoetry has no restriction
STATIC_BOUNDS, //!< bounds and world space transform are immutable
STATIC //!< skinning/morphing not allowed and Vertex/IndexBuffer immutables
};
/**
* Creates a builder for renderable components.
*
@@ -204,6 +213,17 @@ public:
VertexBuffer* UTILS_NONNULL vertices,
IndexBuffer* UTILS_NONNULL indices) noexcept; //!< \overload
/**
* Specify the type of geometry for this renderable. DYNAMIC geometry has no restriction,
* STATIC_BOUNDS geometry means that both the bounds and the world-space transform of the
* the renderable are immutable.
* STATIC geometry has the same restrictions as STATIC_BOUNDS, but in addition disallows
* skinning, morphing and changing the VertexBuffer or IndexBuffer in any way.
* @param enable whether this renderable has static bounds. false by default.
*/
Builder& geometryType(GeometryType type) noexcept;
/**
* Binds a material instance to the specified primitive.
*
@@ -603,11 +623,12 @@ public:
/**
* Changes the bounding box used for frustum culling.
* The renderable must not have staticGeometry enabled.
*
* \see Builder::boundingBox()
* \see RenderableManager::getAxisAlignedBoundingBox()
*/
void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept;
void setAxisAlignedBoundingBox(Instance instance, const Box& aabb);
/**
* Changes the visibility bits.
+5
View File
@@ -295,6 +295,11 @@ utils::JobSystem& Engine::getJobSystem() noexcept {
return downcast(this)->getJobSystem();
}
void Engine::setPaused(bool paused) {
ASSERT_PRECONDITION(UTILS_HAS_THREADING, "Pause is meant for multi-threaded platforms.");
downcast(this)->setPaused(paused);
}
DebugRegistry& Engine::getDebugRegistry() noexcept {
return downcast(this)->getDebugRegistry();
}
+11 -12
View File
@@ -33,18 +33,17 @@ namespace filament {
using namespace utils;
using namespace backend;
size_t HwRenderPrimitiveFactory::KeyHash::operator()(
HwRenderPrimitiveFactory::Key const& p) const noexcept {
return utils::hash::combine(
p.params.vbh.getId(),
utils::hash::combine(p.params.ibh.getId(), (size_t)p.params.type));
size_t HwRenderPrimitiveFactory::Parameters::hash() const noexcept {
return utils::hash::combine(vbh.getId(),
utils::hash::combine(ibh.getId(),
(size_t)type));
}
bool operator==(HwRenderPrimitiveFactory::Key const& lhs,
HwRenderPrimitiveFactory::Key const& rhs) noexcept {
return lhs.params.vbh == rhs.params.vbh &&
lhs.params.ibh == rhs.params.ibh &&
lhs.params.type == rhs.params.type;
bool operator==(HwRenderPrimitiveFactory::Parameters const& lhs,
HwRenderPrimitiveFactory::Parameters const& rhs) noexcept {
return lhs.vbh == rhs.vbh &&
lhs.ibh == rhs.ibh &&
lhs.type == rhs.type;
}
// ------------------------------------------------------------------------------------------------
@@ -67,7 +66,7 @@ auto HwRenderPrimitiveFactory::create(DriverApi& driver,
backend::PrimitiveType type) noexcept -> Handle {
// see if we already have seen this RenderPrimitive
Key const key{{ vbh, ibh, type }, 1 };
Key const key({ vbh, ibh, type });
auto pos = mBimap.find(key);
// the common case is that we've never seen it (i.e.: no reuse)
@@ -77,7 +76,7 @@ auto HwRenderPrimitiveFactory::create(DriverApi& driver,
return handle;
}
pos->first.pKey->refs++;
++(pos->first.pKey->refs);
return pos->second.handle;
}
+21 -11
View File
@@ -52,8 +52,11 @@ public:
backend::VertexBufferHandle vbh; // 4
backend::IndexBufferHandle ibh; // 4
backend::PrimitiveType type; // 4
size_t hash() const noexcept;
};
friend bool operator==(Parameters const& lhs, Parameters const& rhs) noexcept;
Handle create(backend::DriverApi& driver,
backend::VertexBufferHandle vbh,
backend::IndexBufferHandle ibh,
@@ -63,29 +66,36 @@ public:
private:
struct Key {
// The key should not be copyable, unfortunately due to how the Bimap works we have
// to copy-construct it once.
Key(Key const&) = default;
Key& operator=(Key const&) = delete;
Key& operator=(Key&&) noexcept = delete;
explicit Key(Parameters const& params) : params(params), refs(1) { }
Parameters params;
mutable uint32_t refs; // 4 bytes
bool operator==(Key const& rhs) const noexcept {
return params == rhs.params;
}
};
struct KeyHash {
size_t operator()(Key const& p) const noexcept;
struct KeyHasher {
size_t operator()(Key const& p) const noexcept {
return p.params.hash();
}
};
friend bool operator==(Key const& lhs, Key const& rhs) noexcept;
struct Value { // 4 bytes
Handle handle;
};
struct ValueHash {
size_t operator()(Value const& p) const noexcept {
std::hash<Handle::HandleId> const h;
return h(p.handle.getId());
struct ValueHasher {
size_t operator()(Value const v) const noexcept {
return std::hash<Handle::HandleId>()(v.handle.getId());
}
};
friend bool operator==(Value const& lhs, Value const& rhs) noexcept {
friend bool operator==(Value const lhs, Value const rhs) noexcept {
return lhs.handle == rhs.handle;
}
@@ -104,7 +114,7 @@ private:
PoolAllocatorArena mArena;
// The special Bimap
Bimap<Key, Value, KeyHash, ValueHash,
Bimap<Key, Value, KeyHasher, ValueHasher,
utils::STLAllocator<Key, PoolAllocatorArena>> mBimap;
};
+1 -2
View File
@@ -22,7 +22,6 @@
#include <private/backend/DriverApi.h>
#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Hash.h>
@@ -66,7 +65,7 @@ auto HwVertexBufferInfoFactory::create(DriverApi& driver,
uint8_t attributeCount,
backend::AttributeArray attributes) noexcept -> Handle {
Key const key{{ bufferCount, attributeCount, {}, attributes }, 1 };
Key const key({ bufferCount, attributeCount, {}, attributes });
auto pos = mBimap.find(key);
// the common case is that we've never seen it (i.e.: no reuse)
+9 -4
View File
@@ -67,6 +67,12 @@ public:
private:
struct Key { // 140 bytes
// The key should not be copyable, unfortunately due to how the Bimap works we have
// to copy-construct it once.
Key(Key const&) = default;
Key& operator=(Key const&) = delete;
Key& operator=(Key&&) noexcept = delete;
explicit Key(Parameters const& params) : params(params), refs(1) { }
Parameters params;
mutable uint32_t refs; // 4 bytes
bool operator==(Key const& rhs) const noexcept {
@@ -85,13 +91,12 @@ private:
};
struct ValueHasher {
size_t operator()(Value v) const noexcept {
std::hash<Handle::HandleId> const hasher;
return hasher(v.handle.getId());
size_t operator()(Value const v) const noexcept {
return std::hash<Handle::HandleId>()(v.handle.getId());
}
};
friend bool operator==(Value const& lhs, Value const& rhs) noexcept {
friend bool operator==(Value const lhs, Value const rhs) noexcept {
return lhs.handle == rhs.handle;
}
+15 -15
View File
@@ -3292,8 +3292,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
SamplerMagFilter filterMag,
SamplerMinFilter filterMin) noexcept {
assert_invariant(fg.getDescriptor(input).depth > 1);
assert_invariant(fg.getDescriptor(input).type == SamplerType::SAMPLER_2D_ARRAY);
auto& inputTextureDesc = fg.getDescriptor(input);
assert_invariant(inputTextureDesc.depth > 1);
assert_invariant(inputTextureDesc.type == SamplerType::SAMPLER_2D_ARRAY);
// TODO: add support for sub-resources
assert_invariant(fg.getSubResourceDescriptor(input).layer == 0);
@@ -3329,14 +3330,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
.filterMag = filterMag,
.filterMin = filterMin
});
mi->setParameter("layerIndex", 0);
mi->setParameter("viewport", float4{
float(vp.left) / inputDesc.width,
float(vp.bottom) / inputDesc.height,
float(vp.width) / inputDesc.width,
float(vp.height) / inputDesc.height
});
mi->commit(driver);
mi->use(driver);
auto pipeline = material.getPipelineState(mEngine);
@@ -3347,18 +3346,19 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
pipeline.first.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
}
// Blit the scene rendered to the first layer to the left half of the screen.
out.params.viewport.width /= 2;
render(out, pipeline, driver);
// The width of each view takes up 1/depth of the screen width.
out.params.viewport.width /= inputTextureDesc.depth;
// Blit the scene rendered to the second layer to the right half of the screen.
// Don't clear or discard the target to keep the previously rendered left half image.
mi->setParameter("layerIndex", 1);
mi->commit(driver);
out.params.flags.clear = filament::backend::TargetBufferFlags::NONE;
out.params.flags.discardStart = filament::backend::TargetBufferFlags::NONE;
out.params.viewport.left += out.params.viewport.width;
render(out, pipeline, driver);
// Render all layers of the texture to the screen side-by-side.
for (uint32_t i = 0; i < inputTextureDesc.depth; ++i) {
mi->setParameter("layerIndex", i);
mi->commit(driver);
render(out, pipeline, driver);
// From the second draw, don't clear the targetbuffer.
out.params.flags.clear = filament::backend::TargetBufferFlags::NONE;
out.params.flags.discardStart = filament::backend::TargetBufferFlags::NONE;
out.params.viewport.left += out.params.viewport.width;
}
});
return ppQuadBlit->output;
+4 -5
View File
@@ -184,8 +184,7 @@ void RenderPass::appendCommands(FEngine& engine,
Command* curr = commands.data();
size_t const commandCount = commands.size();
auto stereoscopicEyeCount =
renderFlags & IS_STEREOSCOPIC ? engine.getConfig().stereoscopicEyeCount : 1;
auto stereoscopicEyeCount = engine.getConfig().stereoscopicEyeCount;
const float3 cameraPosition(mCameraPosition);
const float3 cameraForwardVector(mCameraForwardVector);
@@ -521,7 +520,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
const bool hasShadowing = renderFlags & HAS_SHADOWING;
const bool viewInverseFrontFaces = renderFlags & HAS_INVERSE_FRONT_FACES;
const bool hasStereo = renderFlags & IS_STEREOSCOPIC;
const bool hasInstancedStereo = renderFlags & IS_INSTANCED_STEREOSCOPIC;
Command cmdColor;
@@ -590,7 +589,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
// soaInstanceInfo[i].count is the number of instances the user has requested, either for
// manual or hybrid instancing. Instanced stereo multiplies the number of instances by the
// eye count.
if (UTILS_UNLIKELY(hasStereo)) {
if (UTILS_UNLIKELY(hasInstancedStereo)) {
cmdColor.primitive.instanceCount =
(soaInstanceInfo[i].count * stereoEyeCount) |
PrimitiveInfo::USER_INSTANCE_MASK;
@@ -624,7 +623,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
cmdDepth.primitive.skinningTexture = skinning.handleSampler;
cmdDepth.primitive.morphWeightBuffer = morphing.handle;
if (UTILS_UNLIKELY(hasStereo)) {
if (UTILS_UNLIKELY(hasInstancedStereo)) {
cmdColor.primitive.instanceCount =
(soaInstanceInfo[i].count * stereoEyeCount) |
PrimitiveInfo::USER_INSTANCE_MASK;
+3 -3
View File
@@ -275,9 +275,9 @@ public:
"Command isn't trivially destructible");
using RenderFlags = uint8_t;
static constexpr RenderFlags HAS_SHADOWING = 0x01;
static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02;
static constexpr RenderFlags IS_STEREOSCOPIC = 0x04;
static constexpr RenderFlags HAS_SHADOWING = 0x01;
static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02;
static constexpr RenderFlags IS_INSTANCED_STEREOSCOPIC = 0x04;
// Arena used for commands
using Arena = utils::Arena<
+1 -1
View File
@@ -56,7 +56,7 @@ void RenderableManager::destroy(utils::Entity e) noexcept {
return downcast(this)->destroy(e);
}
void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept {
void RenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) {
downcast(this)->setAxisAlignedBoundingBox(instance, aabb);
}
+16 -2
View File
@@ -57,6 +57,7 @@ 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 = 0;
data.shadows = blackboard.get<FrameGraphTexture>("shadows");
data.ssao = blackboard.get<FrameGraphTexture>("ssao");
@@ -124,7 +125,9 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
// depth auto-resolve, in which case we must allocate the depth
// buffer with MS and manually resolve it (see "Resolved Depth Buffer"
// pass).
.depth = colorBufferDesc.depth,
.samples = canAutoResolveDepth ? colorBufferDesc.samples : uint8_t(config.msaa),
.type = colorBufferDesc.type,
.format = format,
});
if (config.enabledStencilBuffer) {
@@ -150,7 +153,17 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
data.depth = builder.read(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
data.color = builder.write(data.color, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
data.depth = builder.write(data.depth, FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
if (engine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW) {
// Add sampleable usage flag for depth in multiview rendering, othewise it's
// treated as renderbuffer in the backend and crashed.
data.depth = builder.write(data.depth,
FrameGraphTexture::Usage::DEPTH_ATTACHMENT |
FrameGraphTexture::Usage::SAMPLEABLE);
layerCount = engine.getConfig().stereoscopicEyeCount;
} else {
data.depth = builder.write(data.depth,
FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
}
/*
* There is a bit of magic happening here regarding the viewport used.
@@ -172,7 +185,8 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
.stencil = data.stencil },
.clearColor = config.clearColor,
.samples = config.msaa,
.clearFlags = clearColorFlags | clearDepthFlags | clearStencilFlags });
.layerCount = layerCount,
.clearFlags = clearColorFlags | clearDepthFlags | clearStencilFlags});
blackboard["depth"] = data.depth;
},
[=, &view, &engine](FrameGraphResources const& resources,
+2 -2
View File
@@ -129,10 +129,10 @@ void ResourceAllocator::terminate() noexcept {
RenderTargetHandle ResourceAllocator::createRenderTarget(const char*,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, MRT color, TargetBufferInfo depth,
uint8_t samples, uint8_t layerCount, MRT color, TargetBufferInfo depth,
TargetBufferInfo stencil) noexcept {
return mBackend.createRenderTarget(targetBufferFlags,
width, height, samples ? samples : 1u, color, depth, stencil);
width, height, samples ? samples : 1u, layerCount, color, depth, stencil);
}
void ResourceAllocator::destroyRenderTarget(RenderTargetHandle h) noexcept {
+2
View File
@@ -45,6 +45,7 @@ public:
uint32_t width,
uint32_t height,
uint8_t samples,
uint8_t layerCount,
backend::MRT color,
backend::TargetBufferInfo depth,
backend::TargetBufferInfo stencil) noexcept = 0;
@@ -77,6 +78,7 @@ public:
uint32_t width,
uint32_t height,
uint8_t samples,
uint8_t layerCount,
backend::MRT color,
backend::TargetBufferInfo depth,
backend::TargetBufferInfo stencil) noexcept override;
+1 -1
View File
@@ -253,7 +253,7 @@ float3 PBRNeutralToneMapper::operator()(math::float3 color) const noexcept {
color *= newPeak / peak;
float g = 1.0f - 1.0f / (desaturation * (peak - newPeak) + 1.0f);
return mix(color, float3(1.0f), g);
return mix(color, float3(newPeak), g);
}
//------------------------------------------------------------------------------
+21 -1
View File
@@ -58,6 +58,7 @@ struct RenderableManager::BuilderDetails {
bool mScreenSpaceContactShadows : 1;
bool mSkinningBufferMode : 1;
bool mFogEnabled : 1;
RenderableManager::Builder::GeometryType mGeometryType : 2;
size_t mSkinningBoneCount = 0;
size_t mMorphTargetCount = 0;
Bone const* mUserBones = nullptr;
@@ -75,7 +76,9 @@ struct RenderableManager::BuilderDetails {
explicit BuilderDetails(size_t count)
: mEntries(count), mCulling(true), mCastShadows(false),
mReceiveShadows(true), mScreenSpaceContactShadows(false),
mSkinningBufferMode(false), mFogEnabled(true), mBonePairs() {
mSkinningBufferMode(false), mFogEnabled(true),
mGeometryType(RenderableManager::Builder::GeometryType::DYNAMIC),
mBonePairs() {
}
// this is only needed for the explicit instantiation below
BuilderDetails() = default;
@@ -121,6 +124,11 @@ RenderableManager::Builder& RenderableManager::Builder::geometry(size_t index,
return *this;
}
RenderableManager::Builder& RenderableManager::Builder::geometryType(GeometryType type) noexcept {
mImpl->mGeometryType = type;
return *this;
}
RenderableManager::Builder& RenderableManager::Builder::material(size_t index,
MaterialInstance const* materialInstance) noexcept {
if (index < mImpl->mEntries.size()) {
@@ -388,11 +396,21 @@ RenderableManager::Builder::Result RenderableManager::Builder::build(Engine& eng
ASSERT_PRECONDITION(mImpl->mSkinningBoneCount <= CONFIG_MAX_BONE_COUNT,
"bone count > %u", CONFIG_MAX_BONE_COUNT);
ASSERT_PRECONDITION(mImpl->mInstanceCount <= CONFIG_MAX_INSTANCES || !mImpl->mInstanceBuffer,
"instance count is %zu, but instance count is limited to CONFIG_MAX_INSTANCES (%zu) "
"instances when supplying transforms via an InstanceBuffer.",
mImpl->mInstanceCount,
CONFIG_MAX_INSTANCES);
if (mImpl->mGeometryType == GeometryType::STATIC) {
ASSERT_PRECONDITION(mImpl->mSkinningBoneCount > 0,
"Skinning can't be used with STATIC geometry");
ASSERT_PRECONDITION(mImpl->mMorphTargetCount > 0,
"Morphing can't be used with STATIC geometry");
}
if (mImpl->mInstanceBuffer) {
size_t const bufferInstanceCount = mImpl->mInstanceBuffer->mInstanceCount;
ASSERT_PRECONDITION(mImpl->mInstanceCount <= bufferInstanceCount,
@@ -519,6 +537,8 @@ void FRenderableManager::create(
setSkinning(ci, false);
setMorphing(ci, builder->mMorphTargetCount);
setFogEnabled(ci, builder->mFogEnabled);
// do this after calling setAxisAlignedBoundingBox
static_cast<Visibility&>(mManager[ci].visibility).geometryType = builder->mGeometryType;
mManager[ci].channels = builder->mLightChannels;
InstancesInfo& instances = manager[ci].instances;
+42 -15
View File
@@ -22,22 +22,30 @@
#include "HwRenderPrimitiveFactory.h"
#include "UniformBuffer.h"
#include "backend/DriverApiForward.h"
#include <backend/Handle.h>
#include <details/InstanceBuffer.h>
#include <filament/Box.h>
#include <filament/RenderableManager.h>
#include <details/InstanceBuffer.h>
#include <private/filament/UibStructs.h>
#include <backend/DriverApiForward.h>
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utils/Entity.h>
#include <utils/Panic.h>
#include <utils/SingleInstanceComponentManager.h>
#include <utils/Slice.h>
#include <utils/Range.h>
#include <math/mat4.h>
#include <algorithm>
#include <stddef.h>
#include <stdint.h>
namespace filament {
class FBufferObject;
@@ -49,9 +57,12 @@ class FSkinningBuffer;
class FVertexBuffer;
class FTexture;
class MorphTargetBuffer;
class FRenderableManager : public RenderableManager {
public:
using Instance = RenderableManager::Instance;
using GeometryType = RenderableManager::Builder::GeometryType;
// TODO: consider renaming, this pertains to material variants, not strictly visibility.
struct Visibility {
@@ -60,11 +71,13 @@ public:
bool castShadows : 1;
bool receiveShadows : 1;
bool culling : 1;
bool skinning : 1;
bool morphing : 1;
bool screenSpaceContactShadows : 1;
bool reversedWindingOrder : 1;
bool fog : 1;
GeometryType geometryType : 2;
};
static_assert(sizeof(Visibility) == sizeof(uint16_t), "Visibility should be 16 bits");
@@ -115,7 +128,7 @@ public:
void destroy(utils::Entity e) noexcept;
inline void setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept;
inline void setAxisAlignedBoundingBox(Instance instance, const Box& aabb);
inline void setLayerMask(Instance instance, uint8_t select, uint8_t values) noexcept;
@@ -136,13 +149,13 @@ public:
inline void setPrimitives(Instance instance, utils::Slice<FRenderPrimitive> const& primitives) noexcept;
inline void setSkinning(Instance instance, bool enable) noexcept;
inline void setSkinning(Instance instance, bool enable);
void setBones(Instance instance, Bone const* transforms, size_t boneCount, size_t offset = 0);
void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount, size_t offset = 0);
void setSkinningBuffer(Instance instance, FSkinningBuffer* skinningBuffer,
size_t count, size_t offset);
inline void setMorphing(Instance instance, bool enable) noexcept;
inline void setMorphing(Instance instance, bool enable);
void setMorphWeights(Instance instance, float const* weights, size_t count, size_t offset);
void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex,
FMorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count);
@@ -295,8 +308,12 @@ private:
FILAMENT_DOWNCAST(RenderableManager)
void FRenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) noexcept {
void FRenderableManager::setAxisAlignedBoundingBox(Instance instance, const Box& aabb) {
if (instance) {
ASSERT_PRECONDITION(
static_cast<Visibility const&>(
mManager[instance].visibility).geometryType == GeometryType::DYNAMIC,
"This renderable has staticBounds enabled; its AABB cannot change.");
mManager[instance].aabb = aabb;
}
}
@@ -368,16 +385,26 @@ bool FRenderableManager::getFogEnabled(RenderableManager::Instance instance) con
return getVisibility(instance).fog;
}
void FRenderableManager::setSkinning(Instance instance, bool enable) noexcept {
void FRenderableManager::setSkinning(Instance instance, bool enable) {
if (instance) {
Visibility& visibility = mManager[instance].visibility;
ASSERT_PRECONDITION(
visibility.geometryType != GeometryType::STATIC || !enable,
"Skinning can't be used with STATIC geometry");
visibility.skinning = enable;
}
}
void FRenderableManager::setMorphing(Instance instance, bool enable) noexcept {
void FRenderableManager::setMorphing(Instance instance, bool enable) {
if (instance) {
Visibility& visibility = mManager[instance].visibility;
ASSERT_PRECONDITION(
visibility.geometryType != GeometryType::STATIC || !enable,
"Morphing can't be used with STATIC geometry");
visibility.morphing = enable;
}
}
@@ -446,22 +473,22 @@ FRenderableManager::getInstancesInfo(Instance instance) const noexcept {
}
utils::Slice<FRenderPrimitive> const& FRenderableManager::getRenderPrimitives(
Instance instance, uint8_t level) const noexcept {
Instance instance, UTILS_UNUSED uint8_t level) const noexcept {
return mManager[instance].primitives;
}
utils::Slice<FRenderPrimitive>& FRenderableManager::getRenderPrimitives(
Instance instance, uint8_t level) noexcept {
Instance instance, UTILS_UNUSED uint8_t level) noexcept {
return mManager[instance].primitives;
}
utils::Slice<FRenderableManager::MorphTargets> const& FRenderableManager::getMorphTargets(
Instance instance, uint8_t level) const noexcept {
Instance instance, UTILS_UNUSED uint8_t level) const noexcept {
return mManager[instance].morphTargets;
}
utils::Slice<FRenderableManager::MorphTargets>& FRenderableManager::getMorphTargets(
Instance instance, uint8_t level) noexcept {
Instance instance, UTILS_UNUSED uint8_t level) noexcept {
return mManager[instance].morphTargets;
}
+31 -6
View File
@@ -69,6 +69,7 @@ struct Engine::BuilderDetails {
Engine::Config mConfig;
FeatureLevel mFeatureLevel = FeatureLevel::FEATURE_LEVEL_1;
void* mSharedContext = nullptr;
bool mPaused = false;
static Config validateConfig(const Config* pConfig) noexcept;
};
@@ -100,7 +101,8 @@ Engine* FEngine::create(Engine::Builder const& builder) {
DriverConfig const driverConfig{
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = instance->getConfig().textureUseAfterFreePoolSize,
.disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile
.disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck
};
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
@@ -200,7 +202,8 @@ FEngine::FEngine(Engine::Builder const& builder) :
mCameraManager(*this),
mCommandBufferQueue(
builder->mConfig.minCommandBufferSizeMB * MiB,
builder->mConfig.commandBufferSizeMB * MiB),
builder->mConfig.commandBufferSizeMB * MiB,
builder->mPaused),
mPerRenderPassArena(
"FEngine::mPerRenderPassAllocator",
builder->mConfig.perRenderPassArenaSizeMB * MiB),
@@ -339,7 +342,7 @@ void FEngine::init() {
if (UTILS_UNLIKELY(mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)) {
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL0_DATA, MATERIALS_DEFAULTMATERIAL0_SIZE);
MATERIALS_DEFAULTMATERIAL_FL0_DATA, MATERIALS_DEFAULTMATERIAL_FL0_SIZE);
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
} else
#endif
@@ -347,8 +350,20 @@ void FEngine::init() {
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
switch (mConfig.stereoscopicType) {
case StereoscopicType::INSTANCED:
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
break;
case StereoscopicType::MULTIVIEW:
#ifdef FILAMENT_ENABLE_MULTIVIEW
defaultMaterialBuilder.package(
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_DATA, MATERIALS_DEFAULTMATERIAL_MULTIVIEW_SIZE);
#else
assert_invariant(false);
#endif
break;
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
float3 dummyPositions[1] = {};
@@ -655,7 +670,8 @@ int FEngine::loop() {
DriverConfig const driverConfig {
.handleArenaSize = getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = mConfig.textureUseAfterFreePoolSize,
.disableParallelShaderCompile = mConfig.disableParallelShaderCompile
.disableParallelShaderCompile = mConfig.disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck
};
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
@@ -1186,6 +1202,10 @@ void FEngine::destroy(FEngine* engine) {
}
}
void FEngine::setPaused(bool paused) {
mCommandBufferQueue.setPaused(paused);
}
Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept {
FEngine::DriverApi& driver = const_cast<FEngine*>(this)->getDriverApi();
return driver.getFeatureLevel();
@@ -1239,6 +1259,11 @@ Engine::Builder& Engine::Builder::sharedContext(void* sharedContext) noexcept {
return *this;
}
Engine::Builder& Engine::Builder::paused(bool paused) noexcept {
mImpl->mPaused = paused;
return *this;
}
#if UTILS_HAS_THREADING
void Engine::Builder::build(Invocable<void(void*)>&& callback) const {
+5
View File
@@ -340,6 +340,8 @@ public:
void destroy(utils::Entity e);
void setPaused(bool paused);
void flushAndWait();
// flush the current buffer
@@ -588,6 +590,9 @@ public:
struct {
bool debug_froxel_visualization = false;
} lighting;
struct {
bool combine_multiview_images = true;
} stereo;
matdbg::DebugServer* server = nullptr;
} debug;
};
+3
View File
@@ -641,6 +641,9 @@ void FMaterial::getSurfaceProgramSlow(Variant variant,
Program pb{ getProgramWithVariants(variant, vertexVariant, fragmentVariant) };
pb.priorityQueue(priorityQueue);
pb.multiview(
mEngine.getConfig().stereoscopicType == StereoscopicType::MULTIVIEW &&
Variant::isStereoVariant(variant));
createAndCacheProgram(std::move(pb), variant);
}
+3 -1
View File
@@ -34,6 +34,7 @@ struct RenderTarget::BuilderDetails {
uint32_t mWidth{};
uint32_t mHeight{};
uint8_t mSamples = 1; // currently not settable in the public facing API
uint8_t mLayerCount = 0;// currently not settable in the public facing API
};
using BuilderType = RenderTarget;
@@ -160,7 +161,8 @@ FRenderTarget::FRenderTarget(FEngine& engine, const RenderTarget::Builder& build
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createRenderTarget(mAttachmentMask,
builder.mImpl->mWidth, builder.mImpl->mHeight, builder.mImpl->mSamples, mrt, dinfo, {});
builder.mImpl->mWidth, builder.mImpl->mHeight, builder.mImpl->mSamples,
builder.mImpl->mLayerCount, mrt, dinfo, {});
}
void FRenderTarget::terminate(FEngine& engine) {
+34 -7
View File
@@ -111,6 +111,8 @@ FRenderer::FRenderer(FEngine& engine) :
&engine.debug.shadowmap.display_shadow_texture_level_count);
debugRegistry.registerProperty("d.shadowmap.display_shadow_texture_power",
&engine.debug.shadowmap.display_shadow_texture_power);
debugRegistry.registerProperty("d.stereo.combine_multiview_images",
&engine.debug.stereo.combine_multiview_images);
DriverApi& driver = engine.getDriverApi();
@@ -233,8 +235,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
SYSTRACE_CALL();
#if defined(__ANDROID__)
#if 0 && defined(__ANDROID__)
char scratch[PROP_VALUE_MAX + 1];
int length = __system_property_get("debug.filament.protected", scratch);
if (swapChain && length > 0) {
@@ -521,7 +522,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// DEBUG: driver commands must all happen from the same thread. Enforce that on debug builds.
driver.debugThreading();
const bool hasPostProcess = view.hasPostProcessPass();
bool hasPostProcess = view.hasPostProcessPass();
bool hasScreenSpaceRefraction = false;
bool hasColorGrading = hasPostProcess;
bool hasDithering = view.getDithering() == Dithering::TEMPORAL;
@@ -537,7 +538,16 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
auto colorGrading = view.getColorGrading();
auto ssReflectionsOptions = view.getScreenSpaceReflectionsOptions();
auto guardBandOptions = view.getGuardBandOptions();
const bool isRenderingMultiview = view.hasStereo() &&
engine.getConfig().stereoscopicType == backend::StereoscopicType::MULTIVIEW;
// 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) {
hasPostProcess = false;
msaaOptions.enabled = false;
}
const uint8_t msaaSampleCount = msaaOptions.enabled ? msaaOptions.sampleCount : 1u;
if (!hasPostProcess) {
// disable all effects that are part of post-processing
dofOptions.enabled = false;
@@ -701,7 +711,10 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
RenderPass::RenderFlags renderFlags = 0;
if (view.hasShadowing()) renderFlags |= RenderPass::HAS_SHADOWING;
if (view.isFrontFaceWindingInverted()) renderFlags |= RenderPass::HAS_INVERSE_FRONT_FACES;
if (view.hasStereo()) renderFlags |= RenderPass::IS_STEREOSCOPIC;
if (view.hasStereo() &&
engine.getConfig().stereoscopicType == backend::StereoscopicType::INSTANCED) {
renderFlags |= RenderPass::IS_INSTANCED_STEREOSCOPIC;
}
RenderPassBuilder passBuilder(commandArena);
passBuilder.renderFlags(renderFlags);
@@ -978,12 +991,18 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
RenderPass const pass{ passBuilder.build(engine) };
FrameGraphTexture::Descriptor const desc = {
FrameGraphTexture::Descriptor colorBufferDesc = {
.width = config.physicalViewport.width,
.height = config.physicalViewport.height,
.format = config.hdrFormat
};
// Set the depth to the number of layers if we're rendering multiview.
if (isRenderingMultiview) {
colorBufferDesc.depth = engine.getConfig().stereoscopicEyeCount;
colorBufferDesc.type = backend::SamplerType::SAMPLER_2D_ARRAY;
}
// a non-drawing pass to prepare everything that need to be before the color passes execute
fg.addTrivialSideEffectPass("Prepare Color Passes",
[=, &js, &view, &ppm](DriverApi& driver) {
@@ -991,7 +1010,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
if (colorGradingConfig.asSubpass) {
ppm.colorGradingPrepareSubpass(driver,
colorGrading, colorGradingConfig, vignetteOptions,
desc.width, desc.height);
colorBufferDesc.width, colorBufferDesc.height);
} else if (colorGradingConfig.customResolve) {
ppm.customResolvePrepareSubpass(driver,
PostProcessManager::CustomResolveOp::COMPRESS);
@@ -1009,7 +1028,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// the color pass itself + color-grading as subpass if needed
auto colorPassOutput = RendererUtils::colorPass(fg, "Color Pass", mEngine, view,
desc, config, colorGradingConfigForColor, pass.getExecutor());
colorBufferDesc, config, colorGradingConfigForColor, pass.getExecutor());
if (view.isScreenSpaceRefractionEnabled() && !pass.empty()) {
// this cancels the colorPass() call above if refraction is active.
@@ -1153,6 +1172,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
}
}
// Debug: combine the array texture for multiview into a single image.
if (UTILS_UNLIKELY(isRenderingMultiview && engine.debug.stereo.combine_multiview_images)) {
input = ppm.debugCombineArrayTexture(fg, blendModeTranslucent, input, xvp, {
.width = vp.width, .height = vp.height,
.format = colorGradingConfig.ldrFormat },
SamplerMagFilter::NEAREST, SamplerMinFilter::NEAREST);
}
// We need to do special processing when rendering directly into the swap-chain, that is when
// the viewRenderTarget is the default render target (mRenderTarget) and we're rendering into
// it.
+13 -2
View File
@@ -120,11 +120,22 @@ FMaterial const* FSkybox::createMaterial(FEngine& engine) {
Material::Builder builder;
#ifdef FILAMENT_ENABLE_FEATURE_LEVEL_0
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == Engine::FeatureLevel::FEATURE_LEVEL_0)) {
builder.package(MATERIALS_SKYBOX0_DATA, MATERIALS_SKYBOX0_SIZE);
builder.package(MATERIALS_SKYBOX_FL0_DATA, MATERIALS_SKYBOX_FL0_SIZE);
} else
#endif
{
builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE);
switch (engine.getConfig().stereoscopicType) {
case Engine::StereoscopicType::INSTANCED:
builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE);
break;
case Engine::StereoscopicType::MULTIVIEW:
#ifdef FILAMENT_ENABLE_MULTIVIEW
builder.package(MATERIALS_SKYBOX_MULTIVIEW_DATA, MATERIALS_SKYBOX_MULTIVIEW_SIZE);
#else
assert_invariant(false);
#endif
break;
}
}
auto material = builder.build(engine);
return downcast(material);

Some files were not shown because too many files have changed in this diff Show More