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