Commit 5e7b1c41 by Le Hoang Quyen Committed by Commit Bot

Metal: Create a dedicated class for Window Surface.

To distinguish it from PBuffer class in future. Bug: angleproject:2634 Change-Id: I1e256a74584fb001158465cd3068925847231984 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2281795 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 249db6da
...@@ -161,7 +161,7 @@ SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state, ...@@ -161,7 +161,7 @@ SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window, EGLNativeWindowType window,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
return new SurfaceMtl(this, state, window, attribs); return new WindowSurfaceMtl(this, state, window, attribs);
} }
SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state, SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state,
......
...@@ -29,7 +29,6 @@ class SurfaceMtl : public SurfaceImpl ...@@ -29,7 +29,6 @@ class SurfaceMtl : public SurfaceImpl
public: public:
SurfaceMtl(DisplayMtl *display, SurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state, const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs); const egl::AttributeMap &attribs);
~SurfaceMtl() override; ~SurfaceMtl() override;
...@@ -59,7 +58,6 @@ class SurfaceMtl : public SurfaceImpl ...@@ -59,7 +58,6 @@ class SurfaceMtl : public SurfaceImpl
void setFixedWidth(EGLint width) override; void setFixedWidth(EGLint width) override;
void setFixedHeight(EGLint height) override; void setFixedHeight(EGLint height) override;
// width and height can change with client window resizing
EGLint getWidth() const override; EGLint getWidth() const override;
EGLint getHeight() const override; EGLint getHeight() const override;
...@@ -72,21 +70,15 @@ class SurfaceMtl : public SurfaceImpl ...@@ -72,21 +70,15 @@ class SurfaceMtl : public SurfaceImpl
GLsizei samples, GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override; FramebufferAttachmentRenderTarget **rtOut) override;
private: protected:
angle::Result swapImpl(const gl::Context *context); // Ensure companion (depth, stencil) textures' size is correct w.r.t color texture.
angle::Result ensureRenderTargetsCreated(const gl::Context *context);
angle::Result obtainNextDrawable(const gl::Context *context);
angle::Result ensureDepthStencilSizeCorrect(const gl::Context *context, angle::Result ensureDepthStencilSizeCorrect(const gl::Context *context,
gl::Framebuffer::DirtyBits *fboDirtyBits); gl::Framebuffer::DirtyBits *fboDirtyBits);
// Check if metal layer has been resized.
void checkIfLayerResized();
mtl::AutoObjCObj<CAMetalLayer> mMetalLayer = nil; mtl::TextureRef mColorTexture;
CALayer *mLayer;
mtl::AutoObjCPtr<id<CAMetalDrawable>> mCurrentDrawable = nil;
mtl::TextureRef mDrawableTexture;
mtl::TextureRef mDepthTexture; mtl::TextureRef mDepthTexture;
mtl::TextureRef mStencilTexture; mtl::TextureRef mStencilTexture;
bool mUsePackedDepthStencil = false; bool mUsePackedDepthStencil = false;
mtl::Format mColorFormat; mtl::Format mColorFormat;
...@@ -98,6 +90,49 @@ class SurfaceMtl : public SurfaceImpl ...@@ -98,6 +90,49 @@ class SurfaceMtl : public SurfaceImpl
RenderTargetMtl mStencilRenderTarget; RenderTargetMtl mStencilRenderTarget;
}; };
class WindowSurfaceMtl : public SurfaceMtl
{
public:
WindowSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs);
~WindowSurfaceMtl() override;
void destroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
egl::Error makeCurrent(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
EGLint getSwapBehavior() const override;
// width and height can change with client window resizing
EGLint getWidth() const override;
EGLint getHeight() const override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
private:
angle::Result swapImpl(const gl::Context *context);
angle::Result ensureRenderTargetsCreated(const gl::Context *context);
angle::Result obtainNextDrawable(const gl::Context *context);
// Check if metal layer has been resized.
void checkIfLayerResized();
mtl::AutoObjCObj<CAMetalLayer> mMetalLayer = nil;
CALayer *mLayer;
mtl::AutoObjCPtr<id<CAMetalDrawable>> mCurrentDrawable = nil;
};
} // namespace rx } // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */ #endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */
...@@ -31,6 +31,16 @@ namespace rx ...@@ -31,6 +31,16 @@ namespace rx
namespace namespace
{ {
#define ANGLE_TO_EGL_TRY(EXPR) \
do \
{ \
if (ANGLE_UNLIKELY((EXPR) != angle::Result::Continue)) \
{ \
return egl::EglBadSurface(); \
} \
} while (0)
constexpr angle::FormatID kDefaultFrameBufferDepthFormatId = angle::FormatID::D32_FLOAT; constexpr angle::FormatID kDefaultFrameBufferDepthFormatId = angle::FormatID::D32_FLOAT;
constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT; constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT;
constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId = constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId =
...@@ -169,13 +179,12 @@ void StopFrameCapture() ...@@ -169,13 +179,12 @@ void StopFrameCapture()
} }
} }
// SurfaceMtl implementation
SurfaceMtl::SurfaceMtl(DisplayMtl *display, SurfaceMtl::SurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state, const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
: SurfaceImpl(state), mLayer((__bridge CALayer *)(window)) : SurfaceImpl(state)
{ {
// NOTE(hqle): Width and height attributes is ignored for now.
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf says that BGRA8Unorm is // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf says that BGRA8Unorm is
// only supported if depth24Stencil8PixelFormatSupported capabilitiy is YES. Yet // only supported if depth24Stencil8PixelFormatSupported capabilitiy is YES. Yet
...@@ -222,76 +231,30 @@ SurfaceMtl::~SurfaceMtl() {} ...@@ -222,76 +231,30 @@ SurfaceMtl::~SurfaceMtl() {}
void SurfaceMtl::destroy(const egl::Display *display) void SurfaceMtl::destroy(const egl::Display *display)
{ {
mDrawableTexture = nullptr; mColorTexture = nullptr;
mDepthTexture = nullptr; mDepthTexture = nullptr;
mStencilTexture = nullptr; mStencilTexture = nullptr;
mCurrentDrawable = nil;
if (mMetalLayer && mMetalLayer.get() != mLayer) mColorRenderTarget.reset();
{ mDepthRenderTarget.reset();
// If we created metal layer in SurfaceMtl::initialize(), mStencilRenderTarget.reset();
// we need to detach it from super layer now.
[mMetalLayer.get() removeFromSuperlayer];
}
mMetalLayer = nil;
} }
egl::Error SurfaceMtl::initialize(const egl::Display *display) egl::Error SurfaceMtl::initialize(const egl::Display *display)
{ {
DisplayMtl *displayMtl = mtl::GetImpl(display);
id<MTLDevice> metalDevice = displayMtl->getMetalDevice();
StartFrameCapture(metalDevice, displayMtl->cmdQueue().get());
ANGLE_MTL_OBJC_SCOPE
{
if ([mLayer isKindOfClass:CAMetalLayer.class])
{
mMetalLayer.retainAssign(static_cast<CAMetalLayer *>(mLayer));
}
else
{
mMetalLayer = [[[CAMetalLayer alloc] init] ANGLE_MTL_AUTORELEASE];
mMetalLayer.get().frame = mLayer.frame;
}
mMetalLayer.get().device = metalDevice;
mMetalLayer.get().pixelFormat = mColorFormat.metalFormat;
mMetalLayer.get().framebufferOnly = NO; // This to allow readPixels
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
// Autoresize with parent layer.
mMetalLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
#endif
if (mMetalLayer.get() != mLayer)
{
mMetalLayer.get().contentsScale = mLayer.contentsScale;
[mLayer addSublayer:mMetalLayer.get()];
}
// ensure drawableSize is set to correct value:
checkIfLayerResized();
}
return egl::NoError(); return egl::NoError();
} }
FramebufferImpl *SurfaceMtl::createDefaultFramebuffer(const gl::Context *context, FramebufferImpl *SurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) const gl::FramebufferState &state)
{ {
auto fbo = new FramebufferMtl(state, /* flipY */ true); auto fbo = new FramebufferMtl(state, /* flipY */ false);
return fbo; return fbo;
} }
egl::Error SurfaceMtl::makeCurrent(const gl::Context *context) egl::Error SurfaceMtl::makeCurrent(const gl::Context *context)
{ {
angle::Result result = obtainNextDrawable(context);
if (result != angle::Result::Continue)
{
return egl::EglBadCurrentSurface();
}
return egl::NoError(); return egl::NoError();
} }
...@@ -302,13 +265,6 @@ egl::Error SurfaceMtl::unMakeCurrent(const gl::Context *context) ...@@ -302,13 +265,6 @@ egl::Error SurfaceMtl::unMakeCurrent(const gl::Context *context)
egl::Error SurfaceMtl::swap(const gl::Context *context) egl::Error SurfaceMtl::swap(const gl::Context *context)
{ {
angle::Result result = swapImpl(context);
if (result != angle::Result::Continue)
{
return egl::EglBadSurface();
}
return egl::NoError(); return egl::NoError();
} }
...@@ -364,31 +320,20 @@ void SurfaceMtl::setFixedHeight(EGLint height) ...@@ -364,31 +320,20 @@ void SurfaceMtl::setFixedHeight(EGLint height)
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
// width and height can change with client window resizing
EGLint SurfaceMtl::getWidth() const EGLint SurfaceMtl::getWidth() const
{ {
if (mDrawableTexture) if (mColorTexture)
{ {
return static_cast<EGLint>(mDrawableTexture->width()); return static_cast<EGLint>(mColorTexture->width());
}
if (mMetalLayer)
{
return static_cast<EGLint>(mMetalLayer.get().drawableSize.width);
} }
return 0; return 0;
} }
EGLint SurfaceMtl::getHeight() const EGLint SurfaceMtl::getHeight() const
{ {
if (mDrawableTexture) if (mColorTexture)
{
return static_cast<EGLint>(mDrawableTexture->height());
}
if (mMetalLayer)
{ {
return static_cast<EGLint>(mMetalLayer.get().drawableSize.height); return static_cast<EGLint>(mColorTexture->height());
} }
return 0; return 0;
} }
...@@ -400,7 +345,7 @@ EGLint SurfaceMtl::isPostSubBufferSupported() const ...@@ -400,7 +345,7 @@ EGLint SurfaceMtl::isPostSubBufferSupported() const
EGLint SurfaceMtl::getSwapBehavior() const EGLint SurfaceMtl::getSwapBehavior() const
{ {
return EGL_BUFFER_DESTROYED; return EGL_BUFFER_PRESERVED;
} }
angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
...@@ -409,8 +354,7 @@ angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, ...@@ -409,8 +354,7 @@ angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
GLsizei samples, GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
// NOTE(hqle): Support MSAA. ASSERT(mColorTexture);
ANGLE_TRY(ensureRenderTargetsCreated(context));
switch (binding) switch (binding)
{ {
...@@ -432,23 +376,13 @@ angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, ...@@ -432,23 +376,13 @@ angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result SurfaceMtl::ensureRenderTargetsCreated(const gl::Context *context)
{
if (!mDrawableTexture)
{
ANGLE_TRY(obtainNextDrawable(context));
}
return angle::Result::Continue;
}
angle::Result SurfaceMtl::ensureDepthStencilSizeCorrect(const gl::Context *context, angle::Result SurfaceMtl::ensureDepthStencilSizeCorrect(const gl::Context *context,
gl::Framebuffer::DirtyBits *fboDirtyBits) gl::Framebuffer::DirtyBits *fboDirtyBits)
{ {
ASSERT(mDrawableTexture && mDrawableTexture->get()); ASSERT(mColorTexture && mColorTexture->get());
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
auto size = mDrawableTexture->size(); auto size = mColorTexture->size();
if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size)) if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size))
{ {
...@@ -478,7 +412,155 @@ angle::Result SurfaceMtl::ensureDepthStencilSizeCorrect(const gl::Context *conte ...@@ -478,7 +412,155 @@ angle::Result SurfaceMtl::ensureDepthStencilSizeCorrect(const gl::Context *conte
return angle::Result::Continue; return angle::Result::Continue;
} }
void SurfaceMtl::checkIfLayerResized() // WindowSurfaceMtl implementation.
WindowSurfaceMtl::WindowSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs)
: SurfaceMtl(display, state, attribs), mLayer((__bridge CALayer *)(window))
{}
WindowSurfaceMtl::~WindowSurfaceMtl() {}
void WindowSurfaceMtl::destroy(const egl::Display *display)
{
SurfaceMtl::destroy(display);
mCurrentDrawable = nil;
if (mMetalLayer && mMetalLayer.get() != mLayer)
{
// If we created metal layer in WindowSurfaceMtl::initialize(),
// we need to detach it from super layer now.
[mMetalLayer.get() removeFromSuperlayer];
}
mMetalLayer = nil;
}
egl::Error WindowSurfaceMtl::initialize(const egl::Display *display)
{
egl::Error re = SurfaceMtl::initialize(display);
if (re.isError())
{
return re;
}
DisplayMtl *displayMtl = mtl::GetImpl(display);
id<MTLDevice> metalDevice = displayMtl->getMetalDevice();
StartFrameCapture(metalDevice, displayMtl->cmdQueue().get());
ANGLE_MTL_OBJC_SCOPE
{
if ([mLayer isKindOfClass:CAMetalLayer.class])
{
mMetalLayer.retainAssign(static_cast<CAMetalLayer *>(mLayer));
}
else
{
mMetalLayer = [[[CAMetalLayer alloc] init] ANGLE_MTL_AUTORELEASE];
mMetalLayer.get().frame = mLayer.frame;
}
mMetalLayer.get().device = metalDevice;
mMetalLayer.get().pixelFormat = mColorFormat.metalFormat;
mMetalLayer.get().framebufferOnly = NO; // Support blitting and glReadPixels
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
// Autoresize with parent layer.
mMetalLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
#endif
if (mMetalLayer.get() != mLayer)
{
mMetalLayer.get().contentsScale = mLayer.contentsScale;
[mLayer addSublayer:mMetalLayer.get()];
}
// ensure drawableSize is set to correct value:
checkIfLayerResized();
}
return egl::NoError();
}
FramebufferImpl *WindowSurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
auto fbo = new FramebufferMtl(state, /* flipY */ true);
return fbo;
}
egl::Error WindowSurfaceMtl::makeCurrent(const gl::Context *context)
{
ANGLE_TO_EGL_TRY(obtainNextDrawable(context));
return egl::NoError();
}
egl::Error WindowSurfaceMtl::swap(const gl::Context *context)
{
ANGLE_TO_EGL_TRY(swapImpl(context));
return egl::NoError();
}
// width and height can change with client window resizing
EGLint WindowSurfaceMtl::getWidth() const
{
if (mColorTexture)
{
return static_cast<EGLint>(mColorTexture->width());
}
if (mMetalLayer)
{
return static_cast<EGLint>(mMetalLayer.get().drawableSize.width);
}
return SurfaceMtl::getWidth();
}
EGLint WindowSurfaceMtl::getHeight() const
{
if (mColorTexture)
{
return static_cast<EGLint>(mColorTexture->height());
}
if (mMetalLayer)
{
return static_cast<EGLint>(mMetalLayer.get().drawableSize.height);
}
return SurfaceMtl::getHeight();
}
EGLint WindowSurfaceMtl::getSwapBehavior() const
{
return EGL_BUFFER_DESTROYED;
}
angle::Result WindowSurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
// NOTE(hqle): Support MSAA.
ANGLE_TRY(ensureRenderTargetsCreated(context));
return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
}
angle::Result WindowSurfaceMtl::ensureRenderTargetsCreated(const gl::Context *context)
{
if (!mColorTexture)
{
ANGLE_TRY(obtainNextDrawable(context));
}
return angle::Result::Continue;
}
void WindowSurfaceMtl::checkIfLayerResized()
{ {
CGSize currentDrawableSize = mMetalLayer.get().drawableSize; CGSize currentDrawableSize = mMetalLayer.get().drawableSize;
CGSize currentLayerSize = mMetalLayer.get().bounds.size; CGSize currentLayerSize = mMetalLayer.get().bounds.size;
...@@ -493,7 +575,7 @@ void SurfaceMtl::checkIfLayerResized() ...@@ -493,7 +575,7 @@ void SurfaceMtl::checkIfLayerResized()
} }
} }
angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context) angle::Result WindowSurfaceMtl::obtainNextDrawable(const gl::Context *context)
{ {
checkIfLayerResized(); checkIfLayerResized();
...@@ -505,9 +587,9 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context) ...@@ -505,9 +587,9 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context)
ANGLE_MTL_TRY(contextMtl, mMetalLayer); ANGLE_MTL_TRY(contextMtl, mMetalLayer);
if (mDrawableTexture) if (mColorTexture)
{ {
mDrawableTexture->set(nil); mColorTexture->set(nil);
} }
mCurrentDrawable = nil; mCurrentDrawable = nil;
...@@ -522,18 +604,18 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context) ...@@ -522,18 +604,18 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context)
mMetalLayer.get().allowsNextDrawableTimeout = YES; mMetalLayer.get().allowsNextDrawableTimeout = YES;
} }
if (!mDrawableTexture) if (!mColorTexture)
{ {
mDrawableTexture = mtl::Texture::MakeFromMetal(mCurrentDrawable.get().texture); mColorTexture = mtl::Texture::MakeFromMetal(mCurrentDrawable.get().texture);
mColorRenderTarget.set(mDrawableTexture, 0, 0, mColorFormat); mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
} }
else else
{ {
mDrawableTexture->set(mCurrentDrawable.get().texture); mColorTexture->set(mCurrentDrawable.get().texture);
} }
ANGLE_MTL_LOG("Current metal drawable size=%d,%d", mDrawableTexture->width(), ANGLE_MTL_LOG("Current metal drawable size=%d,%d", mColorTexture->width(),
mDrawableTexture->height()); mColorTexture->height());
gl::Framebuffer::DirtyBits fboDirtyBits; gl::Framebuffer::DirtyBits fboDirtyBits;
fboDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); fboDirtyBits.set(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
...@@ -556,7 +638,7 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context) ...@@ -556,7 +638,7 @@ angle::Result SurfaceMtl::obtainNextDrawable(const gl::Context *context)
} }
} }
angle::Result SurfaceMtl::swapImpl(const gl::Context *context) angle::Result WindowSurfaceMtl::swapImpl(const gl::Context *context)
{ {
ANGLE_TRY(ensureRenderTargetsCreated(context)); ANGLE_TRY(ensureRenderTargetsCreated(context));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment