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