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