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