• 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 #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         angle::ObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
239 
240     const std::string mFragmentShaderName;
241 
242     angle::ObjCPtr<id<MTLFunction>> mVertexShader;
243     std::array<angle::ObjCPtr<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     ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
259     struct ShaderKey
260     {
261         int sourceTextureType        = 0;
262         uint32_t numColorAttachments : 29;
263         uint32_t unmultiplyAlpha : 1;
264         uint32_t premultiplyAlpha : 1;
265         uint32_t transformLinearToSrgb : 1;
ShaderKeyShaderKey266         ShaderKey()
267             : numColorAttachments(0),
268               unmultiplyAlpha(false),
269               premultiplyAlpha(false),
270               transformLinearToSrgb(false)
271         {}
ShaderKeyShaderKey272         ShaderKey(int sourceTextureType,
273                   uint32_t numColorAttachments,
274                   bool unmultiplyAlpha,
275                   bool premultiplyAlpha,
276                   bool transformLinearToSrgb)
277             : sourceTextureType(sourceTextureType),
278               numColorAttachments(numColorAttachments),
279               unmultiplyAlpha(unmultiplyAlpha != premultiplyAlpha ? unmultiplyAlpha : false),
280               premultiplyAlpha(unmultiplyAlpha != premultiplyAlpha ? premultiplyAlpha : false),
281               transformLinearToSrgb(transformLinearToSrgb)
282         {}
283         bool operator==(const ShaderKey &other) const
284         {
285             return sourceTextureType == other.sourceTextureType &&
286                    numColorAttachments == other.numColorAttachments &&
287                    unmultiplyAlpha == other.unmultiplyAlpha &&
288                    premultiplyAlpha == other.premultiplyAlpha &&
289                    transformLinearToSrgb == other.transformLinearToSrgb;
290         }
291         struct Hash
292         {
operatorShaderKey::Hash293             size_t operator()(const ShaderKey &k) const noexcept
294             {
295                 return angle::HashMultiple(k.sourceTextureType, k.numColorAttachments,
296                                            k.unmultiplyAlpha, k.premultiplyAlpha,
297                                            k.transformLinearToSrgb);
298             }
299         };
300     };
301     ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
302     static_assert(sizeof(ShaderKey) == 8);
303     angle::Result ensureShadersInitialized(ContextMtl *ctx,
304                                            const ShaderKey &key,
305                                            angle::ObjCPtr<id<MTLFunction>> *fragmentShaderOut);
306 
307     angle::Result setupColorBlitWithDraw(const gl::Context *context,
308                                          RenderCommandEncoder *cmdEncoder,
309                                          const ColorBlitParams &params);
310 
311     angle::Result getColorBlitRenderPipelineState(
312         const gl::Context *context,
313         RenderCommandEncoder *cmdEncoder,
314         const ColorBlitParams &params,
315         angle::ObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
316 
317     const std::string mFragmentShaderName;
318 
319     angle::ObjCPtr<id<MTLFunction>> mVertexShader;
320 
321     // Blit fragment shaders.
322     std::unordered_map<ShaderKey, angle::ObjCPtr<id<MTLFunction>>, ShaderKey::Hash>
323         mBlitFragmentShaders;
324 };
325 
326 class DepthStencilBlitUtils final : angle::NonCopyable
327 {
328   public:
329     angle::Result blitDepthStencilWithDraw(const gl::Context *context,
330                                            RenderCommandEncoder *cmdEncoder,
331                                            const DepthStencilBlitParams &params);
332 
333     // Blit stencil data using intermediate buffer. This function is used on devices with no
334     // support for direct stencil write in shader. Thus an intermediate buffer storing copied
335     // stencil data is needed.
336     // NOTE: this function shares the params struct with depth & stencil blit, but depth texture
337     // parameter is not used. This function will break existing render pass.
338     angle::Result blitStencilViaCopyBuffer(const gl::Context *context,
339                                            const StencilBlitViaBufferParams &params);
340 
341   private:
342     angle::Result ensureShadersInitialized(ContextMtl *ctx,
343                                            int sourceDepthTextureType,
344                                            int sourceStencilTextureType,
345                                            angle::ObjCPtr<id<MTLFunction>> *fragmentShaderOut);
346 
347     angle::Result setupDepthStencilBlitWithDraw(const gl::Context *context,
348                                                 RenderCommandEncoder *cmdEncoder,
349                                                 const DepthStencilBlitParams &params);
350 
351     angle::Result getDepthStencilBlitRenderPipelineState(
352         const gl::Context *context,
353         RenderCommandEncoder *cmdEncoder,
354         const DepthStencilBlitParams &params,
355         angle::ObjCPtr<id<MTLRenderPipelineState>> *outRenderPipelineState);
356 
357     angle::Result getStencilToBufferComputePipelineState(
358         ContextMtl *ctx,
359         const StencilBlitViaBufferParams &params,
360         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipelineState);
361 
362     angle::ObjCPtr<id<MTLFunction>> mVertexShader;
363 
364     std::array<angle::ObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
365         mDepthBlitFragmentShaders;
366     std::array<angle::ObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
367         mStencilBlitFragmentShaders;
368     std::array<std::array<angle::ObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>,
369                mtl_shader::kTextureTypeCount>
370         mDepthStencilBlitFragmentShaders;
371 
372     std::array<angle::ObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount>
373         mStencilBlitToBufferComputeShaders;
374 
375     // Intermediate buffer for storing copied stencil data. Used when device doesn't support
376     // writing stencil in shader.
377     BufferRef mStencilCopyBuffer;
378 };
379 
380 // util class for generating index buffer
381 class IndexGeneratorUtils final : angle::NonCopyable
382 {
383   public:
384     angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
385                                         const IndexConversionParams &params);
386     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
387                                                  const TriFanOrLineLoopFromArrayParams &params);
388     // Generate triangle fan index buffer for glDrawElements().
389     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
390                                                         const IndexGenerationParams &params,
391                                                         uint32_t *indicesGenerated);
392 
393     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
394                                                    const TriFanOrLineLoopFromArrayParams &params);
395     angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
396                                               uint32_t firstVertex,
397                                               uint32_t lastVertex,
398                                               const BufferRef &dstBuffer,
399                                               uint32_t dstOffset);
400     // Generate line loop index buffer for glDrawElements().
401     // Destination buffer must have at least 2x the number of original indices if primitive restart
402     // is enabled.
403     angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
404                                                           const IndexGenerationParams &params,
405                                                           uint32_t *indicesGenerated);
406     // Generate line loop's last segment index buffer for glDrawElements().
407     // NOTE: this function assumes primitive restart is not enabled.
408     angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
409                                                                const IndexGenerationParams &params);
410 
411   private:
412     // Index generator compute shaders:
413     //  - First dimension: index type.
414     //  - second dimension: source buffer's offset is aligned or not.
415     using IndexConversionShaderArray = std::array<std::array<angle::ObjCPtr<id<MTLFunction>>, 2>,
416                                                   angle::EnumSize<gl::DrawElementsType>()>;
417 
418     angle::Result getIndexConversionPipeline(
419         ContextMtl *contextMtl,
420         gl::DrawElementsType srcType,
421         uint32_t srcOffset,
422         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
423     // Get compute pipeline to generate tri fan/line loop index for glDrawElements().
424     angle::Result getIndicesFromElemArrayGeneratorPipeline(
425         ContextMtl *contextMtl,
426         gl::DrawElementsType srcType,
427         uint32_t srcOffset,
428         NSString *shaderName,
429         IndexConversionShaderArray *pipelineCacheArray,
430         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
431     // Defer loading of compute pipeline to generate tri fan index for glDrawArrays().
432     angle::Result getTriFanFromArrayGeneratorPipeline(
433         ContextMtl *contextMtl,
434         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
435     // Defer loading of compute pipeline to generate line loop index for glDrawArrays().
436     angle::Result getLineLoopFromArrayGeneratorPipeline(
437         ContextMtl *contextMtl,
438         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
439 
440     angle::Result generateTriFanBufferFromElementsArrayGPU(
441         ContextMtl *contextMtl,
442         gl::DrawElementsType srcType,
443         uint32_t indexCount,
444         const BufferRef &srcBuffer,
445         uint32_t srcOffset,
446         const BufferRef &dstBuffer,
447         // Must be multiples of kIndexBufferOffsetAlignment
448         uint32_t dstOffset);
449     angle::Result generateTriFanBufferFromElementsArrayCPU(ContextMtl *contextMtl,
450                                                            const IndexGenerationParams &params,
451                                                            uint32_t *indicesGenerated);
452 
453     angle::Result generateLineLoopBufferFromElementsArrayGPU(
454         ContextMtl *contextMtl,
455         gl::DrawElementsType srcType,
456         uint32_t indexCount,
457         const BufferRef &srcBuffer,
458         uint32_t srcOffset,
459         const BufferRef &dstBuffer,
460         // Must be multiples of kIndexBufferOffsetAlignment
461         uint32_t dstOffset);
462     angle::Result generateLineLoopBufferFromElementsArrayCPU(ContextMtl *contextMtl,
463                                                              const IndexGenerationParams &params,
464                                                              uint32_t *indicesGenerated);
465     angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
466         ContextMtl *contextMtl,
467         const IndexGenerationParams &params);
468 
469     IndexConversionShaderArray mIndexConversionShaders;
470 
471     IndexConversionShaderArray mTriFanFromElemArrayGeneratorShaders;
472     angle::ObjCPtr<id<MTLFunction>> mTriFanFromArraysGeneratorShader;
473 
474     IndexConversionShaderArray mLineLoopFromElemArrayGeneratorShaders;
475     angle::ObjCPtr<id<MTLFunction>> mLineLoopFromArraysGeneratorShader;
476 };
477 
478 // Util class for handling visibility query result
479 class VisibilityResultUtils final : angle::NonCopyable
480 {
481   public:
482     angle::Result combineVisibilityResult(
483         ContextMtl *contextMtl,
484         bool keepOldValue,
485         const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets,
486         const BufferRef &renderPassResultBuf,
487         const BufferRef &finalResultBuf);
488 
489   private:
490     angle::Result getVisibilityResultCombinePipeline(
491         ContextMtl *contextMtl,
492         bool keepOldValue,
493         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
494     // Visibility combination compute shaders:
495     // - 0: This compute shader only combines the new values and discard old value.
496     // - 1: This compute shader keep the old value and combines with new values.
497     std::array<angle::ObjCPtr<id<MTLFunction>>, 2> mVisibilityResultCombineComputeShaders;
498 };
499 
500 // Util class for handling mipmap generation
501 class MipmapUtils final : angle::NonCopyable
502 {
503   public:
504     // Compute based mipmap generation.
505     angle::Result generateMipmapCS(ContextMtl *contextMtl,
506                                    const TextureRef &srcTexture,
507                                    bool sRGBMipmap,
508                                    NativeTexLevelArray *mipmapOutputViews);
509 
510   private:
511     angle::Result get3DMipGeneratorPipeline(
512         ContextMtl *contextMtl,
513         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
514     angle::Result get2DMipGeneratorPipeline(
515         ContextMtl *contextMtl,
516         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
517     angle::Result get2DArrayMipGeneratorPipeline(
518         ContextMtl *contextMtl,
519         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
520     angle::Result getCubeMipGeneratorPipeline(
521         ContextMtl *contextMtl,
522         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
523 
524     // Mipmaps generating compute pipeline:
525     angle::ObjCPtr<id<MTLFunction>> m3DMipGeneratorShader;
526     angle::ObjCPtr<id<MTLFunction>> m2DMipGeneratorShader;
527     angle::ObjCPtr<id<MTLFunction>> m2DArrayMipGeneratorShader;
528     angle::ObjCPtr<id<MTLFunction>> mCubeMipGeneratorShader;
529 };
530 
531 // Util class for handling pixels copy between buffers and textures
532 class CopyPixelsUtils final : angle::NonCopyable
533 {
534   public:
535     CopyPixelsUtils() = default;
536     CopyPixelsUtils(const std::string &readShaderName, const std::string &writeShaderName);
537 
538     angle::Result unpackPixelsFromBufferToTexture(ContextMtl *contextMtl,
539                                                   const angle::Format &srcAngleFormat,
540                                                   const CopyPixelsFromBufferParams &params);
541     angle::Result packPixelsFromTextureToBuffer(ContextMtl *contextMtl,
542                                                 const angle::Format &dstAngleFormat,
543                                                 const CopyPixelsToBufferParams &params);
544 
545   private:
546     angle::Result getPixelsCopyPipeline(
547         ContextMtl *contextMtl,
548         const angle::Format &angleFormat,
549         const TextureRef &texture,
550         bool bufferWrite,
551         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
552     // Copy pixels between buffer and texture compute pipelines:
553     // - First dimension: pixel format.
554     // - Second dimension: texture type * (buffer read/write flag)
555     using PixelsCopyComputeShaderArray =
556         std::array<std::array<angle::ObjCPtr<id<MTLFunction>>, mtl_shader::kTextureTypeCount * 2>,
557                    angle::kNumANGLEFormats>;
558     PixelsCopyComputeShaderArray mPixelsCopyComputeShaders;
559 
560     const std::string mReadShaderName;
561     const std::string mWriteShaderName;
562 };
563 
564 // Util class for handling vertex format conversion on GPU
565 class VertexFormatConversionUtils final : angle::NonCopyable
566 {
567   public:
568     // Convert vertex format to float. Compute shader version.
569     angle::Result convertVertexFormatToFloatCS(ContextMtl *contextMtl,
570                                                const angle::Format &srcAngleFormat,
571                                                const VertexFormatConvertParams &params);
572     // Convert vertex format to float. Vertex shader version. This version should be used if
573     // a render pass is active and we don't want to break it. Explicit memory barrier must be
574     // supported.
575     angle::Result convertVertexFormatToFloatVS(const gl::Context *context,
576                                                RenderCommandEncoder *renderEncoder,
577                                                const angle::Format &srcAngleFormat,
578                                                const VertexFormatConvertParams &params);
579     // Expand number of components per vertex's attribute (or just simply copy components between
580     // buffers with different stride and offset)
581     angle::Result expandVertexFormatComponentsCS(ContextMtl *contextMtl,
582                                                  const angle::Format &srcAngleFormat,
583                                                  const VertexFormatConvertParams &params);
584     angle::Result expandVertexFormatComponentsVS(const gl::Context *context,
585                                                  RenderCommandEncoder *renderEncoder,
586                                                  const angle::Format &srcAngleFormat,
587                                                  const VertexFormatConvertParams &params);
588 
589   private:
590     angle::Result getComponentsExpandComputePipeline(
591         ContextMtl *contextMtl,
592         angle::ObjCPtr<id<MTLComputePipelineState>> *outPipelineState);
593     angle::Result getComponentsExpandRenderPipeline(
594         ContextMtl *contextMtl,
595         RenderCommandEncoder *renderEncoder,
596         angle::ObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
597 
598     angle::Result getFloatConverstionComputePipeline(
599         ContextMtl *contextMtl,
600         const angle::Format &srcAngleFormat,
601         angle::ObjCPtr<id<MTLComputePipelineState>> *outPipelineState);
602 
603     angle::Result getFloatConverstionRenderPipeline(
604         ContextMtl *contextMtl,
605         RenderCommandEncoder *renderEncoder,
606         const angle::Format &srcAngleFormat,
607         angle::ObjCPtr<id<MTLRenderPipelineState>> *outPipelineState);
608 
609     template <typename EncoderType, typename PipelineType>
610     angle::Result setupCommonConvertVertexFormatToFloat(ContextMtl *contextMtl,
611                                                         EncoderType cmdEncoder,
612                                                         const PipelineType &pipeline,
613                                                         const angle::Format &srcAngleFormat,
614                                                         const VertexFormatConvertParams &params);
615     template <typename EncoderType, typename PipelineType>
616     angle::Result setupCommonExpandVertexFormatComponents(ContextMtl *contextMtl,
617                                                           EncoderType cmdEncoder,
618                                                           const PipelineType &pipeline,
619                                                           const angle::Format &srcAngleFormat,
620                                                           const VertexFormatConvertParams &params);
621 
622     using ConvertToFloatComputeShaderArray =
623         std::array<angle::ObjCPtr<id<MTLFunction>>, angle::kNumANGLEFormats>;
624     using ConvertToFloatVertexShaderArray =
625         std::array<angle::ObjCPtr<id<MTLFunction>>, angle::kNumANGLEFormats>;
626 
627     ConvertToFloatComputeShaderArray mConvertToFloatCompPipelineCaches;
628     ConvertToFloatVertexShaderArray mConvertToFloatVertexShaders;
629 
630     angle::ObjCPtr<id<MTLFunction>> mComponentsExpandComputeShader;
631     angle::ObjCPtr<id<MTLFunction>> mComponentsExpandVertexShader;
632 };
633 
634 // Util class for linearizing PVRTC1 data for buffer to texture uploads
635 class BlockLinearizationUtils final : angle::NonCopyable
636 {
637   public:
638     angle::Result linearizeBlocks(ContextMtl *contextMtl, const BlockLinearizationParams &params);
639 
640   private:
641     angle::Result getBlockLinearizationComputePipeline(
642         ContextMtl *contextMtl,
643         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
644 
645     angle::ObjCPtr<id<MTLFunction>> mLinearizeBlocksComputeShader;
646 };
647 
648 // Util class for saturating floating-pont depth data for texture uploads
649 class DepthSaturationUtils final : angle::NonCopyable
650 {
651   public:
652     angle::Result saturateDepth(ContextMtl *contextMtl, const DepthSaturationParams &params);
653 
654   private:
655     angle::Result getDepthSaturationComputePipeline(
656         ContextMtl *contextMtl,
657         angle::ObjCPtr<id<MTLComputePipelineState>> *outComputePipeline);
658 
659     angle::ObjCPtr<id<MTLFunction>> mSaturateDepthComputeShader;
660 };
661 
662 // RenderUtils: container class of various util classes above
663 class RenderUtils : angle::NonCopyable
664 {
665   public:
666     RenderUtils();
667 
668     // Clear current framebuffer
669     angle::Result clearWithDraw(const gl::Context *context,
670                                 RenderCommandEncoder *cmdEncoder,
671                                 const ClearRectParams &params);
672     // Blit texture data to current framebuffer
673     angle::Result blitColorWithDraw(const gl::Context *context,
674                                     RenderCommandEncoder *cmdEncoder,
675                                     const angle::Format &srcAngleFormat,
676                                     const ColorBlitParams &params);
677     // Same as above but blit the whole texture to the whole of current framebuffer.
678     // This function assumes the framebuffer and the source texture have same size.
679     angle::Result blitColorWithDraw(const gl::Context *context,
680                                     RenderCommandEncoder *cmdEncoder,
681                                     const angle::Format &srcAngleFormat,
682                                     const TextureRef &srcTexture);
683     angle::Result copyTextureWithDraw(const gl::Context *context,
684                                       RenderCommandEncoder *cmdEncoder,
685                                       const angle::Format &srcAngleFormat,
686                                       const angle::Format &dstAngleFormat,
687                                       const ColorBlitParams &params);
688 
689     angle::Result blitDepthStencilWithDraw(const gl::Context *context,
690                                            RenderCommandEncoder *cmdEncoder,
691                                            const DepthStencilBlitParams &params);
692     // See DepthStencilBlitUtils::blitStencilViaCopyBuffer()
693     angle::Result blitStencilViaCopyBuffer(const gl::Context *context,
694                                            const StencilBlitViaBufferParams &params);
695 
696     // See IndexGeneratorUtils
697     angle::Result convertIndexBufferGPU(ContextMtl *contextMtl,
698                                         const IndexConversionParams &params);
699     angle::Result generateTriFanBufferFromArrays(ContextMtl *contextMtl,
700                                                  const TriFanOrLineLoopFromArrayParams &params);
701     angle::Result generateTriFanBufferFromElementsArray(ContextMtl *contextMtl,
702                                                         const IndexGenerationParams &params,
703                                                         uint32_t *indicesGenerated);
704 
705     angle::Result generateLineLoopBufferFromArrays(ContextMtl *contextMtl,
706                                                    const TriFanOrLineLoopFromArrayParams &params);
707     angle::Result generateLineLoopLastSegment(ContextMtl *contextMtl,
708                                               uint32_t firstVertex,
709                                               uint32_t lastVertex,
710                                               const BufferRef &dstBuffer,
711                                               uint32_t dstOffset);
712     angle::Result generateLineLoopBufferFromElementsArray(ContextMtl *contextMtl,
713                                                           const IndexGenerationParams &params,
714                                                           uint32_t *indicesGenerated);
715     angle::Result generateLineLoopLastSegmentFromElementsArray(ContextMtl *contextMtl,
716                                                                const IndexGenerationParams &params);
717 
718     void combineVisibilityResult(ContextMtl *contextMtl,
719                                  bool keepOldValue,
720                                  const VisibilityBufferOffsetsMtl &renderPassResultBufOffsets,
721                                  const BufferRef &renderPassResultBuf,
722                                  const BufferRef &finalResultBuf);
723 
724     // Compute based mipmap generation. Only possible for 3D texture for now.
725     angle::Result generateMipmapCS(ContextMtl *contextMtl,
726                                    const TextureRef &srcTexture,
727                                    bool sRGBMipmap,
728                                    NativeTexLevelArray *mipmapOutputViews);
729 
730     angle::Result unpackPixelsFromBufferToTexture(ContextMtl *contextMtl,
731                                                   const angle::Format &srcAngleFormat,
732                                                   const CopyPixelsFromBufferParams &params);
733     angle::Result packPixelsFromTextureToBuffer(ContextMtl *contextMtl,
734                                                 const angle::Format &dstAngleFormat,
735                                                 const CopyPixelsToBufferParams &params);
736 
737     // See VertexFormatConversionUtils::convertVertexFormatToFloatCS()
738     angle::Result convertVertexFormatToFloatCS(ContextMtl *contextMtl,
739                                                const angle::Format &srcAngleFormat,
740                                                const VertexFormatConvertParams &params);
741     // See VertexFormatConversionUtils::convertVertexFormatToFloatVS()
742     angle::Result convertVertexFormatToFloatVS(const gl::Context *context,
743                                                RenderCommandEncoder *renderEncoder,
744                                                const angle::Format &srcAngleFormat,
745                                                const VertexFormatConvertParams &params);
746     // See VertexFormatConversionUtils::expandVertexFormatComponentsCS()
747     angle::Result expandVertexFormatComponentsCS(ContextMtl *contextMtl,
748                                                  const angle::Format &srcAngleFormat,
749                                                  const VertexFormatConvertParams &params);
750     // See VertexFormatConversionUtils::expandVertexFormatComponentsVS()
751     angle::Result expandVertexFormatComponentsVS(const gl::Context *context,
752                                                  RenderCommandEncoder *renderEncoder,
753                                                  const angle::Format &srcAngleFormat,
754                                                  const VertexFormatConvertParams &params);
755 
756     angle::Result generatePrimitiveRestartTrianglesBuffer(ContextMtl *contextMtl,
757                                                           const IndexGenerationParams &params,
758                                                           size_t *indicesGenerated);
759 
760     // See BlockLinearizationUtils::linearizeBlocks()
761     angle::Result linearizeBlocks(ContextMtl *contextMtl, const BlockLinearizationParams &params);
762 
763     // See DepthSaturationUtils::saturateDepth()
764     angle::Result saturateDepth(ContextMtl *contextMtl, const DepthSaturationParams &params);
765 
766   private:
767     std::array<ClearUtils, angle::EnumSize<PixelType>()> mClearUtils;
768 
769     std::array<ColorBlitUtils, angle::EnumSize<PixelType>()> mColorBlitUtils;
770     ColorBlitUtils mCopyTextureFloatToUIntUtils;
771 
772     DepthStencilBlitUtils mDepthStencilBlitUtils;
773     IndexGeneratorUtils mIndexUtils;
774     VisibilityResultUtils mVisibilityResultUtils;
775     MipmapUtils mMipmapUtils;
776     std::array<CopyPixelsUtils, angle::EnumSize<PixelType>()> mCopyPixelsUtils;
777     VertexFormatConversionUtils mVertexFormatUtils;
778     BlockLinearizationUtils mBlockLinearizationUtils;
779     DepthSaturationUtils mDepthSaturationUtils;
780 };
781 
782 }  // namespace mtl
783 }  // namespace rx
784 
785 #endif /* LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_ */
786