Compare commits
7 Commits
pf/testing
...
pf/test-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46f38957f2 | ||
|
|
b204b92e35 | ||
|
|
0a5b85f740 | ||
|
|
01318588d5 | ||
|
|
71b193a192 | ||
|
|
07324d63b6 | ||
|
|
3387f5bf33 |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.56.7'
|
||||
implementation 'com.google.android.filament:filament-android:1.56.8'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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.7'
|
||||
pod 'Filament', '~> 1.56.8'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -1271,7 +1271,7 @@ public class Engine {
|
||||
* {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.</p>
|
||||
*/
|
||||
public void flushAndWait() {
|
||||
flushAndWait(Fence.WAIT_FOR_EVER);
|
||||
boolean unused = flushAndWait(Fence.WAIT_FOR_EVER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.56.7
|
||||
VERSION_NAME=1.56.8
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -139,11 +139,11 @@ if (FILAMENT_SUPPORTS_METAL)
|
||||
src/metal/MetalEnums.mm
|
||||
src/metal/MetalExternalImage.mm
|
||||
src/metal/MetalHandles.mm
|
||||
src/metal/MetalPlatform.mm
|
||||
src/metal/MetalShaderCompiler.mm
|
||||
src/metal/MetalState.mm
|
||||
src/metal/MetalTimerQuery.mm
|
||||
src/metal/MetalUtils.mm
|
||||
src/metal/PlatformMetal.mm
|
||||
)
|
||||
|
||||
set(METAL_CPP_SRCS
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Platform.h>
|
||||
@@ -24,9 +24,12 @@
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class MetalPlatform final : public Platform {
|
||||
struct PlatformMetalImpl;
|
||||
|
||||
class PlatformMetal final : public Platform {
|
||||
public:
|
||||
~MetalPlatform() override;
|
||||
PlatformMetal();
|
||||
~PlatformMetal() noexcept override;
|
||||
|
||||
Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override;
|
||||
int getOSVersion() const noexcept override { return 0; }
|
||||
@@ -54,11 +57,30 @@ public:
|
||||
*/
|
||||
id<MTLCommandBuffer> createAndEnqueueCommandBuffer() noexcept;
|
||||
|
||||
private:
|
||||
id<MTLCommandQueue> mCommandQueue = nil;
|
||||
/**
|
||||
* The action to take if a Drawable cannot be acquired.
|
||||
*
|
||||
* Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the
|
||||
* completion of each frame. These are limited and provided round-robin style by the system.
|
||||
*/
|
||||
enum class DrawableFailureBehavior : uint8_t {
|
||||
/**
|
||||
* Terminates the application and reports an error message (default).
|
||||
*/
|
||||
PANIC,
|
||||
/*
|
||||
* Aborts execution of the current frame. The Metal backend will attempt to acquire a new
|
||||
* drawable at the next frame.
|
||||
*/
|
||||
ABORT_FRAME
|
||||
};
|
||||
void setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept;
|
||||
DrawableFailureBehavior getDrawableFailureBehavior() const noexcept;
|
||||
|
||||
private:
|
||||
PlatformMetalImpl* pImpl = nullptr;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H
|
||||
@@ -18,9 +18,9 @@
|
||||
#define TNT_FILAMENT_DRIVER_METALBUFFER_H
|
||||
|
||||
#include "MetalContext.h"
|
||||
#include "MetalPlatform.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/PlatformMetal.h>
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
@@ -54,12 +54,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void setPlatform(MetalPlatform* p) { platform = p; }
|
||||
static void setPlatform(PlatformMetal* p) { platform = p; }
|
||||
|
||||
private:
|
||||
typedef std::chrono::steady_clock clock_t;
|
||||
|
||||
static MetalPlatform* platform;
|
||||
static PlatformMetal* platform;
|
||||
|
||||
std::chrono::time_point<clock_t> mBeginning;
|
||||
const char* mName;
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
assert_invariant(type != Type::NONE);
|
||||
return aliveBuffers[toIndex(type)];
|
||||
}
|
||||
static void setPlatform(MetalPlatform* p) { platform = p; }
|
||||
static void setPlatform(PlatformMetal* p) { platform = p; }
|
||||
|
||||
private:
|
||||
void swap(TrackedMetalBuffer& other) noexcept {
|
||||
@@ -152,7 +152,7 @@ private:
|
||||
id<MTLBuffer> mBuffer;
|
||||
Type mType = Type::NONE;
|
||||
|
||||
static MetalPlatform* platform;
|
||||
static PlatformMetal* platform;
|
||||
static std::array<uint64_t, TypeCount> aliveBuffers;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace filament {
|
||||
namespace backend {
|
||||
|
||||
std::array<uint64_t, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
|
||||
MetalPlatform* TrackedMetalBuffer::platform = nullptr;
|
||||
MetalPlatform* ScopedAllocationTimer::platform = nullptr;
|
||||
PlatformMetal* TrackedMetalBuffer::platform = nullptr;
|
||||
PlatformMetal* ScopedAllocationTimer::platform = nullptr;
|
||||
|
||||
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
|
||||
size_t size, bool forceGpuBuffer)
|
||||
|
||||
@@ -128,6 +128,7 @@ struct MetalContext {
|
||||
std::atomic<uint64_t> latestCompletedCommandBufferId = 0;
|
||||
id<MTLCommandBuffer> pendingCommandBuffer = nil;
|
||||
id<MTLRenderCommandEncoder> currentRenderPassEncoder = nil;
|
||||
uint32_t currentFrame = 0;
|
||||
|
||||
std::atomic<bool> memorylessLimitsReached = false;
|
||||
|
||||
@@ -156,6 +157,7 @@ struct MetalContext {
|
||||
RenderPassFlags currentRenderPassFlags;
|
||||
MetalRenderTarget* currentRenderTarget = nullptr;
|
||||
bool validPipelineBound = false;
|
||||
bool currentRenderPassAbandoned = false;
|
||||
|
||||
// State trackers.
|
||||
PipelineStateTracker pipelineState;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
class MetalPlatform;
|
||||
class PlatformMetal;
|
||||
|
||||
class MetalBuffer;
|
||||
class MetalProgram;
|
||||
@@ -51,19 +51,19 @@ struct BufferState;
|
||||
#endif
|
||||
|
||||
class MetalDriver final : public DriverBase {
|
||||
explicit MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept;
|
||||
explicit MetalDriver(PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept;
|
||||
~MetalDriver() noexcept override;
|
||||
Dispatcher getDispatcher() const noexcept final;
|
||||
|
||||
public:
|
||||
static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig);
|
||||
static Driver* create(PlatformMetal* platform, const Platform::DriverConfig& driverConfig);
|
||||
|
||||
private:
|
||||
|
||||
friend class MetalSwapChain;
|
||||
friend struct MetalDescriptorSet;
|
||||
|
||||
MetalPlatform& mPlatform;
|
||||
PlatformMetal& mPlatform;
|
||||
MetalContext* mContext;
|
||||
|
||||
ShaderModel getShaderModel() const noexcept final;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "MetalState.h"
|
||||
#include "MetalTimerQuery.h"
|
||||
|
||||
#include "MetalPlatform.h"
|
||||
#include <backend/platforms/PlatformMetal.h>
|
||||
|
||||
#include <CoreVideo/CVMetalTexture.h>
|
||||
#include <CoreVideo/CVPixelBuffer.h>
|
||||
@@ -57,7 +57,7 @@
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
|
||||
Driver* MetalDriverFactory::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* MetalDriverFactory::create(PlatformMetal* const platform, const Platform::DriverConfig& driverConfig) {
|
||||
#if 0
|
||||
// this is useful for development, but too verbose even for debug builds
|
||||
// For reference on a 64-bits machine in Release mode:
|
||||
@@ -96,7 +96,7 @@ Driver* MetalDriverFactory::create(MetalPlatform* const platform, const Platform
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
Driver* MetalDriver::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) {
|
||||
Driver* MetalDriver::create(PlatformMetal* const platform, const Platform::DriverConfig& driverConfig) {
|
||||
assert_invariant(platform);
|
||||
size_t defaultSize = FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
|
||||
Platform::DriverConfig validConfig {driverConfig};
|
||||
@@ -109,7 +109,7 @@ Dispatcher MetalDriver::getDispatcher() const noexcept {
|
||||
}
|
||||
|
||||
MetalDriver::MetalDriver(
|
||||
MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||
PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept
|
||||
: mPlatform(*platform),
|
||||
mContext(new MetalContext),
|
||||
mHandleAllocator(
|
||||
@@ -246,6 +246,7 @@ void MetalDriver::tick(int) {
|
||||
|
||||
void MetalDriver::beginFrame(int64_t monotonic_clock_ns,
|
||||
int64_t refreshIntervalNs, uint32_t frameId) {
|
||||
mContext->currentFrame = frameId;
|
||||
DEBUG_LOG("beginFrame(monotonic_clock_ns = %lld, refreshIntervalNs = %lld, frameId = %d)\n",
|
||||
monotonic_clock_ns, refreshIntervalNs, frameId);
|
||||
#if defined(FILAMENT_METAL_PROFILING)
|
||||
@@ -631,19 +632,19 @@ void MetalDriver::createFenceR(Handle<HwFence> fh, int dummy) {
|
||||
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
||||
if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
|
||||
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow;
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, pixelBuffer, flags);
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, pixelBuffer, flags);
|
||||
// This release matches the retain call in setupExternalImage. The MetalSwapchain will have
|
||||
// retained the buffer by now.
|
||||
CVPixelBufferRelease((CVPixelBufferRef)pixelBuffer);
|
||||
} else {
|
||||
auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow;
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, metalLayer, flags);
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, metalLayer, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
uint32_t width, uint32_t height, uint64_t flags) {
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, width, height, flags);
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, width, height, flags);
|
||||
}
|
||||
|
||||
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
@@ -1268,6 +1269,13 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
renderTarget->setUpRenderPassAttachments(descriptor, params);
|
||||
|
||||
if (renderTarget->involvesAbandonedSwapChain()) {
|
||||
mContext->currentRenderPassAbandoned = true;
|
||||
return;
|
||||
} else {
|
||||
mContext->currentRenderPassAbandoned = false;
|
||||
}
|
||||
|
||||
mContext->currentRenderPassEncoder =
|
||||
[getPendingCommandBuffer(mContext) renderCommandEncoderWithDescriptor:descriptor];
|
||||
if (!mContext->groupMarkers.empty()) {
|
||||
@@ -1329,6 +1337,10 @@ void MetalDriver::endRenderPass(int dummy) {
|
||||
os_signpost_interval_end(mContext->log, OS_SIGNPOST_ID_EXCLUSIVE, "Render pass");
|
||||
#endif
|
||||
|
||||
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
|
||||
return;
|
||||
}
|
||||
|
||||
[mContext->currentRenderPassEncoder endEncoding];
|
||||
|
||||
// Command encoders are one time use. Set it to nil to release the encoder and ensure we don't
|
||||
@@ -1629,6 +1641,11 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers,
|
||||
auto srcTarget = handle_cast<MetalRenderTarget>(src);
|
||||
auto dstTarget = handle_cast<MetalRenderTarget>(dst);
|
||||
|
||||
if (UTILS_UNLIKELY(srcTarget->involvesAbandonedSwapChain() ||
|
||||
dstTarget->involvesAbandonedSwapChain())) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(buffers == TargetBufferFlags::COLOR0)
|
||||
<< "blitDEPRECATED only supports COLOR0";
|
||||
|
||||
@@ -1913,6 +1930,10 @@ void MetalDriver::bindDescriptorSet(
|
||||
}
|
||||
|
||||
void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr)
|
||||
<< "draw() without a valid command encoder.";
|
||||
DEBUG_LOG("draw2(...)\n");
|
||||
@@ -1956,6 +1977,9 @@ void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t inst
|
||||
|
||||
void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph,
|
||||
uint32_t const indexOffset, uint32_t const indexCount, uint32_t const instanceCount) {
|
||||
if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) {
|
||||
return;
|
||||
}
|
||||
MetalRenderPrimitive const* const rp = handle_cast<MetalRenderPrimitive>(rph);
|
||||
ps.primitiveType = rp->type;
|
||||
ps.vertexBufferInfo = rp->vertexBuffer->vbih;
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
|
||||
namespace filament {
|
||||
namespace backend {
|
||||
class MetalPlatform;
|
||||
class PlatformMetal;
|
||||
class Driver;
|
||||
|
||||
class MetalDriverFactory {
|
||||
public:
|
||||
static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig);
|
||||
static Driver* create(PlatformMetal* platform, const Platform::DriverConfig& driverConfig);
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "MetalState.h" // for MetalState::VertexDescription
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/PlatformMetal.h>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/CString.h>
|
||||
@@ -51,13 +52,16 @@ class MetalSwapChain : public HwSwapChain {
|
||||
public:
|
||||
|
||||
// Instantiate a SwapChain from a CAMetalLayer
|
||||
MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags);
|
||||
MetalSwapChain(MetalContext& context, PlatformMetal& platform, CAMetalLayer* nativeWindow,
|
||||
uint64_t flags);
|
||||
|
||||
// Instantiate a SwapChain from a CVPixelBuffer
|
||||
MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags);
|
||||
MetalSwapChain(MetalContext& context, PlatformMetal& platform, CVPixelBufferRef pixelBuffer,
|
||||
uint64_t flags);
|
||||
|
||||
// Instantiate a headless SwapChain.
|
||||
MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags);
|
||||
MetalSwapChain(MetalContext& context, PlatformMetal& platform, int32_t width, int32_t height,
|
||||
uint64_t flags);
|
||||
|
||||
~MetalSwapChain();
|
||||
|
||||
@@ -86,6 +90,8 @@ public:
|
||||
|
||||
bool isPixelBuffer() const { return type == SwapChainType::CVPIXELBUFFERREF; }
|
||||
|
||||
bool isAbandoned() const;
|
||||
|
||||
private:
|
||||
|
||||
enum class SwapChainType {
|
||||
@@ -103,6 +109,7 @@ private:
|
||||
void ensureDepthStencilTexture();
|
||||
|
||||
MetalContext& context;
|
||||
PlatformMetal& platform;
|
||||
id<CAMetalDrawable> drawable = nil;
|
||||
id<MTLTexture> depthStencilTexture = nil;
|
||||
id<MTLTexture> headlessDrawable = nil;
|
||||
@@ -114,6 +121,8 @@ private:
|
||||
MetalExternalImage externalImage;
|
||||
SwapChainType type;
|
||||
|
||||
int64_t abandonedUntilFrame = -1;
|
||||
|
||||
// These fields store a callback to notify the client that a frame is ready for presentation. If
|
||||
// !frameScheduled.callback, then the Metal backend automatically calls presentDrawable when the
|
||||
// frame is committed. Otherwise, the Metal backend will not automatically present the frame.
|
||||
@@ -341,6 +350,8 @@ public:
|
||||
|
||||
void setUpRenderPassAttachments(MTLRenderPassDescriptor* descriptor, const RenderPassParams& params);
|
||||
|
||||
bool involvesAbandonedSwapChain() const noexcept;
|
||||
|
||||
MTLViewport getViewportFromClientViewport(
|
||||
Viewport rect, float depthRangeNear, float depthRangeFar) {
|
||||
const int32_t height = int32_t(getAttachmentSize().y);
|
||||
|
||||
@@ -69,8 +69,10 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
|
||||
return MTLTextureUsage(u);
|
||||
}
|
||||
|
||||
MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags)
|
||||
MetalSwapChain::MetalSwapChain(
|
||||
MetalContext& context, PlatformMetal& platform, CAMetalLayer* nativeWindow, uint64_t flags)
|
||||
: context(context),
|
||||
platform(platform),
|
||||
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||
layer(nativeWindow),
|
||||
layerDrawableMutex(std::make_shared<std::mutex>()),
|
||||
@@ -94,15 +96,19 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
|
||||
layer.device = context.device;
|
||||
}
|
||||
|
||||
MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags)
|
||||
MetalSwapChain::MetalSwapChain(MetalContext& context, PlatformMetal& platform, int32_t width,
|
||||
int32_t height, uint64_t flags)
|
||||
: context(context),
|
||||
platform(platform),
|
||||
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||
headlessWidth(width),
|
||||
headlessHeight(height),
|
||||
type(SwapChainType::HEADLESS) {}
|
||||
|
||||
MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags)
|
||||
MetalSwapChain::MetalSwapChain(MetalContext& context, PlatformMetal& platform,
|
||||
CVPixelBufferRef pixelBuffer, uint64_t flags)
|
||||
: context(context),
|
||||
platform(platform),
|
||||
depthStencilFormat(decideDepthStencilFormat(flags)),
|
||||
externalImage(MetalExternalImage::createFromImage(context, pixelBuffer)),
|
||||
type(SwapChainType::CVPIXELBUFFERREF) {
|
||||
@@ -140,6 +146,10 @@ NSUInteger MetalSwapChain::getSurfaceHeight() const {
|
||||
return (NSUInteger) layer.drawableSize.height;
|
||||
}
|
||||
|
||||
bool MetalSwapChain::isAbandoned() const {
|
||||
return context.currentFrame < abandonedUntilFrame;
|
||||
}
|
||||
|
||||
id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
if (drawable) {
|
||||
return drawable.texture;
|
||||
@@ -180,7 +190,18 @@ id<MTLTexture> MetalSwapChain::acquireDrawable() {
|
||||
drawable = [layer nextDrawable];
|
||||
}
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(drawable != nil) << "Could not obtain drawable.";
|
||||
if (UTILS_UNLIKELY(drawable == nil)) {
|
||||
switch (platform.getDrawableFailureBehavior()) {
|
||||
case PlatformMetal::DrawableFailureBehavior::PANIC:
|
||||
FILAMENT_CHECK_POSTCONDITION(drawable != nil) << "Could not obtain drawable.";
|
||||
break;
|
||||
|
||||
case PlatformMetal::DrawableFailureBehavior::ABORT_FRAME:
|
||||
abandonedUntilFrame = context.currentFrame + 1;
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return drawable.texture;
|
||||
}
|
||||
|
||||
@@ -1117,12 +1138,20 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc
|
||||
}
|
||||
}
|
||||
|
||||
bool MetalRenderTarget::involvesAbandonedSwapChain() const noexcept {
|
||||
const auto* draw = context->currentDrawSwapChain;
|
||||
const auto* read = context->currentReadSwapChain;
|
||||
return (draw && draw->isAbandoned()) || (read && read->isAbandoned());
|
||||
}
|
||||
|
||||
MetalRenderTarget::Attachment MetalRenderTarget::getDrawColorAttachment(size_t index) {
|
||||
assert_invariant(index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT);
|
||||
Attachment result = color[index];
|
||||
if (index == 0 && defaultRenderTarget) {
|
||||
assert_invariant(context->currentDrawSwapChain);
|
||||
result.texture = context->currentDrawSwapChain->acquireDrawable();
|
||||
// acquireDrawable may fail to acquire the drawable, in which case result.texture will be
|
||||
// nil, and an invalid attachment
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1133,6 +1162,8 @@ MetalRenderTarget::Attachment MetalRenderTarget::getReadColorAttachment(size_t i
|
||||
if (index == 0 && defaultRenderTarget) {
|
||||
assert_invariant(context->currentReadSwapChain);
|
||||
result.texture = context->currentReadSwapChain->acquireDrawable();
|
||||
// acquireDrawable may fail to acquire the drawable, in which case result.texture will be
|
||||
// nil, and an invalid attachment
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MetalPlatform.h"
|
||||
#include <backend/platforms/PlatformMetal.h>
|
||||
|
||||
#include "MetalDriverFactory.h"
|
||||
|
||||
@@ -22,19 +22,32 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
struct PlatformMetalImpl {
|
||||
id<MTLCommandQueue> mCommandQueue = nil;
|
||||
// read form driver thread, read/written to from client thread
|
||||
std::atomic<PlatformMetal::DrawableFailureBehavior> mDrawableFailureBehavior =
|
||||
PlatformMetal::DrawableFailureBehavior::PANIC;
|
||||
};
|
||||
|
||||
Platform* createDefaultMetalPlatform() {
|
||||
return new MetalPlatform();
|
||||
return new PlatformMetal();
|
||||
}
|
||||
|
||||
MetalPlatform::~MetalPlatform() = default;
|
||||
PlatformMetal::PlatformMetal() : pImpl(new PlatformMetalImpl) {}
|
||||
|
||||
Driver* MetalPlatform::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
PlatformMetal::~PlatformMetal() noexcept {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept {
|
||||
return MetalDriverFactory::create(this, driverConfig);
|
||||
}
|
||||
|
||||
id<MTLDevice> MetalPlatform::createDevice() noexcept {
|
||||
id<MTLDevice> PlatformMetal::createDevice() noexcept {
|
||||
id<MTLDevice> result;
|
||||
|
||||
#if !defined(FILAMENT_IOS)
|
||||
@@ -62,16 +75,24 @@ id<MTLDevice> MetalPlatform::createDevice() noexcept {
|
||||
return result;
|
||||
}
|
||||
|
||||
id<MTLCommandQueue> MetalPlatform::createCommandQueue(id<MTLDevice> device) noexcept {
|
||||
mCommandQueue = [device newCommandQueue];
|
||||
mCommandQueue.label = @"Filament";
|
||||
return mCommandQueue;
|
||||
id<MTLCommandQueue> PlatformMetal::createCommandQueue(id<MTLDevice> device) noexcept {
|
||||
pImpl->mCommandQueue = [device newCommandQueue];
|
||||
pImpl->mCommandQueue.label = @"Filament";
|
||||
return pImpl->mCommandQueue;
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> MetalPlatform::createAndEnqueueCommandBuffer() noexcept {
|
||||
id<MTLCommandBuffer> commandBuffer = [mCommandQueue commandBuffer];
|
||||
id<MTLCommandBuffer> PlatformMetal::createAndEnqueueCommandBuffer() noexcept {
|
||||
id<MTLCommandBuffer> commandBuffer = [pImpl->mCommandQueue commandBuffer];
|
||||
[commandBuffer enqueue];
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept {
|
||||
pImpl->mDrawableFailureBehavior = behavior;
|
||||
}
|
||||
|
||||
PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept {
|
||||
return pImpl->mDrawableFailureBehavior;
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
@@ -161,13 +161,24 @@ public:
|
||||
return mProtectedMemorySupported;
|
||||
}
|
||||
|
||||
inline bool isImageView2DOn3DImageSupported() const noexcept {
|
||||
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
|
||||
}
|
||||
|
||||
private:
|
||||
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
|
||||
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
};
|
||||
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 mDebugUtilsSupported = false;
|
||||
|
||||
@@ -198,11 +198,20 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.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.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
}
|
||||
if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
||||
} else if (target == SamplerType::SAMPLER_2D_ARRAY) {
|
||||
imageInfo.arrayLayers = depth;
|
||||
imageInfo.extent.depth = 1;
|
||||
// NOTE: We do not use VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT here because:
|
||||
|
||||
@@ -84,6 +84,13 @@ FixedCapacityVector<const char*> getEnabledLayers() {
|
||||
}
|
||||
#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) {
|
||||
// Print some driver or MoltenVK information if it is available.
|
||||
if (vkGetPhysicalDeviceProperties2) {
|
||||
@@ -92,8 +99,8 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
|
||||
};
|
||||
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &driverProperties,
|
||||
};
|
||||
chainStruct(&physicalDeviceProperties2, &driverProperties);
|
||||
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
|
||||
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
|
||||
<< driverProperties.driverInfo << utils::io::endl;
|
||||
@@ -194,7 +201,7 @@ 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
|
||||
// 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,
|
||||
@@ -231,7 +238,9 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
|
||||
|
||||
VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
VkInstance instance;
|
||||
VkInstanceCreateInfo instanceCreateInfo = {};
|
||||
VkInstanceCreateInfo instanceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
};
|
||||
bool validationFeaturesSupported = false;
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
|
||||
@@ -282,7 +291,6 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
appInfo.pEngineName = "Filament";
|
||||
appInfo.apiVersion
|
||||
= 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.enabledExtensionCount = enabledExtensionCount;
|
||||
instanceCreateInfo.ppEnabledExtensionNames = ppEnabledExtensions;
|
||||
@@ -290,16 +298,17 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||
}
|
||||
|
||||
VkValidationFeaturesEXT features = {};
|
||||
VkValidationFeaturesEXT features = {
|
||||
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
|
||||
};
|
||||
VkValidationFeatureEnableEXT enables[] = {
|
||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
|
||||
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
|
||||
};
|
||||
if (validationFeaturesSupported) {
|
||||
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
|
||||
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
|
||||
features.pEnabledValidationFeatures = enables;
|
||||
instanceCreateInfo.pNext = &features;
|
||||
chainStruct(&instanceCreateInfo, &features);
|
||||
}
|
||||
|
||||
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
|
||||
@@ -310,11 +319,13 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
|
||||
|
||||
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
|
||||
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions) {
|
||||
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
|
||||
bool requestImageView2DOn3DImage) {
|
||||
VkDevice device;
|
||||
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
|
||||
const float queuePriority[] = {1.0f};
|
||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
||||
float queuePriority[] = {1.0f};
|
||||
VkDeviceCreateInfo deviceCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
};
|
||||
FixedCapacityVector<const char*> requestExtensions;
|
||||
requestExtensions.reserve(deviceExtensions.size() + 1);
|
||||
|
||||
@@ -323,6 +334,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
for (auto const& ext: deviceExtensions) {
|
||||
requestExtensions.push_back(ext.data());
|
||||
}
|
||||
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
|
||||
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
|
||||
deviceQueueCreateInfo[0].queueCount = 1;
|
||||
@@ -334,7 +346,6 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
deviceQueueCreateInfo[1].queueCount = 1;
|
||||
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority[0];
|
||||
|
||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
bool const hasProtectedQueue = protectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX;
|
||||
deviceCreateInfo.queueCreateInfoCount = hasProtectedQueue ? 2 : 1;
|
||||
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
|
||||
@@ -353,42 +364,36 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
|
||||
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
|
||||
|
||||
void* pNext = nullptr;
|
||||
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.imageViewFormatSwizzle = VK_TRUE,
|
||||
.mutableComparisonSamplers = VK_TRUE,
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
|
||||
.imageViewFormatSwizzle = VK_TRUE,
|
||||
.mutableComparisonSamplers = VK_TRUE,
|
||||
.imageView2DOn3DImage = requestImageView2DOn3DImage ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||
portability.pNext = pNext;
|
||||
pNext = &portability;
|
||||
chainStruct(&deviceCreateInfo, &portability);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.multiview = VK_TRUE,
|
||||
.multiviewGeometryShader = VK_FALSE,
|
||||
.multiviewTessellationShader = VK_FALSE
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
|
||||
.pNext = nullptr,
|
||||
.multiview = VK_TRUE,
|
||||
.multiviewGeometryShader = VK_FALSE,
|
||||
.multiviewTessellationShader = VK_FALSE,
|
||||
};
|
||||
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
|
||||
multiview.pNext = pNext;
|
||||
pNext = &multiview;
|
||||
chainStruct(&deviceCreateInfo, &multiview);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
|
||||
.protectedMemory = VK_TRUE,
|
||||
};
|
||||
if (hasProtectedQueue) {
|
||||
// Enable protected memory, if requested.
|
||||
protectedMemory.protectedMemory = VK_TRUE;
|
||||
protectedMemory.pNext = pNext;
|
||||
pNext = &protectedMemory;
|
||||
chainStruct(&deviceCreateInfo, &protectedMemory);
|
||||
}
|
||||
|
||||
deviceCreateInfo.pNext = pNext;
|
||||
|
||||
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
|
||||
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
|
||||
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
|
||||
@@ -501,7 +506,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
|
||||
// Does the device have any command queues that support graphics?
|
||||
// In theory, we should also ensure that the device supports presentation of our
|
||||
// particular VkSurface, but we don't have a VkSurface yet, so we'll skip this requirement.
|
||||
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
|
||||
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
|
||||
== INVALID_VK_INDEX) {
|
||||
continue;
|
||||
}
|
||||
@@ -721,14 +726,11 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
VkPhysicalDeviceProtectedMemoryFeatures queryProtectedMemoryFeatures = {
|
||||
.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 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
|
||||
};
|
||||
protectedMemoryProperties.pNext = context.mPhysicalDeviceProperties.pNext;
|
||||
context.mPhysicalDeviceProperties.pNext = &protectedMemoryProperties;
|
||||
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
|
||||
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
|
||||
|
||||
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
|
||||
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
|
||||
@@ -738,17 +740,17 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
|
||||
mImpl->mGraphicsQueueFamilyIndex
|
||||
= mImpl->mGraphicsQueueFamilyIndex == INVALID_VK_INDEX
|
||||
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
|
||||
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
|
||||
VK_QUEUE_GRAPHICS_BIT)
|
||||
: mImpl->mGraphicsQueueFamilyIndex;
|
||||
assert_invariant(mImpl->mGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
|
||||
|
||||
// We know we need to allocate the protected version of the VK objects
|
||||
context.mProtectedMemorySupported =
|
||||
context.mProtectedMemorySupported =
|
||||
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
|
||||
if (context.mProtectedMemorySupported) {
|
||||
mImpl->mProtectedGraphicsQueueFamilyIndex
|
||||
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
|
||||
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
|
||||
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
|
||||
assert_invariant(mImpl->mProtectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
|
||||
}
|
||||
@@ -768,7 +770,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
|
||||
// Applying the same logic to the protected queue index (Not sure about shared context and protection)
|
||||
mImpl->mProtectedGraphicsQueueIndex
|
||||
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
|
||||
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
|
||||
mImpl->mProtectedGraphicsQueueIndex;
|
||||
|
||||
ExtensionSet deviceExts;
|
||||
@@ -785,11 +787,24 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
|
||||
}
|
||||
}
|
||||
|
||||
mImpl->mDevice
|
||||
= mImpl->mDevice == VK_NULL_HANDLE ? createLogicalDevice(mImpl->mPhysicalDevice,
|
||||
context.mPhysicalDeviceFeatures, mImpl->mGraphicsQueueFamilyIndex,
|
||||
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts)
|
||||
: mImpl->mDevice;
|
||||
bool requestPortabilitySubsetImageView2DOn3DImage = false;
|
||||
if (setContains(deviceExts, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
|
||||
// We are on a non-conformant vulkan implementation so we need to ascertain if the features
|
||||
// we need are available.
|
||||
|
||||
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);
|
||||
|
||||
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,
|
||||
|
||||
@@ -689,11 +689,9 @@ public:
|
||||
bool use_shadow_atlas = false;
|
||||
} shadows;
|
||||
struct {
|
||||
#ifndef NDEBUG
|
||||
bool assert_material_instance_in_use = true;
|
||||
#else
|
||||
// TODO: default the following two flags to true.
|
||||
bool assert_material_instance_in_use = false;
|
||||
#endif
|
||||
bool assert_destroy_material_before_material_instance = false;
|
||||
} debug;
|
||||
} engine;
|
||||
struct {
|
||||
@@ -720,7 +718,10 @@ public:
|
||||
&features.engine.shadows.use_shadow_atlas, false },
|
||||
{ "features.engine.debug.assert_material_instance_in_use",
|
||||
"Assert when a MaterialInstance is destroyed while it is in use by RenderableManager.",
|
||||
&features.engine.debug.assert_material_instance_in_use, false }
|
||||
&features.engine.debug.assert_material_instance_in_use, false },
|
||||
{ "features.engine.debug.assert_destroy_material_before_material_instance",
|
||||
"Assert when a Material is destroyed but its instances are still alive.",
|
||||
&features.engine.debug.assert_destroy_material_before_material_instance, false },
|
||||
}};
|
||||
|
||||
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
|
||||
|
||||
@@ -383,9 +383,14 @@ void FMaterial::terminate(FEngine& engine) {
|
||||
auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList();
|
||||
auto pos = materialInstanceResourceList.find(this);
|
||||
if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) {
|
||||
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
if (engine.features.engine.debug.assert_destroy_material_before_material_instance) {
|
||||
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
|
||||
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
} else {
|
||||
utils::slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but "
|
||||
<< pos->second.size() << " instances still alive.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1351,8 +1351,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
}
|
||||
|
||||
if (hasFXAA) {
|
||||
bool const preserveAlphaChannel = needsAlphaChannel ||
|
||||
(hasColorGrading && colorGradingConfig.outputLuminance);
|
||||
bool const preserveAlphaChannel =
|
||||
// we're transparent -- alpha channel has user data
|
||||
needsAlphaChannel ||
|
||||
// the color-grading pass outputted the luminance channel, and we have an upscaling pass
|
||||
(hasColorGrading && colorGradingConfig.outputLuminance && scaled);
|
||||
input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat, preserveAlphaChannel);
|
||||
// the padded buffer is resolved now
|
||||
xvp.left = xvp.bottom = 0;
|
||||
|
||||
@@ -16,7 +16,7 @@ material {
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : fxaa
|
||||
name : outputLuminance
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
@@ -110,10 +110,10 @@ void postProcess(inout PostProcessInputs postProcess) {
|
||||
color = dither(color, materialParams.temporalNoise);
|
||||
}
|
||||
|
||||
// kill alpha computations when opaque / fxaa luminance
|
||||
// kill alpha computations when opaque / luminance
|
||||
#if POST_PROCESS_OPAQUE
|
||||
color.a = 1.0;
|
||||
if (materialParams.fxaa > 0) {
|
||||
if (materialParams.outputLuminance > 0) {
|
||||
color.a = luminance(color.rgb);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.56.7"
|
||||
spec.version = "1.56.8"
|
||||
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.7/filament-v1.56.7-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.8/filament-v1.56.8-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.56.7",
|
||||
"version": "1.56.8",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user