Files
tubestation/gfx/webrender_bindings/RenderEGLImageTextureHost.cpp
Jamie Nicol dc6e889fb4 Bug 1731980 - Ensure SurfaceTextures with transforms get rendered at correct size. r=gfx-reviewers,lsalzman
On Android we use SurfaceTextures to render content from sources such
as the video decoder. These may have a transform set which is supposed
to be applied to the texture coordinates used to sample the
texture. Webrender (and software webrender), however, do not handle
this correctly, meaning videos may be rendered at the incorrect size
on some devices.

SurfaceTextures should always be rendered with their bottom-left being
their origin, eg vertically flipped. Additionally, the texture
transform returned on most devices seems to be a simple y-flip
transform with no scaling. Webrender currently just ignores the y-flip
due to the texture origin, which cancels out us not handling the
y-flip from the transform, meaning video looks correct on most
devices. Some devices, however, do return a scaling transform which we
must handle.

This patch removes the override of WebRenderTextureHost::NeedsYFlip()
that was causing us to ignore the y-flip due to the texture origin -
since we will now apply the transform we must handle this correctly
too.

It adds a virtual method RenderTextureHost::GetUvCoords(), that
returns the texture coordinates that should be used by webrender to
sample from external textures. In most cases these are simply (0, 0)
and (size.x, size.y), but in RenderAndroidSurfaceTextureHost we
override this function to apply the transformation. This ensures we
use the correct coordinates whenever the texture is rendered by
webrender, eg in both software and hardware webrender when rendering
in the non-compositing-path, and by hardware webrender's draw
compositor. Additionally, the composite.glsl shader requires a fix to
calculate the UV bounds correctly, as the coordinates may now be
inverted.

Lastly, we fix software webrender with the OpenGL
compositor. CompositorOGL already has the required functionality to
apply the texture transformation as it was used back in the layers
days. We must simply ensure that we pass the value of the
mIgnoreTransform flag from the original SurfaceTextureHost, through to
the RenderAndroidSurfaceTextureHost, and finally to the
SurfaceTextureSource which we hand to CompositorOGL.

Differential Revision: https://phabricator.services.mozilla.com/D144306
2022-04-25 16:47:51 +00:00

104 lines
3.4 KiB
C++

/* -*- 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RenderEGLImageTextureHost.h"
#include "mozilla/gfx/Logging.h"
#include "GLContextEGL.h"
#include "GLLibraryEGL.h"
namespace mozilla {
namespace wr {
RenderEGLImageTextureHost::RenderEGLImageTextureHost(EGLImage aImage,
EGLSync aSync,
gfx::IntSize aSize)
: mImage(aImage),
mSync(aSync),
mSize(aSize),
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, wr::ImageRendering aRendering) {
MOZ_ASSERT(aChannelIndex == 0);
if (mGL.get() != aGL) {
if (mGL) {
// This should not happen. SharedSurface_EGLImage is created only in
// parent process.
MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
return InvalidToWrExternalImage();
}
mGL = aGL;
}
if (!mImage || !mGL || !mGL->MakeCurrent()) {
return InvalidToWrExternalImage();
}
EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
if (mSync) {
const auto& gle = gl::GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
MOZ_ASSERT(egl->IsExtensionSupported(gl::EGLExtension::KHR_fence_sync));
status = egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER);
// We do not need to delete sync here. It is deleted by
// SharedSurface_EGLImage.
mSync = 0;
}
if (status != LOCAL_EGL_CONDITION_SATISFIED) {
MOZ_ASSERT(
status != 0,
"ClientWaitSync generated an error. Has mSync already been destroyed?");
return InvalidToWrExternalImage();
}
if (!mTextureHandle) {
mTextureTarget = mGL->GetPreferredEGLImageTextureTarget();
MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
mGL->fGenTextures(1, &mTextureHandle);
// Cache rendering filter.
mCachedRendering = aRendering;
ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, mTextureTarget,
mTextureHandle, aRendering);
mGL->fEGLImageTargetTexture2D(mTextureTarget, mImage);
} else if (IsFilterUpdateNecessary(aRendering)) {
// Cache new rendering filter.
mCachedRendering = aRendering;
ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, mTextureTarget,
mTextureHandle, aRendering);
}
const auto uvs = GetUvCoords(mSize);
return NativeTextureToWrExternalImage(
mTextureHandle, uvs.first.x, uvs.first.y, uvs.second.x, uvs.second.y);
}
void RenderEGLImageTextureHost::Unlock() {}
void RenderEGLImageTextureHost::DeleteTextureHandle() {
if (mTextureHandle) {
// XXX recycle gl texture, since SharedSurface_EGLImage and
// RenderEGLImageTextureHost is not recycled.
mGL->fDeleteTextures(1, &mTextureHandle);
mTextureHandle = 0;
}
}
} // namespace wr
} // namespace mozilla