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/Version.h"
26 #include "libANGLE/angletypes.h"
27
28 #if TARGET_OS_IPHONE
29 # if !defined(ANGLE_IOS_DEPLOY_TARGET)
30 # define ANGLE_IOS_DEPLOY_TARGET __IPHONE_11_0
31 # endif
32 #endif
33
34 #define ANGLE_MTL_OBJC_SCOPE @autoreleasepool
35
36 #if !__has_feature(objc_arc)
37 # define ANGLE_MTL_AUTORELEASE autorelease
38 #else
39 # define ANGLE_MTL_AUTORELEASE self
40 #endif
41
42 #define ANGLE_MTL_UNUSED __attribute__((unused))
43
44 #if defined(ANGLE_MTL_ENABLE_TRACE)
45 # define ANGLE_MTL_LOG(...) NSLog(@__VA_ARGS__)
46 #else
47 # define ANGLE_MTL_LOG(...) (void)0
48 #endif
49
50 namespace egl
51 {
52 class Display;
53 class Image;
54 } // namespace egl
55
56 #define ANGLE_GL_OBJECTS_X(PROC) \
57 PROC(Buffer) \
58 PROC(Context) \
59 PROC(Framebuffer) \
60 PROC(MemoryObject) \
61 PROC(Query) \
62 PROC(Program) \
63 PROC(Semaphore) \
64 PROC(Texture) \
65 PROC(TransformFeedback) \
66 PROC(VertexArray)
67
68 #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
69
70 namespace gl
71 {
72 struct Rectangle;
73 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT)
74 } // namespace gl
75
76 #define ANGLE_PRE_DECLARE_MTL_OBJECT(OBJ) class OBJ##Mtl;
77
78 namespace rx
79 {
80 class DisplayMtl;
81 class ContextMtl;
82 class FramebufferMtl;
83 class BufferMtl;
84 class VertexArrayMtl;
85 class TextureMtl;
86 class ProgramMtl;
87
ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)88 ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_MTL_OBJECT)
89
90 namespace mtl
91 {
92
93 // NOTE(hqle): support variable max number of vertex attributes
94 constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
95 // NOTE(hqle): support variable max number of render targets
96 constexpr uint32_t kMaxRenderTargets = 1;
97
98 constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
99
100 // Metal limits
101 constexpr uint32_t kMaxShaderBuffers = 31;
102 constexpr uint32_t kMaxShaderSamplers = 16;
103 constexpr size_t kDefaultUniformsMaxSize = 4 * 1024;
104 constexpr uint32_t kMaxViewports = 1;
105
106 constexpr uint32_t kVertexAttribBufferStrideAlignment = 4;
107 // Alignment requirement for offset passed to setVertex|FragmentBuffer
108 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
109 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
110 #else
111 constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
112 #endif
113 constexpr uint32_t kIndexBufferOffsetAlignment = 4;
114
115 // Front end binding limits
116 constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
117
118 // Binding index start for vertex data buffers:
119 constexpr uint32_t kVboBindingIndexStart = 0;
120
121 // Binding index for default attribute buffer:
122 constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVertexAttribs;
123 // Binding index for driver uniforms:
124 constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
125 // Binding index for default uniforms:
126 constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
127
128 constexpr uint32_t kStencilMaskAll = 0xff; // Only 8 bits stencil is supported
129
130 constexpr float kEmulatedAlphaValue = 1.0f;
131
132 // NOTE(hqle): Support ES 3.0.
133 constexpr gl::Version kMaxSupportedGLVersion = gl::Version(2, 0);
134
135 template <typename T>
136 struct ImplTypeHelper;
137
138 // clang-format off
139 #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
140 template<> \
141 struct ImplTypeHelper<gl::OBJ> \
142 { \
143 using ImplType = OBJ##Mtl; \
144 };
145 // clang-format on
146
147 ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
148
149 template <>
150 struct ImplTypeHelper<egl::Display>
151 {
152 using ImplType = DisplayMtl;
153 };
154
155 template <typename T>
156 using GetImplType = typename ImplTypeHelper<T>::ImplType;
157
158 template <typename T>
159 GetImplType<T> *GetImpl(const T *_Nonnull glObject)
160 {
161 return GetImplAs<GetImplType<T>>(glObject);
162 }
163
164 // This class wraps Objective-C pointer inside, it will manage the lifetime of
165 // the Objective-C pointer. Changing pointer is not supported outside subclass.
166 template <typename T>
167 class WrappedObject
168 {
169 public:
170 WrappedObject() = default;
171 ~WrappedObject() { release(); }
172
173 bool valid() const { return (mMetalObject != nil); }
174
175 T get() const { return mMetalObject; }
176 inline void reset() { release(); }
177
178 operator T() const { return get(); }
179
180 protected:
181 inline void set(T obj) { retainAssign(obj); }
182
183 void retainAssign(T obj)
184 {
185 T retained = obj;
186 #if !__has_feature(objc_arc)
187 [retained retain];
188 #endif
189 release();
190 mMetalObject = obj;
191 }
192
193 private:
194 void release()
195 {
196 #if !__has_feature(objc_arc)
197 [mMetalObject release];
198 #endif
199 mMetalObject = nil;
200 }
201
202 T mMetalObject = nil;
203 };
204
205 // This class is similar to WrappedObject, however, it allows changing the
206 // internal pointer with public methods.
207 template <typename T>
208 class AutoObjCPtr : public WrappedObject<T>
209 {
210 public:
211 using ParentType = WrappedObject<T>;
212
213 AutoObjCPtr() {}
214
215 AutoObjCPtr(const std::nullptr_t &theNull) {}
216
217 AutoObjCPtr(const AutoObjCPtr &src) { this->retainAssign(src.get()); }
218
219 AutoObjCPtr(AutoObjCPtr &&src) { this->transfer(std::forward<AutoObjCPtr>(src)); }
220
221 // Take ownership of the pointer
222 AutoObjCPtr(T &&src)
223 {
224 this->retainAssign(src);
225 src = nil;
226 }
227
228 AutoObjCPtr &operator=(const AutoObjCPtr &src)
229 {
230 this->retainAssign(src.get());
231 return *this;
232 }
233
234 AutoObjCPtr &operator=(AutoObjCPtr &&src)
235 {
236 this->transfer(std::forward<AutoObjCPtr>(src));
237 return *this;
238 }
239
240 // Take ownership of the pointer
241 AutoObjCPtr &operator=(T &&src)
242 {
243 this->retainAssign(src);
244 src = nil;
245 return *this;
246 }
247
248 AutoObjCPtr &operator=(const std::nullptr_t &theNull)
249 {
250 this->set(nil);
251 return *this;
252 }
253
254 bool operator==(const AutoObjCPtr &rhs) const { return (*this) == rhs.get(); }
255
256 bool operator==(T rhs) const { return this->get() == rhs; }
257
258 bool operator==(const std::nullptr_t &theNull) const { return this->get(); }
259
260 inline operator bool() { return this->get(); }
261
262 bool operator!=(const AutoObjCPtr &rhs) const { return (*this) != rhs.get(); }
263
264 bool operator!=(T rhs) const { return this->get() != rhs; }
265
266 using ParentType::retainAssign;
267
268 private:
269 void transfer(AutoObjCPtr &&src)
270 {
271 this->retainAssign(std::move(src.get()));
272 src.reset();
273 }
274 };
275
276 template <typename T>
277 using AutoObjCObj = AutoObjCPtr<T *>;
278
279 struct ClearOptions
280 {
281 Optional<MTLClearColor> clearColor;
282 Optional<float> clearDepth;
283 Optional<uint32_t> clearStencil;
284 };
285
286 class CommandQueue;
287 class ErrorHandler
288 {
289 public:
290 virtual ~ErrorHandler() {}
291
292 virtual void handleError(GLenum error,
293 const char *file,
294 const char *function,
295 unsigned int line) = 0;
296
297 virtual void handleError(NSError *_Nullable error,
298 const char *file,
299 const char *function,
300 unsigned int line) = 0;
301 };
302
303 class Context : public ErrorHandler
304 {
305 public:
306 Context(DisplayMtl *displayMtl);
307 _Nullable id<MTLDevice> getMetalDevice() const;
308 mtl::CommandQueue &cmdQueue();
309
310 DisplayMtl *getDisplay() const { return mDisplay; }
311
312 protected:
313 DisplayMtl *mDisplay;
314 };
315
316 #define ANGLE_MTL_CHECK(context, test, error) \
317 do \
318 { \
319 if (ANGLE_UNLIKELY(!(test))) \
320 { \
321 context->handleError(error, __FILE__, ANGLE_FUNCTION, __LINE__); \
322 return angle::Result::Stop; \
323 } \
324 } while (0)
325
326 #define ANGLE_MTL_TRY(context, test) ANGLE_MTL_CHECK(context, test, GL_INVALID_OPERATION)
327
328 #define ANGLE_MTL_UNREACHABLE(context) \
329 UNREACHABLE(); \
330 ANGLE_MTL_TRY(context, false)
331
332 } // namespace mtl
333 } // namespace rx
334
335 #endif /* LIBANGLE_RENDERER_METAL_MTL_COMMON_H_ */
336