some applications and conformance tests expects to have non-zero bit counts for all red,green and blue channels. The translator expose all EGL compliant configs, including monochrome and RG configs. We now filter those out and expose to the guest only the RGB configs. Change-Id: I9a293675359135a548ce1c089f31a48ea2b7f46e
323 lines
9.8 KiB
C++
323 lines
9.8 KiB
C++
/*
|
|
* 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;
|
|
}
|
|
|
|
//
|
|
// Filter out not RGB configs
|
|
//
|
|
EGLint redSize, greenSize, blueSize;
|
|
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE, &redSize);
|
|
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE, &blueSize);
|
|
s_egl.eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &greenSize);
|
|
if (redSize==0 || greenSize==0 || blueSize==0) 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 0
|
|
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 ((configs != NULL) && (configs_size > 0) && (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
|
|
if (configs && nVerifiedCfgs < configs_size) {
|
|
configs[nVerifiedCfgs] = fbIdx;
|
|
}
|
|
nVerifiedCfgs++;
|
|
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;
|
|
}
|
|
}
|