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