summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/Surface.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/angle/checkout/src/libANGLE/Surface.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/Surface.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/Surface.cpp941
1 files changed, 941 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/Surface.cpp b/gfx/angle/checkout/src/libANGLE/Surface.cpp
new file mode 100644
index 0000000000..acb382dd10
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/Surface.cpp
@@ -0,0 +1,941 @@
+//
+// 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;
+ case angle::SubjectMessage::SwapchainImageChanged:
+ onStateChange(angle::SubjectMessage::SwapchainImageChanged);
+ 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