summaryrefslogtreecommitdiffstats
path: root/gfx/gl/TextureImageEGL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl/TextureImageEGL.cpp')
-rw-r--r--gfx/gl/TextureImageEGL.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/gfx/gl/TextureImageEGL.cpp b/gfx/gl/TextureImageEGL.cpp
new file mode 100644
index 0000000000..539c7fda73
--- /dev/null
+++ b/gfx/gl/TextureImageEGL.cpp
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextureImageEGL.h"
+#include "GLLibraryEGL.h"
+#include "GLContext.h"
+#include "GLContextEGL.h"
+#include "GLUploadHelpers.h"
+#include "gfxPlatform.h"
+#include "mozilla/gfx/Types.h"
+
+namespace mozilla {
+namespace gl {
+
+static GLenum GLFormatForImage(gfx::SurfaceFormat aFormat) {
+ switch (aFormat) {
+ case gfx::SurfaceFormat::B8G8R8A8:
+ case gfx::SurfaceFormat::B8G8R8X8:
+ return LOCAL_GL_RGBA;
+ case gfx::SurfaceFormat::R5G6B5_UINT16:
+ return LOCAL_GL_RGB;
+ case gfx::SurfaceFormat::A8:
+ return LOCAL_GL_LUMINANCE;
+ default:
+ NS_WARNING("Unknown GL format for Surface format");
+ }
+ return 0;
+}
+
+static GLenum GLTypeForImage(gfx::SurfaceFormat aFormat) {
+ switch (aFormat) {
+ case gfx::SurfaceFormat::B8G8R8A8:
+ case gfx::SurfaceFormat::B8G8R8X8:
+ case gfx::SurfaceFormat::A8:
+ return LOCAL_GL_UNSIGNED_BYTE;
+ case gfx::SurfaceFormat::R5G6B5_UINT16:
+ return LOCAL_GL_UNSIGNED_SHORT_5_6_5;
+ default:
+ NS_WARNING("Unknown GL format for Surface format");
+ }
+ return 0;
+}
+
+TextureImageEGL::TextureImageEGL(GLuint aTexture, const gfx::IntSize& aSize,
+ GLenum aWrapMode, ContentType aContentType,
+ GLContext* aContext, Flags aFlags,
+ TextureState aTextureState,
+ TextureImage::ImageFormat aImageFormat)
+ : TextureImage(aSize, aWrapMode, aContentType, aFlags),
+ mGLContext(aContext),
+ mUpdateFormat(gfx::ImageFormatToSurfaceFormat(aImageFormat)),
+ mEGLImage(nullptr),
+ mTexture(aTexture),
+ mSurface(nullptr),
+ mConfig(nullptr),
+ mTextureState(aTextureState),
+ mBound(false) {
+ if (mUpdateFormat == gfx::SurfaceFormat::UNKNOWN) {
+ mUpdateFormat =
+ gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());
+ }
+
+ if (mUpdateFormat == gfx::SurfaceFormat::R5G6B5_UINT16) {
+ mTextureFormat = gfx::SurfaceFormat::R8G8B8X8;
+ } else if (mUpdateFormat == gfx::SurfaceFormat::B8G8R8X8) {
+ mTextureFormat = gfx::SurfaceFormat::B8G8R8X8;
+ } else {
+ mTextureFormat = gfx::SurfaceFormat::B8G8R8A8;
+ }
+}
+
+TextureImageEGL::~TextureImageEGL() {
+ if (mGLContext->IsDestroyed() || !mGLContext->IsOwningThreadCurrent()) {
+ return;
+ }
+
+ // If we have a context, then we need to delete the texture;
+ // if we don't have a context (either real or shared),
+ // then they went away when the contex was deleted, because it
+ // was the only one that had access to it.
+ if (mGLContext->MakeCurrent()) {
+ mGLContext->fDeleteTextures(1, &mTexture);
+ }
+ ReleaseTexImage();
+ DestroyEGLSurface();
+}
+
+bool TextureImageEGL::DirectUpdate(
+ gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion,
+ const gfx::IntPoint& aFrom /* = gfx::IntPoint(0,0) */) {
+ gfx::IntRect bounds = aRegion.GetBounds();
+
+ nsIntRegion region;
+ if (mTextureState != Valid) {
+ bounds = gfx::IntRect(0, 0, mSize.width, mSize.height);
+ region = nsIntRegion(bounds);
+ } else {
+ region = aRegion;
+ }
+
+ bool needInit = mTextureState == Created;
+ size_t uploadSize = 0;
+ mTextureFormat = UploadSurfaceToTexture(mGLContext, aSurf, region, mTexture,
+ mSize, &uploadSize, needInit, aFrom);
+ if (mTextureFormat == gfx::SurfaceFormat::UNKNOWN) {
+ return false;
+ }
+
+ if (uploadSize > 0) {
+ UpdateUploadSize(uploadSize);
+ }
+
+ mTextureState = Valid;
+ return true;
+}
+
+void TextureImageEGL::BindTexture(GLenum aTextureUnit) {
+ // Ensure the texture is allocated before it is used.
+ if (mTextureState == Created) {
+ Resize(mSize);
+ }
+
+ mGLContext->fActiveTexture(aTextureUnit);
+ mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+ mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+}
+
+void TextureImageEGL::Resize(const gfx::IntSize& aSize) {
+ if (mSize == aSize && mTextureState != Created) return;
+
+ mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+ mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
+ GLFormatForImage(mUpdateFormat), aSize.width,
+ aSize.height, 0, GLFormatForImage(mUpdateFormat),
+ GLTypeForImage(mUpdateFormat), nullptr);
+
+ mTextureState = Allocated;
+ mSize = aSize;
+}
+
+bool TextureImageEGL::BindTexImage() {
+ if (mBound && !ReleaseTexImage()) return false;
+
+ const auto& gle = GLContextEGL::Cast(mGLContext);
+ const auto& egl = gle->mEgl;
+ EGLBoolean success =
+ egl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
+
+ if (success == LOCAL_EGL_FALSE) return false;
+
+ mBound = true;
+ return true;
+}
+
+bool TextureImageEGL::ReleaseTexImage() {
+ if (!mBound) return true;
+
+ const auto& gle = GLContextEGL::Cast(mGLContext);
+ const auto& egl = gle->mEgl;
+ EGLBoolean success =
+ egl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
+
+ if (success == LOCAL_EGL_FALSE) return false;
+
+ mBound = false;
+ return true;
+}
+
+void TextureImageEGL::DestroyEGLSurface(void) {
+ if (!mSurface) return;
+
+ const auto& gle = GLContextEGL::Cast(mGLContext);
+ const auto& egl = gle->mEgl;
+ egl->fDestroySurface(mSurface);
+ mSurface = nullptr;
+}
+
+already_AddRefed<TextureImage> CreateTextureImageEGL(
+ GLContext* gl, const gfx::IntSize& aSize,
+ TextureImage::ContentType aContentType, GLenum aWrapMode,
+ TextureImage::Flags aFlags, TextureImage::ImageFormat aImageFormat) {
+ RefPtr<TextureImage> t =
+ new gl::TiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat);
+ return t.forget();
+}
+
+already_AddRefed<TextureImage> TileGenFuncEGL(
+ GLContext* gl, const gfx::IntSize& aSize,
+ TextureImage::ContentType aContentType, TextureImage::Flags aFlags,
+ TextureImage::ImageFormat aImageFormat) {
+ gl->MakeCurrent();
+
+ GLuint texture;
+ gl->fGenTextures(1, &texture);
+
+ RefPtr<TextureImageEGL> teximage =
+ new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
+ gl, aFlags, TextureImage::Created, aImageFormat);
+
+ teximage->BindTexture(LOCAL_GL_TEXTURE0);
+
+ GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST
+ : LOCAL_GL_LINEAR;
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
+ texfilter);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
+ texfilter);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
+ LOCAL_GL_CLAMP_TO_EDGE);
+
+ return teximage.forget();
+}
+
+} // namespace gl
+} // namespace mozilla