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 14#include "common/debug.h" 15#include "libANGLE/renderer/metal/BufferMtl.h" 16#include "libANGLE/renderer/metal/CompilerMtl.h" 17#include "libANGLE/renderer/metal/DisplayMtl.h" 18#include "libANGLE/renderer/metal/FrameBufferMtl.h" 19#include "libANGLE/renderer/metal/ProgramMtl.h" 20#include "libANGLE/renderer/metal/RenderBufferMtl.h" 21#include "libANGLE/renderer/metal/ShaderMtl.h" 22#include "libANGLE/renderer/metal/TextureMtl.h" 23#include "libANGLE/renderer/metal/VertexArrayMtl.h" 24#include "libANGLE/renderer/metal/mtl_command_buffer.h" 25#include "libANGLE/renderer/metal/mtl_format_utils.h" 26#include "libANGLE/renderer/metal/mtl_utils.h" 27 28namespace rx 29{ 30 31namespace 32{ 33#if TARGET_OS_OSX 34// Unlimited triangle fan buffers 35constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 0; 36#else 37// Allow up to 10 buffers for trifan/line loop generation without stalling the GPU. 38constexpr uint32_t kMaxTriFanLineLoopBuffersPerFrame = 10; 39#endif 40 41angle::Result TriangleFanBoundCheck(ContextMtl *context, size_t numTris) 42{ 43 bool indexCheck = 44 (numTris > std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3)); 45 ANGLE_CHECK(context, !indexCheck, 46 "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, " 47 "too many indices required.", 48 GL_OUT_OF_MEMORY); 49 return angle::Result::Continue; 50} 51 52angle::Result GetTriangleFanIndicesCount(ContextMtl *context, 53 GLsizei vetexCount, 54 uint32_t *numElemsOut) 55{ 56 size_t numTris = vetexCount - 2; 57 ANGLE_TRY(TriangleFanBoundCheck(context, numTris)); 58 size_t numIndices = numTris * 3; 59 ANGLE_CHECK(context, numIndices <= std::numeric_limits<uint32_t>::max(), 60 "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, " 61 "too many indices required.", 62 GL_OUT_OF_MEMORY); 63 64 *numElemsOut = static_cast<uint32_t>(numIndices); 65 return angle::Result::Continue; 66} 67 68angle::Result AllocateTriangleFanBufferFromPool(ContextMtl *context, 69 GLsizei vertexCount, 70 mtl::BufferPool *pool, 71 mtl::BufferRef *bufferOut, 72 uint32_t *offsetOut, 73 uint32_t *numElemsOut) 74{ 75 uint32_t numIndices; 76 ANGLE_TRY(GetTriangleFanIndicesCount(context, vertexCount, &numIndices)); 77 78 size_t offset; 79 pool->releaseInFlightBuffers(context); 80 ANGLE_TRY(pool->allocate(context, numIndices * sizeof(uint32_t), nullptr, bufferOut, &offset, 81 nullptr)); 82 83 *offsetOut = static_cast<uint32_t>(offset); 84 *numElemsOut = numIndices; 85 86 return angle::Result::Continue; 87} 88 89bool NeedToInvertDepthRange(float near, float far) 90{ 91 return near > far; 92} 93} // namespace 94 95ContextMtl::ContextMtl(const gl::State &state, gl::ErrorSet *errorSet, DisplayMtl *display) 96 : ContextImpl(state, errorSet), 97 mtl::Context(display), 98 mCmdBuffer(&display->cmdQueue()), 99 mRenderEncoder(&mCmdBuffer), 100 mBlitEncoder(&mCmdBuffer), 101 mComputeEncoder(&mCmdBuffer) 102{} 103 104ContextMtl::~ContextMtl() {} 105 106angle::Result ContextMtl::initialize() 107{ 108 mBlendDesc.reset(); 109 mDepthStencilDesc.reset(); 110 111 mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment, 112 kMaxTriFanLineLoopBuffersPerFrame); 113 mLineLoopIndexBuffer.initialize(this, 0, 2 * sizeof(uint32_t), 114 kMaxTriFanLineLoopBuffersPerFrame); 115 mLineLoopIndexBuffer.setAlwaysAllocateNewBuffer(true); 116 117 return angle::Result::Continue; 118} 119 120void ContextMtl::onDestroy(const gl::Context *context) 121{ 122 mTriFanIndexBuffer.destroy(this); 123 mLineLoopIndexBuffer.destroy(this); 124 125 mIncompleteTextures.onDestroy(context); 126 mIncompleteTexturesInitialized = false; 127} 128 129angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *context) 130{ 131 if (ANGLE_LIKELY(mIncompleteTexturesInitialized)) 132 { 133 return angle::Result::Continue; 134 } 135 constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, 136 gl::TextureType::CubeMap}; 137 for (gl::TextureType texType : supportedTextureTypes) 138 { 139 gl::Texture *texture; 140 ANGLE_UNUSED_VARIABLE(texture); 141 ANGLE_TRY(mIncompleteTextures.getIncompleteTexture(context, texType, nullptr, &texture)); 142 } 143 mIncompleteTexturesInitialized = true; 144 145 return angle::Result::Continue; 146} 147 148// Flush and finish. 149angle::Result ContextMtl::flush(const gl::Context *context) 150{ 151 flushCommandBufer(); 152 return angle::Result::Continue; 153} 154angle::Result ContextMtl::finish(const gl::Context *context) 155{ 156 ANGLE_TRY(finishCommandBuffer()); 157 return angle::Result::Continue; 158} 159 160// Drawing methods. 161angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *context, 162 GLint first, 163 GLsizei count, 164 GLsizei instances) 165{ 166 uint32_t genIndicesCount; 167 ANGLE_TRY(GetTriangleFanIndicesCount(this, count, &genIndicesCount)); 168 169 size_t indexBufferSize = genIndicesCount * sizeof(uint32_t); 170 // We can reuse the previously generated index buffer if it has more than enough indices 171 // data already. 172 if (mTriFanArraysIndexBuffer == nullptr || mTriFanArraysIndexBuffer->size() < indexBufferSize) 173 { 174 // Re-generate a new index buffer, which the first index will be zero. 175 ANGLE_TRY( 176 mtl::Buffer::MakeBuffer(this, indexBufferSize, nullptr, &mTriFanArraysIndexBuffer)); 177 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( 178 this, {0, static_cast<uint32_t>(count), mTriFanArraysIndexBuffer, 0})); 179 } 180 181 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, 182 gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0))); 183 184 // Draw with the zero starting index buffer, shift the vertex index using baseVertex instanced 185 // draw: 186 mRenderEncoder.drawIndexedInstancedBaseVertex(MTLPrimitiveTypeTriangle, genIndicesCount, 187 MTLIndexTypeUInt32, mTriFanArraysIndexBuffer, 0, 188 instances, first); 189 190 return angle::Result::Continue; 191} 192angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context, 193 GLint first, 194 GLsizei count, 195 GLsizei instances) 196{ 197 // Legacy method is only used for GPU lacking instanced draw capabilities. 198 ASSERT(instances == 1); 199 200 mtl::BufferRef genIdxBuffer; 201 uint32_t genIdxBufferOffset; 202 uint32_t genIndicesCount; 203 ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, 204 &genIdxBufferOffset, &genIndicesCount)); 205 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromArrays( 206 this, {static_cast<uint32_t>(first), static_cast<uint32_t>(count), genIdxBuffer, 207 genIdxBufferOffset})); 208 209 ANGLE_TRY(setupDraw(context, gl::PrimitiveMode::TriangleFan, first, count, instances, 210 gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0))); 211 212 mRenderEncoder.drawIndexed(MTLPrimitiveTypeTriangle, genIndicesCount, MTLIndexTypeUInt32, 213 genIdxBuffer, genIdxBufferOffset); 214 215 return angle::Result::Continue; 216} 217angle::Result ContextMtl::drawTriFanArrays(const gl::Context *context, 218 GLint first, 219 GLsizei count, 220 GLsizei instances) 221{ 222 if (count <= 3) 223 { 224 return drawArraysInstanced(context, gl::PrimitiveMode::Triangles, first, count, instances); 225 } 226 if (getDisplay()->getFeatures().hasBaseVertexInstancedDraw.enabled) 227 { 228 return drawTriFanArraysWithBaseVertex(context, first, count, instances); 229 } 230 return drawTriFanArraysLegacy(context, first, count, instances); 231} 232 233angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, 234 gl::PrimitiveMode mode, 235 GLint first, 236 GLsizei count, 237 GLsizei instances) 238{ 239 // Real instances count. Zero means this is not instanced draw. 240 GLsizei instanceCount = instances ? instances : 1; 241 242 if (mCullAllPolygons && gl::IsPolygonMode(mode)) 243 { 244 return angle::Result::Continue; 245 } 246 247 if (mode == gl::PrimitiveMode::TriangleFan) 248 { 249 return drawTriFanArrays(context, first, count, instanceCount); 250 } 251 252 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); 253 254 ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum, 255 nullptr)); 256 257 if (instances == 0) 258 { 259 // This method is called from normal drawArrays() 260 mRenderEncoder.draw(mtlType, first, count); 261 } 262 else 263 { 264 mRenderEncoder.drawInstanced(mtlType, first, count, instanceCount); 265 } 266 267 return angle::Result::Continue; 268} 269 270angle::Result ContextMtl::drawArrays(const gl::Context *context, 271 gl::PrimitiveMode mode, 272 GLint first, 273 GLsizei count) 274{ 275 return drawArraysImpl(context, mode, first, count, 0); 276} 277 278angle::Result ContextMtl::drawArraysInstanced(const gl::Context *context, 279 gl::PrimitiveMode mode, 280 GLint first, 281 GLsizei count, 282 GLsizei instances) 283{ 284 if (instances == 0) 285 { 286 return angle::Result::Continue; 287 } 288 return drawArraysImpl(context, mode, first, count, instances); 289} 290 291angle::Result ContextMtl::drawArraysInstancedBaseInstance(const gl::Context *context, 292 gl::PrimitiveMode mode, 293 GLint first, 294 GLsizei count, 295 GLsizei instanceCount, 296 GLuint baseInstance) 297{ 298 UNIMPLEMENTED(); 299 return angle::Result::Stop; 300} 301 302angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, 303 GLsizei count, 304 gl::DrawElementsType type, 305 const void *indices, 306 GLsizei instances) 307{ 308 if (count > 3) 309 { 310 mtl::BufferRef genIdxBuffer; 311 uint32_t genIdxBufferOffset; 312 uint32_t genIndicesCount; 313 ANGLE_TRY(AllocateTriangleFanBufferFromPool(this, count, &mTriFanIndexBuffer, &genIdxBuffer, 314 &genIdxBufferOffset, &genIndicesCount)); 315 316 ANGLE_TRY(getDisplay()->getUtils().generateTriFanBufferFromElementsArray( 317 this, {type, count, indices, genIdxBuffer, genIdxBufferOffset})); 318 319 ANGLE_TRY(mTriFanIndexBuffer.commit(this)); 320 321 ANGLE_TRY( 322 setupDraw(context, gl::PrimitiveMode::TriangleFan, 0, count, instances, type, indices)); 323 324 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeTriangle, genIndicesCount, 325 MTLIndexTypeUInt32, genIdxBuffer, genIdxBufferOffset, 326 instances); 327 328 return angle::Result::Continue; 329 } // if (count > 3) 330 return drawElementsInstanced(context, gl::PrimitiveMode::Triangles, count, type, indices, 331 instances); 332} 333 334angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, 335 gl::PrimitiveMode mode, 336 GLsizei count, 337 gl::DrawElementsType type, 338 const void *indices, 339 GLsizei instances) 340{ 341 // Real instances count. Zero means this is not instanced draw. 342 GLsizei instanceCount = instances ? instances : 1; 343 344 if (mCullAllPolygons && gl::IsPolygonMode(mode)) 345 { 346 return angle::Result::Continue; 347 } 348 349 if (mode == gl::PrimitiveMode::TriangleFan) 350 { 351 return drawTriFanElements(context, count, type, indices, instanceCount); 352 } 353 354 mtl::BufferRef idxBuffer; 355 size_t convertedOffset = 0; 356 gl::DrawElementsType convertedType = type; 357 358 ANGLE_TRY(mVertexArray->getIndexBuffer(context, type, count, indices, &idxBuffer, 359 &convertedOffset, &convertedType)); 360 361 ASSERT(idxBuffer); 362 ASSERT((convertedOffset % mtl::kIndexBufferOffsetAlignment) == 0); 363 364 ANGLE_TRY(setupDraw(context, mode, 0, count, instances, type, indices)); 365 366 MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); 367 368 MTLIndexType mtlIdxType = mtl::GetIndexType(convertedType); 369 370 if (instances == 0) 371 { 372 // Normal draw 373 mRenderEncoder.drawIndexed(mtlType, count, mtlIdxType, idxBuffer, convertedOffset); 374 } 375 else 376 { 377 // Instanced draw 378 mRenderEncoder.drawIndexedInstanced(mtlType, count, mtlIdxType, idxBuffer, convertedOffset, 379 instanceCount); 380 } 381 382 return angle::Result::Continue; 383} 384 385angle::Result ContextMtl::drawElements(const gl::Context *context, 386 gl::PrimitiveMode mode, 387 GLsizei count, 388 gl::DrawElementsType type, 389 const void *indices) 390{ 391 return drawElementsImpl(context, mode, count, type, indices, 0); 392} 393 394angle::Result ContextMtl::drawElementsBaseVertex(const gl::Context *context, 395 gl::PrimitiveMode mode, 396 GLsizei count, 397 gl::DrawElementsType type, 398 const void *indices, 399 GLint baseVertex) 400{ 401 // NOTE(hqle): ES 3.2 402 UNIMPLEMENTED(); 403 return angle::Result::Stop; 404} 405 406angle::Result ContextMtl::drawElementsInstanced(const gl::Context *context, 407 gl::PrimitiveMode mode, 408 GLsizei count, 409 gl::DrawElementsType type, 410 const void *indices, 411 GLsizei instanceCount) 412{ 413 if (instanceCount == 0) 414 { 415 return angle::Result::Continue; 416 } 417 return drawElementsImpl(context, mode, count, type, indices, instanceCount); 418} 419 420angle::Result ContextMtl::drawElementsInstancedBaseVertex(const gl::Context *context, 421 gl::PrimitiveMode mode, 422 GLsizei count, 423 gl::DrawElementsType type, 424 const void *indices, 425 GLsizei instanceCount, 426 GLint baseVertex) 427{ 428 // NOTE(hqle): ES 3.2 429 UNIMPLEMENTED(); 430 return angle::Result::Stop; 431} 432 433angle::Result ContextMtl::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context, 434 gl::PrimitiveMode mode, 435 GLsizei count, 436 gl::DrawElementsType type, 437 const void *indices, 438 GLsizei instances, 439 GLint baseVertex, 440 GLuint baseInstance) 441{ 442 UNIMPLEMENTED(); 443 return angle::Result::Stop; 444} 445 446angle::Result ContextMtl::drawRangeElements(const gl::Context *context, 447 gl::PrimitiveMode mode, 448 GLuint start, 449 GLuint end, 450 GLsizei count, 451 gl::DrawElementsType type, 452 const void *indices) 453{ 454 // NOTE(hqle): ES 3.0 455 UNIMPLEMENTED(); 456 return angle::Result::Stop; 457} 458 459angle::Result ContextMtl::drawRangeElementsBaseVertex(const gl::Context *context, 460 gl::PrimitiveMode mode, 461 GLuint start, 462 GLuint end, 463 GLsizei count, 464 gl::DrawElementsType type, 465 const void *indices, 466 GLint baseVertex) 467{ 468 // NOTE(hqle): ES 3.2 469 UNIMPLEMENTED(); 470 return angle::Result::Stop; 471} 472 473angle::Result ContextMtl::drawArraysIndirect(const gl::Context *context, 474 gl::PrimitiveMode mode, 475 const void *indirect) 476{ 477 // NOTE(hqle): ES 3.0 478 UNIMPLEMENTED(); 479 return angle::Result::Stop; 480} 481angle::Result ContextMtl::drawElementsIndirect(const gl::Context *context, 482 gl::PrimitiveMode mode, 483 gl::DrawElementsType type, 484 const void *indirect) 485{ 486 // NOTE(hqle): ES 3.0 487 UNIMPLEMENTED(); 488 return angle::Result::Stop; 489} 490 491// Device loss 492gl::GraphicsResetStatus ContextMtl::getResetStatus() 493{ 494 return gl::GraphicsResetStatus::NoError; 495} 496 497// Vendor and description strings. 498std::string ContextMtl::getVendorString() const 499{ 500 return getDisplay()->getVendorString(); 501} 502std::string ContextMtl::getRendererDescription() const 503{ 504 return getDisplay()->getRendererDescription(); 505} 506 507// EXT_debug_marker 508angle::Result ContextMtl::insertEventMarker(GLsizei length, const char *marker) 509{ 510 return angle::Result::Continue; 511} 512 513angle::Result ContextMtl::pushGroupMarker(GLsizei length, const char *marker) 514{ 515 return angle::Result::Continue; 516} 517 518angle::Result ContextMtl::popGroupMarker() 519{ 520 return angle::Result::Continue; 521} 522 523// KHR_debug 524angle::Result ContextMtl::pushDebugGroup(const gl::Context *context, 525 GLenum source, 526 GLuint id, 527 const std::string &message) 528{ 529 return angle::Result::Continue; 530} 531 532angle::Result ContextMtl::popDebugGroup(const gl::Context *context) 533{ 534 return angle::Result::Continue; 535} 536 537// State sync with dirty bits. 538angle::Result ContextMtl::syncState(const gl::Context *context, 539 const gl::State::DirtyBits &dirtyBits, 540 const gl::State::DirtyBits &bitMask) 541{ 542 const gl::State &glState = context->getState(); 543 544 // Initialize incomplete texture set. 545 ANGLE_TRY(ensureIncompleteTexturesCreated(context)); 546 547 for (size_t dirtyBit : dirtyBits) 548 { 549 switch (dirtyBit) 550 { 551 case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED: 552 case gl::State::DIRTY_BIT_SCISSOR: 553 updateScissor(glState); 554 break; 555 case gl::State::DIRTY_BIT_VIEWPORT: 556 { 557 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 558 updateViewport(framebufferMtl, glState.getViewport(), glState.getNearPlane(), 559 glState.getFarPlane()); 560 // Update the scissor, which will be constrained to the viewport 561 updateScissor(glState); 562 break; 563 } 564 case gl::State::DIRTY_BIT_DEPTH_RANGE: 565 updateDepthRange(glState.getNearPlane(), glState.getFarPlane()); 566 break; 567 case gl::State::DIRTY_BIT_BLEND_COLOR: 568 mDirtyBits.set(DIRTY_BIT_BLEND_COLOR); 569 break; 570 case gl::State::DIRTY_BIT_BLEND_ENABLED: 571 mBlendDesc.updateBlendEnabled(glState.getBlendState()); 572 invalidateRenderPipeline(); 573 break; 574 case gl::State::DIRTY_BIT_BLEND_FUNCS: 575 mBlendDesc.updateBlendFactors(glState.getBlendState()); 576 invalidateRenderPipeline(); 577 break; 578 case gl::State::DIRTY_BIT_BLEND_EQUATIONS: 579 mBlendDesc.updateBlendOps(glState.getBlendState()); 580 invalidateRenderPipeline(); 581 break; 582 case gl::State::DIRTY_BIT_COLOR_MASK: 583 mBlendDesc.updateWriteMask(glState.getBlendState()); 584 invalidateRenderPipeline(); 585 break; 586 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: 587 // NOTE(hqle): MSAA support 588 break; 589 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE_ENABLED: 590 // NOTE(hqle): MSAA support 591 break; 592 case gl::State::DIRTY_BIT_SAMPLE_COVERAGE: 593 // NOTE(hqle): MSAA support 594 break; 595 case gl::State::DIRTY_BIT_SAMPLE_MASK_ENABLED: 596 // NOTE(hqle): MSAA support 597 break; 598 case gl::State::DIRTY_BIT_SAMPLE_MASK: 599 // NOTE(hqle): MSAA support 600 break; 601 case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED: 602 mDepthStencilDesc.updateDepthTestEnabled(glState.getDepthStencilState()); 603 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 604 break; 605 case gl::State::DIRTY_BIT_DEPTH_FUNC: 606 mDepthStencilDesc.updateDepthCompareFunc(glState.getDepthStencilState()); 607 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 608 break; 609 case gl::State::DIRTY_BIT_DEPTH_MASK: 610 mDepthStencilDesc.updateDepthWriteEnabled(glState.getDepthStencilState()); 611 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 612 break; 613 case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED: 614 mDepthStencilDesc.updateStencilTestEnabled(glState.getDepthStencilState()); 615 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 616 break; 617 case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT: 618 mDepthStencilDesc.updateStencilFrontFuncs(glState.getDepthStencilState()); 619 mStencilRefFront = 620 gl::clamp<int, int, int>(glState.getStencilRef(), 0, mtl::kStencilMaskAll); 621 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 622 mDirtyBits.set(DIRTY_BIT_STENCIL_REF); 623 break; 624 case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK: 625 mDepthStencilDesc.updateStencilBackFuncs(glState.getDepthStencilState()); 626 mStencilRefBack = 627 gl::clamp<int, int, int>(glState.getStencilBackRef(), 0, mtl::kStencilMaskAll); 628 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 629 mDirtyBits.set(DIRTY_BIT_STENCIL_REF); 630 break; 631 case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT: 632 mDepthStencilDesc.updateStencilFrontOps(glState.getDepthStencilState()); 633 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 634 break; 635 case gl::State::DIRTY_BIT_STENCIL_OPS_BACK: 636 mDepthStencilDesc.updateStencilBackOps(glState.getDepthStencilState()); 637 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 638 break; 639 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT: 640 mDepthStencilDesc.updateStencilFrontWriteMask(glState.getDepthStencilState()); 641 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 642 break; 643 case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK: 644 mDepthStencilDesc.updateStencilBackWriteMask(glState.getDepthStencilState()); 645 mDirtyBits.set(DIRTY_BIT_DEPTH_STENCIL_DESC); 646 break; 647 case gl::State::DIRTY_BIT_CULL_FACE_ENABLED: 648 case gl::State::DIRTY_BIT_CULL_FACE: 649 updateCullMode(glState); 650 break; 651 case gl::State::DIRTY_BIT_FRONT_FACE: 652 updateFrontFace(glState); 653 break; 654 case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED: 655 case gl::State::DIRTY_BIT_POLYGON_OFFSET: 656 updateDepthBias(glState); 657 break; 658 case gl::State::DIRTY_BIT_RASTERIZER_DISCARD_ENABLED: 659 // NOTE(hqle): ES 3.0 feature. 660 break; 661 case gl::State::DIRTY_BIT_LINE_WIDTH: 662 // Do nothing 663 break; 664 case gl::State::DIRTY_BIT_PRIMITIVE_RESTART_ENABLED: 665 // NOTE(hqle): ES 3.0 feature. 666 break; 667 case gl::State::DIRTY_BIT_CLEAR_COLOR: 668 mClearColor.red = glState.getColorClearValue().red; 669 mClearColor.green = glState.getColorClearValue().green; 670 mClearColor.blue = glState.getColorClearValue().blue; 671 mClearColor.alpha = glState.getColorClearValue().alpha; 672 break; 673 case gl::State::DIRTY_BIT_CLEAR_DEPTH: 674 break; 675 case gl::State::DIRTY_BIT_CLEAR_STENCIL: 676 mClearStencil = glState.getStencilClearValue() & mtl::kStencilMaskAll; 677 break; 678 case gl::State::DIRTY_BIT_UNPACK_STATE: 679 // This is a no-op, its only important to use the right unpack state when we do 680 // setImage or setSubImage in TextureMtl, which is plumbed through the frontend call 681 break; 682 case gl::State::DIRTY_BIT_UNPACK_BUFFER_BINDING: 683 break; 684 case gl::State::DIRTY_BIT_PACK_STATE: 685 // This is a no-op, its only important to use the right pack state when we do 686 // call readPixels later on. 687 break; 688 case gl::State::DIRTY_BIT_PACK_BUFFER_BINDING: 689 break; 690 case gl::State::DIRTY_BIT_DITHER_ENABLED: 691 break; 692 case gl::State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING: 693 break; 694 case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING: 695 updateDrawFrameBufferBinding(context); 696 break; 697 case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING: 698 break; 699 case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING: 700 updateVertexArray(context); 701 break; 702 case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING: 703 break; 704 case gl::State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING: 705 break; 706 case gl::State::DIRTY_BIT_PROGRAM_BINDING: 707 mProgram = mtl::GetImpl(glState.getProgram()); 708 break; 709 case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE: 710 updateProgramExecutable(context); 711 break; 712 case gl::State::DIRTY_BIT_TEXTURE_BINDINGS: 713 invalidateCurrentTextures(); 714 break; 715 case gl::State::DIRTY_BIT_SAMPLER_BINDINGS: 716 invalidateCurrentTextures(); 717 break; 718 case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING: 719 // Nothing to do. 720 break; 721 case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING: 722 // NOTE(hqle): ES 3.0 feature. 723 break; 724 case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS: 725 // NOTE(hqle): ES 3.0 feature. 726 break; 727 case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING: 728 break; 729 case gl::State::DIRTY_BIT_IMAGE_BINDINGS: 730 // NOTE(hqle): properly handle GLSL images. 731 invalidateCurrentTextures(); 732 break; 733 case gl::State::DIRTY_BIT_MULTISAMPLING: 734 // NOTE(hqle): MSAA feature. 735 break; 736 case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_ONE: 737 // NOTE(hqle): this is part of EXT_multisample_compatibility. 738 // NOTE(hqle): MSAA feature. 739 break; 740 case gl::State::DIRTY_BIT_COVERAGE_MODULATION: 741 break; 742 case gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB: 743 break; 744 case gl::State::DIRTY_BIT_CURRENT_VALUES: 745 { 746 invalidateDefaultAttributes(glState.getAndResetDirtyCurrentValues()); 747 break; 748 } 749 case gl::State::DIRTY_BIT_PROVOKING_VERTEX: 750 break; 751 case gl::State::DIRTY_BIT_EXTENDED: 752 updateExtendedState(glState); 753 break; 754 default: 755 UNREACHABLE(); 756 break; 757 } 758 } 759 760 return angle::Result::Continue; 761} 762 763void ContextMtl::updateExtendedState(const gl::State &glState) 764{ 765 // Handling clip distance enabled flags, mipmap generation hint & shader derivative 766 // hint. 767 invalidateDriverUniforms(); 768} 769 770// Disjoint timer queries 771GLint ContextMtl::getGPUDisjoint() 772{ 773 UNIMPLEMENTED(); 774 return 0; 775} 776GLint64 ContextMtl::getTimestamp() 777{ 778 UNIMPLEMENTED(); 779 return 0; 780} 781 782// Context switching 783angle::Result ContextMtl::onMakeCurrent(const gl::Context *context) 784{ 785 invalidateState(context); 786 return angle::Result::Continue; 787} 788angle::Result ContextMtl::onUnMakeCurrent(const gl::Context *context) 789{ 790 flushCommandBufer(); 791 return angle::Result::Continue; 792} 793 794// Native capabilities, unmodified by gl::Context. 795gl::Caps ContextMtl::getNativeCaps() const 796{ 797 return getDisplay()->getNativeCaps(); 798} 799const gl::TextureCapsMap &ContextMtl::getNativeTextureCaps() const 800{ 801 return getDisplay()->getNativeTextureCaps(); 802} 803const gl::Extensions &ContextMtl::getNativeExtensions() const 804{ 805 return getDisplay()->getNativeExtensions(); 806} 807const gl::Limitations &ContextMtl::getNativeLimitations() const 808{ 809 return getDisplay()->getNativeLimitations(); 810} 811 812// Shader creation 813CompilerImpl *ContextMtl::createCompiler() 814{ 815 return new CompilerMtl(); 816} 817ShaderImpl *ContextMtl::createShader(const gl::ShaderState &state) 818{ 819 return new ShaderMtl(state); 820} 821ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state) 822{ 823 return new ProgramMtl(state); 824} 825 826// Framebuffer creation 827FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state) 828{ 829 return new FramebufferMtl(state, false); 830} 831 832// Texture creation 833TextureImpl *ContextMtl::createTexture(const gl::TextureState &state) 834{ 835 return new TextureMtl(state); 836} 837 838// Renderbuffer creation 839RenderbufferImpl *ContextMtl::createRenderbuffer(const gl::RenderbufferState &state) 840{ 841 return new RenderbufferMtl(state); 842} 843 844// Buffer creation 845BufferImpl *ContextMtl::createBuffer(const gl::BufferState &state) 846{ 847 return new BufferMtl(state); 848} 849 850// Vertex Array creation 851VertexArrayImpl *ContextMtl::createVertexArray(const gl::VertexArrayState &state) 852{ 853 return new VertexArrayMtl(state, this); 854} 855 856// Query and Fence creation 857QueryImpl *ContextMtl::createQuery(gl::QueryType type) 858{ 859 // NOTE(hqle): ES 3.0 860 UNIMPLEMENTED(); 861 return nullptr; 862} 863FenceNVImpl *ContextMtl::createFenceNV() 864{ 865 UNIMPLEMENTED(); 866 return nullptr; 867} 868SyncImpl *ContextMtl::createSync() 869{ 870 UNIMPLEMENTED(); 871 return nullptr; 872} 873 874// Transform Feedback creation 875TransformFeedbackImpl *ContextMtl::createTransformFeedback(const gl::TransformFeedbackState &state) 876{ 877 // NOTE(hqle): ES 3.0 878 UNIMPLEMENTED(); 879 return nullptr; 880} 881 882// Sampler object creation 883SamplerImpl *ContextMtl::createSampler(const gl::SamplerState &state) 884{ 885 // NOTE(hqle): ES 3.0 886 UNIMPLEMENTED(); 887 return nullptr; 888} 889 890// Program Pipeline object creation 891ProgramPipelineImpl *ContextMtl::createProgramPipeline(const gl::ProgramPipelineState &data) 892{ 893 // NOTE(hqle): ES 3.0 894 UNIMPLEMENTED(); 895 return nullptr; 896} 897 898// Memory object creation. 899MemoryObjectImpl *ContextMtl::createMemoryObject() 900{ 901 UNIMPLEMENTED(); 902 return nullptr; 903} 904 905// Semaphore creation. 906SemaphoreImpl *ContextMtl::createSemaphore() 907{ 908 UNIMPLEMENTED(); 909 return nullptr; 910} 911 912OverlayImpl *ContextMtl::createOverlay(const gl::OverlayState &state) 913{ 914 UNIMPLEMENTED(); 915 return nullptr; 916} 917 918angle::Result ContextMtl::dispatchCompute(const gl::Context *context, 919 GLuint numGroupsX, 920 GLuint numGroupsY, 921 GLuint numGroupsZ) 922{ 923 // NOTE(hqle): ES 3.0 924 UNIMPLEMENTED(); 925 return angle::Result::Stop; 926} 927angle::Result ContextMtl::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect) 928{ 929 // NOTE(hqle): ES 3.0 930 UNIMPLEMENTED(); 931 return angle::Result::Stop; 932} 933 934angle::Result ContextMtl::memoryBarrier(const gl::Context *context, GLbitfield barriers) 935{ 936 // NOTE(hqle): ES 3.0 937 UNIMPLEMENTED(); 938 return angle::Result::Stop; 939} 940angle::Result ContextMtl::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) 941{ 942 // NOTE(hqle): ES 3.0 943 UNIMPLEMENTED(); 944 return angle::Result::Stop; 945} 946 947// override mtl::ErrorHandler 948void ContextMtl::handleError(GLenum glErrorCode, 949 const char *file, 950 const char *function, 951 unsigned int line) 952{ 953 std::stringstream errorStream; 954 errorStream << "Metal backend encountered an error. Code=" << glErrorCode << "."; 955 956 mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line); 957} 958 959void ContextMtl::handleError(NSError *nserror, 960 const char *file, 961 const char *function, 962 unsigned int line) 963{ 964 if (!nserror) 965 { 966 return; 967 } 968 969 std::stringstream errorStream; 970 errorStream << "Metal backend encountered an error: \n" 971 << nserror.localizedDescription.UTF8String; 972 973 mErrors->handleError(GL_INVALID_OPERATION, errorStream.str().c_str(), file, function, line); 974} 975 976void ContextMtl::invalidateState(const gl::Context *context) 977{ 978 mDirtyBits.set(); 979 980 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 981} 982 983void ContextMtl::invalidateDefaultAttribute(size_t attribIndex) 984{ 985 mDirtyDefaultAttribsMask.set(attribIndex); 986 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 987} 988 989void ContextMtl::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask) 990{ 991 if (dirtyMask.any()) 992 { 993 mDirtyDefaultAttribsMask |= dirtyMask; 994 mDirtyBits.set(DIRTY_BIT_DEFAULT_ATTRIBS); 995 } 996} 997 998void ContextMtl::invalidateCurrentTextures() 999{ 1000 mDirtyBits.set(DIRTY_BIT_TEXTURES); 1001} 1002 1003void ContextMtl::invalidateDriverUniforms() 1004{ 1005 mDirtyBits.set(DIRTY_BIT_DRIVER_UNIFORMS); 1006} 1007 1008void ContextMtl::invalidateRenderPipeline() 1009{ 1010 mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE); 1011} 1012 1013const MTLClearColor &ContextMtl::getClearColorValue() const 1014{ 1015 return mClearColor; 1016} 1017MTLColorWriteMask ContextMtl::getColorMask() const 1018{ 1019 return mBlendDesc.writeMask; 1020} 1021float ContextMtl::getClearDepthValue() const 1022{ 1023 return getState().getDepthClearValue(); 1024} 1025uint32_t ContextMtl::getClearStencilValue() const 1026{ 1027 return mClearStencil; 1028} 1029uint32_t ContextMtl::getStencilMask() const 1030{ 1031 return getState().getDepthStencilState().stencilWritemask & mtl::kStencilMaskAll; 1032} 1033 1034bool ContextMtl::getDepthMask() const 1035{ 1036 return getState().getDepthStencilState().depthMask; 1037} 1038 1039const mtl::Format &ContextMtl::getPixelFormat(angle::FormatID angleFormatId) const 1040{ 1041 return getDisplay()->getPixelFormat(angleFormatId); 1042} 1043 1044// See mtl::FormatTable::getVertexFormat() 1045const mtl::VertexFormat &ContextMtl::getVertexFormat(angle::FormatID angleFormatId, 1046 bool tightlyPacked) const 1047{ 1048 return getDisplay()->getVertexFormat(angleFormatId, tightlyPacked); 1049} 1050 1051angle::Result ContextMtl::getIncompleteTexture(const gl::Context *context, 1052 gl::TextureType type, 1053 gl::Texture **textureOut) 1054{ 1055 return mIncompleteTextures.getIncompleteTexture(context, type, nullptr, textureOut); 1056} 1057 1058void ContextMtl::endEncoding(mtl::RenderCommandEncoder *encoder) 1059{ 1060 encoder->endEncoding(); 1061} 1062 1063void ContextMtl::endEncoding(bool forceSaveRenderPassContent) 1064{ 1065 if (mRenderEncoder.valid()) 1066 { 1067 if (forceSaveRenderPassContent) 1068 { 1069 // Save the work in progress. 1070 mRenderEncoder.setColorStoreAction(MTLStoreActionStore); 1071 mRenderEncoder.setDepthStencilStoreAction(MTLStoreActionStore, MTLStoreActionStore); 1072 } 1073 1074 mRenderEncoder.endEncoding(); 1075 } 1076 1077 if (mBlitEncoder.valid()) 1078 { 1079 mBlitEncoder.endEncoding(); 1080 } 1081 1082 if (mComputeEncoder.valid()) 1083 { 1084 mComputeEncoder.endEncoding(); 1085 } 1086} 1087 1088void ContextMtl::flushCommandBufer() 1089{ 1090 if (!mCmdBuffer.valid()) 1091 { 1092 return; 1093 } 1094 1095 endEncoding(true); 1096 mCmdBuffer.commit(); 1097} 1098 1099void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable) 1100{ 1101 ensureCommandBufferValid(); 1102 1103 // Always discard default FBO's depth stencil buffers at the end of the frame: 1104 if (mDrawFramebufferIsDefault && hasStartedRenderPass(mDrawFramebuffer)) 1105 { 1106 constexpr GLenum dsAttachments[] = {GL_DEPTH, GL_STENCIL}; 1107 (void)mDrawFramebuffer->invalidate(context, 2, dsAttachments); 1108 1109 endEncoding(false); 1110 1111 // Reset discard flag by notify framebuffer that a new render pass has started. 1112 mDrawFramebuffer->onStartedDrawingToFrameBuffer(context); 1113 } 1114 1115 endEncoding(false); 1116 mCmdBuffer.present(presentationDrawable); 1117 mCmdBuffer.commit(); 1118} 1119 1120angle::Result ContextMtl::finishCommandBuffer() 1121{ 1122 flushCommandBufer(); 1123 1124 if (mCmdBuffer.valid()) 1125 { 1126 mCmdBuffer.finish(); 1127 } 1128 1129 return angle::Result::Continue; 1130} 1131 1132bool ContextMtl::hasStartedRenderPass(const mtl::RenderPassDesc &desc) 1133{ 1134 return mRenderEncoder.valid() && 1135 mRenderEncoder.renderPassDesc().equalIgnoreLoadStoreOptions(desc); 1136} 1137 1138bool ContextMtl::hasStartedRenderPass(FramebufferMtl *framebuffer) 1139{ 1140 return framebuffer && hasStartedRenderPass(framebuffer->getRenderPassDesc(this)); 1141} 1142 1143// Get current render encoder 1144mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder() 1145{ 1146 if (!mRenderEncoder.valid()) 1147 { 1148 return nullptr; 1149 } 1150 1151 return &mRenderEncoder; 1152} 1153 1154mtl::RenderCommandEncoder *ContextMtl::getCurrentFramebufferRenderCommandEncoder() 1155{ 1156 if (!mDrawFramebuffer) 1157 { 1158 return nullptr; 1159 } 1160 1161 return getRenderCommandEncoder(mDrawFramebuffer->getRenderPassDesc(this)); 1162} 1163 1164mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::RenderPassDesc &desc) 1165{ 1166 if (hasStartedRenderPass(desc)) 1167 { 1168 return &mRenderEncoder; 1169 } 1170 1171 endEncoding(false); 1172 1173 ensureCommandBufferValid(); 1174 1175 // Need to re-apply everything on next draw call. 1176 mDirtyBits.set(); 1177 1178 return &mRenderEncoder.restart(desc); 1179} 1180 1181// Utilities to quickly create render command enconder to a specific texture: 1182// The previous content of texture will be loaded if clearColor is not provided 1183mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder( 1184 const mtl::TextureRef &textureTarget, 1185 const gl::ImageIndex &index, 1186 const Optional<MTLClearColor> &clearColor) 1187{ 1188 ASSERT(textureTarget && textureTarget->valid()); 1189 1190 mtl::RenderPassDesc rpDesc; 1191 1192 rpDesc.colorAttachments[0].texture = textureTarget; 1193 rpDesc.colorAttachments[0].level = index.getLevelIndex(); 1194 rpDesc.colorAttachments[0].slice = index.hasLayer() ? index.getLayerIndex() : 0; 1195 rpDesc.numColorAttachments = 1; 1196 1197 if (clearColor.valid()) 1198 { 1199 rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear; 1200 rpDesc.colorAttachments[0].clearColor = 1201 mtl::EmulatedAlphaClearColor(clearColor.value(), textureTarget->getColorWritableMask()); 1202 } 1203 1204 return getRenderCommandEncoder(rpDesc); 1205} 1206// The previous content of texture will be loaded 1207mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::TextureRef &textureTarget, 1208 const gl::ImageIndex &index) 1209{ 1210 return getRenderCommandEncoder(textureTarget, index, Optional<MTLClearColor>()); 1211} 1212 1213mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder() 1214{ 1215 if (mBlitEncoder.valid()) 1216 { 1217 return &mBlitEncoder; 1218 } 1219 1220 endEncoding(true); 1221 1222 ensureCommandBufferValid(); 1223 1224 return &mBlitEncoder.restart(); 1225} 1226 1227mtl::ComputeCommandEncoder *ContextMtl::getComputeCommandEncoder() 1228{ 1229 if (mComputeEncoder.valid()) 1230 { 1231 return &mComputeEncoder; 1232 } 1233 1234 endEncoding(true); 1235 1236 ensureCommandBufferValid(); 1237 1238 return &mComputeEncoder.restart(); 1239} 1240 1241void ContextMtl::ensureCommandBufferValid() 1242{ 1243 if (!mCmdBuffer.valid()) 1244 { 1245 mCmdBuffer.restart(); 1246 } 1247 1248 ASSERT(mCmdBuffer.valid()); 1249} 1250 1251void ContextMtl::updateViewport(FramebufferMtl *framebufferMtl, 1252 const gl::Rectangle &viewport, 1253 float nearPlane, 1254 float farPlane) 1255{ 1256 mViewport = mtl::GetViewport(viewport, framebufferMtl->getState().getDimensions().height, 1257 framebufferMtl->flipY(), nearPlane, farPlane); 1258 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 1259 1260 invalidateDriverUniforms(); 1261} 1262 1263void ContextMtl::updateDepthRange(float nearPlane, float farPlane) 1264{ 1265 if (NeedToInvertDepthRange(nearPlane, farPlane)) 1266 { 1267 // We also need to invert the depth in shader later by using scale value stored in driver 1268 // uniform depthRange.reserved 1269 std::swap(nearPlane, farPlane); 1270 } 1271 mViewport.znear = nearPlane; 1272 mViewport.zfar = farPlane; 1273 mDirtyBits.set(DIRTY_BIT_VIEWPORT); 1274 1275 invalidateDriverUniforms(); 1276} 1277 1278void ContextMtl::updateScissor(const gl::State &glState) 1279{ 1280 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 1281 gl::Rectangle renderArea = framebufferMtl->getCompleteRenderArea(); 1282 1283 ANGLE_MTL_LOG("renderArea = %d,%d,%d,%d", renderArea.x, renderArea.y, renderArea.width, 1284 renderArea.height); 1285 1286 // Clip the render area to the viewport. 1287 gl::Rectangle viewportClippedRenderArea; 1288 gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea); 1289 1290 gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false); 1291 if (framebufferMtl->flipY()) 1292 { 1293 scissoredArea.y = renderArea.height - scissoredArea.y - scissoredArea.height; 1294 } 1295 1296 ANGLE_MTL_LOG("scissoredArea = %d,%d,%d,%d", scissoredArea.x, scissoredArea.y, 1297 scissoredArea.width, scissoredArea.height); 1298 1299 mScissorRect = mtl::GetScissorRect(scissoredArea); 1300 mDirtyBits.set(DIRTY_BIT_SCISSOR); 1301} 1302 1303void ContextMtl::updateCullMode(const gl::State &glState) 1304{ 1305 const gl::RasterizerState &rasterState = glState.getRasterizerState(); 1306 1307 mCullAllPolygons = false; 1308 if (!rasterState.cullFace) 1309 { 1310 mCullMode = MTLCullModeNone; 1311 } 1312 else 1313 { 1314 switch (rasterState.cullMode) 1315 { 1316 case gl::CullFaceMode::Back: 1317 mCullMode = MTLCullModeBack; 1318 break; 1319 case gl::CullFaceMode::Front: 1320 mCullMode = MTLCullModeFront; 1321 break; 1322 case gl::CullFaceMode::FrontAndBack: 1323 mCullAllPolygons = true; 1324 break; 1325 default: 1326 UNREACHABLE(); 1327 break; 1328 } 1329 } 1330 1331 mDirtyBits.set(DIRTY_BIT_CULL_MODE); 1332} 1333 1334void ContextMtl::updateFrontFace(const gl::State &glState) 1335{ 1336 FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer()); 1337 mWinding = 1338 mtl::GetFontfaceWinding(glState.getRasterizerState().frontFace, !framebufferMtl->flipY()); 1339 mDirtyBits.set(DIRTY_BIT_WINDING); 1340} 1341 1342void ContextMtl::updateDepthBias(const gl::State &glState) 1343{ 1344 mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); 1345} 1346 1347void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context) 1348{ 1349 const gl::State &glState = getState(); 1350 1351 mDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer()); 1352 mDrawFramebufferIsDefault = mDrawFramebuffer->getState().isDefault(); 1353 1354 mDrawFramebuffer->onStartedDrawingToFrameBuffer(context); 1355 1356 onDrawFrameBufferChange(context, mDrawFramebuffer); 1357} 1358 1359void ContextMtl::onDrawFrameBufferChange(const gl::Context *context, FramebufferMtl *framebuffer) 1360{ 1361 const gl::State &glState = getState(); 1362 ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer())); 1363 1364 mDirtyBits.set(DIRTY_BIT_DRAW_FRAMEBUFFER); 1365 1366 updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(), 1367 glState.getFarPlane()); 1368 updateFrontFace(glState); 1369 updateScissor(glState); 1370 1371 // Need to re-apply state to RenderCommandEncoder 1372 invalidateState(context); 1373} 1374 1375void ContextMtl::updateProgramExecutable(const gl::Context *context) 1376{ 1377 // Need to rebind textures 1378 invalidateCurrentTextures(); 1379 // Need to re-upload default attributes 1380 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 1381 // Render pipeline need to be re-applied 1382 invalidateRenderPipeline(); 1383} 1384 1385void ContextMtl::updateVertexArray(const gl::Context *context) 1386{ 1387 const gl::State &glState = getState(); 1388 mVertexArray = mtl::GetImpl(glState.getVertexArray()); 1389 invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); 1390 invalidateRenderPipeline(); 1391} 1392 1393angle::Result ContextMtl::updateDefaultAttribute(size_t attribIndex) 1394{ 1395 const gl::State &glState = mState; 1396 const gl::VertexAttribCurrentValueData &defaultValue = 1397 glState.getVertexAttribCurrentValues()[attribIndex]; 1398 1399 constexpr size_t kDefaultGLAttributeValueSize = 1400 sizeof(gl::VertexAttribCurrentValueData::Values); 1401 1402 static_assert(kDefaultGLAttributeValueSize == mtl::kDefaultAttributeSize, 1403 "Unexpected default attribute size"); 1404 memcpy(mDefaultAttributes[attribIndex].values, &defaultValue.Values, 1405 mtl::kDefaultAttributeSize); 1406 1407 return angle::Result::Continue; 1408} 1409 1410angle::Result ContextMtl::setupDraw(const gl::Context *context, 1411 gl::PrimitiveMode mode, 1412 GLint firstVertex, 1413 GLsizei vertexOrIndexCount, 1414 GLsizei instances, 1415 gl::DrawElementsType indexTypeOrNone, 1416 const void *indices) 1417{ 1418 ASSERT(mProgram); 1419 1420 // instances=0 means no instanced draw. 1421 GLsizei instanceCount = instances ? instances : 1; 1422 1423 mtl::BufferRef lineLoopLastSegmentIndexBuffer; 1424 if (mode == gl::PrimitiveMode::LineLoop) 1425 { 1426 // Generate line loop last segment before render command encoder is created 1427 ANGLE_TRY(genLineLoopLastSegment(context, firstVertex, vertexOrIndexCount, instanceCount, 1428 indexTypeOrNone, indices, 1429 &lineLoopLastSegmentIndexBuffer)); 1430 } 1431 1432 // Must be called before the render command encoder is started. 1433 if (context->getStateCache().hasAnyActiveClientAttrib()) 1434 { 1435 ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, 1436 instanceCount, indexTypeOrNone, indices)); 1437 } 1438 // This must be called before render command encoder is started. 1439 bool textureChanged = false; 1440 if (mDirtyBits.test(DIRTY_BIT_TEXTURES)) 1441 { 1442 textureChanged = true; 1443 ANGLE_TRY(handleDirtyActiveTextures(context)); 1444 } 1445 1446 if (!mRenderEncoder.valid()) 1447 { 1448 // re-apply everything 1449 invalidateState(context); 1450 } 1451 1452 if (mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER)) 1453 { 1454 // Start new render command encoder 1455 const mtl::RenderPassDesc &rpDesc = mDrawFramebuffer->getRenderPassDesc(this); 1456 ANGLE_MTL_TRY(this, getRenderCommandEncoder(rpDesc)); 1457 1458 // re-apply everything 1459 invalidateState(context); 1460 } 1461 1462 Optional<mtl::RenderPipelineDesc> changedPipelineDesc; 1463 ANGLE_TRY(checkIfPipelineChanged(context, mode, &changedPipelineDesc)); 1464 1465 for (size_t bit : mDirtyBits) 1466 { 1467 switch (bit) 1468 { 1469 case DIRTY_BIT_TEXTURES: 1470 // Already handled. 1471 break; 1472 case DIRTY_BIT_DEFAULT_ATTRIBS: 1473 ANGLE_TRY(handleDirtyDefaultAttribs(context)); 1474 break; 1475 case DIRTY_BIT_DRIVER_UNIFORMS: 1476 ANGLE_TRY(handleDirtyDriverUniforms(context)); 1477 break; 1478 case DIRTY_BIT_DEPTH_STENCIL_DESC: 1479 ANGLE_TRY(handleDirtyDepthStencilState(context)); 1480 break; 1481 case DIRTY_BIT_DEPTH_BIAS: 1482 ANGLE_TRY(handleDirtyDepthBias(context)); 1483 break; 1484 case DIRTY_BIT_STENCIL_REF: 1485 mRenderEncoder.setStencilRefVals(mStencilRefFront, mStencilRefBack); 1486 break; 1487 case DIRTY_BIT_BLEND_COLOR: 1488 mRenderEncoder.setBlendColor( 1489 mState.getBlendColor().red, mState.getBlendColor().green, 1490 mState.getBlendColor().blue, mState.getBlendColor().alpha); 1491 break; 1492 case DIRTY_BIT_VIEWPORT: 1493 mRenderEncoder.setViewport(mViewport); 1494 break; 1495 case DIRTY_BIT_SCISSOR: 1496 mRenderEncoder.setScissorRect(mScissorRect); 1497 break; 1498 case DIRTY_BIT_DRAW_FRAMEBUFFER: 1499 // Already handled. 1500 break; 1501 case DIRTY_BIT_CULL_MODE: 1502 mRenderEncoder.setCullMode(mCullMode); 1503 break; 1504 case DIRTY_BIT_WINDING: 1505 mRenderEncoder.setFrontFacingWinding(mWinding); 1506 break; 1507 case DIRTY_BIT_RENDER_PIPELINE: 1508 // Already handled. See checkIfPipelineChanged(). 1509 break; 1510 default: 1511 UNREACHABLE(); 1512 break; 1513 } 1514 } 1515 1516 mDirtyBits.reset(); 1517 1518 ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, changedPipelineDesc, textureChanged)); 1519 1520 if (mode == gl::PrimitiveMode::LineLoop) 1521 { 1522 // Draw last segment of line loop here 1523 if (instances == 0) 1524 { 1525 mRenderEncoder.drawIndexed(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32, 1526 lineLoopLastSegmentIndexBuffer, 0); 1527 } 1528 else 1529 { 1530 mRenderEncoder.drawIndexedInstanced(MTLPrimitiveTypeLine, 2, MTLIndexTypeUInt32, 1531 lineLoopLastSegmentIndexBuffer, 0, instanceCount); 1532 } 1533 } 1534 1535 return angle::Result::Continue; 1536} 1537 1538angle::Result ContextMtl::genLineLoopLastSegment(const gl::Context *context, 1539 GLint firstVertex, 1540 GLsizei vertexOrIndexCount, 1541 GLsizei instanceCount, 1542 gl::DrawElementsType indexTypeOrNone, 1543 const void *indices, 1544 mtl::BufferRef *lastSegmentIndexBufferOut) 1545{ 1546 mLineLoopIndexBuffer.releaseInFlightBuffers(this); 1547 1548 mtl::BufferRef newBuffer; 1549 ANGLE_TRY(mLineLoopIndexBuffer.allocate(this, 2 * sizeof(uint32_t), nullptr, &newBuffer, 1550 nullptr, nullptr)); 1551 1552 if (indexTypeOrNone == gl::DrawElementsType::InvalidEnum) 1553 { 1554 ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegment( 1555 this, firstVertex, firstVertex + vertexOrIndexCount - 1, newBuffer, 0)); 1556 } 1557 else 1558 { 1559 // NOTE(hqle): Support drawRangeElements & instanced draw, which means firstVertex has to be 1560 // taken into account 1561 ASSERT(firstVertex == 0); 1562 ANGLE_TRY(getDisplay()->getUtils().generateLineLoopLastSegmentFromElementsArray( 1563 this, {indexTypeOrNone, vertexOrIndexCount, indices, newBuffer, 0})); 1564 } 1565 1566 ANGLE_TRY(mLineLoopIndexBuffer.commit(this)); 1567 1568 *lastSegmentIndexBufferOut = newBuffer; 1569 1570 return angle::Result::Continue; 1571} 1572 1573angle::Result ContextMtl::handleDirtyActiveTextures(const gl::Context *context) 1574{ 1575 const gl::State &glState = mState; 1576 const gl::Program *program = glState.getProgram(); 1577 1578 const gl::ActiveTexturesCache &textures = glState.getActiveTexturesCache(); 1579 const gl::ActiveTextureMask &activeTextures = program->getExecutable().getActiveSamplersMask(); 1580 1581 for (size_t textureUnit : activeTextures) 1582 { 1583 gl::Texture *texture = textures[textureUnit]; 1584 1585 if (texture == nullptr) 1586 { 1587 continue; 1588 } 1589 1590 TextureMtl *textureMtl = mtl::GetImpl(texture); 1591 1592 // Make sure texture's images update will be transferred to GPU. 1593 ANGLE_TRY(textureMtl->ensureTextureCreated(context)); 1594 1595 // The binding of this texture will be done by ProgramMtl. 1596 } 1597 1598 return angle::Result::Continue; 1599} 1600 1601angle::Result ContextMtl::handleDirtyDefaultAttribs(const gl::Context *context) 1602{ 1603 for (size_t attribIndex : mDirtyDefaultAttribsMask) 1604 { 1605 ANGLE_TRY(updateDefaultAttribute(attribIndex)); 1606 } 1607 1608 ASSERT(mRenderEncoder.valid()); 1609 mRenderEncoder.setFragmentData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex); 1610 mRenderEncoder.setVertexData(mDefaultAttributes, mtl::kDefaultAttribsBindingIndex); 1611 1612 mDirtyDefaultAttribsMask.reset(); 1613 return angle::Result::Continue; 1614} 1615 1616angle::Result ContextMtl::handleDirtyDriverUniforms(const gl::Context *context) 1617{ 1618 const gl::Rectangle &glViewport = mState.getViewport(); 1619 1620 float depthRangeNear = mState.getNearPlane(); 1621 float depthRangeFar = mState.getFarPlane(); 1622 float depthRangeDiff = depthRangeFar - depthRangeNear; 1623 1624 mDriverUniforms.viewport[0] = glViewport.x; 1625 mDriverUniforms.viewport[1] = glViewport.y; 1626 mDriverUniforms.viewport[2] = glViewport.width; 1627 mDriverUniforms.viewport[3] = glViewport.height; 1628 1629 mDriverUniforms.halfRenderArea[0] = 1630 static_cast<float>(mDrawFramebuffer->getState().getDimensions().width) * 0.5f; 1631 mDriverUniforms.halfRenderArea[1] = 1632 static_cast<float>(mDrawFramebuffer->getState().getDimensions().height) * 0.5f; 1633 mDriverUniforms.flipXY[0] = 1.0f; 1634 mDriverUniforms.flipXY[1] = mDrawFramebuffer->flipY() ? -1.0f : 1.0f; 1635 mDriverUniforms.negFlipXY[0] = mDriverUniforms.flipXY[0]; 1636 mDriverUniforms.negFlipXY[1] = -mDriverUniforms.flipXY[1]; 1637 1638 mDriverUniforms.enabledClipDistances = mState.getEnabledClipDistances().bits(); 1639 1640 mDriverUniforms.depthRange[0] = depthRangeNear; 1641 mDriverUniforms.depthRange[1] = depthRangeFar; 1642 mDriverUniforms.depthRange[2] = depthRangeDiff; 1643 mDriverUniforms.depthRange[3] = NeedToInvertDepthRange(depthRangeNear, depthRangeFar) ? -1 : 1; 1644 1645 // Fill in a mat2 identity matrix, plus padding 1646 mDriverUniforms.preRotation[0] = 1.0f; 1647 mDriverUniforms.preRotation[1] = 0.0f; 1648 mDriverUniforms.preRotation[2] = 0.0f; 1649 mDriverUniforms.preRotation[3] = 0.0f; 1650 mDriverUniforms.preRotation[4] = 0.0f; 1651 mDriverUniforms.preRotation[5] = 1.0f; 1652 mDriverUniforms.preRotation[6] = 0.0f; 1653 mDriverUniforms.preRotation[7] = 0.0f; 1654 1655 // Fill in a mat2 identity matrix, plus padding 1656 mDriverUniforms.fragRotation[0] = 1.0f; 1657 mDriverUniforms.fragRotation[1] = 0.0f; 1658 mDriverUniforms.fragRotation[2] = 0.0f; 1659 mDriverUniforms.fragRotation[3] = 0.0f; 1660 mDriverUniforms.fragRotation[4] = 0.0f; 1661 mDriverUniforms.fragRotation[5] = 1.0f; 1662 mDriverUniforms.fragRotation[6] = 0.0f; 1663 mDriverUniforms.fragRotation[7] = 0.0f; 1664 1665 ASSERT(mRenderEncoder.valid()); 1666 mRenderEncoder.setFragmentData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 1667 mRenderEncoder.setVertexData(mDriverUniforms, mtl::kDriverUniformsBindingIndex); 1668 1669 return angle::Result::Continue; 1670} 1671 1672angle::Result ContextMtl::handleDirtyDepthStencilState(const gl::Context *context) 1673{ 1674 ASSERT(mRenderEncoder.valid()); 1675 1676 // Need to handle the case when render pass doesn't have depth/stencil attachment. 1677 mtl::DepthStencilDesc dsDesc = mDepthStencilDesc; 1678 const mtl::RenderPassDesc &renderPassDesc = mDrawFramebuffer->getRenderPassDesc(this); 1679 1680 if (!renderPassDesc.depthAttachment.texture) 1681 { 1682 dsDesc.depthWriteEnabled = false; 1683 dsDesc.depthCompareFunction = MTLCompareFunctionAlways; 1684 } 1685 1686 if (!renderPassDesc.stencilAttachment.texture) 1687 { 1688 dsDesc.frontFaceStencil.reset(); 1689 dsDesc.backFaceStencil.reset(); 1690 } 1691 1692 // Apply depth stencil state 1693 mRenderEncoder.setDepthStencilState(getDisplay()->getDepthStencilState(dsDesc)); 1694 1695 return angle::Result::Continue; 1696} 1697 1698angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context) 1699{ 1700 const gl::RasterizerState &raserState = mState.getRasterizerState(); 1701 ASSERT(mRenderEncoder.valid()); 1702 if (!mState.isPolygonOffsetFillEnabled()) 1703 { 1704 mRenderEncoder.setDepthBias(0, 0, 0); 1705 } 1706 else 1707 { 1708 mRenderEncoder.setDepthBias(raserState.polygonOffsetUnits, raserState.polygonOffsetFactor, 1709 0); 1710 } 1711 1712 return angle::Result::Continue; 1713} 1714 1715angle::Result ContextMtl::checkIfPipelineChanged( 1716 const gl::Context *context, 1717 gl::PrimitiveMode primitiveMode, 1718 Optional<mtl::RenderPipelineDesc> *changedPipelineDesc) 1719{ 1720 ASSERT(mRenderEncoder.valid()); 1721 mtl::PrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode); 1722 1723 bool rppChange = mDirtyBits.test(DIRTY_BIT_RENDER_PIPELINE) || 1724 topologyClass != mRenderPipelineDesc.inputPrimitiveTopology; 1725 1726 // Obtain RenderPipelineDesc's vertex array descriptor. 1727 ANGLE_TRY(mVertexArray->setupDraw(context, &mRenderEncoder, &rppChange, 1728 &mRenderPipelineDesc.vertexDescriptor)); 1729 1730 if (rppChange) 1731 { 1732 const mtl::RenderPassDesc &renderPassDesc = mDrawFramebuffer->getRenderPassDesc(this); 1733 // Obtain RenderPipelineDesc's output descriptor. 1734 renderPassDesc.populateRenderPipelineOutputDesc(mBlendDesc, 1735 &mRenderPipelineDesc.outputDescriptor); 1736 1737 mRenderPipelineDesc.inputPrimitiveTopology = topologyClass; 1738 1739 *changedPipelineDesc = mRenderPipelineDesc; 1740 } 1741 1742 return angle::Result::Continue; 1743} 1744} 1745