Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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
#include "RenderEGLImageTextureHost.h"
#include "mozilla/gfx/Logging.h"
#include "GLContextEGL.h"
#include "GLLibraryEGL.h"
#include "GLReadTexImageHelper.h"
#include "OGLShaderConfig.h"
namespace mozilla {
namespace wr {
RenderEGLImageTextureHost::RenderEGLImageTextureHost(EGLImage aImage,
EGLSync aSync,
gfx::IntSize aSize,
gfx::SurfaceFormat aFormat)
: mImage(aImage),
mSync(aSync),
mSize(aSize),
mFormat(aFormat),
mTextureTarget(LOCAL_GL_TEXTURE_2D),
mTextureHandle(0) {
MOZ_COUNT_CTOR_INHERITED(RenderEGLImageTextureHost, RenderTextureHost);
}
RenderEGLImageTextureHost::~RenderEGLImageTextureHost() {
MOZ_COUNT_DTOR_INHERITED(RenderEGLImageTextureHost, RenderTextureHost);
DeleteTextureHandle();
}
wr::WrExternalImage RenderEGLImageTextureHost::Lock(uint8_t aChannelIndex,
gl::GLContext* aGL) {
MOZ_ASSERT(aChannelIndex == 0);
if (mGL.get() != aGL) {
if (mGL) {
// This should not happen. On android, SingletonGL is used.
MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
return InvalidToWrExternalImage();
}
mGL = aGL;
}
if (!mImage || !mGL || !mGL->MakeCurrent()) {
return InvalidToWrExternalImage();
}
if (!WaitSync() || !CreateTextureHandle()) {
return InvalidToWrExternalImage();
}
return NativeTextureToWrExternalImage(mTextureHandle, 0.0, 0.0,
static_cast<float>(mSize.width),
static_cast<float>(mSize.height));
}
void RenderEGLImageTextureHost::Unlock() {}
RefPtr<layers::TextureSource> RenderEGLImageTextureHost::CreateTextureSource(
layers::TextureSourceProvider* aProvider) {
gl::GLContext* gl = aProvider->GetGLContext();
if (mGL.get() != gl) {
if (mGL) {
// This should not happen. On android, SingletonGL is used.
MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
return nullptr;
}
mGL = gl;
}
if (!WaitSync()) {
return nullptr;
}
return new layers::EGLImageTextureSource(
aProvider, mImage, mFormat, gl->GetPreferredEGLImageTextureTarget(),
LOCAL_GL_CLAMP_TO_EDGE, mSize);
}
gfx::SurfaceFormat RenderEGLImageTextureHost::GetFormat() const {
MOZ_ASSERT(mFormat == gfx::SurfaceFormat::R8G8B8A8 ||
mFormat == gfx::SurfaceFormat::R8G8B8X8);
// SWGL does not support RGBA/RGBX so we must provide data in BGRA/BGRX
// format. ReadTexImage() called by MapPlane() will ensure that data gets
// converted correctly.
if (mFormat == gfx::SurfaceFormat::R8G8B8A8) {
return gfx::SurfaceFormat::B8G8R8A8;
}
if (mFormat == gfx::SurfaceFormat::R8G8B8X8) {
return gfx::SurfaceFormat::B8G8R8X8;
}
gfxCriticalNoteOnce << "Unexpected color format of RenderEGLImageTextureHost";
return gfx::SurfaceFormat::UNKNOWN;
}
bool RenderEGLImageTextureHost::MapPlane(RenderCompositor* aCompositor,
uint8_t aChannelIndex,
PlaneInfo& aPlaneInfo) {
RefPtr<gfx::DataSourceSurface> readback = ReadTexImage();
if (!readback) {
return false;
}
gfx::DataSourceSurface::MappedSurface map;
if (!readback->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
return false;
}
mReadback = readback;
aPlaneInfo.mSize = mSize;
aPlaneInfo.mStride = map.mStride;
aPlaneInfo.mData = map.mData;
return true;
}
void RenderEGLImageTextureHost::UnmapPlanes() {
if (mReadback) {
mReadback->Unmap();
mReadback = nullptr;
}
}
bool RenderEGLImageTextureHost::CreateTextureHandle() {
if (mTextureHandle) {
return true;
}
mTextureTarget = mGL->GetPreferredEGLImageTextureTarget();
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
mGL->fGenTextures(1, &mTextureHandle);
ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, mTextureTarget,
mTextureHandle);
mGL->fEGLImageTargetTexture2D(mTextureTarget, mImage);
return true;
}
void RenderEGLImageTextureHost::DeleteTextureHandle() {
if (mTextureHandle) {
if (mGL && mGL->MakeCurrent()) {
// XXX recycle gl texture, since SharedSurface_EGLImage and
// RenderEGLImageTextureHost is not recycled.
mGL->fDeleteTextures(1, &mTextureHandle);
}
mTextureHandle = 0;
}
}
bool RenderEGLImageTextureHost::WaitSync() {
bool syncSucceeded = true;
if (mSync) {
const auto& gle = gl::GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
MOZ_ASSERT(egl->IsExtensionSupported(gl::EGLExtension::KHR_fence_sync));
if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) {
syncSucceeded = egl->fWaitSync(mSync, 0) == LOCAL_EGL_TRUE;
} else {
syncSucceeded = egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER) ==
LOCAL_EGL_CONDITION_SATISFIED;
}
// We do not need to delete sync here. It is deleted by
// SharedSurface_EGLImage.
mSync = 0;
}
MOZ_ASSERT(
syncSucceeded,
"(Client)WaitSync generated an error. Has mSync already been destroyed?");
return syncSucceeded;
}
already_AddRefed<gfx::DataSourceSurface>
RenderEGLImageTextureHost::ReadTexImage() {
if (!mGL) {
mGL = RenderThread::Get()->SingletonGL();
if (!mGL) {
return nullptr;
}
}
if (!WaitSync() || !CreateTextureHandle()) {
return nullptr;
}
// Allocate resulting image surface.
// Use GetFormat() rather than mFormat for the DataSourceSurface. eg BGRA
// rather than RGBA, as the latter is not supported by swgl.
// ReadTexImageHelper will take care of converting the data for us.
const gfx::SurfaceFormat surfFormat = GetFormat();
int32_t stride = mSize.width * BytesPerPixel(surfFormat);
RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateDataSourceSurfaceWithStride(mSize, surfFormat,
stride);
if (!surf) {
return nullptr;
}
layers::ShaderConfigOGL config =
layers::ShaderConfigFromTargetAndFormat(mTextureTarget, mFormat);
int shaderConfig = config.mFeatures;
bool ret = mGL->ReadTexImageHelper()->ReadTexImage(
surf, mTextureHandle, mTextureTarget, mSize, gfx::Matrix4x4(),
shaderConfig, /* aYInvert */ false);
if (!ret) {
return nullptr;
}
return surf.forget();
}
} // namespace wr
} // namespace mozilla