blob: d013276f55fcb7e77addd33f60a33da98ea8433a [file] [log] [blame]
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DisplayAndroid.cpp: Android implementation of egl::Display
#include <android/native_window.h>
#include "common/debug.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
#include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
#include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
#include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h"
#include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h"
namespace
{
const char *GetEGLPath()
{
#if defined(__LP64__)
return "/system/lib64/libEGL.so";
#else
return "/system/lib/libEGL.so";
#endif
}
} // namespace
namespace rx
{
DisplayAndroid::DisplayAndroid(const egl::DisplayState &state)
: DisplayEGL(state), mDummyPbuffer(EGL_NO_SURFACE)
{
}
DisplayAndroid::~DisplayAndroid()
{
}
egl::Error DisplayAndroid::initialize(egl::Display *display)
{
FunctionsEGLDL *egl = new FunctionsEGLDL();
mEGL = egl;
ANGLE_TRY(egl->initialize(display->getNativeDisplayId(), GetEGLPath()));
gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
ASSERT(eglVersion >= gl::Version(1, 4));
static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR, "Extension define must match core");
EGLint esBit = (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
? EGL_OPENGL_ES3_BIT
: EGL_OPENGL_ES2_BIT;
// clang-format off
mConfigAttribList =
{
// Choose RGBA8888
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
// EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
// must match for contexts to be compatible.
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_SAMPLE_BUFFERS, 0,
// Android doesn't support pixmaps
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_CONFIG_CAVEAT, EGL_NONE,
EGL_CONFORMANT, esBit,
EGL_RENDERABLE_TYPE, esBit,
};
if (mEGL->hasExtension("EGL_EXT_pixel_format_float"))
{
// Don't request floating point configs
mConfigAttribList.push_back(EGL_COLOR_COMPONENT_TYPE_EXT);
mConfigAttribList.push_back(EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
}
// Complete the attrib list
mConfigAttribList.push_back(EGL_NONE);
// clang-format on
EGLint numConfig;
EGLBoolean success = mEGL->chooseConfig(mConfigAttribList.data(), &mConfig, 1, &numConfig);
if (success == EGL_FALSE)
{
return egl::Error(mEGL->getError(), "eglChooseConfig failed");
}
ANGLE_TRY(initializeContext(display->getAttributeMap()));
int dummyPbufferAttribs[] = {
EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
};
mDummyPbuffer = mEGL->createPbufferSurface(mConfig, dummyPbufferAttribs);
if (mDummyPbuffer == EGL_NO_SURFACE)
{
return egl::Error(mEGL->getError(), "eglCreatePbufferSurface failed");
}
success = mEGL->makeCurrent(mDummyPbuffer, mContext);
if (success == EGL_FALSE)
{
return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
}
mFunctionsGL = mEGL->makeFunctionsGL();
mFunctionsGL->initialize();
return DisplayGL::initialize(display);
}
void DisplayAndroid::terminate()
{
DisplayGL::terminate();
EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (success == EGL_FALSE)
{
ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
}
if (mDummyPbuffer != EGL_NO_SURFACE)
{
success = mEGL->destroySurface(mDummyPbuffer);
mDummyPbuffer = EGL_NO_SURFACE;
if (success == EGL_FALSE)
{
ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
}
}
if (mContext != EGL_NO_CONTEXT)
{
success = mEGL->destroyContext(mContext);
mContext = EGL_NO_CONTEXT;
if (success == EGL_FALSE)
{
ERR() << "eglDestroyContext error " << egl::Error(mEGL->getError());
}
}
egl::Error result = mEGL->terminate();
if (result.isError())
{
ERR() << "eglTerminate error " << result;
}
SafeDelete(mEGL);
SafeDelete(mFunctionsGL);
}
SurfaceImpl *DisplayAndroid::createWindowSurface(const egl::SurfaceState &state,
EGLNativeWindowType window,
const egl::AttributeMap &attribs)
{
EGLConfig config;
EGLint numConfig;
EGLBoolean success;
const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[state.config->configID], EGL_NONE};
success = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig);
ASSERT(success && numConfig == 1);
return new WindowSurfaceEGL(state, mEGL, config, window, attribs.toIntVector(), mContext,
getRenderer());
}
SurfaceImpl *DisplayAndroid::createPbufferSurface(const egl::SurfaceState &state,
const egl::AttributeMap &attribs)
{
EGLConfig config;
EGLint numConfig;
EGLBoolean success;
const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[state.config->configID], EGL_NONE};
success = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig);
ASSERT(success && numConfig == 1);
return new PbufferSurfaceEGL(state, mEGL, config, attribs.toIntVector(), mContext,
getRenderer());
}
SurfaceImpl *DisplayAndroid::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
}
SurfaceImpl *DisplayAndroid::createPixmapSurface(const egl::SurfaceState &state,
NativePixmapType nativePixmap,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
}
ImageImpl *DisplayAndroid::createImage(const egl::ImageState &state,
EGLenum target,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return DisplayGL::createImage(state, target, attribs);
}
template <typename T>
void DisplayAndroid::getConfigAttrib(EGLConfig config, EGLint attribute, T *value) const
{
EGLint tmp;
EGLBoolean success = mEGL->getConfigAttrib(config, attribute, &tmp);
ASSERT(success == EGL_TRUE);
*value = tmp;
}
template <typename T, typename U>
void DisplayAndroid::getConfigAttribIfExtension(EGLConfig config,
EGLint attribute,
T *value,
const char *extension,
const U &defaultValue) const
{
if (mEGL->hasExtension(extension))
{
getConfigAttrib(config, attribute, value);
}
else
{
*value = static_cast<T>(defaultValue);
}
}
egl::ConfigSet DisplayAndroid::generateConfigs()
{
egl::ConfigSet configSet;
mConfigIds.clear();
EGLint numConfigs;
EGLBoolean success = mEGL->chooseConfig(mConfigAttribList.data(), nullptr, 0, &numConfigs);
ASSERT(success == EGL_TRUE && numConfigs > 0);
std::vector<EGLConfig> configs(numConfigs);
EGLint numConfigs2;
success =
mEGL->chooseConfig(mConfigAttribList.data(), configs.data(), numConfigs, &numConfigs2);
ASSERT(success == EGL_TRUE && numConfigs2 == numConfigs);
for (int i = 0; i < numConfigs; i++)
{
egl::Config config;
getConfigAttrib(configs[i], EGL_BUFFER_SIZE, &config.bufferSize);
getConfigAttrib(configs[i], EGL_RED_SIZE, &config.redSize);
getConfigAttrib(configs[i], EGL_GREEN_SIZE, &config.greenSize);
getConfigAttrib(configs[i], EGL_BLUE_SIZE, &config.blueSize);
getConfigAttrib(configs[i], EGL_LUMINANCE_SIZE, &config.luminanceSize);
getConfigAttrib(configs[i], EGL_ALPHA_SIZE, &config.alphaSize);
getConfigAttrib(configs[i], EGL_ALPHA_MASK_SIZE, &config.alphaMaskSize);
getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGB, &config.bindToTextureRGB);
getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGBA, &config.bindToTextureRGBA);
getConfigAttrib(configs[i], EGL_COLOR_BUFFER_TYPE, &config.colorBufferType);
getConfigAttrib(configs[i], EGL_CONFIG_CAVEAT, &config.configCaveat);
getConfigAttrib(configs[i], EGL_CONFIG_ID, &config.configID);
getConfigAttrib(configs[i], EGL_CONFORMANT, &config.conformant);
getConfigAttrib(configs[i], EGL_DEPTH_SIZE, &config.depthSize);
getConfigAttrib(configs[i], EGL_LEVEL, &config.level);
getConfigAttrib(configs[i], EGL_MAX_PBUFFER_WIDTH, &config.maxPBufferWidth);
getConfigAttrib(configs[i], EGL_MAX_PBUFFER_HEIGHT, &config.maxPBufferHeight);
getConfigAttrib(configs[i], EGL_MAX_PBUFFER_PIXELS, &config.maxPBufferPixels);
getConfigAttrib(configs[i], EGL_MAX_SWAP_INTERVAL, &config.maxSwapInterval);
getConfigAttrib(configs[i], EGL_MIN_SWAP_INTERVAL, &config.minSwapInterval);
getConfigAttrib(configs[i], EGL_NATIVE_RENDERABLE, &config.nativeRenderable);
getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_ID, &config.nativeVisualID);
getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_TYPE, &config.nativeVisualType);
getConfigAttrib(configs[i], EGL_RENDERABLE_TYPE, &config.renderableType);
getConfigAttrib(configs[i], EGL_SAMPLE_BUFFERS, &config.sampleBuffers);
getConfigAttrib(configs[i], EGL_SAMPLES, &config.samples);
getConfigAttrib(configs[i], EGL_STENCIL_SIZE, &config.stencilSize);
getConfigAttrib(configs[i], EGL_SURFACE_TYPE, &config.surfaceType);
getConfigAttrib(configs[i], EGL_TRANSPARENT_TYPE, &config.transparentType);
getConfigAttrib(configs[i], EGL_TRANSPARENT_RED_VALUE, &config.transparentRedValue);
getConfigAttrib(configs[i], EGL_TRANSPARENT_GREEN_VALUE, &config.transparentGreenValue);
getConfigAttrib(configs[i], EGL_TRANSPARENT_BLUE_VALUE, &config.transparentBlueValue);
getConfigAttribIfExtension(configs[i], EGL_COLOR_COMPONENT_TYPE_EXT,
&config.colorComponentType, "EGL_EXT_pixel_format_float",
EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
if (config.colorBufferType == EGL_RGB_BUFFER)
{
ASSERT(config.colorComponentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
if (config.redSize == 8 && config.greenSize == 8 && config.blueSize == 8 &&
config.alphaSize == 8)
{
config.renderTargetFormat = GL_RGBA8;
}
else if (config.redSize == 8 && config.greenSize == 8 && config.blueSize == 8 &&
config.alphaSize == 0)
{
config.renderTargetFormat = GL_RGB8;
}
else if (config.redSize == 5 && config.greenSize == 6 && config.blueSize == 5 &&
config.alphaSize == 0)
{
config.renderTargetFormat = GL_RGB565;
}
else
{
UNREACHABLE();
}
}
else
{
UNREACHABLE();
}
if (config.depthSize == 0 && config.stencilSize == 0)
{
config.depthStencilFormat = GL_ZERO;
}
else if (config.depthSize == 16 && config.stencilSize == 0)
{
config.depthStencilFormat = GL_DEPTH_COMPONENT16;
}
else if (config.depthSize == 24 && config.stencilSize == 0)
{
config.depthStencilFormat = GL_DEPTH_COMPONENT24;
}
else if (config.depthSize == 24 && config.stencilSize == 8)
{
config.depthStencilFormat = GL_DEPTH24_STENCIL8;
}
else if (config.depthSize == 0 && config.stencilSize == 8)
{
config.depthStencilFormat = GL_STENCIL_INDEX8;
}
else
{
UNREACHABLE();
}
config.matchNativePixmap = EGL_NONE;
config.optimalOrientation = 0;
int internalId = configSet.add(config);
mConfigIds[internalId] = config.configID;
}
return configSet;
}
bool DisplayAndroid::testDeviceLost()
{
return false;
}
egl::Error DisplayAndroid::restoreLostDevice()
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
{
return ANativeWindow_getFormat(window) >= 0;
}
egl::Error DisplayAndroid::getDevice(DeviceImpl **device)
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
egl::Error DisplayAndroid::waitClient() const
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
egl::Error DisplayAndroid::waitNative(EGLint engine,
egl::Surface *drawSurface,
egl::Surface *readSurface) const
{
UNIMPLEMENTED();
return egl::Error(EGL_SUCCESS);
}
} // namespace rx