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