xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/mtl_render_utils.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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.h:
7 //    Defines the class interface for RenderUtils, which contains many utility functions and shaders
8 //    for converting, blitting, copying as well as generating data, and many more.
9 //
10 
11 #ifndef LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
12 #define LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
13 
14 #import <Metal/Metal.h>
15 #include <unordered_map>
16 
17 #include "libANGLE/angletypes.h"
18 #include "libANGLE/renderer/metal/RenderTargetMtl.h"
19 #include "libANGLE/renderer/metal/mtl_command_buffer.h"
20 #include "libANGLE/renderer/metal/mtl_context_device.h"
21 #include "libANGLE/renderer/metal/mtl_state_cache.h"
22 #include "libANGLE/renderer/metal/shaders/constants.h"
23 
24 namespace rx
25 {
26 
27 class BufferMtl;
28 class ContextMtl;
29 class DisplayMtl;
30 class VisibilityBufferOffsetsMtl;
31 
32 namespace mtl
33 {
34 
35 struct ClearRectParams
36 {
ClearRectParamsClearRectParams37     ClearRectParams() { clearWriteMaskArray.fill(MTLColorWriteMaskAll); }
38 
39     Optional<ClearColorValue> clearColor;
40     Optional<float> clearDepth;
41     Optional<uint32_t> clearStencil;
42 
43     WriteMaskArray clearWriteMaskArray;
44 
45     const mtl::Format *colorFormat = nullptr;
46     gl::Extents dstTextureSize;
47 
48     // Only clear enabled buffers
49     gl::DrawBufferMask enabledBuffers;
50     gl::Rectangle clearArea;
51 
52     bool flipY = false;
53 };
54 
55 struct NormalizedCoords
56 {
57     NormalizedCoords();
58     NormalizedCoords(float x, float y, float width, float height, const gl::Rectangle &rect);
59     NormalizedCoords(const gl::Rectangle &rect, const gl::Extents &extents);
60     float v[4];
61 };
62 
63 struct BlitParams
64 {
65     gl::Extents dstTextureSize;
66     gl::Rectangle dstRect;
67     gl::Rectangle dstScissorRect;
68     // Destination texture needs to have viewport Y flipped?
69     // The difference between this param and unpackFlipY is that unpackFlipY is from
70     // glCopyImageCHROMIUM()/glBlitFramebuffer(), and dstFlipY controls whether the final viewport
71     // needs to be flipped when drawing to destination texture. It is possible to combine the two
72     // flags before passing to RenderUtils. However, to avoid duplicated works, just pass the two
73     // flags to RenderUtils, they will be combined internally by RenderUtils logic.
74     bool dstFlipY = false;
75     bool dstFlipX = false;
76 
77     TextureRef src;
78     MipmapNativeLevel srcLevel = kZeroNativeMipLevel;
79     uint32_t srcLayer          = 0;
80 
81     // Source rectangle:
82     // NOTE: if srcYFlipped=true, this rectangle will be converted internally to flipped rect before
83     // blitting.
84     NormalizedCoords srcNormalizedCoords;
85 
86     bool srcYFlipped = false;  // source texture has data flipped in Y direction
87     bool unpackFlipX = false;  // flip texture data copying process in X direction
88     bool unpackFlipY = false;  // flip texture data copying process in Y direction
89 };
90 
91 struct ColorBlitParams : public BlitParams
92 {
ColorBlitParamsColorBlitParams93     ColorBlitParams() {}
94 
95     gl::DrawBufferMask enabledBuffers;
96     GLenum filter               = GL_NEAREST;
97     bool unpackPremultiplyAlpha = false;
98     bool unpackUnmultiplyAlpha  = false;
99     bool transformLinearToSrgb  = false;
100     bool dstLuminance           = false;
101 };
102 
103 struct DepthStencilBlitParams : public BlitParams
104 {
105     TextureRef srcStencil;
106 };
107 
108 // Stencil blit via an intermediate buffer. NOTE: source depth texture parameter is ignored.
109 // See DepthStencilBlitUtils::blitStencilViaCopyBuffer()
110 struct StencilBlitViaBufferParams : public DepthStencilBlitParams
111 {
112     StencilBlitViaBufferParams();
113     StencilBlitViaBufferParams(const DepthStencilBlitParams &src);
114 
115     TextureRef dstStencil;
116     MipmapNativeLevel dstStencilLevel = kZeroNativeMipLevel;
117     uint32_t dstStencilLayer          = 0;
118     bool dstPackedDepthStencilFormat  = false;
119 };
120 
121 struct TriFanOrLineLoopFromArrayParams
122 {
123     uint32_t firstVertex;
124     uint32_t vertexCount;
125     BufferRef dstBuffer;
126     // Must be multiples of kIndexBufferOffsetAlignment
127     uint32_t dstOffset;
128 };
129 
130 struct IndexConversionParams
131 {
132 
133     gl::DrawElementsType srcType;
134     uint32_t indexCount;
135     const BufferRef &srcBuffer;
136     uint32_t srcOffset;
137     const BufferRef &dstBuffer;
138     // Must be multiples of kIndexBufferOffsetAlignment
139     uint32_t dstOffset;
140     bool primitiveRestartEnabled = false;
141 };
142 
143 struct IndexGenerationParams
144 {
145     gl::DrawElementsType srcType;
146     GLsizei indexCount;
147     const void *indices;
148     BufferRef dstBuffer;
149     uint32_t dstOffset;
150     bool primitiveRestartEnabled = false;
151 };
152 
153 struct CopyPixelsCommonParams
154 {
155     BufferRef buffer;
156     uint32_t bufferStartOffset = 0;
157     uint32_t bufferRowPitch    = 0;
158 
159     TextureRef texture;
160 };
161 
162 struct CopyPixelsFromBufferParams : CopyPixelsCommonParams
163 {
164     uint32_t bufferDepthPitch = 0;
165 
166     // z offset is:
167     //  - slice index if texture is array.
168     //  - depth if texture is 3d.
169     gl::Box textureArea;
170 };
171 
172 struct CopyPixelsToBufferParams : CopyPixelsCommonParams
173 {
174     gl::Rectangle textureArea;
175     MipmapNativeLevel textureLevel = kZeroNativeMipLevel;
176     uint32_t textureSliceOrDeph    = 0;
177     bool reverseTextureRowOrder;
178 };
179 
180 struct VertexFormatConvertParams
181 {
182     BufferRef srcBuffer;
183     uint32_t srcBufferStartOffset = 0;
184     uint32_t srcStride            = 0;
185     uint32_t srcDefaultAlphaData  = 0;  // casted as uint
186 
187     BufferRef dstBuffer;
188     uint32_t dstBufferStartOffset = 0;
189     uint32_t dstStride            = 0;
190     uint32_t dstComponents        = 0;
191 
192     uint32_t vertexCount = 0;
193 };
194 
195 struct BlockLinearizationParams
196 {
197     BufferRef srcBuffer;
198     BufferRef dstBuffer;
199     uint32_t srcBufferOffset;
200     uint32_t blocksWide;
201     uint32_t blocksHigh;
202 };
203 
204 struct DepthSaturationParams
205 {
206     BufferRef srcBuffer;
207     BufferRef dstBuffer;
208     uint32_t srcBufferOffset;
209     uint32_t dstWidth;
210     uint32_t dstHeight;
211     uint32_t srcPitch;
212 };
213 
214 // Utils class for clear & blitting
215 class ClearUtils final : angle::NonCopyable
216 {
217   public:
218     ClearUtils() = delete;
219     ClearUtils(const std::string &fragmentShaderName);
220 
221     // Clear current framebuffer
222     angle::Result clearWithDraw(const gl::Context *context,
223                                 RenderCommandEncoder *cmdEncoder,
224                                 const ClearRectParams &params);
225 
226   private:
227     angle::Result ensureShadersInitialized(ContextMtl *ctx, uint32_t numColorAttachments);
228 
229     angle::Result setupClearWithDraw(const gl::Context *context,
230                                      RenderCommandEncoder *cmdEncoder,
231                                      const ClearRectParams &params);
232     id<MTLDepthStencilState> getClearDepthStencilState(const gl::Context *context,
233                                                        const ClearRectParams &params);
234     angle::Result getClearRenderPipelineState(
235         const gl::Context *context,
236         RenderCommandEncoder *cmdEncoder,
237         const ClearRectParams &params,
238         AutoObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
239 
240     const std::string mFragmentShaderName;
241 
242     AutoObjCPtr<id<MTLFunction>> mVertexShader;
243     std::array<AutoObjCPtr<id<MTLFunction>>, kMaxRenderTargets + 1> mFragmentShaders;
244 };
245 
246 class ColorBlitUtils final : angle::NonCopyable
247 {
248   public:
249     ColorBlitUtils() = delete;
250     ColorBlitUtils(const std::string &fragmentShaderName);
251 
252     // Blit texture data to current framebuffer
253     angle::Result blitColorWithDraw(const gl::Context *context,
254                                     RenderCommandEncoder *cmdEncoder,
255                                     const ColorBlitParams &params);
256 
257   private:
258     struct ShaderKey
259     {
260         uint32_t numColorAttachments = 0;
261         int sourceTextureType        = 0;
262         bool unmultiplyAlpha         = false;
263         bool premultiplyAlpha        = false;
264         bool transformLinearToSrgb   = false;
265         bool operator==(const ShaderKey &other) const
266         {
267             return numColorAttachments == other.numColorAttachments &&
268                    unmultiplyAlpha == other.unmultiplyAlpha &&
269                    premultiplyAlpha == other.premultiplyAlpha &&
270                    transformLinearToSrgb == other.transformLinearToSrgb &&
271                    sourceTextureType == other.sourceTextureType;
272         }
273         struct Hash
274         {
operatorShaderKey::Hash275             size_t operator()(const ShaderKey &k) const noexcept
276             {
277                 return angle::HashMultiple(k.numColorAttachments, k.unmultiplyAlpha,
278                                            k.premultiplyAlpha, k.sourceTextureType);
279             }
280         };
281     };
282     angle::Result ensureShadersInitialized(ContextMtl *ctx,
283                                            const ShaderKey &key,
284                                            AutoObjCPtr<id<MTLFunction>> *fragmentShaderOut);
285 
286     angle::Result setupColorBlitWithDraw(const gl::Context *context,
287                                          RenderCommandEncoder *cmdEncoder,
288                                          const ColorBlitParams &params);
289 
290     angle::Result getColorBlitRenderPipelineState(
291         const gl::Context *context,
292         RenderCommandEncoder *cmdEncoder,
293         const ColorBlitParams &params,
294         AutoObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
295 
296     const std::string mFragmentShaderName;
297 
298     AutoObjCPtr<id<MTLFunction>> mVertexShader;
299 
300     // Blit fragment shaders.
301     std::unordered_map<ShaderKey, AutoObjCPtr<id<MTLFunction>>, ShaderKey::Hash>
302         mBlitFragmentShaders;
303 };
304 
305 class DepthStencilBlitUtils final : angle::NonCopyable
306 {
307   public:
308     angle::Result blitDepthStencilWithDraw(const gl::Context *context,
309                                            RenderCommandEncoder *cmdEncoder,
310                                            const DepthStencilBlitParams &params);
311 
312     // Blit stencil data using intermediate buffer. This function is used on devices with no
313     // support for direct stencil write in shader. Thus an intermediate buffer storing copied
314     // stencil data is needed.
315     // NOTE: this function shares the params struct with depth & stencil blit, but depth texture
316     // parameter is not used. This function will break existing render pass.
317     angle::Result blitStencilViaCopyBuffer(const gl::Context *context,
318                                            const StencilBlitViaBufferParams &params);
319 
320   private:
321     angle::Result ensureShadersInitialized(ContextMtl *ctx,
322                                            int sourceDepthTextureType,
323                                            int sourceStencilTextureType,
324                                            AutoObjCPtr<id<MTLFunction>> *fragmentShaderOut);
325 
326     angle::Result setupDepthStencilBlitWithDraw(const gl::Context *context,
327                                                 RenderCommandEncoder *cmdEncoder,
328                                                 const DepthStencilBlitParams &params);
329 
330     angle::Result getDepthStencilBlitRenderPipelineState(
331         const gl::Context *context,
332         RenderCommandEncoder *cmdEncoder,
333         const DepthStencilBlitParams &params,
334         AutoObjCPtr<id<MTLRenderPipelineState>> *outRenderPipelineState);
335 
336     angle::Result getStencilToBufferComputePipelineState(
337         ContextMtl *ctx,
338         const StencilBlitViaBufferParams &params,
339         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipelineState);
340 
341     AutoObjCPtr<id<MTLFunction>> mVertexShader;
342 
343     std::array<AutoObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
344         mDepthBlitFragmentShaders;
345     std::array<AutoObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
346         mStencilBlitFragmentShaders;
347     std::array<std::array<AutoObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>,
348                mtl_shader::kTextureTypeCount>
349         mDepthStencilBlitFragmentShaders;
350 
351     std::array<AutoObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
352         mStencilBlitToBufferComputeShaders;
353 
354     // Intermediate buffer for storing copied stencil data. Used when device doesn't support
355     // writing stencil in shader.
356     BufferRef mStencilCopyBuffer;
357 };
358 
359 // util class for generating index buffer
360 class IndexGeneratorUtils final : angle::NonCopyable
361 {
362   public:
363     angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
364                                         const IndexConversionParams &params);
365     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
366                                                  const TriFanOrLineLoopFromArrayParams &params);
367     // Generate triangle fan index buffer for glDrawElements().
368     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
369                                                         const IndexGenerationParams &params,
370                                                         uint32_t *indicesGenerated);
371 
372     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
373                                                    const TriFanOrLineLoopFromArrayParams &params);
374     angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
375                                               uint32_t firstVertex,
376                                               uint32_t lastVertex,
377                                               const BufferRef &dstBuffer,
378                                               uint32_t dstOffset);
379     // Generate line loop index buffer for glDrawElements().
380     // Destination buffer must have at least 2x the number of original indices if primitive restart
381     // is enabled.
382     angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
383                                                           const IndexGenerationParams &params,
384                                                           uint32_t *indicesGenerated);
385     // Generate line loop's last segment index buffer for glDrawElements().
386     // NOTE: this function assumes primitive restart is not enabled.
387     angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
388                                                                const IndexGenerationParams &params);
389 
390     angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
391                                                        const IndexGenerationParams &params,
392                                                        size_t *indicesGenerated);
393 
394     angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
395                                                       const IndexGenerationParams &params,
396                                                       size_t *indicesGenerated);
397 
398     angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
399                                                           const IndexGenerationParams &params,
400                                                           size_t *indicesGenerated);
401 
402   private:
403     // Index generator compute shaders:
404     //  - First dimension: index type.
405     //  - second dimension: source buffer's offset is aligned or not.
406     using IndexConversionShaderArray = std::array<std::array<AutoObjCPtr<id<MTLFunction>>, 2>,
407                                                   angle::EnumSize<gl::DrawElementsType>()>;
408 
409     angle::Result getIndexConversionPipeline(
410         ContextMtl *contextMtl,
411         gl::DrawElementsType srcType,
412         uint32_t srcOffset,
413         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
414     // Get compute pipeline to generate tri fan/line loop index for glDrawElements().
415     angle::Result getIndicesFromElemArrayGeneratorPipeline(
416         ContextMtl *contextMtl,
417         gl::DrawElementsType srcType,
418         uint32_t srcOffset,
419         NSString *shaderName,
420         IndexConversionShaderArray *pipelineCacheArray,
421         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
422     // Defer loading of compute pipeline to generate tri fan index for glDrawArrays().
423     angle::Result getTriFanFromArrayGeneratorPipeline(
424         ContextMtl *contextMtl,
425         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
426     // Defer loading of compute pipeline to generate line loop index for glDrawArrays().
427     angle::Result getLineLoopFromArrayGeneratorPipeline(
428         ContextMtl *contextMtl,
429         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
430 
431     angle::Result generateTriFanBufferFromElementsArrayGPU(
432         ContextMtl *contextMtl,
433         gl::DrawElementsType srcType,
434         uint32_t indexCount,
435         const BufferRef &srcBuffer,
436         uint32_t srcOffset,
437         const BufferRef &dstBuffer,
438         // Must be multiples of kIndexBufferOffsetAlignment
439         uint32_t dstOffset);
440     angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
441                                                            const IndexGenerationParams &params,
442                                                            uint32_t *indicesGenerated);
443 
444     angle::Result generateLineLoopBufferFromElementsArrayGPU(
445         ContextMtl *contextMtl,
446         gl::DrawElementsType srcType,
447         uint32_t indexCount,
448         const BufferRef &srcBuffer,
449         uint32_t srcOffset,
450         const BufferRef &dstBuffer,
451         // Must be multiples of kIndexBufferOffsetAlignment
452         uint32_t dstOffset);
453     angle::Result generateLineLoopBufferFromElementsArrayCPU(ContextMtl *contextMtl,
454                                                              const IndexGenerationParams &params,
455                                                              uint32_t *indicesGenerated);
456     angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
457         ContextMtl *contextMtl,
458         const IndexGenerationParams &params);
459 
460     angle::Result generatePrimitiveRestartBuffer(ContextMtl *contextMtl,
461                                                  unsigned numVerticesPerPrimitive,
462                                                  const IndexGenerationParams &params,
463                                                  size_t *indicesGenerated);
464 
465     IndexConversionShaderArray mIndexConversionShaders;
466 
467     IndexConversionShaderArray mTriFanFromElemArrayGeneratorShaders;
468     AutoObjCPtr<id<MTLFunction>> mTriFanFromArraysGeneratorShader;
469 
470     IndexConversionShaderArray mLineLoopFromElemArrayGeneratorShaders;
471     AutoObjCPtr<id<MTLFunction>> mLineLoopFromArraysGeneratorShader;
472 };
473 
474 // Util class for handling visibility query result
475 class VisibilityResultUtils final : angle::NonCopyable
476 {
477   public:
478     angle::Result combineVisibilityResult(
479         ContextMtl *contextMtl,
480         bool keepOldValue,
481         const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets,
482         const BufferRef &renderPassResultBuf,
483         const BufferRef &finalResultBuf);
484 
485   private:
486     angle::Result getVisibilityResultCombinePipeline(
487         ContextMtl *contextMtl,
488         bool keepOldValue,
489         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
490     // Visibility combination compute shaders:
491     // - 0: This compute shader only combines the new values and discard old value.
492     // - 1: This compute shader keep the old value and combines with new values.
493     std::array<AutoObjCPtr<id<MTLFunction>>, 2> mVisibilityResultCombineComputeShaders;
494 };
495 
496 // Util class for handling mipmap generation
497 class MipmapUtils final : angle::NonCopyable
498 {
499   public:
500     // Compute based mipmap generation.
501     angle::Result generateMipmapCS(ContextMtl *contextMtl,
502                                    const TextureRef &srcTexture,
503                                    bool sRGBMipmap,
504                                    NativeTexLevelArray *mipmapOutputViews);
505 
506   private:
507     angle::Result get3DMipGeneratorPipeline(
508         ContextMtl *contextMtl,
509         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
510     angle::Result get2DMipGeneratorPipeline(
511         ContextMtl *contextMtl,
512         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
513     angle::Result get2DArrayMipGeneratorPipeline(
514         ContextMtl *contextMtl,
515         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
516     angle::Result getCubeMipGeneratorPipeline(
517         ContextMtl *contextMtl,
518         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
519 
520     // Mipmaps generating compute pipeline:
521     AutoObjCPtr<id<MTLFunction>> m3DMipGeneratorShader;
522     AutoObjCPtr<id<MTLFunction>> m2DMipGeneratorShader;
523     AutoObjCPtr<id<MTLFunction>> m2DArrayMipGeneratorShader;
524     AutoObjCPtr<id<MTLFunction>> mCubeMipGeneratorShader;
525 };
526 
527 // Util class for handling pixels copy between buffers and textures
528 class CopyPixelsUtils final : angle::NonCopyable
529 {
530   public:
531     CopyPixelsUtils() = default;
532     CopyPixelsUtils(const std::string &readShaderName, const std::string &writeShaderName);
533 
534     angle::Result unpackPixelsFromBufferToTexture(ContextMtl *contextMtl,
535                                                   const angle::Format &srcAngleFormat,
536                                                   const CopyPixelsFromBufferParams &params);
537     angle::Result packPixelsFromTextureToBuffer(ContextMtl *contextMtl,
538                                                 const angle::Format &dstAngleFormat,
539                                                 const CopyPixelsToBufferParams &params);
540 
541   private:
542     angle::Result getPixelsCopyPipeline(
543         ContextMtl *contextMtl,
544         const angle::Format &angleFormat,
545         const TextureRef &texture,
546         bool bufferWrite,
547         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
548     // Copy pixels between buffer and texture compute pipelines:
549     // - First dimension: pixel format.
550     // - Second dimension: texture type * (buffer read/write flag)
551     using PixelsCopyComputeShaderArray =
552         std::array<std::array<AutoObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount * 2>,
553                    angle::kNumANGLEFormats>;
554     PixelsCopyComputeShaderArray mPixelsCopyComputeShaders;
555 
556     const std::string mReadShaderName;
557     const std::string mWriteShaderName;
558 };
559 
560 // Util class for handling vertex format conversion on GPU
561 class VertexFormatConversionUtils final : angle::NonCopyable
562 {
563   public:
564     // Convert vertex format to float. Compute shader version.
565     angle::Result convertVertexFormatToFloatCS(ContextMtl *contextMtl,
566                                                const angle::Format &srcAngleFormat,
567                                                const VertexFormatConvertParams &params);
568     // Convert vertex format to float. Vertex shader version. This version should be used if
569     // a render pass is active and we don't want to break it. Explicit memory barrier must be
570     // supported.
571     angle::Result convertVertexFormatToFloatVS(const gl::Context *context,
572                                                RenderCommandEncoder *renderEncoder,
573                                                const angle::Format &srcAngleFormat,
574                                                const VertexFormatConvertParams &params);
575     // Expand number of components per vertex's attribute (or just simply copy components between
576     // buffers with different stride and offset)
577     angle::Result expandVertexFormatComponentsCS(ContextMtl *contextMtl,
578                                                  const angle::Format &srcAngleFormat,
579                                                  const VertexFormatConvertParams &params);
580     angle::Result expandVertexFormatComponentsVS(const gl::Context *context,
581                                                  RenderCommandEncoder *renderEncoder,
582                                                  const angle::Format &srcAngleFormat,
583                                                  const VertexFormatConvertParams &params);
584 
585   private:
586     angle::Result getComponentsExpandComputePipeline(
587         ContextMtl *contextMtl,
588         AutoObjCPtr<id<MTLComputePipelineState>> *outPipelineState);
589     angle::Result getComponentsExpandRenderPipeline(
590         ContextMtl *contextMtl,
591         RenderCommandEncoder *renderEncoder,
592         AutoObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
593 
594     angle::Result getFloatConverstionComputePipeline(
595         ContextMtl *contextMtl,
596         const angle::Format &srcAngleFormat,
597         AutoObjCPtr<id<MTLComputePipelineState>> *outPipelineState);
598 
599     angle::Result getFloatConverstionRenderPipeline(
600         ContextMtl *contextMtl,
601         RenderCommandEncoder *renderEncoder,
602         const angle::Format &srcAngleFormat,
603         AutoObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
604 
605     template <typename EncoderType, typename PipelineType>
606     angle::Result setupCommonConvertVertexFormatToFloat(ContextMtl *contextMtl,
607                                                         EncoderType cmdEncoder,
608                                                         const PipelineType &pipeline,
609                                                         const angle::Format &srcAngleFormat,
610                                                         const VertexFormatConvertParams &params);
611     template <typename EncoderType, typename PipelineType>
612     angle::Result setupCommonExpandVertexFormatComponents(ContextMtl *contextMtl,
613                                                           EncoderType cmdEncoder,
614                                                           const PipelineType &pipeline,
615                                                           const angle::Format &srcAngleFormat,
616                                                           const VertexFormatConvertParams &params);
617 
618     using ConvertToFloatComputeShaderArray =
619         std::array<AutoObjCPtr<id<MTLFunction>>, angle::kNumANGLEFormats>;
620     using ConvertToFloatVertexShaderArray =
621         std::array<AutoObjCPtr<id<MTLFunction>>, angle::kNumANGLEFormats>;
622 
623     ConvertToFloatComputeShaderArray mConvertToFloatCompPipelineCaches;
624     ConvertToFloatVertexShaderArray mConvertToFloatVertexShaders;
625 
626     AutoObjCPtr<id<MTLFunction>> mComponentsExpandComputeShader;
627     AutoObjCPtr<id<MTLFunction>> mComponentsExpandVertexShader;
628 };
629 
630 // Util class for linearizing PVRTC1 data for buffer to texture uploads
631 class BlockLinearizationUtils final : angle::NonCopyable
632 {
633   public:
634     angle::Result linearizeBlocks(ContextMtl *contextMtl, const BlockLinearizationParams &params);
635 
636   private:
637     angle::Result getBlockLinearizationComputePipeline(
638         ContextMtl *contextMtl,
639         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
640 
641     AutoObjCPtr<id<MTLFunction>> mLinearizeBlocksComputeShader;
642 };
643 
644 // Util class for saturating floating-pont depth data for texture uploads
645 class DepthSaturationUtils final : angle::NonCopyable
646 {
647   public:
648     angle::Result saturateDepth(ContextMtl *contextMtl, const DepthSaturationParams &params);
649 
650   private:
651     angle::Result getDepthSaturationComputePipeline(
652         ContextMtl *contextMtl,
653         AutoObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
654 
655     AutoObjCPtr<id<MTLFunction>> mSaturateDepthComputeShader;
656 };
657 
658 // RenderUtils: container class of various util classes above
659 class RenderUtils : public Context, angle::NonCopyable
660 {
661   public:
662     RenderUtils(DisplayMtl *display);
663     ~RenderUtils() override;
664 
665     // Clear current framebuffer
666     angle::Result clearWithDraw(const gl::Context *context,
667                                 RenderCommandEncoder *cmdEncoder,
668                                 const ClearRectParams &params);
669     // Blit texture data to current framebuffer
670     angle::Result blitColorWithDraw(const gl::Context *context,
671                                     RenderCommandEncoder *cmdEncoder,
672                                     const angle::Format &srcAngleFormat,
673                                     const ColorBlitParams &params);
674     // Same as above but blit the whole texture to the whole of current framebuffer.
675     // This function assumes the framebuffer and the source texture have same size.
676     angle::Result blitColorWithDraw(const gl::Context *context,
677                                     RenderCommandEncoder *cmdEncoder,
678                                     const angle::Format &srcAngleFormat,
679                                     const TextureRef &srcTexture);
680     angle::Result copyTextureWithDraw(const gl::Context *context,
681                                       RenderCommandEncoder *cmdEncoder,
682                                       const angle::Format &srcAngleFormat,
683                                       const angle::Format &dstAngleFormat,
684                                       const ColorBlitParams &params);
685 
686     angle::Result blitDepthStencilWithDraw(const gl::Context *context,
687                                            RenderCommandEncoder *cmdEncoder,
688                                            const DepthStencilBlitParams &params);
689     // See DepthStencilBlitUtils::blitStencilViaCopyBuffer()
690     angle::Result blitStencilViaCopyBuffer(const gl::Context *context,
691                                            const StencilBlitViaBufferParams &params);
692 
693     // See IndexGeneratorUtils
694     angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
695                                         const IndexConversionParams &params);
696     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
697                                                  const TriFanOrLineLoopFromArrayParams &params);
698     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
699                                                         const IndexGenerationParams &params,
700                                                         uint32_t *indicesGenerated);
701 
702     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
703                                                    const TriFanOrLineLoopFromArrayParams &params);
704     angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
705                                               uint32_t firstVertex,
706                                               uint32_t lastVertex,
707                                               const BufferRef &dstBuffer,
708                                               uint32_t dstOffset);
709     angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
710                                                           const IndexGenerationParams &params,
711                                                           uint32_t *indicesGenerated);
712     angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
713                                                                const IndexGenerationParams &params);
714 
715     void combineVisibilityResult(ContextMtl *contextMtl,
716                                  bool keepOldValue,
717                                  const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets,
718                                  const BufferRef &renderPassResultBuf,
719                                  const BufferRef &finalResultBuf);
720 
721     // Compute based mipmap generation. Only possible for 3D texture for now.
722     angle::Result generateMipmapCS(ContextMtl *contextMtl,
723                                    const TextureRef &srcTexture,
724                                    bool sRGBMipmap,
725                                    NativeTexLevelArray *mipmapOutputViews);
726 
727     angle::Result unpackPixelsFromBufferToTexture(ContextMtl *contextMtl,
728                                                   const angle::Format &srcAngleFormat,
729                                                   const CopyPixelsFromBufferParams &params);
730     angle::Result packPixelsFromTextureToBuffer(ContextMtl *contextMtl,
731                                                 const angle::Format &dstAngleFormat,
732                                                 const CopyPixelsToBufferParams &params);
733 
734     // See VertexFormatConversionUtils::convertVertexFormatToFloatCS()
735     angle::Result convertVertexFormatToFloatCS(ContextMtl *contextMtl,
736                                                const angle::Format &srcAngleFormat,
737                                                const VertexFormatConvertParams &params);
738     // See VertexFormatConversionUtils::convertVertexFormatToFloatVS()
739     angle::Result convertVertexFormatToFloatVS(const gl::Context *context,
740                                                RenderCommandEncoder *renderEncoder,
741                                                const angle::Format &srcAngleFormat,
742                                                const VertexFormatConvertParams &params);
743     // See VertexFormatConversionUtils::expandVertexFormatComponentsCS()
744     angle::Result expandVertexFormatComponentsCS(ContextMtl *contextMtl,
745                                                  const angle::Format &srcAngleFormat,
746                                                  const VertexFormatConvertParams &params);
747     // See VertexFormatConversionUtils::expandVertexFormatComponentsVS()
748     angle::Result expandVertexFormatComponentsVS(const gl::Context *context,
749                                                  RenderCommandEncoder *renderEncoder,
750                                                  const angle::Format &srcAngleFormat,
751                                                  const VertexFormatConvertParams &params);
752 
753     angle::Result generatePrimitiveRestartPointsBuffer(ContextMtl *contextMtl,
754                                                        const IndexGenerationParams &params,
755                                                        size_t *indicesGenerated);
756     angle::Result generatePrimitiveRestartLinesBuffer(ContextMtl *contextMtl,
757                                                       const IndexGenerationParams &params,
758                                                       size_t *indicesGenerated);
759     angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
760                                                           const IndexGenerationParams &params,
761                                                           size_t *indicesGenerated);
762 
763     // See BlockLinearizationUtils::linearizeBlocks()
764     angle::Result linearizeBlocks(ContextMtl *contextMtl, const BlockLinearizationParams &params);
765 
766     // See DepthSaturationUtils::saturateDepth()
767     angle::Result saturateDepth(ContextMtl *contextMtl, const DepthSaturationParams &params);
768 
769   private:
770     // override ErrorHandler
771     void handleError(GLenum error,
772                      const char *message,
773                      const char *file,
774                      const char *function,
775                      unsigned int line) override;
776     void handleError(NSError *error,
777                      const char *message,
778                      const char *file,
779                      const char *function,
780                      unsigned int line) override;
781 
782     std::array<ClearUtils, angle::EnumSize<PixelType>()> mClearUtils;
783 
784     std::array<ColorBlitUtils, angle::EnumSize<PixelType>()> mColorBlitUtils;
785     ColorBlitUtils mCopyTextureFloatToUIntUtils;
786 
787     DepthStencilBlitUtils mDepthStencilBlitUtils;
788     IndexGeneratorUtils mIndexUtils;
789     VisibilityResultUtils mVisibilityResultUtils;
790     MipmapUtils mMipmapUtils;
791     std::array<CopyPixelsUtils, angle::EnumSize<PixelType>()> mCopyPixelsUtils;
792     VertexFormatConversionUtils mVertexFormatUtils;
793     BlockLinearizationUtils mBlockLinearizationUtils;
794     DepthSaturationUtils mDepthSaturationUtils;
795 };
796 
797 }  // namespace mtl
798 }  // namespace rx
799 
800 #endif /* LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_ */
801