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// mtl_render_utils.mm: 7// Implements the class methods for RenderUtils. 8// 9 10#include "libANGLE/renderer/metal/mtl_render_utils.h" 11 12#include <utility> 13 14#include "common/debug.h" 15#include "libANGLE/renderer/metal/BufferMtl.h" 16#include "libANGLE/renderer/metal/ContextMtl.h" 17#include "libANGLE/renderer/metal/DisplayMtl.h" 18#include "libANGLE/renderer/metal/ProgramMtl.h" 19#include "libANGLE/renderer/metal/QueryMtl.h" 20#include "libANGLE/renderer/metal/mtl_common.h" 21#include "libANGLE/renderer/metal/mtl_utils.h" 22 23namespace rx 24{ 25namespace mtl 26{ 27namespace 28{ 29 30#define NUM_COLOR_OUTPUTS_CONSTANT_NAME @"kNumColorOutputs" 31#define SOURCE_BUFFER_ALIGNED_CONSTANT_NAME @"kSourceBufferAligned" 32#define SOURCE_IDX_IS_U8_CONSTANT_NAME @"kSourceIndexIsU8" 33#define SOURCE_IDX_IS_U16_CONSTANT_NAME @"kSourceIndexIsU16" 34#define SOURCE_IDX_IS_U32_CONSTANT_NAME @"kSourceIndexIsU32" 35#define PREMULTIPLY_ALPHA_CONSTANT_NAME @"kPremultiplyAlpha" 36#define UNMULTIPLY_ALPHA_CONSTANT_NAME @"kUnmultiplyAlpha" 37#define SOURCE_TEXTURE_TYPE_CONSTANT_NAME @"kSourceTextureType" 38#define SOURCE_TEXTURE2_TYPE_CONSTANT_NAME @"kSourceTexture2Type" 39#define COPY_FORMAT_TYPE_CONSTANT_NAME @"kCopyFormatType" 40#define PIXEL_COPY_TEXTURE_TYPE_CONSTANT_NAME @"kCopyTextureType" 41#define VISIBILITY_RESULT_KEEP_OLD_VAL_CONSTANT_NAME @"kCombineWithExistingResult" 42 43// See libANGLE/renderer/metal/shaders/clear.metal 44struct ClearParamsUniform 45{ 46 float clearColor[4]; 47 float clearDepth; 48 float padding[3]; 49}; 50 51// See libANGLE/renderer/metal/shaders/blit.metal 52struct BlitParamsUniform 53{ 54 // 0: lower left, 1: lower right, 2: upper left 55 float srcTexCoords[3][2]; 56 int srcLevel = 0; 57 int srcLayer = 0; 58 uint8_t dstFlipX = 0; 59 uint8_t dstFlipY = 0; 60 uint8_t dstLuminance = 0; // dest texture is luminace 61 uint8_t padding[13]; 62}; 63 64struct BlitStencilToBufferParamsUniform 65{ 66 float srcStartTexCoords[2]; 67 float srcTexCoordSteps[2]; 68 uint32_t srcLevel; 69 uint32_t srcLayer; 70 71 uint32_t dstSize[2]; 72 uint32_t dstBufferRowPitch; 73 uint8_t resolveMS; 74 75 uint8_t padding[11]; 76}; 77 78// See libANGLE/renderer/metal/shaders/genIndices.metal 79struct TriFanOrLineLoopArrayParams 80{ 81 uint firstVertex; 82 uint vertexCount; 83 uint padding[2]; 84}; 85 86struct IndexConversionUniform 87{ 88 uint32_t srcOffset; 89 uint32_t indexCount; 90 uint8_t primitiveRestartEnabled; 91 uint8_t padding[7]; 92}; 93 94// See libANGLE/renderer/metal/shaders/visibility.metal 95struct CombineVisibilityResultUniform 96{ 97 uint32_t startOffset; 98 uint32_t numOffsets; 99 uint32_t padding[2]; 100}; 101 102// See libANGLE/renderer/metal/shaders/gen_mipmap.metal 103struct Generate3DMipmapUniform 104{ 105 uint32_t srcLevel; 106 uint32_t numMipmapsToGenerate; 107 uint8_t sRGB; 108 uint8_t padding[7]; 109}; 110 111// See libANGLE/renderer/metal/shaders/copy_buffer.metal 112struct CopyPixelFromBufferUniforms 113{ 114 uint32_t copySize[3]; 115 uint32_t padding1; 116 uint32_t textureOffset[3]; 117 uint32_t padding2; 118 uint32_t bufferStartOffset; 119 uint32_t pixelSize; 120 uint32_t bufferRowPitch; 121 uint32_t bufferDepthPitch; 122}; 123struct WritePixelToBufferUniforms 124{ 125 uint32_t copySize[2]; 126 uint32_t textureOffset[2]; 127 128 uint32_t bufferStartOffset; 129 uint32_t pixelSize; 130 uint32_t bufferRowPitch; 131 132 uint32_t textureLevel; 133 uint32_t textureLayer; 134 uint8_t reverseTextureRowOrder; 135 136 uint8_t padding[11]; 137}; 138 139struct CopyVertexUniforms 140{ 141 uint32_t srcBufferStartOffset; 142 uint32_t srcStride; 143 uint32_t srcComponentBytes; 144 uint32_t srcComponents; 145 uint32_t srcDefaultAlphaData; 146 147 uint32_t dstBufferStartOffset; 148 uint32_t dstStride; 149 uint32_t dstComponents; 150 151 uint32_t vertexCount; 152 153 uint32_t padding[3]; 154}; 155 156// Class to automatically disable occlusion query upon entering block and re-able it upon 157// exiting block. 158struct ScopedDisableOcclusionQuery 159{ 160 ScopedDisableOcclusionQuery(ContextMtl *contextMtl, 161 RenderCommandEncoder *encoder, 162 angle::Result *resultOut) 163 : mContextMtl(contextMtl), mEncoder(encoder), mResultOut(resultOut) 164 { 165#ifndef NDEBUG 166 if (contextMtl->hasActiveOcclusionQuery()) 167 { 168 encoder->pushDebugGroup(@"Disabled OcclusionQuery"); 169 } 170#endif 171 // temporarily disable occlusion query 172 contextMtl->disableActiveOcclusionQueryInRenderPass(); 173 } 174 ~ScopedDisableOcclusionQuery() 175 { 176 *mResultOut = mContextMtl->restartActiveOcclusionQueryInRenderPass(); 177#ifndef NDEBUG 178 if (mContextMtl->hasActiveOcclusionQuery()) 179 { 180 mEncoder->popDebugGroup(); 181 } 182#else 183 ANGLE_UNUSED_VARIABLE(mEncoder); 184#endif 185 } 186 187 private: 188 ContextMtl *mContextMtl; 189 RenderCommandEncoder *mEncoder; 190 191 angle::Result *mResultOut; 192}; 193 194void GetBlitTexCoords(const NormalizedCoords &normalizedCoords, 195 bool srcYFlipped, 196 bool unpackFlipX, 197 bool unpackFlipY, 198 float *u0, 199 float *v0, 200 float *u1, 201 float *v1) 202{ 203 *u0 = normalizedCoords.v[0]; 204 *v0 = normalizedCoords.v[1]; 205 *u1 = normalizedCoords.v[2]; 206 *v1 = normalizedCoords.v[3]; 207 208 if (srcYFlipped) 209 { 210 *v0 = 1.0 - *v0; 211 *v1 = 1.0 - *v1; 212 } 213 214 if (unpackFlipX) 215 { 216 std::swap(*u0, *u1); 217 } 218 219 if (unpackFlipY) 220 { 221 std::swap(*v0, *v1); 222 } 223} 224 225template <typename T> 226angle::Result GenTriFanFromClientElements(ContextMtl *contextMtl, 227 GLsizei count, 228 bool primitiveRestartEnabled, 229 const T *indices, 230 const BufferRef &dstBuffer, 231 uint32_t dstOffset, 232 uint32_t *indicesGenerated) 233{ 234 ASSERT(count > 2); 235 constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max(); 236 GLsizei dstTriangle = 0; 237 uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset); 238 T triFirstIdx, srcPrevIdx; 239 memcpy(&triFirstIdx, indices, sizeof(triFirstIdx)); 240 memcpy(&srcPrevIdx, indices + 1, sizeof(srcPrevIdx)); 241 242 if (primitiveRestartEnabled) 243 { 244 GLsizei triFirstIdxLoc = 0; 245 while (triFirstIdx == kSrcPrimitiveRestartIndex) 246 { 247 ++triFirstIdxLoc; 248 memcpy(&triFirstIdx, indices + triFirstIdxLoc, sizeof(triFirstIdx)); 249 } 250 251 for (GLsizei i = triFirstIdxLoc + 2; i < count; ++i) 252 { 253 uint32_t triIndices[3]; 254 T srcIdx; 255 memcpy(&srcIdx, indices + i, sizeof(srcIdx)); 256 bool completeTriangle = true; 257 if (srcPrevIdx == kSrcPrimitiveRestartIndex || srcIdx == kSrcPrimitiveRestartIndex) 258 { 259 // Incomplete triangle. Move to next triangle and set triFirstIndex 260 triFirstIdx = srcIdx; 261 triFirstIdxLoc = i; 262 completeTriangle = false; 263 } 264 else if (i < triFirstIdxLoc + 2) 265 { 266 // Incomplete triangle, move to next triangle 267 completeTriangle = false; 268 } 269 else 270 { 271 triIndices[0] = triFirstIdx; 272 triIndices[1] = srcPrevIdx; 273 triIndices[2] = srcIdx; 274 } 275 if (completeTriangle) 276 { 277 memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices)); 278 ++dstTriangle; 279 } 280 srcPrevIdx = srcIdx; 281 } 282 } 283 else 284 { 285 for (GLsizei i = 2; i < count; ++i) 286 { 287 T srcIdx; 288 memcpy(&srcIdx, indices + i, sizeof(srcIdx)); 289 290 uint32_t triIndices[3]; 291 triIndices[0] = triFirstIdx; 292 triIndices[1] = srcPrevIdx; 293 triIndices[2] = srcIdx; 294 srcPrevIdx = srcIdx; 295 296 memcpy(dstPtr + 3 * dstTriangle, triIndices, sizeof(triIndices)); 297 ++dstTriangle; 298 } 299 } 300 if (indicesGenerated) 301 *indicesGenerated = dstTriangle * 3; 302 dstBuffer->unmapAndFlushSubset( 303 contextMtl, dstOffset, 304 (indicesGenerated ? *(indicesGenerated) : (dstTriangle * 3)) * sizeof(uint32_t)); 305 306 return angle::Result::Continue; 307} 308 309template <typename T> 310angle::Result GenPrimitiveRestartBuffer(ContextMtl *contextMtl, 311 GLsizei count, 312 GLsizei indicesPerPrimitive, 313 const T *indices, 314 const BufferRef &dstBuffer, 315 uint32_t dstOffset, 316 size_t *indicesGenerated) 317{ 318 constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max(); 319 uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset); 320 GLsizei readValueLoc = 0; 321 T readValue = 0; 322 uint32_t dstIdx = 0; 323 memcpy(&readValue, indices, sizeof(readValue)); 324 while (readValue == kSrcPrimitiveRestartIndex) 325 { 326 327 ++readValueLoc; 328 memcpy(&readValue, indices + readValueLoc, sizeof(readValue)); 329 } 330 while (readValueLoc + indicesPerPrimitive <= count) 331 { 332 333 uint32_t primIndicies[3]; 334 bool foundPrimitive = true; 335 for (int k = 0; k < indicesPerPrimitive; ++k) 336 { 337 memcpy(&readValue, indices + readValueLoc, sizeof(readValue)); 338 ++readValueLoc; 339 if (readValue == kSrcPrimitiveRestartIndex) 340 { 341 foundPrimitive = false; 342 break; 343 } 344 else 345 { 346 primIndicies[k] = (uint32_t)readValue; 347 } 348 } 349 if (foundPrimitive) 350 { 351 memcpy(&dstPtr[dstIdx], primIndicies, (indicesPerPrimitive) * sizeof(uint32_t)); 352 dstIdx += indicesPerPrimitive; 353 } 354 } 355 if (indicesGenerated) 356 *indicesGenerated = dstIdx; 357 return angle::Result::Continue; 358} 359 360template <typename T> 361angle::Result GenLineLoopFromClientElements(ContextMtl *contextMtl, 362 GLsizei count, 363 bool primitiveRestartEnabled, 364 const T *indices, 365 const BufferRef &dstBuffer, 366 uint32_t dstOffset, 367 uint32_t *indicesGenerated) 368{ 369 ASSERT(count >= 2); 370 constexpr T kSrcPrimitiveRestartIndex = std::numeric_limits<T>::max(); 371 const uint32_t kDstPrimitiveRestartIndex = std::numeric_limits<uint32_t>::max(); 372 373 uint32_t *dstPtr = reinterpret_cast<uint32_t *>(dstBuffer->map(contextMtl) + dstOffset); 374 // lineLoopFirstIdx: value of of current line loop's first vertex index. Can change when 375 // encounter a primitive restart index. 376 T lineLoopFirstIdx; 377 memcpy(&lineLoopFirstIdx, indices, sizeof(lineLoopFirstIdx)); 378 379 if (primitiveRestartEnabled) 380 { 381 // lineLoopFirstIdxLoc: location of current line loop's first vertex in the source buffer. 382 GLsizei lineLoopFirstIdxLoc = 0; 383 while (lineLoopFirstIdx == kSrcPrimitiveRestartIndex) 384 { 385 memcpy(&dstPtr[lineLoopFirstIdxLoc++], &kDstPrimitiveRestartIndex, 386 sizeof(kDstPrimitiveRestartIndex)); 387 memcpy(&lineLoopFirstIdx, indices + lineLoopFirstIdxLoc, sizeof(lineLoopFirstIdx)); 388 } 389 390 // dstIdx : value of index to be written to dest buffer 391 uint32_t dstIdx = lineLoopFirstIdx; 392 memcpy(&dstPtr[lineLoopFirstIdxLoc], &dstIdx, sizeof(dstIdx)); 393 // dstWritten: number of indices written to dest buffer 394 uint32_t dstWritten = lineLoopFirstIdxLoc + 1; 395 396 for (GLsizei i = lineLoopFirstIdxLoc + 1; i < count; ++i) 397 { 398 // srcIdx : value of index from source buffer 399 T srcIdx; 400 memcpy(&srcIdx, indices + i, sizeof(srcIdx)); 401 if (srcIdx == kSrcPrimitiveRestartIndex) 402 { 403 // breaking line strip 404 dstIdx = lineLoopFirstIdx; 405 memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx)); 406 memcpy(&dstPtr[dstWritten++], &kDstPrimitiveRestartIndex, 407 sizeof(kDstPrimitiveRestartIndex)); 408 lineLoopFirstIdxLoc = i + 1; 409 } 410 else 411 { 412 dstIdx = srcIdx; 413 memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx)); 414 if (lineLoopFirstIdxLoc == i) 415 { 416 lineLoopFirstIdx = srcIdx; 417 } 418 } 419 } 420 421 if (lineLoopFirstIdxLoc < count) 422 { 423 // last segment 424 dstIdx = lineLoopFirstIdx; 425 memcpy(&dstPtr[dstWritten++], &dstIdx, sizeof(dstIdx)); 426 } 427 428 *indicesGenerated = dstWritten; 429 } 430 else 431 { 432 uint32_t dstIdx = lineLoopFirstIdx; 433 memcpy(dstPtr, &dstIdx, sizeof(dstIdx)); 434 memcpy(dstPtr + count, &dstIdx, sizeof(dstIdx)); 435 for (GLsizei i = 1; i < count; ++i) 436 { 437 T srcIdx; 438 memcpy(&srcIdx, indices + i, sizeof(srcIdx)); 439 440 dstIdx = srcIdx; 441 memcpy(dstPtr + i, &dstIdx, sizeof(dstIdx)); 442 } 443 444 *indicesGenerated = count + 1; 445 } 446 dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, (*indicesGenerated) * sizeof(uint32_t)); 447 448 return angle::Result::Continue; 449} 450 451template <typename T> 452void GetFirstLastIndicesFromClientElements(GLsizei count, 453 const T *indices, 454 uint32_t *firstOut, 455 uint32_t *lastOut) 456{ 457 *firstOut = 0; 458 *lastOut = 0; 459 memcpy(firstOut, indices, sizeof(indices[0])); 460 memcpy(lastOut, indices + count - 1, sizeof(indices[0])); 461} 462 463int GetShaderTextureType(const TextureRef &texture) 464{ 465 if (!texture) 466 { 467 return -1; 468 } 469 switch (texture->textureType()) 470 { 471 case MTLTextureType2D: 472 return mtl_shader::kTextureType2D; 473 case MTLTextureType2DArray: 474 return mtl_shader::kTextureType2DArray; 475 case MTLTextureType2DMultisample: 476 return mtl_shader::kTextureType2DMultisample; 477 case MTLTextureTypeCube: 478 return mtl_shader::kTextureTypeCube; 479 case MTLTextureType3D: 480 return mtl_shader::kTextureType3D; 481 default: 482 UNREACHABLE(); 483 } 484 485 return 0; 486} 487 488int GetPixelTypeIndex(const angle::Format &angleFormat) 489{ 490 if (angleFormat.isSint()) 491 { 492 return static_cast<int>(PixelType::Int); 493 } 494 else if (angleFormat.isUint()) 495 { 496 return static_cast<int>(PixelType::UInt); 497 } 498 else 499 { 500 return static_cast<int>(PixelType::Float); 501 } 502} 503 504ANGLE_INLINE 505void EnsureComputePipelineInitialized(ContextMtl *context, 506 NSString *functionName, 507 AutoObjCPtr<id<MTLComputePipelineState>> *pipelineOut) 508{ 509 AutoObjCPtr<id<MTLComputePipelineState>> &pipeline = *pipelineOut; 510 if (pipeline) 511 { 512 return; 513 } 514 515 ANGLE_MTL_OBJC_SCOPE 516 { 517 const mtl::ContextDevice &metalDevice = context->getMetalDevice(); 518 auto shaderLib = context->getDisplay()->getDefaultShadersLib(); 519 NSError *err = nil; 520 id<MTLFunction> shader = [shaderLib newFunctionWithName:functionName]; 521 522 [shader ANGLE_MTL_AUTORELEASE]; 523 524 pipeline = metalDevice.newComputePipelineStateWithFunction(shader, &err); 525 if (err && !pipeline) 526 { 527 ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n"; 528 } 529 530 ASSERT(pipeline); 531 } 532} 533 534ANGLE_INLINE 535void EnsureSpecializedComputePipelineInitialized( 536 ContextMtl *context, 537 NSString *functionName, 538 MTLFunctionConstantValues *funcConstants, 539 AutoObjCPtr<id<MTLComputePipelineState>> *pipelineOut) 540{ 541 if (!funcConstants) 542 { 543 // Non specialized constants provided, use default creation function. 544 EnsureComputePipelineInitialized(context, functionName, pipelineOut); 545 return; 546 } 547 548 AutoObjCPtr<id<MTLComputePipelineState>> &pipeline = *pipelineOut; 549 if (pipeline) 550 { 551 return; 552 } 553 554 ANGLE_MTL_OBJC_SCOPE 555 { 556 const mtl::ContextDevice &metalDevice = context->getMetalDevice(); 557 auto shaderLib = context->getDisplay()->getDefaultShadersLib(); 558 NSError *err = nil; 559 560 auto shader = adoptObjCObj([shaderLib newFunctionWithName:functionName 561 constantValues:funcConstants 562 error:&err]); 563 if (err && !shader) 564 { 565 ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n"; 566 } 567 568 pipeline = metalDevice.newComputePipelineStateWithFunction(shader, &err); 569 if (err && !pipeline) 570 { 571 ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n"; 572 } 573 ASSERT(pipeline); 574 } 575} 576 577// Function to initialize render pipeline cache with only vertex shader. 578ANGLE_INLINE 579void EnsureVertexShaderOnlyPipelineCacheInitialized(ContextMtl *context, 580 NSString *vertexFunctionName, 581 id<MTLLibrary> shaderLib, 582 RenderPipelineCache *pipelineCacheOut) 583{ 584 RenderPipelineCache &pipelineCache = *pipelineCacheOut; 585 if (pipelineCache.getVertexShader()) 586 { 587 // Already initialized 588 return; 589 } 590 auto shader = adoptObjCObj([shaderLib newFunctionWithName:vertexFunctionName]); 591 pipelineCache.setVertexShader(context, shader); 592} 593 594// Function to initialize specialized render pipeline cache with only vertex shader. 595ANGLE_INLINE 596void EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized( 597 ContextMtl *context, 598 NSString *vertexFunctionName, 599 MTLFunctionConstantValues *funcConstants, 600 RenderPipelineCache *pipelineCacheOut) 601{ 602 if (!funcConstants) 603 { 604 // Non specialized constants provided, use default creation function. 605 DisplayMtl *display = context->getDisplay(); 606 auto shaderLib = display->getDefaultShadersLib(); 607 EnsureVertexShaderOnlyPipelineCacheInitialized(context, vertexFunctionName, shaderLib, 608 pipelineCacheOut); 609 return; 610 } 611 612 RenderPipelineCache &pipelineCache = *pipelineCacheOut; 613 if (pipelineCache.getVertexShader()) 614 { 615 // Already initialized 616 return; 617 } 618 619 ANGLE_MTL_OBJC_SCOPE 620 { 621 DisplayMtl *display = context->getDisplay(); 622 auto shaderLib = display->getDefaultShadersLib(); 623 NSError *err = nil; 624 auto shader = adoptObjCObj([shaderLib newFunctionWithName:vertexFunctionName 625 constantValues:funcConstants 626 error:&err]); 627 if (err && !shader) 628 { 629 ERR() << "Internal error: " << err.localizedDescription.UTF8String << "\n"; 630 } 631 pipelineCache.setVertexShader(context, shader); 632 } 633} 634 635// Get pipeline descriptor for render pipeline that contains vertex shader acting as compute shader. 636ANGLE_INLINE 637RenderPipelineDesc GetComputingVertexShaderOnlyRenderPipelineDesc(RenderCommandEncoder *cmdEncoder) 638{ 639 RenderPipelineDesc pipelineDesc; 640 const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); 641 642 renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor); 643 pipelineDesc.rasterizationType = RenderPipelineRasterization::Disabled; 644 pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassPoint; 645 646 return pipelineDesc; 647} 648 649// Get pipeline descriptor for render pipeline that contains vertex shader acting as transform 650// feedback. 651 652template <typename T> 653void ClearRenderPipelineCacheArray(T *pipelineCacheArray) 654{ 655 for (RenderPipelineCache &pipelineCache : *pipelineCacheArray) 656 { 657 pipelineCache.clear(); 658 } 659} 660 661template <typename T> 662void ClearRenderPipelineCache2DArray(T *pipelineCache2DArray) 663{ 664 for (auto &level1Array : *pipelineCache2DArray) 665 { 666 ClearRenderPipelineCacheArray(&level1Array); 667 } 668} 669 670template <typename T> 671void ClearPipelineStateArray(T *pipelineCacheArray) 672{ 673 for (auto &pipeline : *pipelineCacheArray) 674 { 675 pipeline = nil; 676 } 677} 678 679template <typename T> 680void ClearPipelineState2DArray(T *pipelineCache2DArray) 681{ 682 for (auto &level1Array : *pipelineCache2DArray) 683 { 684 ClearPipelineStateArray(&level1Array); 685 } 686} 687 688// Dispatch compute using 3D grid 689void DispatchCompute(ContextMtl *contextMtl, 690 ComputeCommandEncoder *encoder, 691 bool allowNonUniform, 692 const MTLSize &numThreads, 693 const MTLSize &threadsPerThreadgroup) 694{ 695 if (allowNonUniform && contextMtl->getDisplay()->getFeatures().hasNonUniformDispatch.enabled) 696 { 697 encoder->dispatchNonUniform(numThreads, threadsPerThreadgroup); 698 } 699 else 700 { 701 MTLSize groups = MTLSizeMake( 702 (numThreads.width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width, 703 (numThreads.height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 704 (numThreads.depth + threadsPerThreadgroup.depth - 1) / threadsPerThreadgroup.depth); 705 encoder->dispatch(groups, threadsPerThreadgroup); 706 } 707} 708 709// Dispatch compute using 1D grid 710void DispatchCompute(ContextMtl *contextMtl, 711 ComputeCommandEncoder *cmdEncoder, 712 id<MTLComputePipelineState> pipelineState, 713 size_t numThreads) 714{ 715 NSUInteger w = std::min<NSUInteger>(pipelineState.threadExecutionWidth, numThreads); 716 MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1); 717 718 if (contextMtl->getDisplay()->getFeatures().hasNonUniformDispatch.enabled) 719 { 720 MTLSize threads = MTLSizeMake(numThreads, 1, 1); 721 cmdEncoder->dispatchNonUniform(threads, threadsPerThreadgroup); 722 } 723 else 724 { 725 MTLSize groups = MTLSizeMake((numThreads + w - 1) / w, 1, 1); 726 cmdEncoder->dispatch(groups, threadsPerThreadgroup); 727 } 728} 729 730void SetupFullscreenQuadDrawCommonStates(RenderCommandEncoder *cmdEncoder) 731{ 732 cmdEncoder->setCullMode(MTLCullModeNone); 733 cmdEncoder->setTriangleFillMode(MTLTriangleFillModeFill); 734 cmdEncoder->setDepthBias(0, 0, 0); 735} 736 737void SetupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, 738 const BlitParams ¶ms, 739 bool isColorBlit) 740{ 741 742 BlitParamsUniform uniformParams; 743 uniformParams.dstFlipX = params.dstFlipX ? 1 : 0; 744 uniformParams.dstFlipY = params.dstFlipY ? 1 : 0; 745 uniformParams.srcLevel = params.srcLevel.get(); 746 uniformParams.srcLayer = params.srcLayer; 747 if (isColorBlit) 748 { 749 const ColorBlitParams *colorParams = static_cast<const ColorBlitParams *>(¶ms); 750 uniformParams.dstLuminance = colorParams->dstLuminance ? 1 : 0; 751 } 752 753 float u0, v0, u1, v1; 754 GetBlitTexCoords(params.srcNormalizedCoords, params.srcYFlipped, params.unpackFlipX, 755 params.unpackFlipY, &u0, &v0, &u1, &v1); 756 757 float du = u1 - u0; 758 float dv = v1 - v0; 759 760 // lower left 761 uniformParams.srcTexCoords[0][0] = u0; 762 uniformParams.srcTexCoords[0][1] = v0; 763 764 // lower right 765 uniformParams.srcTexCoords[1][0] = u1 + du; 766 uniformParams.srcTexCoords[1][1] = v0; 767 768 // upper left 769 uniformParams.srcTexCoords[2][0] = u0; 770 uniformParams.srcTexCoords[2][1] = v1 + dv; 771 772 cmdEncoder->setVertexData(uniformParams, 0); 773 cmdEncoder->setFragmentData(uniformParams, 0); 774} 775 776void SetupCommonBlitWithDrawStates(const gl::Context *context, 777 RenderCommandEncoder *cmdEncoder, 778 const BlitParams ¶ms, 779 bool isColorBlit) 780{ 781 // Setup states 782 SetupFullscreenQuadDrawCommonStates(cmdEncoder); 783 784 // Viewport 785 MTLViewport viewportMtl = 786 GetViewport(params.dstRect, params.dstTextureSize.height, params.dstFlipY); 787 MTLScissorRect scissorRectMtl = 788 GetScissorRect(params.dstScissorRect, params.dstTextureSize.height, params.dstFlipY); 789 cmdEncoder->setViewport(viewportMtl); 790 cmdEncoder->setScissorRect(scissorRectMtl); 791 792 if (params.src) 793 { 794 cmdEncoder->setFragmentTexture(params.src, 0); 795 } 796 797 // Uniform 798 SetupBlitWithDrawUniformData(cmdEncoder, params, isColorBlit); 799} 800 801// Overloaded functions to be used with both compute and render command encoder. 802ANGLE_INLINE void SetComputeOrVertexBuffer(RenderCommandEncoder *encoder, 803 const BufferRef &buffer, 804 uint32_t offset, 805 uint32_t index) 806{ 807 encoder->setBuffer(gl::ShaderType::Vertex, buffer, offset, index); 808} 809ANGLE_INLINE void SetComputeOrVertexBufferForWrite(RenderCommandEncoder *encoder, 810 const BufferRef &buffer, 811 uint32_t offset, 812 uint32_t index) 813{ 814 encoder->setBufferForWrite(gl::ShaderType::Vertex, buffer, offset, index); 815} 816ANGLE_INLINE void SetComputeOrVertexBuffer(ComputeCommandEncoder *encoder, 817 const BufferRef &buffer, 818 uint32_t offset, 819 uint32_t index) 820{ 821 encoder->setBuffer(buffer, offset, index); 822} 823ANGLE_INLINE void SetComputeOrVertexBufferForWrite(ComputeCommandEncoder *encoder, 824 const BufferRef &buffer, 825 uint32_t offset, 826 uint32_t index) 827{ 828 encoder->setBufferForWrite(buffer, offset, index); 829} 830 831template <typename T> 832ANGLE_INLINE void SetComputeOrVertexData(RenderCommandEncoder *encoder, 833 const T &data, 834 uint32_t index) 835{ 836 encoder->setData(gl::ShaderType::Vertex, data, index); 837} 838template <typename T> 839ANGLE_INLINE void SetComputeOrVertexData(ComputeCommandEncoder *encoder, 840 const T &data, 841 uint32_t index) 842{ 843 encoder->setData(data, index); 844} 845 846ANGLE_INLINE void SetPipelineState(RenderCommandEncoder *encoder, 847 id<MTLRenderPipelineState> pipeline) 848{ 849 encoder->setRenderPipelineState(pipeline); 850} 851ANGLE_INLINE void SetPipelineState(ComputeCommandEncoder *encoder, 852 id<MTLComputePipelineState> pipeline) 853{ 854 encoder->setComputePipelineState(pipeline); 855} 856 857} // namespace 858 859NormalizedCoords::NormalizedCoords() : v{0.0f, 0.0f, 1.0f, 1.0f} {} 860 861NormalizedCoords::NormalizedCoords(float x, 862 float y, 863 float width, 864 float height, 865 const gl::Rectangle &rect) 866 : v{ 867 x / rect.width, 868 y / rect.height, 869 (x + width) / rect.width, 870 (y + height) / rect.height, 871 } 872{} 873 874NormalizedCoords::NormalizedCoords(const gl::Rectangle &rect, const gl::Extents &extents) 875 : v{ 876 static_cast<float>(rect.x0()) / extents.width, 877 static_cast<float>(rect.y0()) / extents.height, 878 static_cast<float>(rect.x1()) / extents.width, 879 static_cast<float>(rect.y1()) / extents.height, 880 } 881{} 882 883// StencilBlitViaBufferParams implementation 884StencilBlitViaBufferParams::StencilBlitViaBufferParams() {} 885 886StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitParams &srcParams) 887{ 888 dstTextureSize = srcParams.dstTextureSize; 889 dstRect = srcParams.dstRect; 890 dstScissorRect = srcParams.dstScissorRect; 891 dstFlipY = srcParams.dstFlipY; 892 dstFlipX = srcParams.dstFlipX; 893 srcNormalizedCoords = srcParams.srcNormalizedCoords; 894 srcYFlipped = srcParams.srcYFlipped; 895 unpackFlipX = srcParams.unpackFlipX; 896 unpackFlipY = srcParams.unpackFlipY; 897 898 srcStencil = srcParams.srcStencil; 899} 900 901// RenderUtils implementation 902RenderUtils::RenderUtils(DisplayMtl *display) 903 : Context(display), 904 mClearUtils( 905 {ClearUtils("clearIntFS"), ClearUtils("clearUIntFS"), ClearUtils("clearFloatFS")}), 906 mColorBlitUtils({ColorBlitUtils("blitIntFS"), ColorBlitUtils("blitUIntFS"), 907 ColorBlitUtils("blitFloatFS")}), 908 mCopyTextureFloatToUIntUtils("copyTextureFloatToUIntFS"), 909 mCopyPixelsUtils( 910 {CopyPixelsUtils("readFromBufferToIntTexture", "writeFromIntTextureToBuffer"), 911 CopyPixelsUtils("readFromBufferToUIntTexture", "writeFromUIntTextureToBuffer"), 912 CopyPixelsUtils("readFromBufferToFloatTexture", "writeFromFloatTextureToBuffer")}) 913{} 914 915RenderUtils::~RenderUtils() {} 916 917angle::Result RenderUtils::initialize() 918{ 919 return angle::Result::Continue; 920} 921 922void RenderUtils::onDestroy() 923{ 924 mDepthStencilBlitUtils.onDestroy(); 925 mIndexUtils.onDestroy(); 926 mVisibilityResultUtils.onDestroy(); 927 mMipmapUtils.onDestroy(); 928 mVertexFormatUtils.onDestroy(); 929 mCopyTextureFloatToUIntUtils.onDestroy(); 930 931 for (ClearUtils &util : mClearUtils) 932 { 933 util.onDestroy(); 934 } 935 for (ColorBlitUtils &util : mColorBlitUtils) 936 { 937 util.onDestroy(); 938 } 939 for (CopyPixelsUtils &util : mCopyPixelsUtils) 940 { 941 util.onDestroy(); 942 } 943} 944 945// override ErrorHandler 946void RenderUtils::handleError(GLenum glErrorCode, 947 const char *file, 948 const char *function, 949 unsigned int line) 950{ 951 ERR() << "Metal backend encountered an internal error. Code=" << glErrorCode << "."; 952} 953 954void RenderUtils::handleError(NSError *nserror, 955 const char *file, 956 const char *function, 957 unsigned int line) 958{ 959 if (!nserror) 960 { 961 return; 962 } 963 964 std::stringstream errorStream; 965 ERR() << "Metal backend encountered an internal error: \n" 966 << nserror.localizedDescription.UTF8String; 967} 968 969// Clear current framebuffer 970angle::Result RenderUtils::clearWithDraw(const gl::Context *context, 971 RenderCommandEncoder *cmdEncoder, 972 const ClearRectParams ¶ms) 973{ 974 int index = 0; 975 if (params.clearColor.valid()) 976 { 977 index = static_cast<int>(params.clearColor.value().getType()); 978 } 979 else if (params.colorFormat) 980 { 981 index = GetPixelTypeIndex(params.colorFormat->actualAngleFormat()); 982 } 983 return mClearUtils[index].clearWithDraw(context, cmdEncoder, params); 984} 985 986// Blit texture data to current framebuffer 987angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context, 988 RenderCommandEncoder *cmdEncoder, 989 const angle::Format &srcAngleFormat, 990 const ColorBlitParams ¶ms) 991{ 992 int index = GetPixelTypeIndex(srcAngleFormat); 993 return mColorBlitUtils[index].blitColorWithDraw(context, cmdEncoder, params); 994} 995 996angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context, 997 RenderCommandEncoder *cmdEncoder, 998 const angle::Format &srcAngleFormat, 999 const TextureRef &srcTexture) 1000{ 1001 if (!srcTexture) 1002 { 1003 return angle::Result::Continue; 1004 } 1005 ColorBlitParams params; 1006 params.enabledBuffers.set(0); 1007 params.src = srcTexture; 1008 params.dstTextureSize = gl::Extents(static_cast<int>(srcTexture->widthAt0()), 1009 static_cast<int>(srcTexture->heightAt0()), 1010 static_cast<int>(srcTexture->depthAt0())); 1011 params.dstRect = params.dstScissorRect = 1012 gl::Rectangle(0, 0, params.dstTextureSize.width, params.dstTextureSize.height); 1013 params.srcNormalizedCoords = NormalizedCoords(); 1014 1015 return blitColorWithDraw(context, cmdEncoder, srcAngleFormat, params); 1016} 1017 1018angle::Result RenderUtils::copyTextureWithDraw(const gl::Context *context, 1019 RenderCommandEncoder *cmdEncoder, 1020 const angle::Format &srcAngleFormat, 1021 const angle::Format &dstAngleFormat, 1022 const ColorBlitParams ¶ms) 1023{ 1024 if (!srcAngleFormat.isInt() && dstAngleFormat.isUint()) 1025 { 1026 return mCopyTextureFloatToUIntUtils.blitColorWithDraw(context, cmdEncoder, params); 1027 } 1028 ASSERT(srcAngleFormat.isSint() == dstAngleFormat.isSint() && 1029 srcAngleFormat.isUint() == dstAngleFormat.isUint()); 1030 return blitColorWithDraw(context, cmdEncoder, srcAngleFormat, params); 1031} 1032 1033angle::Result RenderUtils::blitDepthStencilWithDraw(const gl::Context *context, 1034 RenderCommandEncoder *cmdEncoder, 1035 const DepthStencilBlitParams ¶ms) 1036{ 1037 return mDepthStencilBlitUtils.blitDepthStencilWithDraw(context, cmdEncoder, params); 1038} 1039 1040angle::Result RenderUtils::blitStencilViaCopyBuffer(const gl::Context *context, 1041 const StencilBlitViaBufferParams ¶ms) 1042{ 1043 return mDepthStencilBlitUtils.blitStencilViaCopyBuffer(context, params); 1044} 1045 1046angle::Result RenderUtils::convertIndexBufferGPU(ContextMtl *contextMtl, 1047 const IndexConversionParams ¶ms) 1048{ 1049 return mIndexUtils.convertIndexBufferGPU(contextMtl, params); 1050} 1051angle::Result RenderUtils::generateTriFanBufferFromArrays( 1052 ContextMtl *contextMtl, 1053 const TriFanOrLineLoopFromArrayParams ¶ms) 1054{ 1055 return mIndexUtils.generateTriFanBufferFromArrays(contextMtl, params); 1056} 1057angle::Result RenderUtils::generateTriFanBufferFromElementsArray( 1058 ContextMtl *contextMtl, 1059 const IndexGenerationParams ¶ms, 1060 uint32_t *indicesGenerated) 1061{ 1062 return mIndexUtils.generateTriFanBufferFromElementsArray(contextMtl, params, indicesGenerated); 1063} 1064 1065angle::Result RenderUtils::generateLineLoopBufferFromArrays( 1066 ContextMtl *contextMtl, 1067 const TriFanOrLineLoopFromArrayParams ¶ms) 1068{ 1069 return mIndexUtils.generateLineLoopBufferFromArrays(contextMtl, params); 1070} 1071angle::Result RenderUtils::generateLineLoopLastSegment(ContextMtl *contextMtl, 1072 uint32_t firstVertex, 1073 uint32_t lastVertex, 1074 const BufferRef &dstBuffer, 1075 uint32_t dstOffset) 1076{ 1077 return mIndexUtils.generateLineLoopLastSegment(contextMtl, firstVertex, lastVertex, dstBuffer, 1078 dstOffset); 1079} 1080angle::Result RenderUtils::generateLineLoopBufferFromElementsArray( 1081 ContextMtl *contextMtl, 1082 const IndexGenerationParams ¶ms, 1083 uint32_t *indicesGenerated) 1084{ 1085 return mIndexUtils.generateLineLoopBufferFromElementsArray(contextMtl, params, 1086 indicesGenerated); 1087} 1088angle::Result RenderUtils::generateLineLoopLastSegmentFromElementsArray( 1089 ContextMtl *contextMtl, 1090 const IndexGenerationParams ¶ms) 1091{ 1092 return mIndexUtils.generateLineLoopLastSegmentFromElementsArray(contextMtl, params); 1093} 1094angle::Result RenderUtils::generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl, 1095 const IndexGenerationParams ¶ms, 1096 size_t *indicesGenerated) 1097{ 1098 return mIndexUtils.generatePrimitiveRestartPointsBuffer(contextMtl, params, indicesGenerated); 1099} 1100angle::Result RenderUtils::generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl, 1101 const IndexGenerationParams ¶ms, 1102 size_t *indicesGenerated) 1103{ 1104 return mIndexUtils.generatePrimitiveRestartLinesBuffer(contextMtl, params, indicesGenerated); 1105} 1106angle::Result RenderUtils::generatePrimitiveRestartTrianglesBuffer( 1107 ContextMtl *contextMtl, 1108 const IndexGenerationParams ¶ms, 1109 size_t *indicesGenerated) 1110{ 1111 return mIndexUtils.generatePrimitiveRestartTrianglesBuffer(contextMtl, params, 1112 indicesGenerated); 1113} 1114 1115void RenderUtils::combineVisibilityResult( 1116 ContextMtl *contextMtl, 1117 bool keepOldValue, 1118 const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets, 1119 const BufferRef &renderPassResultBuf, 1120 const BufferRef &finalResultBuf) 1121{ 1122 return mVisibilityResultUtils.combineVisibilityResult( 1123 contextMtl, keepOldValue, renderPassResultBufOffsets, renderPassResultBuf, finalResultBuf); 1124} 1125 1126// Compute based mipmap generation 1127angle::Result RenderUtils::generateMipmapCS(ContextMtl *contextMtl, 1128 const TextureRef &srcTexture, 1129 bool sRGBMipmap, 1130 NativeTexLevelArray *mipmapOutputViews) 1131{ 1132 return mMipmapUtils.generateMipmapCS(contextMtl, srcTexture, sRGBMipmap, mipmapOutputViews); 1133} 1134 1135angle::Result RenderUtils::unpackPixelsFromBufferToTexture(ContextMtl *contextMtl, 1136 const angle::Format &srcAngleFormat, 1137 const CopyPixelsFromBufferParams ¶ms) 1138{ 1139 int index = GetPixelTypeIndex(srcAngleFormat); 1140 return mCopyPixelsUtils[index].unpackPixelsFromBufferToTexture(contextMtl, srcAngleFormat, 1141 params); 1142} 1143angle::Result RenderUtils::packPixelsFromTextureToBuffer(ContextMtl *contextMtl, 1144 const angle::Format &dstAngleFormat, 1145 const CopyPixelsToBufferParams ¶ms) 1146{ 1147 int index = GetPixelTypeIndex(dstAngleFormat); 1148 return mCopyPixelsUtils[index].packPixelsFromTextureToBuffer(contextMtl, dstAngleFormat, 1149 params); 1150} 1151 1152angle::Result RenderUtils::convertVertexFormatToFloatCS(ContextMtl *contextMtl, 1153 const angle::Format &srcAngleFormat, 1154 const VertexFormatConvertParams ¶ms) 1155{ 1156 return mVertexFormatUtils.convertVertexFormatToFloatCS(contextMtl, srcAngleFormat, params); 1157} 1158 1159angle::Result RenderUtils::convertVertexFormatToFloatVS(const gl::Context *context, 1160 RenderCommandEncoder *encoder, 1161 const angle::Format &srcAngleFormat, 1162 const VertexFormatConvertParams ¶ms) 1163{ 1164 return mVertexFormatUtils.convertVertexFormatToFloatVS(context, encoder, srcAngleFormat, 1165 params); 1166} 1167 1168// Expand number of components per vertex's attribute 1169angle::Result RenderUtils::expandVertexFormatComponentsCS(ContextMtl *contextMtl, 1170 const angle::Format &srcAngleFormat, 1171 const VertexFormatConvertParams ¶ms) 1172{ 1173 return mVertexFormatUtils.expandVertexFormatComponentsCS(contextMtl, srcAngleFormat, params); 1174} 1175 1176angle::Result RenderUtils::expandVertexFormatComponentsVS(const gl::Context *context, 1177 RenderCommandEncoder *encoder, 1178 const angle::Format &srcAngleFormat, 1179 const VertexFormatConvertParams ¶ms) 1180{ 1181 return mVertexFormatUtils.expandVertexFormatComponentsVS(context, encoder, srcAngleFormat, 1182 params); 1183} 1184 1185// ClearUtils implementation 1186ClearUtils::ClearUtils(const std::string &fragmentShaderName) 1187 : mFragmentShaderName(fragmentShaderName) 1188{} 1189 1190ClearUtils::ClearUtils(const ClearUtils &src) : ClearUtils(src.mFragmentShaderName) {} 1191 1192void ClearUtils::onDestroy() 1193{ 1194 ClearRenderPipelineCacheArray(&mClearRenderPipelineCache); 1195} 1196 1197void ClearUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, uint32_t numOutputs) 1198{ 1199 RenderPipelineCache &cache = mClearRenderPipelineCache[numOutputs]; 1200 if (cache.getVertexShader() && cache.getFragmentShader()) 1201 { 1202 // Already initialized. 1203 return; 1204 } 1205 1206 ANGLE_MTL_OBJC_SCOPE 1207 { 1208 NSError *err = nil; 1209 id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib(); 1210 id<MTLFunction> vertexShader = 1211 [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]; 1212 MTLFunctionConstantValues *funcConstants = 1213 [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1214 1215 // Create clear shader pipeline cache for each number of color outputs. 1216 // So clear k color outputs will use mClearRenderPipelineCache[k] for example: 1217 [funcConstants setConstantValue:&numOutputs 1218 type:MTLDataTypeUInt 1219 withName:NUM_COLOR_OUTPUTS_CONSTANT_NAME]; 1220 1221 id<MTLFunction> fragmentShader = [[shaderLib 1222 newFunctionWithName:[NSString stringWithUTF8String:mFragmentShaderName.c_str()] 1223 constantValues:funcConstants 1224 error:&err] ANGLE_MTL_AUTORELEASE]; 1225 ASSERT(fragmentShader); 1226 1227 cache.setVertexShader(ctx, vertexShader); 1228 cache.setFragmentShader(ctx, fragmentShader); 1229 } 1230} 1231 1232id<MTLDepthStencilState> ClearUtils::getClearDepthStencilState(const gl::Context *context, 1233 const ClearRectParams ¶ms) 1234{ 1235 ContextMtl *contextMtl = GetImpl(context); 1236 1237 if (!params.clearDepth.valid() && !params.clearStencil.valid()) 1238 { 1239 // Doesn't clear depth nor stencil 1240 return contextMtl->getDisplay()->getStateCache().getNullDepthStencilState( 1241 contextMtl->getMetalDevice()); 1242 } 1243 1244 DepthStencilDesc desc; 1245 desc.reset(); 1246 1247 if (params.clearDepth.valid()) 1248 { 1249 // Clear depth state 1250 desc.depthWriteEnabled = true; 1251 } 1252 else 1253 { 1254 desc.depthWriteEnabled = false; 1255 } 1256 1257 if (params.clearStencil.valid()) 1258 { 1259 // Clear stencil state 1260 desc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace; 1261 desc.frontFaceStencil.writeMask = contextMtl->getStencilMask(); 1262 desc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace; 1263 desc.backFaceStencil.writeMask = contextMtl->getStencilMask(); 1264 } 1265 1266 return contextMtl->getDisplay()->getStateCache().getDepthStencilState( 1267 contextMtl->getMetalDevice(), desc); 1268} 1269 1270id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Context *context, 1271 RenderCommandEncoder *cmdEncoder, 1272 const ClearRectParams ¶ms) 1273{ 1274 ContextMtl *contextMtl = GetImpl(context); 1275 // The color mask to be applied to every color attachment: 1276 WriteMaskArray clearWriteMaskArray = params.clearWriteMaskArray; 1277 if (!params.clearColor.valid()) 1278 { 1279 clearWriteMaskArray.fill(MTLColorWriteMaskNone); 1280 } 1281 1282 RenderPipelineDesc pipelineDesc; 1283 const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); 1284 1285 renderPassDesc.populateRenderPipelineOutputDesc(clearWriteMaskArray, 1286 &pipelineDesc.outputDescriptor); 1287 1288 // Disable clear for some outputs that are not enabled 1289 pipelineDesc.outputDescriptor.updateEnabledDrawBuffers(params.enabledBuffers); 1290 1291 pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle; 1292 1293 ensureRenderPipelineStateCacheInitialized(contextMtl, renderPassDesc.numColorAttachments); 1294 RenderPipelineCache &cache = mClearRenderPipelineCache[renderPassDesc.numColorAttachments]; 1295 1296 return cache.getRenderPipelineState(contextMtl, pipelineDesc); 1297} 1298 1299angle::Result ClearUtils::setupClearWithDraw(const gl::Context *context, 1300 RenderCommandEncoder *cmdEncoder, 1301 const ClearRectParams ¶ms) 1302{ 1303 // Generate render pipeline state 1304 id<MTLRenderPipelineState> renderPipelineState = 1305 getClearRenderPipelineState(context, cmdEncoder, params); 1306 if (renderPipelineState == nil) 1307 { 1308 // Return early 1309 return angle::Result::Stop; 1310 } 1311 ASSERT(renderPipelineState); 1312 // Setup states 1313 SetupFullscreenQuadDrawCommonStates(cmdEncoder); 1314 cmdEncoder->setRenderPipelineState(renderPipelineState); 1315 1316 id<MTLDepthStencilState> dsState = getClearDepthStencilState(context, params); 1317 cmdEncoder->setDepthStencilState(dsState).setStencilRefVal(params.clearStencil.value()); 1318 1319 // Viewports 1320 MTLViewport viewport; 1321 MTLScissorRect scissorRect; 1322 1323 viewport = GetViewport(params.clearArea, params.dstTextureSize.height, params.flipY); 1324 1325 scissorRect = GetScissorRect(params.clearArea, params.dstTextureSize.height, params.flipY); 1326 1327 cmdEncoder->setViewport(viewport); 1328 cmdEncoder->setScissorRect(scissorRect); 1329 1330 // uniform 1331 ClearParamsUniform uniformParams; 1332 const ClearColorValue &clearValue = params.clearColor.value(); 1333 // ClearColorValue is an int, uint, float union so it's safe to use only floats. 1334 // The Shader will do the bit cast based on appropriate format type. 1335 // See shaders/clear.metal (3 variants ClearFloatFS, ClearIntFS and ClearUIntFS each does the 1336 // appropriate bit cast) 1337 ASSERT(sizeof(uniformParams.clearColor) == clearValue.getValueBytes().size()); 1338 std::memcpy(uniformParams.clearColor, clearValue.getValueBytes().data(), 1339 clearValue.getValueBytes().size()); 1340 uniformParams.clearDepth = params.clearDepth.value(); 1341 1342 cmdEncoder->setVertexData(uniformParams, 0); 1343 cmdEncoder->setFragmentData(uniformParams, 0); 1344 return angle::Result::Continue; 1345} 1346 1347angle::Result ClearUtils::clearWithDraw(const gl::Context *context, 1348 RenderCommandEncoder *cmdEncoder, 1349 const ClearRectParams ¶ms) 1350{ 1351 ClearRectParams overridedParams = params; 1352 // Make sure we don't clear attachment that doesn't exist 1353 const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); 1354 if (renderPassDesc.numColorAttachments == 0) 1355 { 1356 overridedParams.clearColor.reset(); 1357 } 1358 if (!renderPassDesc.depthAttachment.texture) 1359 { 1360 overridedParams.clearDepth.reset(); 1361 } 1362 if (!renderPassDesc.stencilAttachment.texture) 1363 { 1364 overridedParams.clearStencil.reset(); 1365 } 1366 1367 if (!overridedParams.clearColor.valid() && !overridedParams.clearDepth.valid() && 1368 !overridedParams.clearStencil.valid()) 1369 { 1370 return angle::Result::Continue; 1371 } 1372 ContextMtl *contextMtl = GetImpl(context); 1373 ANGLE_TRY(setupClearWithDraw(context, cmdEncoder, overridedParams)); 1374 1375 angle::Result result; 1376 { 1377 // Need to disable occlusion query, otherwise clearing will affect the occlusion counting 1378 ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result); 1379 // Draw the screen aligned triangle 1380 cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3); 1381 } 1382 1383 // Invalidate current context's state 1384 contextMtl->invalidateState(context); 1385 1386 return result; 1387} 1388 1389// ColorBlitUtils implementation 1390ColorBlitUtils::ColorBlitUtils(const std::string &fragmentShaderName) 1391 : mFragmentShaderName(fragmentShaderName) 1392{} 1393 1394ColorBlitUtils::ColorBlitUtils(const ColorBlitUtils &src) : ColorBlitUtils(src.mFragmentShaderName) 1395{} 1396 1397void ColorBlitUtils::onDestroy() 1398{ 1399 ClearRenderPipelineCache2DArray(&mBlitRenderPipelineCache); 1400 ClearRenderPipelineCache2DArray(&mBlitPremultiplyAlphaRenderPipelineCache); 1401 ClearRenderPipelineCache2DArray(&mBlitUnmultiplyAlphaRenderPipelineCache); 1402} 1403 1404void ColorBlitUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, 1405 uint32_t numOutputs, 1406 int alphaPremultiplyType, 1407 int textureType, 1408 RenderPipelineCache *cacheOut) 1409{ 1410 RenderPipelineCache &pipelineCache = *cacheOut; 1411 if (pipelineCache.getVertexShader() && pipelineCache.getFragmentShader()) 1412 { 1413 // Already initialized. 1414 return; 1415 } 1416 1417 ANGLE_MTL_OBJC_SCOPE 1418 { 1419 NSError *err = nil; 1420 id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib(); 1421 id<MTLFunction> vertexShader = 1422 [[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE]; 1423 MTLFunctionConstantValues *funcConstants = 1424 [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1425 1426 constexpr BOOL multiplyAlphaFlags[][2] = {// premultiply, unmultiply 1427 1428 // Normal blit 1429 {NO, NO}, 1430 // Blit premultiply-alpha 1431 {YES, NO}, 1432 // Blit unmultiply alpha 1433 {NO, YES}}; 1434 1435 // Set alpha multiply flags 1436 [funcConstants setConstantValue:&multiplyAlphaFlags[alphaPremultiplyType][0] 1437 type:MTLDataTypeBool 1438 withName:PREMULTIPLY_ALPHA_CONSTANT_NAME]; 1439 [funcConstants setConstantValue:&multiplyAlphaFlags[alphaPremultiplyType][1] 1440 type:MTLDataTypeBool 1441 withName:UNMULTIPLY_ALPHA_CONSTANT_NAME]; 1442 1443 // We create blit shader pipeline cache for each number of color outputs. 1444 // So blit k color outputs will use mBlitRenderPipelineCache[k-1] for example: 1445 [funcConstants setConstantValue:&numOutputs 1446 type:MTLDataTypeUInt 1447 withName:NUM_COLOR_OUTPUTS_CONSTANT_NAME]; 1448 1449 // Set texture type constant 1450 [funcConstants setConstantValue:&textureType 1451 type:MTLDataTypeInt 1452 withName:SOURCE_TEXTURE_TYPE_CONSTANT_NAME]; 1453 1454 id<MTLFunction> fragmentShader = [[shaderLib 1455 newFunctionWithName:[NSString stringWithUTF8String:mFragmentShaderName.c_str()] 1456 constantValues:funcConstants 1457 error:&err] ANGLE_MTL_AUTORELEASE]; 1458 1459 ASSERT(vertexShader); 1460 ASSERT(fragmentShader); 1461 pipelineCache.setVertexShader(ctx, vertexShader); 1462 pipelineCache.setFragmentShader(ctx, fragmentShader); 1463 } 1464} 1465 1466id<MTLRenderPipelineState> ColorBlitUtils::getColorBlitRenderPipelineState( 1467 const gl::Context *context, 1468 RenderCommandEncoder *cmdEncoder, 1469 const ColorBlitParams ¶ms) 1470{ 1471 ContextMtl *contextMtl = GetImpl(context); 1472 RenderPipelineDesc pipelineDesc; 1473 const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); 1474 1475 renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor); 1476 1477 // Disable blit for some outputs that are not enabled 1478 pipelineDesc.outputDescriptor.updateEnabledDrawBuffers(params.enabledBuffers); 1479 1480 pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle; 1481 1482 RenderPipelineCache *pipelineCache; 1483 int alphaPremultiplyType; 1484 uint32_t nOutputIndex = renderPassDesc.numColorAttachments - 1; 1485 int textureType = GetShaderTextureType(params.src); 1486 if (params.unpackPremultiplyAlpha == params.unpackUnmultiplyAlpha) 1487 { 1488 alphaPremultiplyType = 0; 1489 pipelineCache = &mBlitRenderPipelineCache[nOutputIndex][textureType]; 1490 } 1491 else if (params.unpackPremultiplyAlpha) 1492 { 1493 alphaPremultiplyType = 1; 1494 pipelineCache = &mBlitPremultiplyAlphaRenderPipelineCache[nOutputIndex][textureType]; 1495 } 1496 else 1497 { 1498 alphaPremultiplyType = 2; 1499 pipelineCache = &mBlitUnmultiplyAlphaRenderPipelineCache[nOutputIndex][textureType]; 1500 } 1501 1502 ensureRenderPipelineStateCacheInitialized(contextMtl, renderPassDesc.numColorAttachments, 1503 alphaPremultiplyType, textureType, pipelineCache); 1504 1505 return pipelineCache->getRenderPipelineState(contextMtl, pipelineDesc); 1506} 1507 1508angle::Result ColorBlitUtils::setupColorBlitWithDraw(const gl::Context *context, 1509 RenderCommandEncoder *cmdEncoder, 1510 const ColorBlitParams ¶ms) 1511{ 1512 ASSERT(cmdEncoder->renderPassDesc().numColorAttachments >= 1 && params.src); 1513 1514 ContextMtl *contextMtl = mtl::GetImpl(context); 1515 1516 // Generate render pipeline state 1517 id<MTLRenderPipelineState> renderPipelineState = 1518 getColorBlitRenderPipelineState(context, cmdEncoder, params); 1519 ASSERT(renderPipelineState); 1520 if (!renderPipelineState) 1521 { 1522 // return early 1523 return angle::Result::Stop; 1524 } 1525 // Setup states 1526 cmdEncoder->setRenderPipelineState(renderPipelineState); 1527 cmdEncoder->setDepthStencilState( 1528 contextMtl->getDisplay()->getStateCache().getNullDepthStencilState( 1529 contextMtl->getMetalDevice())); 1530 1531 SetupCommonBlitWithDrawStates(context, cmdEncoder, params, true); 1532 1533 // Set sampler state 1534 SamplerDesc samplerDesc; 1535 samplerDesc.reset(); 1536 samplerDesc.minFilter = samplerDesc.magFilter = GetFilter(params.filter); 1537 1538 cmdEncoder->setFragmentSamplerState(contextMtl->getDisplay()->getStateCache().getSamplerState( 1539 contextMtl->getMetalDevice(), samplerDesc), 1540 0, FLT_MAX, 0); 1541 return angle::Result::Continue; 1542} 1543 1544angle::Result ColorBlitUtils::blitColorWithDraw(const gl::Context *context, 1545 RenderCommandEncoder *cmdEncoder, 1546 const ColorBlitParams ¶ms) 1547{ 1548 if (!params.src) 1549 { 1550 return angle::Result::Continue; 1551 } 1552 ContextMtl *contextMtl = GetImpl(context); 1553 ANGLE_TRY(setupColorBlitWithDraw(context, cmdEncoder, params)); 1554 1555 angle::Result result; 1556 { 1557 // Need to disable occlusion query, otherwise blitting will affect the occlusion counting 1558 ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result); 1559 // Draw the screen aligned triangle 1560 cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3); 1561 } 1562 1563 // Invalidate current context's state 1564 contextMtl->invalidateState(context); 1565 1566 return result; 1567} 1568 1569// DepthStencilBlitUtils implementation 1570void DepthStencilBlitUtils::onDestroy() 1571{ 1572 ClearRenderPipelineCacheArray(&mDepthBlitRenderPipelineCache); 1573 ClearRenderPipelineCacheArray(&mStencilBlitRenderPipelineCache); 1574 ClearRenderPipelineCache2DArray(&mDepthStencilBlitRenderPipelineCache); 1575 1576 ClearPipelineStateArray(&mStencilBlitToBufferComPipelineCache); 1577 1578 mStencilCopyBuffer = nullptr; 1579} 1580 1581void DepthStencilBlitUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, 1582 int sourceDepthTextureType, 1583 int sourceStencilTextureType, 1584 RenderPipelineCache *cacheOut) 1585{ 1586 RenderPipelineCache &cache = *cacheOut; 1587 if (cache.getVertexShader() && cache.getFragmentShader()) 1588 { 1589 // Already initialized. 1590 return; 1591 } 1592 1593 ANGLE_MTL_OBJC_SCOPE 1594 { 1595 NSError *err = nil; 1596 id<MTLLibrary> shaderLib = ctx->getDisplay()->getDefaultShadersLib(); 1597 id<MTLFunction> vertexShader = 1598 [[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE]; 1599 MTLFunctionConstantValues *funcConstants = 1600 [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1601 1602 NSString *shaderName; 1603 if (sourceDepthTextureType != -1 && sourceStencilTextureType != -1) 1604 { 1605 shaderName = @"blitDepthStencilFS"; 1606 } 1607 else if (sourceDepthTextureType != -1) 1608 { 1609 shaderName = @"blitDepthFS"; 1610 } 1611 else 1612 { 1613 shaderName = @"blitStencilFS"; 1614 } 1615 1616 if (sourceDepthTextureType != -1) 1617 { 1618 [funcConstants setConstantValue:&sourceDepthTextureType 1619 type:MTLDataTypeInt 1620 withName:SOURCE_TEXTURE_TYPE_CONSTANT_NAME]; 1621 } 1622 if (sourceStencilTextureType != -1) 1623 { 1624 1625 [funcConstants setConstantValue:&sourceStencilTextureType 1626 type:MTLDataTypeInt 1627 withName:SOURCE_TEXTURE2_TYPE_CONSTANT_NAME]; 1628 } 1629 1630 id<MTLFunction> fragmentShader = 1631 [[shaderLib newFunctionWithName:shaderName constantValues:funcConstants 1632 error:&err] ANGLE_MTL_AUTORELEASE]; 1633 ASSERT(fragmentShader); 1634 1635 cache.setVertexShader(ctx, vertexShader); 1636 cache.setFragmentShader(ctx, fragmentShader); 1637 } 1638} 1639 1640id<MTLComputePipelineState> DepthStencilBlitUtils::getStencilToBufferComputePipelineState( 1641 ContextMtl *contextMtl, 1642 const StencilBlitViaBufferParams ¶ms) 1643{ 1644 int sourceStencilTextureType = GetShaderTextureType(params.srcStencil); 1645 AutoObjCPtr<id<MTLComputePipelineState>> &cache = 1646 mStencilBlitToBufferComPipelineCache[sourceStencilTextureType]; 1647 if (cache) 1648 { 1649 return cache; 1650 } 1651 1652 ANGLE_MTL_OBJC_SCOPE 1653 { 1654 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1655 1656 [funcConstants setConstantValue:&sourceStencilTextureType 1657 type:MTLDataTypeInt 1658 withName:SOURCE_TEXTURE2_TYPE_CONSTANT_NAME]; 1659 1660 EnsureSpecializedComputePipelineInitialized(contextMtl, @"blitStencilToBufferCS", 1661 funcConstants, &cache); 1662 } 1663 1664 return cache; 1665} 1666 1667id<MTLRenderPipelineState> DepthStencilBlitUtils::getDepthStencilBlitRenderPipelineState( 1668 const gl::Context *context, 1669 RenderCommandEncoder *cmdEncoder, 1670 const DepthStencilBlitParams ¶ms) 1671{ 1672 ContextMtl *contextMtl = GetImpl(context); 1673 RenderPipelineDesc pipelineDesc; 1674 const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc(); 1675 1676 renderPassDesc.populateRenderPipelineOutputDesc(&pipelineDesc.outputDescriptor); 1677 1678 // Disable all color outputs 1679 pipelineDesc.outputDescriptor.updateEnabledDrawBuffers(gl::DrawBufferMask()); 1680 1681 pipelineDesc.inputPrimitiveTopology = kPrimitiveTopologyClassTriangle; 1682 1683 RenderPipelineCache *pipelineCache; 1684 1685 int depthTextureType = GetShaderTextureType(params.src); 1686 int stencilTextureType = GetShaderTextureType(params.srcStencil); 1687 if (params.src && params.srcStencil) 1688 { 1689 pipelineCache = &mDepthStencilBlitRenderPipelineCache[depthTextureType][stencilTextureType]; 1690 } 1691 else if (params.src) 1692 { 1693 // Only depth blit 1694 pipelineCache = &mDepthBlitRenderPipelineCache[depthTextureType]; 1695 } 1696 else 1697 { 1698 // Only stencil blit 1699 pipelineCache = &mStencilBlitRenderPipelineCache[stencilTextureType]; 1700 } 1701 1702 ensureRenderPipelineStateCacheInitialized(contextMtl, depthTextureType, stencilTextureType, 1703 pipelineCache); 1704 1705 return pipelineCache->getRenderPipelineState(contextMtl, pipelineDesc); 1706} 1707 1708angle::Result DepthStencilBlitUtils::setupDepthStencilBlitWithDraw( 1709 const gl::Context *context, 1710 RenderCommandEncoder *cmdEncoder, 1711 const DepthStencilBlitParams ¶ms) 1712{ 1713 ContextMtl *contextMtl = mtl::GetImpl(context); 1714 1715 ASSERT(params.src || params.srcStencil); 1716 1717 SetupCommonBlitWithDrawStates(context, cmdEncoder, params, false); 1718 1719 // Generate render pipeline state 1720 id<MTLRenderPipelineState> renderPipelineState = 1721 getDepthStencilBlitRenderPipelineState(context, cmdEncoder, params); 1722 if (!renderPipelineState) 1723 { 1724 return angle::Result::Stop; 1725 } 1726 // Setup states 1727 cmdEncoder->setRenderPipelineState(renderPipelineState); 1728 1729 // Depth stencil state 1730 mtl::DepthStencilDesc dsStateDesc; 1731 dsStateDesc.reset(); 1732 dsStateDesc.depthCompareFunction = MTLCompareFunctionAlways; 1733 1734 if (params.src) 1735 { 1736 // Enable depth write 1737 dsStateDesc.depthWriteEnabled = true; 1738 } 1739 else 1740 { 1741 // Disable depth write 1742 dsStateDesc.depthWriteEnabled = false; 1743 } 1744 1745 if (params.srcStencil) 1746 { 1747 cmdEncoder->setFragmentTexture(params.srcStencil, 1); 1748 1749 if (!contextMtl->getDisplay()->getFeatures().hasShaderStencilOutput.enabled) 1750 { 1751 // Hardware must support stencil writing directly in shader. 1752 UNREACHABLE(); 1753 } 1754 // Enable stencil write to framebuffer 1755 dsStateDesc.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionAlways; 1756 dsStateDesc.backFaceStencil.stencilCompareFunction = MTLCompareFunctionAlways; 1757 1758 dsStateDesc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace; 1759 dsStateDesc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationReplace; 1760 1761 dsStateDesc.frontFaceStencil.writeMask = kStencilMaskAll; 1762 dsStateDesc.backFaceStencil.writeMask = kStencilMaskAll; 1763 } 1764 1765 cmdEncoder->setDepthStencilState(contextMtl->getDisplay()->getStateCache().getDepthStencilState( 1766 contextMtl->getMetalDevice(), dsStateDesc)); 1767 return angle::Result::Continue; 1768} 1769 1770angle::Result DepthStencilBlitUtils::blitDepthStencilWithDraw(const gl::Context *context, 1771 RenderCommandEncoder *cmdEncoder, 1772 const DepthStencilBlitParams ¶ms) 1773{ 1774 if (!params.src && !params.srcStencil) 1775 { 1776 return angle::Result::Continue; 1777 } 1778 ContextMtl *contextMtl = GetImpl(context); 1779 1780 ANGLE_TRY(setupDepthStencilBlitWithDraw(context, cmdEncoder, params)); 1781 1782 angle::Result result; 1783 { 1784 // Need to disable occlusion query, otherwise blitting will affect the occlusion counting 1785 ScopedDisableOcclusionQuery disableOcclusionQuery(contextMtl, cmdEncoder, &result); 1786 // Draw the screen aligned triangle 1787 cmdEncoder->draw(MTLPrimitiveTypeTriangle, 0, 3); 1788 } 1789 1790 // Invalidate current context's state 1791 contextMtl->invalidateState(context); 1792 1793 return result; 1794} 1795 1796angle::Result DepthStencilBlitUtils::blitStencilViaCopyBuffer( 1797 const gl::Context *context, 1798 const StencilBlitViaBufferParams ¶ms) 1799{ 1800 // Depth texture must be omitted. 1801 ASSERT(!params.src); 1802 if (!params.srcStencil || !params.dstStencil) 1803 { 1804 return angle::Result::Continue; 1805 } 1806 ContextMtl *contextMtl = GetImpl(context); 1807 1808 // Create intermediate buffer. 1809 uint32_t bufferRequiredRowPitch = 1810 static_cast<uint32_t>(params.dstRect.width) * params.dstStencil->samples(); 1811 uint32_t bufferRequiredSize = 1812 bufferRequiredRowPitch * static_cast<uint32_t>(params.dstRect.height); 1813 if (!mStencilCopyBuffer || mStencilCopyBuffer->size() < bufferRequiredSize) 1814 { 1815 ANGLE_TRY(Buffer::MakeBuffer(contextMtl, bufferRequiredSize, nullptr, &mStencilCopyBuffer)); 1816 } 1817 1818 // Copy stencil data to buffer via compute shader. We cannot use blit command since blit command 1819 // doesn't support multisample resolve and scaling. 1820 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 1821 ASSERT(cmdEncoder); 1822 1823 id<MTLComputePipelineState> pipeline = 1824 getStencilToBufferComputePipelineState(contextMtl, params); 1825 1826 cmdEncoder->setComputePipelineState(pipeline); 1827 1828 float u0, v0, u1, v1; 1829 bool unpackFlipX = params.unpackFlipX; 1830 bool unpackFlipY = params.unpackFlipY; 1831 if (params.dstFlipX) 1832 { 1833 unpackFlipX = !unpackFlipX; 1834 } 1835 if (params.dstFlipY) 1836 { 1837 unpackFlipY = !unpackFlipY; 1838 } 1839 GetBlitTexCoords(params.srcNormalizedCoords, params.srcYFlipped, unpackFlipX, unpackFlipY, &u0, 1840 &v0, &u1, &v1); 1841 1842 BlitStencilToBufferParamsUniform uniform; 1843 uniform.srcTexCoordSteps[0] = (u1 - u0) / params.dstRect.width; 1844 uniform.srcTexCoordSteps[1] = (v1 - v0) / params.dstRect.height; 1845 uniform.srcStartTexCoords[0] = u0 + uniform.srcTexCoordSteps[0] * 0.5f; 1846 uniform.srcStartTexCoords[1] = v0 + uniform.srcTexCoordSteps[1] * 0.5f; 1847 uniform.srcLevel = params.srcLevel.get(); 1848 uniform.srcLayer = params.srcLayer; 1849 uniform.dstSize[0] = params.dstRect.width; 1850 uniform.dstSize[1] = params.dstRect.height; 1851 uniform.dstBufferRowPitch = bufferRequiredRowPitch; 1852 uniform.resolveMS = params.dstStencil->samples() == 1; 1853 1854 cmdEncoder->setTexture(params.srcStencil, 1); 1855 1856 cmdEncoder->setData(uniform, 0); 1857 cmdEncoder->setBufferForWrite(mStencilCopyBuffer, 0, 1); 1858 1859 NSUInteger w = pipeline.threadExecutionWidth; 1860 MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1); 1861 DispatchCompute(contextMtl, cmdEncoder, /** allowNonUniform */ true, 1862 MTLSizeMake(params.dstRect.width, params.dstRect.height, 1), 1863 threadsPerThreadgroup); 1864 1865 // Copy buffer to real destination texture 1866 ASSERT(params.dstStencil->textureType() != MTLTextureType3D); 1867 1868 mtl::BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder(); 1869 1870 // Only copy the scissored area of the buffer. 1871 MTLScissorRect viewportRectMtl = 1872 GetScissorRect(params.dstRect, params.dstTextureSize.height, params.dstFlipY); 1873 MTLScissorRect scissorRectMtl = 1874 GetScissorRect(params.dstScissorRect, params.dstTextureSize.height, params.dstFlipY); 1875 1876 uint32_t dx = static_cast<uint32_t>(scissorRectMtl.x - viewportRectMtl.x); 1877 uint32_t dy = static_cast<uint32_t>(scissorRectMtl.y - viewportRectMtl.y); 1878 1879 uint32_t bufferStartReadableOffset = dx + bufferRequiredRowPitch * dy; 1880 blitEncoder->copyBufferToTexture( 1881 mStencilCopyBuffer, bufferStartReadableOffset, bufferRequiredRowPitch, 0, 1882 MTLSizeMake(scissorRectMtl.width, scissorRectMtl.height, 1), params.dstStencil, 1883 params.dstStencilLayer, params.dstStencilLevel, 1884 MTLOriginMake(scissorRectMtl.x, scissorRectMtl.y, 0), 1885 params.dstPackedDepthStencilFormat ? MTLBlitOptionStencilFromDepthStencil 1886 : MTLBlitOptionNone); 1887 1888 return angle::Result::Continue; 1889} 1890 1891// IndexGeneratorUtils implementation 1892void IndexGeneratorUtils::onDestroy() 1893{ 1894 ClearPipelineState2DArray(&mIndexConversionPipelineCaches); 1895 ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches); 1896 ClearPipelineState2DArray(&mLineLoopFromElemArrayGeneratorPipelineCaches); 1897 1898 mTriFanFromArraysGeneratorPipeline = nil; 1899 mLineLoopFromArraysGeneratorPipeline = nil; 1900} 1901 1902AutoObjCPtr<id<MTLComputePipelineState>> IndexGeneratorUtils::getIndexConversionPipeline( 1903 ContextMtl *contextMtl, 1904 gl::DrawElementsType srcType, 1905 uint32_t srcOffset) 1906{ 1907 size_t elementSize = gl::GetDrawElementsTypeSize(srcType); 1908 BOOL aligned = (srcOffset % elementSize) == 0; 1909 int srcTypeKey = static_cast<int>(srcType); 1910 AutoObjCPtr<id<MTLComputePipelineState>> &cache = 1911 mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0]; 1912 1913 if (!cache) 1914 { 1915 ANGLE_MTL_OBJC_SCOPE 1916 { 1917 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1918 1919 [funcConstants setConstantValue:&aligned 1920 type:MTLDataTypeBool 1921 withName:SOURCE_BUFFER_ALIGNED_CONSTANT_NAME]; 1922 1923 NSString *shaderName = nil; 1924 switch (srcType) 1925 { 1926 case gl::DrawElementsType::UnsignedByte: 1927 // No need for specialized shader 1928 funcConstants = nil; 1929 shaderName = @"convertIndexU8ToU16"; 1930 break; 1931 case gl::DrawElementsType::UnsignedShort: 1932 shaderName = @"convertIndexU16"; 1933 break; 1934 case gl::DrawElementsType::UnsignedInt: 1935 shaderName = @"convertIndexU32"; 1936 break; 1937 default: 1938 UNREACHABLE(); 1939 } 1940 1941 EnsureSpecializedComputePipelineInitialized(contextMtl, shaderName, funcConstants, 1942 &cache); 1943 } 1944 } 1945 1946 return cache; 1947} 1948 1949AutoObjCPtr<id<MTLComputePipelineState>> 1950IndexGeneratorUtils::getIndicesFromElemArrayGeneratorPipeline( 1951 ContextMtl *contextMtl, 1952 gl::DrawElementsType srcType, 1953 uint32_t srcOffset, 1954 NSString *shaderName, 1955 IndexConversionPipelineArray *pipelineCacheArray) 1956{ 1957 size_t elementSize = gl::GetDrawElementsTypeSize(srcType); 1958 BOOL aligned = (srcOffset % elementSize) == 0; 1959 int srcTypeKey = static_cast<int>(srcType); 1960 1961 AutoObjCPtr<id<MTLComputePipelineState>> &cache = 1962 (*pipelineCacheArray)[srcTypeKey][aligned ? 1 : 0]; 1963 1964 if (!cache) 1965 { 1966 ANGLE_MTL_OBJC_SCOPE 1967 { 1968 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 1969 1970 bool isU8 = false; 1971 bool isU16 = false; 1972 bool isU32 = false; 1973 1974 switch (srcType) 1975 { 1976 case gl::DrawElementsType::UnsignedByte: 1977 isU8 = true; 1978 break; 1979 case gl::DrawElementsType::UnsignedShort: 1980 isU16 = true; 1981 break; 1982 case gl::DrawElementsType::UnsignedInt: 1983 isU32 = true; 1984 break; 1985 default: 1986 UNREACHABLE(); 1987 } 1988 1989 [funcConstants setConstantValue:&aligned 1990 type:MTLDataTypeBool 1991 withName:SOURCE_BUFFER_ALIGNED_CONSTANT_NAME]; 1992 [funcConstants setConstantValue:&isU8 1993 type:MTLDataTypeBool 1994 withName:SOURCE_IDX_IS_U8_CONSTANT_NAME]; 1995 [funcConstants setConstantValue:&isU16 1996 type:MTLDataTypeBool 1997 withName:SOURCE_IDX_IS_U16_CONSTANT_NAME]; 1998 [funcConstants setConstantValue:&isU32 1999 type:MTLDataTypeBool 2000 withName:SOURCE_IDX_IS_U32_CONSTANT_NAME]; 2001 2002 EnsureSpecializedComputePipelineInitialized(contextMtl, shaderName, funcConstants, 2003 &cache); 2004 } 2005 } 2006 2007 return cache; 2008} 2009 2010void IndexGeneratorUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl *contextMtl) 2011{ 2012 EnsureComputePipelineInitialized(contextMtl, @"genTriFanIndicesFromArray", 2013 &mTriFanFromArraysGeneratorPipeline); 2014} 2015 2016void IndexGeneratorUtils::ensureLineLoopFromArrayGeneratorInitialized(ContextMtl *contextMtl) 2017{ 2018 EnsureComputePipelineInitialized(contextMtl, @"genLineLoopIndicesFromArray", 2019 &mLineLoopFromArraysGeneratorPipeline); 2020} 2021 2022angle::Result IndexGeneratorUtils::convertIndexBufferGPU(ContextMtl *contextMtl, 2023 const IndexConversionParams ¶ms) 2024{ 2025 ComputeCommandEncoder *cmdEncoder = contextMtl->getIndexPreprocessingCommandEncoder(); 2026 ASSERT(cmdEncoder); 2027 2028 AutoObjCPtr<id<MTLComputePipelineState>> pipelineState = 2029 getIndexConversionPipeline(contextMtl, params.srcType, params.srcOffset); 2030 2031 ASSERT(pipelineState); 2032 2033 cmdEncoder->setComputePipelineState(pipelineState); 2034 2035 ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0); 2036 2037 IndexConversionUniform uniform; 2038 uniform.srcOffset = params.srcOffset; 2039 uniform.indexCount = params.indexCount; 2040 uniform.primitiveRestartEnabled = params.primitiveRestartEnabled; 2041 2042 cmdEncoder->setData(uniform, 0); 2043 cmdEncoder->setBuffer(params.srcBuffer, 0, 1); 2044 cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2); 2045 2046 DispatchCompute(contextMtl, cmdEncoder, pipelineState, params.indexCount); 2047 2048 return angle::Result::Continue; 2049} 2050 2051angle::Result IndexGeneratorUtils::generateTriFanBufferFromArrays( 2052 ContextMtl *contextMtl, 2053 const TriFanOrLineLoopFromArrayParams ¶ms) 2054{ 2055 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2056 ASSERT(cmdEncoder); 2057 ensureTriFanFromArrayGeneratorInitialized(contextMtl); 2058 2059 ASSERT(params.vertexCount > 2); 2060 2061 cmdEncoder->setComputePipelineState(mTriFanFromArraysGeneratorPipeline); 2062 2063 ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0); 2064 2065 TriFanOrLineLoopArrayParams uniform; 2066 2067 uniform.firstVertex = params.firstVertex; 2068 uniform.vertexCount = params.vertexCount - 2; 2069 2070 cmdEncoder->setData(uniform, 0); 2071 cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2); 2072 2073 DispatchCompute(contextMtl, cmdEncoder, mTriFanFromArraysGeneratorPipeline, 2074 uniform.vertexCount); 2075 2076 return angle::Result::Continue; 2077} 2078 2079angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArray( 2080 ContextMtl *contextMtl, 2081 const IndexGenerationParams ¶ms, 2082 uint32_t *indicesGenerated) 2083{ 2084 const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray(); 2085 const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); 2086 if (elementBuffer) 2087 { 2088 BufferMtl *elementBufferMtl = GetImpl(elementBuffer); 2089 size_t srcOffset = reinterpret_cast<size_t>(params.indices); 2090 ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(), 2091 "Index offset is too large", GL_INVALID_VALUE); 2092 if (params.primitiveRestartEnabled || 2093 (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled && 2094 contextMtl->getRenderCommandEncoder())) 2095 { 2096 IndexGenerationParams cpuPathParams = params; 2097 cpuPathParams.indices = 2098 elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset; 2099 return generateTriFanBufferFromElementsArrayCPU(contextMtl, cpuPathParams, 2100 indicesGenerated); 2101 } 2102 else 2103 { 2104 return generateTriFanBufferFromElementsArrayGPU( 2105 contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(), 2106 static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset); 2107 } 2108 } 2109 else 2110 { 2111 return generateTriFanBufferFromElementsArrayCPU(contextMtl, params, indicesGenerated); 2112 } 2113} 2114 2115angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayGPU( 2116 ContextMtl *contextMtl, 2117 gl::DrawElementsType srcType, 2118 uint32_t indexCount, 2119 const BufferRef &srcBuffer, 2120 uint32_t srcOffset, 2121 const BufferRef &dstBuffer, 2122 // Must be multiples of kIndexBufferOffsetAlignment 2123 uint32_t dstOffset) 2124{ 2125 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2126 ASSERT(cmdEncoder); 2127 2128 AutoObjCPtr<id<MTLComputePipelineState>> pipelineState = 2129 getIndicesFromElemArrayGeneratorPipeline(contextMtl, srcType, srcOffset, 2130 @"genTriFanIndicesFromElements", 2131 &mTriFanFromElemArrayGeneratorPipelineCaches); 2132 2133 ASSERT(pipelineState); 2134 2135 cmdEncoder->setComputePipelineState(pipelineState); 2136 2137 ASSERT((dstOffset % kIndexBufferOffsetAlignment) == 0); 2138 ASSERT(indexCount > 2); 2139 2140 IndexConversionUniform uniform; 2141 uniform.srcOffset = srcOffset; 2142 uniform.indexCount = indexCount - 2; // Only start from the 3rd element. 2143 2144 cmdEncoder->setData(uniform, 0); 2145 cmdEncoder->setBuffer(srcBuffer, 0, 1); 2146 cmdEncoder->setBufferForWrite(dstBuffer, dstOffset, 2); 2147 2148 DispatchCompute(contextMtl, cmdEncoder, pipelineState, uniform.indexCount); 2149 2150 return angle::Result::Continue; 2151} 2152 2153angle::Result IndexGeneratorUtils::generateTriFanBufferFromElementsArrayCPU( 2154 ContextMtl *contextMtl, 2155 const IndexGenerationParams ¶ms, 2156 uint32_t *genIndices) 2157{ 2158 switch (params.srcType) 2159 { 2160 case gl::DrawElementsType::UnsignedByte: 2161 return GenTriFanFromClientElements(contextMtl, params.indexCount, 2162 params.primitiveRestartEnabled, 2163 static_cast<const uint8_t *>(params.indices), 2164 params.dstBuffer, params.dstOffset, genIndices); 2165 case gl::DrawElementsType::UnsignedShort: 2166 return GenTriFanFromClientElements(contextMtl, params.indexCount, 2167 params.primitiveRestartEnabled, 2168 static_cast<const uint16_t *>(params.indices), 2169 params.dstBuffer, params.dstOffset, genIndices); 2170 case gl::DrawElementsType::UnsignedInt: 2171 return GenTriFanFromClientElements(contextMtl, params.indexCount, 2172 params.primitiveRestartEnabled, 2173 static_cast<const uint32_t *>(params.indices), 2174 params.dstBuffer, params.dstOffset, genIndices); 2175 default: 2176 UNREACHABLE(); 2177 } 2178 2179 return angle::Result::Stop; 2180} 2181 2182angle::Result IndexGeneratorUtils::generateLineLoopBufferFromArrays( 2183 ContextMtl *contextMtl, 2184 const TriFanOrLineLoopFromArrayParams ¶ms) 2185{ 2186 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2187 ASSERT(cmdEncoder); 2188 ensureLineLoopFromArrayGeneratorInitialized(contextMtl); 2189 2190 cmdEncoder->setComputePipelineState(mLineLoopFromArraysGeneratorPipeline); 2191 2192 ASSERT((params.dstOffset % kIndexBufferOffsetAlignment) == 0); 2193 2194 TriFanOrLineLoopArrayParams uniform; 2195 2196 uniform.firstVertex = params.firstVertex; 2197 uniform.vertexCount = params.vertexCount; 2198 2199 cmdEncoder->setData(uniform, 0); 2200 cmdEncoder->setBufferForWrite(params.dstBuffer, params.dstOffset, 2); 2201 2202 DispatchCompute(contextMtl, cmdEncoder, mLineLoopFromArraysGeneratorPipeline, 2203 uniform.vertexCount + 1); 2204 2205 return angle::Result::Continue; 2206} 2207 2208angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArray( 2209 ContextMtl *contextMtl, 2210 const IndexGenerationParams ¶ms, 2211 uint32_t *indicesGenerated) 2212{ 2213 const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray(); 2214 const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); 2215 if (elementBuffer) 2216 { 2217 BufferMtl *elementBufferMtl = GetImpl(elementBuffer); 2218 size_t srcOffset = reinterpret_cast<size_t>(params.indices); 2219 ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(), 2220 "Index offset is too large", GL_INVALID_VALUE); 2221 if (params.primitiveRestartEnabled || 2222 (!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled && 2223 contextMtl->getRenderCommandEncoder())) 2224 { 2225 IndexGenerationParams cpuPathParams = params; 2226 cpuPathParams.indices = 2227 elementBufferMtl->getClientShadowCopyData(contextMtl) + srcOffset; 2228 return generateLineLoopBufferFromElementsArrayCPU(contextMtl, cpuPathParams, 2229 indicesGenerated); 2230 } 2231 else 2232 { 2233 *indicesGenerated = params.indexCount + 1; 2234 return generateLineLoopBufferFromElementsArrayGPU( 2235 contextMtl, params.srcType, params.indexCount, elementBufferMtl->getCurrentBuffer(), 2236 static_cast<uint32_t>(srcOffset), params.dstBuffer, params.dstOffset); 2237 } 2238 } 2239 else 2240 { 2241 return generateLineLoopBufferFromElementsArrayCPU(contextMtl, params, indicesGenerated); 2242 } 2243} 2244 2245angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArrayGPU( 2246 ContextMtl *contextMtl, 2247 gl::DrawElementsType srcType, 2248 uint32_t indexCount, 2249 const BufferRef &srcBuffer, 2250 uint32_t srcOffset, 2251 const BufferRef &dstBuffer, 2252 // Must be multiples of kIndexBufferOffsetAlignment 2253 uint32_t dstOffset) 2254{ 2255 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2256 ASSERT(cmdEncoder); 2257 2258 AutoObjCPtr<id<MTLComputePipelineState>> pipelineState = 2259 getIndicesFromElemArrayGeneratorPipeline(contextMtl, srcType, srcOffset, 2260 @"genLineLoopIndicesFromElements", 2261 &mLineLoopFromElemArrayGeneratorPipelineCaches); 2262 2263 ASSERT(pipelineState); 2264 2265 cmdEncoder->setComputePipelineState(pipelineState); 2266 2267 ASSERT((dstOffset % kIndexBufferOffsetAlignment) == 0); 2268 ASSERT(indexCount >= 2); 2269 2270 IndexConversionUniform uniform; 2271 uniform.srcOffset = srcOffset; 2272 uniform.indexCount = indexCount; 2273 2274 cmdEncoder->setData(uniform, 0); 2275 cmdEncoder->setBuffer(srcBuffer, 0, 1); 2276 cmdEncoder->setBufferForWrite(dstBuffer, dstOffset, 2); 2277 2278 DispatchCompute(contextMtl, cmdEncoder, pipelineState, uniform.indexCount + 1); 2279 2280 return angle::Result::Continue; 2281} 2282 2283angle::Result IndexGeneratorUtils::generateLineLoopBufferFromElementsArrayCPU( 2284 ContextMtl *contextMtl, 2285 const IndexGenerationParams ¶ms, 2286 uint32_t *indicesGenerated) 2287{ 2288 switch (params.srcType) 2289 { 2290 case gl::DrawElementsType::UnsignedByte: 2291 return GenLineLoopFromClientElements( 2292 contextMtl, params.indexCount, params.primitiveRestartEnabled, 2293 static_cast<const uint8_t *>(params.indices), params.dstBuffer, params.dstOffset, 2294 indicesGenerated); 2295 case gl::DrawElementsType::UnsignedShort: 2296 return GenLineLoopFromClientElements( 2297 contextMtl, params.indexCount, params.primitiveRestartEnabled, 2298 static_cast<const uint16_t *>(params.indices), params.dstBuffer, params.dstOffset, 2299 indicesGenerated); 2300 case gl::DrawElementsType::UnsignedInt: 2301 return GenLineLoopFromClientElements( 2302 contextMtl, params.indexCount, params.primitiveRestartEnabled, 2303 static_cast<const uint32_t *>(params.indices), params.dstBuffer, params.dstOffset, 2304 indicesGenerated); 2305 default: 2306 UNREACHABLE(); 2307 } 2308 2309 return angle::Result::Stop; 2310} 2311 2312angle::Result IndexGeneratorUtils::generateLineLoopLastSegment(ContextMtl *contextMtl, 2313 uint32_t firstVertex, 2314 uint32_t lastVertex, 2315 const BufferRef &dstBuffer, 2316 uint32_t dstOffset) 2317{ 2318 uint8_t *ptr = dstBuffer->map(contextMtl) + dstOffset; 2319 2320 uint32_t indices[2] = {lastVertex, firstVertex}; 2321 memcpy(ptr, indices, sizeof(indices)); 2322 2323 dstBuffer->unmapAndFlushSubset(contextMtl, dstOffset, sizeof(indices)); 2324 2325 return angle::Result::Continue; 2326} 2327 2328angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArray( 2329 ContextMtl *contextMtl, 2330 const IndexGenerationParams ¶ms) 2331{ 2332 ASSERT(!params.primitiveRestartEnabled); 2333 const gl::VertexArray *vertexArray = contextMtl->getState().getVertexArray(); 2334 const gl::Buffer *elementBuffer = vertexArray->getElementArrayBuffer(); 2335 if (elementBuffer) 2336 { 2337 size_t srcOffset = reinterpret_cast<size_t>(params.indices); 2338 ANGLE_CHECK(contextMtl, srcOffset <= std::numeric_limits<uint32_t>::max(), 2339 "Index offset is too large", GL_INVALID_VALUE); 2340 2341 BufferMtl *bufferMtl = GetImpl(elementBuffer); 2342 std::pair<uint32_t, uint32_t> firstLast; 2343 ANGLE_TRY(bufferMtl->getFirstLastIndices(contextMtl, params.srcType, 2344 static_cast<uint32_t>(srcOffset), 2345 params.indexCount, &firstLast)); 2346 2347 return generateLineLoopLastSegment(contextMtl, firstLast.first, firstLast.second, 2348 params.dstBuffer, params.dstOffset); 2349 } 2350 else 2351 { 2352 return generateLineLoopLastSegmentFromElementsArrayCPU(contextMtl, params); 2353 } 2354} 2355 2356angle::Result IndexGeneratorUtils::generateLineLoopLastSegmentFromElementsArrayCPU( 2357 ContextMtl *contextMtl, 2358 const IndexGenerationParams ¶ms) 2359{ 2360 ASSERT(!params.primitiveRestartEnabled); 2361 2362 uint32_t first, last; 2363 2364 switch (params.srcType) 2365 { 2366 case gl::DrawElementsType::UnsignedByte: 2367 GetFirstLastIndicesFromClientElements( 2368 params.indexCount, static_cast<const uint8_t *>(params.indices), &first, &last); 2369 break; 2370 case gl::DrawElementsType::UnsignedShort: 2371 GetFirstLastIndicesFromClientElements( 2372 params.indexCount, static_cast<const uint16_t *>(params.indices), &first, &last); 2373 break; 2374 case gl::DrawElementsType::UnsignedInt: 2375 GetFirstLastIndicesFromClientElements( 2376 params.indexCount, static_cast<const uint32_t *>(params.indices), &first, &last); 2377 break; 2378 default: 2379 UNREACHABLE(); 2380 return angle::Result::Stop; 2381 } 2382 2383 return generateLineLoopLastSegment(contextMtl, first, last, params.dstBuffer, params.dstOffset); 2384} 2385 2386angle::Result IndexGeneratorUtils::generatePrimitiveRestartBuffer( 2387 ContextMtl *contextMtl, 2388 unsigned numVerticesPerPrimitive, 2389 const IndexGenerationParams ¶ms, 2390 size_t *indicesGenerated) 2391{ 2392 switch (params.srcType) 2393 { 2394 case gl::DrawElementsType::UnsignedByte: 2395 return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive, 2396 static_cast<const uint8_t *>(params.indices), 2397 params.dstBuffer, params.dstOffset, indicesGenerated); 2398 case gl::DrawElementsType::UnsignedShort: 2399 return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive, 2400 static_cast<const uint16_t *>(params.indices), 2401 params.dstBuffer, params.dstOffset, indicesGenerated); 2402 case gl::DrawElementsType::UnsignedInt: 2403 return GenPrimitiveRestartBuffer(contextMtl, params.indexCount, numVerticesPerPrimitive, 2404 static_cast<const uint32_t *>(params.indices), 2405 params.dstBuffer, params.dstOffset, indicesGenerated); 2406 default: 2407 UNREACHABLE(); 2408 return angle::Result::Stop; 2409 } 2410} 2411 2412angle::Result IndexGeneratorUtils::generatePrimitiveRestartTrianglesBuffer( 2413 ContextMtl *contextMtl, 2414 const IndexGenerationParams ¶ms, 2415 size_t *indicesGenerated) 2416{ 2417 return generatePrimitiveRestartBuffer(contextMtl, 3, params, indicesGenerated); 2418} 2419 2420angle::Result IndexGeneratorUtils::generatePrimitiveRestartLinesBuffer( 2421 ContextMtl *contextMtl, 2422 const IndexGenerationParams ¶ms, 2423 size_t *indicesGenerated) 2424{ 2425 return generatePrimitiveRestartBuffer(contextMtl, 2, params, indicesGenerated); 2426} 2427 2428angle::Result IndexGeneratorUtils::generatePrimitiveRestartPointsBuffer( 2429 ContextMtl *contextMtl, 2430 const IndexGenerationParams ¶ms, 2431 size_t *indicesGenerated) 2432{ 2433 return generatePrimitiveRestartBuffer(contextMtl, 1, params, indicesGenerated); 2434} 2435 2436// VisibilityResultUtils implementation 2437void VisibilityResultUtils::onDestroy() 2438{ 2439 ClearPipelineStateArray(&mVisibilityResultCombPipelines); 2440} 2441 2442AutoObjCPtr<id<MTLComputePipelineState>> VisibilityResultUtils::getVisibilityResultCombPipeline( 2443 ContextMtl *contextMtl, 2444 bool keepOldValue) 2445{ 2446 // There is no guarantee Objective-C's BOOL is equal to bool, so casting just in case. 2447 BOOL keepOldValueVal = keepOldValue; 2448 AutoObjCPtr<id<MTLComputePipelineState>> &cache = 2449 mVisibilityResultCombPipelines[keepOldValueVal]; 2450 if (cache) 2451 { 2452 return cache; 2453 } 2454 ANGLE_MTL_OBJC_SCOPE 2455 { 2456 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 2457 2458 [funcConstants setConstantValue:&keepOldValueVal 2459 type:MTLDataTypeBool 2460 withName:VISIBILITY_RESULT_KEEP_OLD_VAL_CONSTANT_NAME]; 2461 2462 EnsureSpecializedComputePipelineInitialized(contextMtl, @"combineVisibilityResult", 2463 funcConstants, &cache); 2464 } 2465 2466 return cache; 2467} 2468 2469void VisibilityResultUtils::combineVisibilityResult( 2470 ContextMtl *contextMtl, 2471 bool keepOldValue, 2472 const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets, 2473 const BufferRef &renderPassResultBuf, 2474 const BufferRef &finalResultBuf) 2475{ 2476 ASSERT(!renderPassResultBufOffsets.empty()); 2477 2478 if (renderPassResultBufOffsets.size() == 1 && !keepOldValue) 2479 { 2480 // Use blit command to copy directly 2481 BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder(); 2482 2483 blitEncoder->copyBuffer(renderPassResultBuf, renderPassResultBufOffsets.front(), 2484 finalResultBuf, 0, kOcclusionQueryResultSize); 2485 return; 2486 } 2487 2488 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2489 ASSERT(cmdEncoder); 2490 2491 id<MTLComputePipelineState> pipeline = 2492 getVisibilityResultCombPipeline(contextMtl, keepOldValue); 2493 cmdEncoder->setComputePipelineState(pipeline); 2494 2495 CombineVisibilityResultUniform options; 2496 // Offset is viewed as 64 bit unit in compute shader. 2497 options.startOffset = renderPassResultBufOffsets.front() / kOcclusionQueryResultSize; 2498 options.numOffsets = renderPassResultBufOffsets.size(); 2499 2500 cmdEncoder->setData(options, 0); 2501 cmdEncoder->setBuffer(renderPassResultBuf, 0, 1); 2502 cmdEncoder->setBufferForWrite(finalResultBuf, 0, 2); 2503 2504 DispatchCompute(contextMtl, cmdEncoder, pipeline, 1); 2505} 2506 2507// MipmapUtils implementation 2508void MipmapUtils::onDestroy() 2509{ 2510 m3DMipGeneratorPipeline = nil; 2511 m2DMipGeneratorPipeline = nil; 2512 m2DArrayMipGeneratorPipeline = nil; 2513 mCubeMipGeneratorPipeline = nil; 2514} 2515 2516void MipmapUtils::ensure3DMipGeneratorPipelineInitialized(ContextMtl *contextMtl) 2517{ 2518 EnsureComputePipelineInitialized(contextMtl, @"generate3DMipmaps", &m3DMipGeneratorPipeline); 2519} 2520 2521void MipmapUtils::ensure2DMipGeneratorPipelineInitialized(ContextMtl *contextMtl) 2522{ 2523 EnsureComputePipelineInitialized(contextMtl, @"generate2DMipmaps", &m2DMipGeneratorPipeline); 2524} 2525 2526void MipmapUtils::ensure2DArrayMipGeneratorPipelineInitialized(ContextMtl *contextMtl) 2527{ 2528 EnsureComputePipelineInitialized(contextMtl, @"generate2DArrayMipmaps", 2529 &m2DArrayMipGeneratorPipeline); 2530} 2531 2532void MipmapUtils::ensureCubeMipGeneratorPipelineInitialized(ContextMtl *contextMtl) 2533{ 2534 EnsureComputePipelineInitialized(contextMtl, @"generateCubeMipmaps", 2535 &mCubeMipGeneratorPipeline); 2536} 2537 2538angle::Result MipmapUtils::generateMipmapCS(ContextMtl *contextMtl, 2539 const TextureRef &srcTexture, 2540 bool sRGBMipmap, 2541 NativeTexLevelArray *mipmapOutputViews) 2542{ 2543 // Only support 3D texture for now. 2544 ASSERT(srcTexture->textureType() == MTLTextureType3D); 2545 2546 MTLSize threadGroupSize; 2547 uint32_t slices = 1; 2548 id<MTLComputePipelineState> computePipeline = nil; 2549 2550 ensure3DMipGeneratorPipelineInitialized(contextMtl); 2551 computePipeline = m3DMipGeneratorPipeline; 2552 threadGroupSize = 2553 MTLSizeMake(kGenerateMipThreadGroupSizePerDim, kGenerateMipThreadGroupSizePerDim, 2554 kGenerateMipThreadGroupSizePerDim); 2555 2556 // The compute shader supports up to 4 mipmaps generated per pass. 2557 // See shaders/gen_mipmap.metal 2558 uint32_t maxMipsPerBatch = 4; 2559 2560 if (threadGroupSize.width * threadGroupSize.height * threadGroupSize.depth > 2561 computePipeline.maxTotalThreadsPerThreadgroup || 2562 ANGLE_UNLIKELY( 2563 !contextMtl->getDisplay()->getFeatures().allowGenMultipleMipsPerPass.enabled)) 2564 { 2565 // Multiple mipmaps generation is not supported due to hardware's thread group size limits. 2566 // Fallback to generate one mip per pass and reduce thread group size. 2567 if (ANGLE_UNLIKELY(threadGroupSize.width * threadGroupSize.height > 2568 computePipeline.maxTotalThreadsPerThreadgroup)) 2569 { 2570 // Even with reduced thread group size, we cannot proceed. 2571 // HACK: use blit command encoder to generate mipmaps if it is not possible 2572 // to use compute shader due to hardware limits. 2573 BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder(); 2574 blitEncoder->generateMipmapsForTexture(srcTexture); 2575 return angle::Result::Continue; 2576 } 2577 2578 threadGroupSize.depth = 1; 2579 maxMipsPerBatch = 1; 2580 } 2581 2582 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2583 ASSERT(cmdEncoder); 2584 2585 switch (srcTexture->textureType()) 2586 { 2587 case MTLTextureType2D: 2588 ensure2DMipGeneratorPipelineInitialized(contextMtl); 2589 cmdEncoder->setComputePipelineState(m2DMipGeneratorPipeline); 2590 threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim, 2591 kGenerateMipThreadGroupSizePerDim, 1); 2592 break; 2593 case MTLTextureType2DArray: 2594 ensure2DArrayMipGeneratorPipelineInitialized(contextMtl); 2595 cmdEncoder->setComputePipelineState(m2DArrayMipGeneratorPipeline); 2596 slices = srcTexture->arrayLength(); 2597 threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim, 2598 kGenerateMipThreadGroupSizePerDim, 1); 2599 break; 2600 case MTLTextureTypeCube: 2601 ensureCubeMipGeneratorPipelineInitialized(contextMtl); 2602 cmdEncoder->setComputePipelineState(mCubeMipGeneratorPipeline); 2603 slices = 6; 2604 threadGroupSize = MTLSizeMake(kGenerateMipThreadGroupSizePerDim, 2605 kGenerateMipThreadGroupSizePerDim, 1); 2606 break; 2607 case MTLTextureType3D: 2608 ensure3DMipGeneratorPipelineInitialized(contextMtl); 2609 cmdEncoder->setComputePipelineState(m3DMipGeneratorPipeline); 2610 threadGroupSize = 2611 MTLSizeMake(kGenerateMipThreadGroupSizePerDim, kGenerateMipThreadGroupSizePerDim, 2612 kGenerateMipThreadGroupSizePerDim); 2613 break; 2614 default: 2615 UNREACHABLE(); 2616 } 2617 2618 Generate3DMipmapUniform options; 2619 2620 uint32_t remainMips = srcTexture->mipmapLevels() - 1; 2621 MipmapNativeLevel batchSrcLevel = kZeroNativeMipLevel; 2622 options.srcLevel = batchSrcLevel.get(); 2623 options.sRGB = sRGBMipmap; 2624 2625 cmdEncoder->setTexture(srcTexture, 0); 2626 cmdEncoder->markResourceBeingWrittenByGPU(srcTexture); 2627 while (remainMips) 2628 { 2629 const TextureRef &firstMipView = 2630 mipmapOutputViews->at(mtl::MipmapNativeLevel(batchSrcLevel + 1)); 2631 gl::Extents size = firstMipView->sizeAt0(); 2632 bool isPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth); 2633 2634 // Currently multiple mipmaps generation is only supported for power of two base level. 2635 if (isPow2) 2636 { 2637 options.numMipmapsToGenerate = std::min(remainMips, maxMipsPerBatch); 2638 } 2639 else 2640 { 2641 options.numMipmapsToGenerate = 1; 2642 } 2643 2644 cmdEncoder->setData(options, 0); 2645 2646 for (uint32_t i = 1; i <= options.numMipmapsToGenerate; ++i) 2647 { 2648 cmdEncoder->setTexture( 2649 mipmapOutputViews->at(mtl::MipmapNativeLevel(options.srcLevel + i)), i); 2650 } 2651 2652 uint32_t threadsPerZ = std::max(slices, firstMipView->depthAt0()); 2653 2654 DispatchCompute( 2655 contextMtl, cmdEncoder, 2656 /** allowNonUniform */ false, 2657 MTLSizeMake(firstMipView->widthAt0(), firstMipView->heightAt0(), threadsPerZ), 2658 threadGroupSize); 2659 2660 remainMips -= options.numMipmapsToGenerate; 2661 batchSrcLevel = batchSrcLevel + options.numMipmapsToGenerate; 2662 options.srcLevel = batchSrcLevel.get(); 2663 } 2664 2665 return angle::Result::Continue; 2666} 2667 2668// CopyPixelsUtils implementation 2669CopyPixelsUtils::CopyPixelsUtils(const std::string &readShaderName, 2670 const std::string &writeShaderName) 2671 : mReadShaderName(readShaderName), mWriteShaderName(writeShaderName) 2672{} 2673CopyPixelsUtils::CopyPixelsUtils(const CopyPixelsUtils &src) 2674 : CopyPixelsUtils(src.mReadShaderName, src.mWriteShaderName) 2675{} 2676 2677void CopyPixelsUtils::onDestroy() 2678{ 2679 ClearPipelineState2DArray(&mPixelsCopyPipelineCaches); 2680} 2681 2682AutoObjCPtr<id<MTLComputePipelineState>> CopyPixelsUtils::getPixelsCopyPipeline( 2683 ContextMtl *contextMtl, 2684 const angle::Format &angleFormat, 2685 const TextureRef &texture, 2686 bool bufferWrite) 2687{ 2688 int formatIDValue = static_cast<int>(angleFormat.id); 2689 int shaderTextureType = GetShaderTextureType(texture); 2690 int index2 = mtl_shader::kTextureTypeCount * (bufferWrite ? 1 : 0) + shaderTextureType; 2691 2692 auto &cache = mPixelsCopyPipelineCaches[formatIDValue][index2]; 2693 2694 if (!cache) 2695 { 2696 // Pipeline not cached, create it now: 2697 ANGLE_MTL_OBJC_SCOPE 2698 { 2699 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 2700 2701 [funcConstants setConstantValue:&formatIDValue 2702 type:MTLDataTypeInt 2703 withName:COPY_FORMAT_TYPE_CONSTANT_NAME]; 2704 [funcConstants setConstantValue:&shaderTextureType 2705 type:MTLDataTypeInt 2706 withName:PIXEL_COPY_TEXTURE_TYPE_CONSTANT_NAME]; 2707 2708 NSString *shaderName = nil; 2709 if (bufferWrite) 2710 { 2711 shaderName = [NSString stringWithUTF8String:mWriteShaderName.c_str()]; 2712 } 2713 else 2714 { 2715 shaderName = [NSString stringWithUTF8String:mReadShaderName.c_str()]; 2716 } 2717 2718 EnsureSpecializedComputePipelineInitialized(contextMtl, shaderName, funcConstants, 2719 &cache); 2720 } 2721 } 2722 2723 return cache; 2724} 2725 2726angle::Result CopyPixelsUtils::unpackPixelsFromBufferToTexture( 2727 ContextMtl *contextMtl, 2728 const angle::Format &srcAngleFormat, 2729 const CopyPixelsFromBufferParams ¶ms) 2730{ 2731 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2732 ASSERT(cmdEncoder); 2733 2734 AutoObjCPtr<id<MTLComputePipelineState>> pipeline = 2735 getPixelsCopyPipeline(contextMtl, srcAngleFormat, params.texture, false); 2736 2737 cmdEncoder->setComputePipelineState(pipeline); 2738 cmdEncoder->setBuffer(params.buffer, 0, 1); 2739 cmdEncoder->setTextureForWrite(params.texture, 0); 2740 2741 CopyPixelFromBufferUniforms options; 2742 options.copySize[0] = params.textureArea.width; 2743 options.copySize[1] = params.textureArea.height; 2744 options.copySize[2] = params.textureArea.depth; 2745 options.bufferStartOffset = params.bufferStartOffset; 2746 options.pixelSize = srcAngleFormat.pixelBytes; 2747 options.bufferRowPitch = params.bufferRowPitch; 2748 options.bufferDepthPitch = params.bufferDepthPitch; 2749 options.textureOffset[0] = params.textureArea.x; 2750 options.textureOffset[1] = params.textureArea.y; 2751 options.textureOffset[2] = params.textureArea.z; 2752 cmdEncoder->setData(options, 0); 2753 2754 NSUInteger w = pipeline.get().threadExecutionWidth; 2755 MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1); 2756 2757 MTLSize threads = 2758 MTLSizeMake(params.textureArea.width, params.textureArea.height, params.textureArea.depth); 2759 2760 DispatchCompute(contextMtl, cmdEncoder, 2761 /** allowNonUniform */ true, threads, threadsPerThreadgroup); 2762 2763 return angle::Result::Continue; 2764} 2765 2766angle::Result CopyPixelsUtils::packPixelsFromTextureToBuffer(ContextMtl *contextMtl, 2767 const angle::Format &dstAngleFormat, 2768 const CopyPixelsToBufferParams ¶ms) 2769{ 2770 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2771 ASSERT(cmdEncoder); 2772 2773 AutoObjCPtr<id<MTLComputePipelineState>> pipeline = 2774 getPixelsCopyPipeline(contextMtl, dstAngleFormat, params.texture, true); 2775 2776 cmdEncoder->setComputePipelineState(pipeline); 2777 cmdEncoder->setTexture(params.texture, 0); 2778 cmdEncoder->setBufferForWrite(params.buffer, 0, 1); 2779 2780 WritePixelToBufferUniforms options; 2781 options.copySize[0] = params.textureArea.width; 2782 options.copySize[1] = params.textureArea.height; 2783 options.bufferStartOffset = params.bufferStartOffset; 2784 options.pixelSize = dstAngleFormat.pixelBytes; 2785 options.bufferRowPitch = params.bufferRowPitch; 2786 options.textureOffset[0] = params.textureArea.x; 2787 options.textureOffset[1] = params.textureArea.y; 2788 options.textureLevel = params.textureLevel.get(); 2789 options.textureLayer = params.textureSliceOrDeph; 2790 options.reverseTextureRowOrder = params.reverseTextureRowOrder; 2791 cmdEncoder->setData(options, 0); 2792 2793 NSUInteger w = pipeline.get().threadExecutionWidth; 2794 MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1); 2795 2796 MTLSize threads = MTLSizeMake(params.textureArea.width, params.textureArea.height, 1); 2797 2798 DispatchCompute(contextMtl, cmdEncoder, 2799 /** allowNonUniform */ true, threads, threadsPerThreadgroup); 2800 2801 return angle::Result::Continue; 2802} 2803 2804// VertexFormatConversionUtils implementation 2805void VertexFormatConversionUtils::onDestroy() 2806{ 2807 ClearPipelineStateArray(&mConvertToFloatCompPipelineCaches); 2808 ClearRenderPipelineCacheArray(&mConvertToFloatRenderPipelineCaches); 2809 2810 mComponentsExpandCompPipeline = nil; 2811 mComponentsExpandRenderPipelineCache.clear(); 2812} 2813 2814angle::Result VertexFormatConversionUtils::convertVertexFormatToFloatCS( 2815 ContextMtl *contextMtl, 2816 const angle::Format &srcAngleFormat, 2817 const VertexFormatConvertParams ¶ms) 2818{ 2819 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2820 ASSERT(cmdEncoder); 2821 2822 AutoObjCPtr<id<MTLComputePipelineState>> pipeline = 2823 getFloatConverstionComputePipeline(contextMtl, srcAngleFormat); 2824 2825 ANGLE_TRY(setupCommonConvertVertexFormatToFloat(contextMtl, cmdEncoder, pipeline, 2826 srcAngleFormat, params)); 2827 2828 DispatchCompute(contextMtl, cmdEncoder, pipeline, params.vertexCount); 2829 return angle::Result::Continue; 2830} 2831 2832angle::Result VertexFormatConversionUtils::convertVertexFormatToFloatVS( 2833 const gl::Context *context, 2834 RenderCommandEncoder *cmdEncoder, 2835 const angle::Format &srcAngleFormat, 2836 const VertexFormatConvertParams ¶ms) 2837{ 2838 ContextMtl *contextMtl = GetImpl(context); 2839 ASSERT(cmdEncoder); 2840 ASSERT(contextMtl->getDisplay()->getFeatures().hasExplicitMemBarrier.enabled); 2841 2842 AutoObjCPtr<id<MTLRenderPipelineState>> pipeline = 2843 getFloatConverstionRenderPipeline(contextMtl, cmdEncoder, srcAngleFormat); 2844 2845 ANGLE_TRY(setupCommonConvertVertexFormatToFloat(contextMtl, cmdEncoder, pipeline, 2846 srcAngleFormat, params)); 2847 2848 cmdEncoder->draw(MTLPrimitiveTypePoint, 0, params.vertexCount); 2849 2850 cmdEncoder->memoryBarrierWithResource(params.dstBuffer, kRenderStageVertex, kRenderStageVertex); 2851 2852 // Invalidate current context's state. 2853 // NOTE(hqle): Consider invalidating only affected states. 2854 contextMtl->invalidateState(context); 2855 2856 return angle::Result::Continue; 2857} 2858 2859template <typename EncoderType, typename PipelineType> 2860angle::Result VertexFormatConversionUtils::setupCommonConvertVertexFormatToFloat( 2861 ContextMtl *contextMtl, 2862 EncoderType cmdEncoder, 2863 const PipelineType &pipeline, 2864 const angle::Format &srcAngleFormat, 2865 const VertexFormatConvertParams ¶ms) 2866{ 2867 if (pipeline == nullptr) 2868 { 2869 return angle::Result::Stop; 2870 } 2871 SetPipelineState(cmdEncoder, pipeline); 2872 SetComputeOrVertexBuffer(cmdEncoder, params.srcBuffer, 0, 1); 2873 SetComputeOrVertexBufferForWrite(cmdEncoder, params.dstBuffer, 0, 2); 2874 2875 CopyVertexUniforms options; 2876 options.srcBufferStartOffset = params.srcBufferStartOffset; 2877 options.srcStride = params.srcStride; 2878 2879 options.dstBufferStartOffset = params.dstBufferStartOffset; 2880 options.dstStride = params.dstStride; 2881 options.dstComponents = params.dstComponents; 2882 2883 options.vertexCount = params.vertexCount; 2884 SetComputeOrVertexData(cmdEncoder, options, 0); 2885 2886 return angle::Result::Continue; 2887} 2888 2889// Expand number of components per vertex's attribute 2890angle::Result VertexFormatConversionUtils::expandVertexFormatComponentsCS( 2891 ContextMtl *contextMtl, 2892 const angle::Format &srcAngleFormat, 2893 const VertexFormatConvertParams ¶ms) 2894{ 2895 ComputeCommandEncoder *cmdEncoder = contextMtl->getComputeCommandEncoder(); 2896 ASSERT(cmdEncoder); 2897 2898 ensureComponentsExpandComputePipelineCreated(contextMtl); 2899 2900 ANGLE_TRY(setupCommonExpandVertexFormatComponents( 2901 contextMtl, cmdEncoder, mComponentsExpandCompPipeline, srcAngleFormat, params)); 2902 2903 DispatchCompute(contextMtl, cmdEncoder, mComponentsExpandCompPipeline, params.vertexCount); 2904 return angle::Result::Continue; 2905} 2906 2907angle::Result VertexFormatConversionUtils::expandVertexFormatComponentsVS( 2908 const gl::Context *context, 2909 RenderCommandEncoder *cmdEncoder, 2910 const angle::Format &srcAngleFormat, 2911 const VertexFormatConvertParams ¶ms) 2912{ 2913 ContextMtl *contextMtl = GetImpl(context); 2914 ASSERT(cmdEncoder); 2915 ASSERT(contextMtl->getDisplay()->getFeatures().hasExplicitMemBarrier.enabled); 2916 2917 AutoObjCPtr<id<MTLRenderPipelineState>> pipeline = 2918 getComponentsExpandRenderPipeline(contextMtl, cmdEncoder); 2919 if (pipeline == nullptr) 2920 { 2921 return angle::Result::Stop; 2922 } 2923 2924 ANGLE_TRY(setupCommonExpandVertexFormatComponents(contextMtl, cmdEncoder, pipeline, 2925 srcAngleFormat, params)); 2926 2927 cmdEncoder->draw(MTLPrimitiveTypePoint, 0, params.vertexCount); 2928 2929 cmdEncoder->memoryBarrierWithResource(params.dstBuffer, kRenderStageVertex, kRenderStageVertex); 2930 2931 // Invalidate current context's state. 2932 // NOTE(hqle): Consider invalidating only affected states. 2933 contextMtl->invalidateState(context); 2934 2935 return angle::Result::Continue; 2936} 2937 2938template <typename EncoderType, typename PipelineType> 2939angle::Result VertexFormatConversionUtils::setupCommonExpandVertexFormatComponents( 2940 ContextMtl *contextMtl, 2941 EncoderType cmdEncoder, 2942 const PipelineType &pipeline, 2943 const angle::Format &srcAngleFormat, 2944 const VertexFormatConvertParams ¶ms) 2945{ 2946 if (pipeline == nullptr) 2947 { 2948 return angle::Result::Stop; 2949 } 2950 SetPipelineState(cmdEncoder, pipeline); 2951 SetComputeOrVertexBuffer(cmdEncoder, params.srcBuffer, 0, 1); 2952 SetComputeOrVertexBufferForWrite(cmdEncoder, params.dstBuffer, 0, 2); 2953 2954 CopyVertexUniforms options; 2955 options.srcBufferStartOffset = params.srcBufferStartOffset; 2956 options.srcStride = params.srcStride; 2957 options.srcComponentBytes = srcAngleFormat.pixelBytes / srcAngleFormat.channelCount; 2958 options.srcComponents = srcAngleFormat.channelCount; 2959 options.srcDefaultAlphaData = params.srcDefaultAlphaData; 2960 2961 options.dstBufferStartOffset = params.dstBufferStartOffset; 2962 options.dstStride = params.dstStride; 2963 options.dstComponents = params.dstComponents; 2964 2965 options.vertexCount = params.vertexCount; 2966 SetComputeOrVertexData(cmdEncoder, options, 0); 2967 2968 return angle::Result::Continue; 2969} 2970 2971void VertexFormatConversionUtils::ensureComponentsExpandComputePipelineCreated( 2972 ContextMtl *contextMtl) 2973{ 2974 EnsureComputePipelineInitialized(contextMtl, @"expandVertexFormatComponentsCS", 2975 &mComponentsExpandCompPipeline); 2976} 2977 2978AutoObjCPtr<id<MTLRenderPipelineState>> 2979VertexFormatConversionUtils::getComponentsExpandRenderPipeline(ContextMtl *contextMtl, 2980 RenderCommandEncoder *cmdEncoder) 2981{ 2982 DisplayMtl *display = contextMtl->getDisplay(); 2983 auto shaderLib = display->getDefaultShadersLib(); 2984 EnsureVertexShaderOnlyPipelineCacheInitialized(contextMtl, @"expandVertexFormatComponentsVS", 2985 shaderLib, 2986 &mComponentsExpandRenderPipelineCache); 2987 2988 RenderPipelineDesc pipelineDesc = GetComputingVertexShaderOnlyRenderPipelineDesc(cmdEncoder); 2989 2990 return mComponentsExpandRenderPipelineCache.getRenderPipelineState(contextMtl, pipelineDesc); 2991} 2992 2993AutoObjCPtr<id<MTLComputePipelineState>> 2994VertexFormatConversionUtils::getFloatConverstionComputePipeline(ContextMtl *contextMtl, 2995 const angle::Format &srcAngleFormat) 2996{ 2997 int formatIDValue = static_cast<int>(srcAngleFormat.id); 2998 2999 auto &cache = mConvertToFloatCompPipelineCaches[formatIDValue]; 3000 3001 if (!cache) 3002 { 3003 // Pipeline not cached, create it now: 3004 ANGLE_MTL_OBJC_SCOPE 3005 { 3006 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 3007 3008 [funcConstants setConstantValue:&formatIDValue 3009 type:MTLDataTypeInt 3010 withName:COPY_FORMAT_TYPE_CONSTANT_NAME]; 3011 3012 EnsureSpecializedComputePipelineInitialized(contextMtl, @"convertToFloatVertexFormatCS", 3013 funcConstants, &cache); 3014 } 3015 } 3016 3017 return cache; 3018} 3019 3020AutoObjCPtr<id<MTLRenderPipelineState>> 3021VertexFormatConversionUtils::getFloatConverstionRenderPipeline(ContextMtl *contextMtl, 3022 RenderCommandEncoder *cmdEncoder, 3023 const angle::Format &srcAngleFormat) 3024{ 3025 int formatIDValue = static_cast<int>(srcAngleFormat.id); 3026 3027 RenderPipelineCache &cache = mConvertToFloatRenderPipelineCaches[formatIDValue]; 3028 3029 if (!cache.getVertexShader()) 3030 { 3031 // Pipeline cache not intialized, do it now: 3032 ANGLE_MTL_OBJC_SCOPE 3033 { 3034 auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; 3035 3036 [funcConstants setConstantValue:&formatIDValue 3037 type:MTLDataTypeInt 3038 withName:COPY_FORMAT_TYPE_CONSTANT_NAME]; 3039 3040 EnsureSpecializedVertexShaderOnlyPipelineCacheInitialized( 3041 contextMtl, @"convertToFloatVertexFormatVS", funcConstants, &cache); 3042 } 3043 } 3044 3045 RenderPipelineDesc pipelineDesc = GetComputingVertexShaderOnlyRenderPipelineDesc(cmdEncoder); 3046 3047 return cache.getRenderPipelineState(contextMtl, pipelineDesc); 3048} 3049 3050} // namespace mtl 3051} // namespace rx 3052