Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36c76daf34 |
@@ -7,3 +7,4 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
- vk: fix stage pool gc logic
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.56.5'
|
||||
implementation 'com.google.android.filament:filament-android:1.56.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.56.5'
|
||||
pod 'Filament', '~> 1.56.0'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,19 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.56.5
|
||||
|
||||
|
||||
## v1.56.4
|
||||
|
||||
|
||||
## v1.56.3
|
||||
|
||||
|
||||
## v1.56.2
|
||||
|
||||
- vk: fix stage pool gc logic
|
||||
|
||||
## v1.56.1
|
||||
|
||||
## v1.56.0
|
||||
|
||||
@@ -38,7 +38,7 @@ Java_com_google_android_filament_EntityManager_nCreateArray(JNIEnv* env, jclass,
|
||||
// (which it is), but still.
|
||||
em->create((size_t) n, reinterpret_cast<Entity *>(entities));
|
||||
|
||||
env->ReleaseIntArrayElements(entities_, entities, 0);
|
||||
env->ReleaseIntArrayElements(entities_, entities, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -167,7 +167,7 @@ Java_com_google_android_filament_IndirectLight_nGetDirectionEstimateStatic(JNIEn
|
||||
jfloat *outDirection = env->GetFloatArrayElements(outDirection_, NULL);
|
||||
*reinterpret_cast<filament::math::float3*>(outDirection) = IndirectLight::getDirectionEstimate((filament::math::float3*)sh);
|
||||
env->ReleaseFloatArrayElements(outDirection_, outDirection, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, JNI_ABORT);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
@@ -178,5 +178,5 @@ Java_com_google_android_filament_IndirectLight_nGetColorEstimateStatic(JNIEnv *e
|
||||
*reinterpret_cast<filament::math::float4*>(outColor) =
|
||||
IndirectLight::getColorEstimate((filament::math::float3*)sh, math::float3{x, y, z});
|
||||
env->ReleaseFloatArrayElements(outColor_, outColor, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, 0);
|
||||
env->ReleaseFloatArrayElements(sh_, sh, JNI_ABORT);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,13 @@ using namespace filament;
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
|
||||
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount, jint shadowQuality) {
|
||||
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
|
||||
Engine* engine = (Engine*) nativeEngine;
|
||||
AutoBuffer buffer(env, buffer_, size);
|
||||
auto builder = Material::Builder();
|
||||
if (shBandCount) {
|
||||
builder.sphericalHarmonicsBandCount(shBandCount);
|
||||
}
|
||||
builder.shadowSamplingQuality((Material::Builder::ShadowSamplingQuality)shadowQuality);
|
||||
Material* material = builder
|
||||
.package(buffer.getData(), buffer.getSize())
|
||||
.build(*engine);
|
||||
|
||||
@@ -344,18 +344,9 @@ public class Material {
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public enum ShadowSamplingQuality {
|
||||
/** 2x2 PCF */
|
||||
HARD,
|
||||
/** 3x3 gaussian filter */
|
||||
LOW,
|
||||
}
|
||||
|
||||
private Buffer mBuffer;
|
||||
private int mSize;
|
||||
private int mShBandCount = 0;
|
||||
private ShadowSamplingQuality mShadowSamplingQuality = ShadowSamplingQuality.LOW;
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the material data. The material data is a binary blob produced by
|
||||
@@ -387,18 +378,6 @@ public class Material {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the quality of shadow sampling. This is only taken into account
|
||||
* if this material is lit and in the surface domain.
|
||||
* @param quality
|
||||
* @return Reference to this Builder for chaining calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder shadowSamplingQuality(ShadowSamplingQuality quality) {
|
||||
mShadowSamplingQuality = quality;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the Material object.
|
||||
*
|
||||
@@ -411,7 +390,7 @@ public class Material {
|
||||
@NonNull
|
||||
public Material build(@NonNull Engine engine) {
|
||||
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
|
||||
mBuffer, mSize, mShBandCount, mShadowSamplingQuality.ordinal());
|
||||
mBuffer, mSize, mShBandCount);
|
||||
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
|
||||
return new Material(nativeMaterial);
|
||||
}
|
||||
@@ -1062,7 +1041,7 @@ public class Material {
|
||||
mNativeObject = 0;
|
||||
}
|
||||
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount, int shadowQuality);
|
||||
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
|
||||
private static native long nCreateInstance(long nativeMaterial);
|
||||
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
|
||||
private static native long nGetDefaultInstance(long nativeMaterial);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.56.5
|
||||
VERSION_NAME=1.56.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-11
@@ -1787,12 +1787,7 @@ non-shader data.
|
||||
declare a variable called <code>eyeDirection</code> you can access it in the fragment shader using
|
||||
<code>variable_eyeDirection</code>. In the vertex shader, the interpolant name is simply a member of
|
||||
the <code>MaterialVertexInputs</code> structure (<code>material.eyeDirection</code> in your example). Each
|
||||
interpolant is of type <code>float4</code> (<code>vec4</code>) in the shaders. By default the precision of the
|
||||
interpolant is <code>highp</code> in <em class="asterisk">both</em> the vertex and fragment shaders.
|
||||
An alternate syntax can be used to specify both the name and precision of the interpolant.
|
||||
In this case the specified precision is used as-is in both fragment and vertex stages, in
|
||||
particular if <code>default</code> is specified the default precision is used is the fragment shader
|
||||
(<code>mediump</code>) and in the vertex shader (<code>highp</code>).
|
||||
interpolant is of type <code>float4</code> (<code>vec4</code>) in the shaders.
|
||||
|
||||
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
|
||||
<span class="line"> name : Skybox,</span>
|
||||
@@ -1803,11 +1798,7 @@ non-shader data.
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> ],</span>
|
||||
<span class="line"> variables : [</span>
|
||||
<span class="line"> eyeDirection,</span>
|
||||
<span class="line"> {</span>
|
||||
<span class="line"> name : eyeColor,</span>
|
||||
<span class="line"> precision : medium</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> eyeDirection</span>
|
||||
<span class="line"> ],</span>
|
||||
<span class="line"> vertexDomain : device,</span>
|
||||
<span class="line"> depthWrite : <span class="hljs-literal">false</span>,</span>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -226,12 +226,10 @@ if (FILAMENT_SUPPORTS_VULKAN)
|
||||
src/vulkan/VulkanUtility.cpp
|
||||
src/vulkan/VulkanUtility.h
|
||||
)
|
||||
if (LINUX OR WIN32)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp)
|
||||
if (ANDROID OR LINUX OR WIN32)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroidLinuxWindows.cpp)
|
||||
elseif (APPLE OR IOS)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformApple.mm)
|
||||
elseif (ANDROID)
|
||||
list(APPEND SRCS src/vulkan/platform/VulkanPlatformAndroid.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -292,64 +292,8 @@ public:
|
||||
*/
|
||||
VkQueue getProtectedGraphicsQueue() const noexcept;
|
||||
|
||||
struct ExternalImageMetadata {
|
||||
/**
|
||||
* The width of the external image
|
||||
*/
|
||||
uint32_t width;
|
||||
|
||||
/**
|
||||
* The height of the external image
|
||||
*/
|
||||
uint32_t height;
|
||||
|
||||
/**
|
||||
* The layer count of the external image
|
||||
*/
|
||||
uint32_t layers;
|
||||
|
||||
/**
|
||||
* The format of the external image
|
||||
*/
|
||||
VkFormat format;
|
||||
|
||||
/**
|
||||
* An external buffer can be protected. This tells you if it is.
|
||||
*/
|
||||
bool isProtected;
|
||||
|
||||
/**
|
||||
* The type of external format (opaque int) if used.
|
||||
*/
|
||||
uint64_t externalFormat;
|
||||
|
||||
/**
|
||||
* Image usage
|
||||
*/
|
||||
VkImageUsageFlags usage;
|
||||
|
||||
/**
|
||||
* Allocation size
|
||||
*/
|
||||
VkDeviceSize allocationSize;
|
||||
|
||||
/**
|
||||
* Heap information
|
||||
*/
|
||||
uint32_t memoryTypeBits;
|
||||
};
|
||||
virtual ExternalImageMetadata getExternalImageMetadata(void* externalImage);
|
||||
|
||||
using ImageData = std::pair<VkImage, VkDeviceMemory>;
|
||||
virtual ImageData createExternalImage(void* externalImage,
|
||||
const ExternalImageMetadata& metadata);
|
||||
|
||||
private:
|
||||
static ExtensionSet getSwapchainInstanceExtensions();
|
||||
static ExternalImageMetadata getExternalImageMetadataImpl(void* externalImage,
|
||||
VkDevice device);
|
||||
static ImageData createExternalImageImpl(void* externalImage, VkDevice device,
|
||||
const VkAllocationCallbacks* allocator, const ExternalImageMetadata& metadata);
|
||||
|
||||
// Platform dependent helper methods
|
||||
using SurfaceBundle = std::tuple<VkSurfaceKHR, VkExtent2D>;
|
||||
|
||||
@@ -135,7 +135,6 @@ struct MetalContext {
|
||||
bool supportsTextureSwizzling = false;
|
||||
bool supportsAutoDepthResolve = false;
|
||||
bool supportsMemorylessRenderTargets = false;
|
||||
bool supportsDepthClamp = false;
|
||||
uint8_t maxColorRenderTargets = 4;
|
||||
struct {
|
||||
uint8_t common;
|
||||
|
||||
@@ -151,11 +151,6 @@ MetalDriver::MetalDriver(
|
||||
mContext->highestSupportedGpuFamily.mac >= 2; // newer macOS GPUs
|
||||
}
|
||||
|
||||
mContext->supportsDepthClamp = false;
|
||||
if (@available(macOS 10.11, iOS 11.0, *)) {
|
||||
mContext->supportsDepthClamp = true;
|
||||
}
|
||||
|
||||
// In order to support resolve store action on depth attachment, the GPU needs to support it.
|
||||
// Note that support for depth resolve implies support for stencil resolve using .sample0 resolve filter.
|
||||
// (Other resolve filters are supported starting .apple5 and .mac2 families).
|
||||
@@ -1068,7 +1063,7 @@ bool MetalDriver::isProtectedTexturesSupported() {
|
||||
}
|
||||
|
||||
bool MetalDriver::isDepthClampSupported() {
|
||||
return mContext->supportsDepthClamp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetalDriver::isWorkaroundNeeded(Workaround workaround) {
|
||||
@@ -1263,7 +1258,6 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->cullModeState.invalidate();
|
||||
mContext->windingState.invalidate();
|
||||
mContext->scissorRectState.invalidate();
|
||||
mContext->depthClampState.invalidate();
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedDescriptorSets.clear();
|
||||
@@ -1735,12 +1729,10 @@ void MetalDriver::bindPipeline(PipelineState const& ps) {
|
||||
}
|
||||
|
||||
// depth clip mode
|
||||
if (mContext->supportsDepthClamp) {
|
||||
MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
|
||||
mContext->depthClampState.updateState(depthClipMode);
|
||||
if (mContext->depthClampState.stateChanged()) {
|
||||
[mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode];
|
||||
}
|
||||
MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip;
|
||||
mContext->depthClampState.updateState(depthClipMode);
|
||||
if (mContext->depthClampState.stateChanged()) {
|
||||
[mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode];
|
||||
}
|
||||
|
||||
// Set the depth-stencil state, if a state change is needed.
|
||||
|
||||
@@ -226,11 +226,9 @@ MetalShaderCompiler::program_token_t MetalShaderCompiler::createProgram(
|
||||
CompilerPriorityQueue const priorityQueue = program.getPriorityQueue();
|
||||
mCompilerThreadPool.queue(priorityQueue, token,
|
||||
[this, name, device = mDevice, program = std::move(program), token]() {
|
||||
@autoreleasepool {
|
||||
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||
token->set(compiledProgram);
|
||||
mCallbackManager.put(token->handle);
|
||||
}
|
||||
MetalFunctionBundle compiledProgram = compileProgram(program, device);
|
||||
token->set(compiledProgram);
|
||||
mCallbackManager.put(token->handle);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
@@ -500,13 +500,11 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
|
||||
// qualcomm seems to have no problem with this (which is good for us)
|
||||
bugs->allow_read_only_ancillary_feedback_loop = true;
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// Older Adreno devices that support ES3.0 only tend to be extremely buggy, so we
|
||||
// fall back to ES2.0.
|
||||
if (major == 3 && minor == 0) {
|
||||
bugs->force_feature_level0 = true;
|
||||
}
|
||||
#endif
|
||||
} else if (strstr(renderer, "Mali")) {
|
||||
// ARM GPU
|
||||
bugs->vao_doesnt_store_element_array_buffer_binding = true;
|
||||
|
||||
@@ -64,14 +64,10 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mLib) {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
}
|
||||
FILAMENT_CHECK_PRECONDITION(mLib)
|
||||
<< "Unable to dlopen libOSMesa to create a software GL context";
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(OSMesaGetProcAddress)
|
||||
<< "Unable to against libOSMesa to create a software GL context";
|
||||
OSMesaGetProcAddress = (GetProcAddressFunc) dlsym(mLib, "OSMesaGetProcAddress");
|
||||
|
||||
OSMesaCreateContext = (CreateContextFunc) OSMesaGetProcAddress("OSMesaCreateContext");
|
||||
OSMesaDestroyContext =
|
||||
@@ -80,9 +76,7 @@ public:
|
||||
}
|
||||
|
||||
~OSMesaAPI() {
|
||||
if (mLib) {
|
||||
dlclose(mLib);
|
||||
}
|
||||
dlclose(mLib);
|
||||
}
|
||||
private:
|
||||
void* mLib = nullptr;
|
||||
|
||||
@@ -544,25 +544,7 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::TextureFormat format,
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) {
|
||||
FVK_SYSTRACE_SCOPE();
|
||||
|
||||
const auto& metadata = mPlatform->getExternalImageMetadata(externalImage);
|
||||
if (metadata.isProtected) {
|
||||
usage |= backend::TextureUsage::PROTECTED;
|
||||
}
|
||||
|
||||
assert_invariant(width == metadata.width);
|
||||
assert_invariant(height == metadata.height);
|
||||
assert_invariant(getVkFormat(format) == metadata.format);
|
||||
|
||||
const auto& data = mPlatform->createExternalImage(externalImage, metadata);
|
||||
|
||||
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
|
||||
mAllocator, &mResourceManager, &mCommands, data.first, data.second, metadata.format,
|
||||
1, metadata.width, metadata.height, usage, mStagePool);
|
||||
|
||||
texture.inc();
|
||||
uint32_t width, uint32_t height, backend::TextureUsage usage, void* image) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
|
||||
@@ -1190,7 +1172,6 @@ TimerQueryResult VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint
|
||||
}
|
||||
|
||||
void VulkanDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
||||
|
||||
}
|
||||
|
||||
void VulkanDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
||||
|
||||
@@ -75,16 +75,15 @@ void VulkanSwapChain::update() {
|
||||
}
|
||||
for (auto const color: bundle.colors) {
|
||||
auto colorTexture = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager,
|
||||
device, mAllocator, mResourceManager, mCommands, color, VK_NULL_HANDLE,
|
||||
bundle.colorFormat, 1, bundle.extent.width, bundle.extent.height, colorUsage,
|
||||
device, mAllocator, mResourceManager, mCommands, color, bundle.colorFormat, 1,
|
||||
bundle.extent.width, bundle.extent.height, TextureUsage::COLOR_ATTACHMENT,
|
||||
mStagePool);
|
||||
mColors.push_back(colorTexture);
|
||||
}
|
||||
|
||||
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device,
|
||||
mAllocator, mResourceManager, mCommands, bundle.depth, VK_NULL_HANDLE,
|
||||
bundle.depthFormat, 1, bundle.extent.width, bundle.extent.height, depthUsage,
|
||||
mStagePool);
|
||||
mDepth = fvkmemory::resource_ptr<VulkanTexture>::construct(mResourceManager, device, mAllocator,
|
||||
mResourceManager, mCommands, bundle.depth, bundle.depthFormat, 1, bundle.extent.width,
|
||||
bundle.extent.height, TextureUsage::DEPTH_ATTACHMENT, mStagePool);
|
||||
|
||||
mExtent = bundle.extent;
|
||||
}
|
||||
|
||||
@@ -164,15 +164,14 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator,
|
||||
// Constructor for internally passed VkImage
|
||||
VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width,
|
||||
uint32_t height, TextureUsage tusage, VulkanStagePool& stagePool)
|
||||
VkFormat format, uint8_t samples, uint32_t width, uint32_t height, TextureUsage tusage,
|
||||
VulkanStagePool& stagePool)
|
||||
: HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED,
|
||||
tusage),
|
||||
mState(fvkmemory::resource_ptr<VulkanTextureState>::construct(resourceManager, device,
|
||||
allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D),
|
||||
1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) {
|
||||
mState->mTextureImage = image;
|
||||
mState->mTextureImageMemory = memory;
|
||||
mPrimaryViewRange = mState->mFullViewRange;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
||||
// The texture will never destroy the given VkImage, but it does manages its subresources.
|
||||
VulkanTexture(VkDevice device, VmaAllocator allocator,
|
||||
fvkmemory::ResourceManager* resourceManager, VulkanCommands* commands, VkImage image,
|
||||
VkDeviceMemory memory, VkFormat format, uint8_t samples, uint32_t width, uint32_t height,
|
||||
TextureUsage tusage, VulkanStagePool& stagePool);
|
||||
VkFormat format, uint8_t samples, uint32_t width, uint32_t height, TextureUsage tusage,
|
||||
VulkanStagePool& stagePool);
|
||||
|
||||
// Constructor for creating a texture view for wrt specific mip range
|
||||
VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, VulkanContext const& context,
|
||||
|
||||
@@ -66,8 +66,7 @@ struct Resource {
|
||||
: resManager(nullptr),
|
||||
id(HandleBase::nullid),
|
||||
mCount(0),
|
||||
restype(ResourceType::UNDEFINED_TYPE),
|
||||
mHandleConsideredDestroyed(false) {}
|
||||
restype(ResourceType::UNDEFINED_TYPE) {}
|
||||
|
||||
private:
|
||||
inline void inc() noexcept {
|
||||
@@ -81,16 +80,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// To be able to detect use-after-free, we need a bit to signify if the handle should be
|
||||
// consider destroyed (from Filament's perspective).
|
||||
inline void setHandleConsiderDestroyed() noexcept {
|
||||
mHandleConsideredDestroyed = true;
|
||||
}
|
||||
|
||||
inline bool isHandleConsideredDestroyed() const {
|
||||
return mHandleConsideredDestroyed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void init(HandleId id, ResourceManager* resManager) {
|
||||
this->id = id;
|
||||
@@ -103,9 +92,7 @@ private:
|
||||
ResourceManager* resManager; // 8
|
||||
HandleId id; // 4
|
||||
uint32_t mCount : 24;
|
||||
ResourceType restype : 7;
|
||||
bool mHandleConsideredDestroyed : 1; // restype + mCount + mHandleConsideredDestroyed
|
||||
// is 4 bytes.
|
||||
ResourceType restype : 6; // restype + mCount is 4 bytes.
|
||||
|
||||
friend class ResourceManager;
|
||||
|
||||
@@ -118,8 +105,7 @@ struct ThreadSafeResource {
|
||||
: resManager(nullptr),
|
||||
id(HandleBase::nullid),
|
||||
mCount(0),
|
||||
restype(ResourceType::UNDEFINED_TYPE),
|
||||
mHandleConsideredDestroyed(false) {}
|
||||
restype(ResourceType::UNDEFINED_TYPE) {}
|
||||
|
||||
private:
|
||||
inline void inc() noexcept {
|
||||
@@ -132,16 +118,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// To be able to detect use-after-free, we need a bit to signify if the handle should be
|
||||
// consider destroyed (from Filament's perspective).
|
||||
inline void setHandleConsiderDestroyed() noexcept {
|
||||
mHandleConsideredDestroyed = true;
|
||||
}
|
||||
|
||||
inline bool isHandleConsideredDestroyed() const {
|
||||
return mHandleConsideredDestroyed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void init(HandleId id, ResourceManager* resManager) {
|
||||
this->id = id;
|
||||
@@ -154,8 +130,7 @@ private:
|
||||
ResourceManager* resManager; // 8
|
||||
HandleId id; // 4
|
||||
std::atomic<uint32_t> mCount; // 4
|
||||
ResourceType restype : 7;
|
||||
bool mHandleConsideredDestroyed : 1; // restype + mHandleConsideredDestroyed is 1 byte
|
||||
ResourceType restype; // 1
|
||||
|
||||
friend class ResourceManager;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "vulkan/memory/ResourceManager.h"
|
||||
|
||||
#include <backend/Handle.h>
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -60,10 +59,6 @@ public:
|
||||
static enabled_resource_ptr<B> cast(ResourceManager* resManager,
|
||||
Handle<B> const& handle) noexcept {
|
||||
D* ptr = resManager->handle_cast<D*, B>(handle);
|
||||
FILAMENT_CHECK_PRECONDITION(!ptr->isHandleConsideredDestroyed())
|
||||
<< "Handle id=" << ptr->id << " (" << getTypeStr(ptr->restype)
|
||||
<< ") is being used after it has been freed";
|
||||
|
||||
return {ptr};
|
||||
}
|
||||
|
||||
@@ -161,8 +156,6 @@ private:
|
||||
// only be used from VulkanDriver.
|
||||
inline void dec() {
|
||||
assert_invariant(mRef);
|
||||
assert_invariant(!mRef->isHandleConsideredDestroyed());
|
||||
mRef->setHandleConsiderDestroyed();
|
||||
mRef->dec();
|
||||
}
|
||||
|
||||
|
||||
@@ -194,15 +194,6 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
||||
#endif
|
||||
// We only support external image for Android for now, but nothing bars us from
|
||||
// supporting other platforms.
|
||||
#if defined(__ANDROID__)
|
||||
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
|
||||
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
|
||||
VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
|
||||
VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
|
||||
#endif
|
||||
|
||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE2_EXTENSION_NAME,
|
||||
@@ -954,16 +945,6 @@ VkQueue VulkanPlatform::getProtectedGraphicsQueue() const noexcept {
|
||||
return mImpl->mProtectedGraphicsQueue;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadata(
|
||||
void* externalImage) {
|
||||
return getExternalImageMetadataImpl(externalImage, mImpl->mDevice);
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImage(void* externalImage,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return createExternalImageImpl(externalImage, mImpl->mDevice, nullptr, metadata);
|
||||
}
|
||||
|
||||
#undef SWAPCHAIN_RET_FUNC
|
||||
|
||||
}// namespace filament::backend
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <backend/platforms/VulkanPlatform.h>
|
||||
|
||||
#include "vulkan/VulkanConstants.h"
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <bluevk/BlueVK.h>
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
#include <android/native_window.h>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
namespace {
|
||||
void getVKFormatAndUsage(const AHardwareBuffer_Desc& desc, VkFormat& format,
|
||||
VkImageUsageFlags& usage, bool& isProtected) {
|
||||
// Refer to "11.2.17. External Memory Handle Types" in the spec, and
|
||||
// Tables 13/14 for how the following derivation works.
|
||||
bool isDepthFormat = false;
|
||||
isProtected = false;
|
||||
switch (desc.format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
||||
format = VK_FORMAT_R8G8B8_UNORM;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
|
||||
format = VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
|
||||
format = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
|
||||
format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_D16_UNORM;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_X8_D24_UNORM_PACK32;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_D32_SFLOAT;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
break;
|
||||
case AHARDWAREBUFFER_FORMAT_S8_UINT:
|
||||
isDepthFormat = true;
|
||||
format = VK_FORMAT_S8_UINT;
|
||||
break;
|
||||
default:
|
||||
format = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
// The following only concern usage flags derived from Table 14.
|
||||
usage = 0;
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||
usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
}
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
|
||||
if (isDepthFormat) {
|
||||
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
} else {
|
||||
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
}
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
|
||||
usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
if (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
|
||||
isProtected = true;
|
||||
}
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData allocateExternalImage(void* externalBuffer,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
VulkanPlatform::ExternalImageMetadata const& metadata) {
|
||||
VulkanPlatform::ImageData data;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalBuffer);
|
||||
|
||||
// if external format we need to specifiy it in the allocation
|
||||
const bool useExternalFormat = metadata.format == VK_FORMAT_UNDEFINED;
|
||||
|
||||
const VkExternalFormatANDROID externalFormat = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.externalFormat = metadata
|
||||
.externalFormat,// pass down the format (external means we don't have it VK defined)
|
||||
};
|
||||
const VkExternalMemoryImageCreateInfo externalCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
|
||||
.pNext = useExternalFormat ? &externalFormat : nullptr,
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
||||
};
|
||||
|
||||
VkImageCreateInfo imageInfo{.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
|
||||
imageInfo.pNext = &externalCreateInfo;
|
||||
imageInfo.format = metadata.format;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent = {
|
||||
metadata.width,
|
||||
metadata.height,
|
||||
1u,
|
||||
};
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = metadata.layers;
|
||||
imageInfo.usage = metadata.usage;
|
||||
// In the unprotected case add R/W capabilities
|
||||
if (metadata.isProtected == false)
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
VkResult result = vkCreateImage(device, &imageInfo, allocator, &data.first);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkCreateImage failed with error=" << result;
|
||||
|
||||
// Allocate the memory
|
||||
VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.buffer = buffer,
|
||||
};
|
||||
VkMemoryDedicatedAllocateInfo memoryDedicatedAllocateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
||||
.pNext = &androidHardwareBufferInfo,
|
||||
.image = data.first,
|
||||
.buffer = VK_NULL_HANDLE,
|
||||
};
|
||||
VkMemoryAllocateInfo allocInfo = {.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &memoryDedicatedAllocateInfo,
|
||||
.allocationSize = metadata.allocationSize,
|
||||
.memoryTypeIndex = metadata.memoryTypeBits};
|
||||
result = vkAllocateMemory(device, &allocInfo, allocator, &data.second);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkAllocateMemory failed with error=" << result;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}// namespace
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(void* externalImage,
|
||||
VkDevice device) {
|
||||
ExternalImageMetadata metadata;
|
||||
AHardwareBuffer* buffer = static_cast<AHardwareBuffer*>(externalImage);
|
||||
if (__builtin_available(android 26, *)) {
|
||||
AHardwareBuffer_Desc bufferDesc;
|
||||
AHardwareBuffer_describe(buffer, &bufferDesc);
|
||||
metadata.width = bufferDesc.width;
|
||||
metadata.height = bufferDesc.height;
|
||||
metadata.layers = bufferDesc.layers;
|
||||
|
||||
getVKFormatAndUsage(bufferDesc, metadata.format, metadata.usage, metadata.isProtected);
|
||||
}
|
||||
// In the unprotected case add R/W capabilities
|
||||
if (metadata.isProtected == false) {
|
||||
metadata.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
VkAndroidHardwareBufferFormatPropertiesANDROID formatInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID,
|
||||
.pNext = nullptr,
|
||||
};
|
||||
VkAndroidHardwareBufferPropertiesANDROID properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||
.pNext = &formatInfo,
|
||||
};
|
||||
VkResult result = vkGetAndroidHardwareBufferPropertiesANDROID(device, buffer, &properties);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkGetAndroidHardwareBufferProperties failed with error=" << result;
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format);
|
||||
metadata.externalFormat = formatInfo.externalFormat;
|
||||
metadata.allocationSize = properties.allocationSize;
|
||||
metadata.memoryTypeBits = properties.memoryTypeBits;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
ImageData data = allocateExternalImage(externalImage, device, allocator, metadata);
|
||||
VkResult result = vkBindImageMemory(device, data.first, data.second, 0);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkBindImageMemory error=" << result << ".";
|
||||
return data;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
return {
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
}
|
||||
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) noexcept {
|
||||
VkSurfaceKHR surface;
|
||||
VkExtent2D extent;
|
||||
|
||||
VkAndroidSurfaceCreateInfoKHR const createInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
|
||||
.window = (ANativeWindow*) nativeWindow,
|
||||
};
|
||||
VkResult const result =
|
||||
vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC, (VkSurfaceKHR*) &surface);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkCreateAndroidSurfaceKHR with error=" << result;
|
||||
return {surface, extent};
|
||||
}
|
||||
}
|
||||
+15
-14
@@ -34,7 +34,9 @@
|
||||
#endif
|
||||
|
||||
// Platform specific includes and defines
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/native_window.h>
|
||||
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#include <dlfcn.h>
|
||||
namespace {
|
||||
typedef struct _wl {
|
||||
@@ -84,20 +86,11 @@ using namespace bluevk;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
void* externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
VulkanPlatform::ExtensionSet const ret = {
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined(__ANDROID__)
|
||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
|
||||
#elif defined(LINUX_OR_FREEBSD) && defined(FILAMENT_SUPPORTS_X11)
|
||||
#if defined(FILAMENT_SUPPORTS_XCB)
|
||||
@@ -123,7 +116,15 @@ VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWin
|
||||
// swap chain extent.
|
||||
VkExtent2D extent;
|
||||
|
||||
#if defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
#if defined(__ANDROID__)
|
||||
VkAndroidSurfaceCreateInfoKHR const createInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
|
||||
.window = (ANativeWindow*) nativeWindow,
|
||||
};
|
||||
VkResult const result = vkCreateAndroidSurfaceKHR(instance, &createInfo, VKALLOC,
|
||||
(VkSurfaceKHR*) &surface);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateAndroidSurfaceKHR error.";
|
||||
#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND)
|
||||
wl* ptrval = reinterpret_cast<wl*>(nativeWindow);
|
||||
extent.width = ptrval->width;
|
||||
extent.height = ptrval->height;
|
||||
@@ -63,17 +63,6 @@ VulkanPlatform::ExtensionSet VulkanPlatform::getSwapchainInstanceExtensions() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataImpl(
|
||||
void* externalImage, VkDevice device) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::ImageData VulkanPlatform::createExternalImageImpl(void* externalImage,
|
||||
VkDevice device, const VkAllocationCallbacks* allocator,
|
||||
const ExternalImageMetadata& metadata) {
|
||||
return {};
|
||||
}
|
||||
|
||||
VulkanPlatform::SurfaceBundle VulkanPlatform::createVkSurfaceKHR(void* nativeWindow,
|
||||
VkInstance instance, uint64_t flags) noexcept {
|
||||
VkSurfaceKHR surface;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace filament {
|
||||
* filament::Camera* myCamera = engine->createCamera(myCameraEntity);
|
||||
* myCamera->setProjection(45, 16.0/9.0, 0.1, 1.0);
|
||||
* myCamera->lookAt({0, 1.60, 1}, {0, 0, 0});
|
||||
* engine->destroyCameraComponent(myCameraEntity);
|
||||
* engine->destroyCameraComponent(myCamera);
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
*
|
||||
|
||||
@@ -103,11 +103,6 @@ public:
|
||||
Builder& operator=(Builder const& rhs) noexcept;
|
||||
Builder& operator=(Builder&& rhs) noexcept;
|
||||
|
||||
enum class ShadowSamplingQuality : uint8_t {
|
||||
HARD, // 2x2 PCF
|
||||
LOW // 3x3 gaussian filter
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies the material data. The material data is a binary blob produced by
|
||||
* libfilamat or by matc.
|
||||
@@ -157,14 +152,6 @@ public:
|
||||
*/
|
||||
Builder& sphericalHarmonicsBandCount(size_t shBandCount) noexcept;
|
||||
|
||||
/**
|
||||
* Set the quality of shadow sampling. This is only taken into account
|
||||
* if this material is lit and in the surface domain.
|
||||
* @param quality
|
||||
* @return
|
||||
*/
|
||||
Builder& shadowSamplingQuality(ShadowSamplingQuality quality) noexcept;
|
||||
|
||||
/**
|
||||
* Creates the Material object and returns a pointer to it.
|
||||
*
|
||||
|
||||
+15
-38
@@ -864,44 +864,21 @@ backend::Viewport RenderPass::Executor::applyScissorViewport(
|
||||
backend::Viewport const& scissorViewport, backend::Viewport const& scissor) noexcept {
|
||||
// scissor is set, we need to apply the offset/clip
|
||||
// clang vectorizes this!
|
||||
constexpr int64_t maxvali = std::numeric_limits<int32_t>::max();
|
||||
|
||||
// we do all the offsetting/clipping math in 64 bits below to avoid overflows
|
||||
struct {
|
||||
int64_t l;
|
||||
int64_t b;
|
||||
int64_t r;
|
||||
int64_t t;
|
||||
} svp, s;
|
||||
|
||||
// convert scissorViewport to {left,bottom,right,top} format
|
||||
svp.l = scissorViewport.left;
|
||||
svp.b = scissorViewport.bottom;
|
||||
svp.r = svp.l + scissorViewport.width;
|
||||
svp.t = svp.b + scissorViewport.height;
|
||||
|
||||
// convert scissor to {left,bottom,right,top} format and offset by scissorViewport's left,bottom
|
||||
s.l = svp.l + scissor.left;
|
||||
s.b = svp.b + scissor.bottom;
|
||||
s.r = s.l + scissor.width;
|
||||
s.t = s.b + scissor.height;
|
||||
|
||||
// clip to the scissorViewport
|
||||
s.l = std::max(s.l, svp.l);
|
||||
s.b = std::max(s.b, svp.b);
|
||||
s.r = std::min(s.r, svp.r);
|
||||
s.t = std::min(s.t, svp.t);
|
||||
|
||||
// clip to positive int32_t
|
||||
s.l = std::max(s.l, int64_t(0));
|
||||
s.b = std::max(s.b, int64_t(0));
|
||||
s.r = std::min(s.r, maxvali);
|
||||
s.t = std::min(s.t, maxvali);
|
||||
|
||||
assert_invariant(s.r >= s.l && s.t >= s.b);
|
||||
|
||||
// convert back to Viewport format
|
||||
return { int32_t(s.l), int32_t(s.b), uint32_t(s.r - s.l), uint32_t(s.t - s.b) };
|
||||
constexpr int32_t maxvali = std::numeric_limits<int32_t>::max();
|
||||
// compute new left/bottom, assume no overflow
|
||||
int32_t const l = scissor.left + scissorViewport.left;
|
||||
int32_t const b = scissor.bottom + scissorViewport.bottom;
|
||||
// compute right/top without overflowing, scissor.width/height guaranteed
|
||||
// to convert to int32
|
||||
int32_t r = (l > maxvali - int32_t(scissor.width)) ? maxvali : l + int32_t(scissor.width);
|
||||
int32_t t = (b > maxvali - int32_t(scissor.height)) ? maxvali : b + int32_t(scissor.height);
|
||||
// clip to the viewport
|
||||
assert_invariant(l == std::max(l, scissorViewport.left));
|
||||
assert_invariant(b == std::max(b, scissorViewport.bottom));
|
||||
r = std::min(r, scissorViewport.left + int32_t(scissorViewport.width));
|
||||
t = std::min(t, scissorViewport.bottom + int32_t(scissorViewport.height));
|
||||
assert_invariant(r >= l && t >= b);
|
||||
return { l, b, uint32_t(r - l), uint32_t(t - b) };
|
||||
}
|
||||
|
||||
UTILS_NOINLINE // no need to be inlined
|
||||
|
||||
@@ -427,7 +427,7 @@ float FLightManager::getSpotLightInnerCone(Instance i) const noexcept {
|
||||
|
||||
void LightManager::ShadowCascades::computeUniformSplits(float splitPositions[3], uint8_t cascades) {
|
||||
size_t s = 0;
|
||||
cascades = min(cascades, (uint8_t) 4u);
|
||||
cascades = max(cascades, (uint8_t) 4u);
|
||||
for (size_t c = 1; c < cascades; c++) {
|
||||
splitPositions[s++] = float(c) / float(cascades);
|
||||
}
|
||||
@@ -436,7 +436,7 @@ void LightManager::ShadowCascades::computeUniformSplits(float splitPositions[3],
|
||||
void LightManager::ShadowCascades::computeLogSplits(float splitPositions[3], uint8_t cascades,
|
||||
float near, float far) {
|
||||
size_t s = 0;
|
||||
cascades = min(cascades, (uint8_t) 4u);
|
||||
cascades = max(cascades, (uint8_t) 4u);
|
||||
for (size_t c = 1; c < cascades; c++) {
|
||||
splitPositions[s++] =
|
||||
(near * std::pow(far / near, float(c) / float(cascades)) - near) / (far - near);
|
||||
@@ -447,7 +447,7 @@ void LightManager::ShadowCascades::computePracticalSplits(float splitPositions[3
|
||||
float near, float far, float lambda) {
|
||||
float uniformSplits[3];
|
||||
float logSplits[3];
|
||||
cascades = min(cascades, (uint8_t) 4u);
|
||||
cascades = max(cascades, (uint8_t) 4u);
|
||||
computeUniformSplits(uniformSplits, cascades);
|
||||
computeLogSplits(logSplits, cascades, near, far);
|
||||
size_t s = 0;
|
||||
|
||||
@@ -529,31 +529,19 @@ void FEngine::shutdown() {
|
||||
mPerViewDescriptorSetLayoutSsrVariant.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
mPerRenderableDescriptorSetLayout.terminate(mHwDescriptorSetLayoutFactory, driver);
|
||||
|
||||
driver.destroyRenderPrimitive(std::move(mFullScreenTriangleRph));
|
||||
driver.destroyRenderPrimitive(mFullScreenTriangleRph);
|
||||
|
||||
destroy(mFullScreenTriangleIb);
|
||||
mFullScreenTriangleIb = nullptr;
|
||||
|
||||
destroy(mFullScreenTriangleVb);
|
||||
mFullScreenTriangleVb = nullptr;
|
||||
|
||||
destroy(mDummyMorphTargetBuffer);
|
||||
mDummyMorphTargetBuffer = nullptr;
|
||||
|
||||
destroy(mDefaultIblTexture);
|
||||
mDefaultIblTexture = nullptr;
|
||||
|
||||
destroy(mDefaultIbl);
|
||||
mDefaultIbl = nullptr;
|
||||
|
||||
destroy(mDefaultColorGrading);
|
||||
mDefaultColorGrading = nullptr;
|
||||
|
||||
destroy(mDefaultMaterial);
|
||||
mDefaultMaterial = nullptr;
|
||||
|
||||
destroy(mUnprotectedDummySwapchain);
|
||||
mUnprotectedDummySwapchain = nullptr;
|
||||
|
||||
/*
|
||||
* clean-up after the user -- we call terminate on each "leaked" object and clear each list.
|
||||
@@ -570,7 +558,6 @@ void FEngine::shutdown() {
|
||||
|
||||
// this must be done after Skyboxes and before materials
|
||||
destroy(mSkyboxMaterial);
|
||||
mSkyboxMaterial = nullptr;
|
||||
|
||||
cleanupResourceList(std::move(mBufferObjects));
|
||||
cleanupResourceList(std::move(mIndexBuffers));
|
||||
@@ -587,12 +574,12 @@ void FEngine::shutdown() {
|
||||
|
||||
cleanupResourceListLocked(mFenceListLock, std::move(mFences));
|
||||
|
||||
driver.destroyTexture(std::move(mDummyOneTexture));
|
||||
driver.destroyTexture(std::move(mDummyOneTextureArray));
|
||||
driver.destroyTexture(std::move(mDummyZeroTexture));
|
||||
driver.destroyTexture(std::move(mDummyZeroTextureArray));
|
||||
driver.destroyTexture(mDummyOneTexture);
|
||||
driver.destroyTexture(mDummyOneTextureArray);
|
||||
driver.destroyTexture(mDummyZeroTexture);
|
||||
driver.destroyTexture(mDummyZeroTextureArray);
|
||||
|
||||
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
|
||||
driver.destroyRenderTarget(mDefaultRenderTarget);
|
||||
|
||||
/*
|
||||
* Shutdown the backend...
|
||||
@@ -1159,13 +1146,8 @@ bool FEngine::destroy(const FMaterial* ptr) {
|
||||
if (!ASSERT_PRECONDITION_NON_FATAL(pos->second.empty(),
|
||||
"destroying material \"%s\" but %u instances still alive",
|
||||
ptr->getName().c_str(), (*pos).second.size())) {
|
||||
// We return true here, because the material has been destroyed. However, this
|
||||
// leaks this material's ResourceList<FMaterialInstance> until the engine
|
||||
// is shut down. Note that it's still possible for the MaterialInstances to be
|
||||
// destroyed manually.
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
mMaterialInstances.erase(pos);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -123,7 +123,6 @@ struct Material::BuilderDetails {
|
||||
size_t mSize = 0;
|
||||
bool mDefaultMaterial = false;
|
||||
int32_t mShBandsCount = 3;
|
||||
Builder::ShadowSamplingQuality mShadowSamplingQuality = Builder::ShadowSamplingQuality::LOW;
|
||||
std::unordered_map<
|
||||
utils::CString,
|
||||
std::variant<int32_t, float, bool>,
|
||||
@@ -153,11 +152,6 @@ Material::Builder& Material::Builder::sphericalHarmonicsBandCount(size_t shBandC
|
||||
return *this;
|
||||
}
|
||||
|
||||
Material::Builder& Material::Builder::shadowSamplingQuality(ShadowSamplingQuality quality) noexcept {
|
||||
mImpl->mShadowSamplingQuality = quality;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
Material::Builder& Material::Builder::constant(const char* name, size_t nameLength, T value) {
|
||||
FILAMENT_CHECK_PRECONDITION(name != nullptr) << "name cannot be null";
|
||||
@@ -327,7 +321,11 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
parser->getSpecularAntiAliasingThreshold(&mSpecularAntiAliasingThreshold);
|
||||
}
|
||||
|
||||
parser->hasCustomDepthShader(&mHasCustomDepthShader);
|
||||
processBlendingMode(parser);
|
||||
processSpecializationConstants(engine, builder, parser);
|
||||
processPushConstants(engine, parser);
|
||||
processDepthVariants(engine, parser);
|
||||
processDescriptorSets(engine, parser);
|
||||
|
||||
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(
|
||||
mIsVariantLit,
|
||||
@@ -335,12 +333,6 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
mRefractionMode == RefractionMode::SCREEN_SPACE,
|
||||
!(mVariantFilterMask & +UserVariantFilterBit::FOG));
|
||||
|
||||
processBlendingMode(parser);
|
||||
processSpecializationConstants(engine, builder, parser);
|
||||
processPushConstants(engine, parser);
|
||||
processDescriptorSets(engine, parser);
|
||||
precacheDepthVariants(engine);
|
||||
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
// Register the material with matdbg.
|
||||
matdbg::DebugServer* server = downcast(engine).debug.server;
|
||||
@@ -354,21 +346,53 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
|
||||
FMaterial::~FMaterial() noexcept = default;
|
||||
|
||||
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
|
||||
// Note: This API is not public at the moment, so it's okay to have some debugging logs
|
||||
// and extra checks.
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mHasCustomDepthShader) {
|
||||
// it would be unsafe to invalidate any of the cached depth variant
|
||||
if (UTILS_UNLIKELY(!((variantMask & Variant::DEP) && !(variantValue & Variant::DEP)))) {
|
||||
slog.w << io::hex << "FMaterial::invalidate("
|
||||
<< +variantMask << ", " << +variantValue
|
||||
<< ") would corrupt the depth variant cache" << io::endl;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
|
||||
auto hasDefaultDepthVariant = [pDefaultMaterial](Variant k) {
|
||||
auto const& end = pDefaultMaterial->mDepthVariants.end();
|
||||
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
|
||||
};
|
||||
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE) {
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
Variant const variant(k);
|
||||
if ((k & variantMask) == variantValue) {
|
||||
if (UTILS_LIKELY(!mIsDefaultMaterial)) {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free it now.
|
||||
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
|
||||
!mHasCustomDepthShader &&
|
||||
hasDefaultDepthVariant(variant);
|
||||
if (isSharedVariant) {
|
||||
// we don't own this variant, skip.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
variantMask |= Variant::DEP;
|
||||
variantValue &= ~Variant::DEP;
|
||||
|
||||
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
|
||||
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
|
||||
pDefaultMaterial->prepareProgram(variant);
|
||||
if (!cachedPrograms[variant.key]) {
|
||||
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mMaterialDomain == MaterialDomain::POST_PROCESS) {
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
} else if (mMaterialDomain == MaterialDomain::COMPUTE) {
|
||||
// TODO: handle compute variants if any
|
||||
}
|
||||
destroyPrograms(mEngine, variantMask, variantValue);
|
||||
}
|
||||
|
||||
void FMaterial::terminate(FEngine& engine) {
|
||||
@@ -556,7 +580,7 @@ Program FMaterial::getProgramWithVariants(
|
||||
<< "The material '" << mName.c_str()
|
||||
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
|
||||
"vertex shader (variant="
|
||||
<< +variant.key << ", filtered=" << +vertexVariant.key << ").";
|
||||
<< variant.key << ", filtered=" << vertexVariant.key << ").";
|
||||
|
||||
/*
|
||||
* Fragment shader
|
||||
@@ -571,7 +595,7 @@ Program FMaterial::getProgramWithVariants(
|
||||
<< "The material '" << mName.c_str()
|
||||
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
|
||||
"fragment shader (variant="
|
||||
<< +variant.key << ", filtered=" << +fragmentVariant.key << ").";
|
||||
<< variant.key << ", filtered=" << ").";
|
||||
|
||||
Program program;
|
||||
program.shader(ShaderStage::VERTEX, vsBuilder.data(), vsBuilder.size())
|
||||
@@ -608,42 +632,11 @@ Program FMaterial::getProgramWithVariants(
|
||||
}
|
||||
|
||||
void FMaterial::createAndCacheProgram(Program&& p, Variant variant) const noexcept {
|
||||
FEngine const& engine = mEngine;
|
||||
DriverApi& driverApi = mEngine.getDriverApi();
|
||||
|
||||
bool const isSharedVariant =
|
||||
(mMaterialDomain == MaterialDomain::SURFACE) &&
|
||||
!mIsDefaultMaterial && !mHasCustomDepthShader &&
|
||||
Variant::isValidDepthVariant(variant);
|
||||
|
||||
// Check if the default material has this program cached
|
||||
if (isSharedVariant) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial) {
|
||||
auto program = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (program) {
|
||||
mCachedPrograms[variant.key] = program;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto program = driverApi.createProgram(std::move(p));
|
||||
driverApi.setDebugTag(program.getId(), mName);
|
||||
assert_invariant(!mCachedPrograms[variant.key]);
|
||||
auto program = mEngine.getDriverApi().createProgram(std::move(p));
|
||||
mEngine.getDriverApi().setDebugTag(program.getId(), mName);
|
||||
assert_invariant(program);
|
||||
mCachedPrograms[variant.key] = program;
|
||||
|
||||
// If the default material doesn't already have this program cached, and all caching conditions
|
||||
// are met (Surface Domain and no custom depth shader), cache it now.
|
||||
// New Materials will inherit these program automatically.
|
||||
if (isSharedVariant) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
if (pDefaultMaterial && !pDefaultMaterial->mCachedPrograms[variant.key]) {
|
||||
// set the tag to the default material name
|
||||
driverApi.setDebugTag(program.getId(), mName);
|
||||
pDefaultMaterial->mCachedPrograms[variant.key] = program;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const noexcept {
|
||||
@@ -748,76 +741,29 @@ void FMaterial::onQueryCallback(void* userdata, VariantList* pVariants) {
|
||||
#endif // FILAMENT_ENABLE_MATDBG
|
||||
|
||||
|
||||
void FMaterial::destroyPrograms(FEngine& engine,
|
||||
Variant::type_t const variantMask, Variant::type_t const variantValue) {
|
||||
|
||||
void FMaterial::destroyPrograms(FEngine& engine) {
|
||||
DriverApi& driverApi = engine.getDriverApi();
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
|
||||
switch (mMaterialDomain) {
|
||||
case MaterialDomain::SURFACE: {
|
||||
if (mIsDefaultMaterial || mHasCustomDepthShader) {
|
||||
// default material or we have custom depth shaders, we destroy all variants
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variants, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free them now.
|
||||
auto hasDefaultDepthVariant = [pDefaultMaterial = engine.getDefaultMaterial()](Variant k) {
|
||||
auto const& end = pDefaultMaterial->mDepthVariants.end();
|
||||
return end != std::find(pDefaultMaterial->mDepthVariants.begin(), end, k);
|
||||
};
|
||||
|
||||
// During Engine::shutdown(), auto-cleanup destroys the default material first,
|
||||
// so this can be null, but this is only used for debugging.
|
||||
UTILS_UNUSED_IN_RELEASE
|
||||
auto UTILS_NULLABLE pDefaultMaterial = engine.getDefaultMaterial();
|
||||
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variant, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
if (Variant::isValidDepthVariant(Variant(k))) {
|
||||
// By construction this should always be true, because this
|
||||
// field is populated only when a material creates the program
|
||||
// for this variant.
|
||||
// During Engine::shutdown, auto-cleanup destroys the
|
||||
// default material first
|
||||
assert_invariant(!pDefaultMaterial ||
|
||||
pDefaultMaterial->mCachedPrograms[k]);
|
||||
// we don't own this variant, skip, but clear the entry.
|
||||
cachedPrograms[k].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
|
||||
const Variant variant(k);
|
||||
if (!mIsDefaultMaterial) {
|
||||
// The depth variants may be shared with the default material, in which case
|
||||
// we should not free it now.
|
||||
bool const isSharedVariant = Variant::isValidDepthVariant(variant) &&
|
||||
!mHasCustomDepthShader && hasDefaultDepthVariant(variant);
|
||||
if (isSharedVariant) {
|
||||
// we don't own this variant, skip.
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MaterialDomain::POST_PROCESS: {
|
||||
for (size_t k = 0, n = POST_PROCESS_VARIANT_COUNT; k < n; ++k) {
|
||||
if ((k & variantMask) == variantValue) {
|
||||
// Only destroy if the handle is valid. Not strictly needed, but we have a lot
|
||||
// of variant, and this generates traffic in the command queue.
|
||||
if (cachedPrograms[k]) {
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MaterialDomain::COMPUTE: {
|
||||
// Compute programs don't have variants
|
||||
driverApi.destroyProgram(std::move(cachedPrograms[0]));
|
||||
break;
|
||||
}
|
||||
driverApi.destroyProgram(cachedPrograms[k]);
|
||||
cachedPrograms[k].clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,11 +951,7 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
|
||||
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
|
||||
(int)engine.getConfig().stereoscopicEyeCount });
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT,
|
||||
builder->mShBandsCount });
|
||||
mSpecializationConstants.push_back({
|
||||
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD,
|
||||
(int32_t)builder->mShadowSamplingQuality });
|
||||
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, builder->mShBandsCount });
|
||||
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
|
||||
// The actual value of this spec-constant is set in the OpenGLDriver backend.
|
||||
mSpecializationConstants.push_back({
|
||||
@@ -1086,32 +1028,34 @@ void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* pars
|
||||
});
|
||||
}
|
||||
|
||||
void FMaterial::precacheDepthVariants(FEngine& engine) {
|
||||
// pre-cache all depth variants inside the default material. Note that this should be
|
||||
// entirely optional; if we remove this pre-caching, these variants will be populated
|
||||
// later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more
|
||||
// memory and increases init time, but reduces hiccups during the first frame.
|
||||
void FMaterial::processDepthVariants(FEngine& engine, MaterialParser const* const parser) {
|
||||
parser->hasCustomDepthShader(&mHasCustomDepthShader);
|
||||
|
||||
if (UTILS_UNLIKELY(mIsDefaultMaterial)) {
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
if (hasVariant(variant)) {
|
||||
prepareProgram(variant);
|
||||
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
|
||||
filaflat::MaterialChunk const& materialChunk{ parser->getMaterialChunk() };
|
||||
auto variants = FixedCapacityVector<Variant>::with_capacity(materialChunk.getShaderCount());
|
||||
materialChunk.visitShaders([&variants](
|
||||
ShaderModel, Variant variant, ShaderStage) {
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
variants.push_back(variant);
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
std::sort(variants.begin(), variants.end(),
|
||||
[](Variant lhs, Variant rhs) { return lhs.key < rhs.key; });
|
||||
auto pos = std::unique(variants.begin(), variants.end());
|
||||
variants.resize(std::distance(variants.begin(), pos));
|
||||
std::swap(mDepthVariants, variants);
|
||||
}
|
||||
|
||||
// if possible pre-cache all depth variants from the default material
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE &&
|
||||
!mIsDefaultMaterial &&
|
||||
!mHasCustomDepthShader) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
assert_invariant(pDefaultMaterial);
|
||||
auto const allDepthVariants = VariantUtils::getDepthVariants();
|
||||
for (auto const variant: allDepthVariants) {
|
||||
assert_invariant(Variant::isValidDepthVariant(variant));
|
||||
mCachedPrograms[variant.key] = pDefaultMaterial->mCachedPrograms[variant.key];
|
||||
if (mMaterialDomain == MaterialDomain::SURFACE) {
|
||||
if (UTILS_UNLIKELY(!mIsDefaultMaterial && !mHasCustomDepthShader)) {
|
||||
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
|
||||
auto& cachedPrograms = mCachedPrograms;
|
||||
for (Variant const variant: pDefaultMaterial->mDepthVariants) {
|
||||
pDefaultMaterial->prepareProgram(variant);
|
||||
cachedPrograms[variant.key] = pDefaultMaterial->getProgram(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,9 +218,7 @@ public:
|
||||
|
||||
uint32_t generateMaterialInstanceId() const noexcept { return mMaterialInstanceId++; }
|
||||
|
||||
void destroyPrograms(FEngine& engine,
|
||||
Variant::type_t variantMask = 0,
|
||||
Variant::type_t variantValue = 0);
|
||||
void destroyPrograms(FEngine& engine);
|
||||
|
||||
// return the id of a specialization constant specified by name for this material
|
||||
std::optional<uint32_t> getSpecializationConstantId(std::string_view name) const noexcept ;
|
||||
@@ -284,7 +282,7 @@ private:
|
||||
|
||||
void processPushConstants(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
void precacheDepthVariants(FEngine& engine);
|
||||
void processDepthVariants(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
|
||||
|
||||
@@ -333,6 +331,7 @@ private:
|
||||
SamplerInterfaceBlock mSamplerInterfaceBlock;
|
||||
BufferInterfaceBlock mUniformInterfaceBlock;
|
||||
SubpassInfo mSubpassInfo;
|
||||
utils::FixedCapacityVector<Variant> mDepthVariants; // only populated with default material
|
||||
|
||||
using BindingUniformInfoContainer = utils::FixedCapacityVector<std::tuple<
|
||||
uint8_t, utils::CString, backend::Program::UniformInfo>>;
|
||||
|
||||
@@ -963,11 +963,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
uint32_t(float(xvp.width ) * aoOptions.resolution),
|
||||
uint32_t(float(xvp.height) * aoOptions.resolution)});
|
||||
|
||||
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
|
||||
// this descriptor-set is also used for ssr/picking/structure and these could be stale
|
||||
// it would be better to use a separate desriptor-set for those two cases so that we don't
|
||||
// have to do this
|
||||
view.unbindSamplers(driver);
|
||||
view.commitUniformsAndSamplers(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -912,10 +912,6 @@ void FView::commitUniformsAndSamplers(DriverApi& driver) const noexcept {
|
||||
mColorPassDescriptorSet.commit(driver);
|
||||
}
|
||||
|
||||
void FView::unbindSamplers(DriverApi& driver) noexcept {
|
||||
mColorPassDescriptorSet.unbindSamplers(driver);
|
||||
}
|
||||
|
||||
void FView::commitFroxels(DriverApi& driverApi) const noexcept {
|
||||
if (mHasDynamicLighting) {
|
||||
mFroxelizer.commit(driverApi);
|
||||
|
||||
@@ -174,7 +174,6 @@ public:
|
||||
|
||||
void commitFroxels(backend::DriverApi& driverApi) const noexcept;
|
||||
void commitUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
void unbindSamplers(backend::DriverApi& driver) noexcept;
|
||||
|
||||
utils::JobSystem::Job* getFroxelizerSync() const noexcept { return mFroxelizerSync; }
|
||||
void setFroxelizerSync(utils::JobSystem::Job* sync) noexcept { mFroxelizerSync = sync; }
|
||||
@@ -535,7 +534,7 @@ private:
|
||||
Viewport mViewport;
|
||||
bool mCulling = true;
|
||||
bool mFrontFaceWindingInverted = false;
|
||||
bool mIsTransparentPickingEnabled = false;
|
||||
bool mIsTransparentPickingEnabled = true;
|
||||
|
||||
FRenderTarget* mRenderTarget = nullptr;
|
||||
|
||||
|
||||
@@ -541,17 +541,6 @@ void ColorPassDescriptorSet::commit(backend::DriverApi& driver) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::unbindSamplers(DriverApi&) noexcept {
|
||||
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
|
||||
// this descriptor-set is also used for ssr/picking/structure and these could be stale
|
||||
// it would be better to use a separate descriptor-set for those two cases so that we don't
|
||||
// have to do this
|
||||
setSampler(+PerViewBindingPoints::STRUCTURE, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SHADOW_MAP, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SSAO, {}, {});
|
||||
setSampler(+PerViewBindingPoints::SSR, {}, {});
|
||||
}
|
||||
|
||||
void ColorPassDescriptorSet::setSampler(backend::descriptor_binding_t binding,
|
||||
TextureHandle th, SamplerParams params) noexcept {
|
||||
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
|
||||
|
||||
@@ -158,8 +158,6 @@ public:
|
||||
// update local data into GPU UBO
|
||||
void commit(backend::DriverApi& driver) noexcept;
|
||||
|
||||
void unbindSamplers(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// bind this UBO
|
||||
void bind(backend::DriverApi& driver, uint8_t index) const noexcept {
|
||||
mDescriptorSet[index].bind(driver, DescriptorSetBindingPoints::PER_VIEW);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.56.5"
|
||||
spec.version = "1.56.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.5/filament-v1.56.5-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.0/filament-v1.56.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -38,13 +38,12 @@ bool initBinder() {
|
||||
}
|
||||
}
|
||||
if (!g_driver.library) {
|
||||
// The library has been linked explicitly during compile.
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc) dlsym(RTLD_LOCAL, "OSMesaGetProcAddress");
|
||||
} else {
|
||||
g_driver.OSMesaGetProcAddress =
|
||||
(ProcAddressFunc) dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_driver.OSMesaGetProcAddress = (ProcAddressFunc)
|
||||
dlsym(g_driver.library, "OSMesaGetProcAddress");
|
||||
|
||||
return g_driver.OSMesaGetProcAddress;
|
||||
}
|
||||
|
||||
@@ -53,9 +52,7 @@ void* loadFunction(const char* name) {
|
||||
}
|
||||
|
||||
void shutdownBinder() {
|
||||
if (g_driver.library) {
|
||||
dlclose(g_driver.library);
|
||||
}
|
||||
dlclose(g_driver.library);
|
||||
memset(&g_driver, 0, sizeof(g_driver));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 56;
|
||||
static constexpr size_t MATERIAL_VERSION = 55;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -81,9 +81,7 @@ enum class ReservedSpecializationConstants : uint8_t {
|
||||
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
|
||||
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
|
||||
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
|
||||
CONFIG_SH_BANDS_COUNT = 9,
|
||||
CONFIG_SHADOW_SAMPLING_METHOD = 10
|
||||
// check CONFIG_MAX_RESERVED_SPEC_CONSTANTS below
|
||||
CONFIG_SH_BANDS_COUNT = 9
|
||||
};
|
||||
|
||||
enum class PushConstantIds : uint8_t {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/Slice.h>
|
||||
|
||||
@@ -272,8 +271,6 @@ namespace VariantUtils {
|
||||
utils::Slice<Variant> getLitVariants() noexcept UTILS_PURE;
|
||||
// list of unlit variants
|
||||
utils::Slice<Variant> getUnlitVariants() noexcept UTILS_PURE;
|
||||
// list of depth variants
|
||||
utils::Slice<Variant> getDepthVariants() noexcept UTILS_PURE;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -16,15 +16,8 @@
|
||||
|
||||
#include <private/filament/Variant.h>
|
||||
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <utils/Slice.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
Variant Variant::filterUserVariant(
|
||||
@@ -72,8 +65,6 @@ Variant Variant::filterUserVariant(
|
||||
|
||||
namespace details {
|
||||
|
||||
namespace {
|
||||
|
||||
// Compile-time variant count for lit and unlit
|
||||
constexpr inline size_t variant_count(bool lit) noexcept {
|
||||
size_t count = 0;
|
||||
@@ -90,17 +81,6 @@ constexpr inline size_t variant_count(bool lit) noexcept {
|
||||
return count;
|
||||
}
|
||||
|
||||
constexpr inline size_t depth_variant_count() noexcept {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < VARIANT_COUNT; i++) {
|
||||
Variant const variant(i);
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Compile-time variant list for lit and unlit
|
||||
template<bool LIT>
|
||||
constexpr auto get_variants() noexcept {
|
||||
@@ -118,18 +98,9 @@ constexpr auto get_variants() noexcept {
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
static auto const gLitVariants{ details::get_variants<true>() };
|
||||
static auto const gUnlitVariants{ details::get_variants<false>() };
|
||||
|
||||
constexpr auto get_depth_variants() noexcept {
|
||||
std::array<Variant, depth_variant_count()> variants;
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < VARIANT_COUNT; i++) {
|
||||
Variant const variant(i);
|
||||
if (Variant::isValidDepthVariant(variant)) {
|
||||
variants[count++] = variant;
|
||||
}
|
||||
}
|
||||
return variants;
|
||||
}
|
||||
|
||||
// Below are compile time sanity-check tests
|
||||
constexpr inline bool reserved_is_not_valid() noexcept {
|
||||
@@ -192,13 +163,6 @@ constexpr inline size_t fragment_variant_count() noexcept {
|
||||
return count;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
static auto const gLitVariants{ details::get_variants<true>() };
|
||||
static auto const gUnlitVariants{ details::get_variants<false>() };
|
||||
static auto const gDepthVariants{ details::get_depth_variants() };
|
||||
|
||||
static_assert(reserved_is_not_valid());
|
||||
static_assert(reserved_variant_count() == 160);
|
||||
static_assert(valid_variant_count() == 96);
|
||||
@@ -218,10 +182,6 @@ utils::Slice<Variant> getUnlitVariants() noexcept {
|
||||
return { details::gUnlitVariants.data(), details::gUnlitVariants.size() };
|
||||
}
|
||||
|
||||
utils::Slice<Variant> getDepthVariants() noexcept {
|
||||
return { details::gDepthVariants.data(), details::gDepthVariants.size() };
|
||||
}
|
||||
|
||||
}; // VariantUtils
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -337,9 +337,6 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
generateSpecializationConstant(out, "CONFIG_SH_BANDS_COUNT",
|
||||
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, 3);
|
||||
|
||||
generateSpecializationConstant(out, "CONFIG_SHADOW_SAMPLING_METHOD",
|
||||
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD, 1);
|
||||
|
||||
// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
|
||||
// be explicitly, statically defined (as in #define). Otherwise (using const int for
|
||||
// example), we'd run into a GPU crash.
|
||||
|
||||
@@ -660,13 +660,11 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
|
||||
CodeGenerator::generateDepthShaderMain(fs, ShaderStage::FRAGMENT);
|
||||
} else {
|
||||
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
|
||||
if (material.isLit) {
|
||||
if (filament::Variant::isSSRVariant(variant)) {
|
||||
CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT);
|
||||
} else {
|
||||
CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant,
|
||||
material.shading,material.hasCustomSurfaceShading);
|
||||
}
|
||||
if (filament::Variant::isSSRVariant(variant)) {
|
||||
CodeGenerator::generateShaderReflections(fs, ShaderStage::FRAGMENT);
|
||||
} else if (material.isLit) {
|
||||
CodeGenerator::generateShaderLit(fs, ShaderStage::FRAGMENT, variant,
|
||||
material.shading,material.hasCustomSurfaceShading);
|
||||
} else {
|
||||
CodeGenerator::generateShaderUnlit(fs, ShaderStage::FRAGMENT, variant,
|
||||
material.hasShadowMultiplier);
|
||||
|
||||
@@ -264,7 +264,7 @@ size_t Animator::getAnimationCount() const {
|
||||
|
||||
void Animator::applyAnimation(size_t animationIndex, float time) const {
|
||||
const Animation& anim = mImpl->animations[animationIndex];
|
||||
time = time == anim.duration ? time : fmod(time, anim.duration);
|
||||
time = fmod(time, anim.duration);
|
||||
TransformManager& transformManager = *mImpl->transformManager;
|
||||
transformManager.openLocalTransformTransaction();
|
||||
for (const auto& channel : anim.channels) {
|
||||
|
||||
@@ -63,7 +63,7 @@ using filamat::ChunkType;
|
||||
using utils::FixedCapacityVector;
|
||||
|
||||
static auto const error = [](int line, std::string const& uri) {
|
||||
utils::slog.e << "[matdbg] DebugServer: 404 at line " << line << ": " << uri << utils::io::endl;
|
||||
utils::slog.e << "DebugServer: 404 at line " << line << ": " << uri << utils::io::endl;
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ MaterialRecord const* ApiHandler::getMaterialRecord(struct mg_request_info const
|
||||
bool ApiHandler::handleGetApiShader(struct mg_connection* conn,
|
||||
struct mg_request_info const* request) {
|
||||
auto const softError = [conn, request](char const* msg) {
|
||||
utils::slog.e << "[matdbg] DebugServer: " << msg << ": " << request->query_string << utils::io::endl;
|
||||
utils::slog.e << "DebugServer: " << msg << ": " << request->query_string << utils::io::endl;
|
||||
mg_printf(conn, kErrorHeader.data(), "application/txt");
|
||||
mg_write(conn, msg, strlen(msg));
|
||||
return true;
|
||||
@@ -266,7 +266,7 @@ bool ApiHandler::handlePost(CivetServer* server, struct mg_connection* conn) {
|
||||
while (readLen < msgLen) {
|
||||
int const res = mg_read(conn, buf, sizeof(buf));
|
||||
if (res < 0) {
|
||||
utils::slog.e << "[matdbg] civet error parsing /api/edit body: " << res << utils::io::endl;
|
||||
utils::slog.e << "civet error parsing /api/edit body: " << res << utils::io::endl;
|
||||
break;
|
||||
}
|
||||
if (res == 0) {
|
||||
|
||||
@@ -115,7 +115,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
slog.e << "[matdbg] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
|
||||
slog.e << "DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
@@ -156,7 +156,7 @@ DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) {
|
||||
if (!mServer->getContext()) {
|
||||
delete mServer;
|
||||
mServer = nullptr;
|
||||
slog.e << "[matdbg] Unable to start DebugServer, see civetweb.txt for details." << io::endl;
|
||||
slog.e << "Unable to start DebugServer, see civetweb.txt for details." << io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) {
|
||||
mServer->addHandler("/api", mApiHandler);
|
||||
mServer->addHandler("", mFileHandler);
|
||||
|
||||
slog.i << "[matdbg] DebugServer listening at http://localhost:" << port << io::endl;
|
||||
slog.i << "DebugServer listening at http://localhost:" << port << io::endl;
|
||||
filamat::GLSLTools::init();
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ MaterialKey
|
||||
DebugServer::addMaterial(const CString& name, const void* data, size_t size, void* userdata) {
|
||||
filaflat::ChunkContainer* container = new filaflat::ChunkContainer(data, size);
|
||||
if (!container->parse()) {
|
||||
slog.e << "[matdbg] DebugServer: unable to parse material package: " << name.c_str() << io::endl;
|
||||
slog.e << "DebugServer: unable to parse material package: " << name.c_str() << io::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ void DebugServer::updateActiveVariants() {
|
||||
bool DebugServer::handleEditCommand(const MaterialKey& key, backend::Backend api, int shaderIndex,
|
||||
const char* source, size_t size) {
|
||||
const auto error = [](int line) {
|
||||
slog.e << "[matdbg] DebugServer: Unable to apply shader edit at line " << line << io::endl;
|
||||
slog.e << "DebugServer: Unable to apply shader edit at line " << line << io::endl;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS, &binary, &diagnostic);
|
||||
spvContextDestroy(context);
|
||||
if (error) {
|
||||
slog.e << "[matdbg] ShaderReplacer spirv-as failed (spv_result_t: " << error << ")" << io::endl;
|
||||
slog.e << "ShaderReplacer spirv-as failed (spv_result_t: " << error << ")" << io::endl;
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
return false;
|
||||
@@ -227,7 +227,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
|
||||
|
||||
const bool ok = tShader.parse(&DefaultTBuiltInResource, version, false, msg);
|
||||
if (!ok) {
|
||||
slog.e << "[matdbg] ShaderReplacer parse:\n" << tShader.getInfoLog() << io::endl;
|
||||
slog.e << "ShaderReplacer parse:\n" << tShader.getInfoLog() << io::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
|
||||
program.addShader(&tShader);
|
||||
const bool linkOk = program.link(msg);
|
||||
if (!linkOk) {
|
||||
slog.e << "[matdbg] ShaderReplacer link:\n" << program.getInfoLog() << io::endl;
|
||||
slog.e << "ShaderReplacer link:\n" << program.getInfoLog() << io::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ bool ShaderReplacer::replaceSpirv(ShaderModel shaderModel, Variant variant,
|
||||
source = (const char*) spirv.data();
|
||||
sourceLength = spirv.size() * 4;
|
||||
|
||||
slog.i << "[matdbg] Success re-generating SPIR-V. (" << sourceLength << " bytes)" << io::endl;
|
||||
slog.i << "Success re-generating SPIR-V. (" << sourceLength << " bytes)" << io::endl;
|
||||
|
||||
// Clone all chunks except Dictionary* and Material*.
|
||||
filaflat::ChunkContainer const& cc = mOriginalPackage;
|
||||
@@ -349,7 +349,7 @@ void ShaderIndex::replaceShader(backend::ShaderModel model, Variant variant,
|
||||
return;
|
||||
}
|
||||
}
|
||||
slog.e << "[matdbg] Failed to replace shader." << io::endl;
|
||||
slog.e << "Failed to replace shader." << io::endl;
|
||||
}
|
||||
|
||||
BlobIndex::BlobIndex(ChunkType dictTag, ChunkType matTag, const filaflat::ChunkContainer& cc) :
|
||||
@@ -426,7 +426,7 @@ void BlobIndex::replaceShader(ShaderModel model, Variant variant,
|
||||
return;
|
||||
}
|
||||
}
|
||||
slog.e << "[matdbg] Unable to replace shader." << io::endl;
|
||||
slog.e << "Unable to replace shader." << io::endl;
|
||||
}
|
||||
|
||||
} // namespace filament::matdbg
|
||||
|
||||
@@ -1043,8 +1043,6 @@ int main(int argc, char** argv) {
|
||||
delete app.resourceLoader;
|
||||
delete app.stbDecoder;
|
||||
delete app.ktxDecoder;
|
||||
delete app.automationSpec;
|
||||
delete app.automationEngine;
|
||||
|
||||
AssetLoader::destroy(&app.assetLoader);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
highp mat3 shading_tangentToWorld; // TBN matrix
|
||||
highp vec3 shading_position; // position of the fragment in world space
|
||||
vec3 shading_view; // normalized vector from the fragment to the eye
|
||||
#if defined(HAS_ATTRIBUTE_TANGENTS)
|
||||
vec3 shading_normal; // normalized transformed normal, in world space
|
||||
vec3 shading_geometricNormal; // normalized geometric normal, in world space
|
||||
vec3 shading_reflected; // reflection of view about normal
|
||||
@@ -16,6 +15,5 @@ highp vec3 shading_position; // position of the fragment in world space
|
||||
#if defined(MATERIAL_HAS_CLEAR_COAT)
|
||||
vec3 shading_clearCoatNormal; // normalized clear coat layer normal, in world space
|
||||
#endif
|
||||
#endif
|
||||
|
||||
highp vec2 shading_normalizedViewportCoord;
|
||||
|
||||
@@ -63,8 +63,6 @@ bool isPerspectiveProjection() {
|
||||
return frameUniforms.clipFromViewMatrix[2].w != 0.0;
|
||||
}
|
||||
|
||||
#if defined(HAS_ATTRIBUTE_TANGENTS)
|
||||
|
||||
/** @public-api */
|
||||
vec3 getWorldNormalVector() {
|
||||
return shading_normal;
|
||||
@@ -85,8 +83,6 @@ float getNdotV() {
|
||||
return shading_NoV;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
highp vec3 getNormalizedPhysicalViewportCoord() {
|
||||
// make sure to handle our reversed-z
|
||||
return vec3(shading_normalizedViewportCoord, gl_FragCoord.z);
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#define SHADOW_SAMPLING_RUNTIME_DPCF 2u
|
||||
#define SHADOW_SAMPLING_RUNTIME_PCSS 3u
|
||||
|
||||
// TODO: this should be user-settable, maybe at the material level
|
||||
#define SHADOW_SAMPLING_PCF_HARD 0
|
||||
#define SHADOW_SAMPLING_PCF_LOW 1
|
||||
#define SHADOW_SAMPLING_METHOD SHADOW_SAMPLING_PCF_LOW
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PCF Shadow Sampling
|
||||
@@ -27,6 +29,7 @@ float sampleDepth(const mediump sampler2DArrayShadow map,
|
||||
return texture(map, vec4(uv, layer, saturate(depth)));
|
||||
}
|
||||
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
|
||||
// use hardware assisted PCF
|
||||
float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
|
||||
const highp vec4 scissorNormalized,
|
||||
@@ -35,7 +38,9 @@ float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
|
||||
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
|
||||
return sampleDepth(map, scissorNormalized, layer, position.xy, position.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
|
||||
// use hardware assisted PCF + 3x3 gaussian filter
|
||||
float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
|
||||
const highp vec4 scissorNormalized,
|
||||
@@ -72,6 +77,7 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
|
||||
sum += uw.y * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.y), depth);
|
||||
return sum * (1.0 / 16.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// use manual PCF
|
||||
float ShadowSample_PCF(const mediump sampler2DArray map,
|
||||
@@ -517,12 +523,11 @@ float shadow(const bool DIRECTIONAL,
|
||||
const int index, highp vec4 shadowPosition, highp float zLight) {
|
||||
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
|
||||
uint layer = shadowUniforms.shadows[index].layer;
|
||||
|
||||
if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD) {
|
||||
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
} else if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW) {
|
||||
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
}
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
|
||||
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
|
||||
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.56.5",
|
||||
"version": "1.56.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user