| // | |
| // Copyright 2002 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. | |
| // | |
| // Surface.cpp: Implements the egl::Surface class, representing a drawing surface | |
| // such as the client area of a window, including any back buffers. | |
| // Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. | |
| #include "libANGLE/Surface.h" | |
| #include <EGL/eglext.h> | |
| #include "libANGLE/Config.h" | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/Display.h" | |
| #include "libANGLE/Framebuffer.h" | |
| #include "libANGLE/Texture.h" | |
| #include "libANGLE/formatutils.h" | |
| #include "libANGLE/renderer/EGLImplFactory.h" | |
| #include "libANGLE/trace.h" | |
| namespace egl | |
| { | |
| namespace | |
| { | |
| angle::SubjectIndex kSurfaceImplSubjectIndex = 0; | |
| } // namespace | |
| SurfaceState::SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn) | |
| : label(nullptr), | |
| config((configIn != nullptr) ? new egl::Config(*configIn) : nullptr), | |
| attributes(attributesIn), | |
| timestampsEnabled(false), | |
| autoRefreshEnabled(false), | |
| directComposition(false), | |
| swapBehavior(EGL_NONE) | |
| { | |
| directComposition = attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE; | |
| } | |
| SurfaceState::~SurfaceState() | |
| { | |
| delete config; | |
| } | |
| bool SurfaceState::isRobustResourceInitEnabled() const | |
| { | |
| return attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE; | |
| } | |
| bool SurfaceState::hasProtectedContent() const | |
| { | |
| return attributes.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) == EGL_TRUE; | |
| } | |
| EGLint SurfaceState::getPreferredSwapInterval() const | |
| { | |
| return attributes.getAsInt(EGL_SWAP_INTERVAL_ANGLE, 1); | |
| } | |
| Surface::Surface(EGLint surfaceType, | |
| GLuint serialId, | |
| const egl::Config *config, | |
| const AttributeMap &attributes, | |
| bool forceRobustResourceInit, | |
| EGLenum buftype) | |
| : FramebufferAttachmentObject(), | |
| mState(config, attributes), | |
| mImplementation(nullptr), | |
| mRefCount(0), | |
| mDestroyed(false), | |
| mType(surfaceType), | |
| mBuftype(buftype), | |
| mPostSubBufferRequested(false), | |
| mLargestPbuffer(false), | |
| mGLColorspace(EGL_GL_COLORSPACE_LINEAR), | |
| mVGAlphaFormat(EGL_VG_ALPHA_FORMAT_NONPRE), | |
| mVGColorspace(EGL_VG_COLORSPACE_sRGB), | |
| mMipmapTexture(false), | |
| mMipmapLevel(0), | |
| mHorizontalResolution(EGL_UNKNOWN), | |
| mVerticalResolution(EGL_UNKNOWN), | |
| mMultisampleResolve(EGL_MULTISAMPLE_RESOLVE_DEFAULT), | |
| mFixedSize(false), | |
| mFixedWidth(0), | |
| mFixedHeight(0), | |
| mTextureFormat(TextureFormat::NoTexture), | |
| mTextureTarget(EGL_NO_TEXTURE), | |
| // FIXME: Determine actual pixel aspect ratio | |
| mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)), | |
| mRenderBuffer(EGL_BACK_BUFFER), | |
| mOrientation(0), | |
| mTexture(nullptr), | |
| mColorFormat(config->renderTargetFormat), | |
| mDSFormat(config->depthStencilFormat), | |
| mIsCurrentOnAnyContext(false), | |
| mLockBufferPtr(nullptr), | |
| mLockBufferPitch(0), | |
| mBufferAgeQueriedSinceLastSwap(false), | |
| mIsDamageRegionSet(false), | |
| mColorInitState(gl::InitState::Initialized), | |
| mDepthStencilInitState(gl::InitState::Initialized), | |
| mImplObserverBinding(this, kSurfaceImplSubjectIndex), | |
| mSerialId(serialId) | |
| { | |
| mPostSubBufferRequested = | |
| (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); | |
| if (mType == EGL_PBUFFER_BIT) | |
| { | |
| mLargestPbuffer = (attributes.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); | |
| } | |
| if (mType == EGL_PIXMAP_BIT) | |
| { | |
| mRenderBuffer = EGL_SINGLE_BUFFER; | |
| } | |
| if (mType == EGL_WINDOW_BIT) | |
| { | |
| mRenderBuffer = mState.attributes.getAsInt(EGL_RENDER_BUFFER, EGL_BACK_BUFFER); | |
| } | |
| mGLColorspace = | |
| static_cast<EGLenum>(attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR)); | |
| mVGAlphaFormat = | |
| static_cast<EGLenum>(attributes.get(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_NONPRE)); | |
| mVGColorspace = static_cast<EGLenum>(attributes.get(EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB)); | |
| mMipmapTexture = (attributes.get(EGL_MIPMAP_TEXTURE, EGL_FALSE) == EGL_TRUE); | |
| mRobustResourceInitialization = | |
| forceRobustResourceInit || | |
| (attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); | |
| if (mRobustResourceInitialization) | |
| { | |
| mColorInitState = gl::InitState::MayNeedInit; | |
| mDepthStencilInitState = gl::InitState::MayNeedInit; | |
| } | |
| mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); | |
| if (mFixedSize) | |
| { | |
| mFixedWidth = static_cast<size_t>(attributes.get(EGL_WIDTH, 0)); | |
| mFixedHeight = static_cast<size_t>(attributes.get(EGL_HEIGHT, 0)); | |
| } | |
| if (mType != EGL_WINDOW_BIT) | |
| { | |
| mTextureFormat = attributes.getAsPackedEnum(EGL_TEXTURE_FORMAT, TextureFormat::NoTexture); | |
| mTextureTarget = static_cast<EGLenum>(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); | |
| } | |
| mOrientation = static_cast<EGLint>(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); | |
| mTextureOffset.x = static_cast<int>(mState.attributes.get(EGL_TEXTURE_OFFSET_X_ANGLE, 0)); | |
| mTextureOffset.y = static_cast<int>(mState.attributes.get(EGL_TEXTURE_OFFSET_Y_ANGLE, 0)); | |
| } | |
| Surface::~Surface() {} | |
| rx::FramebufferAttachmentObjectImpl *Surface::getAttachmentImpl() const | |
| { | |
| return mImplementation; | |
| } | |
| Error Surface::destroyImpl(const Display *display) | |
| { | |
| if (mImplementation) | |
| { | |
| mImplementation->destroy(display); | |
| } | |
| ASSERT(!mTexture); | |
| SafeDelete(mImplementation); | |
| delete this; | |
| return NoError(); | |
| } | |
| void Surface::postSwap(const gl::Context *context) | |
| { | |
| if (mRobustResourceInitialization && mState.swapBehavior != EGL_BUFFER_PRESERVED) | |
| { | |
| mColorInitState = gl::InitState::MayNeedInit; | |
| mDepthStencilInitState = gl::InitState::MayNeedInit; | |
| onStateChange(angle::SubjectMessage::SubjectChanged); | |
| } | |
| mBufferAgeQueriedSinceLastSwap = false; | |
| mIsDamageRegionSet = false; | |
| } | |
| Error Surface::initialize(const Display *display) | |
| { | |
| GLenum overrideRenderTargetFormat = mState.config->renderTargetFormat; | |
| // To account for color space differences, override the renderTargetFormat with the | |
| // non-linear format. If no suitable non-linear format was found, return | |
| // EGL_BAD_MATCH error | |
| if (!gl::ColorspaceFormatOverride(mGLColorspace, &overrideRenderTargetFormat)) | |
| { | |
| return egl::EglBadMatch(); | |
| } | |
| // If an override is required update mState.config as well | |
| if (mState.config->renderTargetFormat != overrideRenderTargetFormat) | |
| { | |
| egl::Config *overrideConfig = new egl::Config(*(mState.config)); | |
| overrideConfig->renderTargetFormat = overrideRenderTargetFormat; | |
| delete mState.config; | |
| mState.config = overrideConfig; | |
| mColorFormat = gl::Format(mState.config->renderTargetFormat); | |
| mDSFormat = gl::Format(mState.config->depthStencilFormat); | |
| } | |
| ANGLE_TRY(mImplementation->initialize(display)); | |
| // Initialized here since impl is nullptr in the constructor. | |
| // Must happen after implementation initialize for Android. | |
| mState.swapBehavior = mImplementation->getSwapBehavior(); | |
| if (mBuftype == EGL_IOSURFACE_ANGLE) | |
| { | |
| GLenum internalFormat = | |
| static_cast<GLenum>(mState.attributes.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE)); | |
| GLenum type = static_cast<GLenum>(mState.attributes.get(EGL_TEXTURE_TYPE_ANGLE)); | |
| // GL_RGBA + GL_HALF_FLOAT is not a valid format/type combination in GLES like it is in | |
| // desktop GL. Adjust the frontend format to be sized RGBA16F. | |
| if (internalFormat == GL_RGBA && type == GL_HALF_FLOAT) | |
| { | |
| internalFormat = GL_RGBA16F; | |
| } | |
| mColorFormat = gl::Format(internalFormat, type); | |
| } | |
| if (mBuftype == EGL_D3D_TEXTURE_ANGLE) | |
| { | |
| const angle::Format *colorFormat = mImplementation->getD3DTextureColorFormat(); | |
| ASSERT(colorFormat != nullptr); | |
| GLenum internalFormat = colorFormat->fboImplementationInternalFormat; | |
| mColorFormat = gl::Format(internalFormat, colorFormat->componentType); | |
| mGLColorspace = EGL_GL_COLORSPACE_LINEAR; | |
| if (mColorFormat.info->colorEncoding == GL_SRGB) | |
| { | |
| mGLColorspace = EGL_GL_COLORSPACE_SRGB; | |
| } | |
| } | |
| if (mType == EGL_WINDOW_BIT && display->getExtensions().getFrameTimestamps) | |
| { | |
| mState.supportedCompositorTimings = mImplementation->getSupportedCompositorTimings(); | |
| mState.supportedTimestamps = mImplementation->getSupportedTimestamps(); | |
| } | |
| mImplObserverBinding.bind(mImplementation); | |
| return NoError(); | |
| } | |
| Error Surface::makeCurrent(const gl::Context *context) | |
| { | |
| if (isLocked()) | |
| { | |
| return EglBadAccess(); | |
| } | |
| ANGLE_TRY(mImplementation->makeCurrent(context)); | |
| mIsCurrentOnAnyContext = true; | |
| addRef(); | |
| return NoError(); | |
| } | |
| Error Surface::unMakeCurrent(const gl::Context *context) | |
| { | |
| ANGLE_TRY(mImplementation->unMakeCurrent(context)); | |
| mIsCurrentOnAnyContext = false; | |
| return releaseRef(context->getDisplay()); | |
| } | |
| Error Surface::releaseRef(const Display *display) | |
| { | |
| ASSERT(mRefCount > 0); | |
| mRefCount--; | |
| if (mRefCount == 0 && mDestroyed) | |
| { | |
| ASSERT(display); | |
| return destroyImpl(display); | |
| } | |
| return NoError(); | |
| } | |
| Error Surface::onDestroy(const Display *display) | |
| { | |
| mDestroyed = true; | |
| if (mRefCount == 0) | |
| { | |
| return destroyImpl(display); | |
| } | |
| return NoError(); | |
| } | |
| void Surface::setLabel(EGLLabelKHR label) | |
| { | |
| mState.label = label; | |
| } | |
| EGLLabelKHR Surface::getLabel() const | |
| { | |
| return mState.label; | |
| } | |
| EGLint Surface::getType() const | |
| { | |
| return mType; | |
| } | |
| Error Surface::prepareSwap(const gl::Context *context) | |
| { | |
| ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::prepareSwap"); | |
| return mImplementation->prepareSwap(context); | |
| } | |
| Error Surface::swap(const gl::Context *context) | |
| { | |
| ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swap"); | |
| context->onPreSwap(); | |
| context->getState().getOverlay()->onSwap(); | |
| ANGLE_TRY(mImplementation->swap(context)); | |
| postSwap(context); | |
| return NoError(); | |
| } | |
| Error Surface::swapWithDamage(const gl::Context *context, const EGLint *rects, EGLint n_rects) | |
| { | |
| ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swapWithDamage"); | |
| context->onPreSwap(); | |
| context->getState().getOverlay()->onSwap(); | |
| ANGLE_TRY(mImplementation->swapWithDamage(context, rects, n_rects)); | |
| postSwap(context); | |
| return NoError(); | |
| } | |
| Error Surface::swapWithFrameToken(const gl::Context *context, EGLFrameTokenANGLE frameToken) | |
| { | |
| ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swapWithFrameToken"); | |
| context->onPreSwap(); | |
| context->getState().getOverlay()->onSwap(); | |
| ANGLE_TRY(mImplementation->swapWithFrameToken(context, frameToken)); | |
| postSwap(context); | |
| return NoError(); | |
| } | |
| Error Surface::postSubBuffer(const gl::Context *context, | |
| EGLint x, | |
| EGLint y, | |
| EGLint width, | |
| EGLint height) | |
| { | |
| if (width == 0 || height == 0) | |
| { | |
| return egl::NoError(); | |
| } | |
| context->getState().getOverlay()->onSwap(); | |
| ANGLE_TRY(mImplementation->postSubBuffer(context, x, y, width, height)); | |
| postSwap(context); | |
| return NoError(); | |
| } | |
| Error Surface::setPresentationTime(EGLnsecsANDROID time) | |
| { | |
| return mImplementation->setPresentationTime(time); | |
| } | |
| Error Surface::querySurfacePointerANGLE(EGLint attribute, void **value) | |
| { | |
| return mImplementation->querySurfacePointerANGLE(attribute, value); | |
| } | |
| EGLint Surface::isPostSubBufferSupported() const | |
| { | |
| return mPostSubBufferRequested && mImplementation->isPostSubBufferSupported(); | |
| } | |
| void Surface::setSwapInterval(EGLint interval) | |
| { | |
| mImplementation->setSwapInterval(interval); | |
| } | |
| void Surface::setMipmapLevel(EGLint level) | |
| { | |
| // Level is set but ignored | |
| UNIMPLEMENTED(); | |
| mMipmapLevel = level; | |
| } | |
| void Surface::setMultisampleResolve(EGLenum resolve) | |
| { | |
| // Behaviour is set but ignored | |
| UNIMPLEMENTED(); | |
| mMultisampleResolve = resolve; | |
| } | |
| void Surface::setSwapBehavior(EGLenum behavior) | |
| { | |
| // Behaviour is set but ignored | |
| UNIMPLEMENTED(); | |
| mState.swapBehavior = behavior; | |
| } | |
| void Surface::setFixedWidth(EGLint width) | |
| { | |
| mFixedWidth = width; | |
| mImplementation->setFixedWidth(width); | |
| } | |
| void Surface::setFixedHeight(EGLint height) | |
| { | |
| mFixedHeight = height; | |
| mImplementation->setFixedHeight(height); | |
| } | |
| const Config *Surface::getConfig() const | |
| { | |
| return mState.config; | |
| } | |
| EGLint Surface::getPixelAspectRatio() const | |
| { | |
| return mPixelAspectRatio; | |
| } | |
| EGLenum Surface::getRenderBuffer() const | |
| { | |
| return mRenderBuffer; | |
| } | |
| EGLenum Surface::getSwapBehavior() const | |
| { | |
| return mState.swapBehavior; | |
| } | |
| TextureFormat Surface::getTextureFormat() const | |
| { | |
| return mTextureFormat; | |
| } | |
| EGLenum Surface::getTextureTarget() const | |
| { | |
| return mTextureTarget; | |
| } | |
| bool Surface::getLargestPbuffer() const | |
| { | |
| return mLargestPbuffer; | |
| } | |
| EGLenum Surface::getGLColorspace() const | |
| { | |
| return mGLColorspace; | |
| } | |
| EGLenum Surface::getVGAlphaFormat() const | |
| { | |
| return mVGAlphaFormat; | |
| } | |
| EGLenum Surface::getVGColorspace() const | |
| { | |
| return mVGColorspace; | |
| } | |
| bool Surface::getMipmapTexture() const | |
| { | |
| return mMipmapTexture; | |
| } | |
| EGLint Surface::getMipmapLevel() const | |
| { | |
| return mMipmapLevel; | |
| } | |
| EGLint Surface::getHorizontalResolution() const | |
| { | |
| return mHorizontalResolution; | |
| } | |
| EGLint Surface::getVerticalResolution() const | |
| { | |
| return mVerticalResolution; | |
| } | |
| EGLenum Surface::getMultisampleResolve() const | |
| { | |
| return mMultisampleResolve; | |
| } | |
| EGLint Surface::isFixedSize() const | |
| { | |
| return mFixedSize; | |
| } | |
| EGLint Surface::getWidth() const | |
| { | |
| return mFixedSize ? static_cast<EGLint>(mFixedWidth) : mImplementation->getWidth(); | |
| } | |
| EGLint Surface::getHeight() const | |
| { | |
| return mFixedSize ? static_cast<EGLint>(mFixedHeight) : mImplementation->getHeight(); | |
| } | |
| egl::Error Surface::getUserWidth(const egl::Display *display, EGLint *value) const | |
| { | |
| if (mFixedSize) | |
| { | |
| *value = static_cast<EGLint>(mFixedWidth); | |
| return NoError(); | |
| } | |
| else | |
| { | |
| return mImplementation->getUserWidth(display, value); | |
| } | |
| } | |
| egl::Error Surface::getUserHeight(const egl::Display *display, EGLint *value) const | |
| { | |
| if (mFixedSize) | |
| { | |
| *value = static_cast<EGLint>(mFixedHeight); | |
| return NoError(); | |
| } | |
| else | |
| { | |
| return mImplementation->getUserHeight(display, value); | |
| } | |
| } | |
| Error Surface::bindTexImage(gl::Context *context, gl::Texture *texture, EGLint buffer) | |
| { | |
| ASSERT(!mTexture); | |
| ANGLE_TRY(mImplementation->bindTexImage(context, texture, buffer)); | |
| if (texture->bindTexImageFromSurface(context, this) == angle::Result::Stop) | |
| { | |
| return Error(EGL_BAD_SURFACE); | |
| } | |
| mTexture = texture; | |
| addRef(); | |
| return NoError(); | |
| } | |
| Error Surface::releaseTexImage(const gl::Context *context, EGLint buffer) | |
| { | |
| ASSERT(context); | |
| ANGLE_TRY(mImplementation->releaseTexImage(context, buffer)); | |
| ASSERT(mTexture); | |
| ANGLE_TRY(ResultToEGL(mTexture->releaseTexImageFromSurface(context))); | |
| return releaseTexImageFromTexture(context); | |
| } | |
| Error Surface::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) | |
| { | |
| return mImplementation->getSyncValues(ust, msc, sbc); | |
| } | |
| Error Surface::getMscRate(EGLint *numerator, EGLint *denominator) | |
| { | |
| return mImplementation->getMscRate(numerator, denominator); | |
| } | |
| Error Surface::releaseTexImageFromTexture(const gl::Context *context) | |
| { | |
| ASSERT(mTexture); | |
| mTexture = nullptr; | |
| return releaseRef(context->getDisplay()); | |
| } | |
| gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const | |
| { | |
| return gl::Extents(getWidth(), getHeight(), 1); | |
| } | |
| gl::Format Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const | |
| { | |
| return (binding == GL_BACK ? mColorFormat : mDSFormat); | |
| } | |
| GLsizei Surface::getAttachmentSamples(const gl::ImageIndex &target) const | |
| { | |
| return getConfig()->samples; | |
| } | |
| bool Surface::isRenderable(const gl::Context *context, | |
| GLenum binding, | |
| const gl::ImageIndex &imageIndex) const | |
| { | |
| return true; | |
| } | |
| bool Surface::isYUV() const | |
| { | |
| // EGL_EXT_yuv_surface is not implemented. | |
| return false; | |
| } | |
| bool Surface::isCreatedWithAHB() const | |
| { | |
| return false; | |
| } | |
| GLuint Surface::getId() const | |
| { | |
| return mSerialId; | |
| } | |
| Error Surface::getBufferAgeImpl(const gl::Context *context, EGLint *age) const | |
| { | |
| // When EGL_BUFFER_PRESERVED, the previous frame contents are copied to | |
| // current frame, so the buffer age is always 1. | |
| if (mState.swapBehavior == EGL_BUFFER_PRESERVED) | |
| { | |
| if (age != nullptr) | |
| { | |
| *age = 1; | |
| } | |
| return egl::NoError(); | |
| } | |
| return mImplementation->getBufferAge(context, age); | |
| } | |
| Error Surface::getBufferAge(const gl::Context *context, EGLint *age) | |
| { | |
| Error err = getBufferAgeImpl(context, age); | |
| if (!err.isError()) | |
| { | |
| mBufferAgeQueriedSinceLastSwap = true; | |
| } | |
| return err; | |
| } | |
| gl::InitState Surface::initState(GLenum binding, const gl::ImageIndex & /*imageIndex*/) const | |
| { | |
| switch (binding) | |
| { | |
| case GL_BACK: | |
| return mColorInitState; | |
| case GL_DEPTH: | |
| case GL_STENCIL: | |
| return mDepthStencilInitState; | |
| default: | |
| UNREACHABLE(); | |
| return gl::InitState::Initialized; | |
| } | |
| } | |
| void Surface::setInitState(GLenum binding, | |
| const gl::ImageIndex & /*imageIndex*/, | |
| gl::InitState initState) | |
| { | |
| switch (binding) | |
| { | |
| case GL_BACK: | |
| mColorInitState = initState; | |
| break; | |
| case GL_DEPTH: | |
| case GL_STENCIL: | |
| mDepthStencilInitState = initState; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| } | |
| void Surface::setTimestampsEnabled(bool enabled) | |
| { | |
| mImplementation->setTimestampsEnabled(enabled); | |
| mState.timestampsEnabled = enabled; | |
| } | |
| bool Surface::isTimestampsEnabled() const | |
| { | |
| return mState.timestampsEnabled; | |
| } | |
| Error Surface::setAutoRefreshEnabled(bool enabled) | |
| { | |
| ANGLE_TRY(mImplementation->setAutoRefreshEnabled(enabled)); | |
| mState.autoRefreshEnabled = enabled; | |
| return NoError(); | |
| } | |
| bool Surface::hasProtectedContent() const | |
| { | |
| return mState.hasProtectedContent(); | |
| } | |
| const SupportedCompositorTiming &Surface::getSupportedCompositorTimings() const | |
| { | |
| return mState.supportedCompositorTimings; | |
| } | |
| Error Surface::getCompositorTiming(EGLint numTimestamps, | |
| const EGLint *names, | |
| EGLnsecsANDROID *values) const | |
| { | |
| return mImplementation->getCompositorTiming(numTimestamps, names, values); | |
| } | |
| Error Surface::getNextFrameId(EGLuint64KHR *frameId) const | |
| { | |
| return mImplementation->getNextFrameId(frameId); | |
| } | |
| const SupportedTimestamps &Surface::getSupportedTimestamps() const | |
| { | |
| return mState.supportedTimestamps; | |
| } | |
| Error Surface::getFrameTimestamps(EGLuint64KHR frameId, | |
| EGLint numTimestamps, | |
| const EGLint *timestamps, | |
| EGLnsecsANDROID *values) const | |
| { | |
| return mImplementation->getFrameTimestamps(frameId, numTimestamps, timestamps, values); | |
| } | |
| void Surface::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) | |
| { | |
| ASSERT(index == kSurfaceImplSubjectIndex); | |
| switch (message) | |
| { | |
| case angle::SubjectMessage::SubjectChanged: | |
| onStateChange(angle::SubjectMessage::ContentsChanged); | |
| break; | |
| case angle::SubjectMessage::SurfaceChanged: | |
| onStateChange(angle::SubjectMessage::SurfaceChanged); | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| } | |
| Error Surface::setRenderBuffer(EGLint renderBuffer) | |
| { | |
| ANGLE_TRY(mImplementation->setRenderBuffer(renderBuffer)); | |
| mRenderBuffer = renderBuffer; | |
| return NoError(); | |
| } | |
| bool Surface::isLocked() const | |
| { | |
| return (mLockBufferPtr != nullptr); | |
| } | |
| EGLint Surface::getBitmapPitch() const | |
| { | |
| return mLockBufferPitch; | |
| } | |
| EGLint Surface::getBitmapOrigin() const | |
| { | |
| return mImplementation->origin(); | |
| } | |
| EGLint Surface::getRedOffset() const | |
| { | |
| const gl::InternalFormat &format = *mColorFormat.info; | |
| if (gl::IsBGRAFormat(format.internalFormat)) | |
| { | |
| return format.blueBits + format.greenBits; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| EGLint Surface::getGreenOffset() const | |
| { | |
| const gl::InternalFormat &format = *mColorFormat.info; | |
| if (gl::IsBGRAFormat(format.internalFormat)) | |
| { | |
| return format.blueBits; | |
| } | |
| else | |
| { | |
| return format.redBits; | |
| } | |
| } | |
| EGLint Surface::getBlueOffset() const | |
| { | |
| const gl::InternalFormat &format = *mColorFormat.info; | |
| if (gl::IsBGRAFormat(format.internalFormat)) | |
| { | |
| return 0; | |
| } | |
| else | |
| { | |
| return format.redBits + format.greenBits; | |
| } | |
| } | |
| EGLint Surface::getAlphaOffset() const | |
| { | |
| const gl::InternalFormat &format = *mColorFormat.info; | |
| if (format.isLUMA()) | |
| { | |
| return format.luminanceBits; // Luma always first, alpha optional | |
| } | |
| // For RGBA/BGRA alpha is last | |
| return format.blueBits + format.greenBits + format.redBits; | |
| } | |
| EGLint Surface::getLuminanceOffset() const | |
| { | |
| return 0; | |
| } | |
| EGLint Surface::getBitmapPixelSize() const | |
| { | |
| constexpr EGLint kBitsPerByte = 8; | |
| const gl::InternalFormat &format = *mColorFormat.info; | |
| return (format.pixelBytes * kBitsPerByte); | |
| } | |
| EGLAttribKHR Surface::getBitmapPointer() const | |
| { | |
| return static_cast<EGLAttribKHR>((intptr_t)mLockBufferPtr); | |
| } | |
| egl::Error Surface::lockSurfaceKHR(const egl::Display *display, const AttributeMap &attributes) | |
| { | |
| EGLint lockBufferUsageHint = attributes.getAsInt( | |
| EGL_LOCK_USAGE_HINT_KHR, (EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR)); | |
| bool preservePixels = ((attributes.getAsInt(EGL_MAP_PRESERVE_PIXELS_KHR, false) == EGL_TRUE) || | |
| (mState.swapBehavior == EGL_BUFFER_PRESERVED)); | |
| return mImplementation->lockSurface(display, lockBufferUsageHint, preservePixels, | |
| &mLockBufferPtr, &mLockBufferPitch); | |
| } | |
| egl::Error Surface::unlockSurfaceKHR(const egl::Display *display) | |
| { | |
| mLockBufferPtr = nullptr; | |
| mLockBufferPitch = 0; | |
| return mImplementation->unlockSurface(display, true); | |
| } | |
| WindowSurface::WindowSurface(rx::EGLImplFactory *implFactory, | |
| const egl::Config *config, | |
| EGLNativeWindowType window, | |
| const AttributeMap &attribs, | |
| bool robustResourceInit) | |
| : Surface(EGL_WINDOW_BIT, implFactory->getNextSurfaceID(), config, attribs, robustResourceInit) | |
| { | |
| mImplementation = implFactory->createWindowSurface(mState, window, attribs); | |
| } | |
| void Surface::setDamageRegion(const EGLint *rects, EGLint n_rects) | |
| { | |
| mIsDamageRegionSet = true; | |
| } | |
| WindowSurface::~WindowSurface() {} | |
| PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, | |
| const Config *config, | |
| const AttributeMap &attribs, | |
| bool robustResourceInit) | |
| : Surface(EGL_PBUFFER_BIT, implFactory->getNextSurfaceID(), config, attribs, robustResourceInit) | |
| { | |
| mImplementation = implFactory->createPbufferSurface(mState, attribs); | |
| } | |
| PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, | |
| const Config *config, | |
| EGLenum buftype, | |
| EGLClientBuffer clientBuffer, | |
| const AttributeMap &attribs, | |
| bool robustResourceInit) | |
| : Surface(EGL_PBUFFER_BIT, | |
| implFactory->getNextSurfaceID(), | |
| config, | |
| attribs, | |
| robustResourceInit, | |
| buftype) | |
| { | |
| mImplementation = | |
| implFactory->createPbufferFromClientBuffer(mState, buftype, clientBuffer, attribs); | |
| } | |
| PbufferSurface::~PbufferSurface() {} | |
| PixmapSurface::PixmapSurface(rx::EGLImplFactory *implFactory, | |
| const Config *config, | |
| NativePixmapType nativePixmap, | |
| const AttributeMap &attribs, | |
| bool robustResourceInit) | |
| : Surface(EGL_PIXMAP_BIT, implFactory->getNextSurfaceID(), config, attribs, robustResourceInit) | |
| { | |
| mImplementation = implFactory->createPixmapSurface(mState, nativePixmap, attribs); | |
| } | |
| PixmapSurface::~PixmapSurface() {} | |
| // SurfaceDeleter implementation. | |
| SurfaceDeleter::SurfaceDeleter(const Display *display) : mDisplay(display) {} | |
| SurfaceDeleter::~SurfaceDeleter() {} | |
| void SurfaceDeleter::operator()(Surface *surface) | |
| { | |
| ANGLE_SWALLOW_ERR(surface->onDestroy(mDisplay)); | |
| } | |
| } // namespace egl |