| // |
| // 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), |
| 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, |
| 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), |
| mInitState(gl::InitState::Initialized), |
| mImplObserverBinding(this, kSurfaceImplSubjectIndex) |
| { |
| 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; |
| } |
| |
| 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) |
| { |
| mInitState = 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) |
| { |
| mInitState = gl::InitState::MayNeedInit; |
| onStateChange(angle::SubjectMessage::SubjectChanged); |
| } |
| } |
| |
| 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; |
| mRefCount++; |
| 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::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; |
| mRefCount++; |
| |
| 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; |
| } |
| |
| GLuint Surface::getId() const |
| { |
| UNREACHABLE(); |
| return 0; |
| } |
| |
| Error Surface::getBufferAge(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); |
| } |
| |
| gl::Framebuffer *Surface::createDefaultFramebuffer(const gl::Context *context, |
| egl::Surface *readSurface) |
| { |
| return new gl::Framebuffer(context, this, readSurface); |
| } |
| |
| gl::InitState Surface::initState(const gl::ImageIndex & /*imageIndex*/) const |
| { |
| return mInitState; |
| } |
| |
| void Surface::setInitState(const gl::ImageIndex & /*imageIndex*/, gl::InitState initState) |
| { |
| mInitState = initState; |
| } |
| |
| void Surface::setTimestampsEnabled(bool enabled) |
| { |
| mImplementation->setTimestampsEnabled(enabled); |
| mState.timestampsEnabled = enabled; |
| } |
| |
| bool Surface::isTimestampsEnabled() const |
| { |
| return mState.timestampsEnabled; |
| } |
| |
| 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, config, attribs, robustResourceInit) |
| { |
| mImplementation = implFactory->createWindowSurface(mState, window, attribs); |
| } |
| |
| WindowSurface::~WindowSurface() {} |
| |
| PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, |
| const Config *config, |
| const AttributeMap &attribs, |
| bool robustResourceInit) |
| : Surface(EGL_PBUFFER_BIT, 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, 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, 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 |