• 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/ObjCPtr.h"
24 #include "common/apple_platform_utils.h"
25 #include "libANGLE/Constants.h"
26 #include "libANGLE/ImageIndex.h"
27 #include "libANGLE/Version.h"
28 #include "libANGLE/angletypes.h"
29 
30 #if defined(ANGLE_MTL_ENABLE_TRACE)
31 #    define ANGLE_MTL_LOG(...) NSLog(@__VA_ARGS__)
32 #else
33 #    define ANGLE_MTL_LOG(...) (void)0
34 #endif
35 
36 #define ANGLE_MTL_OBJC_SCOPE ANGLE_APPLE_OBJC_SCOPE
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 enum class PixelType
177 {
178     Int,
179     UInt,
180     Float,
181     EnumCount,
182 };
183 
184 template <typename T>
185 struct ImplTypeHelper;
186 
187 // clang-format off
188 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
189 template<>                             \
190 struct ImplTypeHelper<gl::OBJ>         \
191 {                                      \
192     using ImplType = OBJ##Mtl;         \
193 };
194 // clang-format on
195 
196 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
197 
198 template <>
199 struct ImplTypeHelper<egl::Display>
200 {
201     using ImplType = DisplayMtl;
202 };
203 
204 template <>
205 struct ImplTypeHelper<egl::Image>
206 {
207     using ImplType = ImageMtl;
208 };
209 
210 template <typename T>
211 using GetImplType = typename ImplTypeHelper<T>::ImplType;
212 
213 template <typename T>
214 GetImplType<T> *GetImpl(const T *glObject)
215 {
216     return GetImplAs<GetImplType<T>>(glObject);
217 }
218 
219 // This class wraps Objective-C pointer inside, it will manage the lifetime of
220 // the Objective-C pointer. Changing pointer is not supported outside subclass.
221 template <typename T>
222 class WrappedObject
223 {
224   public:
225     WrappedObject() = default;
226     ~WrappedObject() { release(); }
227 
228     bool valid() const { return (mMetalObject != nil); }
229 
230     T get() const { return mMetalObject; }
231     T leakObject() { return std::exchange(mMetalObject, nullptr); }
232     inline void reset() { release(); }
233 
234     operator T() const { return get(); }
235 
236   protected:
237     inline void set(T obj) { retainAssign(obj); }
238 
239     void retainAssign(T obj)
240     {
241 
242 #if !__has_feature(objc_arc)
243         T retained = obj;
244         [retained retain];
245 #endif
246         release();
247         mMetalObject = obj;
248     }
249 
250     void unretainAssign(T obj)
251     {
252         release();
253         mMetalObject = obj;
254     }
255 
256   private:
257     void release()
258     {
259 #if !__has_feature(objc_arc)
260         [mMetalObject release];
261 #endif
262         mMetalObject = nil;
263     }
264 
265     T mMetalObject = nil;
266 };
267 
268 // The native image index used by Metal back-end,  the image index uses native mipmap level instead
269 // of "virtual" level modified by OpenGL's base level.
270 using MipmapNativeLevel = gl::LevelIndexWrapper<uint32_t>;
271 
272 constexpr MipmapNativeLevel kZeroNativeMipLevel(0);
273 
274 class ImageNativeIndexIterator;
275 
276 class ImageNativeIndex final
277 {
278   public:
279     ImageNativeIndex() = delete;
280     ImageNativeIndex(const gl::ImageIndex &src, GLint baseLevel)
281     {
282         mNativeIndex = gl::ImageIndex::MakeFromType(src.getType(), src.getLevelIndex() - baseLevel,
283                                                     src.getLayerIndex(), src.getLayerCount());
284     }
285 
286     static ImageNativeIndex FromBaseZeroGLIndex(const gl::ImageIndex &src)
287     {
288         return ImageNativeIndex(src, 0);
289     }
290 
291     MipmapNativeLevel getNativeLevel() const
292     {
293         return MipmapNativeLevel(mNativeIndex.getLevelIndex());
294     }
295 
296     gl::TextureType getType() const { return mNativeIndex.getType(); }
297     GLint getLayerIndex() const { return mNativeIndex.getLayerIndex(); }
298     GLint getLayerCount() const { return mNativeIndex.getLayerCount(); }
299     GLint cubeMapFaceIndex() const { return mNativeIndex.cubeMapFaceIndex(); }
300 
301     bool isLayered() const { return mNativeIndex.isLayered(); }
302     bool hasLayer() const { return mNativeIndex.hasLayer(); }
303     bool has3DLayer() const { return mNativeIndex.has3DLayer(); }
304     bool usesTex3D() const { return mNativeIndex.usesTex3D(); }
305 
306     bool valid() const { return mNativeIndex.valid(); }
307 
308     ImageNativeIndexIterator getLayerIterator(GLint layerCount) const;
309 
310   private:
311     gl::ImageIndex mNativeIndex;
312 };
313 
314 class ImageNativeIndexIterator final
315 {
316   public:
317     ImageNativeIndex next() { return ImageNativeIndex(mNativeIndexIte.next(), 0); }
318     ImageNativeIndex current() const { return ImageNativeIndex(mNativeIndexIte.current(), 0); }
319     bool hasNext() const { return mNativeIndexIte.hasNext(); }
320 
321   private:
322     // This class is only constructable from ImageNativeIndex
323     friend class ImageNativeIndex;
324 
325     explicit ImageNativeIndexIterator(const gl::ImageIndexIterator &baseZeroSrc)
326         : mNativeIndexIte(baseZeroSrc)
327     {}
328 
329     gl::ImageIndexIterator mNativeIndexIte;
330 };
331 
332 using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
333 
334 class ClearColorValue
335 {
336   public:
337     constexpr ClearColorValue()
338         : mType(PixelType::Float), mRedF(0), mGreenF(0), mBlueF(0), mAlphaF(0)
339     {}
340     constexpr ClearColorValue(float r, float g, float b, float a)
341         : mType(PixelType::Float), mRedF(r), mGreenF(g), mBlueF(b), mAlphaF(a)
342     {}
343     constexpr ClearColorValue(int32_t r, int32_t g, int32_t b, int32_t a)
344         : mType(PixelType::Int), mRedI(r), mGreenI(g), mBlueI(b), mAlphaI(a)
345     {}
346     constexpr ClearColorValue(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
347         : mType(PixelType::UInt), mRedU(r), mGreenU(g), mBlueU(b), mAlphaU(a)
348     {}
349     constexpr ClearColorValue(const ClearColorValue &src)
350         : mType(src.mType), mValueBytes(src.mValueBytes)
351     {}
352 
353     MTLClearColor toMTLClearColor() const;
354 
355     PixelType getType() const { return mType; }
356 
357     const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
358 
359     ClearColorValue &operator=(const ClearColorValue &src);
360 
361     void setAsFloat(float r, float g, float b, float a);
362     void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
363     void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
364 
365   private:
366     PixelType mType;
367 
368     union
369     {
370         struct
371         {
372             float mRedF, mGreenF, mBlueF, mAlphaF;
373         };
374         struct
375         {
376             int32_t mRedI, mGreenI, mBlueI, mAlphaI;
377         };
378         struct
379         {
380             uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
381         };
382 
383         ClearColorValueBytes mValueBytes;
384     };
385 };
386 
387 class CommandQueue;
388 
389 class ErrorHandler
390 {
391   public:
392     virtual ~ErrorHandler() {}
393 
394     virtual void handleError(GLenum error,
395                              const char *message,
396                              const char *file,
397                              const char *function,
398                              unsigned int line) = 0;
399 
400     void handleNSError(NSError *error, const char *file, const char *function, unsigned int line)
401     {
402         std::string message;
403         {
404             std::stringstream s;
405             s << "Internal error. Metal error: "
406               << (error != nil ? error.localizedDescription.UTF8String : "nil error");
407             message = s.str();
408         }
409         handleError(GL_INVALID_OPERATION, message.c_str(), file, function, line);
410     }
411 };
412 
413 class Context : public ErrorHandler
414 {
415   public:
416     Context(DisplayMtl *displayMtl);
417     mtl::CommandQueue &cmdQueue();
418 
419     DisplayMtl *getDisplay() const { return mDisplay; }
420 
421   protected:
422     DisplayMtl *mDisplay;
423 };
424 
425 #define ANGLE_MTL_CHECK(context, result, nserror)                                   \
426     do                                                                              \
427     {                                                                               \
428         auto &localResult = (result);                                               \
429         auto &localError  = (nserror);                                              \
430         if (ANGLE_UNLIKELY(!localResult || localError))                             \
431         {                                                                           \
432             context->handleNSError(localError, __FILE__, ANGLE_FUNCTION, __LINE__); \
433             return angle::Result::Stop;                                             \
434         }                                                                           \
435     } while (0)
436 
437 }  // namespace mtl
438 }  // namespace rx
439 
440 #endif /* LIBANGLE_RENDERER_METAL_MTL_COMMON_H_ */
441