blob: cd14156de02c2fdc5b43cc09f0e0204b2277620e [file] [log] [blame]
// Copyright (C) 2015 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 "EmulatedEglConfig.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "host-common/opengl/emugl_config.h"
#include "host-common/feature_control.h"
#include "host-common/logging.h"
#include "host-common/misc.h"
#include "host-common/opengl/misc.h"
#include <stdio.h>
#include <string.h>
namespace gfxstream {
namespace gl {
namespace {
#ifndef EGL_PRESERVED_RESOURCES
#define EGL_PRESERVED_RESOURCES 0x3030
#endif
const GLuint kConfigAttributes[] = {
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_PRESERVED_RESOURCES,
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_RECORDABLE_ANDROID,
EGL_CONFORMANT
};
const size_t kConfigAttributesLen =
sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) {
// Filter out configs which do not support pbuffers, since they
// are used to implement window surfaces.
EGLint surfaceType;
s_egl.eglGetConfigAttrib(
display, config, EGL_SURFACE_TYPE, &surfaceType);
if (!(surfaceType & EGL_PBUFFER_BIT)) {
return false;
}
// Filter out configs that do not support RGB pixel values.
EGLint redSize = 0, greenSize = 0, blueSize = 0;
s_egl.eglGetConfigAttrib(
display, config,EGL_RED_SIZE, &redSize);
s_egl.eglGetConfigAttrib(
display, config, EGL_GREEN_SIZE, &greenSize);
s_egl.eglGetConfigAttrib(
display, config, EGL_BLUE_SIZE, &blueSize);
if (!redSize || !greenSize || !blueSize) {
return false;
}
return true;
}
} // namespace
EmulatedEglConfig::EmulatedEglConfig(EGLint guestConfig,
EGLConfig hostConfig,
EGLDisplay hostDisplay)
: mGuestConfig(guestConfig),
mHostConfig(hostConfig),
mAttribValues(kConfigAttributesLen) {
for (size_t i = 0; i < kConfigAttributesLen; ++i) {
mAttribValues[i] = 0;
s_egl.eglGetConfigAttrib(hostDisplay,
hostConfig,
kConfigAttributes[i],
&mAttribValues[i]);
// This implementation supports guest window surfaces by wrapping
// them around host Pbuffers, so always report it to the guest.
if (kConfigAttributes[i] == EGL_SURFACE_TYPE) {
mAttribValues[i] |= EGL_WINDOW_BIT;
}
// Don't report ES3 renderable type if we don't support it.
if (kConfigAttributes[i] == EGL_RENDERABLE_TYPE) {
if (!feature_is_enabled(
kFeature_GLESDynamicVersion) &&
mAttribValues[i] & EGL_OPENGL_ES3_BIT) {
mAttribValues[i] &= ~EGL_OPENGL_ES3_BIT;
}
}
}
}
EmulatedEglConfigList::EmulatedEglConfigList(EGLDisplay display,
GLESDispatchMaxVersion version)
: mDisplay(display), mGlesDispatchMaxVersion(version) {
if (display == EGL_NO_DISPLAY) {
ERR("Invalid display value %p (EGL_NO_DISPLAY).", (void*)display);
return;
}
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
ERR("Failed to get number of host EGL configs.");
return;
}
std::vector<EGLConfig> hostConfigs(numHostConfigs);
s_egl.eglGetConfigs(display, hostConfigs.data(), numHostConfigs, &numHostConfigs);
for (EGLConfig hostConfig : hostConfigs) {
// Filter out configs that are not compatible with our implementation.
if (!isCompatibleHostConfig(hostConfig, display)) {
continue;
}
const EGLint guestConfig = static_cast<EGLint>(mConfigs.size());
mConfigs.push_back(EmulatedEglConfig(guestConfig, hostConfig, display));
}
}
int EmulatedEglConfigList::chooseConfig(const EGLint* attribs,
EGLint* configs,
EGLint configsSize) const {
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
ERR("Failed to get number of host EGL configs.");
return 0;
}
// If EGL_SURFACE_TYPE appears in |attribs|, the value passed to
// eglChooseConfig should be forced to EGL_PBUFFER_BIT because that's
// what it used by the current implementation, exclusively. This forces
// the rewrite of |attribs| into a new array.
bool hasSurfaceType = false;
bool wantSwapPreserved = false;
int surfaceTypeIdx = 0;
int numAttribs = 0;
std::vector<EGLint> newAttribs;
while (attribs[numAttribs] != EGL_NONE) {
if (attribs[numAttribs] == EGL_SURFACE_TYPE) {
hasSurfaceType = true;
surfaceTypeIdx = numAttribs;
if (attribs[numAttribs+1] & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
wantSwapPreserved = true;
}
}
// Reject config if guest asked for ES3 and we don't have it.
if (attribs[numAttribs] == EGL_RENDERABLE_TYPE) {
if (attribs[numAttribs + 1] != EGL_DONT_CARE &&
attribs[numAttribs + 1] & EGL_OPENGL_ES3_BIT_KHR &&
(!feature_is_enabled(
kFeature_GLESDynamicVersion) ||
mGlesDispatchMaxVersion <
GLES_DISPATCH_MAX_VERSION_3_0)) {
return 0;
}
}
numAttribs += 2;
}
if (numAttribs) {
newAttribs.resize(numAttribs);
memcpy(&newAttribs[0], attribs, numAttribs * sizeof(EGLint));
}
int apiLevel;
emugl::getAvdInfo(NULL, &apiLevel);
if (!hasSurfaceType) {
newAttribs.push_back(EGL_SURFACE_TYPE);
newAttribs.push_back(0);
} else if (wantSwapPreserved && apiLevel <= 19) {
newAttribs[surfaceTypeIdx + 1] &= ~(EGLint)EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
}
if (emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER ||
emugl::getRenderer() == SELECTED_RENDERER_SWIFTSHADER_INDIRECT ||
emugl::getRenderer() == SELECTED_RENDERER_ANGLE ||
emugl::getRenderer() == SELECTED_RENDERER_ANGLE_INDIRECT) {
newAttribs.push_back(EGL_CONFIG_CAVEAT);
newAttribs.push_back(EGL_DONT_CARE);
}
newAttribs.push_back(EGL_NONE);
std::vector<EGLConfig> matchedConfigs(numHostConfigs);
if (s_egl.eglChooseConfig(mDisplay,
&newAttribs[0],
matchedConfigs.data(),
numHostConfigs,
&numHostConfigs) == EGL_FALSE) {
return -s_egl.eglGetError();
}
int result = 0;
for (int n = 0; n < numHostConfigs; ++n) {
// Don't count or write more than |configsSize| items if |configs|
// is not NULL.
if (configs && configsSize > 0 && result >= configsSize) {
break;
}
// Skip incompatible host configs.
if (!isCompatibleHostConfig(matchedConfigs[n], mDisplay)) {
continue;
}
// Find the EmulatedEglConfig with the same EGL_CONFIG_ID
EGLint hostConfigId;
s_egl.eglGetConfigAttrib(
mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId);
for (const EmulatedEglConfig& config : mConfigs) {
if (config.getConfigId() == hostConfigId) {
// There is a match. Write it to |configs| if it is not NULL.
if (configs && result < configsSize) {
configs[result] = config.getGuestEglConfig();
}
result++;
break;
}
}
}
return result;
}
void EmulatedEglConfigList::getPackInfo(EGLint* numConfigs,
EGLint* numAttributes) const {
if (numConfigs) {
*numConfigs = mConfigs.size();
}
if (numAttributes) {
*numAttributes = static_cast<EGLint>(kConfigAttributesLen);
}
}
EGLint EmulatedEglConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const {
GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
GLuint neededByteSize = (mConfigs.size() + 1) * numAttribs * kGLuintSize;
if (!buffer || bufferByteSize < neededByteSize) {
return -neededByteSize;
}
// Write to the buffer the config attribute ids, followed for each one
// of the configs, their values.
memcpy(buffer, kConfigAttributes, kConfigAttributesLen * kGLuintSize);
for (int i = 0; i < mConfigs.size(); ++i) {
memcpy(buffer + (i + 1) * kConfigAttributesLen,
mConfigs[i].mAttribValues.data(),
kConfigAttributesLen * kGLuintSize);
}
return mConfigs.size();
}
} // namespace gl
} // namespace gfxstream