Support stencil buffer when post-processing is disabled (#7227)

This commit is contained in:
Ben Doherty
2023-10-13 10:04:39 -07:00
committed by GitHub
parent fc6744ba75
commit 38ceee8d75
11 changed files with 130 additions and 35 deletions
+2 -1
View File
@@ -11,4 +11,5 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
- engine: Added parameter for configuring JobSystem thread count
- engine: In Java, introduce Engine.Builder
- engine: New tone mapper: `AgXTonemapper`.
- matinfo: Add support for viewing ESSL 1.0 shaders
- matinfo: Add support for viewing ESSL 1.0 shaders
- engine: Add support for stencil buffer when post-processing is disabled (Metal backend only).
@@ -103,6 +103,31 @@ public class SwapChain {
*/
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
/**
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
*
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
* the SwapChain (when post-processing is disabled).
*
* The specific format of the stencil buffer depends on platform support. The following pixel
* formats are tried, in order of preference:
*
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F
* - DEPTH24
*
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F_STENCIL8
* - DEPTH24F_STENCIL8
*
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
* necessary.
*
* @see View#setStencilBufferEnabled
* @see View#setPostProcessingEnabled
*/
public static final long CONFIG_HAS_STENCIL_BUFFER = 0x20;
SwapChain(long nativeSwapChain, Object surface) {
mNativeObject = nativeSwapChain;
mSurface = surface;
@@ -1032,7 +1032,8 @@ public class View {
* </p>
*
* <p>
* Post-processing must be enabled in order to use the stencil buffer.
* If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER
* flag set in order to use the stencil buffer.
* </p>
*
* <p>
@@ -77,6 +77,11 @@ static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
*/
static constexpr uint64_t SWAP_CHAIN_CONFIG_SRGB_COLORSPACE = 0x10;
/**
* Indicates that the SwapChain should also contain a stencil component.
*/
static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = 0x20;
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
+8 -3
View File
@@ -66,6 +66,7 @@ public:
id<MTLTexture> acquireDrawable();
id<MTLTexture> acquireDepthTexture();
id<MTLTexture> acquireStencilTexture();
void releaseDrawable();
@@ -94,12 +95,16 @@ private:
void scheduleFrameScheduledCallback();
void scheduleFrameCompletedCallback();
static MTLPixelFormat decideDepthStencilFormat(uint64_t flags);
void ensureDepthStencilTexture();
MetalContext& context;
id<CAMetalDrawable> drawable = nil;
id<MTLTexture> depthTexture = nil;
id<MTLTexture> depthStencilTexture = nil;
id<MTLTexture> headlessDrawable = nil;
NSUInteger headlessWidth;
NSUInteger headlessHeight;
MTLPixelFormat depthStencilFormat = MTLPixelFormatInvalid;
NSUInteger headlessWidth = 0;
NSUInteger headlessHeight = 0;
CAMetalLayer* layer = nullptr;
MetalExternalImage externalImage;
SwapChainType type;
+47 -28
View File
@@ -57,8 +57,11 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
}
MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags)
: context(context), layer(nativeWindow), externalImage(context),
type(SwapChainType::CAMETALLAYER) {
: context(context),
depthStencilFormat(decideDepthStencilFormat(flags)),
layer(nativeWindow),
externalImage(context),
type(SwapChainType::CAMETALLAYER) {
if (!(flags & SwapChain::CONFIG_TRANSPARENT) && !nativeWindow.opaque) {
utils::slog.w << "Warning: Filament SwapChain has no CONFIG_TRANSPARENT flag, "
@@ -79,17 +82,30 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
}
MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags)
: context(context), headlessWidth(width), headlessHeight(height), externalImage(context),
type(SwapChainType::HEADLESS) { }
: context(context),
depthStencilFormat(decideDepthStencilFormat(flags)),
headlessWidth(width),
headlessHeight(height),
externalImage(context),
type(SwapChainType::HEADLESS) {}
MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags)
: context(context), externalImage(context), type(SwapChainType::CVPIXELBUFFERREF) {
: context(context),
depthStencilFormat(decideDepthStencilFormat(flags)),
externalImage(context),
type(SwapChainType::CVPIXELBUFFERREF) {
assert_invariant(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
MetalExternalImage::assertWritableImage(pixelBuffer);
externalImage.set(pixelBuffer);
assert_invariant(externalImage.isValid());
}
MTLPixelFormat MetalSwapChain::decideDepthStencilFormat(uint64_t flags) {
// These formats are supported on all devices, both iOS and macOS.
return flags & SwapChain::CONFIG_HAS_STENCIL_BUFFER ? MTLPixelFormatDepth32Float_Stencil8
: MTLPixelFormatDepth32Float;
}
MetalSwapChain::~MetalSwapChain() {
externalImage.set(nullptr);
}
@@ -156,37 +172,40 @@ void MetalSwapChain::releaseDrawable() {
}
id<MTLTexture> MetalSwapChain::acquireDepthTexture() {
if (depthTexture) {
// If the surface size has changed, we'll need to allocate a new depth texture.
if (depthTexture.width != getSurfaceWidth() ||
depthTexture.height != getSurfaceHeight()) {
depthTexture = nil;
ensureDepthStencilTexture();
assert_invariant(depthStencilTexture);
return depthStencilTexture;
}
id<MTLTexture> MetalSwapChain::acquireStencilTexture() {
if (!isMetalFormatStencil(depthStencilFormat)) {
return nil;
}
ensureDepthStencilTexture();
assert_invariant(depthStencilTexture);
return depthStencilTexture;
}
void MetalSwapChain::ensureDepthStencilTexture() {
NSUInteger width = getSurfaceWidth();
NSUInteger height = getSurfaceHeight();
if (UTILS_LIKELY(depthStencilTexture)) {
// If the surface size has changed, we'll need to allocate a new depth/stencil texture.
if (UTILS_UNLIKELY(
depthStencilTexture.width != width || depthStencilTexture.height != height)) {
depthStencilTexture = nil;
} else {
return depthTexture;
return;
}
}
const MTLPixelFormat depthFormat =
#if defined(IOS)
MTLPixelFormatDepth32Float;
#else
context.device.depth24Stencil8PixelFormatSupported ?
MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float;
#endif
const NSUInteger width = getSurfaceWidth();
const NSUInteger height = getSurfaceHeight();
MTLTextureDescriptor* descriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:depthFormat
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:depthStencilFormat
width:width
height:height
mipmapped:NO];
descriptor.usage = MTLTextureUsageRenderTarget;
descriptor.resourceOptions = MTLResourceStorageModePrivate;
depthTexture = [context.device newTextureWithDescriptor:descriptor];
return depthTexture;
depthStencilTexture = [context.device newTextureWithDescriptor:descriptor];
}
void MetalSwapChain::setFrameScheduledCallback(FrameScheduledCallback callback, void* user) {
@@ -1123,7 +1142,7 @@ MetalRenderTarget::Attachment MetalRenderTarget::getDepthAttachment() {
MetalRenderTarget::Attachment MetalRenderTarget::getStencilAttachment() {
Attachment result = stencil;
if (defaultRenderTarget) {
// TODO: do we want the default SwapChain to have a default stencil buffer?
result.texture = context->currentDrawSwapChain->acquireStencilTexture();
}
return result;
}
+25
View File
@@ -201,6 +201,31 @@ public:
*/
static constexpr uint64_t CONFIG_SRGB_COLORSPACE = backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE;
/**
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
*
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
* the SwapChain (when post-processing is disabled).
*
* The specific format of the stencil buffer depends on platform support. The following pixel
* formats are tried, in order of preference:
*
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F
* - DEPTH24
*
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F_STENCIL8
* - DEPTH24F_STENCIL8
*
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
* necessary.
*
* @see View.setStencilBufferEnabled
* @see View.setPostProcessingEnabled
*/
static constexpr uint64_t CONFIG_HAS_STENCIL_BUFFER = backend::SWAP_CHAIN_HAS_STENCIL_BUFFER;
/**
* Return whether createSwapChain supports the SWAP_CHAIN_CONFIG_SRGB_COLORSPACE flag.
* The default implementation returns false.
+2 -1
View File
@@ -662,7 +662,8 @@ public:
* Material's stencil comparison function and reference value. Fragments that don't pass the
* stencil test are then discarded.
*
* Post-processing must be enabled in order to use the stencil buffer.
* If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER
* flag set in order to use the stencil buffer.
*
* A renderable's priority (see RenderableManager::setPriority) is useful to control the order
* in which primitives are drawn.
+7
View File
@@ -1095,6 +1095,13 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
}
}
if (UTILS_UNLIKELY(outputIsSwapChain && view.isStencilBufferEnabled())) {
assert_invariant(mSwapChain);
ASSERT_PRECONDITION(mSwapChain->hasStencilBuffer(),
"View has stencil buffer enabled, but SwapChain does not have "
"SwapChain::CONFIG_HAS_STENCIL_BUFFER flag set.");
}
// auto debug = structure
// fg.forwardResource(fgViewRenderTarget, debug ? debug : input);
+4
View File
@@ -58,6 +58,10 @@ public:
return (mConfigFlags & CONFIG_READABLE) != 0;
}
constexpr bool hasStencilBuffer() const noexcept {
return (mConfigFlags & CONFIG_HAS_STENCIL_BUFFER) != 0;
}
backend::Handle<backend::HwSwapChain> getHwHandle() const noexcept {
return mSwapChain;
}
+3 -1
View File
@@ -38,6 +38,7 @@
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/SwapChain.h>
#include <filament/View.h>
#ifndef NDEBUG
@@ -644,7 +645,8 @@ FilamentApp::Window::Window(FilamentApp* filamentApp,
mFilamentApp->mEngine->getSupportedFeatureLevel());
mFilamentApp->mEngine->setActiveFeatureLevel(config.featureLevel);
mSwapChain = mFilamentApp->mEngine->createSwapChain(nativeSwapChain);
mSwapChain = mFilamentApp->mEngine->createSwapChain(
nativeSwapChain, filament::SwapChain::CONFIG_HAS_STENCIL_BUFFER);
}
mRenderer = mFilamentApp->mEngine->createRenderer();