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 angle::Result::Continue; 277} 278angle::Result ContextMtl::finish(const gl::Context *context) 279{ 280 ANGLE_TRY(finishCommandBuffer()); 281 return angle::Result::Continue; 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 angle::Result::Continue; 1081} 1082 1083angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker) 1084{ 1085 mCmdBuffer.pushDebugGroup(ConvertMarkerToString(length, marker)); 1086 return angle::Result::Continue; 1087} 1088 1089angle::Result ContextMtl::popGroupMarker() 1090{ 1091 mCmdBuffer.popDebugGroup(); 1092 return angle::Result::Continue; 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 angle::Result::Continue; 1102} 1103 1104angle::Result ContextMtl::popDebugGroup(const gl::Context *context) 1105{ 1106 return angle::Result::Continue; 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 angle::Result::Continue; 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 angle::Result::Continue; 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 angle::Result::Continue; 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 angle::Result::Continue; 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::handleError(NSError *nserror, 1676 const char *message, 1677 const char *file, 1678 const char *function, 1679 unsigned int line) 1680{ 1681 if (!nserror) 1682 { 1683 return; 1684 } 1685 1686 mErrors->handleError(GL_INVALID_OPERATION, message, file, function, line); 1687} 1688 1689void ContextMtl::invalidateState(const gl::Context *context) 1690{ 1691 mDirtyBits.set(); 1692 1693 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 1694} 1695 1696void ContextMtl::invalidateDefaultAttribute(size_t attribIndex) 1697{ 1698 mDirtyDefaultAttribsMask.set(attribIndex); 1699 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 1700} 1701 1702void ContextMtl::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask) 1703{ 1704 if (dirtyMask.any()) 1705 { 1706 mDirtyDefaultAttribsMask |= dirtyMask; 1707 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 1708 } 1709 1710 // TODO(anglebug.com/40096755): determine how to merge this. 1711#if 0 1712 if (getDisplay()->getFeatures().hasExplicitMemBarrier.enabled) 1713 { 1714 const gl::ProgramExecutable *executable = mState.getProgramExecutable(); 1715 ASSERT(executable); 1716 ASSERT(executable->hasTransformFeedbackOutput() || mState.isTransformFeedbackActive()); 1717 TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(mState.getCurrentTransformFeedback()); 1718 size_t bufferCount = executable->getTransformFeedbackBufferCount(); 1719 const gl::TransformFeedbackBuffersArray<BufferMtl *> &bufferHandles = 1720 transformFeedbackMtl->getBufferHandles(); 1721 for (size_t i = 0; i < bufferCount; i++) 1722 { 1723 const mtl::BufferRef & constBufferRef = bufferHandles[i]->getCurrentBuffer(); 1724 mRenderEncoder.memoryBarrierWithResource(constBufferRef, mtl::kRenderStageVertex, mtl::kRenderStageVertex); 1725 } 1726 } 1727 else 1728 { 1729 //End the command encoder, so any Transform Feedback changes are available to subsequent draw calls. 1730 endEncoding(false); 1731 } 1732#endif 1733} 1734 1735void ContextMtl::invalidateCurrentTextures() 1736{ 1737 mDirtyBits.set(DIRTY_BIT_TEXTURES); 1738} 1739 1740void ContextMtl::invalidateDriverUniforms() 1741{ 1742 mDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS); 1743} 1744 1745void ContextMtl::invalidateRenderPipeline() 1746{ 1747 mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE); 1748} 1749 1750const mtl::ClearColorValue &ContextMtl::getClearColorValue() const 1751{ 1752 return mClearColor; 1753} 1754const mtl::WriteMaskArray &ContextMtl::getWriteMaskArray() const 1755{ 1756 return mWriteMaskArray; 1757} 1758float ContextMtl::getClearDepthValue() const 1759{ 1760 return getState().getDepthClearValue(); 1761} 1762uint32_t ContextMtl::getClearStencilValue() const 1763{ 1764 return mClearStencil; 1765} 1766uint32_t ContextMtl::getStencilMask() const 1767{ 1768 return getState().getDepthStencilState().stencilWritemask & mtl::kStencilMaskAll; 1769} 1770 1771bool ContextMtl::getDepthMask() const 1772{ 1773 return getState().getDepthStencilState().depthMask; 1774} 1775 1776const mtl::Format &ContextMtl::getPixelFormat(angle::FormatID angleFormatId) const 1777{ 1778 return getDisplay()->getPixelFormat(angleFormatId); 1779} 1780 1781// See mtl::FormatTable::getVertexFormat() 1782const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId, 1783 bool tightlyPacked) const 1784{ 1785 return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked); 1786} 1787 1788const mtl::FormatCaps &ContextMtl::getNativeFormatCaps(MTLPixelFormat mtlFormat) const 1789{ 1790 return getDisplay()->getNativeFormatCaps(mtlFormat); 1791} 1792 1793angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context, 1794 gl::TextureType type, 1795 gl::SamplerFormat format, 1796 gl::Texture **textureOut) 1797{ 1798 return mIncompleteTextures.getIncompleteTexture(context, type, format, nullptr, textureOut); 1799} 1800 1801void ContextMtl::endRenderEncoding(mtl::RenderCommandEncoder *encoder) 1802{ 1803 // End any pending visibility query in the render pass 1804 if (mOcclusionQuery) 1805 { 1806 disableActiveOcclusionQueryInRenderPass(); 1807 } 1808 1809 if (mBlitEncoder.valid()) 1810 { 1811 mBlitEncoder.endEncoding(); 1812 } 1813 1814 mOcclusionQueryPool.prepareRenderPassVisibilityPoolBuffer(this); 1815 1816 encoder->endEncoding(); 1817 1818 // Resolve visibility results 1819 mOcclusionQueryPool.resolveVisibilityResults(this); 1820} 1821 1822void ContextMtl::endBlitAndComputeEncoding() 1823{ 1824 if (mBlitEncoder.valid()) 1825 { 1826 mBlitEncoder.endEncoding(); 1827 } 1828 1829 if (mComputeEncoder.valid()) 1830 { 1831 mComputeEncoder.endEncoding(); 1832 mProvokingVertexHelper.releaseInFlightBuffers(this); 1833 } 1834} 1835 1836void ContextMtl::endEncoding(bool forceSaveRenderPassContent) 1837{ 1838 endBlitAndComputeEncoding(); 1839 1840 if (mRenderEncoder.valid()) 1841 { 1842 if (forceSaveRenderPassContent) 1843 { 1844 // Save the work in progress. 1845 mRenderEncoder.setStoreAction(MTLStoreActionStore); 1846 } 1847 1848 endRenderEncoding(&mRenderEncoder); 1849 } 1850 // End blit encoder after render encoder, as endRenderEncoding() might create a 1851 // blit encoder to resolve the visibility results. 1852 if (mBlitEncoder.valid()) 1853 { 1854 mBlitEncoder.endEncoding(); 1855 } 1856} 1857 1858void ContextMtl::flushCommandBuffer(mtl::CommandBufferFinishOperation operation) 1859{ 1860 mRenderPassesSinceFlush = 0; 1861 if (mCmdBuffer.ready()) 1862 { 1863 endEncoding(true); 1864 mCmdBuffer.commit(operation); 1865 mBufferManager.incrementNumCommandBufferCommits(); 1866 } 1867 else 1868 { 1869 mCmdBuffer.wait(operation); 1870 } 1871} 1872 1873void ContextMtl::flushCommandBufferIfNeeded() 1874{ 1875 if (mRenderPassesSinceFlush >= mtl::kMaxRenderPassesPerCommandBuffer || 1876 mCmdBuffer.needsFlushForDrawCallLimits()) 1877 { 1878 // Ensure that we don't accumulate too many unflushed render passes. Don't wait until they 1879 // are submitted, other components handle backpressure so don't create uneccessary CPU/GPU 1880 // synchronization. 1881 flushCommandBuffer(mtl::NoWait); 1882 } 1883} 1884 1885void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable) 1886{ 1887 ensureCommandBufferReady(); 1888 1889 FramebufferMtl *currentframebuffer = mtl::GetImpl(getState().getDrawFramebuffer()); 1890 if (currentframebuffer) 1891 { 1892 currentframebuffer->onFrameEnd(context); 1893 } 1894 1895 endEncoding(false); 1896 mCmdBuffer.present(presentationDrawable); 1897 mCmdBuffer.commit(mtl::NoWait); 1898 mRenderPassesSinceFlush = 0; 1899} 1900 1901angle::Result ContextMtl::finishCommandBuffer() 1902{ 1903 flushCommandBuffer(mtl::WaitUntilFinished); 1904 return angle::Result::Continue; 1905} 1906 1907bool ContextMtl::hasStartedRenderPass(const mtl::RenderPassDesc &desc) 1908{ 1909 return mRenderEncoder.valid() && 1910 mRenderEncoder.renderPassDesc().equalIgnoreLoadStoreOptions(desc); 1911} 1912 1913bool ContextMtl::isCurrentRenderEncoderSerial(uint64_t serial) 1914{ 1915 if (!mRenderEncoder.valid()) 1916 { 1917 return false; 1918 } 1919 1920 return serial == mRenderEncoder.getSerial(); 1921} 1922 1923// Get current render encoder 1924mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder() 1925{ 1926 if (!mRenderEncoder.valid()) 1927 { 1928 return nullptr; 1929 } 1930 1931 return &mRenderEncoder; 1932} 1933 1934mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc) 1935{ 1936 if (hasStartedRenderPass(desc)) 1937 { 1938 return &mRenderEncoder; 1939 } 1940 1941 endEncoding(false); 1942 1943 ensureCommandBufferReady(); 1944 ++mRenderPassesSinceFlush; 1945 1946 // Need to re-apply everything on next draw call. 1947 mDirtyBits.set(); 1948 1949 const mtl::ContextDevice &metalDevice = getMetalDevice(); 1950 if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice)) 1951 { 1952 NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice); 1953 NSUInteger renderTargetSize = 1954 ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, this, metalDevice); 1955 if (renderTargetSize > maxSize) 1956 { 1957 std::stringstream errorStream; 1958 errorStream << "This set of render targets requires " << renderTargetSize 1959 << " bytes of pixel storage. This device supports " << maxSize << " bytes."; 1960 ANGLE_MTL_HANDLE_ERROR(this, errorStream.str().c_str(), GL_INVALID_OPERATION); 1961 return nullptr; 1962 } 1963 } 1964 return &mRenderEncoder.restart(desc, getNativeCaps().maxColorAttachments); 1965} 1966 1967// Utilities to quickly create render command encoder to a specific texture: 1968// The previous content of texture will be loaded 1969mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder( 1970 const mtl::TextureRef &textureTarget, 1971 const mtl::ImageNativeIndex &index) 1972{ 1973 ASSERT(textureTarget && textureTarget->valid()); 1974 1975 mtl::RenderPassDesc rpDesc; 1976 1977 rpDesc.colorAttachments[0].texture = textureTarget; 1978 rpDesc.colorAttachments[0].level = index.getNativeLevel(); 1979 rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0; 1980 rpDesc.numColorAttachments = 1; 1981 rpDesc.rasterSampleCount = textureTarget->samples(); 1982 1983 return getRenderPassCommandEncoder(rpDesc); 1984} 1985 1986// The previous content of texture will be loaded if clearColor is not provided 1987mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoderWithClear( 1988 const RenderTargetMtl &renderTarget, 1989 const Optional<MTLClearColor> &clearColor) 1990{ 1991 ASSERT(renderTarget.getTexture()); 1992 1993 mtl::RenderPassDesc rpDesc; 1994 renderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]); 1995 rpDesc.numColorAttachments = 1; 1996 rpDesc.rasterSampleCount = renderTarget.getRenderSamples(); 1997 1998 if (clearColor.valid()) 1999 { 2000 rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear; 2001 rpDesc.colorAttachments[0].clearColor = mtl::EmulatedAlphaClearColor( 2002 clearColor.value(), renderTarget.getTexture()->getColorWritableMask()); 2003 2004 endEncoding(true); 2005 } 2006 2007 return getRenderPassCommandEncoder(rpDesc); 2008} 2009// The previous content of texture will be loaded 2010mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoder( 2011 const RenderTargetMtl &renderTarget) 2012{ 2013 return getRenderTargetCommandEncoderWithClear(renderTarget, Optional<MTLClearColor>()); 2014} 2015 2016mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder() 2017{ 2018 if (mRenderEncoder.valid() || mComputeEncoder.valid()) 2019 { 2020 endEncoding(true); 2021 } 2022 2023 if (mBlitEncoder.valid()) 2024 { 2025 return &mBlitEncoder; 2026 } 2027 2028 endEncoding(true); 2029 ensureCommandBufferReady(); 2030 2031 return &mBlitEncoder.restart(); 2032} 2033 2034mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoderWithoutEndingRenderEncoder() 2035{ 2036 if (mBlitEncoder.valid()) 2037 { 2038 return &mBlitEncoder; 2039 } 2040 2041 endBlitAndComputeEncoding(); 2042 ensureCommandBufferReady(); 2043 2044 return &mBlitEncoder.restart(); 2045} 2046 2047mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoder() 2048{ 2049 if (mRenderEncoder.valid() || mBlitEncoder.valid()) 2050 { 2051 endEncoding(true); 2052 } 2053 2054 if (mComputeEncoder.valid()) 2055 { 2056 return &mComputeEncoder; 2057 } 2058 2059 endEncoding(true); 2060 ensureCommandBufferReady(); 2061 2062 return &mComputeEncoder.restart(); 2063} 2064 2065mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoderWithoutEndingRenderEncoder() 2066{ 2067 if (mComputeEncoder.valid()) 2068 { 2069 return &mComputeEncoder; 2070 } 2071 2072 endBlitAndComputeEncoding(); 2073 ensureCommandBufferReady(); 2074 2075 return &mComputeEncoder.restart(); 2076} 2077 2078mtl::ComputeCommandEncoder *ContextMtl::getIndexPreprocessingCommandEncoder() 2079{ 2080 return getComputeCommandEncoder(); 2081} 2082 2083void ContextMtl::ensureCommandBufferReady() 2084{ 2085 flushCommandBufferIfNeeded(); 2086 2087 if (!mCmdBuffer.ready()) 2088 { 2089 mCmdBuffer.restart(); 2090 } 2091 2092 ASSERT(mCmdBuffer.ready()); 2093} 2094 2095void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl, 2096 const gl::Rectangle &viewport, 2097 float nearPlane, 2098 float farPlane) 2099{ 2100 mViewport = mtl::GetViewport(viewport, framebufferMtl->getState().getDimensions().height, 2101 framebufferMtl->flipY(), nearPlane, farPlane); 2102 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 2103 2104 invalidateDriverUniforms(); 2105} 2106 2107void ContextMtl::updateDepthRange(float nearPlane, float farPlane) 2108{ 2109 if (NeedToInvertDepthRange(nearPlane, farPlane)) 2110 { 2111 // We also need to invert the depth in shader later by using scale value stored in driver 2112 // uniform depthRange.reserved 2113 std::swap(nearPlane, farPlane); 2114 } 2115 mViewport.znear = nearPlane; 2116 mViewport.zfar = farPlane; 2117 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 2118 2119 invalidateDriverUniforms(); 2120} 2121 2122void ContextMtl::updateBlendDescArray(const gl::BlendStateExt &blendStateExt) 2123{ 2124 for (size_t i = 0; i < mBlendDescArray.size(); i++) 2125 { 2126 mtl::BlendDesc &blendDesc = mBlendDescArray[i]; 2127 if (blendStateExt.getEnabledMask().test(i)) 2128 { 2129 blendDesc.blendingEnabled = true; 2130 2131 blendDesc.sourceRGBBlendFactor = 2132 mtl::GetBlendFactor(blendStateExt.getSrcColorIndexed(i)); 2133 blendDesc.sourceAlphaBlendFactor = 2134 mtl::GetBlendFactor(blendStateExt.getSrcAlphaIndexed(i)); 2135 blendDesc.destinationRGBBlendFactor = 2136 mtl::GetBlendFactor(blendStateExt.getDstColorIndexed(i)); 2137 blendDesc.destinationAlphaBlendFactor = 2138 mtl::GetBlendFactor(blendStateExt.getDstAlphaIndexed(i)); 2139 2140 blendDesc.rgbBlendOperation = mtl::GetBlendOp(blendStateExt.getEquationColorIndexed(i)); 2141 blendDesc.alphaBlendOperation = 2142 mtl::GetBlendOp(blendStateExt.getEquationAlphaIndexed(i)); 2143 } 2144 else 2145 { 2146 // Enforce default state when blending is disabled, 2147 blendDesc.reset(blendDesc.writeMask); 2148 } 2149 } 2150 invalidateRenderPipeline(); 2151} 2152 2153void ContextMtl::updateScissor(const gl::State &glState) 2154{ 2155 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 2156 gl::Rectangle renderArea = framebufferMtl->getCompleteRenderArea(); 2157 2158 ANGLE_MTL_LOG("renderArea = %d,%d,%d,%d", renderArea.x, renderArea.y, renderArea.width, 2159 renderArea.height); 2160 2161 // Clip the render area to the viewport. 2162 gl::Rectangle viewportClippedRenderArea; 2163 if (!gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea)) 2164 { 2165 viewportClippedRenderArea = gl::Rectangle(); 2166 } 2167 2168 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false); 2169 if (framebufferMtl->flipY()) 2170 { 2171 scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height; 2172 } 2173 2174 ANGLE_MTL_LOG("scissoredArea = %d,%d,%d,%d", scissoredArea.x, scissoredArea.y, 2175 scissoredArea.width, scissoredArea.height); 2176 2177 mScissorRect = mtl::GetScissorRect(scissoredArea); 2178 mDirtyBits.set(DIRTY_BIT_SCISSOR); 2179} 2180 2181void ContextMtl::updateCullMode(const gl::State &glState) 2182{ 2183 const gl::RasterizerState &rasterState = glState.getRasterizerState(); 2184 2185 mCullAllPolygons = false; 2186 if (!rasterState.cullFace) 2187 { 2188 mCullMode = MTLCullModeNone; 2189 } 2190 else 2191 { 2192 switch (rasterState.cullMode) 2193 { 2194 case gl::CullFaceMode::Back: 2195 mCullMode = MTLCullModeBack; 2196 break; 2197 case gl::CullFaceMode::Front: 2198 mCullMode = MTLCullModeFront; 2199 break; 2200 case gl::CullFaceMode::FrontAndBack: 2201 mCullAllPolygons = true; 2202 break; 2203 default: 2204 UNREACHABLE(); 2205 break; 2206 } 2207 } 2208 2209 mDirtyBits.set(DIRTY_BIT_CULL_MODE); 2210} 2211 2212void ContextMtl::updateFrontFace(const gl::State &glState) 2213{ 2214 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 2215 const bool upperLeftOrigin = mState.getClipOrigin() == gl::ClipOrigin::UpperLeft; 2216 mWinding = mtl::GetFrontfaceWinding(glState.getRasterizerState().frontFace, 2217 framebufferMtl->flipY() == upperLeftOrigin); 2218 mDirtyBits.set(DIRTY_BIT_WINDING); 2219} 2220 2221// Index rewrite is required if: 2222// Provkoing vertex mode is 'last' 2223// Program has at least one 'flat' attribute 2224// PrimitiveMode is not POINTS. 2225bool ContextMtl::requiresIndexRewrite(const gl::State &state, gl::PrimitiveMode mode) 2226{ 2227 return mode != gl::PrimitiveMode::Points && mExecutable->hasFlatAttribute() && 2228 (state.getProvokingVertex() == gl::ProvokingVertexConvention::LastVertexConvention); 2229} 2230 2231void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context) 2232{ 2233 const gl::State &glState = getState(); 2234 2235 FramebufferMtl *newDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer()); 2236 if (newDrawFramebuffer != mDrawFramebuffer) 2237 { 2238 // Reset this flag if the framebuffer has changed to not sync it twice 2239 mForceResyncDrawFramebuffer = false; 2240 } 2241 2242 mDrawFramebuffer = newDrawFramebuffer; 2243 2244 mDrawFramebuffer->onStartedDrawingToFrameBuffer(context); 2245 2246 onDrawFrameBufferChangedState(context, mDrawFramebuffer, true); 2247} 2248 2249void ContextMtl::onDrawFrameBufferChangedState(const gl::Context *context, 2250 FramebufferMtl *framebuffer, 2251 bool renderPassChanged) 2252{ 2253 const gl::State &glState = getState(); 2254 ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer())); 2255 2256 updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(), 2257 glState.getFarPlane()); 2258 updateFrontFace(glState); 2259 updateScissor(glState); 2260 2261 if (renderPassChanged) 2262 { 2263 // End any render encoding using the old render pass. 2264 endEncoding(false); 2265 // Need to re-apply state to RenderCommandEncoder 2266 invalidateState(context); 2267 } 2268 else 2269 { 2270 // Invalidate current pipeline only. 2271 invalidateRenderPipeline(); 2272 } 2273} 2274 2275void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer) 2276{ 2277 const gl::State &glState = getState(); 2278 FramebufferMtl *framebuffer = mtl::GetImpl(glState.getDrawFramebuffer()); 2279 if (framebuffer->getAttachedBackbuffer() != backbuffer) 2280 { 2281 return; 2282 } 2283 2284 onDrawFrameBufferChangedState(context, framebuffer, true); 2285} 2286 2287angle::Result ContextMtl::onOcclusionQueryBegin(const gl::Context *context, QueryMtl *query) 2288{ 2289 ASSERT(mOcclusionQuery == nullptr); 2290 mOcclusionQuery = query; 2291 2292 if (mRenderEncoder.valid()) 2293 { 2294 // if render pass has started, start the query in the encoder 2295 return startOcclusionQueryInRenderPass(query, true); 2296 } 2297 else 2298 { 2299 query->resetVisibilityResult(this); 2300 } 2301 2302 return angle::Result::Continue; 2303} 2304void ContextMtl::onOcclusionQueryEnd(const gl::Context *context, QueryMtl *query) 2305{ 2306 ASSERT(mOcclusionQuery == query); 2307 2308 if (mRenderEncoder.valid()) 2309 { 2310 // if render pass has started, end the query in the encoder 2311 disableActiveOcclusionQueryInRenderPass(); 2312 } 2313 2314 mOcclusionQuery = nullptr; 2315} 2316void ContextMtl::onOcclusionQueryDestroy(const gl::Context *context, QueryMtl *query) 2317{ 2318 if (query->getAllocatedVisibilityOffsets().empty()) 2319 { 2320 return; 2321 } 2322 if (mOcclusionQuery == query) 2323 { 2324 onOcclusionQueryEnd(context, query); 2325 } 2326 mOcclusionQueryPool.deallocateQueryOffset(this, query); 2327} 2328 2329void ContextMtl::disableActiveOcclusionQueryInRenderPass() 2330{ 2331 if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty()) 2332 { 2333 return; 2334 } 2335 2336 ASSERT(mRenderEncoder.valid()); 2337 mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeDisabled, 2338 mOcclusionQuery->getAllocatedVisibilityOffsets().back()); 2339} 2340 2341angle::Result ContextMtl::restartActiveOcclusionQueryInRenderPass() 2342{ 2343 if (!mOcclusionQuery || mOcclusionQuery->getAllocatedVisibilityOffsets().empty()) 2344 { 2345 return angle::Result::Continue; 2346 } 2347 2348 return startOcclusionQueryInRenderPass(mOcclusionQuery, false); 2349} 2350 2351angle::Result ContextMtl::startOcclusionQueryInRenderPass(QueryMtl *query, bool clearOldValue) 2352{ 2353 ASSERT(mRenderEncoder.valid()); 2354 2355 ANGLE_TRY(mOcclusionQueryPool.allocateQueryOffset(this, query, clearOldValue)); 2356 2357 mRenderEncoder.setVisibilityResultMode(MTLVisibilityResultModeBoolean, 2358 query->getAllocatedVisibilityOffsets().back()); 2359 2360 // We need to mark the query's buffer as being written in this command buffer now. Since the 2361 // actual writing is deferred until the render pass ends and user could try to read the query 2362 // result before the render pass ends. 2363 mCmdBuffer.setWriteDependency(query->getVisibilityResultBuffer(), /*isRenderCommand=*/true); 2364 2365 return angle::Result::Continue; 2366} 2367 2368void ContextMtl::onTransformFeedbackActive(const gl::Context *context, TransformFeedbackMtl *xfb) 2369{ 2370 // NOTE(hqle): We have to end current render pass to enable synchronization before XFB 2371 // buffers could be used as vertex input. Consider a better approach. 2372 endEncoding(true); 2373} 2374 2375void ContextMtl::onTransformFeedbackInactive(const gl::Context *context, TransformFeedbackMtl *xfb) 2376{ 2377 // NOTE(hqle): We have to end current render pass to enable synchronization before XFB 2378 // buffers could be used as vertex input. Consider a better approach. 2379 endEncoding(true); 2380} 2381 2382uint64_t ContextMtl::queueEventSignal(id<MTLEvent> event, uint64_t value) 2383{ 2384 ensureCommandBufferReady(); 2385 // Event is queued to be signaled after current render pass. If we have helper blit or 2386 // compute encoders, avoid queueing by stopping them immediately so we get to insert the event 2387 // right away. 2388 endBlitAndComputeEncoding(); 2389 return mCmdBuffer.queueEventSignal(event, value); 2390} 2391 2392void ContextMtl::serverWaitEvent(id<MTLEvent> event, uint64_t value) 2393{ 2394 ensureCommandBufferReady(); 2395 2396 // Event waiting cannot be encoded if there is active encoder. 2397 endEncoding(true); 2398 2399 mCmdBuffer.serverWaitEvent(event, value); 2400} 2401 2402void ContextMtl::updateProgramExecutable(const gl::Context *context) 2403{ 2404 // Need to rebind textures 2405 invalidateCurrentTextures(); 2406 // Need to re-upload default attributes 2407 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 2408 // Render pipeline need to be re-applied 2409 invalidateRenderPipeline(); 2410} 2411 2412void ContextMtl::updateVertexArray(const gl::Context *context) 2413{ 2414 const gl::State &glState = getState(); 2415 mVertexArray = mtl::GetImpl(glState.getVertexArray()); 2416 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 2417 invalidateRenderPipeline(); 2418} 2419 2420angle::Result ContextMtl::updateDefaultAttribute(size_t attribIndex) 2421{ 2422 const gl::State &glState = mState; 2423 const gl::VertexAttribCurrentValueData &defaultValue = 2424 glState.getVertexAttribCurrentValues()[attribIndex]; 2425 2426 constexpr size_t kDefaultGLAttributeValueSize = 2427 sizeof(gl::VertexAttribCurrentValueData::Values); 2428 2429 static_assert(kDefaultGLAttributeValueSize == mtl::kDefaultAttributeSize, 2430 "Unexpected default attribute size"); 2431 memcpy(mDefaultAttributes[attribIndex].values, &defaultValue.Values, 2432 mtl::kDefaultAttributeSize); 2433 2434 return angle::Result::Continue; 2435} 2436 2437static bool isDrawNoOp(const mtl::RenderPipelineDesc &descriptor, 2438 ContextMtl *context, 2439 const mtl::ContextDevice &device) 2440{ 2441 // Ensure there is at least one valid render target. 2442 bool hasValidRenderTarget = false; 2443 2444 const NSUInteger maxColorRenderTargets = GetMaxNumberOfRenderTargetsForDevice(device); 2445 for (NSUInteger i = 0; i < maxColorRenderTargets; ++i) 2446 { 2447 const auto &colorAttachment = descriptor.outputDescriptor.colorAttachments[i]; 2448 if (colorAttachment.pixelFormat != MTLPixelFormatInvalid) 2449 { 2450 hasValidRenderTarget = true; 2451 break; 2452 } 2453 } 2454 2455 if (!hasValidRenderTarget && 2456 descriptor.outputDescriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid) 2457 { 2458 hasValidRenderTarget = true; 2459 } 2460 2461 if (!hasValidRenderTarget && 2462 descriptor.outputDescriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid) 2463 { 2464 hasValidRenderTarget = true; 2465 } 2466 2467 if (!hasValidRenderTarget) 2468 { 2469 FramebufferMtl *framebufferMtl = mtl::GetImpl(context->getState().getDrawFramebuffer()); 2470 hasValidRenderTarget = framebufferMtl->renderPassHasDefaultWidthOrHeight(); 2471 } 2472 2473 // Draw is no op if there is no valid render target, and we're not in a 2474 // rasterization-disabled draw. 2475 2476 bool noRenderTarget = !hasValidRenderTarget; 2477 bool rasterizationDisabled = !descriptor.rasterizationEnabled(); 2478 return !rasterizationDisabled && noRenderTarget; 2479} 2480 2481angle::Result ContextMtl::setupDraw(const gl::Context *context, 2482 gl::PrimitiveMode mode, 2483 GLint firstVertex, 2484 GLsizei vertexOrIndexCount, 2485 GLsizei instances, 2486 gl::DrawElementsType indexTypeOrNone, 2487 const void *indices, 2488 bool xfbPass, 2489 bool *isNoOp) 2490{ 2491 ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances, 2492 indexTypeOrNone, indices, xfbPass, isNoOp)); 2493 if (*isNoOp) 2494 { 2495 return angle::Result::Continue; 2496 } 2497 if (!mRenderEncoder.valid()) 2498 { 2499 // Flush occurred during setup, due to running out of memory while setting up the render 2500 // pass state. This would happen for example when there is no more space in the uniform 2501 // buffers in the uniform buffer pool. The rendering would be flushed to free the uniform 2502 // buffer memory for new usage. In this case, re-run the setup. 2503 ANGLE_TRY(setupDrawImpl(context, mode, firstVertex, vertexOrIndexCount, instances, 2504 indexTypeOrNone, indices, xfbPass, isNoOp)); 2505 2506 if (*isNoOp) 2507 { 2508 return angle::Result::Continue; 2509 } 2510 // Setup with flushed state should either produce a working encoder or fail with an error 2511 // result. 2512 ASSERT(mRenderEncoder.valid()); 2513 } 2514 return angle::Result::Continue; 2515} 2516 2517angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, 2518 gl::PrimitiveMode mode, 2519 GLint firstVertex, 2520 GLsizei vertexOrIndexCount, 2521 GLsizei instances, 2522 gl::DrawElementsType indexTypeOrNone, 2523 const void *indices, 2524 bool xfbPass, 2525 bool *isNoOp) 2526{ 2527 ASSERT(mExecutable); 2528 *isNoOp = false; 2529 // instances=0 means no instanced draw. 2530 GLsizei instanceCount = instances ? instances : 1; 2531 2532 if (context->getStateCache().hasAnyActiveClientAttrib()) 2533 { 2534 ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, 2535 instanceCount, indexTypeOrNone, indices)); 2536 } 2537 2538 // This must be called before render command encoder is started. 2539 bool textureChanged = false; 2540 if (mDirtyBits.test(DIRTY_BIT_TEXTURES)) 2541 { 2542 textureChanged = true; 2543 ANGLE_TRY(handleDirtyActiveTextures(context)); 2544 } 2545 2546 if (mDirtyBits.test(DIRTY_BIT_RASTERIZER_DISCARD)) 2547 { 2548 if (getState().isTransformFeedbackActiveUnpaused()) 2549 { 2550 // If XFB is active we need to reset render pass since we could use a dummy render 2551 // target if only XFB is needed. 2552 invalidateState(context); 2553 } 2554 else 2555 { 2556 invalidateRenderPipeline(); 2557 } 2558 } 2559 2560 if (!mRenderEncoder.valid()) 2561 { 2562 // re-apply everything 2563 invalidateState(context); 2564 } 2565 2566 if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER)) 2567 { 2568 ANGLE_TRY(handleDirtyRenderPass(context)); 2569 } 2570 2571 if (mOcclusionQuery && mOcclusionQueryPool.getNumRenderPassAllocatedQueries() == 0) 2572 { 2573 // The occlusion query is still active, and a new render pass has started. 2574 // We need to continue the querying process in the new render encoder. 2575 ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false)); 2576 } 2577 2578 bool isPipelineDescChanged; 2579 ANGLE_TRY(checkIfPipelineChanged(context, mode, xfbPass, &isPipelineDescChanged)); 2580 2581 bool uniformBuffersDirty = false; 2582 2583 if (IsTransformFeedbackOnly(getState())) 2584 { 2585 // Filter out unneeded dirty bits 2586 filterOutXFBOnlyDirtyBits(context); 2587 } 2588 2589 for (size_t bit : mDirtyBits) 2590 { 2591 switch (bit) 2592 { 2593 case DIRTY_BIT_TEXTURES: 2594 // Already handled. 2595 break; 2596 case DIRTY_BIT_DEFAULT_ATTRIBS: 2597 ANGLE_TRY(handleDirtyDefaultAttribs(context)); 2598 break; 2599 case DIRTY_BIT_DRIVER_UNIFORMS: 2600 ANGLE_TRY(handleDirtyDriverUniforms(context, firstVertex, vertexOrIndexCount)); 2601 break; 2602 case DIRTY_BIT_DEPTH_STENCIL_DESC: 2603 ANGLE_TRY(handleDirtyDepthStencilState(context)); 2604 break; 2605 case DIRTY_BIT_DEPTH_BIAS: 2606 ANGLE_TRY(handleDirtyDepthBias(context)); 2607 break; 2608 case DIRTY_BIT_DEPTH_CLIP_MODE: 2609 mRenderEncoder.setDepthClipMode( 2610 mState.isDepthClampEnabled() ? MTLDepthClipModeClamp : MTLDepthClipModeClip); 2611 break; 2612 case DIRTY_BIT_STENCIL_REF: 2613 mRenderEncoder.setStencilRefVals(mStencilRefFront, mStencilRefBack); 2614 break; 2615 case DIRTY_BIT_BLEND_COLOR: 2616 mRenderEncoder.setBlendColor( 2617 mState.getBlendColor().red, mState.getBlendColor().green, 2618 mState.getBlendColor().blue, mState.getBlendColor().alpha); 2619 break; 2620 case DIRTY_BIT_VIEWPORT: 2621 mRenderEncoder.setViewport(mViewport); 2622 break; 2623 case DIRTY_BIT_SCISSOR: 2624 mRenderEncoder.setScissorRect(mScissorRect); 2625 break; 2626 case DIRTY_BIT_DRAW_FRAMEBUFFER: 2627 // Already handled. 2628 break; 2629 case DIRTY_BIT_CULL_MODE: 2630 mRenderEncoder.setCullMode(mCullMode); 2631 break; 2632 case DIRTY_BIT_FILL_MODE: 2633 mRenderEncoder.setTriangleFillMode(mState.getPolygonMode() == gl::PolygonMode::Fill 2634 ? MTLTriangleFillModeFill 2635 : MTLTriangleFillModeLines); 2636 break; 2637 case DIRTY_BIT_WINDING: 2638 mRenderEncoder.setFrontFacingWinding(mWinding); 2639 break; 2640 case DIRTY_BIT_RENDER_PIPELINE: 2641 // Already handled. See checkIfPipelineChanged(). 2642 break; 2643 case DIRTY_BIT_UNIFORM_BUFFERS_BINDING: 2644 uniformBuffersDirty = true; 2645 break; 2646 case DIRTY_BIT_RASTERIZER_DISCARD: 2647 // Already handled. 2648 break; 2649 default: 2650 UNREACHABLE(); 2651 break; 2652 } 2653 } 2654 2655 if (xfbPass && !mDirtyBits.test(DIRTY_BIT_DRIVER_UNIFORMS)) 2656 { 2657 // If handleDirtyDriverUniforms() was not called and this is XFB pass, we still need to 2658 // update XFB related uniforms 2659 ANGLE_TRY( 2660 fillDriverXFBUniforms(firstVertex, vertexOrIndexCount, /** skippedInstances */ 0)); 2661 mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2662 } 2663 2664 mDirtyBits.reset(); 2665 // Check to see if our state would lead to a no-op draw. 2666 // If so, skip program setup until we end up with a state that requires a program. 2667 if (isDrawNoOp(mRenderPipelineDesc, this, mContextDevice)) 2668 { 2669 *isNoOp = true; 2670 } 2671 else 2672 { 2673 ANGLE_TRY(mExecutable->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc, 2674 isPipelineDescChanged, textureChanged, 2675 uniformBuffersDirty)); 2676 } 2677 2678 return angle::Result::Continue; 2679} 2680 2681void ContextMtl::filterOutXFBOnlyDirtyBits(const gl::Context *context) 2682{ 2683 ASSERT(IsTransformFeedbackOnly(getState())); 2684 2685 ASSERT(mRenderEncoder.renderPassDesc().colorAttachments[0].texture == mDummyXFBRenderTexture); 2686 2687 // In transform feedback only pass, only vertex shader's related states are needed. 2688 constexpr size_t kUnneededBits = 2689 angle::Bit<size_t>(DIRTY_BIT_DEPTH_STENCIL_DESC) | 2690 angle::Bit<size_t>(DIRTY_BIT_DEPTH_BIAS) | angle::Bit<size_t>(DIRTY_BIT_STENCIL_REF) | 2691 angle::Bit<size_t>(DIRTY_BIT_BLEND_COLOR) | angle::Bit<size_t>(DIRTY_BIT_VIEWPORT) | 2692 angle::Bit<size_t>(DIRTY_BIT_SCISSOR) | angle::Bit<size_t>(DIRTY_BIT_CULL_MODE) | 2693 angle::Bit<size_t>(DIRTY_BIT_FILL_MODE) | angle::Bit<size_t>(DIRTY_BIT_WINDING); 2694 2695 mDirtyBits &= ~kUnneededBits; 2696} 2697 2698angle::Result ContextMtl::handleDirtyRenderPass(const gl::Context *context) 2699{ 2700 if (!IsTransformFeedbackOnly(mState)) 2701 { 2702 // Start new render command encoder 2703 mtl::RenderCommandEncoder *encoder; 2704 ANGLE_TRY(mDrawFramebuffer->ensureRenderPassStarted(context, &encoder)); 2705 } 2706 else 2707 { 2708 // XFB is active and rasterization is disabled. Use dummy render target. 2709 // We currently need to end the render pass when XFB is activated/deactivated so using 2710 // a small dummy render target would make the render pass ending very cheap. 2711 if (!mDummyXFBRenderTexture) 2712 { 2713 ANGLE_TRY(mtl::Texture::Make2DTexture(this, 2714 getPixelFormat(angle::FormatID::R8G8B8A8_UNORM), 2715 1, 1, 1, true, false, &mDummyXFBRenderTexture)); 2716 } 2717 mtl::RenderCommandEncoder *encoder = getTextureRenderCommandEncoder( 2718 mDummyXFBRenderTexture, 2719 mtl::ImageNativeIndex::FromBaseZeroGLIndex(gl::ImageIndex::Make2D(0))); 2720 encoder->setColorLoadAction(MTLLoadActionDontCare, MTLClearColor(), 0); 2721 encoder->setColorStoreAction(MTLStoreActionDontCare); 2722 2723#ifndef NDEBUG 2724 encoder->setLabel(@"TransformFeedbackOnlyPass"); 2725#endif 2726 } 2727 2728 // re-apply everything 2729 invalidateState(context); 2730 2731 return angle::Result::Continue; 2732} 2733 2734angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context) 2735{ 2736 const gl::State &glState = mState; 2737 const gl::ProgramExecutable *executable = glState.getProgramExecutable(); 2738 2739 constexpr auto ensureTextureStorageCreated = [](const gl::Context *context, 2740 gl::Texture *texture) -> angle::Result { 2741 if (texture == nullptr) 2742 { 2743 return angle::Result::Continue; 2744 } 2745 2746 TextureMtl *textureMtl = mtl::GetImpl(texture); 2747 2748 // Make sure texture's image definitions will be transferred to GPU. 2749 ANGLE_TRY(textureMtl->ensureNativeStorageCreated(context)); 2750 2751 // The binding of this texture will be done by ProgramMtl. 2752 return angle::Result::Continue; 2753 }; 2754 2755 const gl::ActiveTexturesCache &textures = glState.getActiveTexturesCache(); 2756 const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask(); 2757 2758 for (size_t textureUnit : activeTextures) 2759 { 2760 ANGLE_TRY(ensureTextureStorageCreated(context, textures[textureUnit])); 2761 } 2762 2763 for (size_t imageUnit : executable->getActiveImagesMask()) 2764 { 2765 ANGLE_TRY( 2766 ensureTextureStorageCreated(context, glState.getImageUnit(imageUnit).texture.get())); 2767 } 2768 2769 return angle::Result::Continue; 2770} 2771 2772angle::Result ContextMtl::handleDirtyDefaultAttribs(const gl::Context *context) 2773{ 2774 for (size_t attribIndex : mDirtyDefaultAttribsMask) 2775 { 2776 ANGLE_TRY(updateDefaultAttribute(attribIndex)); 2777 } 2778 2779 ASSERT(mRenderEncoder.valid()); 2780 mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex); 2781 2782 mDirtyDefaultAttribsMask.reset(); 2783 return angle::Result::Continue; 2784} 2785 2786angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context, 2787 GLint drawCallFirstVertex, 2788 uint32_t verticesPerInstance) 2789{ 2790 mDriverUniforms.depthRange[0] = mState.getNearPlane(); 2791 mDriverUniforms.depthRange[1] = mState.getFarPlane(); 2792 2793 mDriverUniforms.renderArea = mDrawFramebuffer->getState().getDimensions().height << 16 | 2794 mDrawFramebuffer->getState().getDimensions().width; 2795 2796 const float flipX = 1.0; 2797 const float flipY = mDrawFramebuffer->flipY() ? -1.0f : 1.0f; 2798 mDriverUniforms.flipXY = gl::PackSnorm4x8( 2799 flipX, flipY, flipX, mState.getClipOrigin() == gl::ClipOrigin::LowerLeft ? -flipY : flipY); 2800 2801 // gl_ClipDistance 2802 const uint32_t enabledClipDistances = mState.getEnabledClipDistances().bits(); 2803 ASSERT((enabledClipDistances & ~sh::vk::kDriverUniformsMiscEnabledClipPlanesMask) == 0); 2804 2805 // GL_CLIP_DEPTH_MODE_EXT 2806 const uint32_t transformDepth = !mState.isClipDepthModeZeroToOne(); 2807 ASSERT((transformDepth & ~sh::vk::kDriverUniformsMiscTransformDepthMask) == 0); 2808 2809 // GL_SAMPLE_ALPHA_TO_COVERAGE 2810 const uint32_t alphaToCoverage = mState.isSampleAlphaToCoverageEnabled(); 2811 ASSERT((alphaToCoverage & ~sh::vk::kDriverUniformsMiscAlphaToCoverageMask) == 0); 2812 2813 mDriverUniforms.misc = 2814 (enabledClipDistances << sh::vk::kDriverUniformsMiscEnabledClipPlanesOffset) | 2815 (transformDepth << sh::vk::kDriverUniformsMiscTransformDepthOffset) | 2816 (alphaToCoverage << sh::vk::kDriverUniformsMiscAlphaToCoverageOffset); 2817 2818 // Sample coverage mask 2819 if (mState.isSampleCoverageEnabled()) 2820 { 2821 const uint32_t sampleBitCount = mDrawFramebuffer->getSamples(); 2822 ASSERT(sampleBitCount < 32); 2823 const uint32_t coverageSampleBitCount = 2824 static_cast<uint32_t>(std::round(mState.getSampleCoverageValue() * sampleBitCount)); 2825 uint32_t coverageMask = (1u << coverageSampleBitCount) - 1; 2826 if (mState.getSampleCoverageInvert()) 2827 { 2828 const uint32_t sampleMask = (1u << sampleBitCount) - 1; 2829 coverageMask = sampleMask & (~coverageMask); 2830 } 2831 mDriverUniforms.coverageMask = coverageMask; 2832 } 2833 else 2834 { 2835 mDriverUniforms.coverageMask = 0xFFFFFFFFu; 2836 } 2837 2838 // Sample mask 2839 if (mState.isSampleMaskEnabled()) 2840 { 2841 mDriverUniforms.coverageMask &= mState.getSampleMaskWord(0); 2842 } 2843 2844 ANGLE_TRY( 2845 fillDriverXFBUniforms(drawCallFirstVertex, verticesPerInstance, /** skippedInstances */ 0)); 2846 2847 ASSERT(mRenderEncoder.valid()); 2848 mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2849 mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 2850 2851 return angle::Result::Continue; 2852} 2853 2854angle::Result ContextMtl::fillDriverXFBUniforms(GLint drawCallFirstVertex, 2855 uint32_t verticesPerInstance, 2856 uint32_t skippedInstances) 2857{ 2858 gl::TransformFeedback *transformFeedback = getState().getCurrentTransformFeedback(); 2859 2860 bool xfbActiveUnpaused = getState().isTransformFeedbackActiveUnpaused(); 2861 if (!transformFeedback || !xfbActiveUnpaused) 2862 { 2863 return angle::Result::Continue; 2864 } 2865 2866 mDriverUniforms.xfbVerticesPerInstance = verticesPerInstance; 2867 2868 TransformFeedbackMtl *transformFeedbackMtl = mtl::GetImpl(transformFeedback); 2869 2870 return transformFeedbackMtl->getBufferOffsets(this, drawCallFirstVertex, 2871 verticesPerInstance * skippedInstances, 2872 mDriverUniforms.xfbBufferOffsets); 2873} 2874 2875angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context) 2876{ 2877 ASSERT(mRenderEncoder.valid()); 2878 2879 // Need to handle the case when render pass doesn't have depth/stencil attachment. 2880 mtl::DepthStencilDesc dsDesc = mDepthStencilDesc; 2881 const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc(); 2882 2883 if (!renderPassDesc.depthAttachment.texture) 2884 { 2885 dsDesc.depthWriteEnabled = false; 2886 dsDesc.depthCompareFunction = MTLCompareFunctionAlways; 2887 } 2888 2889 if (!renderPassDesc.stencilAttachment.texture) 2890 { 2891 dsDesc.frontFaceStencil.reset(); 2892 dsDesc.backFaceStencil.reset(); 2893 } 2894 2895 // Apply depth stencil state 2896 mRenderEncoder.setDepthStencilState( 2897 getDisplay()->getStateCache().getDepthStencilState(getMetalDevice(), dsDesc)); 2898 2899 return angle::Result::Continue; 2900} 2901 2902angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context) 2903{ 2904 const gl::RasterizerState &rasterState = mState.getRasterizerState(); 2905 ASSERT(mRenderEncoder.valid()); 2906 if (!mState.isPolygonOffsetEnabled()) 2907 { 2908 mRenderEncoder.setDepthBias(0, 0, 0); 2909 } 2910 else 2911 { 2912 mRenderEncoder.setDepthBias(rasterState.polygonOffsetUnits, rasterState.polygonOffsetFactor, 2913 rasterState.polygonOffsetClamp); 2914 } 2915 2916 return angle::Result::Continue; 2917} 2918 2919angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context, 2920 gl::PrimitiveMode primitiveMode, 2921 bool xfbPass, 2922 bool *isPipelineDescChanged) 2923{ 2924 ASSERT(mRenderEncoder.valid()); 2925 MTLPrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode); 2926 2927 bool rppChange = mDirtyBits.test(DIRTY_BIT_RENDER_PIPELINE) || 2928 topologyClass != mRenderPipelineDesc.inputPrimitiveTopology; 2929 2930 // Obtain RenderPipelineDesc's vertex array descriptor. 2931 ANGLE_TRY(mVertexArray->setupDraw(context, &mRenderEncoder, &rppChange, 2932 &mRenderPipelineDesc.vertexDescriptor)); 2933 2934 if (rppChange) 2935 { 2936 const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc(); 2937 // Obtain RenderPipelineDesc's output descriptor. 2938 renderPassDesc.populateRenderPipelineOutputDesc(mBlendDescArray, 2939 &mRenderPipelineDesc.outputDescriptor); 2940 2941 if (xfbPass) 2942 { 2943 // In XFB pass, we disable fragment shader. 2944 mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Disabled; 2945 } 2946 else if (mState.isRasterizerDiscardEnabled()) 2947 { 2948 // If XFB is not active and rasterizer discard is enabled, we need to emulate the 2949 // discard. Because in this case, vertex shader might write to stage output values and 2950 // Metal doesn't allow rasterization to be disabled. 2951 mRenderPipelineDesc.rasterizationType = 2952 mtl::RenderPipelineRasterization::EmulatedDiscard; 2953 } 2954 else 2955 { 2956 mRenderPipelineDesc.rasterizationType = mtl::RenderPipelineRasterization::Enabled; 2957 } 2958 mRenderPipelineDesc.inputPrimitiveTopology = topologyClass; 2959 mRenderPipelineDesc.alphaToCoverageEnabled = 2960 mState.isSampleAlphaToCoverageEnabled() && 2961 mRenderPipelineDesc.outputDescriptor.rasterSampleCount > 1 && 2962 !getDisplay()->getFeatures().emulateAlphaToCoverage.enabled; 2963 2964 mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers( 2965 mDrawFramebuffer->getState().getEnabledDrawBuffers()); 2966 } 2967 2968 *isPipelineDescChanged = rppChange; 2969 2970 return angle::Result::Continue; 2971} 2972 2973} // namespace rx 2974