Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d064e2ed78 | ||
|
|
a22873bb2e | ||
|
|
b2801d0a5c | ||
|
|
1a5f1cc6ab | ||
|
|
9f5001d347 | ||
|
|
9042f628d4 | ||
|
|
83d71d0f57 | ||
|
|
cb8b1bfefa | ||
|
|
8824f59051 | ||
|
|
d8af04f08f | ||
|
|
559bc4eb96 | ||
|
|
c16cab239d | ||
|
|
68719f913a | ||
|
|
038ed69a92 | ||
|
|
69822a91cf | ||
|
|
24ff10b5db | ||
|
|
ec2f5b8078 | ||
|
|
538aa39127 | ||
|
|
8de56a2bbc | ||
|
|
ea5d7d4f47 |
@@ -8,5 +8,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
|||||||
|
|
||||||
## Release notes for next branch cut
|
## Release notes for next branch cut
|
||||||
|
|
||||||
- matdbg: Add support for debugging ESSL 1.0 shaders
|
- Support including PlatformMetal.h in C++ files.
|
||||||
- backend: New platform API to better handle external textures [⚠️ **New Material Version**]
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.filament:filament-android:1.56.7'
|
implementation 'com.google.android.filament:filament-android:1.57.0'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
|||||||
iOS projects can use CocoaPods to install the latest release:
|
iOS projects can use CocoaPods to install the latest release:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pod 'Filament', '~> 1.56.7'
|
pod 'Filament', '~> 1.57.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
@@ -7,6 +7,14 @@ 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
|
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||||
|
|
||||||
|
## v1.57.1
|
||||||
|
|
||||||
|
|
||||||
|
## v1.57.0
|
||||||
|
|
||||||
|
- matdbg: Add support for debugging ESSL 1.0 shaders
|
||||||
|
- backend: New platform API to better handle external textures [⚠️ **New Material Version**]
|
||||||
|
|
||||||
## v1.56.8
|
## v1.56.8
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -329,6 +329,18 @@ Java_com_google_android_filament_MaterialInstance_nSetCullingMode(JNIEnv*,
|
|||||||
instance->setCullingMode((MaterialInstance::CullingMode) cullingMode);
|
instance->setCullingMode((MaterialInstance::CullingMode) cullingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_com_google_android_filament_MaterialInstance_nSetCullingModeSeparate(JNIEnv*, jclass,
|
||||||
|
jlong nativeMaterialInstance,
|
||||||
|
jlong colorPassCullingMode, jlong shadowPassCullingMode) {
|
||||||
|
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||||
|
instance->setCullingMode(
|
||||||
|
(MaterialInstance::CullingMode) colorPassCullingMode,
|
||||||
|
(MaterialInstance::CullingMode) shadowPassCullingMode);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_com_google_android_filament_MaterialInstance_nSetColorWrite(JNIEnv*,
|
Java_com_google_android_filament_MaterialInstance_nSetColorWrite(JNIEnv*,
|
||||||
@@ -505,6 +517,14 @@ Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, j
|
|||||||
return (jint)instance->getCullingMode();
|
return (jint)instance->getCullingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_com_google_android_filament_MaterialInstance_nGetShadowCullingMode(JNIEnv* env, jclass,
|
||||||
|
jlong nativeMaterialInstance) {
|
||||||
|
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||||
|
return (jint)instance->getShadowCullingMode();
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
|
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
|
||||||
|
|||||||
+25
@@ -556,6 +556,20 @@ public class MaterialInstance {
|
|||||||
nSetCullingMode(getNativeObject(), mode.ordinal());
|
nSetCullingMode(getNativeObject(), mode.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the default triangle culling state that was set on the material separately for the
|
||||||
|
* color and shadow passes
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||||
|
* Rasterization: culling</a>
|
||||||
|
*/
|
||||||
|
public void setCullingMode(@NonNull Material.CullingMode colorPassCullingMode,
|
||||||
|
@NonNull Material.CullingMode shadowPassCullingMode) {
|
||||||
|
nSetCullingModeSeparate(getNativeObject(),
|
||||||
|
colorPassCullingMode.ordinal(), shadowPassCullingMode.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the face culling mode.
|
* Returns the face culling mode.
|
||||||
*/
|
*/
|
||||||
@@ -564,6 +578,14 @@ public class MaterialInstance {
|
|||||||
return sCullingModeValues[nGetCullingMode(getNativeObject())];
|
return sCullingModeValues[nGetCullingMode(getNativeObject())];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the face culling mode for the shadow passes.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Material.CullingMode getShadowCullingMode() {
|
||||||
|
return sCullingModeValues[nGetShadowCullingMode(getNativeObject())];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the default color-buffer write state that was set on the material.
|
* Overrides the default color-buffer write state that was set on the material.
|
||||||
*
|
*
|
||||||
@@ -920,6 +942,8 @@ public class MaterialInstance {
|
|||||||
|
|
||||||
private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided);
|
private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided);
|
||||||
private static native void nSetCullingMode(long nativeMaterialInstance, long mode);
|
private static native void nSetCullingMode(long nativeMaterialInstance, long mode);
|
||||||
|
private static native void nSetCullingModeSeparate(long nativeMaterialInstance,
|
||||||
|
long colorPassCullingMode, long shadowPassCullingMode);
|
||||||
private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable);
|
private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable);
|
||||||
private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable);
|
private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable);
|
||||||
private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable);
|
private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable);
|
||||||
@@ -952,6 +976,7 @@ public class MaterialInstance {
|
|||||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
|
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
|
||||||
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
|
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
|
||||||
private static native int nGetCullingMode(long nativeMaterialInstance);
|
private static native int nGetCullingMode(long nativeMaterialInstance);
|
||||||
|
private static native int nGetShadowCullingMode(long nativeMaterialInstance);
|
||||||
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
|
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
|
||||||
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
|
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
|
||||||
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
|
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
GROUP=com.google.android.filament
|
GROUP=com.google.android.filament
|
||||||
VERSION_NAME=1.56.7
|
VERSION_NAME=1.57.0
|
||||||
|
|
||||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ public:
|
|||||||
|
|
||||||
void clear() noexcept;
|
void clear() noexcept;
|
||||||
void reset(ExternalImage* UTILS_NULLABLE p) noexcept;
|
void reset(ExternalImage* UTILS_NULLABLE p) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend utils::io::ostream& operator<<(utils::io::ostream& out,
|
||||||
|
ExternalImageHandle const& handle);
|
||||||
};
|
};
|
||||||
|
|
||||||
using ExternalImageHandleRef = ExternalImageHandle const&;
|
using ExternalImageHandleRef = ExternalImageHandle const&;
|
||||||
@@ -165,7 +169,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @return nullptr on failure, or a pointer to the newly created driver.
|
* @return nullptr on failure, or a pointer to the newly created driver.
|
||||||
*/
|
*/
|
||||||
virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
|
virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext,
|
||||||
const DriverConfig& driverConfig) noexcept = 0;
|
const DriverConfig& driverConfig) noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -56,6 +57,18 @@ public:
|
|||||||
unsigned int id; // GLuint id
|
unsigned int id; // GLuint id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the OpenGL vendor string of the specified Driver instance.
|
||||||
|
* @return The GL_VENDOR string
|
||||||
|
*/
|
||||||
|
static utils::CString getVendorString(Driver const* UTILS_NONNULL driver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the OpenGL vendor string of the specified Driver instance
|
||||||
|
* @return The GL_RENDERER string
|
||||||
|
*/
|
||||||
|
static utils::CString getRendererString(Driver const* UTILS_NONNULL driver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the driver to destroy the OpenGL context. This should clean up any windows
|
* Called by the driver to destroy the OpenGL context. This should clean up any windows
|
||||||
* or buffers from initialization. This is for instance where `eglDestroyContext` would be
|
* or buffers from initialization. This is for instance where `eglDestroyContext` would be
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
|
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
|
||||||
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
|
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
|
||||||
#include <backend/platforms/OpenGLPlatform.h>
|
#include <backend/platforms/OpenGLPlatform.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ protected:
|
|||||||
* Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation
|
* Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation
|
||||||
* that supports OpenGL/OpenGL ES.
|
* that supports OpenGL/OpenGL ES.
|
||||||
*/
|
*/
|
||||||
Driver* createDriver(void* sharedContext,
|
Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override;
|
||||||
const Platform::DriverConfig& driverConfig) noexcept override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This returns zero. This method can be overridden to return something more useful.
|
* This returns zero. This method can be overridden to return something more useful.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
|
||||||
|
|
||||||
|
#import <Metal/Metal.h>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
struct MetalDevice {
|
||||||
|
id<MTLDevice> device;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MetalCommandQueue {
|
||||||
|
id<MTLCommandQueue> commandQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MetalCommandBuffer {
|
||||||
|
id<MTLCommandBuffer> commandBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::backend
|
||||||
|
|
||||||
|
#endif // TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_OBJC_H
|
||||||
@@ -20,12 +20,17 @@
|
|||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
struct PlatformMetalImpl;
|
struct PlatformMetalImpl;
|
||||||
|
|
||||||
|
// In order for this header to be compatible with Objective-C and C++, we use these wrappers around
|
||||||
|
// id<MTL*> objects.
|
||||||
|
// See PlatformMetal-Objc.h.
|
||||||
|
struct MetalDevice;
|
||||||
|
struct MetalCommandQueue;
|
||||||
|
struct MetalCommandBuffer;
|
||||||
|
|
||||||
class PlatformMetal final : public Platform {
|
class PlatformMetal final : public Platform {
|
||||||
public:
|
public:
|
||||||
PlatformMetal();
|
PlatformMetal();
|
||||||
@@ -41,21 +46,22 @@ public:
|
|||||||
* free to decide which one to use. On mobile systems with a single GPU, implementations should
|
* free to decide which one to use. On mobile systems with a single GPU, implementations should
|
||||||
* simply return the result of MTLCreateSystemDefaultDevice();
|
* simply return the result of MTLCreateSystemDefaultDevice();
|
||||||
*/
|
*/
|
||||||
virtual id<MTLDevice> createDevice() noexcept;
|
virtual void createDevice(MetalDevice& outDevice) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a command submission queue on the Metal device object.
|
* Create a command submission queue on the Metal device object.
|
||||||
*
|
*
|
||||||
* @param device The device which was returned from createDevice()
|
* @param device The device which was returned from createDevice()
|
||||||
*/
|
*/
|
||||||
virtual id<MTLCommandQueue> createCommandQueue(id<MTLDevice> device) noexcept;
|
virtual void createCommandQueue(
|
||||||
|
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
|
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
|
||||||
* guaranteed to execute before all subsequent command buffers created either by Filament, or
|
* guaranteed to execute before all subsequent command buffers created either by Filament, or
|
||||||
* further calls to this method.
|
* further calls to this method.
|
||||||
*/
|
*/
|
||||||
id<MTLCommandBuffer> createAndEnqueueCommandBuffer() noexcept;
|
void createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The action to take if a Drawable cannot be acquired.
|
* The action to take if a Drawable cannot be acquired.
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ public:
|
|||||||
// where the gpu only has one graphics queue. Then the client needs to ensure that no
|
// where the gpu only has one graphics queue. Then the client needs to ensure that no
|
||||||
// concurrent access can occur.
|
// concurrent access can occur.
|
||||||
uint32_t graphicsQueueIndex = 0xFFFFFFFF;
|
uint32_t graphicsQueueIndex = 0xFFFFFFFF;
|
||||||
|
bool debugUtilsSupported = false;
|
||||||
|
bool debugMarkersSupported = false;
|
||||||
|
bool multiviewSupported = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +91,7 @@ public:
|
|||||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||||
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
|
VkFormat depthFormat = VK_FORMAT_UNDEFINED;
|
||||||
VkExtent2D extent = {0, 0};
|
VkExtent2D extent = {0, 0};
|
||||||
|
uint32_t layerCount = 1;
|
||||||
bool isProtected = false;
|
bool isProtected = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -303,6 +307,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The layerCount of the external image
|
||||||
|
*/
|
||||||
|
uint32_t layerCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The layer count of the external image
|
* The layer count of the external image
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Set to true to print every command out on log.d. This requires RTTI and DEBUG
|
// Set to true to print every command out on log.d. This requires RTTI and DEBUG
|
||||||
#define DEBUG_COMMAND_STREAM false
|
#define DEBUG_COMMAND_STREAM true
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,13 @@ void Platform::ExternalImageHandle::incref(ExternalImage* p) noexcept {
|
|||||||
|
|
||||||
void Platform::ExternalImageHandle::decref(ExternalImage* p) noexcept {
|
void Platform::ExternalImageHandle::decref(ExternalImage* p) noexcept {
|
||||||
if (p) {
|
if (p) {
|
||||||
// When decrementing the ref-count, unless it reaches zero, there is no need to acquire data; we need to
|
// When decrementing the ref-count, unless it reaches zero, there is no need to acquire
|
||||||
// release all previous writes though so they can be visible to the thread that will actually delete the
|
// data; we need to release all previous writes though so they can be visible to the thread
|
||||||
// object.
|
// that will actually delete the object.
|
||||||
if (p->mRefCount.fetch_sub(1, std::memory_order_release) == 1) {
|
if (p->mRefCount.fetch_sub(1, std::memory_order_release) == 1) {
|
||||||
// if we reach zero, we're about to delete the object, we need to acquire all previous writes from other
|
// if we reach zero, we're about to delete the object, we need to acquire all previous
|
||||||
// threads (i.e.: the memory from other threads prior to the decref() need to be visible now.
|
// writes from other threads (i.e.: the memory from other threads prior to the decref()
|
||||||
|
// need to be visible now.
|
||||||
std::atomic_thread_fence(std::memory_order_acquire);
|
std::atomic_thread_fence(std::memory_order_acquire);
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
@@ -68,7 +69,8 @@ Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle&& rhs) no
|
|||||||
rhs.mTarget = nullptr;
|
rhs.mTarget = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle const& rhs) noexcept {
|
Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(
|
||||||
|
ExternalImageHandle const& rhs) noexcept {
|
||||||
if (UTILS_LIKELY(this != &rhs)) {
|
if (UTILS_LIKELY(this != &rhs)) {
|
||||||
incref(rhs.mTarget);
|
incref(rhs.mTarget);
|
||||||
decref(mTarget);
|
decref(mTarget);
|
||||||
@@ -77,7 +79,8 @@ Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(External
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle&& rhs) noexcept {
|
Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(
|
||||||
|
ExternalImageHandle&& rhs) noexcept {
|
||||||
if (UTILS_LIKELY(this != &rhs)) {
|
if (UTILS_LIKELY(this != &rhs)) {
|
||||||
decref(mTarget);
|
decref(mTarget);
|
||||||
mTarget = rhs.mTarget;
|
mTarget = rhs.mTarget;
|
||||||
@@ -97,6 +100,12 @@ void Platform::ExternalImageHandle::reset(ExternalImage* p) noexcept {
|
|||||||
mTarget = p;
|
mTarget = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::io::ostream& operator<<(utils::io::ostream& out,
|
||||||
|
Platform::ExternalImageHandle const& handle) {
|
||||||
|
out << "ExternalImageHandle{" << handle.mTarget << "}";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
Platform::ExternalImage::~ExternalImage() noexcept = default;
|
Platform::ExternalImage::~ExternalImage() noexcept = default;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "MetalTimerQuery.h"
|
#include "MetalTimerQuery.h"
|
||||||
|
|
||||||
#include <backend/platforms/PlatformMetal.h>
|
#include <backend/platforms/PlatformMetal.h>
|
||||||
|
#include <backend/platforms/PlatformMetal-ObjC.h>
|
||||||
|
|
||||||
#include <CoreVideo/CVMetalTexture.h>
|
#include <CoreVideo/CVMetalTexture.h>
|
||||||
#include <CoreVideo/CVPixelBuffer.h>
|
#include <CoreVideo/CVPixelBuffer.h>
|
||||||
@@ -120,7 +121,10 @@ MetalDriver::MetalDriver(
|
|||||||
TrackedMetalBuffer::setPlatform(platform);
|
TrackedMetalBuffer::setPlatform(platform);
|
||||||
ScopedAllocationTimer::setPlatform(platform);
|
ScopedAllocationTimer::setPlatform(platform);
|
||||||
|
|
||||||
mContext->device = mPlatform.createDevice();
|
MetalDevice device;
|
||||||
|
device.device = nil;
|
||||||
|
mPlatform.createDevice(device);
|
||||||
|
mContext->device = device.device;
|
||||||
assert_invariant(mContext->device);
|
assert_invariant(mContext->device);
|
||||||
|
|
||||||
mContext->emptyBuffer = [mContext->device newBufferWithLength:16
|
mContext->emptyBuffer = [mContext->device newBufferWithLength:16
|
||||||
@@ -186,7 +190,12 @@ MetalDriver::MetalDriver(
|
|||||||
[mContext->device.name containsString:@"Apple A8 GPU"] ||
|
[mContext->device.name containsString:@"Apple A8 GPU"] ||
|
||||||
[mContext->device.name containsString:@"Apple A7 GPU"];
|
[mContext->device.name containsString:@"Apple A7 GPU"];
|
||||||
|
|
||||||
mContext->commandQueue = mPlatform.createCommandQueue(mContext->device);
|
MetalCommandQueue commandQueue;
|
||||||
|
commandQueue.commandQueue = nil;
|
||||||
|
mPlatform.createCommandQueue(device, commandQueue);
|
||||||
|
assert_invariant(commandQueue.commandQueue);
|
||||||
|
|
||||||
|
mContext->commandQueue = commandQueue.commandQueue;
|
||||||
mContext->pipelineStateCache.setDevice(mContext->device);
|
mContext->pipelineStateCache.setDevice(mContext->device);
|
||||||
mContext->depthStencilStateCache.setDevice(mContext->device);
|
mContext->depthStencilStateCache.setDevice(mContext->device);
|
||||||
mContext->samplerStateCache.setDevice(mContext->device);
|
mContext->samplerStateCache.setDevice(mContext->device);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <backend/platforms/PlatformMetal.h>
|
#include <backend/platforms/PlatformMetal.h>
|
||||||
|
#include <backend/platforms/PlatformMetal-ObjC.h>
|
||||||
|
|
||||||
#include "MetalDriverFactory.h"
|
#include "MetalDriverFactory.h"
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::Dri
|
|||||||
return MetalDriverFactory::create(this, driverConfig);
|
return MetalDriverFactory::create(this, driverConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLDevice> PlatformMetal::createDevice() noexcept {
|
void PlatformMetal::createDevice(MetalDevice& outDevice) noexcept {
|
||||||
id<MTLDevice> result;
|
id<MTLDevice> result;
|
||||||
|
|
||||||
#if !defined(FILAMENT_IOS)
|
#if !defined(FILAMENT_IOS)
|
||||||
@@ -72,19 +73,20 @@ id<MTLDevice> PlatformMetal::createDevice() noexcept {
|
|||||||
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
|
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
|
||||||
<< utils::io::endl;
|
<< utils::io::endl;
|
||||||
|
|
||||||
return result;
|
outDevice.device = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLCommandQueue> PlatformMetal::createCommandQueue(id<MTLDevice> device) noexcept {
|
void PlatformMetal::createCommandQueue(
|
||||||
pImpl->mCommandQueue = [device newCommandQueue];
|
MetalDevice& device, MetalCommandQueue& outCommandQueue) noexcept {
|
||||||
|
pImpl->mCommandQueue = [device.device newCommandQueue];
|
||||||
pImpl->mCommandQueue.label = @"Filament";
|
pImpl->mCommandQueue.label = @"Filament";
|
||||||
return pImpl->mCommandQueue;
|
outCommandQueue.commandQueue = pImpl->mCommandQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLCommandBuffer> PlatformMetal::createAndEnqueueCommandBuffer() noexcept {
|
void PlatformMetal::createAndEnqueueCommandBuffer(MetalCommandBuffer& outCommandBuffer) noexcept {
|
||||||
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
||||||
[commandBuffer enqueue];
|
[commandBuffer enqueue];
|
||||||
return commandBuffer;
|
outCommandBuffer.commandBuffer = commandBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
#include <backend/Handle.h>
|
||||||
|
|
||||||
#include "noop/NoopDriver.h"
|
#include "noop/NoopDriver.h"
|
||||||
#include "CommandStreamDispatcher.h"
|
#include "CommandStreamDispatcher.h"
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
|
|
||||||
|
#include "private/backend/CommandStream.h"
|
||||||
#include "private/backend/Dispatcher.h"
|
#include "private/backend/Dispatcher.h"
|
||||||
#include "private/backend/DriverApi.h"
|
#include "private/backend/DriverApi.h"
|
||||||
|
|
||||||
@@ -46,9 +47,11 @@
|
|||||||
#include <utils/BitmaskEnum.h>
|
#include <utils/BitmaskEnum.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/CString.h>
|
#include <utils/CString.h>
|
||||||
|
#include <utils/Invocable.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/Systrace.h>
|
#include <utils/Systrace.h>
|
||||||
|
#include <utils/Slice.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/ostream.h>
|
#include <utils/ostream.h>
|
||||||
@@ -154,8 +157,8 @@ using namespace GLUtils;
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
||||||
void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept {
|
void* const /*sharedGLContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||||
assert_invariant(platform);
|
assert_invariant(platform);
|
||||||
OpenGLPlatform* const ec = platform;
|
OpenGLPlatform* const ec = platform;
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
constexpr size_t defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||||
Platform::DriverConfig validConfig{ driverConfig };
|
Platform::DriverConfig validConfig{ driverConfig };
|
||||||
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
|
||||||
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
|
||||||
@@ -277,7 +280,6 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
|
|||||||
driverConfig.disableHandleUseAfterFreeCheck),
|
driverConfig.disableHandleUseAfterFreeCheck),
|
||||||
mDriverConfig(driverConfig),
|
mDriverConfig(driverConfig),
|
||||||
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
|
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
|
||||||
|
|
||||||
// set a reasonable default value for our stream array
|
// set a reasonable default value for our stream array
|
||||||
mTexturesWithStreamsAttached.reserve(8);
|
mTexturesWithStreamsAttached.reserve(8);
|
||||||
mStreamsWithPendingAcquiredImage.reserve(8);
|
mStreamsWithPendingAcquiredImage.reserve(8);
|
||||||
@@ -366,8 +368,8 @@ void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
|
|||||||
mContext.bindSampler(unit, sampler);
|
mContext.bindSampler(unit, sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
void OpenGLDriver::setPushConstant(ShaderStage stage, uint8_t index,
|
||||||
backend::PushConstantVariant value) {
|
PushConstantVariant value) {
|
||||||
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
|
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
|
||||||
|
|
||||||
#if FILAMENT_ENABLE_MATDBG
|
#if FILAMENT_ENABLE_MATDBG
|
||||||
@@ -376,7 +378,7 @@ void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
utils::Slice<std::pair<GLint, ConstantType>> constants;
|
Slice<std::pair<GLint, ConstantType>> constants;
|
||||||
if (stage == ShaderStage::VERTEX) {
|
if (stage == ShaderStage::VERTEX) {
|
||||||
constants = mCurrentPushConstants->vertexConstants;
|
constants = mCurrentPushConstants->vertexConstants;
|
||||||
} else if (stage == ShaderStage::FRAGMENT) {
|
} else if (stage == ShaderStage::FRAGMENT) {
|
||||||
@@ -681,7 +683,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
|
|||||||
bo->gl.buffer = malloc(byteCount);
|
bo->gl.buffer = malloc(byteCount);
|
||||||
memset(bo->gl.buffer, 0, byteCount);
|
memset(bo->gl.buffer, 0, byteCount);
|
||||||
} else {
|
} else {
|
||||||
bo->gl.binding = GLUtils::getBufferBindingType(bindingType);
|
bo->gl.binding = getBufferBindingType(bindingType);
|
||||||
glGenBuffers(1, &bo->gl.id);
|
glGenBuffers(1, &bo->gl.id);
|
||||||
gl.bindBuffer(bo->gl.binding, bo->gl.id);
|
gl.bindBuffer(bo->gl.binding, bo->gl.id);
|
||||||
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
|
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
|
||||||
@@ -758,7 +760,7 @@ void OpenGLDriver::createProgramR(Handle<HwProgram> ph, Program&& program) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
void OpenGLDriver::textureStorage(GLTexture* t,
|
||||||
uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept {
|
uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept {
|
||||||
|
|
||||||
auto& gl = mContext;
|
auto& gl = mContext;
|
||||||
@@ -1144,7 +1146,7 @@ void OpenGLDriver::createTextureExternalImageR(Handle<HwTexture> th, SamplerType
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
void OpenGLDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||||
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
|
TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage,
|
||||||
void* image, uint32_t plane) {
|
void* image, uint32_t plane) {
|
||||||
// not relevant for the OpenGL backend
|
// not relevant for the OpenGL backend
|
||||||
}
|
}
|
||||||
@@ -1460,7 +1462,7 @@ void OpenGLDriver::framebufferTexture(TargetBufferInfo const& binfo,
|
|||||||
&& ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0)
|
&& ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0)
|
||||||
|| gl.ext.EXT_multisampled_render_to_texture2)) {
|
|| gl.ext.EXT_multisampled_render_to_texture2)) {
|
||||||
assert_invariant(rt->gl.samples > 1);
|
assert_invariant(rt->gl.samples > 1);
|
||||||
// We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture,
|
// We have a multi-sample rendertarget, and we have EXT_multisampled_render_to_texture,
|
||||||
// so, we can directly use a 1-sample texture as attachment, multi-sample resolve,
|
// so, we can directly use a 1-sample texture as attachment, multi-sample resolve,
|
||||||
// will happen automagically and efficiently in the driver.
|
// will happen automagically and efficiently in the driver.
|
||||||
// This extension only exists on OpenGL ES.
|
// This extension only exists on OpenGL ES.
|
||||||
@@ -1660,9 +1662,9 @@ void OpenGLDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|||||||
rt->gl.samples = samples;
|
rt->gl.samples = samples;
|
||||||
rt->targets = targets;
|
rt->targets = targets;
|
||||||
|
|
||||||
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmin = { std::numeric_limits<uint32_t>::max() };
|
UTILS_UNUSED_IN_RELEASE vec2<uint32_t> tmin = { std::numeric_limits<uint32_t>::max() };
|
||||||
UTILS_UNUSED_IN_RELEASE math::vec2<uint32_t> tmax = { 0 };
|
UTILS_UNUSED_IN_RELEASE vec2<uint32_t> tmax = { 0 };
|
||||||
auto checkDimensions = [&tmin, &tmax](GLTexture* t, uint8_t level) {
|
auto checkDimensions = [&tmin, &tmax](GLTexture const* t, uint8_t level) {
|
||||||
const auto twidth = std::max(1u, t->width >> level);
|
const auto twidth = std::max(1u, t->width >> level);
|
||||||
const auto theight = std::max(1u, t->height >> level);
|
const auto theight = std::max(1u, t->height >> level);
|
||||||
tmin = { std::min(tmin.x, twidth), std::min(tmin.y, theight) };
|
tmin = { std::min(tmin.x, twidth), std::min(tmin.y, theight) };
|
||||||
@@ -2364,11 +2366,11 @@ bool OpenGLDriver::isStereoSupported() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (mDriverConfig.stereoscopicType) {
|
switch (mDriverConfig.stereoscopicType) {
|
||||||
case backend::StereoscopicType::INSTANCED:
|
case StereoscopicType::INSTANCED:
|
||||||
return mContext.ext.EXT_clip_cull_distance;
|
return mContext.ext.EXT_clip_cull_distance;
|
||||||
case backend::StereoscopicType::MULTIVIEW:
|
case StereoscopicType::MULTIVIEW:
|
||||||
return mContext.ext.OVR_multiview2;
|
return mContext.ext.OVR_multiview2;
|
||||||
case backend::StereoscopicType::NONE:
|
case StereoscopicType::NONE:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2381,7 +2383,7 @@ bool OpenGLDriver::isDepthStencilResolveSupported() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat format) {
|
bool OpenGLDriver::isDepthStencilBlitSupported(TextureFormat) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2415,12 +2417,12 @@ FeatureLevel OpenGLDriver::getFeatureLevel() {
|
|||||||
return mContext.getFeatureLevel();
|
return mContext.getFeatureLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
math::float2 OpenGLDriver::getClipSpaceParams() {
|
float2 OpenGLDriver::getClipSpaceParams() {
|
||||||
return mContext.ext.EXT_clip_control ?
|
return mContext.ext.EXT_clip_control ?
|
||||||
// z-coordinate of virtual and physical clip-space is in [-w, 0]
|
// z-coordinate of virtual and physical clip-space is in [-w, 0]
|
||||||
math::float2{ 1.0f, 0.0f } :
|
float2{ 1.0f, 0.0f } :
|
||||||
// z-coordinate of virtual clip-space is in [-w,0], physical is in [-w, w]
|
// z-coordinate of virtual clip-space is in [-w,0], physical is in [-w, w]
|
||||||
math::float2{ 2.0f, -1.0f };
|
float2{ 2.0f, -1.0f };
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t OpenGLDriver::getMaxDrawBuffers() {
|
uint8_t OpenGLDriver::getMaxDrawBuffers() {
|
||||||
@@ -2484,7 +2486,7 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
|
|||||||
// Updating driver objects
|
// Updating driver objects
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
void OpenGLDriver::setDebugTag(HandleBase::HandleId handleId, CString tag) {
|
||||||
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
|
mHandleAllocator.associateTagToHandle(handleId, std::move(tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2660,7 +2662,7 @@ void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
|
|||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
void OpenGLDriver::setTextureData(GLTexture const* t, uint32_t level,
|
||||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
PixelBufferDescriptor&& p) {
|
PixelBufferDescriptor&& p) {
|
||||||
@@ -2769,7 +2771,7 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level,
|
|||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
void OpenGLDriver::setCompressedTextureData(GLTexture const* t, uint32_t level,
|
||||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
PixelBufferDescriptor&& p) {
|
PixelBufferDescriptor&& p) {
|
||||||
@@ -3410,8 +3412,8 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::readBufferSubData(backend::BufferObjectHandle boh,
|
void OpenGLDriver::readBufferSubData(BufferObjectHandle boh,
|
||||||
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
|
uint32_t offset, uint32_t size, BufferDescriptor&& p) {
|
||||||
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
|
UTILS_UNUSED_IN_RELEASE auto& gl = mContext;
|
||||||
assert_invariant(!gl.isES2());
|
assert_invariant(!gl.isES2());
|
||||||
|
|
||||||
@@ -3489,14 +3491,6 @@ void OpenGLDriver::whenFrameComplete(const std::function<void()>& fn) noexcept {
|
|||||||
|
|
||||||
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
|
void OpenGLDriver::whenGpuCommandsComplete(const std::function<void()>& fn) noexcept {
|
||||||
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
// glFenceSync can return 0 in certain situations. For example, we've seen this happen on Web
|
|
||||||
// when the GL context has been lost.
|
|
||||||
// Unfortunately, there's not much we can do here. The fn callback will never execute, which
|
|
||||||
// could cause issues. If we've lost the WebGL context though, Filament is most likely shutting
|
|
||||||
// down anyway, so in practice this might not be a big problem.
|
|
||||||
if (!sync) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mGpuCommandCompleteOps.emplace_back(sync, fn);
|
mGpuCommandCompleteOps.emplace_back(sync, fn);
|
||||||
CHECK_GL_ERROR(utils::slog.e)
|
CHECK_GL_ERROR(utils::slog.e)
|
||||||
}
|
}
|
||||||
@@ -3566,13 +3560,13 @@ void OpenGLDriver::beginFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch, CallbackHandler* handler,
|
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain>, CallbackHandler*,
|
||||||
FrameScheduledCallback&& callback, uint64_t flags) {
|
FrameScheduledCallback&& /*callback*/, uint64_t /*flags*/) {
|
||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain>,
|
||||||
CallbackHandler* handler, utils::Invocable<void(void)>&& callback) {
|
CallbackHandler*, Invocable<void()>&& /*callback*/) {
|
||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3603,9 +3597,9 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::updateDescriptorSetBuffer(
|
void OpenGLDriver::updateDescriptorSetBuffer(
|
||||||
backend::DescriptorSetHandle dsh,
|
DescriptorSetHandle dsh,
|
||||||
backend::descriptor_binding_t binding,
|
descriptor_binding_t binding,
|
||||||
backend::BufferObjectHandle boh,
|
BufferObjectHandle boh,
|
||||||
uint32_t offset, uint32_t size) {
|
uint32_t offset, uint32_t size) {
|
||||||
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
|
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
|
||||||
GLBufferObject* bo = boh ? handle_cast<GLBufferObject*>(boh) : nullptr;
|
GLBufferObject* bo = boh ? handle_cast<GLBufferObject*>(boh) : nullptr;
|
||||||
@@ -3613,9 +3607,9 @@ void OpenGLDriver::updateDescriptorSetBuffer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::updateDescriptorSetTexture(
|
void OpenGLDriver::updateDescriptorSetTexture(
|
||||||
backend::DescriptorSetHandle dsh,
|
DescriptorSetHandle dsh,
|
||||||
backend::descriptor_binding_t binding,
|
descriptor_binding_t binding,
|
||||||
backend::TextureHandle th,
|
TextureHandle th,
|
||||||
SamplerParams params) {
|
SamplerParams params) {
|
||||||
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
|
GLDescriptorSet* ds = handle_cast<GLDescriptorSet*>(dsh);
|
||||||
GLTexture* t = th ? handle_cast<GLTexture*>(th) : nullptr;
|
GLTexture* t = th ? handle_cast<GLTexture*>(th) : nullptr;
|
||||||
@@ -3648,7 +3642,7 @@ void OpenGLDriver::finish(int) {
|
|||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
|
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
|
||||||
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
|
float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
|
||||||
|
|
||||||
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
|
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
|
||||||
mContext.colorMask(GL_TRUE);
|
mContext.colorMask(GL_TRUE);
|
||||||
@@ -3971,9 +3965,9 @@ void OpenGLDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::bindDescriptorSet(
|
void OpenGLDriver::bindDescriptorSet(
|
||||||
backend::DescriptorSetHandle dsh,
|
DescriptorSetHandle dsh,
|
||||||
backend::descriptor_set_t set,
|
descriptor_set_t set,
|
||||||
backend::DescriptorSetOffsetArray&& offsets) {
|
DescriptorSetOffsetArray&& offsets) {
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(!dsh)) {
|
if (UTILS_UNLIKELY(!dsh)) {
|
||||||
mBoundDescriptorSets[set].dsh = dsh;
|
mBoundDescriptorSets[set].dsh = dsh;
|
||||||
@@ -4005,7 +3999,7 @@ void OpenGLDriver::bindDescriptorSet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept {
|
void OpenGLDriver::updateDescriptors(bitset8 invalidDescriptorSets) noexcept {
|
||||||
assert_invariant(mBoundProgram);
|
assert_invariant(mBoundProgram);
|
||||||
auto const offsetOnly = mInvalidDescriptorSetBindingOffsets & ~mInvalidDescriptorSetBindings;
|
auto const offsetOnly = mInvalidDescriptorSetBindingOffsets & ~mInvalidDescriptorSetBindings;
|
||||||
invalidDescriptorSets.forEachSetBit([this, offsetOnly,
|
invalidDescriptorSets.forEachSetBit([this, offsetOnly,
|
||||||
@@ -4117,7 +4111,7 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, math::uint3 workGroupCount) {
|
void OpenGLDriver::dispatchCompute(Handle<HwProgram> program, uint3 workGroupCount) {
|
||||||
DEBUG_MARKER()
|
DEBUG_MARKER()
|
||||||
getShaderCompilerService().tick();
|
getShaderCompilerService().tick();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "DriverBase.h"
|
#include "DriverBase.h"
|
||||||
#include "OpenGLContext.h"
|
#include "OpenGLContext.h"
|
||||||
|
#include "OpenGLDriverBase.h"
|
||||||
#include "OpenGLTimerQuery.h"
|
#include "OpenGLTimerQuery.h"
|
||||||
#include "GLBufferObject.h"
|
#include "GLBufferObject.h"
|
||||||
#include "GLDescriptorSet.h"
|
#include "GLDescriptorSet.h"
|
||||||
@@ -26,11 +27,10 @@
|
|||||||
#include "GLTexture.h"
|
#include "GLTexture.h"
|
||||||
#include "ShaderCompilerService.h"
|
#include "ShaderCompilerService.h"
|
||||||
|
|
||||||
#include <backend/platforms/OpenGLPlatform.h>
|
|
||||||
|
|
||||||
#include <backend/AcquiredImage.h>
|
#include <backend/AcquiredImage.h>
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
#include <backend/Handle.h>
|
#include <backend/Handle.h>
|
||||||
|
#include <backend/PipelineState.h>
|
||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
#include <backend/Program.h>
|
#include <backend/Program.h>
|
||||||
#include <backend/TargetBufferInfo.h>
|
#include <backend/TargetBufferInfo.h>
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <utils/bitset.h>
|
#include <utils/bitset.h>
|
||||||
#include <utils/FixedCapacityVector.h>
|
#include <utils/FixedCapacityVector.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
|
|
||||||
#include <math/vec4.h>
|
#include <math/vec4.h>
|
||||||
@@ -74,14 +75,14 @@ class OpenGLProgram;
|
|||||||
class TimerQueryFactoryInterface;
|
class TimerQueryFactoryInterface;
|
||||||
struct PushConstantBundle;
|
struct PushConstantBundle;
|
||||||
|
|
||||||
class OpenGLDriver final : public DriverBase {
|
class OpenGLDriver final : public OpenGLDriverBase {
|
||||||
inline explicit OpenGLDriver(OpenGLPlatform* platform,
|
inline explicit OpenGLDriver(OpenGLPlatform* platform,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept;
|
const Platform::DriverConfig& driverConfig) noexcept;
|
||||||
~OpenGLDriver() noexcept final;
|
~OpenGLDriver() noexcept override;
|
||||||
Dispatcher getDispatcher() const noexcept final;
|
Dispatcher getDispatcher() const noexcept override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext,
|
static OpenGLDriver* create(OpenGLPlatform* platform, void* sharedGLContext,
|
||||||
const Platform::DriverConfig& driverConfig) noexcept;
|
const Platform::DriverConfig& driverConfig) noexcept;
|
||||||
|
|
||||||
class DebugMarker {
|
class DebugMarker {
|
||||||
@@ -184,7 +185,7 @@ public:
|
|||||||
std::condition_variable cond;
|
std::condition_variable cond;
|
||||||
FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED };
|
FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED };
|
||||||
};
|
};
|
||||||
std::shared_ptr<State> state{ std::make_shared<GLFence::State>() };
|
std::shared_ptr<State> state{ std::make_shared<State>() };
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenGLDriver(OpenGLDriver const&) = delete;
|
OpenGLDriver(OpenGLDriver const&) = delete;
|
||||||
@@ -203,13 +204,21 @@ private:
|
|||||||
return mShaderCompilerService;
|
return mShaderCompilerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderModel getShaderModel() const noexcept final;
|
ShaderModel getShaderModel() const noexcept override;
|
||||||
ShaderLanguage getShaderLanguage() const noexcept final;
|
ShaderLanguage getShaderLanguage() const noexcept override;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver interface
|
* OpenGLDriver interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
utils::CString getVendorString() const noexcept override {
|
||||||
|
return utils::CString{ mContext.state.vendor };
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::CString getRendererString() const noexcept override {
|
||||||
|
return utils::CString{ mContext.state.renderer };
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
friend class ConcreteDispatcher;
|
friend class ConcreteDispatcher;
|
||||||
|
|
||||||
@@ -236,21 +245,21 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename D, typename B, typename ... ARGS>
|
template<typename D, typename B, typename ... ARGS>
|
||||||
typename std::enable_if<std::is_base_of<B, D>::value, D>::type*
|
std::enable_if_t<std::is_base_of_v<B, D>, D>*
|
||||||
construct(Handle<B> const& handle, ARGS&& ... args) {
|
construct(Handle<B> const& handle, ARGS&& ... args) {
|
||||||
return mHandleAllocator.destroyAndConstruct<D, B>(handle, std::forward<ARGS>(args) ...);
|
return mHandleAllocator.destroyAndConstruct<D, B>(handle, std::forward<ARGS>(args) ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename B, typename D,
|
template<typename B, typename D,
|
||||||
typename = typename std::enable_if<std::is_base_of<B, D>::value, D>::type>
|
typename = std::enable_if_t<std::is_base_of_v<B, D>, D>>
|
||||||
void destruct(Handle<B>& handle, D const* p) noexcept {
|
void destruct(Handle<B>& handle, D const* p) noexcept {
|
||||||
return mHandleAllocator.deallocate(handle, p);
|
return mHandleAllocator.deallocate(handle, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Dp, typename B>
|
template<typename Dp, typename B>
|
||||||
typename std::enable_if_t<
|
std::enable_if_t<
|
||||||
std::is_pointer_v<Dp> &&
|
std::is_pointer_v<Dp> &&
|
||||||
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
|
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
|
||||||
handle_cast(Handle<B>& handle) {
|
handle_cast(Handle<B>& handle) {
|
||||||
return mHandleAllocator.handle_cast<Dp, B>(handle);
|
return mHandleAllocator.handle_cast<Dp, B>(handle);
|
||||||
}
|
}
|
||||||
@@ -261,9 +270,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Dp, typename B>
|
template<typename Dp, typename B>
|
||||||
inline typename std::enable_if_t<
|
std::enable_if_t<
|
||||||
std::is_pointer_v<Dp> &&
|
std::is_pointer_v<Dp> &&
|
||||||
std::is_base_of_v<B, typename std::remove_pointer_t<Dp>>, Dp>
|
std::is_base_of_v<B, std::remove_pointer_t<Dp>>, Dp>
|
||||||
handle_cast(Handle<B> const& handle) {
|
handle_cast(Handle<B> const& handle) {
|
||||||
return mHandleAllocator.handle_cast<Dp, B>(handle);
|
return mHandleAllocator.handle_cast<Dp, B>(handle);
|
||||||
}
|
}
|
||||||
@@ -288,13 +297,13 @@ private:
|
|||||||
|
|
||||||
void setStencilState(StencilState ss) noexcept;
|
void setStencilState(StencilState ss) noexcept;
|
||||||
|
|
||||||
void setTextureData(GLTexture* t,
|
void setTextureData(GLTexture const* t,
|
||||||
uint32_t level,
|
uint32_t level,
|
||||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
PixelBufferDescriptor&& p);
|
PixelBufferDescriptor&& p);
|
||||||
|
|
||||||
void setCompressedTextureData(GLTexture* t,
|
void setCompressedTextureData(GLTexture const* t,
|
||||||
uint32_t level,
|
uint32_t level,
|
||||||
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||||
uint32_t width, uint32_t height, uint32_t depth,
|
uint32_t width, uint32_t height, uint32_t depth,
|
||||||
@@ -303,7 +312,7 @@ private:
|
|||||||
void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width,
|
void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width,
|
||||||
uint32_t height, uint8_t samples) const noexcept;
|
uint32_t height, uint8_t samples) const noexcept;
|
||||||
|
|
||||||
void textureStorage(OpenGLDriver::GLTexture* t, uint32_t width, uint32_t height,
|
void textureStorage(GLTexture* t, uint32_t width, uint32_t height,
|
||||||
uint32_t depth, bool useProtectedMemory) noexcept;
|
uint32_t depth, bool useProtectedMemory) noexcept;
|
||||||
|
|
||||||
/* State tracking GL wrappers... */
|
/* State tracking GL wrappers... */
|
||||||
@@ -335,9 +344,9 @@ private:
|
|||||||
void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept;
|
void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
backend::DescriptorSetHandle dsh;
|
DescriptorSetHandle dsh;
|
||||||
std::array<uint32_t, CONFIG_UNIFORM_BINDING_COUNT> offsets;
|
std::array<uint32_t, CONFIG_UNIFORM_BINDING_COUNT> offsets;
|
||||||
} mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT];
|
} mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT] = {};
|
||||||
|
|
||||||
void clearWithRasterPipe(TargetBufferFlags clearFlags,
|
void clearWithRasterPipe(TargetBufferFlags clearFlags,
|
||||||
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept;
|
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept;
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
|
||||||
|
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
|
||||||
|
|
||||||
|
#include "DriverBase.h"
|
||||||
|
|
||||||
|
#include <utils/CString.h>
|
||||||
|
|
||||||
|
namespace filament::backend {
|
||||||
|
|
||||||
|
class OpenGLDriverBase : public DriverBase {
|
||||||
|
protected:
|
||||||
|
~OpenGLDriverBase() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual utils::CString getVendorString() const noexcept = 0;
|
||||||
|
virtual utils::CString getRendererString() const noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // filament::backend
|
||||||
|
|
||||||
|
#endif //TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <backend/platforms/OpenGLPlatform.h>
|
#include <backend/platforms/OpenGLPlatform.h>
|
||||||
|
|
||||||
|
#include "OpenGLDriverBase.h"
|
||||||
#include "OpenGLDriverFactory.h"
|
#include "OpenGLDriverFactory.h"
|
||||||
|
|
||||||
#include <backend/AcquiredImage.h>
|
#include <backend/AcquiredImage.h>
|
||||||
@@ -23,21 +24,45 @@
|
|||||||
#include <backend/Platform.h>
|
#include <backend/Platform.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "OpenGLDriver.h"
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
OpenGLDriverBase::~OpenGLDriverBase() = default;
|
||||||
|
|
||||||
Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform,
|
Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform,
|
||||||
void* sharedContext, const Platform::DriverConfig& driverConfig) {
|
void* sharedContext, const DriverConfig& driverConfig) {
|
||||||
return OpenGLDriverFactory::create(platform, sharedContext, driverConfig);
|
return OpenGLDriverFactory::create(platform, sharedContext, driverConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLPlatform::~OpenGLPlatform() noexcept = default;
|
OpenGLPlatform::~OpenGLPlatform() noexcept = default;
|
||||||
|
|
||||||
|
utils::CString OpenGLPlatform::getVendorString(Driver const* driver) {
|
||||||
|
auto const p = static_cast<OpenGLDriverBase const*>(driver);
|
||||||
|
#if UTILS_HAS_RTTI
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(dynamic_cast<OpenGLDriverBase const*>(driver))
|
||||||
|
<< "Driver* has not been allocated with OpenGLPlatform";
|
||||||
|
#endif
|
||||||
|
return p->getVendorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::CString OpenGLPlatform::getRendererString(Driver const* driver) {
|
||||||
|
auto const p = static_cast<OpenGLDriverBase const*>(driver);
|
||||||
|
#if UTILS_HAS_RTTI
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(dynamic_cast<OpenGLDriverBase const*>(driver))
|
||||||
|
<< "Driver* has not been allocated with OpenGLPlatform";
|
||||||
|
#endif
|
||||||
|
return p->getRendererString();
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
|
void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain,
|
||||||
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
|
utils::Invocable<void()>, utils::Invocable<void(size_t)>) noexcept {
|
||||||
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
|
makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain);
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
|
|||||||
clearGlError();
|
clearGlError();
|
||||||
|
|
||||||
// success!!
|
// success!!
|
||||||
return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig);
|
return createDefaultDriver(this, sharedContext, driverConfig);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
// if we're here, we've failed
|
// if we're here, we've failed
|
||||||
@@ -551,7 +551,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(
|
|||||||
return sc;
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
|
void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept {
|
||||||
if (swapChain) {
|
if (swapChain) {
|
||||||
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
||||||
if (sc->sur != EGL_NO_SURFACE) {
|
if (sc->sur != EGL_NO_SURFACE) {
|
||||||
@@ -564,7 +564,7 @@ void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept {
|
bool PlatformEGL::isSwapChainProtected(SwapChain* swapChain) noexcept {
|
||||||
if (swapChain) {
|
if (swapChain) {
|
||||||
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
||||||
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
|
return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT);
|
||||||
@@ -585,10 +585,10 @@ bool PlatformEGL::makeCurrent(ContextType type,
|
|||||||
return success == EGL_TRUE ? true : false;
|
return success == EGL_TRUE ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
|
void PlatformEGL::makeCurrent(SwapChain* drawSwapChain,
|
||||||
Platform::SwapChain* readSwapChain,
|
SwapChain* readSwapChain,
|
||||||
utils::Invocable<void()> preContextChange,
|
Invocable<void()> preContextChange,
|
||||||
utils::Invocable<void(size_t index)> postContextChange) noexcept {
|
Invocable<void(size_t index)> postContextChange) noexcept {
|
||||||
|
|
||||||
assert_invariant(drawSwapChain);
|
assert_invariant(drawSwapChain);
|
||||||
assert_invariant(readSwapChain);
|
assert_invariant(readSwapChain);
|
||||||
@@ -647,7 +647,7 @@ void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformEGL::commit(Platform::SwapChain* swapChain) noexcept {
|
void PlatformEGL::commit(SwapChain* swapChain) noexcept {
|
||||||
if (swapChain) {
|
if (swapChain) {
|
||||||
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
SwapChainEGL const* const sc = static_cast<SwapChainEGL const*>(swapChain);
|
||||||
if (sc->sur != EGL_NO_SURFACE) {
|
if (sc->sur != EGL_NO_SURFACE) {
|
||||||
@@ -670,7 +670,7 @@ Platform::Fence* PlatformEGL::createFence() noexcept {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept {
|
void PlatformEGL::destroyFence(Fence* fence) noexcept {
|
||||||
#ifdef EGL_KHR_reusable_sync
|
#ifdef EGL_KHR_reusable_sync
|
||||||
EGLSyncKHR sync = (EGLSyncKHR) fence;
|
EGLSyncKHR sync = (EGLSyncKHR) fence;
|
||||||
if (sync != EGL_NO_SYNC_KHR) {
|
if (sync != EGL_NO_SYNC_KHR) {
|
||||||
@@ -680,7 +680,7 @@ void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FenceStatus PlatformEGL::waitFence(
|
FenceStatus PlatformEGL::waitFence(
|
||||||
Platform::Fence* fence, uint64_t timeout) noexcept {
|
Fence* fence, uint64_t timeout) noexcept {
|
||||||
#ifdef EGL_KHR_reusable_sync
|
#ifdef EGL_KHR_reusable_sync
|
||||||
EGLSyncKHR sync = (EGLSyncKHR) fence;
|
EGLSyncKHR sync = (EGLSyncKHR) fence;
|
||||||
if (sync != EGL_NO_SYNC_KHR) {
|
if (sync != EGL_NO_SYNC_KHR) {
|
||||||
@@ -746,7 +746,7 @@ void PlatformEGL::initializeGlExtensions() noexcept {
|
|||||||
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
|
ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3");
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept {
|
EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ContextType::NONE:
|
case ContextType::NONE:
|
||||||
return EGL_NO_CONTEXT;
|
return EGL_NO_CONTEXT;
|
||||||
|
|||||||
@@ -163,13 +163,24 @@ public:
|
|||||||
return mProtectedMemorySupported;
|
return mProtectedMemorySupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isImageView2DOn3DImageSupported() const noexcept {
|
||||||
|
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||||
};
|
};
|
||||||
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
|
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||||
|
};
|
||||||
|
VkPhysicalDevicePortabilitySubsetFeaturesKHR mPortabilitySubsetFeatures = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||||
|
// By default, on platforms where we don't have portability subset, then this feature must
|
||||||
|
// exists. We only fill this struct only when portability subset is needed (i.e.
|
||||||
|
// non-conformant vulkan implementation).
|
||||||
|
.imageView2DOn3DImage = VK_TRUE,
|
||||||
};
|
};
|
||||||
bool mDebugMarkersSupported = false;
|
bool mDebugMarkersSupported = false;
|
||||||
bool mDebugUtilsSupported = false;
|
bool mDebugUtilsSupported = false;
|
||||||
|
|||||||
@@ -579,7 +579,7 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
|
|||||||
|
|
||||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||||
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||||
1, metadata.width, metadata.height, usage, mStagePool);
|
1, metadata.width, metadata.height, /*depth=*/1, usage, mStagePool);
|
||||||
|
|
||||||
texture.inc();
|
texture.inc();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,6 +128,15 @@ fvkmemory::resource_ptr<VulkanTexture> initMsaaTexture(
|
|||||||
return msTexture;
|
return msTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanAttachment createSwapchainAttachment(const fvkmemory::resource_ptr<VulkanTexture> texture) {
|
||||||
|
return VulkanAttachment {
|
||||||
|
.texture = texture,
|
||||||
|
.level = 0,
|
||||||
|
.layerCount = static_cast<uint8_t>(texture ? texture->getPrimaryViewRange().layerCount : 1),
|
||||||
|
.layer = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr<VulkanTexture> texture) {
|
void VulkanDescriptorSet::acquire(fvkmemory::resource_ptr<VulkanTexture> texture) {
|
||||||
@@ -274,22 +283,21 @@ void VulkanRenderTarget::bindToSwapChain(fvkmemory::resource_ptr<VulkanSwapChain
|
|||||||
height = extent.height;
|
height = extent.height;
|
||||||
mProtected = swapchain->isProtected();
|
mProtected = swapchain->isProtected();
|
||||||
|
|
||||||
VulkanAttachment color = {};
|
VulkanAttachment color = createSwapchainAttachment(swapchain->getCurrentColor());
|
||||||
color.texture = swapchain->getCurrentColor();
|
|
||||||
mInfo->attachments = {color};
|
mInfo->attachments = {color};
|
||||||
|
|
||||||
auto& fbkey = mInfo->fbkey;
|
auto& fbkey = mInfo->fbkey;
|
||||||
auto& rpkey = mInfo->rpkey;
|
auto& rpkey = mInfo->rpkey;
|
||||||
|
|
||||||
rpkey.colorFormat[0] = color.getFormat();
|
rpkey.colorFormat[0] = color.getFormat();
|
||||||
|
rpkey.viewCount = color.layerCount;
|
||||||
fbkey.width = width;
|
fbkey.width = width;
|
||||||
fbkey.height = height;
|
fbkey.height = height;
|
||||||
fbkey.color[0] = color.getImageView();
|
fbkey.color[0] = color.getImageView();
|
||||||
fbkey.resolve[0] = VK_NULL_HANDLE;
|
fbkey.resolve[0] = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (swapchain->getDepth()) {
|
if (swapchain->getDepth()) {
|
||||||
VulkanAttachment depth = {};
|
VulkanAttachment depth = createSwapchainAttachment(swapchain->getDepth());
|
||||||
depth.texture = swapchain->getDepth();
|
|
||||||
mInfo->attachments.push_back(depth);
|
mInfo->attachments.push_back(depth);
|
||||||
mInfo->depthIndex = 1;
|
mInfo->depthIndex = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -218,12 +218,6 @@ struct VulkanProgram : public HwProgram, fvkmemory::Resource {
|
|||||||
mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value);
|
mInfo->pushConstantDescription.write(cmdbuf, layout, stage, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
|
|
||||||
inline utils::FixedCapacityVector<std::string> const& getBindingToName() const {
|
|
||||||
return mInfo->bindingToName;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: handle compute shaders.
|
// TODO: handle compute shaders.
|
||||||
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
|
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
|
||||||
static constexpr uint8_t const MAX_SHADER_MODULES = 2;
|
static constexpr uint8_t const MAX_SHADER_MODULES = 2;
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ VulkanSwapChain::VulkanSwapChain(VulkanPlatform* platform, VulkanContext const&
|
|||||||
mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize),
|
mFlushAndWaitOnResize(platform->getCustomization().flushAndWaitOnWindowResize),
|
||||||
mTransitionSwapChainImageLayoutForPresent(
|
mTransitionSwapChainImageLayoutForPresent(
|
||||||
platform->getCustomization().transitionSwapChainImageLayoutForPresent),
|
platform->getCustomization().transitionSwapChainImageLayoutForPresent),
|
||||||
|
mLayerCount(1),
|
||||||
|
mCurrentSwapIndex(0),
|
||||||
mAcquired(false),
|
mAcquired(false),
|
||||||
mIsFirstRenderPass(true) {
|
mIsFirstRenderPass(true) {
|
||||||
swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent);
|
swapChain = mPlatform->createSwapChain(nativeWindow, flags, extent);
|
||||||
@@ -76,17 +78,18 @@ void VulkanSwapChain::update() {
|
|||||||
for (auto const color: bundle.colors) {
|
for (auto const color: bundle.colors) {
|
||||||
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
|
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
|
||||||
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
|
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
|
||||||
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, colorUsage,
|
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, colorUsage,
|
||||||
mStagePool);
|
mStagePool);
|
||||||
mColors.push_back(colorTexture);
|
mColors.push_back(colorTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
|
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
|
||||||
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
|
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
|
||||||
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, depthUsage,
|
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, bundle.layerCount, depthUsage,
|
||||||
mStagePool);
|
mStagePool);
|
||||||
|
|
||||||
mExtent = bundle.extent;
|
mExtent = bundle.extent;
|
||||||
|
mLayerCount = bundle.layerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::present() {
|
void VulkanSwapChain::present() {
|
||||||
@@ -97,7 +100,7 @@ void VulkanSwapChain::present() {
|
|||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = 1,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = mLayerCount,
|
||||||
};
|
};
|
||||||
mColors[mCurrentSwapIndex]->transitionLayout(&commands, subresources, VulkanLayout::PRESENT);
|
mColors[mCurrentSwapIndex]->transitionLayout(&commands, subresources, VulkanLayout::PRESENT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ private:
|
|||||||
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
|
utils::FixedCapacityVector<fvkmemory::resource_ptr<VulkanTexture>> mColors;
|
||||||
fvkmemory::resource_ptr<VulkanTexture> mDepth;
|
fvkmemory::resource_ptr<VulkanTexture> mDepth;
|
||||||
VkExtent2D mExtent;
|
VkExtent2D mExtent;
|
||||||
|
uint32_t mLayerCount;
|
||||||
uint32_t mCurrentSwapIndex;
|
uint32_t mCurrentSwapIndex;
|
||||||
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
|
std::function<void(Platform::SwapChain* handle)> mExplicitImageReadyWait = nullptr;
|
||||||
bool mAcquired;
|
bool mAcquired;
|
||||||
|
|||||||
@@ -144,6 +144,16 @@ inline VulkanLayout getDefaultLayoutImpl(VkImageUsageFlags vkusage) {
|
|||||||
return getDefaultLayoutImpl(usage);
|
return getDefaultLayoutImpl(usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SamplerType getSamplerTypeFromDepth(uint32_t const depth) {
|
||||||
|
return depth > 1 ? SamplerType::SAMPLER_2D_ARRAY
|
||||||
|
: SamplerType::SAMPLER_2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getLayerCountFromDepth(uint32_t const depth) {
|
||||||
|
return getLayerCount(getSamplerTypeFromDepth(depth), depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
||||||
@@ -165,12 +175,12 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
|||||||
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
|
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||||
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
|
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
|
||||||
uint32_t height, TextureUsage tusage, VulkanStagePool& stagePool)
|
uint32_t height, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
||||||
: HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED,
|
: HwTexture(getSamplerTypeFromDepth(depth), 1, samples, width, height, depth, TextureFormat::UNUSED,
|
||||||
tusage),
|
tusage),
|
||||||
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
||||||
allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D),
|
||||||
1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
|
/*mipLevels=*/1, getLayerCountFromDepth(depth), getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
|
||||||
mState->mTextureImage = image;
|
mState->mTextureImage = image;
|
||||||
mState->mTextureImageMemory = memory;
|
mState->mTextureImageMemory = memory;
|
||||||
mPrimaryViewRange = mState->mFullViewRange;
|
mPrimaryViewRange = mState->mFullViewRange;
|
||||||
@@ -183,7 +193,6 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h,
|
uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h,
|
||||||
uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool)
|
||||||
: HwTexture(target, levels, samples, w, h, depth, tformat, tusage),
|
: HwTexture(target, levels, samples, w, h, depth, tformat, tusage),
|
||||||
|
|
||||||
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
||||||
allocator, commands, stagePool, fvkutils::getVkFormat(tformat),
|
allocator, commands, stagePool, fvkutils::getVkFormat(tformat),
|
||||||
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
fvkutils::getViewType(target), levels, getLayerCount(target, depth),
|
||||||
@@ -199,11 +208,20 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.usage = 0,
|
.usage = 0,
|
||||||
};
|
};
|
||||||
if (target == SamplerType::SAMPLER_CUBEMAP) {
|
if (target == SamplerType::SAMPLER_3D && any(tusage & TextureUsage::ALL_ATTACHMENTS)) {
|
||||||
|
if (context.isImageView2DOn3DImageSupported()) {
|
||||||
|
// Note that VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is only meant to create 2D views of
|
||||||
|
// a 3D image in the case where the image is the render target. So, for example, it's
|
||||||
|
// not meant to allow for 2D views that can be used with a sampler.
|
||||||
|
imageInfo.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
|
||||||
|
} else {
|
||||||
|
FVK_LOGW << "Note: creating 2D views on 3D image is not available on this platform. "
|
||||||
|
<< "i.e. we cannot render to slices of a 3D image" << utils::io::endl;
|
||||||
|
}
|
||||||
|
} else if (target == SamplerType::SAMPLER_CUBEMAP) {
|
||||||
imageInfo.arrayLayers = 6;
|
imageInfo.arrayLayers = 6;
|
||||||
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||||
}
|
} else if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
||||||
if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
|
||||||
imageInfo.arrayLayers = depth;
|
imageInfo.arrayLayers = depth;
|
||||||
imageInfo.extent.depth = 1;
|
imageInfo.extent.depth = 1;
|
||||||
// NOTE: We do not use VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT here because:
|
// NOTE: We do not use VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT here because:
|
||||||
@@ -247,9 +265,9 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
|||||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||||
// Validate that the format is actually sampleable.
|
// Validate that the format is actually sampleable.
|
||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, state->mVkFormat, &props);
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, mState->mVkFormat, &props);
|
||||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << state->mVkFormat << " is not "
|
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
|
||||||
"sampleable with optimal tiling." << utils::io::endl;
|
"sampleable with optimal tiling." << utils::io::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -631,15 +649,16 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
|
|||||||
|
|
||||||
if (hasTransitions) {
|
if (hasTransitions) {
|
||||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||||
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
|
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
|
||||||
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
|
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
|
||||||
<< range.levelCount << ")" << " from=" << oldLayout << " to=" << newLayout
|
<< range.levelCount << ")" << " from=" << oldLayout << " to=" << newLayout
|
||||||
<< " format=" << state->mVkFormat << " depth=" << isVkDepthFormat(state->mVkFormat)
|
<< " format=" << mState->mVkFormat << " depth="
|
||||||
|
<< fvkutils::isVkDepthFormat(mState->mVkFormat)
|
||||||
<< " slice-by-slice=" << transitionSliceBySlice << utils::io::endl;
|
<< " slice-by-slice=" << transitionSliceBySlice << utils::io::endl;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
#if FVK_ENABLED(FVK_DEBUG_LAYOUT_TRANSITION)
|
||||||
FVK_LOGD << "transition texture=" << state->mTextureImage << " (" << range.baseArrayLayer
|
FVK_LOGD << "transition texture=" << mState->mTextureImage << " (" << range.baseArrayLayer
|
||||||
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
|
<< "," << range.baseMipLevel << ")" << " count=(" << range.layerCount << ","
|
||||||
<< range.levelCount << ")" << " to=" << newLayout
|
<< range.levelCount << ")" << " to=" << newLayout
|
||||||
<< " is skipped because of no change in layout" << utils::io::endl;
|
<< " is skipped because of no change in layout" << utils::io::endl;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
|||||||
// The texture will never destroy the given VkImage, but it does manages its subresources.
|
// The texture will never destroy the given VkImage, but it does manages its subresources.
|
||||||
VulkanTexture(VkDevice device, VmaAllocator allocator,
|
VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||||
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth,
|
||||||
TextureUsage tusage, VulkanStagePool& stagePool);
|
TextureUsage tusage, VulkanStagePool& stagePool);
|
||||||
|
|
||||||
// Constructor for creating a texture view for wrt specific mip range
|
// Constructor for creating a texture view for wrt specific mip range
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include "vulkan/VulkanContext.h"
|
||||||
#include "vulkan/platform/VulkanPlatformSwapChainImpl.h"
|
#include "vulkan/platform/VulkanPlatformSwapChainImpl.h"
|
||||||
#include "vulkan/VulkanConstants.h"
|
#include "vulkan/VulkanConstants.h"
|
||||||
#include "vulkan/VulkanDriver.h"
|
#include "vulkan/VulkanDriver.h"
|
||||||
@@ -68,7 +69,7 @@ FixedCapacityVector<const char*> getEnabledLayers() {
|
|||||||
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
|
constexpr size_t kMaxEnabledLayersCount = sizeof(DESIRED_LAYERS) / sizeof(DESIRED_LAYERS[0]);
|
||||||
|
|
||||||
const FixedCapacityVector<VkLayerProperties> availableLayers
|
const FixedCapacityVector<VkLayerProperties> availableLayers
|
||||||
= filament::backend::enumerate(vkEnumerateInstanceLayerProperties);
|
= fvkutils::enumerate(vkEnumerateInstanceLayerProperties);
|
||||||
|
|
||||||
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
|
auto enabledLayers = FixedCapacityVector<const char*>::with_capacity(kMaxEnabledLayersCount);
|
||||||
for (auto const& desired: DESIRED_LAYERS) {
|
for (auto const& desired: DESIRED_LAYERS) {
|
||||||
@@ -84,6 +85,13 @@ FixedCapacityVector<const char*> getEnabledLayers() {
|
|||||||
}
|
}
|
||||||
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
|
||||||
|
|
||||||
|
template<typename StructA, typename StructB>
|
||||||
|
StructA* chainStruct(StructA* structA, StructB* structB) {
|
||||||
|
structB->pNext = const_cast<void*>(structA->pNext);
|
||||||
|
structA->pNext = (void*) structB;
|
||||||
|
return structA;
|
||||||
|
}
|
||||||
|
|
||||||
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||||
// Print some driver or MoltenVK information if it is available.
|
// Print some driver or MoltenVK information if it is available.
|
||||||
if (vkGetPhysicalDeviceProperties2) {
|
if (vkGetPhysicalDeviceProperties2) {
|
||||||
@@ -92,8 +100,8 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
|||||||
};
|
};
|
||||||
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = {
|
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||||
.pNext = &driverProperties,
|
|
||||||
};
|
};
|
||||||
|
chainStruct(&physicalDeviceProperties2, &driverProperties);
|
||||||
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
|
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
|
||||||
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
|
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||||
<< driverProperties.driverInfo << utils::io::endl;
|
<< driverProperties.driverInfo << utils::io::endl;
|
||||||
@@ -143,7 +151,7 @@ void printDepthFormats(VkPhysicalDevice device) {
|
|||||||
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
const VkFormatFeatureFlags required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||||
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
| VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||||
FVK_LOGI << "Sampleable depth formats: ";
|
FVK_LOGI << "Sampleable depth formats: ";
|
||||||
for (VkFormat format : ALL_VK_FORMATS) {
|
for (VkFormat format : fvkutils::ALL_VK_FORMATS) {
|
||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
vkGetPhysicalDeviceFormatProperties(device, format, &props);
|
||||||
if ((props.optimalTilingFeatures & required) == required) {
|
if ((props.optimalTilingFeatures & required) == required) {
|
||||||
@@ -231,7 +239,9 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
|||||||
|
|
||||||
VkInstance createInstance(ExtensionSet const& requiredExts) {
|
VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
VkInstanceCreateInfo instanceCreateInfo = {};
|
VkInstanceCreateInfo instanceCreateInfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
};
|
||||||
bool validationFeaturesSupported = false;
|
bool validationFeaturesSupported = false;
|
||||||
|
|
||||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||||
@@ -239,7 +249,7 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
if (!enabledLayers.empty()) {
|
if (!enabledLayers.empty()) {
|
||||||
// If layers are supported, Check if VK_EXT_validation_features is supported.
|
// If layers are supported, Check if VK_EXT_validation_features is supported.
|
||||||
FixedCapacityVector<VkExtensionProperties> const availableValidationExts
|
FixedCapacityVector<VkExtensionProperties> const availableValidationExts
|
||||||
= filament::backend::enumerate(vkEnumerateInstanceExtensionProperties,
|
= fvkutils::enumerate(vkEnumerateInstanceExtensionProperties,
|
||||||
"VK_LAYER_KHRONOS_validation");
|
"VK_LAYER_KHRONOS_validation");
|
||||||
for (auto const& extProps: availableValidationExts) {
|
for (auto const& extProps: availableValidationExts) {
|
||||||
if (!strcmp(extProps.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) {
|
if (!strcmp(extProps.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME)) {
|
||||||
@@ -282,7 +292,6 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
appInfo.pEngineName = "Filament";
|
appInfo.pEngineName = "Filament";
|
||||||
appInfo.apiVersion
|
appInfo.apiVersion
|
||||||
= VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0);
|
= VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0);
|
||||||
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
||||||
instanceCreateInfo.pApplicationInfo = &appInfo;
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
||||||
instanceCreateInfo.enabledExtensionCount = enabledExtensionCount;
|
instanceCreateInfo.enabledExtensionCount = enabledExtensionCount;
|
||||||
instanceCreateInfo.ppEnabledExtensionNames = ppEnabledExtensions;
|
instanceCreateInfo.ppEnabledExtensionNames = ppEnabledExtensions;
|
||||||
@@ -290,16 +299,17 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkValidationFeaturesEXT features = {};
|
VkValidationFeaturesEXT features = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
|
||||||
|
};
|
||||||
VkValidationFeatureEnableEXT enables[] = {
|
VkValidationFeatureEnableEXT enables[] = {
|
||||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
|
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
|
||||||
};
|
};
|
||||||
if (validationFeaturesSupported) {
|
if (validationFeaturesSupported) {
|
||||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
|
||||||
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
|
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
|
||||||
features.pEnabledValidationFeatures = enables;
|
features.pEnabledValidationFeatures = enables;
|
||||||
instanceCreateInfo.pNext = &features;
|
chainStruct(&instanceCreateInfo, &features);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
|
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
|
||||||
@@ -310,11 +320,13 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
|||||||
|
|
||||||
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||||
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
|
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
|
||||||
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions) {
|
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
|
||||||
|
bool requestImageView2DOn3DImage) {
|
||||||
VkDevice device;
|
VkDevice device;
|
||||||
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
|
float queuePriority[] = {1.0f};
|
||||||
const float queuePriority[] = {1.0f};
|
VkDeviceCreateInfo deviceCreateInfo = {
|
||||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||||
|
};
|
||||||
FixedCapacityVector<const char*> requestExtensions;
|
FixedCapacityVector<const char*> requestExtensions;
|
||||||
requestExtensions.reserve(deviceExtensions.size() + 1);
|
requestExtensions.reserve(deviceExtensions.size() + 1);
|
||||||
|
|
||||||
@@ -323,6 +335,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
|||||||
for (auto const& ext: deviceExtensions) {
|
for (auto const& ext: deviceExtensions) {
|
||||||
requestExtensions.push_back(ext.data());
|
requestExtensions.push_back(ext.data());
|
||||||
}
|
}
|
||||||
|
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
|
||||||
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
|
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
|
||||||
deviceQueueCreateInfo[0].queueCount = 1;
|
deviceQueueCreateInfo[0].queueCount = 1;
|
||||||
@@ -334,7 +347,6 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
|||||||
deviceQueueCreateInfo[1].queueCount = 1;
|
deviceQueueCreateInfo[1].queueCount = 1;
|
||||||
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority[0];
|
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority[0];
|
||||||
|
|
||||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
||||||
bool const hasProtectedQueue = protectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX;
|
bool const hasProtectedQueue = protectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX;
|
||||||
deviceCreateInfo.queueCreateInfoCount = hasProtectedQueue ? 2 : 1;
|
deviceCreateInfo.queueCreateInfoCount = hasProtectedQueue ? 2 : 1;
|
||||||
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
|
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
|
||||||
@@ -353,42 +365,35 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
|||||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
||||||
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
||||||
|
|
||||||
void* pNext = nullptr;
|
|
||||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
|
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||||
.pNext = nullptr,
|
.imageViewFormatSwizzle = VK_TRUE,
|
||||||
.imageViewFormatSwizzle = VK_TRUE,
|
.imageView2DOn3DImage = requestImageView2DOn3DImage ? VK_TRUE : VK_FALSE,
|
||||||
.mutableComparisonSamplers = VK_TRUE,
|
.mutableComparisonSamplers = VK_TRUE,
|
||||||
};
|
};
|
||||||
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||||
portability.pNext = pNext;
|
chainStruct(&deviceCreateInfo, &portability);
|
||||||
pNext = &portability;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||||
.pNext = nullptr,
|
.multiview = VK_TRUE,
|
||||||
.multiview = VK_TRUE,
|
.multiviewGeometryShader = VK_FALSE,
|
||||||
.multiviewGeometryShader = VK_FALSE,
|
.multiviewTessellationShader = VK_FALSE,
|
||||||
.multiviewTessellationShader = VK_FALSE
|
|
||||||
};
|
};
|
||||||
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
|
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
|
||||||
multiview.pNext = pNext;
|
chainStruct(&deviceCreateInfo, &multiview);
|
||||||
pNext = &multiview;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
|
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
|
||||||
|
.protectedMemory = VK_TRUE,
|
||||||
};
|
};
|
||||||
if (hasProtectedQueue) {
|
if (hasProtectedQueue) {
|
||||||
// Enable protected memory, if requested.
|
// Enable protected memory, if requested.
|
||||||
protectedMemory.protectedMemory = VK_TRUE;
|
chainStruct(&deviceCreateInfo, &protectedMemory);
|
||||||
protectedMemory.pNext = pNext;
|
|
||||||
pNext = &protectedMemory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceCreateInfo.pNext = pNext;
|
|
||||||
|
|
||||||
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
|
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
|
||||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||||
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
|
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
|
||||||
@@ -721,14 +726,11 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
VkPhysicalDeviceProtectedMemoryFeatures queryProtectedMemoryFeatures = {
|
VkPhysicalDeviceProtectedMemoryFeatures queryProtectedMemoryFeatures = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
|
||||||
};
|
};
|
||||||
// Chain to the pNext linked list
|
|
||||||
queryProtectedMemoryFeatures.pNext = context.mPhysicalDeviceFeatures.pNext;
|
|
||||||
context.mPhysicalDeviceFeatures.pNext = &queryProtectedMemoryFeatures;
|
|
||||||
VkPhysicalDeviceProtectedMemoryProperties protectedMemoryProperties = {
|
VkPhysicalDeviceProtectedMemoryProperties protectedMemoryProperties = {
|
||||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
|
||||||
};
|
};
|
||||||
protectedMemoryProperties.pNext = context.mPhysicalDeviceProperties.pNext;
|
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
|
||||||
context.mPhysicalDeviceProperties.pNext = &protectedMemoryProperties;
|
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
|
||||||
|
|
||||||
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
||||||
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
|
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
|
||||||
@@ -785,11 +787,23 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mImpl->mDevice
|
bool requestPortabilitySubsetImageView2DOn3DImage = false;
|
||||||
= mImpl->mDevice == VK_NULL_HANDLE ? createLogicalDevice(mImpl->mPhysicalDevice,
|
if (setContains(deviceExts, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||||
context.mPhysicalDeviceFeatures, mImpl->mGraphicsQueueFamilyIndex,
|
// We are on a non-conformant vulkan implementation so we need to ascertain if the features
|
||||||
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts)
|
// we need are available.
|
||||||
: mImpl->mDevice;
|
chainStruct(&context.mPhysicalDeviceFeatures, &context.mPortabilitySubsetFeatures);
|
||||||
|
vkGetPhysicalDeviceFeatures2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceFeatures);
|
||||||
|
requestPortabilitySubsetImageView2DOn3DImage =
|
||||||
|
context.mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mImpl->mDevice =
|
||||||
|
mImpl->mDevice == VK_NULL_HANDLE
|
||||||
|
? createLogicalDevice(mImpl->mPhysicalDevice, context.mPhysicalDeviceFeatures,
|
||||||
|
mImpl->mGraphicsQueueFamilyIndex,
|
||||||
|
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts,
|
||||||
|
requestPortabilitySubsetImageView2DOn3DImage)
|
||||||
|
: mImpl->mDevice;
|
||||||
assert_invariant(mImpl->mDevice != VK_NULL_HANDLE);
|
assert_invariant(mImpl->mDevice != VK_NULL_HANDLE);
|
||||||
|
|
||||||
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,
|
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,
|
||||||
@@ -806,9 +820,16 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the extension support in the context
|
// Store the extension support in the context
|
||||||
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
if (!mImpl->mSharedContext) {
|
||||||
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
context.mDebugUtilsSupported = setContains(instExts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||||
|
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);
|
||||||
|
} else {
|
||||||
|
VulkanSharedContext const* scontext = (VulkanSharedContext const*) sharedContext;
|
||||||
|
context.mDebugUtilsSupported = scontext->debugUtilsSupported;
|
||||||
|
context.mDebugMarkersSupported = scontext->debugMarkersSupported;
|
||||||
|
context.mMultiviewEnabled = scontext->multiviewSupported;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the availability of lazily allocated memory
|
// Check the availability of lazily allocated memory
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange&
|
|||||||
case filament::backend::VulkanLayout::VALUE: { \
|
case filament::backend::VulkanLayout::VALUE: { \
|
||||||
out << #VALUE; \
|
out << #VALUE; \
|
||||||
out << " [" \
|
out << " [" \
|
||||||
<< filament::backend::imgutil::getVkLayout( \
|
<< filament::backend::fvkutils::getVkLayout( \
|
||||||
filament::backend::VulkanLayout::VALUE) \
|
filament::backend::VulkanLayout::VALUE) \
|
||||||
<< "]"; \
|
<< "]"; \
|
||||||
break; \
|
break; \
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#ifndef TNT_FILAMENT_ENGINE_H
|
#ifndef TNT_FILAMENT_ENGINE_H
|
||||||
#define TNT_FILAMENT_ENGINE_H
|
#define TNT_FILAMENT_ENGINE_H
|
||||||
|
|
||||||
|
|
||||||
#include <filament/FilamentAPI.h>
|
#include <filament/FilamentAPI.h>
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
class Entity;
|
class Entity;
|
||||||
class EntityManager;
|
class EntityManager;
|
||||||
@@ -40,6 +42,10 @@ class JobSystem;
|
|||||||
|
|
||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
|
namespace backend {
|
||||||
|
class Driver;
|
||||||
|
} // backend
|
||||||
|
|
||||||
class BufferObject;
|
class BufferObject;
|
||||||
class Camera;
|
class Camera;
|
||||||
class ColorGrading;
|
class ColorGrading;
|
||||||
@@ -183,6 +189,7 @@ public:
|
|||||||
using DriverConfig = backend::Platform::DriverConfig;
|
using DriverConfig = backend::Platform::DriverConfig;
|
||||||
using FeatureLevel = backend::FeatureLevel;
|
using FeatureLevel = backend::FeatureLevel;
|
||||||
using StereoscopicType = backend::StereoscopicType;
|
using StereoscopicType = backend::StereoscopicType;
|
||||||
|
using Driver = backend::Driver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config is used to define the memory footprint used by the engine, such as the
|
* Config is used to define the memory footprint used by the engine, such as the
|
||||||
@@ -582,6 +589,11 @@ public:
|
|||||||
static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token);
|
static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the Driver instance used by this Engine.
|
||||||
|
* @see OpenGLPlatform
|
||||||
|
*/
|
||||||
|
backend::Driver const* UTILS_NONNULL getDriver() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the Engine instance and all associated resources.
|
* Destroy the Engine instance and all associated resources.
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public:
|
|||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated string literal */
|
/** inline helper to provide the name as a null-terminated string literal */
|
||||||
template<typename T, typename = is_supported_parameter_t<T>>
|
template<typename T, typename = is_supported_parameter_t<T>>
|
||||||
void setParameter(StringLiteral name, T const& value) {
|
void setParameter(StringLiteral const name, T const& value) {
|
||||||
setParameter<T>(name.data, name.size, value);
|
setParameter<T>(name.data, name.size, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,14 +148,14 @@ public:
|
|||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated string literal */
|
/** inline helper to provide the name as a null-terminated string literal */
|
||||||
template<typename T, typename = is_supported_parameter_t<T>>
|
template<typename T, typename = is_supported_parameter_t<T>>
|
||||||
void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t count) {
|
void setParameter(StringLiteral const name, const T* UTILS_NONNULL values, size_t const count) {
|
||||||
setParameter<T>(name.data, name.size, values, count);
|
setParameter<T>(name.data, name.size, values, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated C string */
|
/** inline helper to provide the name as a null-terminated C string */
|
||||||
template<typename T, typename = is_supported_parameter_t<T>>
|
template<typename T, typename = is_supported_parameter_t<T>>
|
||||||
void setParameter(const char* UTILS_NONNULL name,
|
void setParameter(const char* UTILS_NONNULL name,
|
||||||
const T* UTILS_NONNULL values, size_t count) {
|
const T* UTILS_NONNULL values, size_t const count) {
|
||||||
setParameter<T>(name, strlen(name), values, count);
|
setParameter<T>(name, strlen(name), values, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ public:
|
|||||||
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler);
|
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler);
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated string literal */
|
/** inline helper to provide the name as a null-terminated string literal */
|
||||||
void setParameter(StringLiteral name,
|
void setParameter(StringLiteral const name,
|
||||||
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) {
|
Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) {
|
||||||
setParameter(name.data, name.size, texture, sampler);
|
setParameter(name.data, name.size, texture, sampler);
|
||||||
}
|
}
|
||||||
@@ -202,12 +202,12 @@ public:
|
|||||||
RgbType type, math::float3 color);
|
RgbType type, math::float3 color);
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated string literal */
|
/** inline helper to provide the name as a null-terminated string literal */
|
||||||
void setParameter(StringLiteral name, RgbType type, math::float3 color) {
|
void setParameter(StringLiteral const name, RgbType const type, math::float3 const color) {
|
||||||
setParameter(name.data, name.size, type, color);
|
setParameter(name.data, name.size, type, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated C string */
|
/** inline helper to provide the name as a null-terminated C string */
|
||||||
void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) {
|
void setParameter(const char* UTILS_NONNULL name, RgbType const type, math::float3 const color) {
|
||||||
setParameter(name, strlen(name), type, color);
|
setParameter(name, strlen(name), type, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,12 +226,12 @@ public:
|
|||||||
RgbaType type, math::float4 color);
|
RgbaType type, math::float4 color);
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated string literal */
|
/** inline helper to provide the name as a null-terminated string literal */
|
||||||
void setParameter(StringLiteral name, RgbaType type, math::float4 color) {
|
void setParameter(StringLiteral const name, RgbaType const type, math::float4 const color) {
|
||||||
setParameter(name.data, name.size, type, color);
|
setParameter(name.data, name.size, type, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated C string */
|
/** inline helper to provide the name as a null-terminated C string */
|
||||||
void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) {
|
void setParameter(const char* UTILS_NONNULL name, RgbaType const type, math::float4 const color) {
|
||||||
setParameter(name, strlen(name), type, color);
|
setParameter(name, strlen(name), type, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ public:
|
|||||||
|
|
||||||
/** inline helper to provide the name as a null-terminated C string */
|
/** inline helper to provide the name as a null-terminated C string */
|
||||||
template<typename T, typename = is_supported_parameter_t<T>>
|
template<typename T, typename = is_supported_parameter_t<T>>
|
||||||
T getParameter(StringLiteral name) const {
|
T getParameter(StringLiteral const name) const {
|
||||||
return getParameter<T>(name.data, name.size);
|
return getParameter<T>(name.data, name.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,11 +376,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setCullingMode(CullingMode culling) noexcept;
|
void setCullingMode(CullingMode culling) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the default triangle culling state that was set on the material separately for the
|
||||||
|
* color and shadow passes
|
||||||
|
*/
|
||||||
|
void setCullingMode(CullingMode colorPassCullingMode, CullingMode shadowPassCullingMode) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the face culling mode.
|
* Returns the face culling mode.
|
||||||
*/
|
*/
|
||||||
CullingMode getCullingMode() const noexcept;
|
CullingMode getCullingMode() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the face culling mode for the shadow passes.
|
||||||
|
*/
|
||||||
|
CullingMode getShadowCullingMode() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the default color-buffer write state that was set on the material.
|
* Overrides the default color-buffer write state that was set on the material.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -141,6 +141,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void removeEntities(const utils::Entity* UTILS_NONNULL entities, size_t count);
|
void removeEntities(const utils::Entity* UTILS_NONNULL entities, size_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all entities to the Scene.
|
||||||
|
*/
|
||||||
|
void removeAllEntities() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total number of Entities in the Scene, whether alive or not.
|
* Returns the total number of Entities in the Scene, whether alive or not.
|
||||||
* @return Total number of Entities in the Scene.
|
* @return Total number of Entities in the Scene.
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ Engine* Engine::getEngine(void* token) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Driver const* Engine::getDriver() const noexcept {
|
||||||
|
return std::addressof(downcast(this)->getDriver());
|
||||||
|
}
|
||||||
|
|
||||||
void Engine::destroy(Engine** pEngine) {
|
void Engine::destroy(Engine** pEngine) {
|
||||||
if (pEngine) {
|
if (pEngine) {
|
||||||
Engine* engine = *pEngine;
|
Engine* engine = *pEngine;
|
||||||
|
|||||||
@@ -17,6 +17,26 @@
|
|||||||
#include <filament/MaterialInstance.h>
|
#include <filament/MaterialInstance.h>
|
||||||
|
|
||||||
#include "details/Material.h"
|
#include "details/Material.h"
|
||||||
|
#include "details/MaterialInstance.h"
|
||||||
|
|
||||||
|
#include <filament/Color.h>
|
||||||
|
#include <filament/MaterialEnums.h>
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/debug.h>
|
||||||
|
|
||||||
|
#include <math/vec2.h>
|
||||||
|
#include <math/vec3.h>
|
||||||
|
#include <math/vec4.h>
|
||||||
|
#include <math/mat3.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
@@ -85,7 +105,7 @@ void MaterialInstance::setParameter(const char* name, size_t nameLength, T const
|
|||||||
template<>
|
template<>
|
||||||
UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, size_t const nameLength, bool const& v) {
|
UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, size_t const nameLength, bool const& v) {
|
||||||
// this kills tail-call optimization
|
// this kills tail-call optimization
|
||||||
setParameter(name, nameLength, (uint32_t)v);
|
setParameter(name, nameLength, uint32_t(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -125,8 +145,8 @@ template UTILS_PUBLIC void MaterialInstance::setParameter<mat4f> (const char*
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <typename T, typename>
|
template <typename T, typename>
|
||||||
void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* value, size_t count) {
|
void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* values, size_t count) {
|
||||||
downcast(this)->setParameterImpl({ name, nameLength }, value, count);
|
downcast(this)->setParameterImpl({ name, nameLength }, values, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -272,6 +292,11 @@ void MaterialInstance::setCullingMode(CullingMode const culling) noexcept {
|
|||||||
downcast(this)->setCullingMode(culling);
|
downcast(this)->setCullingMode(culling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MaterialInstance::setCullingMode(CullingMode const colorPassCullingMode,
|
||||||
|
CullingMode const shadowPassCullingMode) noexcept {
|
||||||
|
downcast(this)->setCullingMode(colorPassCullingMode, shadowPassCullingMode);
|
||||||
|
}
|
||||||
|
|
||||||
void MaterialInstance::setColorWrite(bool const enable) noexcept {
|
void MaterialInstance::setColorWrite(bool const enable) noexcept {
|
||||||
downcast(this)->setColorWrite(enable);
|
downcast(this)->setColorWrite(enable);
|
||||||
}
|
}
|
||||||
@@ -353,6 +378,10 @@ CullingMode MaterialInstance::getCullingMode() const noexcept {
|
|||||||
return downcast(this)->getCullingMode();
|
return downcast(this)->getCullingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CullingMode MaterialInstance::getShadowCullingMode() const noexcept {
|
||||||
|
return downcast(this)->getShadowCullingMode();
|
||||||
|
}
|
||||||
|
|
||||||
bool MaterialInstance::isColorWriteEnabled() const noexcept {
|
bool MaterialInstance::isColorWriteEnabled() const noexcept {
|
||||||
return downcast(this)->isColorWriteEnabled();
|
return downcast(this)->isColorWriteEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -807,7 +807,13 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
|
|||||||
cmd.key &= ~Z_BUCKET_MASK;
|
cmd.key &= ~Z_BUCKET_MASK;
|
||||||
cmd.key |= makeField(distanceBits >> 22u, Z_BUCKET_MASK, Z_BUCKET_SHIFT);
|
cmd.key |= makeField(distanceBits >> 22u, Z_BUCKET_MASK, Z_BUCKET_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*curr = cmd;
|
||||||
|
// cancel command if both front and back faces are culled
|
||||||
|
curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK);
|
||||||
|
|
||||||
} else if constexpr (isDepthPass) {
|
} else if constexpr (isDepthPass) {
|
||||||
|
const CullingMode cullingMode = hasShadowing ? mi->getShadowCullingMode() : mi->getCullingMode();
|
||||||
const RasterState rs = ma->getRasterState();
|
const RasterState rs = ma->getRasterState();
|
||||||
const TransparencyMode mode = mi->getTransparencyMode();
|
const TransparencyMode mode = mi->getTransparencyMode();
|
||||||
const BlendingMode blendingMode = ma->getBlendingMode();
|
const BlendingMode blendingMode = ma->getBlendingMode();
|
||||||
@@ -816,7 +822,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
|
|||||||
const bool isPickingVariant = Variant::isPickingVariant(variant);
|
const bool isPickingVariant = Variant::isPickingVariant(variant);
|
||||||
|
|
||||||
cmd.key |= mi->getSortingKey(); // already all set-up for direct or'ing
|
cmd.key |= mi->getSortingKey(); // already all set-up for direct or'ing
|
||||||
cmd.info.rasterState.culling = mi->getCullingMode();
|
cmd.info.rasterState.culling = cullingMode;
|
||||||
|
|
||||||
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
|
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
|
||||||
cmd.info.rasterState.depthWrite = (1 // only keep bit 0
|
cmd.info.rasterState.depthWrite = (1 // only keep bit 0
|
||||||
@@ -825,11 +831,12 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag
|
|||||||
& !(filterTranslucentObjects & translucent)
|
& !(filterTranslucentObjects & translucent)
|
||||||
& !(depthFilterAlphaMaskedObjects & rs.alphaToCoverage))
|
& !(depthFilterAlphaMaskedObjects & rs.alphaToCoverage))
|
||||||
| writeDepthForShadowCasters;
|
| writeDepthForShadowCasters;
|
||||||
|
|
||||||
|
*curr = cmd;
|
||||||
|
// cancel command if both front and back faces are culled
|
||||||
|
curr->key |= select(cullingMode == CullingMode::FRONT_AND_BACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
*curr = cmd;
|
|
||||||
// cancel command if both front and back faces are culled
|
|
||||||
curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK);
|
|
||||||
++curr;
|
++curr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ void Scene::removeEntities(const Entity* entities, size_t const count) {
|
|||||||
downcast(this)->removeEntities(entities, count);
|
downcast(this)->removeEntities(entities, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene::removeAllEntities() noexcept {
|
||||||
|
downcast(this)->removeAllEntities();
|
||||||
|
}
|
||||||
|
|
||||||
size_t Scene::getEntityCount() const noexcept {
|
size_t Scene::getEntityCount() const noexcept {
|
||||||
return downcast(this)->getEntityCount();
|
return downcast(this)->getEntityCount();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
#include "details/Fence.h"
|
#include "details/Fence.h"
|
||||||
#include "details/IndexBuffer.h"
|
#include "details/IndexBuffer.h"
|
||||||
#include "details/IndirectLight.h"
|
#include "details/IndirectLight.h"
|
||||||
|
#include "details/InstanceBuffer.h"
|
||||||
#include "details/Material.h"
|
#include "details/Material.h"
|
||||||
|
#include "details/MorphTargetBuffer.h"
|
||||||
#include "details/Renderer.h"
|
#include "details/Renderer.h"
|
||||||
#include "details/Scene.h"
|
#include "details/Scene.h"
|
||||||
#include "details/SkinningBuffer.h"
|
#include "details/SkinningBuffer.h"
|
||||||
@@ -36,28 +38,39 @@
|
|||||||
#include "details/VertexBuffer.h"
|
#include "details/VertexBuffer.h"
|
||||||
#include "details/View.h"
|
#include "details/View.h"
|
||||||
|
|
||||||
|
#include <filament/ColorGrading.h>
|
||||||
#include <filament/Engine.h>
|
#include <filament/Engine.h>
|
||||||
#include <filament/MaterialEnums.h>
|
#include <filament/MaterialEnums.h>
|
||||||
|
|
||||||
#include <private/filament/DescriptorSets.h>
|
#include <private/filament/DescriptorSets.h>
|
||||||
#include <private/filament/EngineEnums.h>
|
#include <private/filament/EngineEnums.h>
|
||||||
|
#include <private/filament/Variant.h>
|
||||||
|
|
||||||
#include <private/backend/PlatformFactory.h>
|
#include <private/backend/PlatformFactory.h>
|
||||||
|
|
||||||
#include <backend/DriverEnums.h>
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
|
#include <utils/Allocator.h>
|
||||||
|
#include <utils/CallStack.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/Invocable.h>
|
#include <utils/Invocable.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
#include <utils/ostream.h>
|
||||||
#include <utils/Panic.h>
|
#include <utils/Panic.h>
|
||||||
#include <utils/PrivateImplementation-impl.h>
|
#include <utils/PrivateImplementation-impl.h>
|
||||||
#include <utils/Systrace.h>
|
#include <utils/Systrace.h>
|
||||||
#include <utils/ThreadUtils.h>
|
#include <utils/ThreadUtils.h>
|
||||||
|
|
||||||
|
#include <math/vec3.h>
|
||||||
|
#include <math/vec4.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <new>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -66,6 +79,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "generated/resources/materials.h"
|
#include "generated/resources/materials.h"
|
||||||
@@ -101,7 +115,7 @@ Engine* FEngine::create(Builder const& builder) {
|
|||||||
|
|
||||||
// Normally we launch a thread and create the context and Driver from there (see FEngine::loop).
|
// Normally we launch a thread and create the context and Driver from there (see FEngine::loop).
|
||||||
// In the single-threaded case, we do so in the here and now.
|
// In the single-threaded case, we do so in the here and now.
|
||||||
if (!UTILS_HAS_THREADING) {
|
if constexpr (!UTILS_HAS_THREADING) {
|
||||||
Platform* platform = builder->mPlatform;
|
Platform* platform = builder->mPlatform;
|
||||||
void* const sharedContext = builder->mSharedContext;
|
void* const sharedContext = builder->mSharedContext;
|
||||||
|
|
||||||
@@ -144,7 +158,7 @@ Engine* FEngine::create(Builder const& builder) {
|
|||||||
// now we can initialize the largest part of the engine
|
// now we can initialize the largest part of the engine
|
||||||
instance->init();
|
instance->init();
|
||||||
|
|
||||||
if (!UTILS_HAS_THREADING) {
|
if constexpr (!UTILS_HAS_THREADING) {
|
||||||
instance->execute();
|
instance->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +177,7 @@ void FEngine::create(Builder const& builder, Invocable<void(void*)>&& callback)
|
|||||||
instance->mDriverThread = std::thread(&FEngine::loop, instance);
|
instance->mDriverThread = std::thread(&FEngine::loop, instance);
|
||||||
|
|
||||||
// launch a thread to call the callback -- so it can't do any damage.
|
// launch a thread to call the callback -- so it can't do any damage.
|
||||||
std::thread callbackThread = std::thread([instance, callback = std::move(callback)]() {
|
std::thread callbackThread = std::thread([instance, callback = std::move(callback)] {
|
||||||
instance->mDriverBarrier.await();
|
instance->mDriverBarrier.await();
|
||||||
callback(instance);
|
callback(instance);
|
||||||
});
|
});
|
||||||
@@ -196,7 +210,7 @@ FEngine* FEngine::getEngine(void* token) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// these must be static because only a pointer is copied to the render stream
|
// These must be static because only a pointer is copied to the render stream
|
||||||
// Note that these coordinates are specified in OpenGL clip space. Other backends can transform
|
// Note that these coordinates are specified in OpenGL clip space. Other backends can transform
|
||||||
// these in the vertex shader as needed.
|
// these in the vertex shader as needed.
|
||||||
static constexpr float4 sFullScreenTriangleVertices[3] = {
|
static constexpr float4 sFullScreenTriangleVertices[3] = {
|
||||||
@@ -206,7 +220,7 @@ static constexpr float4 sFullScreenTriangleVertices[3] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// these must be static because only a pointer is copied to the render stream
|
// these must be static because only a pointer is copied to the render stream
|
||||||
static const uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
|
static constexpr uint16_t sFullScreenTriangleIndices[3] = { 0, 1, 2 };
|
||||||
|
|
||||||
FEngine::FEngine(Builder const& builder) :
|
FEngine::FEngine(Builder const& builder) :
|
||||||
mBackend(builder->mBackend),
|
mBackend(builder->mBackend),
|
||||||
@@ -216,7 +230,6 @@ FEngine::FEngine(Builder const& builder) :
|
|||||||
mPostProcessManager(*this),
|
mPostProcessManager(*this),
|
||||||
mEntityManager(EntityManager::get()),
|
mEntityManager(EntityManager::get()),
|
||||||
mRenderableManager(*this),
|
mRenderableManager(*this),
|
||||||
mTransformManager(),
|
|
||||||
mLightManager(*this),
|
mLightManager(*this),
|
||||||
mCameraManager(*this),
|
mCameraManager(*this),
|
||||||
mCommandBufferQueue(
|
mCommandBufferQueue(
|
||||||
@@ -274,7 +287,7 @@ uint32_t FEngine::getJobSystemThreadPoolSize(Config const& config) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1 thread for the user, 1 thread for the backend
|
// 1 thread for the user, 1 thread for the backend
|
||||||
int threadCount = (int)std::thread::hardware_concurrency() - 2;
|
int threadCount = int(std::thread::hardware_concurrency()) - 2;
|
||||||
// make sure we have at least 1 thread though
|
// make sure we have at least 1 thread though
|
||||||
threadCount = std::max(1, threadCount);
|
threadCount = std::max(1, threadCount);
|
||||||
return threadCount;
|
return threadCount;
|
||||||
@@ -347,8 +360,8 @@ void FEngine::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initialize the dummy textures so that their contents are not undefined
|
// initialize the dummy textures so that their contents are not undefined
|
||||||
static const uint32_t zeroes[6] = {0};
|
static constexpr uint32_t zeroes[6] = {};
|
||||||
static const uint32_t ones = 0xffffffff;
|
static constexpr uint32_t ones = 0xffffffff;
|
||||||
|
|
||||||
mDefaultIblTexture = downcast(Texture::Builder()
|
mDefaultIblTexture = downcast(Texture::Builder()
|
||||||
.width(1).height(1).levels(1)
|
.width(1).height(1).levels(1)
|
||||||
@@ -360,7 +373,7 @@ void FEngine::init() {
|
|||||||
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
|
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||||
|
|
||||||
// 3 bands = 9 float3
|
// 3 bands = 9 float3
|
||||||
const float sh[9 * 3] = { 0.0f };
|
constexpr float sh[9 * 3] = { 0.0f };
|
||||||
mDefaultIbl = downcast(IndirectLight::Builder()
|
mDefaultIbl = downcast(IndirectLight::Builder()
|
||||||
.irradiance(3, reinterpret_cast<const float3*>(sh))
|
.irradiance(3, reinterpret_cast<const float3*>(sh))
|
||||||
.build(*this));
|
.build(*this));
|
||||||
@@ -427,10 +440,10 @@ void FEngine::init() {
|
|||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
|
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
|
||||||
|
|
||||||
float3 dummyPositions[1] = {};
|
constexpr float3 dummyPositions[1] = {};
|
||||||
short4 dummyTangents[1] = {};
|
constexpr short4 dummyTangents[1] = {};
|
||||||
mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0);
|
mDummyMorphTargetBuffer->setPositionsAt(*this, 0, dummyPositions, 1, 0);
|
||||||
mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0);
|
mDummyMorphTargetBuffer->setTangentsAt(*this, 0, dummyTangents, 1, 0);
|
||||||
|
|
||||||
@@ -453,7 +466,7 @@ void FEngine::init() {
|
|||||||
mPostProcessManager.init();
|
mPostProcessManager.init();
|
||||||
|
|
||||||
mDebugRegistry.registerProperty("d.shadowmap.debug_directional_shadowmap",
|
mDebugRegistry.registerProperty("d.shadowmap.debug_directional_shadowmap",
|
||||||
&debug.shadowmap.debug_directional_shadowmap, [this]() {
|
&debug.shadowmap.debug_directional_shadowmap, [this] {
|
||||||
mMaterials.forEach([this](FMaterial* material) {
|
mMaterials.forEach([this](FMaterial* material) {
|
||||||
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
|
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||||
|
|
||||||
@@ -469,7 +482,7 @@ void FEngine::init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mDebugRegistry.registerProperty("d.lighting.debug_froxel_visualization",
|
mDebugRegistry.registerProperty("d.lighting.debug_froxel_visualization",
|
||||||
&debug.lighting.debug_froxel_visualization, [this]() {
|
&debug.lighting.debug_froxel_visualization, [this] {
|
||||||
mMaterials.forEach([this](FMaterial* material) {
|
mMaterials.forEach([this](FMaterial* material) {
|
||||||
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
|
if (material->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||||
|
|
||||||
@@ -607,7 +620,7 @@ void FEngine::shutdown() {
|
|||||||
|
|
||||||
// now wait for all pending commands to be executed and the thread to exit
|
// now wait for all pending commands to be executed and the thread to exit
|
||||||
mCommandBufferQueue.requestExit();
|
mCommandBufferQueue.requestExit();
|
||||||
if (!UTILS_HAS_THREADING) {
|
if constexpr (!UTILS_HAS_THREADING) {
|
||||||
execute();
|
execute();
|
||||||
getDriverApi().terminate();
|
getDriverApi().terminate();
|
||||||
} else {
|
} else {
|
||||||
@@ -638,13 +651,13 @@ void FEngine::prepare() {
|
|||||||
DriverApi& driver = getDriverApi();
|
DriverApi& driver = getDriverApi();
|
||||||
|
|
||||||
for (auto& materialInstanceList: mMaterialInstances) {
|
for (auto& materialInstanceList: mMaterialInstances) {
|
||||||
materialInstanceList.second.forEach([&driver](FMaterialInstance* item) {
|
materialInstanceList.second.forEach([&driver](FMaterialInstance const* item) {
|
||||||
item->commit(driver);
|
item->commit(driver);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
mMaterials.forEach([](FMaterial* material) {
|
mMaterials.forEach([](FMaterial* material) {
|
||||||
#if FILAMENT_ENABLE_MATDBG
|
#if FILAMENT_ENABLE_MATDBG // NOLINT(*-include-cleaner)
|
||||||
material->checkProgramEdits();
|
material->checkProgramEdits();
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
@@ -668,7 +681,7 @@ void FEngine::flushAndWait() {
|
|||||||
flushAndWait(FENCE_WAIT_FOR_EVER);
|
flushAndWait(FENCE_WAIT_FOR_EVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FEngine::flushAndWait(uint64_t timeout) {
|
bool FEngine::flushAndWait(uint64_t const timeout) {
|
||||||
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
|
FILAMENT_CHECK_PRECONDITION(!mCommandBufferQueue.isPaused())
|
||||||
<< "Cannot call Engine::flushAndWait() when rendering thread is paused!";
|
<< "Cannot call Engine::flushAndWait() when rendering thread is paused!";
|
||||||
|
|
||||||
@@ -749,7 +762,7 @@ int FEngine::loop() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FILAMENT_ENABLE_FGVIEWER
|
#if FILAMENT_ENABLE_FGVIEWER // NOLINT(*-include-cleaner)
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
const char* fgviewerPortString = "8085";
|
const char* fgviewerPortString = "8085";
|
||||||
#else
|
#else
|
||||||
@@ -779,9 +792,9 @@ int FEngine::loop() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FEngine::flushCommandBuffer(CommandBufferQueue& commandQueue) {
|
void FEngine::flushCommandBuffer(CommandBufferQueue& commandBufferQueue) const {
|
||||||
getDriver().purge();
|
getDriver().purge();
|
||||||
commandQueue.flush();
|
commandBufferQueue.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
||||||
@@ -802,7 +815,7 @@ const FMaterial* FEngine::getSkyboxMaterial() const noexcept {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T, typename ... ARGS>
|
template<typename T, typename ... ARGS>
|
||||||
inline T* FEngine::create(ResourceList<T>& list,
|
T* FEngine::create(ResourceList<T>& list,
|
||||||
typename T::Builder const& builder, ARGS&& ... args) noexcept {
|
typename T::Builder const& builder, ARGS&& ... args) noexcept {
|
||||||
T* p = mHeapAllocator.make<T>(*this, builder, std::forward<ARGS>(args)...);
|
T* p = mHeapAllocator.make<T>(*this, builder, std::forward<ARGS>(args)...);
|
||||||
if (UTILS_LIKELY(p)) {
|
if (UTILS_LIKELY(p)) {
|
||||||
@@ -880,7 +893,7 @@ FMaterialInstance* FEngine::createMaterialInstance(const FMaterial* material,
|
|||||||
const FMaterialInstance* other, const char* name) noexcept {
|
const FMaterialInstance* other, const char* name) noexcept {
|
||||||
FMaterialInstance* p = mHeapAllocator.make<FMaterialInstance>(*this, other, name);
|
FMaterialInstance* p = mHeapAllocator.make<FMaterialInstance>(*this, other, name);
|
||||||
if (UTILS_LIKELY(p)) {
|
if (UTILS_LIKELY(p)) {
|
||||||
auto pos = mMaterialInstances.emplace(material, "MaterialInstance");
|
auto const pos = mMaterialInstances.emplace(material, "MaterialInstance");
|
||||||
pos.first->second.insert(p);
|
pos.first->second.insert(p);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
@@ -958,7 +971,7 @@ FCamera* FEngine::createCamera(Entity const entity) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FCamera* FEngine::getCameraComponent(Entity const entity) noexcept {
|
FCamera* FEngine::getCameraComponent(Entity const entity) noexcept {
|
||||||
auto ci = mCameraManager.getInstance(entity);
|
auto const ci = mCameraManager.getInstance(entity);
|
||||||
return ci ? mCameraManager.getCamera(ci) : nullptr;
|
return ci ? mCameraManager.getCamera(ci) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,16 +1024,16 @@ void FEngine::cleanupResourceListLocked(Lock& lock, ResourceList<T>&& list) {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
UTILS_ALWAYS_INLINE
|
UTILS_ALWAYS_INLINE
|
||||||
inline bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
|
bool FEngine::isValid(const T* ptr, ResourceList<T> const& list) const {
|
||||||
auto& l = const_cast<ResourceList<T>&>(list);
|
auto& l = const_cast<ResourceList<T>&>(list);
|
||||||
return l.find(ptr) != l.end();
|
return l.find(ptr) != l.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
UTILS_ALWAYS_INLINE
|
UTILS_ALWAYS_INLINE
|
||||||
inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
|
bool FEngine::terminateAndDestroy(const T* p, ResourceList<T>& list) {
|
||||||
if (ptr == nullptr) return true;
|
if (p == nullptr) return true;
|
||||||
bool const success = list.remove(ptr);
|
bool const success = list.remove(p);
|
||||||
|
|
||||||
#if UTILS_HAS_RTTI
|
#if UTILS_HAS_RTTI
|
||||||
auto typeName = CallStack::typeName<T>();
|
auto typeName = CallStack::typeName<T>();
|
||||||
@@ -1030,19 +1043,19 @@ inline bool FEngine::terminateAndDestroy(const T* ptr, ResourceList<T>& list) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ASSERT_PRECONDITION_NON_FATAL(success,
|
if (ASSERT_PRECONDITION_NON_FATAL(success,
|
||||||
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
|
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
|
||||||
const_cast<T*>(ptr)->terminate(*this);
|
const_cast<T*>(p)->terminate(*this);
|
||||||
mHeapAllocator.destroy(const_cast<T*>(ptr));
|
mHeapAllocator.destroy(const_cast<T*>(p));
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Lock>
|
template<typename T, typename Lock>
|
||||||
UTILS_ALWAYS_INLINE
|
UTILS_ALWAYS_INLINE
|
||||||
inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, ResourceList<T>& list) {
|
bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* p, ResourceList<T>& list) {
|
||||||
if (ptr == nullptr) return true;
|
if (p == nullptr) return true;
|
||||||
lock.lock();
|
lock.lock();
|
||||||
bool const success = list.remove(ptr);
|
bool const success = list.remove(p);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
#if UTILS_HAS_RTTI
|
#if UTILS_HAS_RTTI
|
||||||
@@ -1053,9 +1066,9 @@ inline bool FEngine::terminateAndDestroyLocked(Lock& lock, const T* ptr, Resourc
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ASSERT_PRECONDITION_NON_FATAL(success,
|
if (ASSERT_PRECONDITION_NON_FATAL(success,
|
||||||
"Object %s at %p doesn't exist (double free?)", typeNameCStr, ptr)) {
|
"Object %s at %p doesn't exist (double free?)", typeNameCStr, p)) {
|
||||||
const_cast<T*>(ptr)->terminate(*this);
|
const_cast<T*>(p)->terminate(*this);
|
||||||
mHeapAllocator.destroy(const_cast<T*>(ptr));
|
mHeapAllocator.destroy(const_cast<T*>(p));
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@@ -1148,11 +1161,11 @@ bool FEngine::destroy(const FInstanceBuffer* p){
|
|||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
bool FEngine::destroy(const FMaterial* ptr) {
|
bool FEngine::destroy(const FMaterial* p) {
|
||||||
if (ptr == nullptr) return true;
|
if (p == nullptr) return true;
|
||||||
bool const success = terminateAndDestroy(ptr, mMaterials);
|
bool const success = terminateAndDestroy(p, mMaterials);
|
||||||
if (UTILS_LIKELY(success)) {
|
if (UTILS_LIKELY(success)) {
|
||||||
auto pos = mMaterialInstances.find(ptr);
|
auto const pos = mMaterialInstances.find(p);
|
||||||
if (UTILS_LIKELY(pos != mMaterialInstances.cend())) {
|
if (UTILS_LIKELY(pos != mMaterialInstances.cend())) {
|
||||||
mMaterialInstances.erase(pos);
|
mMaterialInstances.erase(pos);
|
||||||
}
|
}
|
||||||
@@ -1161,8 +1174,8 @@ bool FEngine::destroy(const FMaterial* ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
bool FEngine::destroy(const FMaterialInstance* ptr) {
|
bool FEngine::destroy(const FMaterialInstance* p) {
|
||||||
if (ptr == nullptr) return true;
|
if (p == nullptr) return true;
|
||||||
|
|
||||||
// Check that the material instance we're destroying is not in use in the RenderableManager
|
// Check that the material instance we're destroying is not in use in the RenderableManager
|
||||||
// To do this, we currently need to inspect all render primitives in the RenderableManager
|
// To do this, we currently need to inspect all render primitives in the RenderableManager
|
||||||
@@ -1178,13 +1191,13 @@ bool FEngine::destroy(const FMaterialInstance* ptr) {
|
|||||||
for (size_t j = 0; j < primitiveCount; j++) {
|
for (size_t j = 0; j < primitiveCount; j++) {
|
||||||
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
|
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
|
||||||
if (features.engine.debug.assert_material_instance_in_use) {
|
if (features.engine.debug.assert_material_instance_in_use) {
|
||||||
FILAMENT_CHECK_PRECONDITION(mi != ptr)
|
FILAMENT_CHECK_PRECONDITION(mi != p)
|
||||||
<< "destroying MaterialInstance \""
|
<< "destroying MaterialInstance \""
|
||||||
<< mi->getName() << "\" which is still in use by Renderable (entity="
|
<< mi->getName() << "\" which is still in use by Renderable (entity="
|
||||||
<< entity.getId() << ", instance="
|
<< entity.getId() << ", instance="
|
||||||
<< ri.asValue() << ", index=" << j << ")";
|
<< ri.asValue() << ", index=" << j << ")";
|
||||||
} else {
|
} else {
|
||||||
if (UTILS_UNLIKELY(mi == ptr)) {
|
if (UTILS_UNLIKELY(mi == p)) {
|
||||||
slog.e << "destroying MaterialInstance \""
|
slog.e << "destroying MaterialInstance \""
|
||||||
<< mi->getName() << "\" which is still in use by Renderable (entity="
|
<< mi->getName() << "\" which is still in use by Renderable (entity="
|
||||||
<< entity.getId() << ", instance="
|
<< entity.getId() << ", instance="
|
||||||
@@ -1196,11 +1209,11 @@ bool FEngine::destroy(const FMaterialInstance* ptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr->isDefaultInstance()) return false;
|
if (p->isDefaultInstance()) return false;
|
||||||
auto pos = mMaterialInstances.find(ptr->getMaterial());
|
auto const pos = mMaterialInstances.find(p->getMaterial());
|
||||||
assert_invariant(pos != mMaterialInstances.cend());
|
assert_invariant(pos != mMaterialInstances.cend());
|
||||||
if (pos != mMaterialInstances.cend()) {
|
if (pos != mMaterialInstances.cend()) {
|
||||||
return terminateAndDestroy(ptr, pos->second);
|
return terminateAndDestroy(p, pos->second);
|
||||||
}
|
}
|
||||||
// this shouldn't happen, this would be double-free
|
// this shouldn't happen, this would be double-free
|
||||||
return false;
|
return false;
|
||||||
@@ -1253,7 +1266,7 @@ bool FEngine::isValid(const FMaterial* m, const FMaterialInstance* p) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// then find the material instance list for that material
|
// then find the material instance list for that material
|
||||||
auto it = mMaterialInstances.find(m);
|
auto const it = mMaterialInstances.find(m);
|
||||||
if (it == mMaterialInstances.end()) {
|
if (it == mMaterialInstances.end()) {
|
||||||
// this could happen if this material has no material instances at all
|
// this could happen if this material has no material instances at all
|
||||||
return false;
|
return false;
|
||||||
@@ -1342,7 +1355,7 @@ void* FEngine::streamAlloc(size_t const size, size_t const alignment) noexcept {
|
|||||||
|
|
||||||
bool FEngine::execute() {
|
bool FEngine::execute() {
|
||||||
// wait until we get command buffers to be executed (or thread exit requested)
|
// wait until we get command buffers to be executed (or thread exit requested)
|
||||||
auto buffers = mCommandBufferQueue.waitForCommands();
|
auto const buffers = mCommandBufferQueue.waitForCommands();
|
||||||
if (UTILS_UNLIKELY(buffers.empty())) {
|
if (UTILS_UNLIKELY(buffers.empty())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1381,7 +1394,7 @@ Engine::FeatureLevel FEngine::getSupportedFeatureLevel() const noexcept {
|
|||||||
|
|
||||||
Engine::FeatureLevel FEngine::setActiveFeatureLevel(FeatureLevel featureLevel) {
|
Engine::FeatureLevel FEngine::setActiveFeatureLevel(FeatureLevel featureLevel) {
|
||||||
FILAMENT_CHECK_PRECONDITION(featureLevel <= getSupportedFeatureLevel())
|
FILAMENT_CHECK_PRECONDITION(featureLevel <= getSupportedFeatureLevel())
|
||||||
<< "Feature level " << (unsigned)featureLevel << " not supported";
|
<< "Feature level " << unsigned(featureLevel) << " not supported";
|
||||||
FILAMENT_CHECK_PRECONDITION(mActiveFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1)
|
FILAMENT_CHECK_PRECONDITION(mActiveFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1)
|
||||||
<< "Cannot adjust feature level beyond 0 at runtime";
|
<< "Cannot adjust feature level beyond 0 at runtime";
|
||||||
return (mActiveFeatureLevel = std::max(mActiveFeatureLevel, featureLevel));
|
return (mActiveFeatureLevel = std::max(mActiveFeatureLevel, featureLevel));
|
||||||
@@ -1400,7 +1413,7 @@ void FEngine::unprotected() noexcept {
|
|||||||
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
|
mUnprotectedDummySwapchain->makeCurrent(getDriverApi());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FEngine::setFeatureFlag(char const* name, bool const value) noexcept {
|
bool FEngine::setFeatureFlag(char const* name, bool const value) const noexcept {
|
||||||
auto* const p = getFeatureFlagPtr(name);
|
auto* const p = getFeatureFlagPtr(name);
|
||||||
if (p) {
|
if (p) {
|
||||||
*p = value;
|
*p = value;
|
||||||
@@ -1471,7 +1484,7 @@ Engine::Builder& Engine::Builder::feature(char const* name, bool const value) no
|
|||||||
}
|
}
|
||||||
|
|
||||||
Engine::Builder& Engine::Builder::features(std::initializer_list<char const *> const list) noexcept {
|
Engine::Builder& Engine::Builder::features(std::initializer_list<char const *> const list) noexcept {
|
||||||
for (auto name : list) {
|
for (auto const name : list) {
|
||||||
if (name) {
|
if (name) {
|
||||||
feature(name, true);
|
feature(name, true);
|
||||||
}
|
}
|
||||||
@@ -1500,15 +1513,15 @@ Engine::Config Engine::BuilderDetails::validateConfig(Config config) noexcept {
|
|||||||
// Use at least the defaults set by the build system
|
// Use at least the defaults set by the build system
|
||||||
config.minCommandBufferSizeMB = std::max(
|
config.minCommandBufferSizeMB = std::max(
|
||||||
config.minCommandBufferSizeMB,
|
config.minCommandBufferSizeMB,
|
||||||
(uint32_t)FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB);
|
uint32_t(FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
|
||||||
|
|
||||||
config.perFrameCommandsSizeMB = std::max(
|
config.perFrameCommandsSizeMB = std::max(
|
||||||
config.perFrameCommandsSizeMB,
|
config.perFrameCommandsSizeMB,
|
||||||
(uint32_t)FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB);
|
uint32_t(FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
|
||||||
|
|
||||||
config.perRenderPassArenaSizeMB = std::max(
|
config.perRenderPassArenaSizeMB = std::max(
|
||||||
config.perRenderPassArenaSizeMB,
|
config.perRenderPassArenaSizeMB,
|
||||||
(uint32_t)FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB);
|
uint32_t(FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB)); // NOLINT(*-include-cleaner)
|
||||||
|
|
||||||
config.commandBufferSizeMB = std::max(
|
config.commandBufferSizeMB = std::max(
|
||||||
config.commandBufferSizeMB,
|
config.commandBufferSizeMB,
|
||||||
|
|||||||
@@ -61,6 +61,8 @@
|
|||||||
#include <filament/Texture.h>
|
#include <filament/Texture.h>
|
||||||
#include <filament/VertexBuffer.h>
|
#include <filament/VertexBuffer.h>
|
||||||
|
|
||||||
|
#include <backend/DriverEnums.h>
|
||||||
|
|
||||||
#include <utils/Allocator.h>
|
#include <utils/Allocator.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/CountDownLatch.h>
|
#include <utils/CountDownLatch.h>
|
||||||
@@ -122,12 +124,11 @@ class ResourceAllocator;
|
|||||||
*/
|
*/
|
||||||
class FEngine : public Engine {
|
class FEngine : public Engine {
|
||||||
public:
|
public:
|
||||||
|
void* operator new(std::size_t const size) noexcept {
|
||||||
inline void* operator new(std::size_t const size) noexcept {
|
|
||||||
return utils::aligned_alloc(size, alignof(FEngine));
|
return utils::aligned_alloc(size, alignof(FEngine));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void operator delete(void* p) noexcept {
|
void operator delete(void* p) noexcept {
|
||||||
utils::aligned_free(p);
|
utils::aligned_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +491,7 @@ public:
|
|||||||
backend::Handle<backend::HwTexture> getOneTextureArray() const { return mDummyOneTextureArray; }
|
backend::Handle<backend::HwTexture> getOneTextureArray() const { return mDummyOneTextureArray; }
|
||||||
backend::Handle<backend::HwTexture> getZeroTextureArray() const { return mDummyZeroTextureArray; }
|
backend::Handle<backend::HwTexture> getZeroTextureArray() const { return mDummyZeroTextureArray; }
|
||||||
|
|
||||||
static constexpr const size_t MiB = 1024u * 1024u;
|
static constexpr size_t MiB = 1024u * 1024u;
|
||||||
size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; }
|
size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; }
|
||||||
size_t getCommandBufferSize() const noexcept { return mConfig.commandBufferSizeMB * MiB; }
|
size_t getCommandBufferSize() const noexcept { return mConfig.commandBufferSizeMB * MiB; }
|
||||||
size_t getPerFrameCommandsSize() const noexcept { return mConfig.perFrameCommandsSizeMB * MiB; }
|
size_t getPerFrameCommandsSize() const noexcept { return mConfig.perFrameCommandsSizeMB * MiB; }
|
||||||
@@ -510,15 +511,15 @@ public:
|
|||||||
void resetBackendState() noexcept;
|
void resetBackendState() noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
backend::Driver& getDriver() const noexcept { return *mDriver; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit FEngine(Builder const& builder);
|
explicit FEngine(Builder const& builder);
|
||||||
void init();
|
void init();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
int loop();
|
int loop();
|
||||||
void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue);
|
void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue) const;
|
||||||
|
|
||||||
backend::Driver& getDriver() const noexcept { return *mDriver; }
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool isValid(const T* ptr, ResourceList<T> const& list) const;
|
bool isValid(const T* ptr, ResourceList<T> const& list) const;
|
||||||
@@ -729,7 +730,7 @@ public:
|
|||||||
return { mFeatures.data(), mFeatures.size() };
|
return { mFeatures.data(), mFeatures.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setFeatureFlag(char const* name, bool value) noexcept;
|
bool setFeatureFlag(char const* name, bool value) const noexcept;
|
||||||
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
|
std::optional<bool> getFeatureFlag(char const* name) const noexcept;
|
||||||
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
|
bool* getFeatureFlagPtr(std::string_view name, bool allowConstant = false) const noexcept;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -196,10 +196,10 @@ void FMaterialInstance::commit(DriverApi& driver) const {
|
|||||||
for (auto const& [binding, p]: mTextureParameters) {
|
for (auto const& [binding, p]: mTextureParameters) {
|
||||||
assert_invariant(p.texture);
|
assert_invariant(p.texture);
|
||||||
// TODO: figure out a way to do this more efficiently (isValid() is a hashmap lookup)
|
// TODO: figure out a way to do this more efficiently (isValid() is a hashmap lookup)
|
||||||
FEngine& engine = mMaterial->getEngine();
|
FEngine const& engine = mMaterial->getEngine();
|
||||||
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
|
FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture))
|
||||||
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
|
<< "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n";
|
||||||
Handle<HwTexture> handle = p.texture->getHwHandleForSampling();
|
Handle<HwTexture> const handle = p.texture->getHwHandleForSampling();
|
||||||
assert_invariant(handle);
|
assert_invariant(handle);
|
||||||
mDescriptorSet.setSampler(binding, handle, p.params);
|
mDescriptorSet.setSampler(binding, handle, p.params);
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ void FMaterialInstance::commit(DriverApi& driver) const {
|
|||||||
|
|
||||||
void FMaterialInstance::setParameter(std::string_view const name,
|
void FMaterialInstance::setParameter(std::string_view const name,
|
||||||
Handle<HwTexture> texture, SamplerParams const params) {
|
Handle<HwTexture> texture, SamplerParams const params) {
|
||||||
auto binding = mMaterial->getSamplerBinding(name);
|
auto const binding = mMaterial->getSamplerBinding(name);
|
||||||
mDescriptorSet.setSampler(binding, texture, params);
|
mDescriptorSet.setSampler(binding, texture, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto binding = mMaterial->getSamplerBinding(name);
|
auto const binding = mMaterial->getSamplerBinding(name);
|
||||||
if (texture && texture->textureHandleCanMutate()) {
|
if (texture && texture->textureHandleCanMutate()) {
|
||||||
mTextureParameters[binding] = { texture, sampler.getSamplerParams() };
|
mTextureParameters[binding] = { texture, sampler.getSamplerParams() };
|
||||||
} else {
|
} else {
|
||||||
@@ -328,13 +328,13 @@ const char* FMaterialInstance::getName() const noexcept {
|
|||||||
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
|
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
|
||||||
|
|
||||||
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
|
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
|
||||||
std::call_once(mMissingSamplersFlag, [this]() {
|
std::call_once(mMissingSamplersFlag, [this] {
|
||||||
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
||||||
slog.w << "sampler parameters not set in MaterialInstance \""
|
slog.w << "sampler parameters not set in MaterialInstance \""
|
||||||
<< mName.c_str_safe() << "\" or Material \""
|
<< mName.c_str_safe() << "\" or Material \""
|
||||||
<< mMaterial->getName().c_str_safe() << "\":\n";
|
<< mMaterial->getName().c_str_safe() << "\":\n";
|
||||||
mMissingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) {
|
mMissingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) {
|
||||||
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
||||||
return item.binding == binding;
|
return item.binding == binding;
|
||||||
});
|
});
|
||||||
// just safety-check, should never fail
|
// just safety-check, should never fail
|
||||||
@@ -368,7 +368,7 @@ void FMaterialInstance::fixMissingSamplers() const {
|
|||||||
// here we need to set the samplers that are missing
|
// here we need to set the samplers that are missing
|
||||||
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList();
|
||||||
missingSamplerDescriptors.forEachSetBit([this, &list](descriptor_binding_t binding) {
|
missingSamplerDescriptors.forEachSetBit([this, &list](descriptor_binding_t binding) {
|
||||||
auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) {
|
||||||
return item.binding == binding;
|
return item.binding == binding;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ public:
|
|||||||
|
|
||||||
backend::CullingMode getCullingMode() const noexcept { return mCulling; }
|
backend::CullingMode getCullingMode() const noexcept { return mCulling; }
|
||||||
|
|
||||||
|
backend::CullingMode getShadowCullingMode() const noexcept { return mShadowCulling; }
|
||||||
|
|
||||||
bool isColorWriteEnabled() const noexcept { return mColorWrite; }
|
bool isColorWriteEnabled() const noexcept { return mColorWrite; }
|
||||||
|
|
||||||
bool isDepthWriteEnabled() const noexcept { return mDepthWrite; }
|
bool isDepthWriteEnabled() const noexcept { return mDepthWrite; }
|
||||||
@@ -137,6 +139,11 @@ public:
|
|||||||
|
|
||||||
void setCullingMode(CullingMode const culling) noexcept { mCulling = culling; }
|
void setCullingMode(CullingMode const culling) noexcept { mCulling = culling; }
|
||||||
|
|
||||||
|
void setCullingMode(CullingMode const color, CullingMode const shadow) noexcept {
|
||||||
|
mCulling = color;
|
||||||
|
mShadowCulling = shadow;
|
||||||
|
}
|
||||||
|
|
||||||
void setColorWrite(bool const enable) noexcept { mColorWrite = enable; }
|
void setColorWrite(bool const enable) noexcept { mColorWrite = enable; }
|
||||||
|
|
||||||
void setDepthWrite(bool const enable) noexcept { mDepthWrite = enable; }
|
void setDepthWrite(bool const enable) noexcept { mDepthWrite = enable; }
|
||||||
@@ -271,7 +278,9 @@ private:
|
|||||||
float mSpecularAntiAliasingThreshold = 0.0f;
|
float mSpecularAntiAliasingThreshold = 0.0f;
|
||||||
|
|
||||||
backend::CullingMode mCulling : 2;
|
backend::CullingMode mCulling : 2;
|
||||||
|
backend::CullingMode mShadowCulling : 2;
|
||||||
backend::RasterState::DepthFunc mDepthFunc : 3;
|
backend::RasterState::DepthFunc mDepthFunc : 3;
|
||||||
|
|
||||||
bool mColorWrite : 1;
|
bool mColorWrite : 1;
|
||||||
bool mDepthWrite : 1;
|
bool mDepthWrite : 1;
|
||||||
bool mHasScissor : 1;
|
bool mHasScissor : 1;
|
||||||
@@ -283,8 +292,8 @@ private:
|
|||||||
|
|
||||||
// Scissor rectangle is specified as: Left Bottom Width Height.
|
// Scissor rectangle is specified as: Left Bottom Width Height.
|
||||||
backend::Viewport mScissorRect = { 0, 0,
|
backend::Viewport mScissorRect = { 0, 0,
|
||||||
(uint32_t)std::numeric_limits<int32_t>::max(),
|
uint32_t(std::numeric_limits<int32_t>::max()),
|
||||||
(uint32_t)std::numeric_limits<int32_t>::max()
|
uint32_t(std::numeric_limits<int32_t>::max())
|
||||||
};
|
};
|
||||||
|
|
||||||
utils::CString mName;
|
utils::CString mName;
|
||||||
|
|||||||
@@ -546,6 +546,11 @@ void FScene::removeEntities(const Entity* entities, size_t const count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UTILS_NOINLINE
|
||||||
|
void FScene::removeAllEntities() noexcept {
|
||||||
|
mEntities.clear();
|
||||||
|
}
|
||||||
|
|
||||||
UTILS_NOINLINE
|
UTILS_NOINLINE
|
||||||
size_t FScene::getRenderableCount() const noexcept {
|
size_t FScene::getRenderableCount() const noexcept {
|
||||||
FEngine& engine = mEngine;
|
FEngine& engine = mEngine;
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ private:
|
|||||||
void addEntities(const utils::Entity* entities, size_t count);
|
void addEntities(const utils::Entity* entities, size_t count);
|
||||||
void remove(utils::Entity entity);
|
void remove(utils::Entity entity);
|
||||||
void removeEntities(const utils::Entity* entities, size_t count);
|
void removeEntities(const utils::Entity* entities, size_t count);
|
||||||
|
void removeAllEntities() noexcept;
|
||||||
size_t getEntityCount() const noexcept { return mEntities.size(); }
|
size_t getEntityCount() const noexcept { return mEntities.size(); }
|
||||||
size_t getRenderableCount() const noexcept;
|
size_t getRenderableCount() const noexcept;
|
||||||
size_t getLightCount() const noexcept;
|
size_t getLightCount() const noexcept;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
Pod::Spec.new do |spec|
|
Pod::Spec.new do |spec|
|
||||||
spec.name = "Filament"
|
spec.name = "Filament"
|
||||||
spec.version = "1.56.7"
|
spec.version = "1.57.0"
|
||||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||||
spec.homepage = "https://google.github.io/filament"
|
spec.homepage = "https://google.github.io/filament"
|
||||||
spec.authors = "Google LLC."
|
spec.authors = "Google LLC."
|
||||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||||
spec.platform = :ios, "11.0"
|
spec.platform = :ios, "11.0"
|
||||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.7/filament-v1.56.7-ios.tgz" }
|
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.57.0/filament-v1.57.0-ios.tgz" }
|
||||||
|
|
||||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||||
spec.pod_target_xcconfig = {
|
spec.pod_target_xcconfig = {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
// update this when a new version of filament wouldn't work with older materials
|
// update this when a new version of filament wouldn't work with older materials
|
||||||
static constexpr size_t MATERIAL_VERSION = 56;
|
static constexpr size_t MATERIAL_VERSION = 57;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported shading models
|
* Supported shading models
|
||||||
|
|||||||
@@ -704,19 +704,12 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
|
|||||||
::prepareNativeWindow(mWindow);
|
::prepareNativeWindow(mWindow);
|
||||||
|
|
||||||
void* metalLayer = nullptr;
|
void* metalLayer = nullptr;
|
||||||
if (config.backend == filament::Engine::Backend::METAL) {
|
if (config.backend == filament::Engine::Backend::METAL || config.backend == filament::Engine::Backend::VULKAN) {
|
||||||
metalLayer = setUpMetalLayer(nativeWindow);
|
metalLayer = setUpMetalLayer(nativeWindow);
|
||||||
// The swap chain on Metal is a CAMetalLayer.
|
// The swap chain on both native Metal and MoltenVK is a CAMetalLayer.
|
||||||
nativeSwapChain = metalLayer;
|
nativeSwapChain = metalLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
|
||||||
if (config.backend == filament::Engine::Backend::VULKAN) {
|
|
||||||
// We request a Metal layer for rendering via MoltenVK.
|
|
||||||
setUpMetalLayer(nativeWindow);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Write back the active feature level.
|
// Write back the active feature level.
|
||||||
|
|||||||
@@ -222,8 +222,13 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ApiHandler::addMaterial(MaterialRecord const* material) {
|
void ApiHandler::addMaterial(MaterialRecord const* material) {
|
||||||
|
updateMaterial(material->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiHandler::updateMaterial(uint32_t key) {
|
||||||
std::unique_lock const lock(mStatusMutex);
|
std::unique_lock const lock(mStatusMutex);
|
||||||
snprintf(statusMaterialId, sizeof(statusMaterialId), "%8.8x", material->key);
|
mCurrentStatus++;
|
||||||
|
snprintf(statusMaterialId, sizeof(statusMaterialId), "%8.8x", key);
|
||||||
mStatusCondition.notify_all();
|
mStatusCondition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,8 +293,11 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
|
|||||||
sstream >> std::hex >> matid >> std::dec >> api >> shaderIndex;
|
sstream >> std::hex >> matid >> std::dec >> api >> shaderIndex;
|
||||||
std::string const shader = sstream.str().substr(sstream.tellg());
|
std::string const shader = sstream.str().substr(sstream.tellg());
|
||||||
|
|
||||||
mServer->handleEditCommand(matid, backend::Backend(api), shaderIndex, shader.c_str(),
|
if (!mServer->handleEditCommand(matid, backend::Backend(api), shaderIndex, shader.c_str(),
|
||||||
shader.size());
|
shader.size())) {
|
||||||
|
return error(__LINE__, uri);
|
||||||
|
}
|
||||||
|
updateMaterial(matid);
|
||||||
|
|
||||||
mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close");
|
mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: close");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ private:
|
|||||||
bool handleGetStatus(struct mg_connection* conn, struct mg_request_info const* request);
|
bool handleGetStatus(struct mg_connection* conn, struct mg_request_info const* request);
|
||||||
MaterialRecord const* getMaterialRecord(struct mg_request_info const* request);
|
MaterialRecord const* getMaterialRecord(struct mg_request_info const* request);
|
||||||
|
|
||||||
|
void updateMaterial(uint32_t key);
|
||||||
|
|
||||||
DebugServer* mServer;
|
DebugServer* mServer;
|
||||||
|
|
||||||
std::mutex mStatusMutex;
|
std::mutex mStatusMutex;
|
||||||
@@ -64,7 +66,7 @@ private:
|
|||||||
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
|
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
|
||||||
// will always block until statusMaterialId is updated again. The client is expected to keep
|
// will always block until statusMaterialId is updated again. The client is expected to keep
|
||||||
// calling /api/status (a constant "pull" to simulate a push).
|
// calling /api/status (a constant "pull" to simulate a push).
|
||||||
std::atomic<uint64_t> mCurrentStatus = 0;
|
uint64_t mCurrentStatus = 0;
|
||||||
|
|
||||||
SourceFormatter mFormatter;
|
SourceFormatter mFormatter;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <GlslangToSpv.h>
|
#include <GlslangToSpv.h>
|
||||||
@@ -50,10 +51,30 @@ using namespace glslang;
|
|||||||
using namespace utils;
|
using namespace utils;
|
||||||
|
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
using std::stringstream;
|
|
||||||
using std::streampos;
|
using std::streampos;
|
||||||
|
using std::stringstream;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// This is to ensure that the edited material package have the same order of shaders as the output
|
||||||
|
// of the original material. We use the ordering in the front-end to simplify logic.
|
||||||
|
template<typename RecordType>
|
||||||
|
void sortRecords(std::vector<RecordType>& records) {
|
||||||
|
std::sort(records.begin(), records.end(), [](RecordType const& a, RecordType const& b) -> bool {
|
||||||
|
if (a.shaderModel != b.shaderModel) {
|
||||||
|
return a.shaderModel < b.shaderModel;
|
||||||
|
}
|
||||||
|
if (a.variant.key != b.variant.key) {
|
||||||
|
return a.variant.key < b.variant.key;
|
||||||
|
}
|
||||||
|
return a.stage < b.stage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous
|
||||||
|
|
||||||
// Tiny database of shader text that can import / export MaterialTextChunk and DictionaryTextChunk.
|
// Tiny database of shader text that can import / export MaterialTextChunk and DictionaryTextChunk.
|
||||||
class ShaderIndex {
|
class ShaderIndex {
|
||||||
public:
|
public:
|
||||||
@@ -344,6 +365,7 @@ void ShaderIndex::writeChunks(ostream& stream) {
|
|||||||
for (const auto& record : mShaderRecords) {
|
for (const auto& record : mShaderRecords) {
|
||||||
lines.addText(record.shader);
|
lines.addText(record.shader);
|
||||||
}
|
}
|
||||||
|
sortRecords(mShaderRecords);
|
||||||
|
|
||||||
filamat::ChunkContainer cc;
|
filamat::ChunkContainer cc;
|
||||||
const auto& dchunk = cc.push<DictionaryTextChunk>(std::move(lines), mDictTag);
|
const auto& dchunk = cc.push<DictionaryTextChunk>(std::move(lines), mDictTag);
|
||||||
@@ -406,6 +428,8 @@ void BlobIndex::writeChunks(ostream& stream) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sortRecords(mShaderRecords);
|
||||||
|
|
||||||
// Apply SMOL-V compression and write out the results.
|
// Apply SMOL-V compression and write out the results.
|
||||||
filamat::ChunkContainer cc;
|
filamat::ChunkContainer cc;
|
||||||
cc.push<MaterialBinaryChunk>(std::move(mShaderRecords), ChunkType::MaterialSpirv);
|
cc.push<MaterialBinaryChunk>(std::move(mShaderRecords), ChunkType::MaterialSpirv);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ std::string SourceFormatter::format(char const* source) {
|
|||||||
while (fgets(output, 1024, fp) != NULL) {}
|
while (fgets(output, 1024, fp) != NULL) {}
|
||||||
|
|
||||||
int status = pclose(fp);
|
int status = pclose(fp);
|
||||||
if (!fp || !WEXITSTATUS(status)) {
|
if (!fp || WEXITSTATUS(status)) {
|
||||||
std::call_once(mClangWarningFlag, []() {
|
std::call_once(mClangWarningFlag, []() {
|
||||||
utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
|
utils::slog.w << "[matdbg] unable to run clang-format to format shader file. "
|
||||||
<< "Please make sure it's installed." << utils::io::endl;
|
<< "Please make sure it's installed." << utils::io::endl;
|
||||||
|
|||||||
+20
-1
@@ -240,6 +240,25 @@ function(add_demo NAME)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
function(add_demo2 NAME)
|
||||||
|
include_directories(${GENERATION_ROOT})
|
||||||
|
if (APPLE)
|
||||||
|
add_executable(${NAME} helper.h helper.mm ${NAME}.cpp)
|
||||||
|
target_link_libraries(${NAME} PRIVATE sample-resources)
|
||||||
|
target_compile_options(${NAME} PRIVATE ${COMPILER_FLAGS})
|
||||||
|
set_target_properties(${NAME} PROPERTIES FOLDER Samples)
|
||||||
|
|
||||||
|
# This is needed after XCode 15.3
|
||||||
|
target_link_libraries(${NAME} PUBLIC "-framework Cocoa -framework QuartzCore" sdl2)
|
||||||
|
set_target_properties(${NAME} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
|
||||||
|
set_target_properties(${NAME} PROPERTIES INSTALL_RPATH /usr/local/lib)
|
||||||
|
else()
|
||||||
|
add_demo(${NAME})
|
||||||
|
endif()
|
||||||
|
target_link_libraries(${NAME} PRIVATE gltfio)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID)
|
||||||
add_demo(animation)
|
add_demo(animation)
|
||||||
add_demo(depthtesting)
|
add_demo(depthtesting)
|
||||||
@@ -249,7 +268,7 @@ if (NOT ANDROID)
|
|||||||
add_demo(heightfield)
|
add_demo(heightfield)
|
||||||
add_demo(hellomorphing)
|
add_demo(hellomorphing)
|
||||||
add_demo(hellopbr)
|
add_demo(hellopbr)
|
||||||
add_demo(hellotriangle)
|
add_demo2(hellotriangle)
|
||||||
add_demo(helloskinning)
|
add_demo(helloskinning)
|
||||||
add_demo(helloskinningbuffer)
|
add_demo(helloskinningbuffer)
|
||||||
add_demo(helloskinningbuffer_morebones)
|
add_demo(helloskinningbuffer_morebones)
|
||||||
|
|||||||
+165
-166
@@ -1,192 +1,191 @@
|
|||||||
/*
|
#include <fstream>
|
||||||
* Copyright (C) 2018 The Android Open Source Project
|
#include <iostream>
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <filament/Camera.h>
|
#include <filament/Camera.h>
|
||||||
#include <filament/Engine.h>
|
#include <filament/Engine.h>
|
||||||
#include <filament/IndexBuffer.h>
|
#include <filament/IndexBuffer.h>
|
||||||
#include <filament/Material.h>
|
#include <filament/LightManager.h>
|
||||||
#include <filament/MaterialInstance.h>
|
|
||||||
#include <filament/RenderableManager.h>
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/Renderer.h>
|
||||||
#include <filament/Scene.h>
|
#include <filament/Scene.h>
|
||||||
#include <filament/Skybox.h>
|
#include <filament/Skybox.h>
|
||||||
#include <filament/TransformManager.h>
|
|
||||||
#include <filament/VertexBuffer.h>
|
|
||||||
#include <filament/View.h>
|
#include <filament/View.h>
|
||||||
|
#include <filament/Viewport.h>
|
||||||
|
|
||||||
|
#include <filamat/MaterialBuilder.h>
|
||||||
|
|
||||||
#include <utils/EntityManager.h>
|
#include <utils/EntityManager.h>
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <filamentapp/Config.h>
|
#include <math/norm.h>
|
||||||
#include <filamentapp/FilamentApp.h>
|
|
||||||
|
|
||||||
#include <getopt/getopt.h>
|
#include <gltfio/AssetLoader.h>
|
||||||
|
#include <gltfio/ResourceLoader.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <SDL.h>
|
||||||
#include <iostream>
|
#include <SDL_syswm.h>
|
||||||
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
|
||||||
#include "generated/resources/resources.h"
|
#if defined(__linux__)
|
||||||
|
void* getNativeWindow(SDL_Window* sdlWindow) {
|
||||||
|
SDL_SysWMinfo wmi;
|
||||||
|
SDL_VERSION(&wmi.version);
|
||||||
|
SDL_GetWindowWMInfo(sdlWindow, &wmi);
|
||||||
|
if (wmi.subsystem == SDL_SYSWM_X11) {
|
||||||
|
Window win = (Window) wmi.info.x11.window;
|
||||||
|
return (void*) win;
|
||||||
|
} else {
|
||||||
|
std::cout << "Unknown SDL subsystem";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Window* createSDLwindow() {
|
||||||
|
uint32_t windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
|
SDL_Window* win = SDL_CreateWindow("Hello World!", 100, 100, 600, 400, 0);
|
||||||
|
if (win == nullptr) {
|
||||||
|
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
|
||||||
|
SDL_Quit();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace filament;
|
using namespace filament;
|
||||||
using utils::Entity;
|
using namespace math;
|
||||||
using utils::EntityManager;
|
using namespace utils;
|
||||||
|
int main() {
|
||||||
struct App {
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
Config config;
|
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
|
||||||
VertexBuffer* vb;
|
return 1;
|
||||||
IndexBuffer* ib;
|
|
||||||
Material* mat;
|
|
||||||
Camera* cam;
|
|
||||||
Entity camera;
|
|
||||||
Skybox* skybox;
|
|
||||||
Entity renderable;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex {
|
|
||||||
filament::math::float2 position;
|
|
||||||
uint32_t color;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Vertex TRIANGLE_VERTICES[3] = {
|
|
||||||
{{1, 0}, 0xffff0000u},
|
|
||||||
{{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u},
|
|
||||||
{{cos(M_PI * 4 / 3), sin(M_PI * 4 / 3)}, 0xff0000ffu},
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 };
|
|
||||||
|
|
||||||
static void printUsage(char* name) {
|
|
||||||
std::string exec_name(utils::Path(name).getName());
|
|
||||||
std::string usage(
|
|
||||||
"HELLOTRIANGLE renders a spinning colored triangle\n"
|
|
||||||
"Usage:\n"
|
|
||||||
" HELLOTRIANGLE [options]\n"
|
|
||||||
"Options:\n"
|
|
||||||
" --help, -h\n"
|
|
||||||
" Prints this message\n\n"
|
|
||||||
" --api, -a\n"
|
|
||||||
" Specify the backend API: opengl, vulkan, or metal\n"
|
|
||||||
);
|
|
||||||
const std::string from("HELLOTRIANGLE");
|
|
||||||
for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) {
|
|
||||||
usage.replace(pos, from.length(), exec_name);
|
|
||||||
}
|
}
|
||||||
std::cout << usage;
|
const static uint32_t indices[] = { 0, 1, 2, };
|
||||||
}
|
|
||||||
|
|
||||||
static int handleCommandLineArguments(int argc, char* argv[], App* app) {
|
const static math::float3 vertices[] = {
|
||||||
static constexpr const char* OPTSTR = "ha:";
|
{ -10, 0, -10 },
|
||||||
static const struct option OPTIONS[] = {
|
{ -10, 0, 10 },
|
||||||
{ "help", no_argument, nullptr, 'h' },
|
{ 10, 0, 10 },
|
||||||
{ "api", required_argument, nullptr, 'a' },
|
|
||||||
{ nullptr, 0, nullptr, 0 }
|
|
||||||
};
|
};
|
||||||
int opt;
|
|
||||||
int option_index = 0;
|
short4 tbn = math::packSnorm16(
|
||||||
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
|
mat3f::packTangentFrame(
|
||||||
std::string arg(optarg ? optarg : "");
|
math::mat3f{
|
||||||
switch (opt) {
|
float3{ 1.0f, 0.0f, 0.0f },
|
||||||
default:
|
float3{ 0.0f, 0.0f, 1.0f }, float3{ 0.0f, 1.0f, 0.0f } })
|
||||||
case 'h':
|
.xyzw);
|
||||||
printUsage(argv[0]);
|
|
||||||
exit(0);
|
const static math::short4 normals[]{ tbn, tbn, tbn };
|
||||||
case 'a':
|
SDL_Window* window = createSDLwindow();
|
||||||
if (arg == "opengl") {
|
if (!window) {
|
||||||
app->config.backend = Engine::Backend::OPENGL;
|
return 1;
|
||||||
} else if (arg == "vulkan") {
|
}
|
||||||
app->config.backend = Engine::Backend::VULKAN;
|
Engine* engine = Engine::create(filament::backend::Backend::VULKAN);
|
||||||
} else if (arg == "metal") {
|
SwapChain* swapChain = engine->createSwapChain(getNativeWindow(window));
|
||||||
app->config.backend = Engine::Backend::METAL;
|
Renderer* renderer = engine->createRenderer();
|
||||||
} else {
|
|
||||||
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n";
|
auto cameraEntity = EntityManager::get().create();
|
||||||
exit(1);
|
Camera* camera = engine->createCamera(cameraEntity);
|
||||||
}
|
View* view = engine->createView();
|
||||||
break;
|
Scene* scene = engine->createScene();
|
||||||
|
|
||||||
|
view->setCamera(camera);
|
||||||
|
// Determine the current size of the window in physical pixels.
|
||||||
|
uint32_t w, h;
|
||||||
|
SDL_GL_GetDrawableSize(window, (int*) &w, (int*) &h);
|
||||||
|
camera->lookAt(float3(0, 50.5f, 0), float3(0, 0, 0), float3(1.f, 0, 0));
|
||||||
|
camera->setProjection(45.0, double(w) / h, 0.1, 50, Camera::Fov::VERTICAL);
|
||||||
|
view->setViewport({ 0, 0, w, h });
|
||||||
|
view->setScene(scene);
|
||||||
|
view->setPostProcessingEnabled(false);
|
||||||
|
|
||||||
|
VertexBuffer* vertexBuffer =
|
||||||
|
VertexBuffer::Builder()
|
||||||
|
.vertexCount(3)
|
||||||
|
.bufferCount(2)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.attribute(VertexAttribute::TANGENTS, 1, VertexBuffer::AttributeType::SHORT4)
|
||||||
|
.normalized(VertexAttribute::TANGENTS)
|
||||||
|
.build(*engine);
|
||||||
|
|
||||||
|
vertexBuffer->setBufferAt(*engine, 0,
|
||||||
|
VertexBuffer::BufferDescriptor(vertices,
|
||||||
|
vertexBuffer->getVertexCount() * sizeof(vertices[0])));
|
||||||
|
vertexBuffer->setBufferAt(*engine, 1,
|
||||||
|
VertexBuffer::BufferDescriptor(normals,
|
||||||
|
vertexBuffer->getVertexCount() * sizeof(normals[0])));
|
||||||
|
|
||||||
|
IndexBuffer* indexBuffer = IndexBuffer::Builder().indexCount(3).build(*engine);
|
||||||
|
|
||||||
|
indexBuffer->setBuffer(*engine,
|
||||||
|
IndexBuffer::BufferDescriptor(indices,
|
||||||
|
indexBuffer->getIndexCount() * sizeof(uint32_t)));
|
||||||
|
|
||||||
|
filamat::MaterialBuilder::init();
|
||||||
|
filamat::MaterialBuilder builder;
|
||||||
|
builder.name("Material")
|
||||||
|
.material(" void material(inout MaterialInputs material) {\n"
|
||||||
|
" prepareMaterial(material);"
|
||||||
|
" material.baseColor.rgb = materialParams.baseColor;"
|
||||||
|
" }")
|
||||||
|
.parameter("baseColor", filament::backend::UniformType::FLOAT3)
|
||||||
|
.parameter("metallic", filament::backend::UniformType::FLOAT)
|
||||||
|
.parameter("roughness", filament::backend::UniformType::FLOAT)
|
||||||
|
.parameter("reflectance", filament::backend::UniformType::FLOAT)
|
||||||
|
.optimization(filamat::MaterialBuilder::Optimization::NONE)
|
||||||
|
.shading(filamat::MaterialBuilder::Shading::UNLIT)
|
||||||
|
.targetApi(filamat::MaterialBuilder::TargetApi::ALL)
|
||||||
|
.platform(filamat::MaterialBuilder::Platform::ALL);
|
||||||
|
|
||||||
|
filamat::Package package = builder.build(engine->getJobSystem());
|
||||||
|
|
||||||
|
Material* material =
|
||||||
|
Material::Builder().package(package.getData(), package.getSize()).build(*engine);
|
||||||
|
material->setDefaultParameter("baseColor", RgbType::LINEAR, float3{ 1, 0, 0 });
|
||||||
|
material->setDefaultParameter("metallic", 0.0f);
|
||||||
|
material->setDefaultParameter("roughness", 0.4f);
|
||||||
|
material->setDefaultParameter("reflectance", 0.5f);
|
||||||
|
|
||||||
|
MaterialInstance* materialInstance = material->createInstance();
|
||||||
|
Entity renderable = EntityManager::get().create();
|
||||||
|
|
||||||
|
// build a quad
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({ { -1, -1, -1 }, { 1, 1, 1 } })
|
||||||
|
.material(0, materialInstance)
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vertexBuffer, indexBuffer, 0,
|
||||||
|
3)
|
||||||
|
.culling(false)
|
||||||
|
.build(*engine, renderable);
|
||||||
|
scene->addEntity(renderable);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i++ < 1) {
|
||||||
|
// beginFrame() returns false if we need to skip a frame
|
||||||
|
if (renderer->beginFrame(swapChain)) {
|
||||||
|
// for each View
|
||||||
|
renderer->render(view);
|
||||||
|
renderer->endFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return optind;
|
bool running = true;
|
||||||
}
|
SDL_Event event;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
while (running) {
|
||||||
App app{};
|
while (SDL_PollEvent(&event)) {
|
||||||
app.config.title = "hellotriangle";
|
if (event.type == SDL_QUIT) {
|
||||||
app.config.featureLevel = backend::FeatureLevel::FEATURE_LEVEL_0;
|
running = false;
|
||||||
handleCommandLineArguments(argc, argv, &app);
|
}
|
||||||
|
SDL_Delay(16);
|
||||||
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
|
}
|
||||||
app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine);
|
}
|
||||||
scene->setSkybox(app.skybox);
|
|
||||||
view->setPostProcessingEnabled(false);
|
|
||||||
static_assert(sizeof(Vertex) == 12, "Strange vertex size.");
|
|
||||||
app.vb = VertexBuffer::Builder()
|
|
||||||
.vertexCount(3)
|
|
||||||
.bufferCount(1)
|
|
||||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0, 12)
|
|
||||||
.attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4, 8, 12)
|
|
||||||
.normalized(VertexAttribute::COLOR)
|
|
||||||
.build(*engine);
|
|
||||||
app.vb->setBufferAt(*engine, 0,
|
|
||||||
VertexBuffer::BufferDescriptor(TRIANGLE_VERTICES, 36, nullptr));
|
|
||||||
app.ib = IndexBuffer::Builder()
|
|
||||||
.indexCount(3)
|
|
||||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
|
||||||
.build(*engine);
|
|
||||||
app.ib->setBuffer(*engine,
|
|
||||||
IndexBuffer::BufferDescriptor(TRIANGLE_INDICES, 6, nullptr));
|
|
||||||
app.mat = Material::Builder()
|
|
||||||
.package(RESOURCES_BAKEDCOLOR_DATA, RESOURCES_BAKEDCOLOR_SIZE)
|
|
||||||
.build(*engine);
|
|
||||||
app.renderable = EntityManager::get().create();
|
|
||||||
RenderableManager::Builder(1)
|
|
||||||
.boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }})
|
|
||||||
.material(0, app.mat->getDefaultInstance())
|
|
||||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.vb, app.ib, 0, 3)
|
|
||||||
.culling(false)
|
|
||||||
.receiveShadows(false)
|
|
||||||
.castShadows(false)
|
|
||||||
.build(*engine, app.renderable);
|
|
||||||
scene->addEntity(app.renderable);
|
|
||||||
app.camera = utils::EntityManager::get().create();
|
|
||||||
app.cam = engine->createCamera(app.camera);
|
|
||||||
view->setCamera(app.cam);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto cleanup = [&app](Engine* engine, View*, Scene*) {
|
|
||||||
engine->destroy(app.skybox);
|
|
||||||
engine->destroy(app.renderable);
|
|
||||||
engine->destroy(app.mat);
|
|
||||||
engine->destroy(app.vb);
|
|
||||||
engine->destroy(app.ib);
|
|
||||||
engine->destroyCameraComponent(app.camera);
|
|
||||||
utils::EntityManager::get().destroy(app.camera);
|
|
||||||
};
|
|
||||||
|
|
||||||
FilamentApp::get().animate([&app](Engine* engine, View* view, double now) {
|
|
||||||
constexpr float ZOOM = 1.5f;
|
|
||||||
const uint32_t w = view->getViewport().width;
|
|
||||||
const uint32_t h = view->getViewport().height;
|
|
||||||
const float aspect = (float) w / h;
|
|
||||||
app.cam->setProjection(Camera::Projection::ORTHO,
|
|
||||||
-aspect * ZOOM, aspect * ZOOM,
|
|
||||||
-ZOOM, ZOOM, 0, 1);
|
|
||||||
auto& tcm = engine->getTransformManager();
|
|
||||||
tcm.setTransform(tcm.getInstance(app.renderable),
|
|
||||||
filament::math::mat4f::rotation(now, filament::math::float3{ 0, 0, 1 }));
|
|
||||||
});
|
|
||||||
|
|
||||||
FilamentApp::get().run(app.config, setup, cleanup);
|
|
||||||
|
|
||||||
|
engine->destroy(cameraEntity);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef HELLO_TRIANGLE_H
|
||||||
|
#define HELLO_TRIANGLE_H
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
void* getNativeWindow(SDL_Window* sdlWindow);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "helper.h"
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
|
||||||
|
void* getNativeWindow(SDL_Window* sdlWindow) {
|
||||||
|
SDL_SysWMinfo wmi;
|
||||||
|
SDL_VERSION(&wmi.version);
|
||||||
|
FILAMENT_CHECK_POSTCONDITION(SDL_GetWindowWMInfo(sdlWindow, &wmi))
|
||||||
|
<< "SDL version unsupported!";
|
||||||
|
NSWindow* win = wmi.info.cocoa.window;
|
||||||
|
NSView* view = [win contentView];
|
||||||
|
|
||||||
|
[win setColorSpace:[NSColorSpace sRGBColorSpace]];
|
||||||
|
|
||||||
|
[view setWantsLayer:YES];
|
||||||
|
CAMetalLayer* metalLayer = [CAMetalLayer layer];
|
||||||
|
metalLayer.bounds = view.bounds;
|
||||||
|
|
||||||
|
// It's important to set the drawableSize to the actual backing pixels. When rendering
|
||||||
|
// full-screen, we can skip the macOS compositor if the size matches the display size.
|
||||||
|
metalLayer.drawableSize = [view convertSizeToBacking:view.bounds.size];
|
||||||
|
|
||||||
|
// In its implementation of vkGetPhysicalDeviceSurfaceCapabilitiesKHR, MoltenVK takes into
|
||||||
|
// consideration both the size (in points) of the bounds, and the contentsScale of the
|
||||||
|
// CAMetalLayer from which the Vulkan surface was created.
|
||||||
|
// See also https://github.com/KhronosGroup/MoltenVK/issues/428
|
||||||
|
metalLayer.contentsScale = view.window.backingScaleFactor;
|
||||||
|
|
||||||
|
// This is set to NO by default, but is also important to ensure we can bypass the compositor
|
||||||
|
// in full-screen mode
|
||||||
|
// See "Direct to Display" http://metalkit.org/2017/06/30/introducing-metal-2.html.
|
||||||
|
metalLayer.opaque = YES;
|
||||||
|
|
||||||
|
[view setLayer:metalLayer];
|
||||||
|
return metalLayer;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -205,17 +205,11 @@ void setup_window(Window& w, Engine* engine) {
|
|||||||
void* nativeSwapChain = nativeWindow;
|
void* nativeSwapChain = nativeWindow;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
void* metalLayer = nullptr;
|
void* metalLayer = nullptr;
|
||||||
if (kBackend == filament::Engine::Backend::METAL) {
|
if (kBackend == filament::Engine::Backend::METAL || kBackend == filament::Engine::Backend::VULKAN) {
|
||||||
metalLayer = setUpMetalLayer(nativeWindow);
|
metalLayer = setUpMetalLayer(nativeWindow);
|
||||||
// The swap chain on Metal is a CAMetalLayer.
|
// The swap chain on both native Metal and MoltenVK is a CAMetalLayer.
|
||||||
nativeSwapChain = metalLayer;
|
nativeSwapChain = metalLayer;
|
||||||
}
|
}
|
||||||
#if defined(FILAMENT_DRIVER_SUPPORTS_VULKAN)
|
|
||||||
if (kBackend == filament::Engine::Backend::VULKAN) {
|
|
||||||
// We request a Metal layer for rendering via MoltenVK.
|
|
||||||
setUpMetalLayer(nativeWindow);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
w.swapChain = engine->createSwapChain(nativeSwapChain);
|
w.swapChain = engine->createSwapChain(nativeSwapChain);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,27 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Common Helpers
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of the eye being rendered, starting at 0.
|
||||||
|
* @public-api
|
||||||
|
*/
|
||||||
|
int getEyeIndex() {
|
||||||
|
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
|
||||||
|
return instance_index % CONFIG_STEREO_EYE_COUNT;
|
||||||
|
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
|
||||||
|
|
||||||
|
# if defined(TARGET_VULKAN_ENVIRONMENT)
|
||||||
|
return int(gl_ViewIndex);
|
||||||
|
# else
|
||||||
|
// gl_ViewID_OVR is of uint type, which needs an explicit conversion.
|
||||||
|
return int(gl_ViewID_OVR);
|
||||||
|
# endif // TARGET_VULKAN_ENVIRONMENT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Uniforms access
|
// Uniforms access
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -24,20 +48,7 @@ highp mat4 getViewFromClipMatrix() {
|
|||||||
|
|
||||||
/** @public-api */
|
/** @public-api */
|
||||||
highp mat4 getClipFromWorldMatrix() {
|
highp mat4 getClipFromWorldMatrix() {
|
||||||
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
|
return frameUniforms.clipFromWorldMatrix[getEyeIndex()];
|
||||||
int eye = instance_index % CONFIG_STEREO_EYE_COUNT;
|
|
||||||
return frameUniforms.clipFromWorldMatrix[eye];
|
|
||||||
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
|
|
||||||
|
|
||||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
|
||||||
return frameUniforms.clipFromWorldMatrix[gl_ViewIndex];
|
|
||||||
#else
|
|
||||||
return frameUniforms.clipFromWorldMatrix[gl_ViewID_OVR];
|
|
||||||
#endif // TARGET_VULKAN_ENVIRONMENT
|
|
||||||
|
|
||||||
#else
|
|
||||||
return frameUniforms.clipFromWorldMatrix[0];
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public-api */
|
/** @public-api */
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ vec4 getCustom7() { return mesh_custom7; }
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Surface Helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,23 +275,3 @@ vec4 computeWorldPosition() {
|
|||||||
#error Unknown Vertex Domain
|
#error Unknown Vertex Domain
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Index of the eye being rendered, starting at 0.
|
|
||||||
* @public-api
|
|
||||||
*/
|
|
||||||
int getEyeIndex() {
|
|
||||||
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
|
|
||||||
return instance_index % CONFIG_STEREO_EYE_COUNT;
|
|
||||||
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
|
|
||||||
|
|
||||||
#if defined(TARGET_VULKAN_ENVIRONMENT)
|
|
||||||
return int(gl_ViewIndex);
|
|
||||||
#else
|
|
||||||
// gl_ViewID_OVR is of uint type, which needs an explicit conversion.
|
|
||||||
return int(gl_ViewID_OVR);
|
|
||||||
#endif // TARGET_VULKAN_ENVIRONMENT
|
|
||||||
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -661,6 +661,7 @@ class_<View>("View")
|
|||||||
.function("getViewport", &View::getViewport)
|
.function("getViewport", &View::getViewport)
|
||||||
.function("setVisibleLayers", &View::setVisibleLayers)
|
.function("setVisibleLayers", &View::setVisibleLayers)
|
||||||
.function("setPostProcessingEnabled", &View::setPostProcessingEnabled)
|
.function("setPostProcessingEnabled", &View::setPostProcessingEnabled)
|
||||||
|
.function("setDithering", &View::setDithering)
|
||||||
.function("_setAmbientOcclusionOptions", &View::setAmbientOcclusionOptions)
|
.function("_setAmbientOcclusionOptions", &View::setAmbientOcclusionOptions)
|
||||||
.function("_setDepthOfFieldOptions", &View::setDepthOfFieldOptions)
|
.function("_setDepthOfFieldOptions", &View::setDepthOfFieldOptions)
|
||||||
.function("_setMultiSampleAntiAliasingOptions", &View::setMultiSampleAntiAliasingOptions)
|
.function("_setMultiSampleAntiAliasingOptions", &View::setMultiSampleAntiAliasingOptions)
|
||||||
@@ -1391,8 +1392,14 @@ class_<MaterialInstance>("MaterialInstance")
|
|||||||
.function("isDoubleSided", &MaterialInstance::isDoubleSided)
|
.function("isDoubleSided", &MaterialInstance::isDoubleSided)
|
||||||
.function("setTransparencyMode", &MaterialInstance::setTransparencyMode)
|
.function("setTransparencyMode", &MaterialInstance::setTransparencyMode)
|
||||||
.function("getTransparencyMode", &MaterialInstance::getTransparencyMode)
|
.function("getTransparencyMode", &MaterialInstance::getTransparencyMode)
|
||||||
.function("setCullingMode", &MaterialInstance::setCullingMode)
|
.function("setCullingMode", EMBIND_LAMBDA(void,
|
||||||
|
(MaterialInstance* self, MaterialInstance::CullingMode mode), {
|
||||||
|
self->setCullingMode(mode); }), allow_raw_pointers())
|
||||||
|
.function("setCullingModeSeparate", EMBIND_LAMBDA(void,
|
||||||
|
(MaterialInstance* self, MaterialInstance::CullingMode color, MaterialInstance::CullingMode shadows), {
|
||||||
|
self->setCullingMode(color, shadows); }), allow_raw_pointers())
|
||||||
.function("getCullingMode", &MaterialInstance::getCullingMode)
|
.function("getCullingMode", &MaterialInstance::getCullingMode)
|
||||||
|
.function("getShadowCullingMode", &MaterialInstance::getShadowCullingMode)
|
||||||
.function("setColorWrite", &MaterialInstance::setColorWrite)
|
.function("setColorWrite", &MaterialInstance::setColorWrite)
|
||||||
.function("isColorWriteEnabled", &MaterialInstance::isColorWriteEnabled)
|
.function("isColorWriteEnabled", &MaterialInstance::isColorWriteEnabled)
|
||||||
.function("setDepthWrite", &MaterialInstance::setDepthWrite)
|
.function("setDepthWrite", &MaterialInstance::setDepthWrite)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "filament",
|
"name": "filament",
|
||||||
"version": "1.56.7",
|
"version": "1.57.0",
|
||||||
"description": "Real-time physically based rendering engine",
|
"description": "Real-time physically based rendering engine",
|
||||||
"main": "filament.js",
|
"main": "filament.js",
|
||||||
"module": "filament.js",
|
"module": "filament.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user