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