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