1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "EglOsApi.h"
17
18 #include "MacNative.h"
19
20 #include "android/base/containers/Lookup.h"
21
22 #include "emugl/common/lazy_instance.h"
23 #include "emugl/common/shared_library.h"
24 #include "GLcommon/GLLibrary.h"
25 #include "OpenglCodecCommon/ErrorLog.h"
26
27 #include <EGL/egl.h>
28 #include <EGL/eglext.h>
29
30 #include <numeric>
31 #include <unordered_map>
32
33 #define MAX_PBUFFER_MIPMAP_LEVEL 1
34
35 using FinalizedConfigKey = std::pair<bool, int>;
36 struct FinalizedConfigHash {
operator ()FinalizedConfigHash37 std::size_t operator () (const FinalizedConfigKey& p) const {
38 return p.second + 9001 * (p.first ? 1 : 0);
39 }
40 };
41 using FinalizedConfigMap =
42 std::unordered_map<FinalizedConfigKey, void*, FinalizedConfigHash>;
43
44 static emugl::LazyInstance<FinalizedConfigMap> sFinalizedConfigs =
45 LAZY_INSTANCE_INIT;
46
47 namespace {
48
49 class MacSurface : public EglOS::Surface {
50 public:
MacSurface(void * handle,SurfaceType type)51 MacSurface(void* handle, SurfaceType type) :
52 Surface(type), m_handle(handle) {}
53
handle() const54 void* handle() const { return m_handle; }
55
hasMipmap() const56 bool hasMipmap() const { return m_hasMipmap; }
setHasMipmap(bool value)57 void setHasMipmap(bool value) { m_hasMipmap = value; }
58
from(EglOS::Surface * s)59 static MacSurface* from(EglOS::Surface* s) {
60 return static_cast<MacSurface*>(s);
61 }
62
63 private:
64 void* m_handle = nullptr;
65 bool m_hasMipmap = false;
66 };
67
68 class MacContext : public EglOS::Context {
69 public:
MacContext(bool isCoreProfile,void * context)70 explicit MacContext(bool isCoreProfile, void* context) :
71 EglOS::Context(isCoreProfile), mContext(context) {}
72
~MacContext()73 ~MacContext() {
74 nsDestroyContext(mContext);
75 }
76
context() const77 void* context() const { return mContext; }
78
from(EglOS::Context * c)79 static void* from(EglOS::Context* c) {
80 return static_cast<MacContext*>(c)->context();
81 }
82
83 private:
84 void* mContext = nullptr;
85 };
86
87 class MacNativeSupportInfo {
88 public:
MacNativeSupportInfo()89 MacNativeSupportInfo() :
90 numNativeFormats(getNumPixelFormats()),
91 maxOpenGLProfile((MacOpenGLProfileVersions)setupCoreProfileNativeFormats()) { }
92 int numNativeFormats = 0;
93 MacOpenGLProfileVersions maxOpenGLProfile =
94 MAC_OPENGL_PROFILE_LEGACY;
95 };
96
97 static emugl::LazyInstance<MacNativeSupportInfo> sSupportInfo =
98 LAZY_INSTANCE_INIT;
99
100 class MacPixelFormat : public EglOS::PixelFormat {
101 public:
MacPixelFormat(int handle,int redSize,int greenSize,int blueSize)102 MacPixelFormat(int handle, int redSize, int greenSize, int blueSize) :
103 mHandle(handle),
104 mRedSize(redSize),
105 mGreenSize(greenSize),
106 mBlueSize(blueSize) {}
107
clone()108 EglOS::PixelFormat* clone() {
109 return new MacPixelFormat(mHandle, mRedSize, mGreenSize, mBlueSize);
110 }
111
handle() const112 int handle() const { return mHandle; }
redSize() const113 int redSize() const { return mRedSize; }
greenSize() const114 int greenSize() const { return mGreenSize; }
blueSize() const115 int blueSize() const { return mBlueSize; }
116
from(const EglOS::PixelFormat * f)117 static const MacPixelFormat* from(const EglOS::PixelFormat* f) {
118 return static_cast<const MacPixelFormat*>(f);
119 }
120
121 private:
122 MacPixelFormat();
123 MacPixelFormat(const MacPixelFormat& other);
124
125 int mHandle = 0;
126 int mRedSize = 0;
127 int mGreenSize = 0;
128 int mBlueSize = 0;
129 };
130
131
pixelFormatToConfig(int index,EglOS::AddConfigCallback addConfigFunc,void * addConfigOpaque)132 void pixelFormatToConfig(int index,
133 EglOS::AddConfigCallback addConfigFunc,
134 void* addConfigOpaque) {
135 EglOS::ConfigInfo info = {};
136
137 info.surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
138
139 //default values
140 info.native_visual_id = 0;
141 info.native_visual_type = EGL_NONE;
142 info.caveat = EGL_NONE;
143 info.native_renderable = EGL_FALSE;
144
145 info.renderable_type = EGL_OPENGL_ES_BIT |
146 EGL_OPENGL_ES2_BIT |
147 EGL_OPENGL_ES3_BIT;
148
149 info.max_pbuffer_width = PBUFFER_MAX_WIDTH;
150 info.max_pbuffer_height = PBUFFER_MAX_HEIGHT;
151 info.max_pbuffer_size = PBUFFER_MAX_PIXELS;
152 info.samples_per_pixel = 0;
153 info.frame_buffer_level = 0;
154 info.trans_red_val = 0;
155 info.trans_green_val = 0;
156 info.trans_blue_val = 0;
157
158 info.transparent_type = EGL_NONE;
159
160 /* All configs can end up having an alpha channel even if none was requested.
161 * The default config chooser in GLSurfaceView will therefore not find any
162 * matching config. Thus, make sure alpha is zero (or at least signalled as
163 * zero to the calling EGL layer) for the configs where it was intended to
164 * be zero. */
165 info.alpha_size = getPixelFormatAttrib(index, MAC_ALPHA_SIZE);
166
167 info.depth_size = getPixelFormatAttrib(index, MAC_DEPTH_SIZE);
168 info.stencil_size = getPixelFormatAttrib(index, MAC_STENCIL_SIZE);
169 info.samples_per_pixel = getPixelFormatAttrib(index, MAC_SAMPLES_PER_PIXEL);
170
171 //TODO: ask guy if it is OK
172 GLint colorSize = 0;
173 colorSize = (GLint)getPixelFormatAttrib(index, MAC_COLOR_SIZE);
174 info.red_size = info.green_size = info.blue_size = (colorSize / 4);
175
176 info.frmt = new MacPixelFormat(
177 index, info.red_size, info.green_size, info.blue_size);
178
179 (*addConfigFunc)(addConfigOpaque, &info);
180 }
181
182
183 class MacDisplay : public EglOS::Display {
184 public:
MacDisplay(EGLNativeDisplayType dpy)185 explicit MacDisplay(EGLNativeDisplayType dpy) : mDpy(dpy) {}
186
getMaxGlesVersion()187 virtual EglOS::GlesVersion getMaxGlesVersion() {
188 switch (sSupportInfo->maxOpenGLProfile) {
189 case MAC_OPENGL_PROFILE_LEGACY:
190 return EglOS::GlesVersion::ES2;
191 case MAC_OPENGL_PROFILE_3_2:
192 case MAC_OPENGL_PROFILE_4_1:
193 return EglOS::GlesVersion::ES30;
194 default:
195 return EglOS::GlesVersion::ES2;
196 }
197 }
198
queryConfigs(int renderableType,EglOS::AddConfigCallback * addConfigFunc,void * addConfigOpaque)199 virtual void queryConfigs(int renderableType,
200 EglOS::AddConfigCallback* addConfigFunc,
201 void* addConfigOpaque) {
202 for (int i = 0; i < sSupportInfo->numNativeFormats; i++) {
203 pixelFormatToConfig(
204 i,
205 addConfigFunc,
206 addConfigOpaque);
207 }
208
209 // Also disable vsync.
210 int bestSwapInterval = 0;
211 nsSwapInterval(&bestSwapInterval);
212 }
213
isValidNativeWin(EglOS::Surface * win)214 virtual bool isValidNativeWin(EglOS::Surface* win) {
215
216 if (!win) { return false; }
217
218 if (win->type() != MacSurface::WINDOW) {
219 return false;
220 } else {
221 return isValidNativeWin(MacSurface::from(win)->handle());
222 }
223 }
224
isValidNativeWin(EGLNativeWindowType win)225 virtual bool isValidNativeWin(EGLNativeWindowType win) {
226 unsigned int width, height;
227 if (!win) return false;
228 return nsGetWinDims(win, &width, &height);
229 }
230
checkWindowPixelFormatMatch(EGLNativeWindowType win,const EglOS::PixelFormat * pixelFormat,unsigned int * width,unsigned int * height)231 virtual bool checkWindowPixelFormatMatch(
232 EGLNativeWindowType win,
233 const EglOS::PixelFormat* pixelFormat,
234 unsigned int* width,
235 unsigned int* height) {
236 bool ret = nsGetWinDims(win, width, height);
237
238 const MacPixelFormat* format = MacPixelFormat::from(pixelFormat);
239 int r = format->redSize();
240 int g = format->greenSize();
241 int b = format->blueSize();
242
243 bool match = nsCheckColor(win, r + g + b);
244
245 return ret && match;
246 }
247
createContext(EGLint profileMask,const EglOS::PixelFormat * pixelFormat,EglOS::Context * sharedContext)248 virtual emugl::SmartPtr<EglOS::Context> createContext(
249 EGLint profileMask,
250 const EglOS::PixelFormat* pixelFormat,
251 EglOS::Context* sharedContext) {
252
253 void* macSharedContext =
254 sharedContext ? MacContext::from(sharedContext) : NULL;
255
256 bool isCoreProfile =
257 profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
258
259 auto key = std::make_pair(isCoreProfile,
260 MacPixelFormat::from(pixelFormat)->handle());
261
262 void* nsFormat = nullptr;
263 if (auto format = android::base::find(sFinalizedConfigs.get(), key)) {
264 nsFormat = *format;
265 } else {
266 nsFormat =
267 finalizePixelFormat(isCoreProfile,
268 MacPixelFormat::from(pixelFormat)->handle());
269 sFinalizedConfigs.get()[key] = nsFormat;
270 }
271
272 return std::make_shared<MacContext>(
273 isCoreProfile,
274 nsCreateContext(nsFormat,
275 macSharedContext));
276 }
277
createPbufferSurface(const EglOS::PixelFormat * pixelFormat,const EglOS::PbufferInfo * info)278 virtual EglOS::Surface* createPbufferSurface(
279 const EglOS::PixelFormat* pixelFormat,
280 const EglOS::PbufferInfo* info) {
281 GLenum glTexFormat = GL_RGBA, glTexTarget = GL_TEXTURE_2D;
282 switch (info->format) {
283 case EGL_TEXTURE_RGB:
284 glTexFormat = GL_RGB;
285 break;
286 case EGL_TEXTURE_RGBA:
287 glTexFormat = GL_RGBA;
288 break;
289 }
290 EGLint maxMipmap = info->hasMipmap ? MAX_PBUFFER_MIPMAP_LEVEL : 0;
291 bool isLegacyOpenGL =
292 sSupportInfo->maxOpenGLProfile == MAC_OPENGL_PROFILE_LEGACY;
293 MacSurface* result = new MacSurface(
294 isLegacyOpenGL
295 ? nsCreatePBuffer(glTexTarget, glTexFormat, maxMipmap,
296 info->width, info->height)
297 : nullptr,
298 MacSurface::PBUFFER);
299
300 result->setHasMipmap(info->hasMipmap);
301 return result;
302 }
303
releasePbuffer(EglOS::Surface * pb)304 virtual bool releasePbuffer(EglOS::Surface* pb) {
305 if (pb) {
306 nsDestroyPBuffer(MacSurface::from(pb)->handle());
307 delete pb;
308 }
309 return true;
310 }
311
makeCurrent(EglOS::Surface * read,EglOS::Surface * draw,EglOS::Context * ctx)312 virtual bool makeCurrent(EglOS::Surface* read,
313 EglOS::Surface* draw,
314 EglOS::Context* ctx) {
315 // check for unbind
316 if (ctx == NULL && read == NULL && draw == NULL) {
317 nsWindowMakeCurrent(NULL, NULL);
318 return true;
319 }
320 else if (ctx == NULL || read == NULL || draw == NULL) {
321 // error !
322 return false;
323 }
324
325 //dont supporting diffrent read & draw surfaces on Mac
326 if (read != draw) {
327 return false;
328 }
329 switch (draw->type()) {
330 case MacSurface::WINDOW:
331 nsWindowMakeCurrent(MacContext::from(ctx),
332 MacSurface::from(draw)->handle());
333 break;
334 case MacSurface::PBUFFER:
335 {
336 MacSurface* macdraw = MacSurface::from(draw);
337 int mipmapLevel = macdraw->hasMipmap() ? MAX_PBUFFER_MIPMAP_LEVEL : 0;
338 nsPBufferMakeCurrent(MacContext::from(ctx),
339 macdraw->handle(), mipmapLevel);
340 break;
341 }
342 default:
343 return false;
344 }
345 return true;
346 }
347
swapBuffers(EglOS::Surface * srfc)348 virtual void swapBuffers(EglOS::Surface* srfc) {
349 nsSwapBuffers();
350 }
351
dpy() const352 EGLNativeDisplayType dpy() const { return mDpy; }
353
354 private:
355 EglOS::GlesVersion mMaxGlesVersion =
356 EglOS::GlesVersion::ES2;
357 EGLNativeDisplayType mDpy = {};
358 };
359
360 class MacGlLibrary : public GlLibrary {
361 public:
MacGlLibrary()362 MacGlLibrary() {
363 static const char kLibName[] =
364 "/System/Library/Frameworks/OpenGL.framework/OpenGL";
365 char error[256];
366 mLib = emugl::SharedLibrary::open(kLibName, error, sizeof(error));
367 if (!mLib) {
368 ERR("%s: Could not open GL library %s [%s]\n",
369 __FUNCTION__, kLibName, error);
370 }
371 }
372
~MacGlLibrary()373 ~MacGlLibrary() {
374 }
375
376 // override
findSymbol(const char * name)377 virtual GlFunctionPointer findSymbol(const char* name) {
378 if (!mLib) {
379 return NULL;
380 }
381 return reinterpret_cast<GlFunctionPointer>(mLib->findSymbol(name));
382 }
383
384 private:
385 emugl::SharedLibrary* mLib = nullptr;
386 };
387
388 class MacEngine : public EglOS::Engine {
389 public:
getDefaultDisplay()390 virtual EglOS::Display* getDefaultDisplay() {
391 return new MacDisplay(0);
392 }
393
getGlLibrary()394 virtual GlLibrary* getGlLibrary() {
395 return &mGlLib;
396 }
397
eglGetProcAddress(const char *)398 virtual void* eglGetProcAddress(const char*) {
399 return 0;
400 }
401
createWindowSurface(EglOS::PixelFormat * cfg,EGLNativeWindowType wnd)402 virtual EglOS::Surface* createWindowSurface(EglOS::PixelFormat* cfg,
403 EGLNativeWindowType wnd) {
404 return new MacSurface(wnd, MacSurface::WINDOW);
405 }
406
407 private:
408 MacGlLibrary mGlLib;
409 };
410
411 emugl::LazyInstance<MacEngine> sHostEngine = LAZY_INSTANCE_INIT;
412
413 } // namespace
414
415
416 // static
getHostInstance()417 EglOS::Engine* EglOS::Engine::getHostInstance() {
418 return sHostEngine.ptr();
419 }
420
421