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// FramebufferMtl.mm: 7// Implements the class methods for FramebufferMtl. 8// 9 10#include "libANGLE/angletypes.h" 11#include "libANGLE/renderer/metal/ContextMtl.h" 12 13#include <TargetConditionals.h> 14 15#include "common/MemoryBuffer.h" 16#include "common/angleutils.h" 17#include "common/debug.h" 18#include "libANGLE/ErrorStrings.h" 19#include "libANGLE/renderer/metal/BufferMtl.h" 20#include "libANGLE/renderer/metal/DisplayMtl.h" 21#include "libANGLE/renderer/metal/FrameBufferMtl.h" 22#include "libANGLE/renderer/metal/SurfaceMtl.h" 23#include "libANGLE/renderer/metal/mtl_utils.h" 24#include "libANGLE/renderer/renderer_utils.h" 25 26namespace rx 27{ 28namespace 29{ 30// Override clear color based on texture's write mask 31void OverrideMTLClearColor(const mtl::TextureRef &texture, 32 const mtl::ClearColorValue &clearColor, 33 MTLClearColor *colorOut) 34{ 35 *colorOut = 36 mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(), texture->getColorWritableMask()); 37} 38 39const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context, 40 RenderTargetMtl *renderTarget) 41{ 42 GLenum implFormat; 43 44 if (renderTarget && renderTarget->getFormat()) 45 { 46 implFormat = renderTarget->getFormat()->actualAngleFormat().fboImplementationInternalFormat; 47 } 48 else 49 { 50 implFormat = GL_NONE; 51 } 52 53 return gl::GetSizedInternalFormatInfo(implFormat); 54} 55 56} 57 58// FramebufferMtl implementation 59FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, 60 bool flipY, 61 WindowSurfaceMtl *backbuffer) 62 : FramebufferImpl(state), mBackbuffer(backbuffer), mFlipY(flipY) 63{ 64 reset(); 65} 66 67FramebufferMtl::~FramebufferMtl() {} 68 69void FramebufferMtl::reset() 70{ 71 for (auto &rt : mColorRenderTargets) 72 { 73 rt = nullptr; 74 } 75 mDepthRenderTarget = mStencilRenderTarget = nullptr; 76 77 mRenderPassFirstColorAttachmentFormat = nullptr; 78 79 mReadPixelBuffer = nullptr; 80} 81 82void FramebufferMtl::destroy(const gl::Context *context) 83{ 84 reset(); 85} 86 87angle::Result FramebufferMtl::discard(const gl::Context *context, 88 size_t count, 89 const GLenum *attachments) 90{ 91 return invalidate(context, count, attachments); 92} 93 94angle::Result FramebufferMtl::invalidate(const gl::Context *context, 95 size_t count, 96 const GLenum *attachments) 97{ 98 return invalidateImpl(mtl::GetImpl(context), count, attachments); 99} 100 101angle::Result FramebufferMtl::invalidateSub(const gl::Context *context, 102 size_t count, 103 const GLenum *attachments, 104 const gl::Rectangle &area) 105{ 106 if (area.encloses(getCompleteRenderArea())) 107 { 108 return invalidateImpl(mtl::GetImpl(context), count, attachments); 109 } 110 return angle::Result::Continue; 111} 112 113angle::Result FramebufferMtl::clear(const gl::Context *context, GLbitfield mask) 114{ 115 ContextMtl *contextMtl = mtl::GetImpl(context); 116 117 mtl::ClearRectParams clearOpts; 118 119 bool clearColor = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT)); 120 bool clearDepth = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT)); 121 bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT)); 122 123 gl::DrawBufferMask clearColorBuffers; 124 if (clearColor) 125 { 126 clearColorBuffers = mState.getEnabledDrawBuffers(); 127 clearOpts.clearColor = contextMtl->getClearColorValue(); 128 } 129 if (clearDepth) 130 { 131 clearOpts.clearDepth = contextMtl->getClearDepthValue(); 132 } 133 if (clearStencil) 134 { 135 clearOpts.clearStencil = contextMtl->getClearStencilValue(); 136 } 137 138 return clearImpl(context, clearColorBuffers, &clearOpts); 139} 140 141angle::Result FramebufferMtl::clearBufferfv(const gl::Context *context, 142 GLenum buffer, 143 GLint drawbuffer, 144 const GLfloat *values) 145{ 146 mtl::ClearRectParams clearOpts; 147 148 gl::DrawBufferMask clearColorBuffers; 149 if (buffer == GL_DEPTH) 150 { 151 clearOpts.clearDepth = values[0]; 152 } 153 else 154 { 155 clearColorBuffers.set(drawbuffer); 156 clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]); 157 } 158 159 return clearImpl(context, clearColorBuffers, &clearOpts); 160} 161angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context, 162 GLenum buffer, 163 GLint drawbuffer, 164 const GLuint *values) 165{ 166 gl::DrawBufferMask clearColorBuffers; 167 clearColorBuffers.set(drawbuffer); 168 169 mtl::ClearRectParams clearOpts; 170 clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]); 171 172 return clearImpl(context, clearColorBuffers, &clearOpts); 173} 174angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context, 175 GLenum buffer, 176 GLint drawbuffer, 177 const GLint *values) 178{ 179 mtl::ClearRectParams clearOpts; 180 181 gl::DrawBufferMask clearColorBuffers; 182 if (buffer == GL_STENCIL) 183 { 184 clearOpts.clearStencil = values[0] & mtl::kStencilMaskAll; 185 } 186 else 187 { 188 clearColorBuffers.set(drawbuffer); 189 clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]); 190 } 191 192 return clearImpl(context, clearColorBuffers, &clearOpts); 193} 194angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context, 195 GLenum buffer, 196 GLint drawbuffer, 197 GLfloat depth, 198 GLint stencil) 199{ 200 mtl::ClearRectParams clearOpts; 201 clearOpts.clearDepth = depth; 202 clearOpts.clearStencil = stencil & mtl::kStencilMaskAll; 203 204 return clearImpl(context, gl::DrawBufferMask(), &clearOpts); 205} 206 207const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat( 208 const gl::Context *context) const 209{ 210 return GetReadAttachmentInfo(context, getColorReadRenderTargetNoCache(context)); 211} 212 213angle::Result FramebufferMtl::readPixels(const gl::Context *context, 214 const gl::Rectangle &area, 215 GLenum format, 216 GLenum type, 217 const gl::PixelPackState &pack, 218 gl::Buffer *packBuffer, 219 void *pixels) 220{ 221 // Clip read area to framebuffer. 222 const gl::Extents &fbSize = getState().getReadAttachment()->getSize(); 223 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); 224 225 gl::Rectangle clippedArea; 226 if (!ClipRectangle(area, fbRect, &clippedArea)) 227 { 228 // nothing to read 229 return angle::Result::Continue; 230 } 231 gl::Rectangle flippedArea = getCorrectFlippedReadArea(context, clippedArea); 232 233 ContextMtl *contextMtl = mtl::GetImpl(context); 234 235 const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type); 236 237 GLuint outputPitch = 0; 238 ANGLE_CHECK_GL_MATH(contextMtl, 239 sizedFormatInfo.computeRowPitch(type, area.width, pack.alignment, 240 pack.rowLength, &outputPitch)); 241 GLuint outputSkipBytes = 0; 242 ANGLE_CHECK_GL_MATH(contextMtl, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, pack, 243 false, &outputSkipBytes)); 244 245 outputSkipBytes += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes + 246 (clippedArea.y - area.y) * outputPitch; 247 248 const angle::Format &angleFormat = GetFormatFromFormatType(format, type); 249 250 PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOrder, packBuffer, 251 0); 252 253 if (params.packBuffer) 254 { 255 // If PBO is active, pixels is treated as offset. 256 params.offset = reinterpret_cast<ptrdiff_t>(pixels) + outputSkipBytes; 257 } 258 259 if (mFlipY) 260 { 261 params.reverseRowOrder = !params.reverseRowOrder; 262 } 263 264 ANGLE_TRY(readPixelsImpl(context, flippedArea, params, getColorReadRenderTarget(context), 265 static_cast<uint8_t *>(pixels) + outputSkipBytes)); 266 267 return angle::Result::Continue; 268} 269 270namespace 271{ 272 273using FloatRectangle = gl::RectangleImpl<float>; 274 275float clamp0Max(float v, float max) 276{ 277 return std::max(0.0f, std::min(max, v)); 278} 279 280void ClampToBoundsAndAdjustCorrespondingValue(float a, 281 float originalASize, 282 float maxSize, 283 float b, 284 float originalBSize, 285 float *newA, 286 float *newB) 287{ 288 float clippedA = clamp0Max(a, maxSize); 289 float delta = clippedA - a; 290 *newA = clippedA; 291 *newB = b + delta * originalBSize / originalASize; 292} 293 294void ClipRectToBoundsAndAdjustCorrespondingRect(const FloatRectangle &a, 295 const gl::Rectangle &originalA, 296 const gl::Rectangle &clipDimensions, 297 const FloatRectangle &b, 298 const gl::Rectangle &originalB, 299 FloatRectangle *newA, 300 FloatRectangle *newB) 301{ 302 float newAValues[4]; 303 float newBValues[4]; 304 ClampToBoundsAndAdjustCorrespondingValue(a.x0(), originalA.width, clipDimensions.width, b.x0(), 305 originalB.width, &newAValues[0], &newBValues[0]); 306 ClampToBoundsAndAdjustCorrespondingValue(a.y0(), originalA.height, clipDimensions.height, 307 b.y0(), originalB.height, &newAValues[1], 308 &newBValues[1]); 309 ClampToBoundsAndAdjustCorrespondingValue(a.x1(), originalA.width, clipDimensions.width, b.x1(), 310 originalB.width, &newAValues[2], &newBValues[2]); 311 ClampToBoundsAndAdjustCorrespondingValue(a.y1(), originalA.height, clipDimensions.height, 312 b.y1(), originalB.height, &newAValues[3], 313 &newBValues[3]); 314 315 *newA = FloatRectangle(newAValues); 316 *newB = FloatRectangle(newBValues); 317} 318 319void ClipRectsToBoundsAndAdjustCorrespondingRect(const FloatRectangle &a, 320 const gl::Rectangle &originalA, 321 const gl::Rectangle &aClipDimensions, 322 const FloatRectangle &b, 323 const gl::Rectangle &originalB, 324 const gl::Rectangle &bClipDimensions, 325 FloatRectangle *newA, 326 FloatRectangle *newB) 327{ 328 FloatRectangle tempA; 329 FloatRectangle tempB; 330 ClipRectToBoundsAndAdjustCorrespondingRect(a, originalA, aClipDimensions, b, originalB, &tempA, 331 &tempB); 332 ClipRectToBoundsAndAdjustCorrespondingRect(tempB, originalB, bClipDimensions, tempA, originalA, 333 newB, newA); 334} 335 336void RoundValueAndAdjustCorrespondingValue(float a, 337 float originalASize, 338 float b, 339 float originalBSize, 340 int *newA, 341 float *newB) 342{ 343 float roundedA = std::round(a); 344 float delta = roundedA - a; 345 *newA = static_cast<int>(roundedA); 346 *newB = b + delta * originalBSize / originalASize; 347} 348 349gl::Rectangle RoundRectToPixelsAndAdjustCorrespondingRectToMatch(const FloatRectangle &a, 350 const gl::Rectangle &originalA, 351 const FloatRectangle &b, 352 const gl::Rectangle &originalB, 353 FloatRectangle *newB) 354{ 355 int newAValues[4]; 356 float newBValues[4]; 357 RoundValueAndAdjustCorrespondingValue(a.x0(), originalA.width, b.x0(), originalB.width, 358 &newAValues[0], &newBValues[0]); 359 RoundValueAndAdjustCorrespondingValue(a.y0(), originalA.height, b.y0(), originalB.height, 360 &newAValues[1], &newBValues[1]); 361 RoundValueAndAdjustCorrespondingValue(a.x1(), originalA.width, b.x1(), originalB.width, 362 &newAValues[2], &newBValues[2]); 363 RoundValueAndAdjustCorrespondingValue(a.y1(), originalA.height, b.y1(), originalB.height, 364 &newAValues[3], &newBValues[3]); 365 366 *newB = FloatRectangle(newBValues); 367 return gl::Rectangle(newAValues[0], newAValues[1], newAValues[2] - newAValues[0], 368 newAValues[3] - newAValues[1]); 369} 370 371} // namespace 372 373angle::Result FramebufferMtl::blit(const gl::Context *context, 374 const gl::Rectangle &sourceAreaIn, 375 const gl::Rectangle &destAreaIn, 376 GLbitfield mask, 377 GLenum filter) 378{ 379 bool blitColorBuffer = (mask & GL_COLOR_BUFFER_BIT) != 0; 380 bool blitDepthBuffer = (mask & GL_DEPTH_BUFFER_BIT) != 0; 381 bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0; 382 383 const gl::State &glState = context->getState(); 384 const gl::Framebuffer *glSrcFramebuffer = glState.getReadFramebuffer(); 385 386 FramebufferMtl *srcFrameBuffer = mtl::GetImpl(glSrcFramebuffer); 387 388 blitColorBuffer = 389 blitColorBuffer && srcFrameBuffer->getColorReadRenderTarget(context) != nullptr; 390 blitDepthBuffer = blitDepthBuffer && srcFrameBuffer->getDepthRenderTarget() != nullptr; 391 blitStencilBuffer = blitStencilBuffer && srcFrameBuffer->getStencilRenderTarget() != nullptr; 392 393 if (!blitColorBuffer && !blitDepthBuffer && !blitStencilBuffer) 394 { 395 // No-op 396 return angle::Result::Continue; 397 } 398 399 const gl::Rectangle srcFramebufferDimensions = srcFrameBuffer->getCompleteRenderArea(); 400 const gl::Rectangle dstFramebufferDimensions = this->getCompleteRenderArea(); 401 402 FloatRectangle srcRect(sourceAreaIn); 403 FloatRectangle dstRect(destAreaIn); 404 405 FloatRectangle clippedSrcRect; 406 FloatRectangle clippedDstRect; 407 ClipRectsToBoundsAndAdjustCorrespondingRect(srcRect, sourceAreaIn, srcFramebufferDimensions, 408 dstRect, destAreaIn, dstFramebufferDimensions, 409 &clippedSrcRect, &clippedDstRect); 410 411 FloatRectangle adjustedSrcRect; 412 gl::Rectangle srcClippedDestArea = RoundRectToPixelsAndAdjustCorrespondingRectToMatch( 413 clippedDstRect, destAreaIn, clippedSrcRect, sourceAreaIn, &adjustedSrcRect); 414 415 if (srcFrameBuffer->flipY()) 416 { 417 adjustedSrcRect.y = 418 srcFramebufferDimensions.height - adjustedSrcRect.y - adjustedSrcRect.height; 419 adjustedSrcRect = adjustedSrcRect.flip(false, true); 420 } 421 422 // If the destination is flipped in either direction, we will flip the source instead so that 423 // the destination area is always unflipped. 424 adjustedSrcRect = 425 adjustedSrcRect.flip(srcClippedDestArea.isReversedX(), srcClippedDestArea.isReversedY()); 426 srcClippedDestArea = srcClippedDestArea.removeReversal(); 427 428 // Clip the destination area to the framebuffer size and scissor. 429 gl::Rectangle scissoredDestArea; 430 if (!gl::ClipRectangle(ClipRectToScissor(glState, dstFramebufferDimensions, false), 431 srcClippedDestArea, &scissoredDestArea)) 432 { 433 return angle::Result::Continue; 434 } 435 436 // Use blit with draw 437 mtl::BlitParams baseParams; 438 baseParams.dstTextureSize = 439 gl::Extents(dstFramebufferDimensions.width, dstFramebufferDimensions.height, 1); 440 baseParams.dstRect = srcClippedDestArea; 441 baseParams.dstScissorRect = scissoredDestArea; 442 baseParams.dstFlipY = this->flipY(); 443 444 baseParams.srcNormalizedCoords = 445 mtl::NormalizedCoords(adjustedSrcRect.x, adjustedSrcRect.y, adjustedSrcRect.width, 446 adjustedSrcRect.height, srcFramebufferDimensions); 447 // This flag is for auto flipping the rect inside RenderUtils. Since we already flip it using 448 // getCorrectFlippedReadArea(). This flag is not needed. 449 baseParams.srcYFlipped = false; 450 baseParams.unpackFlipX = false; 451 baseParams.unpackFlipY = false; 452 453 return blitWithDraw(context, srcFrameBuffer, blitColorBuffer, blitDepthBuffer, 454 blitStencilBuffer, filter, baseParams); 455} 456 457angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context, 458 FramebufferMtl *srcFrameBuffer, 459 bool blitColorBuffer, 460 bool blitDepthBuffer, 461 bool blitStencilBuffer, 462 GLenum filter, 463 const mtl::BlitParams &baseParams) 464{ 465 ContextMtl *contextMtl = mtl::GetImpl(context); 466 // Use blit with draw 467 mtl::RenderCommandEncoder *renderEncoder = nullptr; 468 469 // Blit Depth & stencil 470 if (blitDepthBuffer || blitStencilBuffer) 471 { 472 mtl::DepthStencilBlitParams dsBlitParams; 473 memcpy(&dsBlitParams, &baseParams, sizeof(baseParams)); 474 RenderTargetMtl *srcDepthRt = srcFrameBuffer->getDepthRenderTarget(); 475 RenderTargetMtl *srcStencilRt = srcFrameBuffer->getStencilRenderTarget(); 476 477 if (blitDepthBuffer) 478 { 479 dsBlitParams.src = srcDepthRt->getTexture(); 480 dsBlitParams.srcLevel = srcDepthRt->getLevelIndex(); 481 dsBlitParams.srcLayer = srcDepthRt->getLayerIndex(); 482 } 483 484 if (blitStencilBuffer && srcStencilRt->getTexture()) 485 { 486 dsBlitParams.srcStencil = srcStencilRt->getTexture()->getStencilView(); 487 dsBlitParams.srcLevel = srcStencilRt->getLevelIndex(); 488 dsBlitParams.srcLayer = srcStencilRt->getLayerIndex(); 489 490 if (!contextMtl->getDisplay()->getFeatures().hasStencilOutput.enabled && 491 mStencilRenderTarget) 492 { 493 // Directly writing to stencil in shader is not supported, use temporary copy buffer 494 // work around. This is a compute pass. 495 mtl::StencilBlitViaBufferParams stencilOnlyBlitParams = dsBlitParams; 496 stencilOnlyBlitParams.dstStencil = mStencilRenderTarget->getTexture(); 497 stencilOnlyBlitParams.dstStencilLayer = mStencilRenderTarget->getLayerIndex(); 498 stencilOnlyBlitParams.dstStencilLevel = mStencilRenderTarget->getLevelIndex(); 499 stencilOnlyBlitParams.dstPackedDepthStencilFormat = 500 mStencilRenderTarget->getFormat()->hasDepthAndStencilBits(); 501 502 ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitStencilViaCopyBuffer( 503 context, stencilOnlyBlitParams)); 504 505 // Prevent the stencil to be blitted with draw again 506 dsBlitParams.srcStencil = nullptr; 507 } 508 } 509 510 // The actual blitting of depth and/or stencil 511 renderEncoder = ensureRenderPassStarted(context); 512 ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitDepthStencilWithDraw( 513 context, renderEncoder, dsBlitParams)); 514 } // if (blitDepthBuffer || blitStencilBuffer) 515 else 516 { 517 renderEncoder = ensureRenderPassStarted(context); 518 } 519 520 // Blit color 521 if (blitColorBuffer) 522 { 523 mtl::ColorBlitParams colorBlitParams; 524 memcpy(&colorBlitParams, &baseParams, sizeof(baseParams)); 525 526 RenderTargetMtl *srcColorRt = srcFrameBuffer->getColorReadRenderTarget(context); 527 ASSERT(srcColorRt); 528 529 colorBlitParams.src = srcColorRt->getTexture(); 530 colorBlitParams.srcLevel = srcColorRt->getLevelIndex(); 531 colorBlitParams.srcLayer = srcColorRt->getLayerIndex(); 532 533 colorBlitParams.enabledBuffers = getState().getEnabledDrawBuffers(); 534 colorBlitParams.filter = filter; 535 colorBlitParams.dstLuminance = srcColorRt->getFormat()->actualAngleFormat().isLUMA(); 536 537 ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw( 538 context, renderEncoder, srcColorRt->getFormat()->actualAngleFormat(), colorBlitParams)); 539 } 540 541 return angle::Result::Continue; 542} 543 544gl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) const 545{ 546 if (!mState.attachmentsHaveSameDimensions()) 547 { 548 return gl::FramebufferStatus::Incomplete( 549 GL_FRAMEBUFFER_UNSUPPORTED, 550 gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions); 551 } 552 553 ContextMtl *contextMtl = mtl::GetImpl(context); 554 if (!contextMtl->getDisplay()->getFeatures().allowSeparatedDepthStencilBuffers.enabled && 555 mState.hasSeparateDepthAndStencilAttachments()) 556 { 557 return gl::FramebufferStatus::Incomplete( 558 GL_FRAMEBUFFER_UNSUPPORTED, 559 gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers); 560 } 561 562 if (mState.getDepthAttachment() && mState.getDepthAttachment()->getFormat().info->depthBits && 563 mState.getDepthAttachment()->getFormat().info->stencilBits) 564 { 565 return checkPackedDepthStencilAttachment(); 566 } 567 568 if (mState.getStencilAttachment() && 569 mState.getStencilAttachment()->getFormat().info->depthBits && 570 mState.getStencilAttachment()->getFormat().info->stencilBits) 571 { 572 return checkPackedDepthStencilAttachment(); 573 } 574 575 return gl::FramebufferStatus::Complete(); 576} 577 578gl::FramebufferStatus FramebufferMtl::checkPackedDepthStencilAttachment() const 579{ 580 if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12.0)) 581 { 582 // If depth/stencil attachment has depth & stencil bits, then depth & stencil must not have 583 // separate attachment. i.e. They must be the same texture or one of them has no 584 // attachment. 585 if (mState.hasSeparateDepthAndStencilAttachments()) 586 { 587 WARN() << "Packed depth stencil texture/buffer must not be mixed with other " 588 "texture/buffer."; 589 return gl::FramebufferStatus::Incomplete( 590 GL_FRAMEBUFFER_UNSUPPORTED, 591 gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers); 592 } 593 } 594 else 595 { 596 // Metal 2.0 and below doesn't allow packed depth stencil texture to be attached only as 597 // depth or stencil buffer. i.e. None of the depth & stencil attachment can be null. 598 if (!mState.getDepthStencilAttachment()) 599 { 600 WARN() << "Packed depth stencil texture/buffer must be bound to both depth & stencil " 601 "attachment point."; 602 return gl::FramebufferStatus::Incomplete( 603 GL_FRAMEBUFFER_UNSUPPORTED, 604 gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers); 605 } 606 } 607 return gl::FramebufferStatus::Complete(); 608} 609 610angle::Result FramebufferMtl::syncState(const gl::Context *context, 611 GLenum binding, 612 const gl::Framebuffer::DirtyBits &dirtyBits, 613 gl::Command command) 614{ 615 ContextMtl *contextMtl = mtl::GetImpl(context); 616 bool mustNotifyContext = false; 617 // Cache old mRenderPassDesc before update*RenderTarget() invalidate it. 618 mtl::RenderPassDesc oldRenderPassDesc = mRenderPassDesc; 619 620 for (size_t dirtyBit : dirtyBits) 621 { 622 switch (dirtyBit) 623 { 624 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: 625 ANGLE_TRY(updateDepthRenderTarget(context)); 626 break; 627 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: 628 ANGLE_TRY(updateStencilRenderTarget(context)); 629 break; 630 case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS: 631 case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS: 632 // NOTE(hqle): What are we supposed to do? 633 break; 634 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: 635 mustNotifyContext = true; 636 break; 637 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: 638 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: 639 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: 640 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES: 641 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS: 642 break; 643 default: 644 { 645 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits"); 646 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) 647 { 648 size_t colorIndexGL = static_cast<size_t>( 649 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); 650 ANGLE_TRY(updateColorRenderTarget(context, colorIndexGL)); 651 } 652 else 653 { 654 ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 && 655 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX); 656 // NOTE: might need to notify context. 657 } 658 break; 659 } 660 } 661 } 662 663 ANGLE_TRY(prepareRenderPass(context, &mRenderPassDesc)); 664 bool renderPassChanged = !oldRenderPassDesc.equalIgnoreLoadStoreOptions(mRenderPassDesc); 665 666 if (mustNotifyContext || renderPassChanged) 667 { 668 FramebufferMtl *currentDrawFramebuffer = 669 mtl::GetImpl(context->getState().getDrawFramebuffer()); 670 if (currentDrawFramebuffer == this) 671 { 672 contextMtl->onDrawFrameBufferChangedState(context, this, renderPassChanged); 673 } 674 675 // Recreate pixel reading buffer if needed in future. 676 mReadPixelBuffer = nullptr; 677 } 678 679 return angle::Result::Continue; 680} 681 682angle::Result FramebufferMtl::getSamplePosition(const gl::Context *context, 683 size_t index, 684 GLfloat *xy) const 685{ 686 UNIMPLEMENTED(); 687 return angle::Result::Stop; 688} 689 690RenderTargetMtl *FramebufferMtl::getColorReadRenderTarget(const gl::Context *context) const 691{ 692 if (mState.getReadIndex() >= mColorRenderTargets.size()) 693 { 694 return nullptr; 695 } 696 697 if (mBackbuffer) 698 { 699 bool isNewDrawable = false; 700 if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable))) 701 { 702 return nullptr; 703 } 704 705 if (isNewDrawable && mBackbuffer->hasRobustResourceInit()) 706 { 707 (void)mBackbuffer->initializeContents(context, gl::ImageIndex::Make2D(0)); 708 } 709 } 710 711 return mColorRenderTargets[mState.getReadIndex()]; 712} 713 714RenderTargetMtl *FramebufferMtl::getColorReadRenderTargetNoCache(const gl::Context *context) const 715{ 716 if (mState.getReadIndex() >= mColorRenderTargets.size()) 717 { 718 return nullptr; 719 } 720 721 if (mBackbuffer) 722 { 723 // If we have a backbuffer/window surface, we can take the old path here and return 724 // the cached color render target. 725 return getColorReadRenderTarget(context); 726 } 727 // If we have no backbuffer, get the attachment from state color attachments, as it may have 728 // changed before syncing. 729 const gl::FramebufferAttachment *attachment = mState.getColorAttachment(mState.getReadIndex()); 730 RenderTargetMtl *currentTarget = nullptr; 731 if (attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(), 732 ¤tTarget) == angle::Result::Stop) 733 { 734 return nullptr; 735 } 736 return currentTarget; 737} 738 739int FramebufferMtl::getSamples() const 740{ 741 return mRenderPassDesc.sampleCount; 742} 743 744gl::Rectangle FramebufferMtl::getCompleteRenderArea() const 745{ 746 return gl::Rectangle(0, 0, mState.getDimensions().width, mState.getDimensions().height); 747} 748 749bool FramebufferMtl::renderPassHasStarted(ContextMtl *contextMtl) const 750{ 751 return contextMtl->hasStartedRenderPass(mRenderPassDesc); 752} 753 754mtl::RenderCommandEncoder *FramebufferMtl::ensureRenderPassStarted(const gl::Context *context) 755{ 756 return ensureRenderPassStarted(context, mRenderPassDesc); 757} 758 759mtl::RenderCommandEncoder *FramebufferMtl::ensureRenderPassStarted(const gl::Context *context, 760 const mtl::RenderPassDesc &desc) 761{ 762 ContextMtl *contextMtl = mtl::GetImpl(context); 763 764 if (mBackbuffer) 765 { 766 // Backbuffer might obtain new drawable, which means it might change the 767 // the native texture used as the target of the render pass. 768 // We need to call this before creating render encoder. 769 bool isNewDrawable; 770 if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable))) 771 { 772 return nullptr; 773 } 774 775 if (isNewDrawable && mBackbuffer->hasRobustResourceInit()) 776 { 777 // Apply robust resource initialization on newly obtained drawable. 778 (void)mBackbuffer->initializeContents(context, gl::ImageIndex::Make2D(0)); 779 } 780 } 781 782 // Only support ensureRenderPassStarted() with different load & store options only. The 783 // texture, level, slice must be the same. 784 ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc)); 785 786 mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(desc); 787 788 if (mRenderPassCleanStart) 789 { 790 // After a clean start we should reset the loadOp to MTLLoadActionLoad in case this render 791 // pass could be interrupted by a conversion compute shader pass then being resumed later. 792 mRenderPassCleanStart = false; 793 for (mtl::RenderPassColorAttachmentDesc &colorAttachment : mRenderPassDesc.colorAttachments) 794 { 795 colorAttachment.loadAction = MTLLoadActionLoad; 796 } 797 mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad; 798 mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad; 799 } 800 801 return encoder; 802} 803 804void FramebufferMtl::setLoadStoreActionOnRenderPassFirstStart( 805 mtl::RenderPassAttachmentDesc *attachmentOut, 806 const bool forceDepthStencilMultisampleLoad) 807{ 808 ASSERT(mRenderPassCleanStart); 809 810 mtl::RenderPassAttachmentDesc &attachment = *attachmentOut; 811 812 if (!forceDepthStencilMultisampleLoad && 813 (attachment.storeAction == MTLStoreActionDontCare || 814 attachment.storeAction == MTLStoreActionMultisampleResolve)) 815 { 816 // If we previously discarded attachment's content, then don't need to load it. 817 attachment.loadAction = MTLLoadActionDontCare; 818 } 819 else 820 { 821 attachment.loadAction = MTLLoadActionLoad; 822 } 823 824 if (attachment.hasImplicitMSTexture()) 825 { 826 if (mBackbuffer) 827 { 828 // Default action for default framebuffer is resolve and keep MS texture's content. 829 // We only discard MS texture's content at the end of the frame. See onFrameEnd(). 830 attachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; 831 } 832 else 833 { 834 // Default action is resolve but don't keep MS texture's content. 835 attachment.storeAction = MTLStoreActionMultisampleResolve; 836 } 837 } 838 else 839 { 840 attachment.storeAction = MTLStoreActionStore; // Default action is store 841 } 842} 843 844void FramebufferMtl::onStartedDrawingToFrameBuffer(const gl::Context *context) 845{ 846 mRenderPassCleanStart = true; 847 848 // If any of the render targets need to load their multisample textures, we should do the same 849 // for depth/stencil. 850 bool forceDepthStencilMultisampleLoad = false; 851 852 // Compute loadOp based on previous storeOp and reset storeOp flags: 853 for (mtl::RenderPassColorAttachmentDesc &colorAttachment : mRenderPassDesc.colorAttachments) 854 { 855 forceDepthStencilMultisampleLoad |= 856 colorAttachment.storeAction == MTLStoreActionStoreAndMultisampleResolve; 857 setLoadStoreActionOnRenderPassFirstStart(&colorAttachment, false); 858 } 859 // Depth load/store 860 setLoadStoreActionOnRenderPassFirstStart(&mRenderPassDesc.depthAttachment, 861 forceDepthStencilMultisampleLoad); 862 863 // Stencil load/store 864 setLoadStoreActionOnRenderPassFirstStart(&mRenderPassDesc.stencilAttachment, 865 forceDepthStencilMultisampleLoad); 866} 867 868void FramebufferMtl::onFrameEnd(const gl::Context *context) 869{ 870 if (!mBackbuffer || mBackbuffer->preserveBuffer()) 871 { 872 return; 873 } 874 875 ContextMtl *contextMtl = mtl::GetImpl(context); 876 // Always discard default FBO's depth stencil & multisample buffers at the end of the frame: 877 if (this->renderPassHasStarted(contextMtl)) 878 { 879 mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(); 880 881 constexpr GLenum dsAttachments[] = {GL_DEPTH, GL_STENCIL}; 882 (void)invalidateImpl(contextMtl, 2, dsAttachments); 883 if (mBackbuffer->getSamples() > 1) 884 { 885 encoder->setColorStoreAction(MTLStoreActionMultisampleResolve, 0); 886 } 887 888 contextMtl->endEncoding(false); 889 890 // Reset discard flag. 891 onStartedDrawingToFrameBuffer(context); 892 } 893} 894 895angle::Result FramebufferMtl::updateColorRenderTarget(const gl::Context *context, 896 size_t colorIndexGL) 897{ 898 ASSERT(colorIndexGL < mtl::kMaxRenderTargets); 899 // Reset load store action 900 mRenderPassDesc.colorAttachments[colorIndexGL].reset(); 901 return updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL), 902 &mColorRenderTargets[colorIndexGL]); 903} 904 905angle::Result FramebufferMtl::updateDepthRenderTarget(const gl::Context *context) 906{ 907 // Reset load store action 908 mRenderPassDesc.depthAttachment.reset(); 909 return updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget); 910} 911 912angle::Result FramebufferMtl::updateStencilRenderTarget(const gl::Context *context) 913{ 914 // Reset load store action 915 mRenderPassDesc.stencilAttachment.reset(); 916 return updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget); 917} 918 919angle::Result FramebufferMtl::updateCachedRenderTarget(const gl::Context *context, 920 const gl::FramebufferAttachment *attachment, 921 RenderTargetMtl **cachedRenderTarget) 922{ 923 RenderTargetMtl *newRenderTarget = nullptr; 924 if (attachment) 925 { 926 ASSERT(attachment->isAttached()); 927 ANGLE_TRY(attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(), 928 &newRenderTarget)); 929 } 930 *cachedRenderTarget = newRenderTarget; 931 return angle::Result::Continue; 932} 933 934angle::Result FramebufferMtl::getReadableViewForRenderTarget( 935 const gl::Context *context, 936 const RenderTargetMtl &rtt, 937 const gl::Rectangle &readArea, 938 mtl::TextureRef *readableDepthViewOut, 939 mtl::TextureRef *readableStencilViewOut, 940 uint32_t *readableViewLevel, 941 uint32_t *readableViewLayer, 942 gl::Rectangle *readableViewArea) 943{ 944 ContextMtl *contextMtl = mtl::GetImpl(context); 945 mtl::TextureRef srcTexture = rtt.getTexture(); 946 uint32_t level = rtt.getLevelIndex().get(); 947 uint32_t slice = rtt.getLayerIndex(); 948 949 // NOTE(hqle): slice is not used atm. 950 ASSERT(slice == 0); 951 952 bool readStencil = readableStencilViewOut; 953 954 if (!srcTexture) 955 { 956 if (readableDepthViewOut) 957 { 958 *readableDepthViewOut = nullptr; 959 } 960 if (readableStencilViewOut) 961 { 962 *readableStencilViewOut = nullptr; 963 } 964 *readableViewArea = readArea; 965 return angle::Result::Continue; 966 } 967 968 bool skipCopy = srcTexture->isShaderReadable(); 969 if (rtt.getFormat()->hasDepthAndStencilBits() && readStencil) 970 { 971 // If the texture is packed depth stencil, and we need stencil view, 972 // then it must support creating different format view. 973 skipCopy = skipCopy && srcTexture->supportFormatView(); 974 } 975 976 if (skipCopy) 977 { 978 // Texture supports stencil view, just use it directly 979 if (readableDepthViewOut) 980 { 981 *readableDepthViewOut = srcTexture; 982 } 983 if (readableStencilViewOut) 984 { 985 *readableStencilViewOut = srcTexture; 986 } 987 *readableViewLevel = level; 988 *readableViewLayer = slice; 989 *readableViewArea = readArea; 990 } 991 else 992 { 993 ASSERT(srcTexture->textureType() != MTLTextureType3D); 994 995 // Texture doesn't support stencil view or not shader readable, copy to an interminate 996 // texture that supports stencil view and shader read. 997 mtl::TextureRef formatableView = srcTexture->getReadableCopy( 998 contextMtl, contextMtl->getBlitCommandEncoder(), level, slice, 999 MTLRegionMake2D(readArea.x, readArea.y, readArea.width, readArea.height)); 1000 1001 ANGLE_CHECK_GL_ALLOC(contextMtl, formatableView); 1002 1003 if (readableDepthViewOut) 1004 { 1005 *readableDepthViewOut = formatableView; 1006 } 1007 if (readableStencilViewOut) 1008 { 1009 *readableStencilViewOut = formatableView->getStencilView(); 1010 } 1011 1012 *readableViewLevel = 0; 1013 *readableViewLayer = 0; 1014 *readableViewArea = gl::Rectangle(0, 0, readArea.width, readArea.height); 1015 } 1016 1017 return angle::Result::Continue; 1018} 1019 1020angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, 1021 mtl::RenderPassDesc *pDescOut) 1022{ 1023 mtl::RenderPassDesc &desc = *pDescOut; 1024 1025 mRenderPassFirstColorAttachmentFormat = nullptr; 1026 mRenderPassAttachmentsSameColorType = true; 1027 uint32_t maxColorAttachments = static_cast<uint32_t>(mState.getColorAttachments().size()); 1028 desc.numColorAttachments = 0; 1029 desc.sampleCount = 1; 1030 for (uint32_t colorIndexGL = 0; colorIndexGL < maxColorAttachments; ++colorIndexGL) 1031 { 1032 ASSERT(colorIndexGL < mtl::kMaxRenderTargets); 1033 1034 mtl::RenderPassColorAttachmentDesc &colorAttachment = desc.colorAttachments[colorIndexGL]; 1035 const RenderTargetMtl *colorRenderTarget = mColorRenderTargets[colorIndexGL]; 1036 1037 if (colorRenderTarget) 1038 { 1039 colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment); 1040 1041 desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1); 1042 desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples()); 1043 1044 if (!mRenderPassFirstColorAttachmentFormat) 1045 { 1046 mRenderPassFirstColorAttachmentFormat = colorRenderTarget->getFormat(); 1047 } 1048 else if (colorRenderTarget->getFormat()) 1049 { 1050 if (mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isSint() != 1051 colorRenderTarget->getFormat()->actualAngleFormat().isSint() || 1052 mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isUint() != 1053 colorRenderTarget->getFormat()->actualAngleFormat().isUint()) 1054 { 1055 mRenderPassAttachmentsSameColorType = false; 1056 } 1057 } 1058 } 1059 else 1060 { 1061 colorAttachment.reset(); 1062 } 1063 } 1064 1065 if (mDepthRenderTarget) 1066 { 1067 mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment); 1068 desc.sampleCount = std::max(desc.sampleCount, mDepthRenderTarget->getRenderSamples()); 1069 } 1070 else 1071 { 1072 desc.depthAttachment.reset(); 1073 } 1074 1075 if (mStencilRenderTarget) 1076 { 1077 mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment); 1078 desc.sampleCount = std::max(desc.sampleCount, mStencilRenderTarget->getRenderSamples()); 1079 } 1080 else 1081 { 1082 desc.stencilAttachment.reset(); 1083 } 1084 1085 return angle::Result::Continue; 1086} 1087 1088angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context, 1089 gl::DrawBufferMask clearColorBuffers, 1090 const mtl::ClearRectParams &clearOpts) 1091{ 1092 ContextMtl *contextMtl = mtl::GetImpl(context); 1093 bool startedRenderPass = contextMtl->hasStartedRenderPass(mRenderPassDesc); 1094 mtl::RenderCommandEncoder *encoder = nullptr; 1095 1096 if (startedRenderPass) 1097 { 1098 encoder = ensureRenderPassStarted(context); 1099 if (encoder->hasDrawCalls()) 1100 { 1101 // Render pass already has draw calls recorded, it is better to use clear with draw 1102 // operation. 1103 return clearWithDraw(context, clearColorBuffers, clearOpts); 1104 } 1105 else 1106 { 1107 // If render pass has started but there is no draw call yet. It is OK to change the 1108 // loadOp. 1109 return clearWithLoadOpRenderPassStarted(context, clearColorBuffers, clearOpts, encoder); 1110 } 1111 } 1112 else 1113 { 1114 return clearWithLoadOpRenderPassNotStarted(context, clearColorBuffers, clearOpts); 1115 } 1116} 1117 1118angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( 1119 const gl::Context *context, 1120 gl::DrawBufferMask clearColorBuffers, 1121 const mtl::ClearRectParams &clearOpts) 1122{ 1123 mtl::RenderPassDesc tempDesc = mRenderPassDesc; 1124 1125 for (uint32_t colorIndexGL = 0; colorIndexGL < tempDesc.numColorAttachments; ++colorIndexGL) 1126 { 1127 ASSERT(colorIndexGL < mtl::kMaxRenderTargets); 1128 1129 mtl::RenderPassColorAttachmentDesc &colorAttachment = 1130 tempDesc.colorAttachments[colorIndexGL]; 1131 const mtl::TextureRef &texture = colorAttachment.texture; 1132 1133 if (clearColorBuffers.test(colorIndexGL)) 1134 { 1135 colorAttachment.loadAction = MTLLoadActionClear; 1136 OverrideMTLClearColor(texture, clearOpts.clearColor.value(), 1137 &colorAttachment.clearColor); 1138 } 1139 } 1140 1141 if (clearOpts.clearDepth.valid()) 1142 { 1143 tempDesc.depthAttachment.loadAction = MTLLoadActionClear; 1144 tempDesc.depthAttachment.clearDepth = clearOpts.clearDepth.value(); 1145 } 1146 1147 if (clearOpts.clearStencil.valid()) 1148 { 1149 tempDesc.stencilAttachment.loadAction = MTLLoadActionClear; 1150 tempDesc.stencilAttachment.clearStencil = clearOpts.clearStencil.value(); 1151 } 1152 1153 // Start new render encoder with loadOp=Clear 1154 ensureRenderPassStarted(context, tempDesc); 1155 1156 return angle::Result::Continue; 1157} 1158 1159angle::Result FramebufferMtl::clearWithLoadOpRenderPassStarted( 1160 const gl::Context *context, 1161 gl::DrawBufferMask clearColorBuffers, 1162 const mtl::ClearRectParams &clearOpts, 1163 mtl::RenderCommandEncoder *encoder) 1164{ 1165 ASSERT(!encoder->hasDrawCalls()); 1166 1167 for (uint32_t colorIndexGL = 0; colorIndexGL < mRenderPassDesc.numColorAttachments; 1168 ++colorIndexGL) 1169 { 1170 ASSERT(colorIndexGL < mtl::kMaxRenderTargets); 1171 1172 mtl::RenderPassColorAttachmentDesc &colorAttachment = 1173 mRenderPassDesc.colorAttachments[colorIndexGL]; 1174 const mtl::TextureRef &texture = colorAttachment.texture; 1175 1176 if (clearColorBuffers.test(colorIndexGL)) 1177 { 1178 MTLClearColor clearVal; 1179 OverrideMTLClearColor(texture, clearOpts.clearColor.value(), &clearVal); 1180 1181 encoder->setColorLoadAction(MTLLoadActionClear, clearVal, colorIndexGL); 1182 } 1183 } 1184 1185 if (clearOpts.clearDepth.valid()) 1186 { 1187 encoder->setDepthLoadAction(MTLLoadActionClear, clearOpts.clearDepth.value()); 1188 } 1189 1190 if (clearOpts.clearStencil.valid()) 1191 { 1192 encoder->setStencilLoadAction(MTLLoadActionClear, clearOpts.clearStencil.value()); 1193 } 1194 1195 return angle::Result::Continue; 1196} 1197 1198angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context, 1199 gl::DrawBufferMask clearColorBuffers, 1200 const mtl::ClearRectParams &clearOpts) 1201{ 1202 ContextMtl *contextMtl = mtl::GetImpl(context); 1203 DisplayMtl *display = contextMtl->getDisplay(); 1204 1205 if (mRenderPassAttachmentsSameColorType) 1206 { 1207 // Start new render encoder if not already. 1208 mtl::RenderCommandEncoder *encoder = ensureRenderPassStarted(context, mRenderPassDesc); 1209 1210 return display->getUtils().clearWithDraw(context, encoder, clearOpts); 1211 } 1212 1213 // Not all attachments have the same color type. 1214 mtl::ClearRectParams overrideClearOps = clearOpts; 1215 overrideClearOps.enabledBuffers.reset(); 1216 1217 // First clear depth/stencil without color attachment 1218 if (clearOpts.clearDepth.valid() || clearOpts.clearStencil.valid()) 1219 { 1220 mtl::RenderPassDesc dsOnlyDesc = mRenderPassDesc; 1221 dsOnlyDesc.numColorAttachments = 0; 1222 mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(dsOnlyDesc); 1223 1224 ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps)); 1225 } 1226 1227 // Clear the color attachment one by one. 1228 overrideClearOps.enabledBuffers.set(0); 1229 for (size_t drawbuffer : clearColorBuffers) 1230 { 1231 if (drawbuffer >= mRenderPassDesc.numColorAttachments) 1232 { 1233 // Iteration over drawbuffer indices always goes in ascending order 1234 break; 1235 } 1236 RenderTargetMtl *renderTarget = mColorRenderTargets[drawbuffer]; 1237 if (!renderTarget || !renderTarget->getTexture()) 1238 { 1239 continue; 1240 } 1241 const mtl::Format &format = *renderTarget->getFormat(); 1242 mtl::PixelType clearColorType = overrideClearOps.clearColor.value().getType(); 1243 if ((clearColorType == mtl::PixelType::Int && !format.actualAngleFormat().isSint()) || 1244 (clearColorType == mtl::PixelType::UInt && !format.actualAngleFormat().isUint()) || 1245 (clearColorType == mtl::PixelType::Float && format.actualAngleFormat().isInt())) 1246 { 1247 continue; 1248 } 1249 1250 overrideClearOps.clearWriteMaskArray[0] = overrideClearOps.clearWriteMaskArray[drawbuffer]; 1251 1252 mtl::RenderCommandEncoder *encoder = 1253 contextMtl->getRenderTargetCommandEncoder(*renderTarget); 1254 ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps)); 1255 } 1256 1257 return angle::Result::Continue; 1258} 1259 1260angle::Result FramebufferMtl::clearImpl(const gl::Context *context, 1261 gl::DrawBufferMask clearColorBuffers, 1262 mtl::ClearRectParams *pClearOpts) 1263{ 1264 auto &clearOpts = *pClearOpts; 1265 1266 if (!clearOpts.clearColor.valid() && !clearOpts.clearDepth.valid() && 1267 !clearOpts.clearStencil.valid()) 1268 { 1269 // No Op. 1270 return angle::Result::Continue; 1271 } 1272 1273 ContextMtl *contextMtl = mtl::GetImpl(context); 1274 const gl::Rectangle renderArea(0, 0, mState.getDimensions().width, 1275 mState.getDimensions().height); 1276 1277 clearOpts.colorFormat = mRenderPassFirstColorAttachmentFormat; 1278 clearOpts.dstTextureSize = mState.getExtents(); 1279 clearOpts.clearArea = ClipRectToScissor(contextMtl->getState(), renderArea, false); 1280 clearOpts.flipY = mFlipY; 1281 1282 // Discard clear altogether if scissor has 0 width or height. 1283 if (clearOpts.clearArea.width == 0 || clearOpts.clearArea.height == 0) 1284 { 1285 return angle::Result::Continue; 1286 } 1287 1288 clearOpts.clearWriteMaskArray = contextMtl->getWriteMaskArray(); 1289 uint32_t stencilMask = contextMtl->getStencilMask(); 1290 if (!contextMtl->getDepthMask()) 1291 { 1292 // Disable depth clearing, since depth write is disable 1293 clearOpts.clearDepth.reset(); 1294 } 1295 1296 // Only clear enabled buffers 1297 clearOpts.enabledBuffers = clearColorBuffers; 1298 1299 bool allBuffersUnmasked = true; 1300 for (size_t enabledBuffer : clearColorBuffers) 1301 { 1302 if (clearOpts.clearWriteMaskArray[enabledBuffer] != MTLColorWriteMaskAll) 1303 { 1304 allBuffersUnmasked = false; 1305 break; 1306 } 1307 } 1308 1309 if (clearOpts.clearArea == renderArea && 1310 (!clearOpts.clearColor.valid() || allBuffersUnmasked) && 1311 (!clearOpts.clearStencil.valid() || 1312 (stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll)) 1313 { 1314 return clearWithLoadOp(context, clearColorBuffers, clearOpts); 1315 } 1316 1317 return clearWithDraw(context, clearColorBuffers, clearOpts); 1318} 1319 1320angle::Result FramebufferMtl::invalidateImpl(ContextMtl *contextMtl, 1321 size_t count, 1322 const GLenum *attachments) 1323{ 1324 gl::DrawBufferMask invalidateColorBuffers; 1325 bool invalidateDepthBuffer = false; 1326 bool invalidateStencilBuffer = false; 1327 1328 for (size_t i = 0; i < count; ++i) 1329 { 1330 const GLenum attachment = attachments[i]; 1331 1332 switch (attachment) 1333 { 1334 case GL_DEPTH: 1335 case GL_DEPTH_ATTACHMENT: 1336 invalidateDepthBuffer = true; 1337 break; 1338 case GL_STENCIL: 1339 case GL_STENCIL_ATTACHMENT: 1340 invalidateStencilBuffer = true; 1341 break; 1342 case GL_DEPTH_STENCIL_ATTACHMENT: 1343 invalidateDepthBuffer = true; 1344 invalidateStencilBuffer = true; 1345 break; 1346 default: 1347 ASSERT( 1348 (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) || 1349 (attachment == GL_COLOR)); 1350 1351 invalidateColorBuffers.set( 1352 attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0)); 1353 } 1354 } 1355 1356 // Set the appropriate storeOp for attachments. 1357 // If we already start the render pass, then need to set the store action now. 1358 bool renderPassStarted = contextMtl->hasStartedRenderPass(mRenderPassDesc); 1359 mtl::RenderCommandEncoder *encoder = 1360 renderPassStarted ? contextMtl->getRenderCommandEncoder() : nullptr; 1361 1362 for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i) 1363 { 1364 if (invalidateColorBuffers.test(i)) 1365 { 1366 mtl::RenderPassColorAttachmentDesc &colorAttachment = 1367 mRenderPassDesc.colorAttachments[i]; 1368 colorAttachment.storeAction = MTLStoreActionDontCare; 1369 if (renderPassStarted) 1370 { 1371 encoder->setColorStoreAction(MTLStoreActionDontCare, i); 1372 } 1373 } 1374 } 1375 1376 if (invalidateDepthBuffer && mDepthRenderTarget) 1377 { 1378 mRenderPassDesc.depthAttachment.storeAction = MTLStoreActionDontCare; 1379 if (renderPassStarted) 1380 { 1381 encoder->setDepthStoreAction(MTLStoreActionDontCare); 1382 } 1383 } 1384 1385 if (invalidateStencilBuffer && mStencilRenderTarget) 1386 { 1387 mRenderPassDesc.stencilAttachment.storeAction = MTLStoreActionDontCare; 1388 if (renderPassStarted) 1389 { 1390 encoder->setStencilStoreAction(MTLStoreActionDontCare); 1391 } 1392 } 1393 1394 return angle::Result::Continue; 1395} 1396 1397gl::Rectangle FramebufferMtl::getCorrectFlippedReadArea(const gl::Context *context, 1398 const gl::Rectangle &glArea) const 1399{ 1400 RenderTargetMtl *readRT = getColorReadRenderTarget(context); 1401 if (!readRT) 1402 { 1403 readRT = mDepthRenderTarget; 1404 } 1405 if (!readRT) 1406 { 1407 readRT = mStencilRenderTarget; 1408 } 1409 ASSERT(readRT); 1410 gl::Rectangle flippedArea = glArea; 1411 if (mFlipY) 1412 { 1413 flippedArea.y = readRT->getTexture()->height(readRT->getLevelIndex()) - flippedArea.y - 1414 flippedArea.height; 1415 } 1416 1417 return flippedArea; 1418} 1419 1420angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context, 1421 const gl::Rectangle &area, 1422 const PackPixelsParams &packPixelsParams, 1423 const RenderTargetMtl *renderTarget, 1424 uint8_t *pixels) const 1425{ 1426 ContextMtl *contextMtl = mtl::GetImpl(context); 1427 if (!renderTarget) 1428 { 1429 return angle::Result::Continue; 1430 } 1431 1432 if (packPixelsParams.packBuffer) 1433 { 1434 return readPixelsToPBO(context, area, packPixelsParams, renderTarget); 1435 } 1436 1437 mtl::TextureRef texture; 1438 if (mBackbuffer) 1439 { 1440 // Backbuffer might have MSAA texture as render target, needs to obtain the 1441 // resolved texture to be able to read pixels. 1442 ANGLE_TRY(mBackbuffer->ensureColorTextureReadyForReadPixels(context)); 1443 texture = mBackbuffer->getColorTexture(); 1444 } 1445 else 1446 { 1447 texture = renderTarget->getTexture(); 1448 // For non-default framebuffer, MSAA read pixels is disallowed. 1449 if (!texture) 1450 { 1451 return angle::Result::Stop; 1452 } 1453 ANGLE_MTL_CHECK(contextMtl, texture->samples() == 1, GL_INVALID_OPERATION); 1454 } 1455 1456 const mtl::Format &readFormat = *renderTarget->getFormat(); 1457 const angle::Format &readAngleFormat = readFormat.actualAngleFormat(); 1458 1459 int bufferRowPitch = area.width * readAngleFormat.pixelBytes; 1460 angle::MemoryBuffer readPixelRowBuffer; 1461 ANGLE_CHECK_GL_ALLOC(contextMtl, readPixelRowBuffer.resize(bufferRowPitch)); 1462 1463 auto packPixelsRowParams = packPixelsParams; 1464 gl::Rectangle srcRowRegion(area.x, area.y, area.width, 1); 1465 1466 int rowOffset = packPixelsParams.reverseRowOrder ? -1 : 1; 1467 int startRow = packPixelsParams.reverseRowOrder ? (area.y1() - 1) : area.y; 1468 1469 // Copy pixels row by row 1470 packPixelsRowParams.area.height = 1; 1471 packPixelsRowParams.reverseRowOrder = false; 1472 for (int r = startRow, i = 0; i < area.height; 1473 ++i, r += rowOffset, pixels += packPixelsRowParams.outputPitch) 1474 { 1475 srcRowRegion.y = r; 1476 packPixelsRowParams.area.y = packPixelsParams.area.y + i; 1477 1478 // Read the pixels data to the row buffer 1479 ANGLE_TRY(mtl::ReadTexturePerSliceBytes( 1480 context, texture, bufferRowPitch, srcRowRegion, renderTarget->getLevelIndex(), 1481 renderTarget->getLayerIndex(), readPixelRowBuffer.data())); 1482 1483 // Convert to destination format 1484 PackPixels(packPixelsRowParams, readAngleFormat, bufferRowPitch, readPixelRowBuffer.data(), 1485 pixels); 1486 } 1487 1488 return angle::Result::Continue; 1489} 1490 1491angle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context, 1492 const gl::Rectangle &area, 1493 const PackPixelsParams &packPixelsParams, 1494 const RenderTargetMtl *renderTarget) const 1495{ 1496 ASSERT(packPixelsParams.packBuffer); 1497 ASSERT(renderTarget); 1498 1499 ContextMtl *contextMtl = mtl::GetImpl(context); 1500 1501 ANGLE_MTL_CHECK(contextMtl, packPixelsParams.offset <= std::numeric_limits<uint32_t>::max(), 1502 GL_INVALID_OPERATION); 1503 uint32_t offset = static_cast<uint32_t>(packPixelsParams.offset); 1504 1505 BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer); 1506 mtl::BufferRef dstBuffer = packBufferMtl->getCurrentBuffer(); 1507 1508 return readPixelsToBuffer(context, area, renderTarget, packPixelsParams.reverseRowOrder, 1509 *packPixelsParams.destFormat, offset, packPixelsParams.outputPitch, 1510 &dstBuffer); 1511} 1512 1513angle::Result FramebufferMtl::readPixelsToBuffer(const gl::Context *context, 1514 const gl::Rectangle &area, 1515 const RenderTargetMtl *renderTarget, 1516 bool reverseRowOrder, 1517 const angle::Format &dstAngleFormat, 1518 uint32_t dstBufferOffset, 1519 uint32_t dstBufferRowPitch, 1520 const mtl::BufferRef *pDstBuffer) const 1521{ 1522 ASSERT(renderTarget); 1523 1524 ContextMtl *contextMtl = mtl::GetImpl(context); 1525 1526 const mtl::Format &readFormat = *renderTarget->getFormat(); 1527 const angle::Format &readAngleFormat = readFormat.actualAngleFormat(); 1528 1529 mtl::TextureRef texture = renderTarget->getTexture(); 1530 1531 const mtl::BufferRef &dstBuffer = *pDstBuffer; 1532 1533 if (dstAngleFormat.id != readAngleFormat.id || texture->samples() > 1 || 1534 (dstBufferOffset % dstAngleFormat.pixelBytes) || 1535 (dstBufferOffset % mtl::kTextureToBufferBlittingAlignment)) 1536 { 1537 const angle::Format *actualDstAngleFormat; 1538 1539 // SRGB is special case: We need to write sRGB values to buffer, not linear values. 1540 switch (readAngleFormat.id) 1541 { 1542 case angle::FormatID::B8G8R8A8_UNORM_SRGB: 1543 case angle::FormatID::R8G8B8_UNORM_SRGB: 1544 case angle::FormatID::R8G8B8A8_UNORM_SRGB: 1545 if (dstAngleFormat.id != readAngleFormat.id) 1546 { 1547 switch (dstAngleFormat.id) 1548 { 1549 case angle::FormatID::B8G8R8A8_UNORM: 1550 actualDstAngleFormat = 1551 &angle::Format::Get(angle::FormatID::B8G8R8A8_UNORM_SRGB); 1552 break; 1553 case angle::FormatID::R8G8B8A8_UNORM: 1554 actualDstAngleFormat = 1555 &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM_SRGB); 1556 break; 1557 default: 1558 // Unsupported format. 1559 ANGLE_MTL_CHECK(contextMtl, false, GL_INVALID_ENUM); 1560 } 1561 break; 1562 } 1563 OS_FALLTHROUGH; 1564 default: 1565 actualDstAngleFormat = &dstAngleFormat; 1566 } 1567 1568 // Use compute shader 1569 mtl::CopyPixelsToBufferParams params; 1570 params.buffer = dstBuffer; 1571 params.bufferStartOffset = dstBufferOffset; 1572 params.bufferRowPitch = dstBufferRowPitch; 1573 1574 params.texture = texture; 1575 params.textureArea = area; 1576 params.textureLevel = renderTarget->getLevelIndex(); 1577 params.textureSliceOrDeph = renderTarget->getLayerIndex(); 1578 params.reverseTextureRowOrder = reverseRowOrder; 1579 1580 ANGLE_TRY(contextMtl->getDisplay()->getUtils().packPixelsFromTextureToBuffer( 1581 contextMtl, *actualDstAngleFormat, params)); 1582 } 1583 else 1584 { 1585 // Use blit command encoder 1586 if (!reverseRowOrder) 1587 { 1588 ANGLE_TRY(mtl::ReadTexturePerSliceBytesToBuffer( 1589 context, texture, dstBufferRowPitch, area, renderTarget->getLevelIndex(), 1590 renderTarget->getLayerIndex(), dstBufferOffset, dstBuffer)); 1591 } 1592 else 1593 { 1594 gl::Rectangle srcRowRegion(area.x, area.y, area.width, 1); 1595 1596 int startRow = area.y1() - 1; 1597 1598 uint32_t bufferRowOffset = dstBufferOffset; 1599 // Copy pixels row by row 1600 for (int r = startRow, copiedRows = 0; copiedRows < area.height; 1601 ++copiedRows, --r, bufferRowOffset += dstBufferRowPitch) 1602 { 1603 srcRowRegion.y = r; 1604 1605 // Read the pixels data to the buffer's row 1606 ANGLE_TRY(mtl::ReadTexturePerSliceBytesToBuffer( 1607 context, texture, dstBufferRowPitch, srcRowRegion, 1608 renderTarget->getLevelIndex(), renderTarget->getLayerIndex(), bufferRowOffset, 1609 dstBuffer)); 1610 } 1611 } 1612 } 1613 1614 return angle::Result::Continue; 1615} 1616 1617} 1618