• 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_common.h:
7 //      Declares common constants, template classes, and mtl::Context - the MTLDevice container &
8 //      error handler base class.
9 //
10 
11 #ifndef LIBANGLE_RENDERER_METAL_MTL_COMMON_H_
12 #define LIBANGLE_RENDERER_METAL_MTL_COMMON_H_
13 
14 #import <Metal/Metal.h>
15 
16 #include <TargetConditionals.h>
17 
18 #include <string>
19 
20 #include "common/Optional.h"
21 #include "common/PackedEnums.h"
22 #include "common/angleutils.h"
23 #include "common/apple_platform_utils.h"
24 #include "libANGLE/Constants.h"
25 #include "libANGLE/ImageIndex.h"
26 #include "libANGLE/Version.h"
27 #include "libANGLE/angletypes.h"
28 
29 #if defined(ANGLE_MTL_ENABLE_TRACE)
30 #    define ANGLE_MTL_LOG(...) NSLog(@__VA_ARGS__)
31 #else
32 #    define ANGLE_MTL_LOG(...) (void)0
33 #endif
34 
35 #define ANGLE_MTL_OBJC_SCOPE ANGLE_APPLE_OBJC_SCOPE
36 #define ANGLE_MTL_AUTORELEASE ANGLE_APPLE_AUTORELEASE
37 #define ANGLE_MTL_RETAIN ANGLE_APPLE_RETAIN
38 #define ANGLE_MTL_RELEASE ANGLE_APPLE_RELEASE
39 
40 namespace egl
41 {
42 class Display;
43 class Image;
44 class Surface;
45 }  // namespace egl
46 
47 #define ANGLE_GL_OBJECTS_X(PROC) \
48     PROC(Buffer)                 \
49     PROC(Context)                \
50     PROC(Framebuffer)            \
51     PROC(MemoryObject)           \
52     PROC(Query)                  \
53     PROC(Program)                \
54     PROC(ProgramExecutable)      \
55     PROC(Sampler)                \
56     PROC(Semaphore)              \
57     PROC(Texture)                \
58     PROC(TransformFeedback)      \
59     PROC(VertexArray)
60 
61 #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
62 
63 namespace gl
64 {
65 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT)
66 }  // namespace gl
67 
68 #define ANGLE_PRE_DECLARE_MTL_OBJECT(OBJ) class OBJ##Mtl;
69 
70 namespace rx
71 {
72 class DisplayMtl;
73 class ContextMtl;
74 class FramebufferMtl;
75 class BufferMtl;
76 class ImageMtl;
77 class VertexArrayMtl;
78 class TextureMtl;
79 class ProgramMtl;
80 class SamplerMtl;
81 class TransformFeedbackMtl;
82 
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)83 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)
84 
85 namespace mtl
86 {
87 
88 // NOTE(hqle): support variable max number of vertex attributes
89 constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
90 // Note: This is the max number of render targets the backend supports.
91 // It is NOT how many the device supports which may be lower. If you
92 // increase this number you will also need to edit the shaders in
93 // metal/shaders/common.h.
94 constexpr uint32_t kMaxRenderTargets = 8;
95 // Metal Apple1 iOS devices only support 4 render targets
96 constexpr uint32_t kMaxRenderTargetsOlderGPUFamilies = 4;
97 
98 constexpr uint32_t kMaxColorTargetBitsApple1To3      = 256;
99 constexpr uint32_t kMaxColorTargetBitsApple4Plus     = 512;
100 constexpr uint32_t kMaxColorTargetBitsMacAndCatalyst = std::numeric_limits<uint32_t>::max();
101 
102 constexpr uint32_t kMaxShaderUBOs = 12;
103 constexpr uint32_t kMaxUBOSize    = 16384;
104 
105 constexpr uint32_t kMaxShaderXFBs = gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
106 
107 // The max size of a buffer that will be allocated in shared memory.
108 // NOTE(hqle): This is just a hint. There is no official document on what is the max allowed size
109 // for shared memory.
110 constexpr size_t kSharedMemBufferMaxBufSizeHint = 256 * 1024;
111 
112 constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
113 
114 // Metal limits
115 constexpr uint32_t kMaxShaderBuffers     = 31;
116 constexpr uint32_t kMaxShaderSamplers    = 16;
117 constexpr size_t kInlineConstDataMaxSize = 4 * 1024;
118 constexpr size_t kDefaultUniformsMaxSize = 16 * 1024;
119 constexpr uint32_t kMaxViewports         = 1;
120 constexpr uint32_t kMaxShaderImages      = gl::IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES;
121 
122 // Restrict in-flight resource usage to 400 MB.
123 // A render pass can use more than 400MB, but the command buffer
124 // will be flushed next time
125 constexpr const size_t kMaximumResidentMemorySizeInBytes = 400 * 1024 * 1024;
126 
127 // Restrict in-flight render passes per command buffer to 16.
128 // The goal is to reduce the number of active render passes on the system at
129 // any one time and this value was determined through experimentation.
130 constexpr uint32_t kMaxRenderPassesPerCommandBuffer = 16;
131 
132 constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
133 // Alignment requirement for offset passed to setVertex|FragmentBuffer
134 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
135 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
136 #else
137 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
138 #endif
139 constexpr uint32_t kIndexBufferOffsetAlignment       = 4;
140 constexpr uint32_t kArgumentBufferOffsetAlignment    = kUniformBufferSettingOffsetMinAlignment;
141 constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
142 
143 // Front end binding limits
144 constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
145 constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
146 
147 // Binding index start for vertex data buffers:
148 constexpr uint32_t kVboBindingIndexStart = 0;
149 
150 // Binding index for default attribute buffer:
151 constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVertexAttribs;
152 // Binding index for driver uniforms:
153 constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
154 // Binding index for default uniforms:
155 constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
156 // Binding index for Transform Feedback Buffers (4)
157 constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
158 // Binding index for shadow samplers' compare modes
159 constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
160 // Binding index for UBO's argument buffer
161 constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
162 
163 constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
164 
165 // This special constant is used to indicate that a particular vertex descriptor's buffer layout
166 // index is unused.
167 constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
168     static_cast<MTLVertexStepFunction>(0xff);
169 
170 constexpr int kEmulatedAlphaValue = 1;
171 
172 constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
173 
174 constexpr gl::Version kMaxSupportedGLVersion = gl::Version(3, 0);
175 
176 // Work-around the enum is not available on macOS
177 #if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED < 110000)) || TARGET_OS_MACCATALYST
178 constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionNone;
179 #else
180 constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionRowLinearPVRTC;
181 #endif
182 
183 #if defined(__MAC_10_14) && (TARGET_OS_OSX || TARGET_OS_MACCATALYST)
184 constexpr MTLBarrierScope kBarrierScopeRenderTargets = MTLBarrierScopeRenderTargets;
185 #else
186 constexpr MTLBarrierScope kBarrierScopeRenderTargets = MTLBarrierScope(0);
187 #endif
188 
189 #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
190 #    define ANGLE_MTL_SWIZZLE_AVAILABLE 1
191 using TextureSwizzleChannels                   = MTLTextureSwizzleChannels;
192 using BarrierScope                             = MTLBarrierScope;
193 using RenderStages                             = MTLRenderStages;
194 constexpr MTLRenderStages kRenderStageVertex   = MTLRenderStageVertex;
195 constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
196 #else
197 #    define ANGLE_MTL_SWIZZLE_AVAILABLE 0
198 using TextureSwizzleChannels                = int;
199 using RenderStages                          = int;
200 constexpr RenderStages kRenderStageVertex   = 1;
201 constexpr RenderStages kRenderStageFragment = 2;
202 #endif
203 
204 enum class PixelType
205 {
206     Int,
207     UInt,
208     Float,
209     EnumCount,
210 };
211 
212 template <typename T>
213 struct ImplTypeHelper;
214 
215 // clang-format off
216 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
217 template<>                             \
218 struct ImplTypeHelper<gl::OBJ>         \
219 {                                      \
220     using ImplType = OBJ##Mtl;         \
221 };
222 // clang-format on
223 
224 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
225 
226 template <>
227 struct ImplTypeHelper<egl::Display>
228 {
229     using ImplType = DisplayMtl;
230 };
231 
232 template <>
233 struct ImplTypeHelper<egl::Image>
234 {
235     using ImplType = ImageMtl;
236 };
237 
238 template <typename T>
239 using GetImplType = typename ImplTypeHelper<T>::ImplType;
240 
241 template <typename T>
242 GetImplType<T> *GetImpl(const T *glObject)
243 {
244     return GetImplAs<GetImplType<T>>(glObject);
245 }
246 
247 // This class wraps Objective-C pointer inside, it will manage the lifetime of
248 // the Objective-C pointer. Changing pointer is not supported outside subclass.
249 template <typename T>
250 class WrappedObject
251 {
252   public:
253     WrappedObject() = default;
254     ~WrappedObject() { release(); }
255 
256     bool valid() const { return (mMetalObject != nil); }
257 
258     T get() const { return mMetalObject; }
259     T leakObject() { return std::exchange(mMetalObject, nullptr); }
260     inline void reset() { release(); }
261 
262     operator T() const { return get(); }
263 
264   protected:
265     inline void set(T obj) { retainAssign(obj); }
266 
267     void retainAssign(T obj)
268     {
269 
270 #if !__has_feature(objc_arc)
271         T retained = obj;
272         [retained retain];
273 #endif
274         release();
275         mMetalObject = obj;
276     }
277 
278     void unretainAssign(T obj)
279     {
280         release();
281         mMetalObject = obj;
282     }
283 
284   private:
285     void release()
286     {
287 #if !__has_feature(objc_arc)
288         [mMetalObject release];
289 #endif
290         mMetalObject = nil;
291     }
292 
293     T mMetalObject = nil;
294 };
295 
296 // Because ARC enablement is a compile-time choice, and we compile this header
297 // both ways, we need a separate copy of our code when ARC is enabled.
298 #if __has_feature(objc_arc)
299 #    define adoptObjCObj adoptObjCObjArc
300 #endif
301 template <typename T>
302 class AutoObjCPtr;
303 template <typename T>
304 using AutoObjCObj = AutoObjCPtr<T *>;
305 template <typename U>
306 AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT) __attribute__((__warn_unused_result__));
307 
308 // This class is similar to WrappedObject, however, it allows changing the
309 // internal pointer with public methods.
310 template <typename T>
311 class AutoObjCPtr : public WrappedObject<T>
312 {
313   public:
314     using ParentType = WrappedObject<T>;
315 
316     AutoObjCPtr() {}
317 
318     AutoObjCPtr(const std::nullptr_t &theNull) {}
319 
320     AutoObjCPtr(const AutoObjCPtr &src) { this->retainAssign(src.get()); }
321 
322     AutoObjCPtr(AutoObjCPtr &&src) { this->transfer(std::forward<AutoObjCPtr>(src)); }
323 
324     // Take ownership of the pointer
325     AutoObjCPtr(T &&src)
326     {
327         this->retainAssign(src);
328         src = nil;
329     }
330 
331     AutoObjCPtr &operator=(const AutoObjCPtr &src)
332     {
333         this->retainAssign(src.get());
334         return *this;
335     }
336 
337     AutoObjCPtr &operator=(AutoObjCPtr &&src)
338     {
339         this->transfer(std::forward<AutoObjCPtr>(src));
340         return *this;
341     }
342 
343     // Take ownership of the pointer
344     AutoObjCPtr &operator=(T &&src)
345     {
346         this->retainAssign(src);
347         src = nil;
348         return *this;
349     }
350 
351     AutoObjCPtr &operator=(std::nullptr_t theNull)
352     {
353         this->set(nil);
354         return *this;
355     }
356 
357     bool operator==(const AutoObjCPtr &rhs) const { return (*this) == rhs.get(); }
358 
359     bool operator==(T rhs) const { return this->get() == rhs; }
360 
361     bool operator==(std::nullptr_t theNull) const { return this->get() == nullptr; }
362 
363     bool operator!=(std::nullptr_t) const { return this->get() != nullptr; }
364 
365     inline operator bool() { return this->get(); }
366 
367     bool operator!=(const AutoObjCPtr &rhs) const { return (*this) != rhs.get(); }
368 
369     bool operator!=(T rhs) const { return this->get() != rhs; }
370 
371     using ParentType::retainAssign;
372 
373     template <typename U>
374     friend AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT)
375         __attribute__((__warn_unused_result__));
376 
377   private:
378     enum AdoptTag
379     {
380         Adopt
381     };
382     AutoObjCPtr(T src, AdoptTag) { this->unretainAssign(src); }
383 
384     void transfer(AutoObjCPtr &&src)
385     {
386         this->retainAssign(std::move(src.get()));
387         src.reset();
388     }
389 };
390 
391 template <typename U>
392 inline AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT src)
393 {
394 #if __has_feature(objc_arc)
395     return src;
396 #elif defined(OBJC_NO_GC)
397     return AutoObjCPtr<U *>(src, AutoObjCPtr<U *>::Adopt);
398 #else
399 #    error "ObjC GC not supported."
400 #endif
401 }
402 
403 // NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
404 #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
405 #    define ANGLE_MTL_EVENT_AVAILABLE 1
406 #else
407 #    define ANGLE_MTL_EVENT_AVAILABLE 0
408 #endif
409 
410 // The native image index used by Metal back-end,  the image index uses native mipmap level instead
411 // of "virtual" level modified by OpenGL's base level.
412 using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
413 
414 constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
415 
416 class ImageNativeIndexIterator;
417 
418 class ImageNativeIndex final
419 {
420   public:
421     ImageNativeIndex() = delete;
422     ImageNativeIndex(const gl::ImageIndex &src, GLint baseLevel)
423     {
424         mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
425                                                     src.getLayerIndex(), src.getLayerCount());
426     }
427 
428     static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
429     {
430         return ImageNativeIndex(src, 0);
431     }
432 
433     MipmapNativeLevel getNativeLevel() const
434     {
435         return MipmapNativeLevel(mNativeIndex.getLevelIndex());
436     }
437 
438     gl::TextureType getType() const { return mNativeIndex.getType(); }
439     GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
440     GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
441     GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
442 
443     bool isLayered() const { return mNativeIndex.isLayered(); }
444     bool hasLayer() const { return mNativeIndex.hasLayer(); }
445     bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
446     bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
447 
448     bool valid() const { return mNativeIndex.valid(); }
449 
450     ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
451 
452   private:
453     gl::ImageIndex mNativeIndex;
454 };
455 
456 class ImageNativeIndexIterator final
457 {
458   public:
459     ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
460     ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
461     bool hasNext() const { return mNativeIndexIte.hasNext(); }
462 
463   private:
464     // This class is only constructable from ImageNativeIndex
465     friend class ImageNativeIndex;
466 
467     explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
468         : mNativeIndexIte(baseZeroSrc)
469     {}
470 
471     gl::ImageIndexIterator mNativeIndexIte;
472 };
473 
474 using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
475 
476 class ClearColorValue
477 {
478   public:
479     constexpr ClearColorValue()
480         : mType(PixelType::Float), mRedF(0), mGreenF(0), mBlueF(0), mAlphaF(0)
481     {}
482     constexpr ClearColorValue(float r, float g, float b, float a)
483         : mType(PixelType::Float), mRedF(r), mGreenF(g), mBlueF(b), mAlphaF(a)
484     {}
485     constexpr ClearColorValue(int32_t r, int32_t g, int32_t b, int32_t a)
486         : mType(PixelType::Int), mRedI(r), mGreenI(g), mBlueI(b), mAlphaI(a)
487     {}
488     constexpr ClearColorValue(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
489         : mType(PixelType::UInt), mRedU(r), mGreenU(g), mBlueU(b), mAlphaU(a)
490     {}
491     constexpr ClearColorValue(const ClearColorValue &src)
492         : mType(src.mType), mValueBytes(src.mValueBytes)
493     {}
494 
495     MTLClearColor toMTLClearColor() const;
496 
497     PixelType getType() const { return mType; }
498 
499     const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
500 
501     ClearColorValue &operator=(const ClearColorValue &src);
502 
503     void setAsFloat(float r, float g, float b, float a);
504     void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
505     void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
506 
507   private:
508     PixelType mType;
509 
510     union
511     {
512         struct
513         {
514             float mRedF, mGreenF, mBlueF, mAlphaF;
515         };
516         struct
517         {
518             int32_t mRedI, mGreenI, mBlueI, mAlphaI;
519         };
520         struct
521         {
522             uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
523         };
524 
525         ClearColorValueBytes mValueBytes;
526     };
527 };
528 
529 class CommandQueue;
530 class ErrorHandler
531 {
532   public:
533     virtual ~ErrorHandler() {}
534 
535     virtual void handleError(GLenum error,
536                              const char *message,
537                              const char *file,
538                              const char *function,
539                              unsigned int line) = 0;
540 
541     virtual void handleError(NSError *error,
542                              const char *message,
543                              const char *file,
544                              const char *function,
545                              unsigned int line) = 0;
546 };
547 
548 class Context : public ErrorHandler
549 {
550   public:
551     Context(DisplayMtl *displayMtl);
552     mtl::CommandQueue &cmdQueue();
553 
554     DisplayMtl *getDisplay() const { return mDisplay; }
555 
556   protected:
557     DisplayMtl *mDisplay;
558 };
559 
560 std::string FormatMetalErrorMessage(GLenum errorCode);
561 std::string FormatMetalErrorMessage(NSError *error);
562 
563 #define ANGLE_MTL_HANDLE_ERROR(context, message, error) \
564     context->handleError(error, message, __FILE__, ANGLE_FUNCTION, __LINE__)
565 
566 #define ANGLE_MTL_CHECK(context, test, error)                                                  \
567     do                                                                                         \
568     {                                                                                          \
569         if (ANGLE_UNLIKELY(!(test)))                                                           \
570         {                                                                                      \
571             context->handleError(error, mtl::FormatMetalErrorMessage(error).c_str(), __FILE__, \
572                                  ANGLE_FUNCTION, __LINE__);                                    \
573             return angle::Result::Stop;                                                        \
574         }                                                                                      \
575     } while (0)
576 
577 #define ANGLE_MTL_TRY(context, test) ANGLE_MTL_CHECK(context, test, GL_INVALID_OPERATION)
578 
579 #define ANGLE_MTL_UNREACHABLE(context) \
580     UNREACHABLE();                     \
581     ANGLE_MTL_TRY(context, false)
582 
583 }  // namespace mtl
584 }  // namespace rx
585 
586 #endif /* LIBANGLE_RENDERER_METAL_MTL_COMMON_H_ */
587