Metal: add config to abandon frame if drawable cannot be acquired (#8397)
This commit is contained in:
@@ -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
|
||||
|
||||
+29
-7
@@ -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) {
|
||||
@@ -1272,6 +1273,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()) {
|
||||
@@ -1333,6 +1341,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
|
||||
@@ -1633,6 +1645,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";
|
||||
|
||||
@@ -1917,6 +1934,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");
|
||||
@@ -1960,6 +1981,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;
|
||||
}
|
||||
|
||||
+32
-11
@@ -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
|
||||
Reference in New Issue
Block a user