/* * 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 "EglDisplay.h" #include "EglConfig.h" #include "EglOsApi.h" #include EglDisplay::EglDisplay(EGLNativeDisplayType dpy, EglOS::Display* idpy) : m_dpy(dpy), m_idpy(idpy), m_initialized(false), m_configInitialized(false), m_nextEglImageId(0), m_globalSharedContext(NULL) { m_manager[GLES_1_1] = new ObjectNameManager(&m_globalNameSpace); m_manager[GLES_2_0] = new ObjectNameManager(&m_globalNameSpace); }; EglDisplay::~EglDisplay() { emugl::Mutex::AutoLock mutex(m_lock); // // Destroy the global context if one was created. // (should be true for windows platform only) // if (m_globalSharedContext != NULL) { m_idpy->destroyContext(m_globalSharedContext); } m_idpy->release(); for(ConfigsList::iterator it = m_configs.begin(); it != m_configs.end(); it++) { delete *it; } delete m_manager[GLES_1_1]; delete m_manager[GLES_2_0]; delete m_idpy; } void EglDisplay::initialize(int renderableType) { emugl::Mutex::AutoLock mutex(m_lock); m_initialized = true; initConfigurations(renderableType); m_configInitialized = true; } bool EglDisplay::isInitialize() { return m_initialized;} void EglDisplay::terminate(){ emugl::Mutex::AutoLock mutex(m_lock); m_contexts.clear(); m_surfaces.clear(); m_initialized = false; } static bool compareEglConfigsPtrs(EglConfig* first,EglConfig* second) { return *first < *second ; } void EglDisplay::addSimplePixelFormat(int red_size, int green_size, int blue_size, int alpha_size) { m_configs.sort(compareEglConfigsPtrs); EGLConfig match; EglConfig dummy(red_size, green_size, blue_size, alpha_size, // RGB_565 EGL_DONT_CARE, EGL_DONT_CARE, 16, // Depth EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, EGL_DONT_CARE, NULL); if(!doChooseConfigs(dummy, &match, 1)) { return; } const EglConfig* config = (EglConfig*)match; int bSize; config->getConfAttrib(EGL_BUFFER_SIZE,&bSize); if(bSize == 16) { return; } int max_config_id = 0; for(ConfigsList::iterator it = m_configs.begin(); it != m_configs.end() ;it++) { EGLint id; (*it)->getConfAttrib(EGL_CONFIG_ID, &id); if(id > max_config_id) max_config_id = id; } EglConfig* newConfig = new EglConfig(*config,max_config_id+1, red_size, green_size, blue_size, alpha_size); m_configs.push_back(newConfig); } void EglDisplay::addMissingConfigs() { addSimplePixelFormat(5, 6, 5, 0); // RGB_565 addSimplePixelFormat(8, 8, 8, 0); // RGB_888 // (Host GPUs that are newer may not list RGB_888 // out of the box.) } void EglDisplay::initConfigurations(int renderableType) { if (m_configInitialized) { return; } m_idpy->queryConfigs(renderableType, addConfig, this); addMissingConfigs(); m_configs.sort(compareEglConfigsPtrs); #if EMUGL_DEBUG for (ConfigsList::const_iterator it = m_configs.begin(); it != m_configs.end(); it++) { EglConfig* config = *it; EGLint red, green, blue, alpha, depth, stencil, renderable, surface; config->getConfAttrib(EGL_RED_SIZE, &red); config->getConfAttrib(EGL_GREEN_SIZE, &green); config->getConfAttrib(EGL_BLUE_SIZE, &blue); config->getConfAttrib(EGL_ALPHA_SIZE, &alpha); config->getConfAttrib(EGL_DEPTH_SIZE, &depth); config->getConfAttrib(EGL_STENCIL_SIZE, &stencil); config->getConfAttrib(EGL_RENDERABLE_TYPE, &renderable); config->getConfAttrib(EGL_SURFACE_TYPE, &surface); } #endif // EMUGL_DEBUG } EglConfig* EglDisplay::getConfig(EGLConfig conf) const { emugl::Mutex::AutoLock mutex(m_lock); for(ConfigsList::const_iterator it = m_configs.begin(); it != m_configs.end(); it++) { if(static_cast(*it) == conf) { return (*it); } } return NULL; } SurfacePtr EglDisplay::getSurface(EGLSurface surface) const { emugl::Mutex::AutoLock mutex(m_lock); /* surface is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(surface); SurfacesHndlMap::const_iterator it = m_surfaces.find(hndl); return it != m_surfaces.end() ? (*it).second : SurfacePtr(NULL); } ContextPtr EglDisplay::getContext(EGLContext ctx) const { emugl::Mutex::AutoLock mutex(m_lock); /* ctx is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(ctx); ContextsHndlMap::const_iterator it = m_contexts.find(hndl); return it != m_contexts.end() ? (*it).second : ContextPtr(NULL); } bool EglDisplay::removeSurface(EGLSurface s) { emugl::Mutex::AutoLock mutex(m_lock); /* s is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(s); SurfacesHndlMap::iterator it = m_surfaces.find(hndl); if(it != m_surfaces.end()) { m_surfaces.erase(it); return true; } return false; } bool EglDisplay::removeContext(EGLContext ctx) { emugl::Mutex::AutoLock mutex(m_lock); /* ctx is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(ctx); ContextsHndlMap::iterator it = m_contexts.find(hndl); if(it != m_contexts.end()) { m_contexts.erase(it); return true; } return false; } bool EglDisplay::removeContext(ContextPtr ctx) { emugl::Mutex::AutoLock mutex(m_lock); ContextsHndlMap::iterator it; for(it = m_contexts.begin(); it != m_contexts.end();it++) { if((*it).second.Ptr() == ctx.Ptr()){ break; } } if(it != m_contexts.end()) { m_contexts.erase(it); return true; } return false; } EglConfig* EglDisplay::getConfig(EGLint id) const { emugl::Mutex::AutoLock mutex(m_lock); for(ConfigsList::const_iterator it = m_configs.begin(); it != m_configs.end(); it++) { if((*it)->id() == id) { return (*it); } } return NULL; } int EglDisplay::getConfigs(EGLConfig* configs,int config_size) const { emugl::Mutex::AutoLock mutex(m_lock); int i = 0; for(ConfigsList::const_iterator it = m_configs.begin(); it != m_configs.end() && i < config_size; i++, it++) { configs[i] = static_cast(*it); } return i; } int EglDisplay::chooseConfigs(const EglConfig& dummy, EGLConfig* configs, int config_size) const { emugl::Mutex::AutoLock mutex(m_lock); return doChooseConfigs(dummy, configs, config_size); } int EglDisplay::doChooseConfigs(const EglConfig& dummy, EGLConfig* configs, int config_size) const { int added = 0; for(ConfigsList::const_iterator it = m_configs.begin(); it != m_configs.end() && (added < config_size || !configs); it++) { if( (*it)->chosen(dummy)){ if(configs) { configs[added] = static_cast(*it); } added++; } } //no need to sort since the configurations are saved already in sorted maner return added; } EGLSurface EglDisplay::addSurface(SurfacePtr s ) { emugl::Mutex::AutoLock mutex(m_lock); unsigned int hndl = s.Ptr()->getHndl(); EGLSurface ret =reinterpret_cast (hndl); if(m_surfaces.find(hndl) != m_surfaces.end()) { return ret; } m_surfaces[hndl] = s; return ret; } EGLContext EglDisplay::addContext(ContextPtr ctx ) { emugl::Mutex::AutoLock mutex(m_lock); unsigned int hndl = ctx.Ptr()->getHndl(); EGLContext ret = reinterpret_cast (hndl); if(m_contexts.find(hndl) != m_contexts.end()) { return ret; } m_contexts[hndl] = ctx; return ret; } EGLImageKHR EglDisplay::addImageKHR(ImagePtr img) { emugl::Mutex::AutoLock mutex(m_lock); do { ++m_nextEglImageId; } while(m_nextEglImageId == 0); img->imageId = m_nextEglImageId; m_eglImages[m_nextEglImageId] = img; return reinterpret_cast(m_nextEglImageId); } ImagePtr EglDisplay::getImage(EGLImageKHR img) const { emugl::Mutex::AutoLock mutex(m_lock); /* img is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(img); ImagesHndlMap::const_iterator i( m_eglImages.find(hndl) ); return (i != m_eglImages.end()) ? (*i).second :ImagePtr(NULL); } bool EglDisplay:: destroyImageKHR(EGLImageKHR img) { emugl::Mutex::AutoLock mutex(m_lock); /* img is "key" in map. */ unsigned int hndl = SafeUIntFromPointer(img); ImagesHndlMap::iterator i( m_eglImages.find(hndl) ); if (i != m_eglImages.end()) { m_eglImages.erase(i); return true; } return false; } EglOS::Context* EglDisplay::getGlobalSharedContext() const { emugl::Mutex::AutoLock mutex(m_lock); #ifndef _WIN32 // find an existing OpenGL context to share with, if exist EglOS::Context* ret = (EglOS::Context*)m_manager[GLES_1_1]->getGlobalContext(); if (!ret) ret = (EglOS::Context*)m_manager[GLES_2_0]->getGlobalContext(); return ret; #else if (!m_globalSharedContext) { // // On windows we create a dummy context to serve as the // "global context" which all contexts share with. // This is because on windows it is not possible to share // with a context which is already current. This dummy context // will never be current to any thread so it is safe to share with. // Create that context using the first config if (m_configs.size() < 1) { // Should not happen! config list should be initialized at this point return NULL; } EglConfig *cfg = (*m_configs.begin()); m_globalSharedContext = m_idpy->createContext( cfg->nativeFormat(), NULL); } return m_globalSharedContext; #endif } // static void EglDisplay::addConfig(void* opaque, const EglOS::ConfigInfo* info) { EglDisplay* display = static_cast(opaque); EglConfig* config = new EglConfig( info->red_size, info->green_size, info->blue_size, info->alpha_size, info->caveat, info->config_id, info->depth_size, info->frame_buffer_level, info->max_pbuffer_width, info->max_pbuffer_height, info->max_pbuffer_size, info->native_renderable, info->renderable_type, info->native_visual_id, info->native_visual_type, info->samples_per_pixel, info->stencil_size, info->surface_type, info->transparent_type, info->trans_red_val, info->trans_green_val, info->trans_blue_val, info->frmt); display->m_configs.push_back(config); }