• 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 "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