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