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// ContextMtl.mm: 7// Implements the class methods for ContextMtl. 8// 9 10#include "libANGLE/renderer/metal/ContextMtl.h" 11 12#include <TargetConditionals.h> 13#include <cstdint> 14 15#include "GLSLANG/ShaderLang.h" 16#include "common/debug.h" 17#include "image_util/loadimage.h" 18#include "libANGLE/Display.h" 19#include "libANGLE/Query.h" 20#include "libANGLE/TransformFeedback.h" 21#include "libANGLE/renderer/OverlayImpl.h" 22#include "libANGLE/renderer/metal/BufferMtl.h" 23#include "libANGLE/renderer/metal/CompilerMtl.h" 24#include "libANGLE/renderer/metal/DisplayMtl.h" 25#include "libANGLE/renderer/metal/FrameBufferMtl.h" 26#include "libANGLE/renderer/metal/ProgramExecutableMtl.h" 27#include "libANGLE/renderer/metal/ProgramMtl.h" 28#include "libANGLE/renderer/metal/QueryMtl.h" 29#include "libANGLE/renderer/metal/RenderBufferMtl.h" 30#include "libANGLE/renderer/metal/RenderTargetMtl.h" 31#include "libANGLE/renderer/metal/SamplerMtl.h" 32#include "libANGLE/renderer/metal/ShaderMtl.h" 33#include "libANGLE/renderer/metal/SyncMtl.h" 34#include "libANGLE/renderer/metal/TextureMtl.h" 35#include "libANGLE/renderer/metal/TransformFeedbackMtl.h" 36#include "libANGLE/renderer/metal/VertexArrayMtl.h" 37#include "libANGLE/renderer/metal/mtl_command_buffer.h" 38#include "libANGLE/renderer/metal/mtl_common.h" 39#include "libANGLE/renderer/metal/mtl_context_device.h" 40#include "libANGLE/renderer/metal/mtl_format_utils.h" 41#include "libANGLE/renderer/metal/mtl_utils.h" 42 43namespace rx 44{ 45 46namespace 47{ 48#if TARGET_OS_OSX 49// Unlimited triangle fan buffers 50constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 0; 51#else 52// Allow up to 10 buffers for trifan/line loop generation without stalling the GPU. 53constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10; 54#endif 55 56#define ANGLE_MTL_XFB_DRAW(DRAW_PROC) \ 57 if (!mState.isTransformFeedbackActiveUnpaused()) \ 58 { \ 59 /* Normal draw call */ \ 60 DRAW_PROC(false); \ 61 } \ 62 else \ 63 { \ 64 /* First pass: write to XFB buffers in vertex shader, fragment shader inactive */ \ 65 bool rasterizationNotDisabled = \ 66 mRenderPipelineDesc.rasterizationType != mtl::RenderPipelineRasterization::Disabled; \ 67 if (rasterizationNotDisabled) \ 68 { \ 69 invalidateRenderPipeline(); \ 70 } \ 71 DRAW_PROC(true); \ 72 if (rasterizationNotDisabled) \ 73 { \ 74 /* Second pass: full rasterization: vertex shader + fragment shader are active. \ 75 Vertex shader writes to stage output but won't write to XFB buffers */ \ 76 invalidateRenderPipeline(); \ 77 DRAW_PROC(false); \ 78 } \ 79 } 80 81angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, 82 GLsizei vertexCount, 83 mtl::BufferPool *pool, 84 mtl::BufferRef *bufferOut, 85 uint32_t *offsetOut, 86 uint32_t *numElemsOut) 87{ 88 uint32_t numIndices; 89 ANGLE_TRY(mtl::GetTriangleFanIndicesCount(context, vertexCount, &numIndices)); 90 91 size_t offset; 92 pool->releaseInFlightBuffers(context); 93 ANGLE_TRY(pool->allocate(context, numIndices * sizeof(uint32_t), nullptr, bufferOut, &offset, 94 nullptr)); 95 96 *offsetOut = static_cast<uint32_t>(offset); 97 *numElemsOut = numIndices; 98 99 return angle::Result::Continue; 100} 101 102angle::Result AllocateBufferFromPool(ContextMtl *context, 103 GLsizei indicesToReserve, 104 mtl::BufferPool *pool, 105 mtl::BufferRef *bufferOut, 106 uint32_t *offsetOut) 107{ 108 size_t offset; 109 pool->releaseInFlightBuffers(context); 110 ANGLE_TRY(pool->allocate(context, indicesToReserve * sizeof(uint32_t), nullptr, bufferOut, 111 &offset, nullptr)); 112 113 *offsetOut = static_cast<uint32_t>(offset); 114 115 return angle::Result::Continue; 116} 117 118bool NeedToInvertDepthRange(float near, float far) 119{ 120 return near > far; 121} 122 123bool IsTransformFeedbackOnly(const gl::State &glState) 124{ 125 return glState.isTransformFeedbackActiveUnpaused() && glState.isRasterizerDiscardEnabled(); 126} 127 128std::string ConvertMarkerToString(GLsizei length, const char *marker) 129{ 130 std::string cppString; 131 if (length == 0) 132 { 133 cppString = marker; 134 } 135 else 136 { 137 cppString.assign(marker, length); 138 } 139 return cppString; 140} 141 142// This class constructs line loop's last segment buffer inside begin() method 143// and perform the draw of the line loop's last segment inside destructor 144class LineLoopLastSegmentHelper 145{ 146 public: 147 LineLoopLastSegmentHelper() {} 148 149 ~LineLoopLastSegmentHelper() 150 { 151 if (!mLineLoopIndexBuffer) 152 { 153 return; 154 } 155 156 // Draw last segment of line loop here 157 mtl::RenderCommandEncoder *encoder = mContextMtl->getRenderCommandEncoder(); 158 ASSERT(encoder); 159 encoder->drawIndexed(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32, mLineLoopIndexBuffer, 0); 160 } 161 162 angle::Result begin(const gl::Context *context, 163 mtl::BufferPool *indexBufferPool, 164 GLint firstVertex, 165 GLsizei vertexOrIndexCount, 166 gl::DrawElementsType indexTypeOrNone, 167 const void *indices) 168 { 169 mContextMtl = mtl::GetImpl(context); 170 171 indexBufferPool->releaseInFlightBuffers(mContextMtl); 172 173 ANGLE_TRY(indexBufferPool->allocate(mContextMtl, 2 * sizeof(uint32_t), nullptr, 174 &mLineLoopIndexBuffer, nullptr, nullptr)); 175 176 if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum) 177 { 178 ANGLE_TRY(mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegment( 179 mContextMtl, firstVertex, firstVertex + vertexOrIndexCount - 1, 180 mLineLoopIndexBuffer, 0)); 181 } 182 else 183 { 184 ASSERT(firstVertex == 0); 185 ANGLE_TRY( 186 mContextMtl->getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray( 187 mContextMtl, 188 {indexTypeOrNone, vertexOrIndexCount, indices, mLineLoopIndexBuffer, 0})); 189 } 190 191 ANGLE_TRY(indexBufferPool->commit(mContextMtl)); 192 193 return angle::Result::Continue; 194 } 195 196 private: 197 ContextMtl *mContextMtl = nullptr; 198 mtl::BufferRef mLineLoopIndexBuffer; 199}; 200 201GLint GetOwnershipIdentity(const egl::AttributeMap &attribs) 202{ 203 return attribs.getAsInt(EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE, 0); 204} 205 206} // namespace 207 208ContextMtl::ContextMtl(const gl::State &state, 209 gl::ErrorSet *errorSet, 210 const egl::AttributeMap &attribs, 211 DisplayMtl *display) 212 : ContextImpl(state, errorSet), 213 mtl::Context(display), 214 mCmdBuffer(&display->cmdQueue()), 215 mRenderEncoder(&mCmdBuffer, 216 mOcclusionQueryPool, 217 display->getFeatures().emulateDontCareLoadWithRandomClear.enabled), 218 mBlitEncoder(&mCmdBuffer), 219 mComputeEncoder(&mCmdBuffer), 220 mDriverUniforms{}, 221 mProvokingVertexHelper(this), 222 mContextDevice(GetOwnershipIdentity(attribs)) 223{} 224 225ContextMtl::~ContextMtl() {} 226 227angle::Result ContextMtl::initialize(const angle::ImageLoadContext &imageLoadContext) 228{ 229 for (mtl::BlendDesc &blendDesc : mBlendDescArray) 230 { 231 blendDesc.reset(); 232 } 233 234 mWriteMaskArray.fill(MTLColorWriteMaskAll); 235 236 mDepthStencilDesc.reset(); 237 238 mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment, 239 kMaxTriFanLineLoopBuffersPerFrame); 240 mLineLoopIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment, 241 kMaxTriFanLineLoopBuffersPerFrame); 242 mLineLoopLastSegmentIndexBuffer.initialize(this, 2 * sizeof(uint32_t), 243 mtl::kIndexBufferOffsetAlignment, 244 kMaxTriFanLineLoopBuffersPerFrame); 245 246 mContextDevice.set(mDisplay->getMetalDevice()); 247 248 mImageLoadContext = imageLoadContext; 249 250 return angle::Result::Continue; 251} 252 253void ContextMtl::onDestroy(const gl::Context *context) 254{ 255 mTriFanIndexBuffer.destroy(this); 256 mLineLoopIndexBuffer.destroy(this); 257 mLineLoopLastSegmentIndexBuffer.destroy(this); 258 mOcclusionQueryPool.destroy(this); 259 260 mIncompleteTextures.onDestroy(context); 261 mProvokingVertexHelper.onDestroy(this); 262 mDummyXFBRenderTexture = nullptr; 263 264 mContextDevice.reset(); 265} 266 267// Flush and finish. 268angle::Result ContextMtl::flush(const gl::Context *context) 269{ 270 // MTLSharedEvent is available on these platforms, and callers 271 // are expected to use the EGL_ANGLE_metal_shared_event_sync 272 // extension to synchronize with ANGLE's Metal backend, if 273 // needed. This is typically required if two MTLDevices are 274 // operating on the same IOSurface. 275 flushCommandBuffer(mtl::NoWait); 276 return checkCommandBufferError(); 277} 278angle::Result ContextMtl::finish(const gl::Context *context) 279{ 280 ANGLE_TRY(finishCommandBuffer()); 281 return checkCommandBufferError(); 282} 283 284ANGLE_INLINE angle::Result ContextMtl::resyncDrawFramebufferIfNeeded(const gl::Context *context) 285{ 286 // Resync the draw framebuffer if 287 // - it has incompatible attachments; OR 288 // - it had incompatible attachments during the previous operation. 289 if (ANGLE_UNLIKELY(mIncompatibleAttachments.any() || mForceResyncDrawFramebuffer)) 290 { 291 if (mIncompatibleAttachments.any()) 292 { 293 ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, 294 "Resyncing the draw framebuffer because it has active attachments " 295 "incompatible with the current program outputs."); 296 } 297 298 // Ensure sync on the next operation if the current state has incompatible attachments. 299 mForceResyncDrawFramebuffer = mIncompatibleAttachments.any(); 300 301 FramebufferMtl *fbo = mtl::GetImpl(getState().getDrawFramebuffer()); 302 ASSERT(fbo != nullptr); 303 return fbo->syncState(context, GL_DRAW_FRAMEBUFFER, gl::Framebuffer::DirtyBits(), 304 gl::Command::Draw); 305 } 306 return angle::Result::Continue; 307} 308 309// Drawing methods. 310angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *context, 311 GLint first, 312 GLsizei count, 313 GLsizei instances, 314 GLuint baseInstance) 315{ 316 ASSERT((getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled)); 317 318 uint32_t genIndicesCount; 319 ANGLE_TRY(mtl::GetTriangleFanIndicesCount(this, count, &genIndicesCount)); 320 321 size_t indexBufferSize = genIndicesCount * sizeof(uint32_t); 322 // We can reuse the previously generated index buffer if it has more than enough indices 323 // data already. 324 if (mTriFanArraysIndexBuffer == nullptr || mTriFanArraysIndexBuffer->size() < indexBufferSize) 325 { 326 // Re-generate a new index buffer, which the first index will be zero. 327 ANGLE_TRY( 328 mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer)); 329 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( 330 this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0})); 331 } 332 333 ASSERT(!getState().isTransformFeedbackActiveUnpaused()); 334 bool isNoOp = false; 335 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, 336 gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0), false, 337 &isNoOp)); 338 if (!isNoOp) 339 { 340 // Draw with the zero starting index buffer, shift the vertex index using baseVertex 341 // instanced draw: 342 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( 343 MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32, mTriFanArraysIndexBuffer, 344 0, instances, first, baseInstance); 345 } 346 347 return angle::Result::Continue; 348} 349angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context, 350 GLint first, 351 GLsizei count, 352 GLsizei instances) 353{ 354 // Legacy method is only used for GPU lacking instanced base vertex draw capabilities. 355 mtl::BufferRef genIdxBuffer; 356 uint32_t genIdxBufferOffset; 357 uint32_t genIndicesCount; 358 ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, 359 &genIdxBufferOffset, &genIndicesCount)); 360 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( 361 this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer, 362 genIdxBufferOffset})); 363 364 ANGLE_TRY(mTriFanIndexBuffer.commit(this)); 365 366 ASSERT(!getState().isTransformFeedbackActiveUnpaused()); 367 bool isNoOp = false; 368 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, 369 gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0), false, 370 &isNoOp)); 371 if (!isNoOp) 372 { 373 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, 374 MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset, 375 instances); 376 } 377 return angle::Result::Continue; 378} 379angle::Result ContextMtl::drawTriFanArrays(const gl::Context *context, 380 GLint first, 381 GLsizei count, 382 GLsizei instances, 383 GLuint baseInstance) 384{ 385 if (count <= 3 && baseInstance == 0) 386 { 387 return drawArraysImpl(context, gl::PrimitiveMode::Triangles, first, count, instances, 0); 388 } 389 if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled) 390 { 391 return drawTriFanArraysWithBaseVertex(context, first, count, instances, baseInstance); 392 } 393 return drawTriFanArraysLegacy(context, first, count, instances); 394} 395 396angle::Result ContextMtl::drawLineLoopArraysNonInstanced(const gl::Context *context, 397 GLint first, 398 GLsizei count) 399{ 400 // Generate line loop's last segment. It will be rendered when this function exits. 401 LineLoopLastSegmentHelper lineloopHelper; 402 // Line loop helper needs to generate last segment indices before rendering command encoder 403 // starts. 404 ANGLE_TRY(lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, first, count, 405 gl::DrawElementsType::InvalidEnum, nullptr)); 406 407 return drawArraysImpl(context, gl::PrimitiveMode::LineStrip, first, count, 0, 0); 408} 409 410angle::Result ContextMtl::drawLineLoopArrays(const gl::Context *context, 411 GLint first, 412 GLsizei count, 413 GLsizei instances, 414 GLuint baseInstance) 415{ 416 if (instances <= 1 && baseInstance == 0) 417 { 418 return drawLineLoopArraysNonInstanced(context, first, count); 419 } 420 421 mtl::BufferRef genIdxBuffer; 422 uint32_t genIdxBufferOffset; 423 uint32_t genIndicesCount = count + 1; 424 425 ANGLE_TRY(AllocateBufferFromPool(this, genIndicesCount, &mLineLoopIndexBuffer, &genIdxBuffer, 426 &genIdxBufferOffset)); 427 ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromArrays( 428 this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer, 429 genIdxBufferOffset})); 430 431 ANGLE_TRY(mLineLoopIndexBuffer.commit(this)); 432 433 ASSERT(!getState().isTransformFeedbackActiveUnpaused()); 434 bool isNoOp = false; 435 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, first, count, instances, 436 gl::DrawElementsType::InvalidEnum, nullptr, false, &isNoOp)); 437 if (!isNoOp) 438 { 439 if (baseInstance == 0) 440 { 441 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, 442 MTLIndexTypeUInt32, genIdxBuffer, 443 genIdxBufferOffset, instances); 444 } 445 else 446 { 447 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( 448 MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer, 449 genIdxBufferOffset, instances, 0, baseInstance); 450 } 451 } 452 453 return angle::Result::Continue; 454} 455 456angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, 457 gl::PrimitiveMode mode, 458 GLint first, 459 GLsizei count, 460 GLsizei instances, 461 GLuint baseInstance) 462{ 463 // Real instances count. Zero means this is not instanced draw. 464 GLsizei instanceCount = instances ? instances : 1; 465 466 if (mCullAllPolygons && gl::IsPolygonMode(mode)) 467 { 468 return angle::Result::Continue; 469 } 470 if (requiresIndexRewrite(context->getState(), mode)) 471 { 472 return drawArraysProvokingVertexImpl(context, mode, first, count, instances, baseInstance); 473 } 474 if (mode == gl::PrimitiveMode::TriangleFan) 475 { 476 return drawTriFanArrays(context, first, count, instanceCount, baseInstance); 477 } 478 else if (mode == gl::PrimitiveMode::LineLoop) 479 { 480 return drawLineLoopArrays(context, first, count, instanceCount, baseInstance); 481 } 482 483 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); 484 485#define DRAW_GENERIC_ARRAY(xfbPass) \ 486 { \ 487 bool isNoOp = false; \ 488 ANGLE_TRY(setupDraw(context, mode, first, count, instances, \ 489 gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ 490 if (!isNoOp) \ 491 { \ 492 \ 493 if (instances == 0) \ 494 { \ 495 /* This method is called from normal drawArrays() */ \ 496 mRenderEncoder.draw(mtlType, first, count); \ 497 } \ 498 else \ 499 { \ 500 if (baseInstance == 0) \ 501 { \ 502 mRenderEncoder.drawInstanced(mtlType, first, count, instanceCount); \ 503 } \ 504 else \ 505 { \ 506 mRenderEncoder.drawInstancedBaseInstance(mtlType, first, count, instanceCount, \ 507 baseInstance); \ 508 } \ 509 } \ 510 } \ 511 } 512 513 ANGLE_MTL_XFB_DRAW(DRAW_GENERIC_ARRAY) 514 515 return angle::Result::Continue; 516} 517 518angle::Result ContextMtl::drawArrays(const gl::Context *context, 519 gl::PrimitiveMode mode, 520 GLint first, 521 GLsizei count) 522{ 523 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 524 return drawArraysImpl(context, mode, first, count, 0, 0); 525} 526 527angle::Result ContextMtl::drawArraysInstanced(const gl::Context *context, 528 gl::PrimitiveMode mode, 529 GLint first, 530 GLsizei count, 531 GLsizei instances) 532{ 533 // Instanced draw calls with zero instances are skipped in the frontend. 534 // The drawArraysImpl function would treat them as non-instanced. 535 ASSERT(instances > 0); 536 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 537 return drawArraysImpl(context, mode, first, count, instances, 0); 538} 539 540angle::Result ContextMtl::drawArraysInstancedBaseInstance(const gl::Context *context, 541 gl::PrimitiveMode mode, 542 GLint first, 543 GLsizei count, 544 GLsizei instanceCount, 545 GLuint baseInstance) 546{ 547 // Instanced draw calls with zero instances are skipped in the frontend. 548 // The drawArraysImpl function would treat them as non-instanced. 549 ASSERT(instanceCount > 0); 550 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 551 return drawArraysImpl(context, mode, first, count, instanceCount, baseInstance); 552} 553 554angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, 555 GLsizei count, 556 gl::DrawElementsType type, 557 const void *indices, 558 GLsizei instances, 559 GLint baseVertex, 560 GLuint baseInstance) 561{ 562 if (count > 3) 563 { 564 mtl::BufferRef genIdxBuffer; 565 uint32_t genIdxBufferOffset; 566 uint32_t genIndicesCount; 567 bool primitiveRestart = getState().isPrimitiveRestartEnabled(); 568 ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, 569 &genIdxBufferOffset, &genIndicesCount)); 570 571 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray( 572 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart}, 573 &genIndicesCount)); 574 575 ANGLE_TRY(mTriFanIndexBuffer.commit(this)); 576 bool isNoOp = false; 577 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type, 578 indices, false, &isNoOp)); 579 if (!isNoOp && genIndicesCount > 0) 580 { 581 if (baseVertex == 0 && baseInstance == 0) 582 { 583 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, 584 MTLIndexTypeUInt32, genIdxBuffer, 585 genIdxBufferOffset, instances); 586 } 587 else 588 { 589 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( 590 MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer, 591 genIdxBufferOffset, instances, baseVertex, baseInstance); 592 } 593 } 594 595 return angle::Result::Continue; 596 } // if (count > 3) 597 return drawElementsImpl(context, gl::PrimitiveMode::Triangles, count, type, indices, instances, 598 baseVertex, baseInstance); 599} 600 601angle::Result ContextMtl::drawLineLoopElementsNonInstancedNoPrimitiveRestart( 602 const gl::Context *context, 603 GLsizei count, 604 gl::DrawElementsType type, 605 const void *indices) 606{ 607 // Generate line loop's last segment. It will be rendered when this function exits. 608 LineLoopLastSegmentHelper lineloopHelper; 609 // Line loop helper needs to generate index before rendering command encoder starts. 610 ANGLE_TRY( 611 lineloopHelper.begin(context, &mLineLoopLastSegmentIndexBuffer, 0, count, type, indices)); 612 613 return drawElementsImpl(context, gl::PrimitiveMode::LineStrip, count, type, indices, 0, 0, 0); 614} 615 616angle::Result ContextMtl::drawLineLoopElements(const gl::Context *context, 617 GLsizei count, 618 gl::DrawElementsType type, 619 const void *indices, 620 GLsizei instances, 621 GLint baseVertex, 622 GLuint baseInstance) 623{ 624 if (count >= 2) 625 { 626 bool primitiveRestart = getState().isPrimitiveRestartEnabled(); 627 if (instances <= 1 && !primitiveRestart && baseVertex == 0 && baseInstance == 0) 628 { 629 // Non instanced draw and no primitive restart, just use faster version. 630 return drawLineLoopElementsNonInstancedNoPrimitiveRestart(context, count, type, 631 indices); 632 } 633 634 mtl::BufferRef genIdxBuffer; 635 uint32_t genIdxBufferOffset; 636 uint32_t reservedIndices = count * 2; 637 uint32_t genIndicesCount; 638 ANGLE_TRY(AllocateBufferFromPool(this, reservedIndices, &mLineLoopIndexBuffer, 639 &genIdxBuffer, &genIdxBufferOffset)); 640 641 ANGLE_TRY(getDisplay()->getUtils().generateLineLoopBufferFromElementsArray( 642 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset, primitiveRestart}, 643 &genIndicesCount)); 644 645 ANGLE_TRY(mLineLoopIndexBuffer.commit(this)); 646 bool isNoOp = false; 647 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::LineLoop, 0, count, instances, type, 648 indices, false, &isNoOp)); 649 if (!isNoOp && genIndicesCount > 0) 650 { 651 if (baseVertex == 0 && baseInstance == 0) 652 { 653 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLineStrip, genIndicesCount, 654 MTLIndexTypeUInt32, genIdxBuffer, 655 genIdxBufferOffset, instances); 656 } 657 else 658 { 659 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( 660 MTLPrimitiveTypeLineStrip, genIndicesCount, MTLIndexTypeUInt32, genIdxBuffer, 661 genIdxBufferOffset, instances, baseVertex, baseInstance); 662 } 663 } 664 665 return angle::Result::Continue; 666 } // if (count >= 2) 667 return drawElementsImpl(context, gl::PrimitiveMode::Lines, count, type, indices, instances, 668 baseVertex, baseInstance); 669} 670 671angle::Result ContextMtl::drawArraysProvokingVertexImpl(const gl::Context *context, 672 gl::PrimitiveMode mode, 673 GLsizei first, 674 GLsizei count, 675 GLsizei instances, 676 GLuint baseInstance) 677{ 678 679 size_t outIndexCount = 0; 680 size_t outIndexOffset = 0; 681 gl::DrawElementsType convertedType = gl::DrawElementsType::UnsignedInt; 682 gl::PrimitiveMode outIndexMode = gl::PrimitiveMode::InvalidEnum; 683 684 mtl::BufferRef drawIdxBuffer; 685 ANGLE_TRY(mProvokingVertexHelper.generateIndexBuffer( 686 mtl::GetImpl(context), first, count, mode, convertedType, outIndexCount, outIndexOffset, 687 outIndexMode, drawIdxBuffer)); 688 GLsizei outIndexCounti32 = static_cast<GLsizei>(outIndexCount); 689 690 // Note: we don't need to pass the generated index buffer to ContextMtl::setupDraw. 691 // Because setupDraw only needs to operate on the original vertex buffers & PrimitiveMode. 692 // setupDraw might convert vertex attributes if the offset & alignment are not natively 693 // supported by Metal. However, the converted attributes have the same order as the original 694 // vertices. Hence the conversion doesn't need to know about the newly generated index buffer. 695#define DRAW_PROVOKING_VERTEX_ARRAY(xfbPass) \ 696 if (xfbPass) \ 697 { \ 698 bool isNoOp = false; \ 699 ANGLE_TRY(setupDraw(context, mode, first, count, instances, \ 700 gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ 701 if (!isNoOp) \ 702 { \ 703 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); \ 704 if (instances == 0) \ 705 { \ 706 /* This method is called from normal drawArrays() */ \ 707 mRenderEncoder.draw(mtlType, first, count); \ 708 } \ 709 else \ 710 { \ 711 if (baseInstance == 0) \ 712 { \ 713 mRenderEncoder.drawInstanced(mtlType, first, count, instances); \ 714 } \ 715 else \ 716 { \ 717 mRenderEncoder.drawInstancedBaseInstance(mtlType, first, count, instances, \ 718 baseInstance); \ 719 } \ 720 } \ 721 } \ 722 } \ 723 else \ 724 { \ 725 bool isNoOp = false; \ 726 ANGLE_TRY(setupDraw(context, mode, first, count, instances, \ 727 gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ 728 \ 729 if (!isNoOp) \ 730 { \ 731 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(outIndexMode); \ 732 MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType); \ 733 if (instances == 0) \ 734 { \ 735 mRenderEncoder.drawIndexed(mtlType, outIndexCounti32, mtlIdxType, drawIdxBuffer, \ 736 outIndexOffset); \ 737 } \ 738 else \ 739 { \ 740 if (baseInstance == 0) \ 741 { \ 742 mRenderEncoder.drawIndexedInstanced(mtlType, outIndexCounti32, mtlIdxType, \ 743 drawIdxBuffer, outIndexOffset, instances); \ 744 } \ 745 else \ 746 { \ 747 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( \ 748 mtlType, outIndexCounti32, mtlIdxType, drawIdxBuffer, outIndexOffset, \ 749 instances, 0, baseInstance); \ 750 } \ 751 } \ 752 } \ 753 } 754 755 ANGLE_MTL_XFB_DRAW(DRAW_PROVOKING_VERTEX_ARRAY) 756 return angle::Result::Continue; 757} 758 759angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, 760 gl::PrimitiveMode mode, 761 GLsizei count, 762 gl::DrawElementsType type, 763 const void *indices, 764 GLsizei instances, 765 GLint baseVertex, 766 GLuint baseInstance) 767{ 768 // Real instances count. Zero means this is not instanced draw. 769 GLsizei instanceCount = instances ? instances : 1; 770 771 if (mCullAllPolygons && gl::IsPolygonMode(mode)) 772 { 773 return angle::Result::Continue; 774 } 775 776 if (mode == gl::PrimitiveMode::TriangleFan) 777 { 778 return drawTriFanElements(context, count, type, indices, instanceCount, baseVertex, 779 baseInstance); 780 } 781 else if (mode == gl::PrimitiveMode::LineLoop) 782 { 783 return drawLineLoopElements(context, count, type, indices, instanceCount, baseVertex, 784 baseInstance); 785 } 786 787 mtl::BufferRef idxBuffer; 788 mtl::BufferRef drawIdxBuffer; 789 size_t convertedOffset = 0; 790 gl::DrawElementsType convertedType = type; 791 792 ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer, 793 &convertedOffset, &convertedType)); 794 795 ASSERT(idxBuffer); 796 ASSERT((convertedType == gl::DrawElementsType::UnsignedShort && (convertedOffset % 2) == 0) || 797 (convertedType == gl::DrawElementsType::UnsignedInt && (convertedOffset % 4) == 0)); 798 799 uint32_t convertedCounti32 = (uint32_t)count; 800 801 size_t provokingVertexAdditionalOffset = 0; 802 803 if (requiresIndexRewrite(context->getState(), mode)) 804 { 805 size_t outIndexCount = 0; 806 gl::PrimitiveMode newMode = gl::PrimitiveMode::InvalidEnum; 807 ANGLE_TRY(mProvokingVertexHelper.preconditionIndexBuffer( 808 mtl::GetImpl(context), idxBuffer, count, convertedOffset, 809 mState.isPrimitiveRestartEnabled(), mode, convertedType, outIndexCount, 810 provokingVertexAdditionalOffset, newMode, drawIdxBuffer)); 811 // Line strips and triangle strips are rewritten to flat line arrays and tri arrays. 812 convertedCounti32 = (uint32_t)outIndexCount; 813 mode = newMode; 814 } 815 else 816 { 817 drawIdxBuffer = idxBuffer; 818 } 819 // Draw commands will only be broken up if transform feedback is enabled, 820 // if the mode is a simple type, and if the buffer contained any restart 821 // indices. 822 // It's safe to use idxBuffer in this case, as it will contain the same count and restart ranges 823 // as drawIdxBuffer. 824 const std::vector<DrawCommandRange> drawCommands = mVertexArray->getDrawIndices( 825 context, type, convertedType, mode, idxBuffer, convertedCounti32, convertedOffset); 826 bool isNoOp = false; 827 ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices, false, &isNoOp)); 828 if (!isNoOp) 829 { 830 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); 831 832 MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType); 833 834 if (instances == 0 && baseVertex == 0 && baseInstance == 0) 835 { 836 // Normal draw 837 for (auto &command : drawCommands) 838 { 839 mRenderEncoder.drawIndexed(mtlType, command.count, mtlIdxType, drawIdxBuffer, 840 command.offset + provokingVertexAdditionalOffset); 841 } 842 } 843 else 844 { 845 // Instanced draw 846 if (baseVertex == 0 && baseInstance == 0) 847 { 848 for (auto &command : drawCommands) 849 { 850 mRenderEncoder.drawIndexedInstanced( 851 mtlType, command.count, mtlIdxType, drawIdxBuffer, 852 command.offset + provokingVertexAdditionalOffset, instanceCount); 853 } 854 } 855 else 856 { 857 for (auto &command : drawCommands) 858 { 859 mRenderEncoder.drawIndexedInstancedBaseVertexBaseInstance( 860 mtlType, command.count, mtlIdxType, drawIdxBuffer, 861 command.offset + provokingVertexAdditionalOffset, instanceCount, baseVertex, 862 baseInstance); 863 } 864 } 865 } 866 } 867 return angle::Result::Continue; 868} 869 870angle::Result ContextMtl::drawElements(const gl::Context *context, 871 gl::PrimitiveMode mode, 872 GLsizei count, 873 gl::DrawElementsType type, 874 const void *indices) 875{ 876 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 877 return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0); 878} 879 880angle::Result ContextMtl::drawElementsBaseVertex(const gl::Context *context, 881 gl::PrimitiveMode mode, 882 GLsizei count, 883 gl::DrawElementsType type, 884 const void *indices, 885 GLint baseVertex) 886{ 887 UNIMPLEMENTED(); 888 return angle::Result::Stop; 889} 890 891angle::Result ContextMtl::drawElementsInstanced(const gl::Context *context, 892 gl::PrimitiveMode mode, 893 GLsizei count, 894 gl::DrawElementsType type, 895 const void *indices, 896 GLsizei instanceCount) 897{ 898 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 899 // Instanced draw calls with zero instances are skipped in the frontend. 900 // The drawElementsImpl function would treat them as non-instanced. 901 ASSERT(instanceCount > 0); 902 return drawElementsImpl(context, mode, count, type, indices, instanceCount, 0, 0); 903} 904 905angle::Result ContextMtl::drawElementsInstancedBaseVertex(const gl::Context *context, 906 gl::PrimitiveMode mode, 907 GLsizei count, 908 gl::DrawElementsType type, 909 const void *indices, 910 GLsizei instanceCount, 911 GLint baseVertex) 912{ 913 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 914 // Instanced draw calls with zero instances are skipped in the frontend. 915 // The drawElementsImpl function would treat them as non-instanced. 916 ASSERT(instanceCount > 0); 917 return drawElementsImpl(context, mode, count, type, indices, instanceCount, baseVertex, 0); 918} 919 920angle::Result ContextMtl::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context, 921 gl::PrimitiveMode mode, 922 GLsizei count, 923 gl::DrawElementsType type, 924 const void *indices, 925 GLsizei instances, 926 GLint baseVertex, 927 GLuint baseInstance) 928{ 929 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 930 // Instanced draw calls with zero instances are skipped in the frontend. 931 // The drawElementsImpl function would treat them as non-instanced. 932 ASSERT(instances > 0); 933 return drawElementsImpl(context, mode, count, type, indices, instances, baseVertex, 934 baseInstance); 935} 936 937angle::Result ContextMtl::drawRangeElements(const gl::Context *context, 938 gl::PrimitiveMode mode, 939 GLuint start, 940 GLuint end, 941 GLsizei count, 942 gl::DrawElementsType type, 943 const void *indices) 944{ 945 ANGLE_TRY(resyncDrawFramebufferIfNeeded(context)); 946 return drawElementsImpl(context, mode, count, type, indices, 0, 0, 0); 947} 948 949angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context, 950 gl::PrimitiveMode mode, 951 GLuint start, 952 GLuint end, 953 GLsizei count, 954 gl::DrawElementsType type, 955 const void *indices, 956 GLint baseVertex) 957{ 958 // NOTE(hqle): ES 3.2 959 UNIMPLEMENTED(); 960 return angle::Result::Stop; 961} 962 963angle::Result ContextMtl::drawArraysIndirect(const gl::Context *context, 964 gl::PrimitiveMode mode, 965 const void *indirect) 966{ 967 // NOTE(hqle): ES 3.0 968 UNIMPLEMENTED(); 969 return angle::Result::Stop; 970} 971angle::Result ContextMtl::drawElementsIndirect(const gl::Context *context, 972 gl::PrimitiveMode mode, 973 gl::DrawElementsType type, 974 const void *indirect) 975{ 976 // NOTE(hqle): ES 3.0 977 UNIMPLEMENTED(); 978 return angle::Result::Stop; 979} 980 981angle::Result ContextMtl::multiDrawArrays(const gl::Context *context, 982 gl::PrimitiveMode mode, 983 const GLint *firsts, 984 const GLsizei *counts, 985 GLsizei drawcount) 986{ 987 return rx::MultiDrawArraysGeneral(this, context, mode, firsts, counts, drawcount); 988} 989 990angle::Result ContextMtl::multiDrawArraysInstanced(const gl::Context *context, 991 gl::PrimitiveMode mode, 992 const GLint *firsts, 993 const GLsizei *counts, 994 const GLsizei *instanceCounts, 995 GLsizei drawcount) 996{ 997 return rx::MultiDrawArraysInstancedGeneral(this, context, mode, firsts, counts, instanceCounts, 998 drawcount); 999} 1000 1001angle::Result ContextMtl::multiDrawArraysIndirect(const gl::Context *context, 1002 gl::PrimitiveMode mode, 1003 const void *indirect, 1004 GLsizei drawcount, 1005 GLsizei stride) 1006{ 1007 return rx::MultiDrawArraysIndirectGeneral(this, context, mode, indirect, drawcount, stride); 1008} 1009 1010angle::Result ContextMtl::multiDrawElements(const gl::Context *context, 1011 gl::PrimitiveMode mode, 1012 const GLsizei *counts, 1013 gl::DrawElementsType type, 1014 const GLvoid *const *indices, 1015 GLsizei drawcount) 1016{ 1017 return rx::MultiDrawElementsGeneral(this, context, mode, counts, type, indices, drawcount); 1018} 1019 1020angle::Result ContextMtl::multiDrawElementsInstanced(const gl::Context *context, 1021 gl::PrimitiveMode mode, 1022 const GLsizei *counts, 1023 gl::DrawElementsType type, 1024 const GLvoid *const *indices, 1025 const GLsizei *instanceCounts, 1026 GLsizei drawcount) 1027{ 1028 return rx::MultiDrawElementsInstancedGeneral(this, context, mode, counts, type, indices, 1029 instanceCounts, drawcount); 1030} 1031 1032angle::Result ContextMtl::multiDrawElementsIndirect(const gl::Context *context, 1033 gl::PrimitiveMode mode, 1034 gl::DrawElementsType type, 1035 const void *indirect, 1036 GLsizei drawcount, 1037 GLsizei stride) 1038{ 1039 return rx::MultiDrawElementsIndirectGeneral(this, context, mode, type, indirect, drawcount, 1040 stride); 1041} 1042 1043angle::Result ContextMtl::multiDrawArraysInstancedBaseInstance(const gl::Context *context, 1044 gl::PrimitiveMode mode, 1045 const GLint *firsts, 1046 const GLsizei *counts, 1047 const GLsizei *instanceCounts, 1048 const GLuint *baseInstances, 1049 GLsizei drawcount) 1050{ 1051 return rx::MultiDrawArraysInstancedBaseInstanceGeneral( 1052 this, context, mode, firsts, counts, instanceCounts, baseInstances, drawcount); 1053} 1054 1055angle::Result ContextMtl::multiDrawElementsInstancedBaseVertexBaseInstance( 1056 const gl::Context *context, 1057 gl::PrimitiveMode mode, 1058 const GLsizei *counts, 1059 gl::DrawElementsType type, 1060 const GLvoid *const *indices, 1061 const GLsizei *instanceCounts, 1062 const GLint *baseVertices, 1063 const GLuint *baseInstances, 1064 GLsizei drawcount) 1065{ 1066 return rx::MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral( 1067 this, context, mode, counts, type, indices, instanceCounts, baseVertices, baseInstances, 1068 drawcount); 1069} 1070 1071// Device loss 1072gl::GraphicsResetStatus ContextMtl::getResetStatus() 1073{ 1074 return gl::GraphicsResetStatus::NoError; 1075} 1076 1077// EXT_debug_marker 1078angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker) 1079{ 1080 return checkCommandBufferError(); 1081} 1082 1083angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker) 1084{ 1085 mCmdBuffer.pushDebugGroup(ConvertMarkerToString(length, marker)); 1086 return checkCommandBufferError(); 1087} 1088 1089angle::Result ContextMtl::popGroupMarker() 1090{ 1091 mCmdBuffer.popDebugGroup(); 1092 return checkCommandBufferError(); 1093} 1094 1095// KHR_debug 1096angle::Result ContextMtl::pushDebugGroup(const gl::Context *context, 1097 GLenum source, 1098 GLuint id, 1099 const std::string &message) 1100{ 1101 return checkCommandBufferError(); 1102} 1103 1104angle::Result ContextMtl::popDebugGroup(const gl::Context *context) 1105{ 1106 return checkCommandBufferError(); 1107} 1108 1109void ContextMtl::updateIncompatibleAttachments(const gl::State &glState) 1110{ 1111 const gl::ProgramExecutable *programExecutable = glState.getProgramExecutable(); 1112 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer(); 1113 if (programExecutable == nullptr || drawFramebuffer == nullptr) 1114 { 1115 mIncompatibleAttachments.reset(); 1116 return; 1117 } 1118 1119 // Cache a mask of incompatible attachments ignoring unused outputs and disabled draw buffers. 1120 mIncompatibleAttachments = 1121 gl::GetComponentTypeMaskDiff(drawFramebuffer->getDrawBufferTypeMask(), 1122 programExecutable->getFragmentOutputsTypeMask()) & 1123 drawFramebuffer->getDrawBufferMask() & programExecutable->getActiveOutputVariablesMask(); 1124} 1125 1126// State sync with dirty bits. 1127angle::Result ContextMtl::syncState(const gl::Context *context, 1128 const gl::state::DirtyBits dirtyBits, 1129 const gl::state::DirtyBits bitMask, 1130 const gl::state::ExtendedDirtyBits extendedDirtyBits, 1131 const gl::state::ExtendedDirtyBits extendedBitMask, 1132 gl::Command command) 1133{ 1134 const gl::State &glState = context->getState(); 1135 1136 // Metal's blend state is set at once, while ANGLE tracks separate dirty 1137 // bits: ENABLED, FUNCS, and EQUATIONS. Merge all three of them to the first one. 1138 // PS: these can not be statically initialized on some architectures as there is 1139 // no constuctor for DirtyBits that takes an int (which becomes BitSetArray<64>). 1140 gl::state::DirtyBits checkBlendBitsMask; 1141 checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_ENABLED); 1142 checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_FUNCS); 1143 checkBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_EQUATIONS); 1144 gl::state::DirtyBits resetBlendBitsMask; 1145 resetBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_FUNCS); 1146 resetBlendBitsMask.set(gl::state::DIRTY_BIT_BLEND_EQUATIONS); 1147 1148 gl::state::DirtyBits mergedDirtyBits = gl::state::DirtyBits(dirtyBits) & ~resetBlendBitsMask; 1149 mergedDirtyBits.set(gl::state::DIRTY_BIT_BLEND_ENABLED, (dirtyBits & checkBlendBitsMask).any()); 1150 1151 for (auto iter = mergedDirtyBits.begin(), endIter = mergedDirtyBits.end(); iter != endIter; 1152 ++iter) 1153 { 1154 size_t dirtyBit = *iter; 1155 switch (dirtyBit) 1156 { 1157 case gl::state::DIRTY_BIT_SCISSOR_TEST_ENABLED: 1158 case gl::state::DIRTY_BIT_SCISSOR: 1159 updateScissor(glState); 1160 break; 1161 case gl::state::DIRTY_BIT_VIEWPORT: 1162 { 1163 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 1164 updateViewport(framebufferMtl, glState.getViewport(), glState.getNearPlane(), 1165 glState.getFarPlane()); 1166 // Update the scissor, which will be constrained to the viewport 1167 updateScissor(glState); 1168 break; 1169 } 1170 case gl::state::DIRTY_BIT_DEPTH_RANGE: 1171 updateDepthRange(glState.getNearPlane(), glState.getFarPlane()); 1172 break; 1173 case gl::state::DIRTY_BIT_BLEND_COLOR: 1174 mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); 1175 break; 1176 case gl::state::DIRTY_BIT_BLEND_ENABLED: 1177 updateBlendDescArray(glState.getBlendStateExt()); 1178 break; 1179 case gl::state::DIRTY_BIT_COLOR_MASK: 1180 { 1181 const gl::BlendStateExt &blendStateExt = glState.getBlendStateExt(); 1182 size_t i = 0; 1183 for (; i < blendStateExt.getDrawBufferCount(); i++) 1184 { 1185 mBlendDescArray[i].updateWriteMask(blendStateExt.getColorMaskIndexed(i)); 1186 mWriteMaskArray[i] = mBlendDescArray[i].writeMask; 1187 } 1188 for (; i < mBlendDescArray.size(); i++) 1189 { 1190 mBlendDescArray[i].updateWriteMask(0); 1191 mWriteMaskArray[i] = mBlendDescArray[i].writeMask; 1192 } 1193 invalidateRenderPipeline(); 1194 break; 1195 } 1196 case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: 1197 if (getDisplay()->getFeatures().emulateAlphaToCoverage.enabled) 1198 { 1199 invalidateDriverUniforms(); 1200 } 1201 else 1202 { 1203 invalidateRenderPipeline(); 1204 } 1205 break; 1206 case gl::state::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED: 1207 case gl::state::DIRTY_BIT_SAMPLE_COVERAGE: 1208 case gl::state::DIRTY_BIT_SAMPLE_MASK_ENABLED: 1209 case gl::state::DIRTY_BIT_SAMPLE_MASK: 1210 invalidateDriverUniforms(); 1211 break; 1212 case gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED: 1213 mDepthStencilDesc.updateDepthTestEnabled(glState.getDepthStencilState()); 1214 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1215 break; 1216 case gl::state::DIRTY_BIT_DEPTH_FUNC: 1217 mDepthStencilDesc.updateDepthCompareFunc(glState.getDepthStencilState()); 1218 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1219 break; 1220 case gl::state::DIRTY_BIT_DEPTH_MASK: 1221 mDepthStencilDesc.updateDepthWriteEnabled(glState.getDepthStencilState()); 1222 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1223 break; 1224 case gl::state::DIRTY_BIT_STENCIL_TEST_ENABLED: 1225 mDepthStencilDesc.updateStencilTestEnabled(glState.getDepthStencilState()); 1226 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1227 break; 1228 case gl::state::DIRTY_BIT_STENCIL_FUNCS_FRONT: 1229 mDepthStencilDesc.updateStencilFrontFuncs(glState.getDepthStencilState()); 1230 mStencilRefFront = glState.getStencilRef(); // clamped on the frontend 1231 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1232 mDirtyBits.set(DIRTY_BIT_STENCIL_REF); 1233 break; 1234 case gl::state::DIRTY_BIT_STENCIL_FUNCS_BACK: 1235 mDepthStencilDesc.updateStencilBackFuncs(glState.getDepthStencilState()); 1236 mStencilRefBack = glState.getStencilBackRef(); // clamped on the frontend 1237 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1238 mDirtyBits.set(DIRTY_BIT_STENCIL_REF); 1239 break; 1240 case gl::state::DIRTY_BIT_STENCIL_OPS_FRONT: 1241 mDepthStencilDesc.updateStencilFrontOps(glState.getDepthStencilState()); 1242 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1243 break; 1244 case gl::state::DIRTY_BIT_STENCIL_OPS_BACK: 1245 mDepthStencilDesc.updateStencilBackOps(glState.getDepthStencilState()); 1246 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1247 break; 1248 case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_FRONT: 1249 mDepthStencilDesc.updateStencilFrontWriteMask(glState.getDepthStencilState()); 1250 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1251 break; 1252 case gl::state::DIRTY_BIT_STENCIL_WRITEMASK_BACK: 1253 mDepthStencilDesc.updateStencilBackWriteMask(glState.getDepthStencilState()); 1254 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 1255 break; 1256 case gl::state::DIRTY_BIT_CULL_FACE_ENABLED: 1257 case gl::state::DIRTY_BIT_CULL_FACE: 1258 updateCullMode(glState); 1259 break; 1260 case gl::state::DIRTY_BIT_FRONT_FACE: 1261 updateFrontFace(glState); 1262 break; 1263 case gl::state::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: 1264 case gl::state::DIRTY_BIT_POLYGON_OFFSET: 1265 mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); 1266 break; 1267 case gl::state::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED: 1268 mDirtyBits.set(DIRTY_BIT_RASTERIZER_DISCARD); 1269 break; 1270 case gl::state::DIRTY_BIT_LINE_WIDTH: 1271 // Do nothing 1272 break; 1273 case gl::state::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED: 1274 // NOTE(hqle): ES 3.0 feature. 1275 break; 1276 case gl::state::DIRTY_BIT_CLEAR_COLOR: 1277 mClearColor = mtl::ClearColorValue( 1278 glState.getColorClearValue().red, glState.getColorClearValue().green, 1279 glState.getColorClearValue().blue, glState.getColorClearValue().alpha); 1280 break; 1281 case gl::state::DIRTY_BIT_CLEAR_DEPTH: 1282 break; 1283 case gl::state::DIRTY_BIT_CLEAR_STENCIL: 1284 mClearStencil = glState.getStencilClearValue() & mtl::kStencilMaskAll; 1285 break; 1286 case gl::state::DIRTY_BIT_UNPACK_STATE: 1287 // This is a no-op, its only important to use the right unpack state when we do 1288 // setImage or setSubImage in TextureMtl, which is plumbed through the frontend call 1289 break; 1290 case gl::state::DIRTY_BIT_UNPACK_BUFFER_BINDING: 1291 break; 1292 case gl::state::DIRTY_BIT_PACK_STATE: 1293 // This is a no-op, its only important to use the right pack state when we do 1294 // call readPixels later on. 1295 break; 1296 case gl::state::DIRTY_BIT_PACK_BUFFER_BINDING: 1297 break; 1298 case gl::state::DIRTY_BIT_DITHER_ENABLED: 1299 break; 1300 case gl::state::DIRTY_BIT_READ_FRAMEBUFFER_BINDING: 1301 break; 1302 case gl::state::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: 1303 updateIncompatibleAttachments(glState); 1304 updateDrawFrameBufferBinding(context); 1305 break; 1306 case gl::state::DIRTY_BIT_RENDERBUFFER_BINDING: 1307 break; 1308 case gl::state::DIRTY_BIT_VERTEX_ARRAY_BINDING: 1309 updateVertexArray(context); 1310 break; 1311 case gl::state::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING: 1312 break; 1313 case gl::state::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING: 1314 break; 1315 case gl::state::DIRTY_BIT_PROGRAM_BINDING: 1316 static_assert( 1317 gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE > gl::state::DIRTY_BIT_PROGRAM_BINDING, 1318 "Dirty bit order"); 1319 iter.setLaterBit(gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE); 1320 break; 1321 case gl::state::DIRTY_BIT_PROGRAM_EXECUTABLE: 1322 { 1323 updateIncompatibleAttachments(glState); 1324 const gl::ProgramExecutable *executable = mState.getProgramExecutable(); 1325 ASSERT(executable); 1326 mExecutable = mtl::GetImpl(executable); 1327 updateProgramExecutable(context); 1328 break; 1329 } 1330 case gl::state::DIRTY_BIT_TEXTURE_BINDINGS: 1331 invalidateCurrentTextures(); 1332 break; 1333 case gl::state::DIRTY_BIT_SAMPLER_BINDINGS: 1334 invalidateCurrentTextures(); 1335 break; 1336 case gl::state::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING: 1337 // Nothing to do. 1338 break; 1339 case gl::state::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING: 1340 // NOTE(hqle): ES 3.0 feature. 1341 break; 1342 case gl::state::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS: 1343 mDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS_BINDING); 1344 break; 1345 case gl::state::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING: 1346 break; 1347 case gl::state::DIRTY_BIT_IMAGE_BINDINGS: 1348 // NOTE(hqle): properly handle GLSL images. 1349 invalidateCurrentTextures(); 1350 break; 1351 case gl::state::DIRTY_BIT_MULTISAMPLING: 1352 // NOTE(hqle): MSAA on/off. 1353 break; 1354 case gl::state::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE: 1355 // NOTE(hqle): this is part of EXT_multisample_compatibility. 1356 // NOTE(hqle): MSAA feature. 1357 break; 1358 case gl::state::DIRTY_BIT_COVERAGE_MODULATION: 1359 break; 1360 case gl::state::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE: 1361 break; 1362 case gl::state::DIRTY_BIT_CURRENT_VALUES: 1363 { 1364 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues()); 1365 break; 1366 } 1367 case gl::state::DIRTY_BIT_PROVOKING_VERTEX: 1368 break; 1369 case gl::state::DIRTY_BIT_EXTENDED: 1370 updateExtendedState(glState, extendedDirtyBits); 1371 break; 1372 case gl::state::DIRTY_BIT_SAMPLE_SHADING: 1373 // Nothing to do until OES_sample_shading is implemented. 1374 break; 1375 case gl::state::DIRTY_BIT_PATCH_VERTICES: 1376 // Nothing to do until EXT_tessellation_shader is implemented. 1377 break; 1378 default: 1379 UNREACHABLE(); 1380 break; 1381 } 1382 } 1383 1384 return angle::Result::Continue; 1385} 1386 1387void ContextMtl::updateExtendedState(const gl::State &glState, 1388 const gl::state::ExtendedDirtyBits extendedDirtyBits) 1389{ 1390 for (size_t extendedDirtyBit : extendedDirtyBits) 1391 { 1392 switch (extendedDirtyBit) 1393 { 1394 case gl::state::EXTENDED_DIRTY_BIT_CLIP_CONTROL: 1395 updateFrontFace(glState); 1396 invalidateDriverUniforms(); 1397 break; 1398 case gl::state::EXTENDED_DIRTY_BIT_CLIP_DISTANCES: 1399 invalidateDriverUniforms(); 1400 break; 1401 case gl::state::EXTENDED_DIRTY_BIT_DEPTH_CLAMP_ENABLED: 1402 mDirtyBits.set(DIRTY_BIT_DEPTH_CLIP_MODE); 1403 break; 1404 case gl::state::EXTENDED_DIRTY_BIT_POLYGON_MODE: 1405 mDirtyBits.set(DIRTY_BIT_FILL_MODE); 1406 mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); 1407 break; 1408 case gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED: 1409 mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); 1410 break; 1411 default: 1412 break; 1413 } 1414 } 1415} 1416 1417// Disjoint timer queries 1418GLint ContextMtl::getGPUDisjoint() 1419{ 1420 // Implementation currently is not affected by this. 1421 return 0; 1422} 1423 1424GLint64 ContextMtl::getTimestamp() 1425{ 1426 // Timestamps are currently unsupported. An implementation 1427 // strategy is written up in anglebug.com/42266300 if they're needed 1428 // in the future. 1429 return 0; 1430} 1431 1432// Context switching 1433angle::Result ContextMtl::onMakeCurrent(const gl::Context *context) 1434{ 1435 invalidateState(context); 1436 gl::Query *query = mState.getActiveQuery(gl::QueryType::TimeElapsed); 1437 if (query) 1438 { 1439 GetImplAs<QueryMtl>(query)->onContextMakeCurrent(context); 1440 } 1441 mBufferManager.incrementNumContextSwitches(); 1442 return checkCommandBufferError(); 1443} 1444angle::Result ContextMtl::onUnMakeCurrent(const gl::Context *context) 1445{ 1446 flushCommandBuffer(mtl::WaitUntilScheduled); 1447 // Note: this 2nd flush is needed because if there is a query in progress 1448 // then during flush, new command buffers are allocated that also need 1449 // to be flushed. This is a temporary fix and we should probably refactor 1450 // this later. See TODO(anglebug.com/42265611) 1451 flushCommandBuffer(mtl::WaitUntilScheduled); 1452 gl::Query *query = mState.getActiveQuery(gl::QueryType::TimeElapsed); 1453 if (query) 1454 { 1455 GetImplAs<QueryMtl>(query)->onContextUnMakeCurrent(context); 1456 } 1457 return checkCommandBufferError(); 1458} 1459 1460// Native capabilities, unmodified by gl::Context. 1461gl::Caps ContextMtl::getNativeCaps() const 1462{ 1463 return getDisplay()->getNativeCaps(); 1464} 1465const gl::TextureCapsMap &ContextMtl::getNativeTextureCaps() const 1466{ 1467 return getDisplay()->getNativeTextureCaps(); 1468} 1469const gl::Extensions &ContextMtl::getNativeExtensions() const 1470{ 1471 return getDisplay()->getNativeExtensions(); 1472} 1473const gl::Limitations &ContextMtl::getNativeLimitations() const 1474{ 1475 return getDisplay()->getNativeLimitations(); 1476} 1477const ShPixelLocalStorageOptions &ContextMtl::getNativePixelLocalStorageOptions() const 1478{ 1479 return getDisplay()->getNativePixelLocalStorageOptions(); 1480} 1481 1482// Shader creation 1483CompilerImpl *ContextMtl::createCompiler() 1484{ 1485 return new CompilerMtl(); 1486} 1487ShaderImpl *ContextMtl::createShader(const gl::ShaderState &state) 1488{ 1489 return new ShaderMtl(state); 1490} 1491ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state) 1492{ 1493 return new ProgramMtl(state); 1494} 1495 1496ProgramExecutableImpl *ContextMtl::createProgramExecutable(const gl::ProgramExecutable *executable) 1497{ 1498 return new ProgramExecutableMtl(executable); 1499} 1500 1501// Framebuffer creation 1502FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state) 1503{ 1504 return new FramebufferMtl(state, this, /* flipY */ false); 1505} 1506 1507// Texture creation 1508TextureImpl *ContextMtl::createTexture(const gl::TextureState &state) 1509{ 1510 return new TextureMtl(state); 1511} 1512 1513// Renderbuffer creation 1514RenderbufferImpl *ContextMtl::createRenderbuffer(const gl::RenderbufferState &state) 1515{ 1516 return new RenderbufferMtl(state); 1517} 1518 1519// Buffer creation 1520BufferImpl *ContextMtl::createBuffer(const gl::BufferState &state) 1521{ 1522 return new BufferMtl(state); 1523} 1524 1525// Vertex Array creation 1526VertexArrayImpl *ContextMtl::createVertexArray(const gl::VertexArrayState &state) 1527{ 1528 return new VertexArrayMtl(state, this); 1529} 1530 1531// Query and Fence creation 1532QueryImpl *ContextMtl::createQuery(gl::QueryType type) 1533{ 1534 return new QueryMtl(type); 1535} 1536FenceNVImpl *ContextMtl::createFenceNV() 1537{ 1538 return new FenceNVMtl(); 1539} 1540SyncImpl *ContextMtl::createSync() 1541{ 1542 return new SyncMtl(); 1543} 1544 1545// Transform Feedback creation 1546TransformFeedbackImpl *ContextMtl::createTransformFeedback(const gl::TransformFeedbackState &state) 1547{ 1548 // NOTE(hqle): ES 3.0 1549 return new TransformFeedbackMtl(state); 1550} 1551 1552// Sampler object creation 1553SamplerImpl *ContextMtl::createSampler(const gl::SamplerState &state) 1554{ 1555 return new SamplerMtl(state); 1556} 1557 1558// Program Pipeline object creation 1559ProgramPipelineImpl *ContextMtl::createProgramPipeline(const gl::ProgramPipelineState &data) 1560{ 1561 // NOTE(hqle): ES 3.0 1562 UNIMPLEMENTED(); 1563 return nullptr; 1564} 1565 1566// Memory object creation. 1567MemoryObjectImpl *ContextMtl::createMemoryObject() 1568{ 1569 UNIMPLEMENTED(); 1570 return nullptr; 1571} 1572 1573// Semaphore creation. 1574SemaphoreImpl *ContextMtl::createSemaphore() 1575{ 1576 UNIMPLEMENTED(); 1577 return nullptr; 1578} 1579 1580OverlayImpl *ContextMtl::createOverlay(const gl::OverlayState &state) 1581{ 1582 // Not implemented. 1583 return new OverlayImpl(state); 1584} 1585 1586angle::Result ContextMtl::dispatchCompute(const gl::Context *context, 1587 GLuint numGroupsX, 1588 GLuint numGroupsY, 1589 GLuint numGroupsZ) 1590{ 1591 // NOTE(hqle): ES 3.0 1592 UNIMPLEMENTED(); 1593 return angle::Result::Stop; 1594} 1595angle::Result ContextMtl::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect) 1596{ 1597 // NOTE(hqle): ES 3.0 1598 UNIMPLEMENTED(); 1599 return angle::Result::Stop; 1600} 1601 1602angle::Result ContextMtl::memoryBarrier(const gl::Context *context, GLbitfield barriers) 1603{ 1604 if (barriers == 0) 1605 { 1606 return checkCommandBufferError(); 1607 } 1608 if (context->getClientVersion() >= gl::Version{3, 1}) 1609 { 1610 // We expect ES 3.0, and as such we don't consider ES 3.1+ objects in this function yet. 1611 UNIMPLEMENTED(); 1612 return angle::Result::Stop; 1613 } 1614 MTLBarrierScope scope; 1615 switch (barriers) 1616 { 1617 case GL_ALL_BARRIER_BITS: 1618 scope = MTLBarrierScopeTextures | MTLBarrierScopeBuffers; 1619#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 1620 if (getDisplay()->hasFragmentMemoryBarriers()) 1621 { 1622 scope |= MTLBarrierScopeRenderTargets; 1623 } 1624#endif 1625 break; 1626 case GL_SHADER_IMAGE_ACCESS_BARRIER_BIT: 1627 scope = MTLBarrierScopeTextures; 1628#if TARGET_OS_OSX || TARGET_OS_MACCATALYST 1629 if (getDisplay()->hasFragmentMemoryBarriers()) 1630 { 1631 // SHADER_IMAGE_ACCESS_BARRIER_BIT (and SHADER_STORAGE_BARRIER_BIT) require that all 1632 // prior types of accesses are finished before writes to the resource. Since this is 1633 // the case, we also have to include render targets in our barrier to ensure any 1634 // rendering completes before an imageLoad(). 1635 // 1636 // NOTE: Apple Silicon doesn't support MTLBarrierScopeRenderTargets. This seems to 1637 // work anyway though, and on that hardware we use programmable blending for pixel 1638 // local storage instead of read_write textures anyway. 1639 scope |= MTLBarrierScopeRenderTargets; 1640 } 1641#endif 1642 break; 1643 default: 1644 UNIMPLEMENTED(); 1645 return angle::Result::Stop; 1646 } 1647 // The GL API doesn't provide a distinction between different shader stages. 1648 // ES 3.0 doesn't have compute. 1649 MTLRenderStages stages = MTLRenderStageVertex; 1650 if (getDisplay()->hasFragmentMemoryBarriers()) 1651 { 1652 stages |= MTLRenderStageFragment; 1653 } 1654 mRenderEncoder.memoryBarrier(scope, stages, stages); 1655 return checkCommandBufferError(); 1656} 1657 1658angle::Result ContextMtl::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) 1659{ 1660 // NOTE(hqle): ES 3.0 1661 UNIMPLEMENTED(); 1662 return angle::Result::Stop; 1663} 1664 1665// override mtl::ErrorHandler 1666void ContextMtl::handleError(GLenum glErrorCode, 1667 const char *message, 1668 const char *file, 1669 const char *function, 1670 unsigned int line) 1671{ 1672 mErrors->handleError(glErrorCode, message, file, function, line); 1673} 1674 1675void ContextMtl::invalidateState(const gl::Context *context) 1676{ 1677 mDirtyBits.set(); 1678 1679 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 1680} 1681 1682void ContextMtl::invalidateDefaultAttribute(size_t attribIndex) 1683{ 1684 mDirtyDefaultAttribsMask.set(attribIndex); 1685 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 1686} 1687 1688void ContextMtl::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask) 1689{ 1690 if (dirtyMask.any()) 1691 { 1692 mDirtyDefaultAttribsMask |= dirtyMask; 1693 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 1694 } 1695 1696 // TODO(anglebug.com/40096755): determine how to merge this. 1697#if 0 1698 if (getDisplay()->getFeatures().hasExplicitMemBarrier.enabled) 1699 { 1700 const gl::ProgramExecutable *executable = mState.getProgramExecutable(); 1701 ASSERT(executable); 1702 ASSERT(executable->hasTransformFeedbackOutput() || mState.isTransformFeedbackActive()); 1703 TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(mState.getCurrentTransformFeedback()); 1704 size_t bufferCount = executable->getTransformFeedbackBufferCount(); 1705 const gl::TransformFeedbackBuffersArray<BufferMtl *> &bufferHandles = 1706 transformFeedbackMtl->getBufferHandles(); 1707 for (size_t i = 0; i < bufferCount; i++) 1708 { 1709 const mtl::BufferRef & constBufferRef = bufferHandles[i]->getCurrentBuffer(); 1710 mRenderEncoder.memoryBarrierWithResource(constBufferRef, mtl::kRenderStageVertex, mtl::kRenderStageVertex); 1711 } 1712 } 1713 else 1714 { 1715 //End the command encoder, so any Transform Feedback changes are available to subsequent draw calls. 1716 endEncoding(false); 1717 } 1718#endif 1719} 1720 1721void ContextMtl::invalidateCurrentTextures() 1722{ 1723 mDirtyBits.set(DIRTY_BIT_TEXTURES); 1724} 1725 1726void ContextMtl::invalidateDriverUniforms() 1727{ 1728 mDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS); 1729} 1730 1731void ContextMtl::invalidateRenderPipeline() 1732{ 1733 mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE); 1734} 1735 1736const mtl::ClearColorValue &ContextMtl::getClearColorValue() const 1737{ 1738 return mClearColor; 1739} 1740const mtl::WriteMaskArray &ContextMtl::getWriteMaskArray() const 1741{ 1742 return mWriteMaskArray; 1743} 1744float ContextMtl::getClearDepthValue() const 1745{ 1746 return getState().getDepthClearValue(); 1747} 1748uint32_t ContextMtl::getClearStencilValue() const 1749{ 1750 return mClearStencil; 1751} 1752uint32_t ContextMtl::getStencilMask() const 1753{ 1754 return getState().getDepthStencilState().stencilWritemask & mtl::kStencilMaskAll; 1755} 1756 1757bool ContextMtl::getDepthMask() const 1758{ 1759 return getState().getDepthStencilState().depthMask; 1760} 1761 1762const mtl::Format &ContextMtl::getPixelFormat(angle::FormatID angleFormatId) const 1763{ 1764 return getDisplay()->getPixelFormat(angleFormatId); 1765} 1766 1767// See mtl::FormatTable::getVertexFormat() 1768const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId, 1769 bool tightlyPacked) const 1770{ 1771 return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked); 1772} 1773 1774const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const 1775{ 1776 return getDisplay()->getNativeFormatCaps(mtlFormat); 1777} 1778 1779angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context, 1780 gl::TextureType type, 1781 gl::SamplerFormat format, 1782 gl::Texture **textureOut) 1783{ 1784 return mIncompleteTextures.getIncompleteTexture(context, type, format, nullptr, textureOut); 1785} 1786 1787void ContextMtl::endRenderEncoding(mtl::RenderCommandEncoder *encoder) 1788{ 1789 // End any pending visibility query in the render pass 1790 if (mOcclusionQuery) 1791 { 1792 disableActiveOcclusionQueryInRenderPass(); 1793 } 1794 1795 if (mBlitEncoder.valid()) 1796 { 1797 mBlitEncoder.endEncoding(); 1798 } 1799 1800 mOcclusionQueryPool.prepareRenderPassVisibilityPoolBuffer(this); 1801 1802 encoder->endEncoding(); 1803 1804 // Resolve visibility results 1805 mOcclusionQueryPool.resolveVisibilityResults(this); 1806} 1807 1808void ContextMtl::endBlitAndComputeEncoding() 1809{ 1810 if (mBlitEncoder.valid()) 1811 { 1812 mBlitEncoder.endEncoding(); 1813 } 1814 1815 if (mComputeEncoder.valid()) 1816 { 1817 mComputeEncoder.endEncoding(); 1818 mProvokingVertexHelper.releaseInFlightBuffers(this); 1819 } 1820} 1821 1822void ContextMtl::endEncoding(bool forceSaveRenderPassContent) 1823{ 1824 endBlitAndComputeEncoding(); 1825 1826 if (mRenderEncoder.valid()) 1827 { 1828 if (forceSaveRenderPassContent) 1829 { 1830 // Save the work in progress. 1831 mRenderEncoder.setStoreAction(MTLStoreActionStore); 1832 } 1833 1834 endRenderEncoding(&mRenderEncoder); 1835 } 1836 // End blit encoder after render encoder, as endRenderEncoding() might create a 1837 // blit encoder to resolve the visibility results. 1838 if (mBlitEncoder.valid()) 1839 { 1840 mBlitEncoder.endEncoding(); 1841 } 1842} 1843 1844void ContextMtl::flushCommandBuffer(mtl::CommandBufferFinishOperation operation) 1845{ 1846 mRenderPassesSinceFlush = 0; 1847 if (mCmdBuffer.ready()) 1848 { 1849 endEncoding(true); 1850 mCmdBuffer.commit(operation); 1851 mBufferManager.incrementNumCommandBufferCommits(); 1852 } 1853 else 1854 { 1855 mCmdBuffer.wait(operation); 1856 } 1857} 1858 1859void ContextMtl::flushCommandBufferIfNeeded() 1860{ 1861 if (mRenderPassesSinceFlush >= mtl::kMaxRenderPassesPerCommandBuffer || 1862 mCmdBuffer.needsFlushForDrawCallLimits()) 1863 { 1864 // Ensure that we don't accumulate too many unflushed render passes. Don't wait until they 1865 // are submitted, other components handle backpressure so don't create uneccessary CPU/GPU 1866 // synchronization. 1867 flushCommandBuffer(mtl::NoWait); 1868 } 1869} 1870 1871void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable) 1872{ 1873 ensureCommandBufferReady(); 1874 1875 FramebufferMtl *currentframebuffer = mtl::GetImpl(getState().getDrawFramebuffer()); 1876 if (currentframebuffer) 1877 { 1878 currentframebuffer->onFrameEnd(context); 1879 } 1880 1881 endEncoding(false); 1882 mCmdBuffer.present(presentationDrawable); 1883 mCmdBuffer.commit(mtl::NoWait); 1884 mRenderPassesSinceFlush = 0; 1885} 1886 1887angle::Result ContextMtl::finishCommandBuffer() 1888{ 1889 flushCommandBuffer(mtl::WaitUntilFinished); 1890 return checkCommandBufferError(); 1891} 1892 1893bool ContextMtl::hasStartedRenderPass(const mtl::RenderPassDesc &desc) 1894{ 1895 return mRenderEncoder.valid() && 1896 mRenderEncoder.renderPassDesc().equalIgnoreLoadStoreOptions(desc); 1897} 1898 1899bool ContextMtl::isCurrentRenderEncoderSerial(uint64_t serial) 1900{ 1901 if (!mRenderEncoder.valid()) 1902 { 1903 return false; 1904 } 1905 1906 return serial == mRenderEncoder.getSerial(); 1907} 1908 1909// Get current render encoder 1910mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder() 1911{ 1912 if (!mRenderEncoder.valid()) 1913 { 1914 return nullptr; 1915 } 1916 1917 return &mRenderEncoder; 1918} 1919 1920mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc) 1921{ 1922 if (hasStartedRenderPass(desc)) 1923 { 1924 return &mRenderEncoder; 1925 } 1926 1927 endEncoding(false); 1928 1929 ensureCommandBufferReady(); 1930 ++mRenderPassesSinceFlush; 1931 1932 // Need to re-apply everything on next draw call. 1933 mDirtyBits.set(); 1934 1935 const mtl::ContextDevice &metalDevice = getMetalDevice(); 1936 if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice)) 1937 { 1938 NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice); 1939 NSUInteger renderTargetSize = 1940 ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, this, metalDevice); 1941 if (renderTargetSize > maxSize) 1942 { 1943 std::stringstream errorStream; 1944 errorStream << "This set of render targets requires " << renderTargetSize 1945 << " bytes of pixel storage. This device supports " << maxSize << " bytes."; 1946 handleError(GL_INVALID_OPERATION, errorStream.str().c_str(), __FILE__, ANGLE_FUNCTION, 1947 __LINE__); 1948 return nullptr; 1949 } 1950 } 1951 return &mRenderEncoder.restart(desc, getNativeCaps().maxColorAttachments); 1952} 1953 1954// Utilities to quickly create render command encoder to a specific texture: 1955// The previous content of texture will be loaded 1956mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder( 1957 const mtl::TextureRef &textureTarget, 1958 const mtl::ImageNativeIndex &index) 1959{ 1960 ASSERT(textureTarget && textureTarget->valid()); 1961 1962 mtl::RenderPassDesc rpDesc; 1963 1964 rpDesc.colorAttachments[0].texture = textureTarget; 1965 rpDesc.colorAttachments[0].level = index.getNativeLevel(); 1966 rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0; 1967 rpDesc.numColorAttachments = 1; 1968 rpDesc.rasterSampleCount = textureTarget->samples(); 1969 1970 return getRenderPassCommandEncoder(rpDesc); 1971} 1972 1973// The previous content of texture will be loaded if clearColor is not provided 1974mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoderWithClear( 1975 const RenderTargetMtl &renderTarget, 1976 const Optional<MTLClearColor> &clearColor) 1977{ 1978 ASSERT(renderTarget.getTexture()); 1979 1980 mtl::RenderPassDesc rpDesc; 1981 renderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]); 1982 rpDesc.numColorAttachments = 1; 1983 rpDesc.rasterSampleCount = renderTarget.getRenderSamples(); 1984 1985 if (clearColor.valid()) 1986 { 1987 rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear; 1988 rpDesc.colorAttachments[0].clearColor = mtl::EmulatedAlphaClearColor( 1989 clearColor.value(), renderTarget.getTexture()->getColorWritableMask()); 1990 1991 endEncoding(true); 1992 } 1993 1994 return getRenderPassCommandEncoder(rpDesc); 1995} 1996// The previous content of texture will be loaded 1997mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoder( 1998 const RenderTargetMtl &renderTarget) 1999{ 2000 return getRenderTargetCommandEncoderWithClear(renderTarget, Optional<MTLClearColor>()); 2001} 2002 2003mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder() 2004{ 2005 if (mRenderEncoder.valid() || mComputeEncoder.valid()) 2006 { 2007 endEncoding(true); 2008 } 2009 2010 if (mBlitEncoder.valid()) 2011 { 2012 return &mBlitEncoder; 2013 } 2014 2015 endEncoding(true); 2016 ensureCommandBufferReady(); 2017 2018 return &mBlitEncoder.restart(); 2019} 2020 2021mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoderWithoutEndingRenderEncoder() 2022{ 2023 if (mBlitEncoder.valid()) 2024 { 2025 return &mBlitEncoder; 2026 } 2027 2028 endBlitAndComputeEncoding(); 2029 ensureCommandBufferReady(); 2030 2031 return &mBlitEncoder.restart(); 2032} 2033 2034mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoder() 2035{ 2036 if (mRenderEncoder.valid() || mBlitEncoder.valid()) 2037 { 2038 endEncoding(true); 2039 } 2040 2041 if (mComputeEncoder.valid()) 2042 { 2043 return &mComputeEncoder; 2044 } 2045 2046 endEncoding(true); 2047 ensureCommandBufferReady(); 2048 2049 return &mComputeEncoder.restart(); 2050} 2051 2052mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoderWithoutEndingRenderEncoder() 2053{ 2054 if (mComputeEncoder.valid()) 2055 { 2056 return &mComputeEncoder; 2057 } 2058 2059 endBlitAndComputeEncoding(); 2060 ensureCommandBufferReady(); 2061 2062 return &mComputeEncoder.restart(); 2063} 2064 2065mtl::ComputeCommandEncoder *ContextMtl::getIndexPreprocessingCommandEncoder() 2066{ 2067 return getComputeCommandEncoder(); 2068} 2069 2070void ContextMtl::ensureCommandBufferReady() 2071{ 2072 flushCommandBufferIfNeeded(); 2073 2074 if (!mCmdBuffer.ready()) 2075 { 2076 mCmdBuffer.restart(); 2077 } 2078 2079 ASSERT(mCmdBuffer.ready()); 2080} 2081 2082void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl, 2083 const gl::Rectangle &viewport, 2084 float nearPlane, 2085 float farPlane) 2086{ 2087 mViewport = mtl::GetViewport(viewport, framebufferMtl->getState().getDimensions().height, 2088 framebufferMtl->flipY(), nearPlane, farPlane); 2089 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 2090 2091 invalidateDriverUniforms(); 2092} 2093 2094void ContextMtl::updateDepthRange(float nearPlane, float farPlane) 2095{ 2096 if (NeedToInvertDepthRange(nearPlane, farPlane)) 2097 { 2098 // We also need to invert the depth in shader later by using scale value stored in driver 2099 // uniform depthRange.reserved 2100 std::swap(nearPlane, farPlane); 2101 } 2102 mViewport.znear = nearPlane; 2103 mViewport.zfar = farPlane; 2104 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 2105 2106 invalidateDriverUniforms(); 2107} 2108 2109void ContextMtl::updateBlendDescArray(const gl::BlendStateExt &blendStateExt) 2110{ 2111 for (size_t i = 0; i < mBlendDescArray.size(); i++) 2112 { 2113 mtl::BlendDesc &blendDesc = mBlendDescArray[i]; 2114 if (blendStateExt.getEnabledMask().test(i)) 2115 { 2116 blendDesc.blendingEnabled = true; 2117 2118 blendDesc.sourceRGBBlendFactor = 2119 mtl::GetBlendFactor(blendStateExt.getSrcColorIndexed(i)); 2120 blendDesc.sourceAlphaBlendFactor = 2121 mtl::GetBlendFactor(blendStateExt.getSrcAlphaIndexed(i)); 2122 blendDesc.destinationRGBBlendFactor = 2123 mtl::GetBlendFactor(blendStateExt.getDstColorIndexed(i)); 2124 blendDesc.destinationAlphaBlendFactor = 2125 mtl::GetBlendFactor(blendStateExt.getDstAlphaIndexed(i)); 2126 2127 blendDesc.rgbBlendOperation = mtl::GetBlendOp(blendStateExt.getEquationColorIndexed(i)); 2128 blendDesc.alphaBlendOperation = 2129 mtl::GetBlendOp(blendStateExt.getEquationAlphaIndexed(i)); 2130 } 2131 else 2132 { 2133 // Enforce default state when blending is disabled, 2134 blendDesc.reset(blendDesc.writeMask); 2135 } 2136 } 2137 invalidateRenderPipeline(); 2138} 2139 2140void ContextMtl::updateScissor(const gl::State &glState) 2141{ 2142 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 2143 gl::Rectangle renderArea = framebufferMtl->getCompleteRenderArea(); 2144 2145 ANGLE_MTL_LOG("renderArea = %d,%d,%d,%d", renderArea.x, renderArea.y, renderArea.width, 2146 renderArea.height); 2147 2148 // Clip the render area to the viewport. 2149 gl::Rectangle viewportClippedRenderArea; 2150 if (!gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea)) 2151 { 2152 viewportClippedRenderArea = gl::Rectangle(); 2153 } 2154 2155 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false); 2156 if (framebufferMtl->flipY()) 2157 { 2158 scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height; 2159 } 2160 2161 ANGLE_MTL_LOG("scissoredArea = %d,%d,%d,%d", scissoredArea.x, scissoredArea.y, 2162 scissoredArea.width, scissoredArea.height); 2163 2164 mScissorRect = mtl::GetScissorRect(scissoredArea); 2165 mDirtyBits.set(DIRTY_BIT_SCISSOR); 2166} 2167 2168void ContextMtl::updateCullMode(const gl::State &glState) 2169{ 2170 const gl::RasterizerState &rasterState = glState.getRasterizerState(); 2171 2172 mCullAllPolygons = false; 2173 if (!rasterState.cullFace) 2174 { 2175 mCullMode = MTLCullModeNone; 2176 } 2177 else 2178 { 2179 switch (rasterState.cullMode) 2180 { 2181 case gl::CullFaceMode::Back: 2182 mCullMode = MTLCullModeBack; 2183 break; 2184 case gl::CullFaceMode::Front: 2185 mCullMode = MTLCullModeFront; 2186 break; 2187 case gl::CullFaceMode::FrontAndBack: 2188 mCullAllPolygons = true; 2189 break; 2190 default: 2191 UNREACHABLE(); 2192 break; 2193 } 2194 } 2195 2196 mDirtyBits.set(DIRTY_BIT_CULL_MODE); 2197} 2198 2199void ContextMtl::updateFrontFace(const gl::State &glState) 2200{ 2201 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 2202 const bool upperLeftOrigin = mState.getClipOrigin() == gl::ClipOrigin::UpperLeft; 2203 mWinding = mtl::GetFrontfaceWinding(glState.getRasterizerState().frontFace, 2204 framebufferMtl->flipY() == upperLeftOrigin); 2205 mDirtyBits.set(DIRTY_BIT_WINDING); 2206} 2207 2208// Index rewrite is required if: 2209// Provkoing vertex mode is 'last' 2210// Program has at least one 'flat' attribute 2211// PrimitiveMode is not POINTS. 2212bool ContextMtl::requiresIndexRewrite(const gl::State &state, gl::PrimitiveMode mode) 2213{ 2214 return mode != gl::PrimitiveMode::Points && mExecutable->hasFlatAttribute() && 2215 (state.getProvokingVertex() == gl::ProvokingVertexConvention::LastVertexConvention); 2216} 2217 2218void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context) 2219{ 2220 const gl::State &glState = getState(); 2221 2222 FramebufferMtl *newDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer()); 2223 if (newDrawFramebuffer != mDrawFramebuffer) 2224 { 2225 // Reset this flag if the framebuffer has changed to not sync it twice 2226 mForceResyncDrawFramebuffer = false; 2227 } 2228 2229 mDrawFramebuffer = newDrawFramebuffer; 2230 2231 mDrawFramebuffer->onStartedDrawingToFrameBuffer(context); 2232 2233 onDrawFrameBufferChangedState(context, mDrawFramebuffer, true); 2234} 2235 2236void ContextMtl::onDrawFrameBufferChangedState(const gl::Context *context, 2237 FramebufferMtl *framebuffer, 2238 bool renderPassChanged) 2239{ 2240 const gl::State &glState = getState(); 2241 ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer())); 2242 2243 updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(), 2244 glState.getFarPlane()); 2245 updateFrontFace(glState); 2246 updateScissor(glState); 2247 2248 if (renderPassChanged) 2249 { 2250 // End any render encoding using the old render pass. 2251 endEncoding(false); 2252 // Need to re-apply state to RenderCommandEncoder 2253 invalidateState(context); 2254 } 2255 else 2256 { 2257 // Invalidate current pipeline only. 2258 invalidateRenderPipeline(); 2259 } 2260} 2261 2262void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer) 2263{ 2264 const gl::State &glState = getState(); 2265 FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer()); 2266 if (framebuffer->getAttachedBackbuffer() != backbuffer) 2267 { 2268 return; 2269 } 2270 2271 onDrawFrameBufferChangedState(context, framebuffer, true); 2272} 2273 2274angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query) 2275{ 2276 ASSERT(mOcclusionQuery == nullptr); 2277 mOcclusionQuery = query; 2278 2279 if (mRenderEncoder.valid()) 2280 { 2281 // if render pass has started, start the query in the encoder 2282 return startOcclusionQueryInRenderPass(query, true); 2283 } 2284 else 2285 { 2286 query->resetVisibilityResult(this); 2287 } 2288 2289 return angle::Result::Continue; 2290} 2291void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query) 2292{ 2293 ASSERT(mOcclusionQuery == query); 2294 2295 if (mRenderEncoder.valid()) 2296 { 2297 // if render pass has started, end the query in the encoder 2298 disableActiveOcclusionQueryInRenderPass(); 2299 } 2300 2301 mOcclusionQuery = nullptr; 2302} 2303void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query) 2304{ 2305 if (query->getAllocatedVisibilityOffsets().empty()) 2306 { 2307 return; 2308 } 2309 if (mOcclusionQuery == query) 2310 { 2311 onOcclusionQueryEnd(context, query); 2312 } 2313 mOcclusionQueryPool.deallocateQueryOffset(this, query); 2314} 2315 2316void ContextMtl::disableActiveOcclusionQueryInRenderPass() 2317{ 2318 if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty()) 2319 { 2320 return; 2321 } 2322 2323 ASSERT(mRenderEncoder.valid()); 2324 mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeDisabled, 2325 mOcclusionQuery->getAllocatedVisibilityOffsets().back()); 2326} 2327 2328angle::Result ContextMtl::restartActiveOcclusionQueryInRenderPass() 2329{ 2330 if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty()) 2331 { 2332 return angle::Result::Continue; 2333 } 2334 2335 return startOcclusionQueryInRenderPass(mOcclusionQuery, false); 2336} 2337 2338angle::Result ContextMtl::startOcclusionQueryInRenderPass(QueryMtl *query, bool clearOldValue) 2339{ 2340 ASSERT(mRenderEncoder.valid()); 2341 2342 ANGLE_TRY(mOcclusionQueryPool.allocateQueryOffset(this, query, clearOldValue)); 2343 2344 mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeBoolean, 2345 query->getAllocatedVisibilityOffsets().back()); 2346 2347 // We need to mark the query's buffer as being written in this command buffer now. Since the 2348 // actual writing is deferred until the render pass ends and user could try to read the query 2349 // result before the render pass ends. 2350 mCmdBuffer.setWriteDependency(query->getVisibilityResultBuffer(), /*isRenderCommand=*/true); 2351 2352 return angle::Result::Continue; 2353} 2354 2355void ContextMtl::onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb) 2356{ 2357 // NOTE(hqle): We have to end current render pass to enable synchronization before XFB 2358 // buffers could be used as vertex input. Consider a better approach. 2359 endEncoding(true); 2360} 2361 2362void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb) 2363{ 2364 // NOTE(hqle): We have to end current render pass to enable synchronization before XFB 2365 // buffers could be used as vertex input. Consider a better approach. 2366 endEncoding(true); 2367} 2368 2369uint64_t ContextMtl::queueEventSignal(id<MTLEvent> event, uint64_t value) 2370{ 2371 ensureCommandBufferReady(); 2372 // Event is queued to be signaled after current render pass. If we have helper blit or 2373 // compute encoders, avoid queueing by stopping them immediately so we get to insert the event 2374 // right away. 2375 endBlitAndComputeEncoding(); 2376 return mCmdBuffer.queueEventSignal(event, value); 2377} 2378 2379void ContextMtl::serverWaitEvent(id<MTLEvent> event, uint64_t value) 2380{ 2381 ensureCommandBufferReady(); 2382 2383 // Event waiting cannot be encoded if there is active encoder. 2384 endEncoding(true); 2385 2386 mCmdBuffer.serverWaitEvent(event, value); 2387} 2388 2389void ContextMtl::updateProgramExecutable(const gl::Context *context) 2390{ 2391 // Need to rebind textures 2392 invalidateCurrentTextures(); 2393 // Need to re-upload default attributes 2394 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 2395 // Render pipeline need to be re-applied 2396 invalidateRenderPipeline(); 2397} 2398 2399void ContextMtl::updateVertexArray(const gl::Context *context) 2400{ 2401 const gl::State &glState = getState(); 2402 mVertexArray = mtl::GetImpl(glState.getVertexArray()); 2403 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 2404 invalidateRenderPipeline(); 2405} 2406 2407angle::Result ContextMtl::updateDefaultAttribute(size_t attribIndex) 2408{ 2409 const gl::State &glState = mState; 2410 const gl::VertexAttribCurrentValueData &defaultValue = 2411 glState.getVertexAttribCurrentValues()[attribIndex]; 2412 2413 constexpr size_t kDefaultGLAttributeValueSize = 2414 sizeof(gl::VertexAttribCurrentValueData::Values); 2415 2416 static_assert(kDefaultGLAttributeValueSize == mtl::kDefaultAttributeSize, 2417 "Unexpected default attribute size"); 2418 memcpy(mDefaultAttributes[attribIndex].values, &defaultValue.Values, 2419 mtl::kDefaultAttributeSize); 2420 2421 return angle::Result::Continue; 2422} 2423 2424static bool isDrawNoOp(const mtl::RenderPipelineDesc &descriptor, 2425 ContextMtl *context, 2426 const mtl::ContextDevice &device) 2427{ 2428 // Ensure there is at least one valid render target. 2429 bool hasValidRenderTarget = false; 2430 2431 const NSUInteger maxColorRenderTargets = GetMaxNumberOfRenderTargetsForDevice(device); 2432 for (NSUInteger i = 0; i < maxColorRenderTargets; ++i) 2433 { 2434 const auto &colorAttachment = descriptor.outputDescriptor.colorAttachments[i]; 2435 if (colorAttachment.pixelFormat != MTLPixelFormatInvalid) 2436 { 2437 hasValidRenderTarget = true; 2438 break; 2439 } 2440 } 2441 2442 if (!hasValidRenderTarget && 2443 descriptor.outputDescriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid) 2444 { 2445 hasValidRenderTarget = true; 2446 } 2447 2448 if (!hasValidRenderTarget && 2449 descriptor.outputDescriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid) 2450 { 2451 hasValidRenderTarget = true; 2452 } 2453 2454 if (!hasValidRenderTarget) 2455 { 2456 FramebufferMtl *framebufferMtl = mtl::GetImpl(context->getState().getDrawFramebuffer()); 2457 hasValidRenderTarget = framebufferMtl->renderPassHasDefaultWidthOrHeight(); 2458 } 2459 2460 // Draw is no op if there is no valid render target, and we're not in a 2461 // rasterization-disabled draw. 2462 2463 bool noRenderTarget = !hasValidRenderTarget; 2464 bool rasterizationDisabled = !descriptor.rasterizationEnabled(); 2465 return !rasterizationDisabled && noRenderTarget; 2466} 2467 2468angle::Result ContextMtl::setupDraw(const gl::Context *context, 2469 gl::PrimitiveMode mode, 2470 GLint firstVertex, 2471 GLsizei vertexOrIndexCount, 2472 GLsizei instances, 2473 gl::DrawElementsType indexTypeOrNone, 2474 const void *indices, 2475 bool xfbPass, 2476 bool *isNoOp) 2477{ 2478 ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances, 2479 indexTypeOrNone, indices, xfbPass, isNoOp)); 2480 if (*isNoOp) 2481 { 2482 return angle::Result::Continue; 2483 } 2484 if (!mRenderEncoder.valid()) 2485 { 2486 // Flush occurred during setup, due to running out of memory while setting up the render 2487 // pass state. This would happen for example when there is no more space in the uniform 2488 // buffers in the uniform buffer pool. The rendering would be flushed to free the uniform 2489 // buffer memory for new usage. In this case, re-run the setup. 2490 ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances, 2491 indexTypeOrNone, indices, xfbPass, isNoOp)); 2492 2493 if (*isNoOp) 2494 { 2495 return checkCommandBufferError(); 2496 } 2497 // Setup with flushed state should either produce a working encoder or fail with an error 2498 // result. 2499 ASSERT(mRenderEncoder.valid()); 2500 } 2501 return angle::Result::Continue; 2502} 2503 2504angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, 2505 gl::PrimitiveMode mode, 2506 GLint firstVertex, 2507 GLsizei vertexOrIndexCount, 2508 GLsizei instances, 2509 gl::DrawElementsType indexTypeOrNone, 2510 const void *indices, 2511 bool xfbPass, 2512 bool *isNoOp) 2513{ 2514 ASSERT(mExecutable); 2515 *isNoOp = false; 2516 // instances=0 means no instanced draw. 2517 GLsizei instanceCount = instances ? instances : 1; 2518 2519 if (context->getStateCache().hasAnyActiveClientAttrib()) 2520 { 2521 ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, 2522 instanceCount, indexTypeOrNone, indices)); 2523 } 2524 2525 // This must be called before render command encoder is started. 2526 bool textureChanged = false; 2527 if (mDirtyBits.test(DIRTY_BIT_TEXTURES)) 2528 { 2529 textureChanged = true; 2530 ANGLE_TRY(handleDirtyActiveTextures(context)); 2531 } 2532 2533 if (mDirtyBits.test(DIRTY_BIT_RASTERIZER_DISCARD)) 2534 { 2535 if (getState().isTransformFeedbackActiveUnpaused()) 2536 { 2537 // If XFB is active we need to reset render pass since we could use a dummy render 2538 // target if only XFB is needed. 2539 invalidateState(context); 2540 } 2541 else 2542 { 2543 invalidateRenderPipeline(); 2544 } 2545 } 2546 2547 if (!mRenderEncoder.valid()) 2548 { 2549 // re-apply everything 2550 invalidateState(context); 2551 } 2552 2553 if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER)) 2554 { 2555 ANGLE_TRY(handleDirtyRenderPass(context)); 2556 } 2557 2558 if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0) 2559 { 2560 // The occlusion query is still active, and a new render pass has started. 2561 // We need to continue the querying process in the new render encoder. 2562 ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false)); 2563 } 2564 2565 bool isPipelineDescChanged; 2566 ANGLE_TRY(checkIfPipelineChanged(context, mode, xfbPass, &isPipelineDescChanged)); 2567 2568 bool uniformBuffersDirty = false; 2569 2570 if (IsTransformFeedbackOnly(getState())) 2571 { 2572 // Filter out unneeded dirty bits 2573 filterOutXFBOnlyDirtyBits(context); 2574 } 2575 2576 for (size_t bit : mDirtyBits) 2577 { 2578 switch (bit) 2579 { 2580 case DIRTY_BIT_TEXTURES: 2581 // Already handled. 2582 break; 2583 case DIRTY_BIT_DEFAULT_ATTRIBS: 2584 ANGLE_TRY(handleDirtyDefaultAttribs(context)); 2585 break; 2586 case DIRTY_BIT_DRIVER_UNIFORMS: 2587 ANGLE_TRY(handleDirtyDriverUniforms(context, firstVertex, vertexOrIndexCount)); 2588 break; 2589 case DIRTY_BIT_DEPTH_STENCIL_DESC: 2590 ANGLE_TRY(handleDirtyDepthStencilState(context)); 2591 break; 2592 case DIRTY_BIT_DEPTH_BIAS: 2593 ANGLE_TRY(handleDirtyDepthBias(context)); 2594 break; 2595 case DIRTY_BIT_DEPTH_CLIP_MODE: 2596 mRenderEncoder.setDepthClipMode( 2597 mState.isDepthClampEnabled() ? MTLDepthClipModeClamp : MTLDepthClipModeClip); 2598 break; 2599 case DIRTY_BIT_STENCIL_REF: 2600 mRenderEncoder.setStencilRefVals(mStencilRefFront, mStencilRefBack); 2601 break; 2602 case DIRTY_BIT_BLEND_COLOR: 2603 mRenderEncoder.setBlendColor( 2604 mState.getBlendColor().red, mState.getBlendColor().green, 2605 mState.getBlendColor().blue, mState.getBlendColor().alpha); 2606 break; 2607 case DIRTY_BIT_VIEWPORT: 2608 mRenderEncoder.setViewport(mViewport); 2609 break; 2610 case DIRTY_BIT_SCISSOR: 2611 mRenderEncoder.setScissorRect(mScissorRect); 2612 break; 2613 case DIRTY_BIT_DRAW_FRAMEBUFFER: 2614 // Already handled. 2615 break; 2616 case DIRTY_BIT_CULL_MODE: 2617 mRenderEncoder.setCullMode(mCullMode); 2618 break; 2619 case DIRTY_BIT_FILL_MODE: 2620 mRenderEncoder.setTriangleFillMode(mState.getPolygonMode() == gl::PolygonMode::Fill 2621 ? MTLTriangleFillModeFill 2622 : MTLTriangleFillModeLines); 2623 break; 2624 case DIRTY_BIT_WINDING: 2625 mRenderEncoder.setFrontFacingWinding(mWinding); 2626 break; 2627 case DIRTY_BIT_RENDER_PIPELINE: 2628 // Already handled. See checkIfPipelineChanged(). 2629 break; 2630 case DIRTY_BIT_UNIFORM_BUFFERS_BINDING: 2631 uniformBuffersDirty = true; 2632 break; 2633 case DIRTY_BIT_RASTERIZER_DISCARD: 2634 // Already handled. 2635 break; 2636 default: 2637 UNREACHABLE(); 2638 break; 2639 } 2640 } 2641 2642 if (xfbPass && !mDirtyBits.test(DIRTY_BIT_DRIVER_UNIFORMS)) 2643 { 2644 // If handleDirtyDriverUniforms() was not called and this is XFB pass, we still need to 2645 // update XFB related uniforms 2646 ANGLE_TRY( 2647 fillDriverXFBUniforms(firstVertex, vertexOrIndexCount, /** skippedInstances */ 0)); 2648 mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2649 } 2650 2651 mDirtyBits.reset(); 2652 // Check to see if our state would lead to a no-op draw. 2653 // If so, skip program setup until we end up with a state that requires a program. 2654 if (isDrawNoOp(mRenderPipelineDesc, this, mContextDevice)) 2655 { 2656 *isNoOp = true; 2657 } 2658 else 2659 { 2660 ANGLE_TRY(mExecutable->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc, 2661 isPipelineDescChanged, textureChanged, 2662 uniformBuffersDirty)); 2663 } 2664 2665 return checkCommandBufferError(); 2666} 2667 2668void ContextMtl::filterOutXFBOnlyDirtyBits(const gl::Context *context) 2669{ 2670 ASSERT(IsTransformFeedbackOnly(getState())); 2671 2672 ASSERT(mRenderEncoder.renderPassDesc().colorAttachments[0].texture == mDummyXFBRenderTexture); 2673 2674 // In transform feedback only pass, only vertex shader's related states are needed. 2675 constexpr size_t kUnneededBits = 2676 angle::Bit<size_t>(DIRTY_BIT_DEPTH_STENCIL_DESC) | 2677 angle::Bit<size_t>(DIRTY_BIT_DEPTH_BIAS) | angle::Bit<size_t>(DIRTY_BIT_STENCIL_REF) | 2678 angle::Bit<size_t>(DIRTY_BIT_BLEND_COLOR) | angle::Bit<size_t>(DIRTY_BIT_VIEWPORT) | 2679 angle::Bit<size_t>(DIRTY_BIT_SCISSOR) | angle::Bit<size_t>(DIRTY_BIT_CULL_MODE) | 2680 angle::Bit<size_t>(DIRTY_BIT_FILL_MODE) | angle::Bit<size_t>(DIRTY_BIT_WINDING); 2681 2682 mDirtyBits &= ~kUnneededBits; 2683} 2684 2685angle::Result ContextMtl::handleDirtyRenderPass(const gl::Context *context) 2686{ 2687 if (!IsTransformFeedbackOnly(mState)) 2688 { 2689 // Start new render command encoder 2690 mtl::RenderCommandEncoder *encoder; 2691 ANGLE_TRY(mDrawFramebuffer->ensureRenderPassStarted(context, &encoder)); 2692 } 2693 else 2694 { 2695 // XFB is active and rasterization is disabled. Use dummy render target. 2696 // We currently need to end the render pass when XFB is activated/deactivated so using 2697 // a small dummy render target would make the render pass ending very cheap. 2698 if (!mDummyXFBRenderTexture) 2699 { 2700 ANGLE_TRY(mtl::Texture::Make2DTexture(this, 2701 getPixelFormat(angle::FormatID::R8G8B8A8_UNORM), 2702 1, 1, 1, true, false, &mDummyXFBRenderTexture)); 2703 } 2704 mtl::RenderCommandEncoder *encoder = getTextureRenderCommandEncoder( 2705 mDummyXFBRenderTexture, 2706 mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0))); 2707 encoder->setColorLoadAction(MTLLoadActionDontCare, MTLClearColor(), 0); 2708 encoder->setColorStoreAction(MTLStoreActionDontCare); 2709 2710#ifndef NDEBUG 2711 encoder->setLabel(@"TransformFeedbackOnlyPass"); 2712#endif 2713 } 2714 2715 // re-apply everything 2716 invalidateState(context); 2717 2718 return angle::Result::Continue; 2719} 2720 2721angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context) 2722{ 2723 const gl::State &glState = mState; 2724 const gl::ProgramExecutable *executable = glState.getProgramExecutable(); 2725 2726 constexpr auto ensureTextureStorageCreated = [](const gl::Context *context, 2727 gl::Texture *texture) -> angle::Result { 2728 if (texture == nullptr) 2729 { 2730 return angle::Result::Continue; 2731 } 2732 2733 TextureMtl *textureMtl = mtl::GetImpl(texture); 2734 2735 // Make sure texture's image definitions will be transferred to GPU. 2736 ANGLE_TRY(textureMtl->ensureNativeStorageCreated(context)); 2737 2738 // The binding of this texture will be done by ProgramMtl. 2739 return angle::Result::Continue; 2740 }; 2741 2742 const gl::ActiveTexturesCache &textures = glState.getActiveTexturesCache(); 2743 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask(); 2744 2745 for (size_t textureUnit : activeTextures) 2746 { 2747 ANGLE_TRY(ensureTextureStorageCreated(context, textures[textureUnit])); 2748 } 2749 2750 for (size_t imageUnit : executable->getActiveImagesMask()) 2751 { 2752 ANGLE_TRY( 2753 ensureTextureStorageCreated(context, glState.getImageUnit(imageUnit).texture.get())); 2754 } 2755 2756 return angle::Result::Continue; 2757} 2758 2759angle::Result ContextMtl::handleDirtyDefaultAttribs(const gl::Context *context) 2760{ 2761 for (size_t attribIndex : mDirtyDefaultAttribsMask) 2762 { 2763 ANGLE_TRY(updateDefaultAttribute(attribIndex)); 2764 } 2765 2766 ASSERT(mRenderEncoder.valid()); 2767 mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex); 2768 2769 mDirtyDefaultAttribsMask.reset(); 2770 return angle::Result::Continue; 2771} 2772 2773angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context, 2774 GLint drawCallFirstVertex, 2775 uint32_t verticesPerInstance) 2776{ 2777 mDriverUniforms.depthRange[0] = mState.getNearPlane(); 2778 mDriverUniforms.depthRange[1] = mState.getFarPlane(); 2779 2780 mDriverUniforms.renderArea = mDrawFramebuffer->getState().getDimensions().height << 16 | 2781 mDrawFramebuffer->getState().getDimensions().width; 2782 2783 const float flipX = 1.0; 2784 const float flipY = mDrawFramebuffer->flipY() ? -1.0f : 1.0f; 2785 mDriverUniforms.flipXY = gl::PackSnorm4x8( 2786 flipX, flipY, flipX, mState.getClipOrigin() == gl::ClipOrigin::LowerLeft ? -flipY : flipY); 2787 2788 // gl_ClipDistance 2789 const uint32_t enabledClipDistances = mState.getEnabledClipDistances().bits(); 2790 ASSERT((enabledClipDistances & ~sh::vk::kDriverUniformsMiscEnabledClipPlanesMask) == 0); 2791 2792 // GL_CLIP_DEPTH_MODE_EXT 2793 const uint32_t transformDepth = !mState.isClipDepthModeZeroToOne(); 2794 ASSERT((transformDepth & ~sh::vk::kDriverUniformsMiscTransformDepthMask) == 0); 2795 2796 // GL_SAMPLE_ALPHA_TO_COVERAGE 2797 const uint32_t alphaToCoverage = mState.isSampleAlphaToCoverageEnabled(); 2798 ASSERT((alphaToCoverage & ~sh::vk::kDriverUniformsMiscAlphaToCoverageMask) == 0); 2799 2800 mDriverUniforms.misc = 2801 (enabledClipDistances << sh::vk::kDriverUniformsMiscEnabledClipPlanesOffset) | 2802 (transformDepth << sh::vk::kDriverUniformsMiscTransformDepthOffset) | 2803 (alphaToCoverage << sh::vk::kDriverUniformsMiscAlphaToCoverageOffset); 2804 2805 // Sample coverage mask 2806 if (mState.isSampleCoverageEnabled()) 2807 { 2808 const uint32_t sampleBitCount = mDrawFramebuffer->getSamples(); 2809 ASSERT(sampleBitCount < 32); 2810 const uint32_t coverageSampleBitCount = 2811 static_cast<uint32_t>(std::round(mState.getSampleCoverageValue() * sampleBitCount)); 2812 uint32_t coverageMask = (1u << coverageSampleBitCount) - 1; 2813 if (mState.getSampleCoverageInvert()) 2814 { 2815 const uint32_t sampleMask = (1u << sampleBitCount) - 1; 2816 coverageMask = sampleMask & (~coverageMask); 2817 } 2818 mDriverUniforms.coverageMask = coverageMask; 2819 } 2820 else 2821 { 2822 mDriverUniforms.coverageMask = 0xFFFFFFFFu; 2823 } 2824 2825 // Sample mask 2826 if (mState.isSampleMaskEnabled()) 2827 { 2828 mDriverUniforms.coverageMask &= mState.getSampleMaskWord(0); 2829 } 2830 2831 ANGLE_TRY( 2832 fillDriverXFBUniforms(drawCallFirstVertex, verticesPerInstance, /** skippedInstances */ 0)); 2833 2834 ASSERT(mRenderEncoder.valid()); 2835 mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2836 mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2837 2838 return angle::Result::Continue; 2839} 2840 2841angle::Result ContextMtl::fillDriverXFBUniforms(GLint drawCallFirstVertex, 2842 uint32_t verticesPerInstance, 2843 uint32_t skippedInstances) 2844{ 2845 gl::TransformFeedback *transformFeedback = getState().getCurrentTransformFeedback(); 2846 2847 bool xfbActiveUnpaused = getState().isTransformFeedbackActiveUnpaused(); 2848 if (!transformFeedback || !xfbActiveUnpaused) 2849 { 2850 return angle::Result::Continue; 2851 } 2852 2853 mDriverUniforms.xfbVerticesPerInstance = verticesPerInstance; 2854 2855 TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(transformFeedback); 2856 2857 return transformFeedbackMtl->getBufferOffsets(this, drawCallFirstVertex, 2858 verticesPerInstance * skippedInstances, 2859 mDriverUniforms.xfbBufferOffsets); 2860} 2861 2862angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context) 2863{ 2864 ASSERT(mRenderEncoder.valid()); 2865 2866 // Need to handle the case when render pass doesn't have depth/stencil attachment. 2867 mtl::DepthStencilDesc dsDesc = mDepthStencilDesc; 2868 const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc(); 2869 2870 if (!renderPassDesc.depthAttachment.texture) 2871 { 2872 dsDesc.depthWriteEnabled = false; 2873 dsDesc.depthCompareFunction = MTLCompareFunctionAlways; 2874 } 2875 2876 if (!renderPassDesc.stencilAttachment.texture) 2877 { 2878 dsDesc.frontFaceStencil.reset(); 2879 dsDesc.backFaceStencil.reset(); 2880 } 2881 2882 // Apply depth stencil state 2883 mRenderEncoder.setDepthStencilState( 2884 getDisplay()->getStateCache().getDepthStencilState(getMetalDevice(), dsDesc)); 2885 2886 return angle::Result::Continue; 2887} 2888 2889angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context) 2890{ 2891 const gl::RasterizerState &rasterState = mState.getRasterizerState(); 2892 ASSERT(mRenderEncoder.valid()); 2893 if (!mState.isPolygonOffsetEnabled()) 2894 { 2895 mRenderEncoder.setDepthBias(0, 0, 0); 2896 } 2897 else 2898 { 2899 mRenderEncoder.setDepthBias(rasterState.polygonOffsetUnits, rasterState.polygonOffsetFactor, 2900 rasterState.polygonOffsetClamp); 2901 } 2902 2903 return angle::Result::Continue; 2904} 2905 2906angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context, 2907 gl::PrimitiveMode primitiveMode, 2908 bool xfbPass, 2909 bool *isPipelineDescChanged) 2910{ 2911 ASSERT(mRenderEncoder.valid()); 2912 MTLPrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode); 2913 2914 bool rppChange = mDirtyBits.test(DIRTY_BIT_RENDER_PIPELINE) || 2915 topologyClass != mRenderPipelineDesc.inputPrimitiveTopology; 2916 2917 // Obtain RenderPipelineDesc's vertex array descriptor. 2918 ANGLE_TRY(mVertexArray->setupDraw(context, &mRenderEncoder, &rppChange, 2919 &mRenderPipelineDesc.vertexDescriptor)); 2920 2921 if (rppChange) 2922 { 2923 const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc(); 2924 // Obtain RenderPipelineDesc's output descriptor. 2925 renderPassDesc.populateRenderPipelineOutputDesc(mBlendDescArray, 2926 &mRenderPipelineDesc.outputDescriptor); 2927 2928 if (xfbPass) 2929 { 2930 // In XFB pass, we disable fragment shader. 2931 mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Disabled; 2932 } 2933 else if (mState.isRasterizerDiscardEnabled()) 2934 { 2935 // If XFB is not active and rasterizer discard is enabled, we need to emulate the 2936 // discard. Because in this case, vertex shader might write to stage output values and 2937 // Metal doesn't allow rasterization to be disabled. 2938 mRenderPipelineDesc.rasterizationType = 2939 mtl::RenderPipelineRasterization::EmulatedDiscard; 2940 } 2941 else 2942 { 2943 mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Enabled; 2944 } 2945 mRenderPipelineDesc.inputPrimitiveTopology = topologyClass; 2946 mRenderPipelineDesc.alphaToCoverageEnabled = 2947 mState.isSampleAlphaToCoverageEnabled() && 2948 mRenderPipelineDesc.outputDescriptor.rasterSampleCount > 1 && 2949 !getDisplay()->getFeatures().emulateAlphaToCoverage.enabled; 2950 2951 mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers( 2952 mDrawFramebuffer->getState().getEnabledDrawBuffers()); 2953 } 2954 2955 *isPipelineDescChanged = rppChange; 2956 2957 return angle::Result::Continue; 2958} 2959 2960angle::Result ContextMtl::checkCommandBufferError() 2961{ 2962 ANGLE_CHECK_GL_ALLOC( 2963 this, mCmdBuffer.cmdQueue().popCmdBufferError() != MTLCommandBufferErrorOutOfMemory); 2964 return angle::Result::Continue; 2965} 2966 2967} // namespace rx 2968