Support stencil buffer when post-processing is disabled (#7227)
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user