• 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 constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
146 // Alignment requirement for offset passed to setVertex|FragmentBuffer
147 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
148 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
149 #else
150 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
151 #endif
152 constexpr uint32_t kIndexBufferOffsetAlignment       = 4;
153 constexpr uint32_t kArgumentBufferOffsetAlignment    = kUniformBufferSettingOffsetMinAlignment;
154 constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
155 
156 // Front end binding limits
157 constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
158 constexpr uint32_t kMaxGLUBOBindings     = 2 * kMaxShaderUBOs;
159 
160 // Binding index start for vertex data buffers:
161 constexpr uint32_t kVboBindingIndexStart = 0;
162 
163 // Binding index for default attribute buffer:
164 constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVertexAttribs;
165 // Binding index for driver uniforms:
166 constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
167 // Binding index for default uniforms:
168 constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
169 // Binding index for Transform Feedback Buffers (4)
170 constexpr uint32_t kTransformFeedbackBindingIndex = kDefaultUniformsBindingIndex + 1;
171 // Binding index for shadow samplers' compare modes
172 constexpr uint32_t kShadowSamplerCompareModesBindingIndex = kTransformFeedbackBindingIndex + 4;
173 // Binding index for UBO's argument buffer
174 constexpr uint32_t kUBOArgumentBufferBindingIndex = kShadowSamplerCompareModesBindingIndex + 1;
175 
176 constexpr uint32_t kStencilMaskAll = 0xff;  // Only 8 bits stencil is supported
177 
178 static const char *kUnassignedAttributeString = " __unassigned_attribute__";
179 
180 // This special constant is used to indicate that a particular vertex descriptor's buffer layout
181 // index is unused.
182 constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
183     static_cast<MTLVertexStepFunction>(0xff);
184 
185 constexpr int kEmulatedAlphaValue = 1;
186 
187 constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
188 
189 constexpr gl::Version kMaxSupportedGLVersion = gl::Version(3, 0);
190 
191 // Work-around the enum is not available on macOS
192 #if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101600)) || TARGET_OS_MACCATALYST
193 constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionNone;
194 #else
195 constexpr MTLBlitOption kBlitOptionRowLinearPVRTC          = MTLBlitOptionRowLinearPVRTC;
196 #endif
197 
198 #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
199 #    define ANGLE_MTL_SWIZZLE_AVAILABLE 1
200 using TextureSwizzleChannels                   = MTLTextureSwizzleChannels;
201 using RenderStages                             = MTLRenderStages;
202 constexpr MTLRenderStages kRenderStageVertex   = MTLRenderStageVertex;
203 constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
204 #else
205 #    define ANGLE_MTL_SWIZZLE_AVAILABLE 0
206 using TextureSwizzleChannels                               = int;
207 using RenderStages                                         = int;
208 constexpr RenderStages kRenderStageVertex                  = 1;
209 constexpr RenderStages kRenderStageFragment                = 2;
210 #endif
211 
212 enum class PixelType
213 {
214     Int,
215     UInt,
216     Float,
217     EnumCount,
218 };
219 
220 template <typename T>
221 struct ImplTypeHelper;
222 
223 // clang-format off
224 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
225 template<>                             \
226 struct ImplTypeHelper<gl::OBJ>         \
227 {                                      \
228     using ImplType = OBJ##Mtl;         \
229 };
230 // clang-format on
231 
232 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
233 
234 template <>
235 struct ImplTypeHelper<egl::Display>
236 {
237     using ImplType = DisplayMtl;
238 };
239 
240 template <>
241 struct ImplTypeHelper<egl::Image>
242 {
243     using ImplType = ImageMtl;
244 };
245 
246 template <typename T>
247 using GetImplType = typename ImplTypeHelper<T>::ImplType;
248 
249 template <typename T>
250 GetImplType<T> *GetImpl(const T *_Nonnull glObject)
251 {
252     return GetImplAs<GetImplType<T>>(glObject);
253 }
254 
255 // This class wraps Objective-C pointer inside, it will manage the lifetime of
256 // the Objective-C pointer. Changing pointer is not supported outside subclass.
257 template <typename T>
258 class WrappedObject
259 {
260   public:
261     WrappedObject() = default;
262     ~WrappedObject() { release(); }
263 
264     bool valid() const { return (mMetalObject != nil); }
265 
266     T get() const { return mMetalObject; }
267     inline void reset() { release(); }
268 
269     operator T() const { return get(); }
270 
271   protected:
272     inline void set(T obj) { retainAssign(obj); }
273 
274     void retainAssign(T obj)
275     {
276 
277 #if !__has_feature(objc_arc)
278         T retained = obj;
279         [retained retain];
280 #endif
281         release();
282         mMetalObject = obj;
283     }
284 
285     void unretainAssign(T obj)
286     {
287         release();
288         mMetalObject = obj;
289     }
290 
291   private:
292     void release()
293     {
294 #if !__has_feature(objc_arc)
295         [mMetalObject release];
296 #endif
297         mMetalObject = nil;
298     }
299 
300     T mMetalObject = nil;
301 };
302 
303 // Because ARC enablement is a compile-time choice, and we compile this header
304 // both ways, we need a separate copy of our code when ARC is enabled.
305 #if __has_feature(objc_arc)
306 #    define adoptObjCObj adoptObjCObjArc
307 #endif
308 template <typename T>
309 class AutoObjCPtr;
310 template <typename T>
311 using AutoObjCObj = AutoObjCPtr<T *>;
312 template <typename U>
313 AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT) __attribute__((__warn_unused_result__));
314 
315 // This class is similar to WrappedObject, however, it allows changing the
316 // internal pointer with public methods.
317 template <typename T>
318 class AutoObjCPtr : public WrappedObject<T>
319 {
320   public:
321     using ParentType = WrappedObject<T>;
322 
323     AutoObjCPtr() {}
324 
325     AutoObjCPtr(const std::nullptr_t &theNull) {}
326 
327     AutoObjCPtr(const AutoObjCPtr &src) { this->retainAssign(src.get()); }
328 
329     AutoObjCPtr(AutoObjCPtr &&src) { this->transfer(std::forward<AutoObjCPtr>(src)); }
330 
331     // Take ownership of the pointer
332     AutoObjCPtr(T &&src)
333     {
334         this->retainAssign(src);
335         src = nil;
336     }
337 
338     AutoObjCPtr &operator=(const AutoObjCPtr &src)
339     {
340         this->retainAssign(src.get());
341         return *this;
342     }
343 
344     AutoObjCPtr &operator=(AutoObjCPtr &&src)
345     {
346         this->transfer(std::forward<AutoObjCPtr>(src));
347         return *this;
348     }
349 
350     // Take ownership of the pointer
351     AutoObjCPtr &operator=(T &&src)
352     {
353         this->retainAssign(src);
354         src = nil;
355         return *this;
356     }
357 
358     AutoObjCPtr &operator=(std::nullptr_t theNull)
359     {
360         this->set(nil);
361         return *this;
362     }
363 
364     bool operator==(const AutoObjCPtr &rhs) const { return (*this) == rhs.get(); }
365 
366     bool operator==(T rhs) const { return this->get() == rhs; }
367 
368     bool operator==(std::nullptr_t theNull) const { return this->get() == nullptr; }
369 
370     bool operator!=(std::nullptr_t) const { return this->get() != nullptr; }
371 
372     inline operator bool() { return this->get(); }
373 
374     bool operator!=(const AutoObjCPtr &rhs) const { return (*this) != rhs.get(); }
375 
376     bool operator!=(T rhs) const { return this->get() != rhs; }
377 
378     using ParentType::retainAssign;
379 
380     template <typename U>
381     friend AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT)
382         __attribute__((__warn_unused_result__));
383 
384   private:
385     enum AdoptTag
386     {
387         Adopt
388     };
389     AutoObjCPtr(T src, AdoptTag) { this->unretainAssign(src); }
390 
391     void transfer(AutoObjCPtr &&src)
392     {
393         this->retainAssign(std::move(src.get()));
394         src.reset();
395     }
396 };
397 
398 template <typename U>
399 inline AutoObjCObj<U> adoptObjCObj(U *NS_RELEASES_ARGUMENT src)
400 {
401 #if __has_feature(objc_arc)
402     return src;
403 #elif defined(OBJC_NO_GC)
404     return AutoObjCPtr<U *>(src, AutoObjCPtr<U *>::Adopt);
405 #else
406 #    error "ObjC GC not supported."
407 #endif
408 }
409 
410 // NOTE: SharedEvent is only declared on iOS 12.0+ or mac 10.14+
411 #if defined(__IPHONE_12_0) || defined(__MAC_10_14)
412 #    define ANGLE_MTL_EVENT_AVAILABLE 1
413 using SharedEventRef = AutoObjCPtr<id<MTLSharedEvent>>;
414 #else
415 #    define ANGLE_MTL_EVENT_AVAILABLE 0
416 using SharedEventRef = AutoObjCObj<NSObject>;
417 #endif
418 
419 // The native image index used by Metal back-end,  the image index uses native mipmap level instead
420 // of "virtual" level modified by OpenGL's base level.
421 using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
422 
423 constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
424 
425 class ImageNativeIndexIterator;
426 
427 class ImageNativeIndex final
428 {
429   public:
430     ImageNativeIndex() = delete;
431     ImageNativeIndex(const gl::ImageIndex &src, GLint baseLevel)
432     {
433         mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
434                                                     src.getLayerIndex(), src.getLayerCount());
435     }
436 
437     static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
438     {
439         return ImageNativeIndex(src, 0);
440     }
441 
442     MipmapNativeLevel getNativeLevel() const
443     {
444         return MipmapNativeLevel(mNativeIndex.getLevelIndex());
445     }
446 
447     gl::TextureType getType() const { return mNativeIndex.getType(); }
448     GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
449     GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
450     GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
451 
452     bool isLayered() const { return mNativeIndex.isLayered(); }
453     bool hasLayer() const { return mNativeIndex.hasLayer(); }
454     bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
455     bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
456 
457     bool valid() const { return mNativeIndex.valid(); }
458 
459     ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
460 
461   private:
462     gl::ImageIndex mNativeIndex;
463 };
464 
465 class ImageNativeIndexIterator final
466 {
467   public:
468     ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
469     ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
470     bool hasNext() const { return mNativeIndexIte.hasNext(); }
471 
472   private:
473     // This class is only constructable from ImageNativeIndex
474     friend class ImageNativeIndex;
475 
476     explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
477         : mNativeIndexIte(baseZeroSrc)
478     {}
479 
480     gl::ImageIndexIterator mNativeIndexIte;
481 };
482 
483 using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
484 
485 class ClearColorValue
486 {
487   public:
488     constexpr ClearColorValue()
489         : mType(PixelType::Float), mRedF(0), mGreenF(0), mBlueF(0), mAlphaF(0)
490     {}
491     constexpr ClearColorValue(float r, float g, float b, float a)
492         : mType(PixelType::Float), mRedF(r), mGreenF(g), mBlueF(b), mAlphaF(a)
493     {}
494     constexpr ClearColorValue(int32_t r, int32_t g, int32_t b, int32_t a)
495         : mType(PixelType::Int), mRedI(r), mGreenI(g), mBlueI(b), mAlphaI(a)
496     {}
497     constexpr ClearColorValue(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
498         : mType(PixelType::UInt), mRedU(r), mGreenU(g), mBlueU(b), mAlphaU(a)
499     {}
500     constexpr ClearColorValue(const ClearColorValue &src)
501         : mType(src.mType), mValueBytes(src.mValueBytes)
502     {}
503 
504     MTLClearColor toMTLClearColor() const;
505 
506     PixelType getType() const { return mType; }
507 
508     const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
509 
510     ClearColorValue &operator=(const ClearColorValue &src);
511 
512     void setAsFloat(float r, float g, float b, float a);
513     void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
514     void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
515 
516   private:
517     PixelType mType;
518 
519     union
520     {
521         struct
522         {
523             float mRedF, mGreenF, mBlueF, mAlphaF;
524         };
525         struct
526         {
527             int32_t mRedI, mGreenI, mBlueI, mAlphaI;
528         };
529         struct
530         {
531             uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
532         };
533 
534         ClearColorValueBytes mValueBytes;
535     };
536 };
537 
538 class CommandQueue;
539 class ErrorHandler
540 {
541   public:
542     virtual ~ErrorHandler() {}
543 
544     virtual void handleError(GLenum error,
545                              const char *file,
546                              const char *function,
547                              unsigned int line) = 0;
548 
549     virtual void handleError(NSError *_Nullable error,
550                              const char *file,
551                              const char *function,
552                              unsigned int line) = 0;
553 };
554 
555 class Context : public ErrorHandler
556 {
557   public:
558     Context(DisplayMtl *displayMtl);
559     _Nullable id<MTLDevice> getMetalDevice() const;
560     mtl::CommandQueue &cmdQueue();
561 
562     DisplayMtl *getDisplay() const { return mDisplay; }
563 
564   protected:
565     DisplayMtl *mDisplay;
566 };
567 
568 #define ANGLE_MTL_CHECK(context, test, error)                                \
569     do                                                                       \
570     {                                                                        \
571         if (ANGLE_UNLIKELY(!(test)))                                         \
572         {                                                                    \
573             context->handleError(error, __FILE__, ANGLE_FUNCTION, __LINE__); \
574             return angle::Result::Stop;                                      \
575         }                                                                    \
576     } while (0)
577 
578 #define ANGLE_MTL_TRY(context, test) ANGLE_MTL_CHECK(context, test, GL_INVALID_OPERATION)
579 
580 #define ANGLE_MTL_UNREACHABLE(context) \
581     UNREACHABLE();                     \
582     ANGLE_MTL_TRY(context, false)
583 
584 }  // namespace mtl
585 }  // namespace rx
586 
587 #endif /* LIBANGLE_RENDERER_METAL_MTL_COMMON_H_ */
588