| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "EglOsApi.h" |
| |
| #include "MacNative.h" |
| |
| #include "emugl/common/lazy_instance.h" |
| #include "emugl/common/shared_library.h" |
| #include "GLcommon/GLLibrary.h" |
| #include "OpenglCodecCommon/ErrorLog.h" |
| |
| #include <list> |
| |
| #define MAX_PBUFFER_MIPMAP_LEVEL 1 |
| |
| namespace { |
| |
| class MacSurface : public EglOS::Surface { |
| public: |
| MacSurface(void* handle, SurfaceType type) : |
| Surface(type), m_handle(handle) {} |
| |
| void* handle() const { return m_handle; } |
| |
| bool hasMipmap() const { return m_hasMipmap; } |
| void setHasMipmap(bool value) { m_hasMipmap = value; } |
| |
| static MacSurface* from(EglOS::Surface* s) { |
| return static_cast<MacSurface*>(s); |
| } |
| |
| private: |
| void* m_handle = nullptr; |
| bool m_hasMipmap = false; |
| }; |
| |
| class MacContext : public EglOS::Context { |
| public: |
| explicit MacContext(void* context) : mContext(context) {} |
| |
| virtual ~MacContext() { |
| nsDestroyContext(mContext); |
| } |
| |
| void* context() const { return mContext; } |
| |
| static void* from(EglOS::Context* c) { |
| return static_cast<MacContext*>(c)->context(); |
| } |
| |
| private: |
| void* mContext = nullptr; |
| }; |
| |
| typedef std::list<void*> NativeFormatList; |
| |
| NativeFormatList s_nativeFormats; |
| |
| void initNativeConfigs(){ |
| int nConfigs = getNumPixelFormats(); |
| if (s_nativeFormats.empty()) { |
| for(int i = 0; i < nConfigs; i++) { |
| void* frmt = getPixelFormat(i); |
| if (frmt) { |
| s_nativeFormats.push_back(frmt); |
| } |
| } |
| } |
| } |
| |
| class MacPixelFormat : public EglOS::PixelFormat { |
| public: |
| MacPixelFormat(void* handle, int redSize, int greenSize, int blueSize) : |
| mHandle(handle), |
| mRedSize(redSize), |
| mGreenSize(greenSize), |
| mBlueSize(blueSize) {} |
| |
| EglOS::PixelFormat* clone() { |
| return new MacPixelFormat(mHandle, mRedSize, mGreenSize, mBlueSize); |
| } |
| |
| void* handle() const { return mHandle; } |
| int redSize() const { return mRedSize; } |
| int greenSize() const { return mGreenSize; } |
| int blueSize() const { return mBlueSize; } |
| |
| static const MacPixelFormat* from(const EglOS::PixelFormat* f) { |
| return static_cast<const MacPixelFormat*>(f); |
| } |
| |
| private: |
| MacPixelFormat(); |
| MacPixelFormat(const MacPixelFormat& other); |
| |
| void* mHandle = nullptr; |
| int mRedSize = 0; |
| int mGreenSize = 0; |
| int mBlueSize = 0; |
| }; |
| |
| |
| void pixelFormatToConfig(int index, |
| int renderableType, |
| void* frmt, |
| EglOS::AddConfigCallback addConfigFunc, |
| void* addConfigOpaque) { |
| EglOS::ConfigInfo info = {}; |
| EGLint doubleBuffer; |
| getPixelFormatAttrib(frmt, MAC_HAS_DOUBLE_BUFFER, &doubleBuffer); |
| if (!doubleBuffer) { |
| return; //pixel double buffer |
| } |
| |
| EGLint window = 0, pbuffer = 0; |
| getPixelFormatAttrib(frmt, MAC_DRAW_TO_WINDOW, &window); |
| getPixelFormatAttrib(frmt, MAC_DRAW_TO_PBUFFER, &pbuffer); |
| |
| info.surface_type = 0; |
| if (window) { |
| info.surface_type |= EGL_WINDOW_BIT; |
| } |
| if (pbuffer) { |
| info.surface_type |= EGL_PBUFFER_BIT; |
| } |
| if (!info.surface_type) { |
| return; |
| } |
| |
| //default values |
| info.native_visual_id = 0; |
| info.native_visual_type = EGL_NONE; |
| info.caveat = EGL_NONE; |
| info.native_renderable = EGL_FALSE; |
| info.renderable_type = renderableType; |
| info.max_pbuffer_width = PBUFFER_MAX_WIDTH; |
| info.max_pbuffer_height = PBUFFER_MAX_HEIGHT; |
| info.max_pbuffer_size = PBUFFER_MAX_PIXELS; |
| info.samples_per_pixel = 0; |
| info.frame_buffer_level = 0; |
| info.trans_red_val = 0; |
| info.trans_green_val = 0; |
| info.trans_blue_val = 0; |
| |
| info.transparent_type = EGL_NONE; |
| |
| /* All configs can end up having an alpha channel even if none was requested. |
| * The default config chooser in GLSurfaceView will therefore not find any |
| * matching config. Thus, make sure alpha is zero (or at least signalled as |
| * zero to the calling EGL layer) for the configs where it was intended to |
| * be zero. */ |
| if (getPixelFormatDefinitionAlpha(index) == 0) { |
| info.alpha_size = 0; |
| } else { |
| getPixelFormatAttrib(frmt, MAC_ALPHA_SIZE, &info.alpha_size); |
| } |
| getPixelFormatAttrib(frmt, MAC_DEPTH_SIZE, &info.depth_size); |
| getPixelFormatAttrib(frmt, MAC_STENCIL_SIZE, &info.stencil_size); |
| getPixelFormatAttrib(frmt, MAC_SAMPLES_PER_PIXEL, &info.samples_per_pixel); |
| |
| //TODO: ask guy if it is OK |
| GLint colorSize = 0; |
| getPixelFormatAttrib(frmt, MAC_COLOR_SIZE, &colorSize); |
| info.red_size = info.green_size = info.blue_size = (colorSize / 4); |
| |
| info.config_id = (EGLint) index; |
| info.frmt = new MacPixelFormat( |
| frmt, info.red_size, info.green_size, info.blue_size); |
| |
| (*addConfigFunc)(addConfigOpaque, &info); |
| } |
| |
| |
| class MacDisplay : public EglOS::Display { |
| public: |
| explicit MacDisplay(EGLNativeDisplayType dpy) : mDpy(dpy) {} |
| |
| virtual void queryConfigs(int renderableType, |
| EglOS::AddConfigCallback* addConfigFunc, |
| void* addConfigOpaque) { |
| initNativeConfigs(); |
| int i = 0; |
| for (NativeFormatList::iterator it = s_nativeFormats.begin(); |
| it != s_nativeFormats.end(); |
| ++it) { |
| pixelFormatToConfig(i++, |
| renderableType, |
| *it, |
| addConfigFunc, |
| addConfigOpaque); |
| } |
| } |
| |
| virtual bool isValidNativeWin(EglOS::Surface* win) { |
| if (win->type() != MacSurface::WINDOW) { |
| return false; |
| } else { |
| return isValidNativeWin(MacSurface::from(win)->handle()); |
| } |
| } |
| |
| virtual bool isValidNativeWin(EGLNativeWindowType win) { |
| unsigned int width, height; |
| return nsGetWinDims(win, &width, &height); |
| } |
| |
| virtual bool checkWindowPixelFormatMatch( |
| EGLNativeWindowType win, |
| const EglOS::PixelFormat* pixelFormat, |
| unsigned int* width, |
| unsigned int* height) { |
| bool ret = nsGetWinDims(win, width, height); |
| |
| const MacPixelFormat* format = MacPixelFormat::from(pixelFormat); |
| int r = format->redSize(); |
| int g = format->greenSize(); |
| int b = format->blueSize(); |
| |
| bool match = nsCheckColor(win, r + g + b); |
| |
| return ret && match; |
| } |
| |
| virtual EglOS::Context* createContext( |
| const EglOS::PixelFormat* pixelFormat, |
| EglOS::Context* sharedContext) { |
| void* macSharedContext = |
| sharedContext ? MacContext::from(sharedContext) : NULL; |
| return new MacContext( |
| nsCreateContext(MacPixelFormat::from(pixelFormat)->handle(), |
| macSharedContext)); |
| } |
| |
| virtual bool destroyContext(EglOS::Context* context) { |
| delete context; |
| return true; |
| } |
| |
| virtual EglOS::Surface* createPbufferSurface( |
| const EglOS::PixelFormat* pixelFormat, |
| const EglOS::PbufferInfo* info) { |
| GLenum glTexFormat = GL_RGBA, glTexTarget = GL_TEXTURE_2D; |
| switch (info->format) { |
| case EGL_TEXTURE_RGB: |
| glTexFormat = GL_RGB; |
| break; |
| case EGL_TEXTURE_RGBA: |
| glTexFormat = GL_RGBA; |
| break; |
| } |
| EGLint maxMipmap = info->hasMipmap ? MAX_PBUFFER_MIPMAP_LEVEL : 0; |
| |
| MacSurface* result = new MacSurface( |
| nsCreatePBuffer( |
| glTexTarget, |
| glTexFormat, |
| maxMipmap, |
| info->width, |
| info->height), |
| MacSurface::PBUFFER); |
| |
| result->setHasMipmap(info->hasMipmap); |
| return result; |
| } |
| |
| virtual bool releasePbuffer(EglOS::Surface* pb) { |
| if (pb) { |
| nsDestroyPBuffer(MacSurface::from(pb)->handle()); |
| } |
| return true; |
| } |
| |
| virtual bool makeCurrent(EglOS::Surface* read, |
| EglOS::Surface* draw, |
| EglOS::Context* ctx) { |
| // check for unbind |
| if (ctx == NULL && read == NULL && draw == NULL) { |
| nsWindowMakeCurrent(NULL, NULL); |
| return true; |
| } |
| else if (ctx == NULL || read == NULL || draw == NULL) { |
| // error ! |
| return false; |
| } |
| |
| //dont supporting diffrent read & draw surfaces on Mac |
| if (read != draw) { |
| return false; |
| } |
| switch (draw->type()) { |
| case MacSurface::WINDOW: |
| nsWindowMakeCurrent(MacContext::from(ctx), |
| MacSurface::from(draw)->handle()); |
| break; |
| case MacSurface::PBUFFER: |
| { |
| MacSurface* macdraw = MacSurface::from(draw); |
| int mipmapLevel = macdraw->hasMipmap() ? MAX_PBUFFER_MIPMAP_LEVEL : 0; |
| nsPBufferMakeCurrent(MacContext::from(ctx), |
| macdraw->handle(), mipmapLevel); |
| break; |
| } |
| default: |
| return false; |
| } |
| return true; |
| } |
| |
| virtual void swapBuffers(EglOS::Surface* srfc) { |
| nsSwapBuffers(); |
| } |
| |
| EGLNativeDisplayType dpy() const { return mDpy; } |
| |
| private: |
| EGLNativeDisplayType mDpy = {}; |
| }; |
| |
| class MacGlLibrary : public GlLibrary { |
| public: |
| MacGlLibrary() { |
| static const char kLibName[] = |
| "/System/Library/Frameworks/OpenGL.framework/OpenGL"; |
| char error[256]; |
| mLib = emugl::SharedLibrary::open(kLibName, error, sizeof(error)); |
| if (!mLib) { |
| ERR("%s: Could not open GL library %s [%s]\n", |
| __FUNCTION__, kLibName, error); |
| } |
| } |
| |
| ~MacGlLibrary() { |
| delete mLib; |
| } |
| |
| // override |
| virtual GlFunctionPointer findSymbol(const char* name) { |
| if (!mLib) { |
| return NULL; |
| } |
| return reinterpret_cast<GlFunctionPointer>(mLib->findSymbol(name)); |
| } |
| |
| private: |
| emugl::SharedLibrary* mLib = nullptr; |
| }; |
| |
| class MacEngine : public EglOS::Engine { |
| public: |
| virtual EglOS::Display* getDefaultDisplay() { |
| return new MacDisplay(0); |
| } |
| |
| virtual GlLibrary* getGlLibrary() { |
| return &mGlLib; |
| } |
| |
| virtual EglOS::Surface* createWindowSurface(EGLNativeWindowType wnd) { |
| return new MacSurface(wnd, MacSurface::WINDOW); |
| } |
| |
| private: |
| MacGlLibrary mGlLib; |
| }; |
| |
| emugl::LazyInstance<MacEngine> sHostEngine = LAZY_INSTANCE_INIT; |
| |
| } // namespace |
| |
| |
| // static |
| EglOS::Engine* EglOS::Engine::getHostInstance() { |
| return sHostEngine.ptr(); |
| } |