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