1// 2// Copyright 2019 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// SurfaceMtl.mm: 7// Implements the class methods for SurfaceMtl. 8// 9 10#include "libANGLE/renderer/metal/SurfaceMtl.h" 11 12#include "common/platform.h" 13#include "libANGLE/Display.h" 14#include "libANGLE/Surface.h" 15#include "libANGLE/renderer/metal/ContextMtl.h" 16#include "libANGLE/renderer/metal/DisplayMtl.h" 17#include "libANGLE/renderer/metal/FrameBufferMtl.h" 18#include "libANGLE/renderer/metal/mtl_format_utils.h" 19#include "libANGLE/renderer/metal/mtl_utils.h" 20#include "mtl_command_buffer.h" 21 22// Compiler can turn on programmatical frame capture in release build by defining 23// ANGLE_METAL_FRAME_CAPTURE flag. 24#if defined(NDEBUG) && !defined(ANGLE_METAL_FRAME_CAPTURE) 25# define ANGLE_METAL_FRAME_CAPTURE_ENABLED 0 26#else 27# define ANGLE_METAL_FRAME_CAPTURE_ENABLED 1 28#endif 29 30namespace rx 31{ 32 33namespace 34{ 35 36constexpr angle::FormatID kDefaultFrameBufferDepthFormatId = angle::FormatID::D32_FLOAT; 37constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::S8_UINT; 38constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId = 39 angle::FormatID::D24_UNORM_S8_UINT; 40 41angle::Result CreateOrResizeTexture(const gl::Context *context, 42 const mtl::Format &format, 43 uint32_t width, 44 uint32_t height, 45 uint32_t samples, 46 bool renderTargetOnly, 47 mtl::TextureRef *textureOut) 48{ 49 ContextMtl *contextMtl = mtl::GetImpl(context); 50 bool allowFormatView = format.hasDepthAndStencilBits(); 51 if (*textureOut) 52 { 53 ANGLE_TRY((*textureOut)->resize(contextMtl, width, height)); 54 size_t resourceSize = EstimateTextureSizeInBytes(format, width, height, 1, samples, 1); 55 if (*textureOut) 56 { 57 (*textureOut)->setEstimatedByteSize(resourceSize); 58 } 59 } 60 else if (samples > 1) 61 { 62 ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples, 63 /** renderTargetOnly */ renderTargetOnly, 64 /** allowFormatView */ allowFormatView, 65 textureOut)); 66 } 67 else 68 { 69 ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, format, width, height, 1, 70 /** renderTargetOnly */ renderTargetOnly, 71 /** allowFormatView */ allowFormatView, textureOut)); 72 } 73 return angle::Result::Continue; 74} 75 76} // anonymous namespace 77 78// SurfaceMtl implementation 79SurfaceMtl::SurfaceMtl(DisplayMtl *display, 80 const egl::SurfaceState &state, 81 const egl::AttributeMap &attribs) 82 : SurfaceImpl(state) 83{ 84 mRobustResourceInit = 85 attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE; 86 mColorFormat = display->getPixelFormat(angle::FormatID::B8G8R8A8_UNORM); 87 88 mSamples = state.config->samples; 89 90 int depthBits = 0; 91 int stencilBits = 0; 92 if (state.config) 93 { 94 depthBits = state.config->depthSize; 95 stencilBits = state.config->stencilSize; 96 } 97 98 if (depthBits && stencilBits) 99 { 100 if (display->getFeatures().allowSeparateDepthStencilBuffers.enabled) 101 { 102 mDepthFormat = display->getPixelFormat(kDefaultFrameBufferDepthFormatId); 103 mStencilFormat = display->getPixelFormat(kDefaultFrameBufferStencilFormatId); 104 } 105 else 106 { 107 // We must use packed depth stencil 108 mUsePackedDepthStencil = true; 109 mDepthFormat = display->getPixelFormat(kDefaultFrameBufferDepthStencilFormatId); 110 mStencilFormat = mDepthFormat; 111 } 112 } 113 else if (depthBits) 114 { 115 mDepthFormat = display->getPixelFormat(kDefaultFrameBufferDepthFormatId); 116 } 117 else if (stencilBits) 118 { 119 mStencilFormat = display->getPixelFormat(kDefaultFrameBufferStencilFormatId); 120 } 121} 122 123SurfaceMtl::~SurfaceMtl() {} 124 125void SurfaceMtl::destroy(const egl::Display *display) 126{ 127 mColorTexture = nullptr; 128 mDepthTexture = nullptr; 129 mStencilTexture = nullptr; 130 131 mMSColorTexture = nullptr; 132 133 mColorRenderTarget.reset(); 134 mColorManualResolveRenderTarget.reset(); 135 mDepthRenderTarget.reset(); 136 mStencilRenderTarget.reset(); 137} 138 139egl::Error SurfaceMtl::initialize(const egl::Display *display) 140{ 141 return egl::NoError(); 142} 143 144egl::Error SurfaceMtl::makeCurrent(const gl::Context *context) 145{ 146 ContextMtl *contextMtl = mtl::GetImpl(context); 147 StartFrameCapture(contextMtl); 148 149 return egl::NoError(); 150} 151 152egl::Error SurfaceMtl::unMakeCurrent(const gl::Context *context) 153{ 154 ContextMtl *contextMtl = mtl::GetImpl(context); 155 contextMtl->flushCommandBuffer(mtl::WaitUntilScheduled); 156 157 StopFrameCapture(); 158 return egl::NoError(); 159} 160 161egl::Error SurfaceMtl::swap(const gl::Context *context) 162{ 163 return egl::NoError(); 164} 165 166egl::Error SurfaceMtl::postSubBuffer(const gl::Context *context, 167 EGLint x, 168 EGLint y, 169 EGLint width, 170 EGLint height) 171{ 172 UNIMPLEMENTED(); 173 return egl::EglBadAccess(); 174} 175 176egl::Error SurfaceMtl::querySurfacePointerANGLE(EGLint attribute, void **value) 177{ 178 UNIMPLEMENTED(); 179 return egl::EglBadAccess(); 180} 181 182egl::Error SurfaceMtl::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer) 183{ 184 UNIMPLEMENTED(); 185 return egl::EglBadAccess(); 186} 187 188egl::Error SurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer) 189{ 190 UNIMPLEMENTED(); 191 return egl::EglBadAccess(); 192} 193 194egl::Error SurfaceMtl::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) 195{ 196 UNIMPLEMENTED(); 197 return egl::EglBadAccess(); 198} 199 200egl::Error SurfaceMtl::getMscRate(EGLint *numerator, EGLint *denominator) 201{ 202 UNIMPLEMENTED(); 203 return egl::EglBadAccess(); 204} 205 206void SurfaceMtl::setSwapInterval(const egl::Display *display, EGLint interval) {} 207 208void SurfaceMtl::setFixedWidth(EGLint width) 209{ 210 UNIMPLEMENTED(); 211} 212 213void SurfaceMtl::setFixedHeight(EGLint height) 214{ 215 UNIMPLEMENTED(); 216} 217 218EGLint SurfaceMtl::getWidth() const 219{ 220 if (mColorTexture) 221 { 222 return static_cast<EGLint>(mColorTexture->widthAt0()); 223 } 224 return 0; 225} 226 227EGLint SurfaceMtl::getHeight() const 228{ 229 if (mColorTexture) 230 { 231 return static_cast<EGLint>(mColorTexture->heightAt0()); 232 } 233 return 0; 234} 235 236EGLint SurfaceMtl::isPostSubBufferSupported() const 237{ 238 return EGL_FALSE; 239} 240 241EGLint SurfaceMtl::getSwapBehavior() const 242{ 243 // dEQP-EGL.functional.query_surface.* requires that for a surface with swap 244 // behavior=EGL_BUFFER_PRESERVED, config.surfaceType must contain 245 // EGL_SWAP_BEHAVIOR_PRESERVED_BIT. 246 // Since we don't support EGL_SWAP_BEHAVIOR_PRESERVED_BIT in egl::Config for now, let's just use 247 // EGL_BUFFER_DESTROYED as default swap behavior. 248 return EGL_BUFFER_DESTROYED; 249} 250 251angle::Result SurfaceMtl::initializeContents(const gl::Context *context, 252 GLenum binding, 253 const gl::ImageIndex &imageIndex) 254{ 255 ASSERT(mColorTexture); 256 257 ContextMtl *contextMtl = mtl::GetImpl(context); 258 259 // Use loadAction=clear 260 mtl::RenderPassDesc rpDesc; 261 rpDesc.rasterSampleCount = mColorTexture->samples(); 262 263 switch (binding) 264 { 265 case GL_BACK: 266 { 267 if (mColorTextureInitialized) 268 { 269 return angle::Result::Continue; 270 } 271 rpDesc.numColorAttachments = 1; 272 mColorRenderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]); 273 rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear; 274 MTLClearColor black = {}; 275 rpDesc.colorAttachments[0].clearColor = 276 mtl::EmulatedAlphaClearColor(black, mColorTexture->getColorWritableMask()); 277 mColorTextureInitialized = true; 278 break; 279 } 280 case GL_DEPTH: 281 case GL_STENCIL: 282 { 283 if (mDepthStencilTexturesInitialized) 284 { 285 return angle::Result::Continue; 286 } 287 if (mDepthTexture) 288 { 289 mDepthRenderTarget.toRenderPassAttachmentDesc(&rpDesc.depthAttachment); 290 rpDesc.depthAttachment.loadAction = MTLLoadActionClear; 291 } 292 if (mStencilTexture) 293 { 294 mStencilRenderTarget.toRenderPassAttachmentDesc(&rpDesc.stencilAttachment); 295 rpDesc.stencilAttachment.loadAction = MTLLoadActionClear; 296 } 297 mDepthStencilTexturesInitialized = true; 298 break; 299 } 300 default: 301 UNREACHABLE(); 302 break; 303 } 304 mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(rpDesc); 305 encoder->setStoreAction(MTLStoreActionStore); 306 307 return angle::Result::Continue; 308} 309 310angle::Result SurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, 311 GLenum binding, 312 const gl::ImageIndex &imageIndex, 313 GLsizei samples, 314 FramebufferAttachmentRenderTarget **rtOut) 315{ 316 ASSERT(mColorTexture); 317 318 switch (binding) 319 { 320 case GL_BACK: 321 *rtOut = &mColorRenderTarget; 322 break; 323 case GL_DEPTH: 324 *rtOut = mDepthFormat.valid() ? &mDepthRenderTarget : nullptr; 325 break; 326 case GL_STENCIL: 327 *rtOut = mStencilFormat.valid() ? &mStencilRenderTarget : nullptr; 328 break; 329 case GL_DEPTH_STENCIL: 330 // NOTE(hqle): ES 3.0 feature 331 UNREACHABLE(); 332 break; 333 } 334 335 return angle::Result::Continue; 336} 337 338egl::Error SurfaceMtl::attachToFramebuffer(const gl::Context *context, gl::Framebuffer *framebuffer) 339{ 340 return egl::NoError(); 341} 342 343egl::Error SurfaceMtl::detachFromFramebuffer(const gl::Context *context, 344 gl::Framebuffer *framebuffer) 345{ 346 return egl::NoError(); 347} 348 349angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *context, 350 const gl::Extents &size) 351{ 352 ContextMtl *contextMtl = mtl::GetImpl(context); 353 354 ASSERT(mColorTexture); 355 356 if (mSamples > 1 && (!mMSColorTexture || mMSColorTexture->sizeAt0() != size)) 357 { 358 mAutoResolveMSColorTexture = 359 contextMtl->getDisplay()->getFeatures().allowMultisampleStoreAndResolve.enabled; 360 ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, size.width, size.height, mSamples, 361 /** renderTargetOnly */ mAutoResolveMSColorTexture, 362 &mMSColorTexture)); 363 364 if (mAutoResolveMSColorTexture) 365 { 366 // Use auto MSAA resolve at the end of render pass. 367 mColorRenderTarget.setImplicitMSTexture(mMSColorTexture); 368 } 369 else 370 { 371 mColorRenderTarget.setTexture(mMSColorTexture); 372 } 373 } 374 375 if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->sizeAt0() != size)) 376 { 377 ANGLE_TRY(CreateOrResizeTexture(context, mDepthFormat, size.width, size.height, mSamples, 378 /** renderTargetOnly */ false, &mDepthTexture)); 379 380 mDepthRenderTarget.set(mDepthTexture, mtl::kZeroNativeMipLevel, 0, mDepthFormat); 381 // Robust resource init: should initialize depth to 1.0. 382 mDepthStencilTexturesInitialized = false; 383 } 384 385 if (mStencilFormat.valid() && (!mStencilTexture || mStencilTexture->sizeAt0() != size)) 386 { 387 if (mUsePackedDepthStencil) 388 { 389 mStencilTexture = mDepthTexture; 390 } 391 else 392 { 393 ANGLE_TRY(CreateOrResizeTexture(context, mStencilFormat, size.width, size.height, 394 mSamples, 395 /** renderTargetOnly */ false, &mStencilTexture)); 396 } 397 398 mStencilRenderTarget.set(mStencilTexture, mtl::kZeroNativeMipLevel, 0, mStencilFormat); 399 // Robust resource init: should initialize stencil to zero. 400 mDepthStencilTexturesInitialized = false; 401 } 402 403 return angle::Result::Continue; 404} 405 406angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context) 407{ 408 ASSERT(mMSColorTexture); 409 if (!mAutoResolveMSColorTexture) 410 { 411 // Manually resolve texture 412 ContextMtl *contextMtl = mtl::GetImpl(context); 413 414 mColorManualResolveRenderTarget.set(mColorTexture, mtl::kZeroNativeMipLevel, 0, 415 mColorFormat); 416 mtl::RenderCommandEncoder *encoder = 417 contextMtl->getRenderTargetCommandEncoder(mColorManualResolveRenderTarget); 418 ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw( 419 context, encoder, mColorFormat.actualAngleFormat(), mMSColorTexture)); 420 contextMtl->endEncoding(true); 421 mColorManualResolveRenderTarget.reset(); 422 } 423 return angle::Result::Continue; 424} 425 426// WindowSurfaceMtl implementation. 427WindowSurfaceMtl::WindowSurfaceMtl(DisplayMtl *display, 428 const egl::SurfaceState &state, 429 EGLNativeWindowType window, 430 const egl::AttributeMap &attribs) 431 : SurfaceMtl(display, state, attribs), mLayer((__bridge CALayer *)(window)) 432{ 433 // NOTE(hqle): Width and height attributes is ignored for now. 434 mCurrentKnownDrawableSize = CGSizeMake(0, 0); 435} 436 437WindowSurfaceMtl::~WindowSurfaceMtl() {} 438 439void WindowSurfaceMtl::destroy(const egl::Display *display) 440{ 441 SurfaceMtl::destroy(display); 442 443 mCurrentDrawable = nil; 444 if (mMetalLayer && mMetalLayer.get() != mLayer) 445 { 446 // If we created metal layer in WindowSurfaceMtl::initialize(), 447 // we need to detach it from super layer now. 448 [mMetalLayer.get() removeFromSuperlayer]; 449 } 450 mMetalLayer = nil; 451} 452 453egl::Error WindowSurfaceMtl::initialize(const egl::Display *display) 454{ 455 egl::Error re = SurfaceMtl::initialize(display); 456 if (re.isError()) 457 { 458 return re; 459 } 460 461 DisplayMtl *displayMtl = mtl::GetImpl(display); 462 id<MTLDevice> metalDevice = displayMtl->getMetalDevice(); 463 464 StartFrameCapture(metalDevice, displayMtl->cmdQueue().get()); 465 466 ANGLE_MTL_OBJC_SCOPE 467 { 468 if ([mLayer isKindOfClass:CAMetalLayer.class]) 469 { 470 mMetalLayer.retainAssign(static_cast<CAMetalLayer *>(mLayer)); 471 } 472 else 473 { 474 mMetalLayer = [[[CAMetalLayer alloc] init] ANGLE_MTL_AUTORELEASE]; 475 mMetalLayer.get().frame = mLayer.frame; 476 } 477 478 mMetalLayer.get().device = metalDevice; 479 mMetalLayer.get().pixelFormat = mColorFormat.metalFormat; 480 mMetalLayer.get().framebufferOnly = NO; // Support blitting and glReadPixels 481 482#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 483 // Autoresize with parent layer. 484 mMetalLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 485#endif 486 if (mMetalLayer.get() != mLayer) 487 { 488 mMetalLayer.get().contentsScale = mLayer.contentsScale; 489 490 [mLayer addSublayer:mMetalLayer.get()]; 491 } 492 493 // ensure drawableSize is set to correct value: 494 mMetalLayer.get().drawableSize = mCurrentKnownDrawableSize = calcExpectedDrawableSize(); 495 } 496 497 return egl::NoError(); 498} 499 500egl::Error WindowSurfaceMtl::swap(const gl::Context *context) 501{ 502 ANGLE_TO_EGL_TRY(swapImpl(context)); 503 504 return egl::NoError(); 505} 506 507void WindowSurfaceMtl::setSwapInterval(const egl::Display *display, EGLint interval) 508{ 509#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 510 mMetalLayer.get().displaySyncEnabled = interval != 0; 511#endif 512} 513 514// width and height can change with client window resizing 515EGLint WindowSurfaceMtl::getWidth() const 516{ 517 return static_cast<EGLint>(mCurrentKnownDrawableSize.width); 518} 519 520EGLint WindowSurfaceMtl::getHeight() const 521{ 522 return static_cast<EGLint>(mCurrentKnownDrawableSize.height); 523} 524 525EGLint WindowSurfaceMtl::getSwapBehavior() const 526{ 527 return EGL_BUFFER_DESTROYED; 528} 529 530angle::Result WindowSurfaceMtl::initializeContents(const gl::Context *context, 531 GLenum binding, 532 const gl::ImageIndex &imageIndex) 533{ 534 ANGLE_TRY(ensureCurrentDrawableObtained(context)); 535 return SurfaceMtl::initializeContents(context, binding, imageIndex); 536} 537 538angle::Result WindowSurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, 539 GLenum binding, 540 const gl::ImageIndex &imageIndex, 541 GLsizei samples, 542 FramebufferAttachmentRenderTarget **rtOut) 543{ 544 ANGLE_TRY(ensureCurrentDrawableObtained(context)); 545 ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context)); 546 547 return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut); 548} 549 550egl::Error WindowSurfaceMtl::attachToFramebuffer(const gl::Context *context, 551 gl::Framebuffer *framebuffer) 552{ 553 FramebufferMtl *framebufferMtl = GetImplAs<FramebufferMtl>(framebuffer); 554 ASSERT(!framebufferMtl->getBackbuffer()); 555 framebufferMtl->setBackbuffer(this); 556 framebufferMtl->setFlipY(true); 557 return egl::NoError(); 558} 559 560egl::Error WindowSurfaceMtl::detachFromFramebuffer(const gl::Context *context, 561 gl::Framebuffer *framebuffer) 562{ 563 FramebufferMtl *framebufferMtl = GetImplAs<FramebufferMtl>(framebuffer); 564 ASSERT(framebufferMtl->getBackbuffer() == this); 565 framebufferMtl->setBackbuffer(nullptr); 566 framebufferMtl->setFlipY(false); 567 return egl::NoError(); 568} 569 570angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context) 571{ 572 if (!mCurrentDrawable) 573 { 574 ANGLE_TRY(obtainNextDrawable(context)); 575 } 576 577 return angle::Result::Continue; 578} 579 580angle::Result WindowSurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *context) 581{ 582 ASSERT(mMetalLayer); 583 584 gl::Extents size(static_cast<int>(mMetalLayer.get().drawableSize.width), 585 static_cast<int>(mMetalLayer.get().drawableSize.height), 1); 586 587 ANGLE_TRY(SurfaceMtl::ensureCompanionTexturesSizeCorrect(context, size)); 588 589 return angle::Result::Continue; 590} 591 592angle::Result WindowSurfaceMtl::ensureColorTextureReadyForReadPixels(const gl::Context *context) 593{ 594 ANGLE_TRY(ensureCurrentDrawableObtained(context)); 595 596 if (mMSColorTexture) 597 { 598 if (mMSColorTexture->isCPUReadMemNeedSync()) 599 { 600 ANGLE_TRY(resolveColorTextureIfNeeded(context)); 601 mMSColorTexture->resetCPUReadMemNeedSync(); 602 } 603 } 604 605 return angle::Result::Continue; 606} 607 608CGSize WindowSurfaceMtl::calcExpectedDrawableSize() const 609{ 610 CGSize currentLayerSize = mMetalLayer.get().bounds.size; 611 CGFloat currentLayerContentsScale = mMetalLayer.get().contentsScale; 612 CGSize expectedDrawableSize = CGSizeMake(currentLayerSize.width * currentLayerContentsScale, 613 currentLayerSize.height * currentLayerContentsScale); 614 615 return expectedDrawableSize; 616} 617 618bool WindowSurfaceMtl::checkIfLayerResized(const gl::Context *context) 619{ 620 if (mMetalLayer.get() != mLayer) 621 { 622 if (mMetalLayer.get().contentsScale != mLayer.contentsScale) 623 { 624 // Parent layer's content scale has changed, update Metal layer's scale factor. 625 mMetalLayer.get().contentsScale = mLayer.contentsScale; 626 } 627#if !TARGET_OS_OSX && !TARGET_OS_MACCATALYST 628 // Only macOS supports autoresizing mask. Thus, the metal layer has to be manually 629 // updated. 630 if (!CGRectEqualToRect(mMetalLayer.get().bounds, mLayer.bounds)) 631 { 632 // Parent layer's bounds has changed, update the Metal layer's bounds as well. 633 mMetalLayer.get().bounds = mLayer.bounds; 634 } 635#endif 636 } 637 638 CGSize currentLayerDrawableSize = mMetalLayer.get().drawableSize; 639 CGSize expectedDrawableSize = calcExpectedDrawableSize(); 640 641 // NOTE(hqle): We need to compare the size against mCurrentKnownDrawableSize also. 642 // That is because metal framework might internally change the drawableSize property of 643 // metal layer, and it might become equal to expectedDrawableSize. If that happens, we cannot 644 // know whether the layer has been resized or not. 645 if (currentLayerDrawableSize.width != expectedDrawableSize.width || 646 currentLayerDrawableSize.height != expectedDrawableSize.height || 647 mCurrentKnownDrawableSize.width != expectedDrawableSize.width || 648 mCurrentKnownDrawableSize.height != expectedDrawableSize.height) 649 { 650 // Resize the internal drawable texture. 651 mMetalLayer.get().drawableSize = mCurrentKnownDrawableSize = expectedDrawableSize; 652 653 return true; 654 } 655 656 return false; 657} 658 659angle::Result WindowSurfaceMtl::obtainNextDrawable(const gl::Context *context) 660{ 661 ANGLE_MTL_OBJC_SCOPE 662 { 663 ContextMtl *contextMtl = mtl::GetImpl(context); 664 665 ANGLE_MTL_TRY(contextMtl, mMetalLayer); 666 667 // Check if layer was resized 668 if (checkIfLayerResized(context)) 669 { 670 contextMtl->onBackbufferResized(context, this); 671 } 672 673 mCurrentDrawable.retainAssign([mMetalLayer nextDrawable]); 674 if (!mCurrentDrawable) 675 { 676 // The GPU might be taking too long finishing its rendering to the previous frame. 677 // Try again, indefinitely wait until the previous frame render finishes. 678 // TODO: this may wait forever here 679 mMetalLayer.get().allowsNextDrawableTimeout = NO; 680 mCurrentDrawable.retainAssign([mMetalLayer nextDrawable]); 681 mMetalLayer.get().allowsNextDrawableTimeout = YES; 682 } 683 684 if (!mColorTexture) 685 { 686 mColorTexture = mtl::Texture::MakeFromMetal(mCurrentDrawable.get().texture); 687 ASSERT(!mColorRenderTarget.getTexture()); 688 mColorRenderTarget.setWithImplicitMSTexture(mColorTexture, mMSColorTexture, 689 mtl::kZeroNativeMipLevel, 0, mColorFormat); 690 } 691 else 692 { 693 mColorTexture->set(mCurrentDrawable.get().texture); 694 } 695 mColorTextureInitialized = false; 696 697 ANGLE_MTL_LOG("Current metal drawable size=%d,%d", mColorTexture->width(), 698 mColorTexture->height()); 699 700 // Now we have to resize depth stencil buffers if required. 701 ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context)); 702 703 return angle::Result::Continue; 704 } 705} 706 707angle::Result WindowSurfaceMtl::swapImpl(const gl::Context *context) 708{ 709 if (mCurrentDrawable) 710 { 711 ASSERT(mColorTexture); 712 713 ContextMtl *contextMtl = mtl::GetImpl(context); 714 715 if (mMSColorTexture) 716 { 717 ANGLE_TRY(resolveColorTextureIfNeeded(context)); 718 } 719 720 contextMtl->present(context, mCurrentDrawable); 721 722 StopFrameCapture(); 723 StartFrameCapture(contextMtl); 724 725 // Invalidate current drawable 726 mColorTexture->set(nil); 727 mCurrentDrawable = nil; 728 } 729 // Robust resource init: should initialize stencil zero and depth to 1.0 after swap. 730 if (mDepthTexture || mStencilTexture) 731 { 732 mDepthStencilTexturesInitialized = false; 733 } 734 return angle::Result::Continue; 735} 736 737// OffscreenSurfaceMtl implementation 738OffscreenSurfaceMtl::OffscreenSurfaceMtl(DisplayMtl *display, 739 const egl::SurfaceState &state, 740 const egl::AttributeMap &attribs) 741 : SurfaceMtl(display, state, attribs) 742{ 743 mSize = gl::Extents(attribs.getAsInt(EGL_WIDTH, 1), attribs.getAsInt(EGL_HEIGHT, 1), 1); 744} 745 746OffscreenSurfaceMtl::~OffscreenSurfaceMtl() {} 747 748void OffscreenSurfaceMtl::destroy(const egl::Display *display) 749{ 750 SurfaceMtl::destroy(display); 751} 752 753EGLint OffscreenSurfaceMtl::getWidth() const 754{ 755 return mSize.width; 756} 757 758EGLint OffscreenSurfaceMtl::getHeight() const 759{ 760 return mSize.height; 761} 762 763egl::Error OffscreenSurfaceMtl::swap(const gl::Context *context) 764{ 765 // Check for surface resize. 766 ANGLE_TO_EGL_TRY(ensureTexturesSizeCorrect(context)); 767 768 return egl::NoError(); 769} 770 771egl::Error OffscreenSurfaceMtl::bindTexImage(const gl::Context *context, 772 gl::Texture *texture, 773 EGLint buffer) 774{ 775 ContextMtl *contextMtl = mtl::GetImpl(context); 776 contextMtl->flushCommandBuffer(mtl::NoWait); 777 778 // Initialize offscreen textures if needed: 779 ANGLE_TO_EGL_TRY(ensureTexturesSizeCorrect(context)); 780 781 return egl::NoError(); 782} 783 784egl::Error OffscreenSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer) 785{ 786 ContextMtl *contextMtl = mtl::GetImpl(context); 787 788 if (mMSColorTexture) 789 { 790 ANGLE_TO_EGL_TRY(resolveColorTextureIfNeeded(context)); 791 } 792 793 // NOTE(hqle): Should we finishCommandBuffer or flush is enough? 794 contextMtl->flushCommandBuffer(mtl::NoWait); 795 return egl::NoError(); 796} 797 798angle::Result OffscreenSurfaceMtl::getAttachmentRenderTarget( 799 const gl::Context *context, 800 GLenum binding, 801 const gl::ImageIndex &imageIndex, 802 GLsizei samples, 803 FramebufferAttachmentRenderTarget **rtOut) 804{ 805 // Initialize offscreen textures if needed: 806 ANGLE_TRY(ensureTexturesSizeCorrect(context)); 807 808 return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut); 809} 810 811angle::Result OffscreenSurfaceMtl::ensureTexturesSizeCorrect(const gl::Context *context) 812{ 813 if (!mColorTexture || mColorTexture->sizeAt0() != mSize) 814 { 815 ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, mSize.width, mSize.height, 1, 816 /** renderTargetOnly */ false, &mColorTexture)); 817 818 mColorRenderTarget.set(mColorTexture, mtl::kZeroNativeMipLevel, 0, mColorFormat); 819 } 820 821 return ensureCompanionTexturesSizeCorrect(context, mSize); 822} 823 824// PBufferSurfaceMtl implementation 825PBufferSurfaceMtl::PBufferSurfaceMtl(DisplayMtl *display, 826 const egl::SurfaceState &state, 827 const egl::AttributeMap &attribs) 828 : OffscreenSurfaceMtl(display, state, attribs) 829{} 830 831void PBufferSurfaceMtl::setFixedWidth(EGLint width) 832{ 833 mSize.width = width; 834} 835 836void PBufferSurfaceMtl::setFixedHeight(EGLint height) 837{ 838 mSize.height = height; 839} 840 841} // namespace rx 842