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