// // Copyright (c) 2002-2014 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 #include #include "libANGLE/Config.h" #include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/Texture.h" #include "libANGLE/Thread.h" #include "libANGLE/formatutils.h" #include "libANGLE/renderer/EGLImplFactory.h" namespace egl { SurfaceState::SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn) : defaultFramebuffer(nullptr), config(configIn), attributes(attributesIn) { } Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) : FramebufferAttachmentObject(), mState(config, attributes), mImplementation(nullptr), mCurrentCount(0), mDestroyed(false), mType(surfaceType), 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(EGL_NO_TEXTURE), mTextureTarget(EGL_NO_TEXTURE), // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio(static_cast(1.0 * EGL_DISPLAY_SCALING)), mRenderBuffer(EGL_BACK_BUFFER), mSwapBehavior(EGL_NONE), mOrientation(0), mTexture(), mBackFormat(config->renderTargetFormat), mDSFormat(config->depthStencilFormat) { mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); mFlexibleSurfaceCompatibilityRequested = (attributes.get(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_FALSE) == EGL_TRUE); if (mType == EGL_PBUFFER_BIT) { mLargestPbuffer = (attributes.get(EGL_LARGEST_PBUFFER, EGL_FALSE) == EGL_TRUE); } mGLColorspace = static_cast(attributes.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_LINEAR)); mVGAlphaFormat = static_cast(attributes.get(EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_NONPRE)); mVGColorspace = static_cast(attributes.get(EGL_VG_COLORSPACE, EGL_VG_COLORSPACE_sRGB)); mMipmapTexture = (attributes.get(EGL_MIPMAP_TEXTURE, EGL_FALSE) == EGL_TRUE); mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE); mRobustResourceInitialization = (attributes.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE); mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); if (mFixedSize) { mFixedWidth = static_cast(attributes.get(EGL_WIDTH, 0)); mFixedHeight = static_cast(attributes.get(EGL_HEIGHT, 0)); } if (mType != EGL_WINDOW_BIT) { mTextureFormat = static_cast(attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE)); mTextureTarget = static_cast(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE)); } mOrientation = static_cast(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0)); } Surface::~Surface() { } rx::FramebufferAttachmentObjectImpl *Surface::getAttachmentImpl() const { return mImplementation; } Error Surface::destroyImpl(const Display *display) { if (mState.defaultFramebuffer) { mState.defaultFramebuffer->destroyDefault(display); } if (mImplementation) { mImplementation->destroy(display); } if (mTexture.get()) { if (mImplementation) { ANGLE_TRY(mImplementation->releaseTexImage(EGL_BACK_BUFFER)); } auto glErr = mTexture->releaseTexImageFromSurface(display->getProxyContext()); if (glErr.isError()) { return Error(EGL_BAD_SURFACE); } mTexture.set(nullptr, nullptr); } if (mState.defaultFramebuffer) { mState.defaultFramebuffer->onDestroy(display->getProxyContext()); } SafeDelete(mState.defaultFramebuffer); SafeDelete(mImplementation); delete this; return NoError(); } Error Surface::initialize(const Display *display) { ANGLE_TRY(mImplementation->initialize(display)); // Initialized here since impl is nullptr in the constructor. // Must happen after implementation initialize for Android. mSwapBehavior = mImplementation->getSwapBehavior(); // Must happen after implementation initialize for OSX. mState.defaultFramebuffer = createDefaultFramebuffer(display); ASSERT(mState.defaultFramebuffer != nullptr); return NoError(); } Error Surface::setIsCurrent(const gl::Context *context, bool isCurrent) { if (isCurrent) { mCurrentCount++; return NoError(); } ASSERT(mCurrentCount > 0); mCurrentCount--; if (mCurrentCount == 0 && mDestroyed) { ASSERT(context); return destroyImpl(context->getCurrentDisplay()); } return NoError(); } Error Surface::onDestroy(const Display *display) { mDestroyed = true; if (mCurrentCount == 0) { return destroyImpl(display); } return NoError(); } EGLint Surface::getType() const { return mType; } Error Surface::swap(const gl::Context *context) { return mImplementation->swap(context); } Error Surface::swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) { return mImplementation->swapWithDamage(context, rects, n_rects); } Error Surface::postSubBuffer(const gl::Context *context, EGLint x, EGLint y, EGLint width, EGLint height) { return mImplementation->postSubBuffer(context, x, y, width, height); } 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(); mSwapBehavior = behavior; } 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 mSwapBehavior; } EGLenum 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(mFixedWidth) : mImplementation->getWidth(); } EGLint Surface::getHeight() const { return mFixedSize ? static_cast(mFixedHeight) : mImplementation->getHeight(); } Error Surface::bindTexImage(const gl::Context *context, gl::Texture *texture, EGLint buffer) { ASSERT(!mTexture.get()); ANGLE_TRY(mImplementation->bindTexImage(texture, buffer)); auto glErr = texture->bindTexImageFromSurface(context, this); if (glErr.isError()) { return Error(EGL_BAD_SURFACE); } mTexture.set(context, texture); return NoError(); } Error Surface::releaseTexImage(const gl::Context *context, EGLint buffer) { ASSERT(context); ANGLE_TRY(mImplementation->releaseTexImage(buffer)); ASSERT(mTexture.get()); auto glErr = mTexture->releaseTexImageFromSurface(context); if (glErr.isError()) { return Error(EGL_BAD_SURFACE); } mTexture.set(context, nullptr); return NoError(); } Error Surface::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) { return mImplementation->getSyncValues(ust, msc, sbc); } void Surface::releaseTexImageFromTexture(const gl::Context *context) { ASSERT(mTexture.get()); mTexture.set(context, nullptr); } gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const { return gl::Extents(getWidth(), getHeight(), 1); } const gl::Format &Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const { return (binding == GL_BACK ? mBackFormat : mDSFormat); } GLsizei Surface::getAttachmentSamples(const gl::ImageIndex &target) const { return getConfig()->samples; } GLuint Surface::getId() const { UNREACHABLE(); return 0; } gl::Framebuffer *Surface::createDefaultFramebuffer(const Display *display) { return new gl::Framebuffer(display, this); } gl::InitState Surface::initState(const gl::ImageIndex & /*imageIndex*/) const { // TODO(jmadill): Lazy surface init. return gl::InitState::Initialized; } void Surface::setInitState(const gl::ImageIndex & /*imageIndex*/, gl::InitState /*initState*/) { // No-op. } WindowSurface::WindowSurface(rx::EGLImplFactory *implFactory, const egl::Config *config, EGLNativeWindowType window, const AttributeMap &attribs) : Surface(EGL_WINDOW_BIT, config, attribs) { mImplementation = implFactory->createWindowSurface(mState, window, attribs); } WindowSurface::~WindowSurface() { } PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, const Config *config, const AttributeMap &attribs) : Surface(EGL_PBUFFER_BIT, config, attribs) { mImplementation = implFactory->createPbufferSurface(mState, attribs); } PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory, const Config *config, EGLenum buftype, EGLClientBuffer clientBuffer, const AttributeMap &attribs) : Surface(EGL_PBUFFER_BIT, config, attribs) { mImplementation = implFactory->createPbufferFromClientBuffer(mState, buftype, clientBuffer, attribs); } PbufferSurface::~PbufferSurface() { } PixmapSurface::PixmapSurface(rx::EGLImplFactory *implFactory, const Config *config, NativePixmapType nativePixmap, const AttributeMap &attribs) : Surface(EGL_PIXMAP_BIT, config, attribs) { 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