blob: 17a0f871b073eac655cae2ab5da9a43af1d032ed [file] [log] [blame]
/*
* 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 "FBConfig.h"
#include "FrameBuffer.h"
#include "EGLDispatch.h"
#include <stdio.h>
FBConfig **FBConfig::s_fbConfigs = NULL;
int FBConfig::s_numConfigs = 0;
const GLuint FBConfig::s_configAttribs[] = {
EGL_DEPTH_SIZE, // must be first - see getDepthSize()
EGL_STENCIL_SIZE, // must be second - see getStencilSize()
EGL_RENDERABLE_TYPE,// must be third - see getRenderableType()
EGL_SURFACE_TYPE, // must be fourth - see getSurfaceType()
EGL_CONFIG_ID, // must be fifth - see chooseConfig()
EGL_BUFFER_SIZE,
EGL_ALPHA_SIZE,
EGL_BLUE_SIZE,
EGL_GREEN_SIZE,
EGL_RED_SIZE,
EGL_CONFIG_CAVEAT,
EGL_LEVEL,
EGL_MAX_PBUFFER_HEIGHT,
EGL_MAX_PBUFFER_PIXELS,
EGL_MAX_PBUFFER_WIDTH,
EGL_NATIVE_RENDERABLE,
EGL_NATIVE_VISUAL_ID,
EGL_NATIVE_VISUAL_TYPE,
EGL_SAMPLES,
EGL_SAMPLE_BUFFERS,
EGL_TRANSPARENT_TYPE,
EGL_TRANSPARENT_BLUE_VALUE,
EGL_TRANSPARENT_GREEN_VALUE,
EGL_TRANSPARENT_RED_VALUE,
EGL_BIND_TO_TEXTURE_RGB,
EGL_BIND_TO_TEXTURE_RGBA,
EGL_MIN_SWAP_INTERVAL,
EGL_MAX_SWAP_INTERVAL,
EGL_LUMINANCE_SIZE,
EGL_ALPHA_MASK_SIZE,
EGL_COLOR_BUFFER_TYPE,
//EGL_MATCH_NATIVE_PIXMAP,
EGL_CONFORMANT
};
const int FBConfig::s_numConfigAttribs = sizeof(FBConfig::s_configAttribs) / sizeof(GLuint);
InitConfigStatus FBConfig::initConfigList(FrameBuffer *fb)
{
InitConfigStatus ret = INIT_CONFIG_FAILED;
if (!fb) {
return ret;
}
const FrameBufferCaps &caps = fb->getCaps();
EGLDisplay dpy = fb->getDisplay();
if (dpy == EGL_NO_DISPLAY) {
fprintf(stderr,"Could not get EGL Display\n");
return ret;
}
//
// Query the set of configs in the EGL backend
//
EGLint nConfigs;
if (!s_egl.eglGetConfigs(dpy, NULL, 0, &nConfigs)) {
fprintf(stderr, "Could not get number of available configs\n");
return ret;
}
EGLConfig *configs = new EGLConfig[nConfigs];
s_egl.eglGetConfigs(dpy, configs, nConfigs, &nConfigs);
//
// Find number of usable configs which support pbuffer rendering
// for each ES and ES2 as well as number of configs supporting
// EGL_BIND_TO_TEXTURE_RGBA for each of ES and ES2.
//
const int GL = 0;
const int GL1 = 1;
const int GL2 = 2;
int numPbuf[3] = {0, 0, 0};
int numBindToTexture[3] = {0, 0, 0};
for (int i=0; i<nConfigs; i++) {
GLint depthSize, stencilSize;
GLint renderType, surfaceType;
GLint bindToTexture;
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_DEPTH_SIZE, &depthSize);
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_STENCIL_SIZE, &stencilSize);
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_RENDERABLE_TYPE, &renderType);
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_SURFACE_TYPE, &surfaceType);
if (depthSize > 0 && stencilSize > 0 &&
(surfaceType & EGL_PBUFFER_BIT) != 0) {
numPbuf[GL]++;
if ((renderType & EGL_OPENGL_ES_BIT) != 0) {
numPbuf[GL1]++;
}
if ((renderType & EGL_OPENGL_ES2_BIT) != 0) {
numPbuf[GL2]++;
}
s_egl.eglGetConfigAttrib(dpy, configs[i],
EGL_BIND_TO_TEXTURE_RGBA, &bindToTexture);
if (bindToTexture) {
numBindToTexture[GL]++;
if ((renderType & EGL_OPENGL_ES_BIT) != 0) {
numBindToTexture[GL1]++;
}
if ((renderType & EGL_OPENGL_ES2_BIT) != 0) {
numBindToTexture[GL2]++;
}
}
}
}
bool useOnlyPbuf = false;
bool useOnlyBindToTexture = false;
int numConfigs = nConfigs;
if ( numPbuf[GL1] > 0 &&
(!caps.hasGL2 || numPbuf[GL2] > 0)) {
useOnlyPbuf = true;
numConfigs = numPbuf[GL];
}
if (useOnlyPbuf &&
!(caps.has_eglimage_texture_2d &&
caps.has_eglimage_renderbuffer) &&
numBindToTexture[GL1] > 0 &&
(!caps.hasGL2 || numBindToTexture[GL2] > 0)) {
useOnlyBindToTexture = true;
numConfigs = numBindToTexture[GL];
ret = INIT_CONFIG_HAS_BIND_TO_TEXTURE;
}
else {
ret = INIT_CONFIG_PASSED;
}
int j = 0;
s_fbConfigs = new FBConfig*[nConfigs];
for (int i=0; i<nConfigs; i++) {
if (useOnlyBindToTexture) {
EGLint bindToTexture;
s_egl.eglGetConfigAttrib(dpy, configs[i],
EGL_BIND_TO_TEXTURE_RGBA, &bindToTexture);
if (!bindToTexture) continue;
}
else if (useOnlyPbuf) {
EGLint surfaceType;
s_egl.eglGetConfigAttrib(dpy, configs[i],
EGL_SURFACE_TYPE, &surfaceType);
if (!(surfaceType & EGL_PBUFFER_BIT)) continue;
}
s_fbConfigs[j++] = new FBConfig(dpy, configs[i]);
}
s_numConfigs = j;
delete configs;
return ret;
}
const FBConfig *FBConfig::get(int p_config)
{
if (p_config >= 0 && p_config < s_numConfigs) {
return s_fbConfigs[p_config];
}
return NULL;
}
int FBConfig::getNumConfigs()
{
return s_numConfigs;
}
void FBConfig::packConfigsInfo(GLuint *buffer)
{
memcpy(buffer, s_configAttribs, s_numConfigAttribs * sizeof(GLuint));
for (int i=0; i<s_numConfigs; i++) {
memcpy(buffer+(i+1)*s_numConfigAttribs,
s_fbConfigs[i]->m_attribValues,
s_numConfigAttribs * sizeof(GLuint));
}
}
int FBConfig::chooseConfig(FrameBuffer *fb, EGLint * attribs, uint32_t * configs, uint32_t configs_size)
{
EGLDisplay dpy = fb->getDisplay();
int ret = 0;
if (dpy == EGL_NO_DISPLAY) {
fprintf(stderr,"Could not get EGL Display\n");
return ret;
}
//
// Query the num of configs in the EGL backend
//
EGLint nConfigs;
if (!s_egl.eglGetConfigs(dpy, NULL, 0, &nConfigs)) {
fprintf(stderr, "Could not get number of available configs\n");
return ret;
}
//
// Query the max matching configs in the backend
//
EGLConfig *matchedConfigs = new EGLConfig[nConfigs];
//
//Until we have EGLImage implementation, we force pbuf configs
//
bool needToAddPbufAttr = true;
int attribCnt = 0;
EGLint * attrib_p = attribs;
if (attribs) {
while (attrib_p[0] != EGL_NONE) {
if (attrib_p[0] == EGL_SURFACE_TYPE) {
attrib_p[1] = EGL_PBUFFER_BIT; //replace whatever was there before
needToAddPbufAttr = false;
}
attrib_p += 2;
attribCnt += 2;
}
}
EGLint * newAttribs = new EGLint[attribCnt + 1 + ((needToAddPbufAttr) ? 2 : 0)];
attrib_p = newAttribs;
if (needToAddPbufAttr) {
*(attrib_p++) = EGL_SURFACE_TYPE;
*(attrib_p++) = EGL_PBUFFER_BIT;
}
memcpy(attrib_p, attribs, attribCnt*sizeof(EGLint));
attrib_p += attribCnt;
*attrib_p = EGL_NONE;
#if 1
DBG("EGLint %d", sizeof(EGLint));
if (newAttribs) {
EGLint * attrib_p = newAttribs;
while (attrib_p[0] != EGL_NONE) {
DBG("attr: 0x%x %d", attrib_p[0], attrib_p[1]);
attrib_p += 2;
}
}
#endif
s_egl.eglChooseConfig(dpy, newAttribs, matchedConfigs, nConfigs, &nConfigs);
delete newAttribs;
//
// From all matchedConfigs we need only config_size FBConfigs, so we intersect both lists compating the CONFIG_ID attribute
//
uint32_t nVerifiedCfgs = 0;
for (int matchedIdx=0; matchedIdx<nConfigs; matchedIdx++) {
if (nVerifiedCfgs >= configs_size) break; //We have enouhgt configs
int sCfgId;
s_egl.eglGetConfigAttrib(dpy, matchedConfigs[matchedIdx], EGL_CONFIG_ID, &sCfgId);
for (int fbIdx=0; fbIdx<s_numConfigs; fbIdx++) {
int dCfgId = s_fbConfigs[fbIdx]->m_attribValues[4]; //CONFIG_ID
if (sCfgId == dCfgId) {
//This config matches the requested attributes and filtered into fbConfigs, so we're happy with it
configs[nVerifiedCfgs++] = fbIdx;
break;
}
}
}
delete matchedConfigs;
return nVerifiedCfgs;
}
FBConfig::FBConfig(EGLDisplay p_eglDpy, EGLConfig p_eglCfg)
{
m_eglConfig = p_eglCfg;
m_attribValues = new GLint[s_numConfigAttribs];
for (int i=0; i<s_numConfigAttribs; i++) {
s_egl.eglGetConfigAttrib(p_eglDpy, p_eglCfg, s_configAttribs[i], &m_attribValues[i]);
//
// All exported configs supports android native window rendering
//
if (s_configAttribs[i] == EGL_SURFACE_TYPE) {
m_attribValues[i] |= EGL_WINDOW_BIT;
}
}
}
FBConfig::~FBConfig()
{
if (m_attribValues) {
delete m_attribValues;
}
}