blob: 231dab6d5956dcc40d27157e5edcef89b0189c9e [file] [log] [blame]
//
// 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 <EGL/eglext.h>
#include <iostream>
#include "libANGLE/Config.h"
#include "libANGLE/Display.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/EGLImplFactory.h"
namespace egl
{
SurfaceState::SurfaceState(const egl::Config *configIn)
: defaultFramebuffer(nullptr), config(configIn)
{
}
Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes)
: FramebufferAttachmentObject(),
mState(config),
mImplementation(nullptr),
mCurrentCount(0),
mDestroyed(false),
mType(surfaceType),
mPostSubBufferRequested(false),
mFixedSize(false),
mFixedWidth(0),
mFixedHeight(0),
mTextureFormat(EGL_NO_TEXTURE),
mTextureTarget(EGL_NO_TEXTURE),
// FIXME: Determine actual pixel aspect ratio
mPixelAspectRatio(static_cast<EGLint>(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);
mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE);
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 = static_cast<EGLenum>(attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE));
mTextureTarget = static_cast<EGLenum>(attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE));
}
mOrientation = static_cast<EGLint>(attributes.get(EGL_SURFACE_ORIENTATION_ANGLE, 0));
}
Surface::~Surface()
{
if (mTexture.get())
{
if (mImplementation)
{
mImplementation->releaseTexImage(EGL_BACK_BUFFER);
}
mTexture->releaseTexImageFromSurface();
mTexture.set(nullptr);
}
SafeDelete(mState.defaultFramebuffer);
SafeDelete(mImplementation);
}
void Surface::destroy(const Display *display)
{
if (mState.defaultFramebuffer)
{
mState.defaultFramebuffer->destroyDefault(display);
}
if (mImplementation)
{
mImplementation->destroy(rx::SafeGetImpl(display));
}
delete this;
}
Error Surface::initialize(const Display &display)
{
ANGLE_TRY(mImplementation->initialize(display.getImplementation()));
// 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();
ASSERT(mState.defaultFramebuffer != nullptr);
return Error(EGL_SUCCESS);
}
void Surface::setIsCurrent(Display *display, bool isCurrent)
{
if (isCurrent)
{
mCurrentCount++;
return;
}
ASSERT(mCurrentCount > 0);
mCurrentCount--;
if (mCurrentCount == 0 && mDestroyed)
{
destroy(display);
}
}
void Surface::onDestroy(Display *display)
{
mDestroyed = true;
if (mCurrentCount == 0)
{
destroy(display);
}
}
EGLint Surface::getType() const
{
return mType;
}
Error Surface::swap(const Display &display)
{
return mImplementation->swap(display.getImplementation());
}
Error Surface::swapWithDamage(EGLint *rects, EGLint n_rects)
{
return mImplementation->swapWithDamage(rects, n_rects);
}
Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
{
return mImplementation->postSubBuffer(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);
}
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;
}
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();
}
Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer)
{
ASSERT(!mTexture.get());
ANGLE_TRY(mImplementation->bindTexImage(texture, buffer));
texture->bindTexImageFromSurface(this);
mTexture.set(texture);
return Error(EGL_SUCCESS);
}
Error Surface::releaseTexImage(EGLint buffer)
{
ANGLE_TRY(mImplementation->releaseTexImage(buffer));
ASSERT(mTexture.get());
mTexture->releaseTexImageFromSurface();
mTexture.set(nullptr);
return Error(EGL_SUCCESS);
}
Error Surface::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
{
return mImplementation->getSyncValues(ust, msc, sbc);
}
void Surface::releaseTexImageFromTexture()
{
ASSERT(mTexture.get());
mTexture.set(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()
{
return new gl::Framebuffer(this);
}
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()
{
}
} // namespace egl