Files
tubestation/gfx/webrender_bindings/RenderTextureHostSWGL.cpp
Lee Salzman 3a5af41230 Bug 1792527 - Explicitly bind mip filter for external textures inside WebRender. r=gw
If an external image shows up multiple times while using a different image rendering
setting on each instance, we can erroneously call handler.lock() for each instance in
parallel, thus defaulting to the last image rendering setting supplied for all instances
in that batch.

To work around this, we get rid of the concept of having RenderTextureHosts maintain and
set the image rendering state, which results in a nice simplification. Then, when we go
to actually bind an external image inside WebRender, we set the image rendering state
at that point, so that regardless of how many instances of an external image are locked
simultaneously, we always use the correct image rendering setting for a batch.

Differential Revision: https://phabricator.services.mozilla.com/D158920
2022-10-10 19:23:51 +00:00

232 lines
7.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 "RenderTextureHostSWGL.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/TextureHost.h"
#include "RenderThread.h"
namespace mozilla {
namespace wr {
bool RenderTextureHostSWGL::UpdatePlanes(RenderCompositor* aCompositor) {
wr_swgl_make_current(mContext);
size_t planeCount = GetPlaneCount();
bool texInit = false;
if (mPlanes.size() < planeCount) {
mPlanes.reserve(planeCount);
while (mPlanes.size() < planeCount) {
mPlanes.push_back(PlaneInfo(wr_swgl_gen_texture(mContext)));
}
texInit = true;
}
gfx::SurfaceFormat format = GetFormat();
gfx::ColorDepth colorDepth = GetColorDepth();
for (size_t i = 0; i < planeCount; i++) {
PlaneInfo& plane = mPlanes[i];
if (!MapPlane(aCompositor, i, plane)) {
if (i > 0) {
UnmapPlanes();
}
return false;
}
GLenum internalFormat = 0;
switch (format) {
case gfx::SurfaceFormat::B8G8R8A8:
case gfx::SurfaceFormat::B8G8R8X8:
MOZ_ASSERT(colorDepth == gfx::ColorDepth::COLOR_8);
internalFormat = LOCAL_GL_RGBA8;
break;
case gfx::SurfaceFormat::YUV:
switch (colorDepth) {
case gfx::ColorDepth::COLOR_8:
internalFormat = LOCAL_GL_R8;
break;
case gfx::ColorDepth::COLOR_10:
case gfx::ColorDepth::COLOR_12:
case gfx::ColorDepth::COLOR_16:
internalFormat = LOCAL_GL_R16;
break;
}
break;
case gfx::SurfaceFormat::NV12:
switch (colorDepth) {
case gfx::ColorDepth::COLOR_8:
internalFormat = i > 0 ? LOCAL_GL_RG8 : LOCAL_GL_R8;
break;
case gfx::ColorDepth::COLOR_10:
case gfx::ColorDepth::COLOR_12:
case gfx::ColorDepth::COLOR_16:
internalFormat = i > 0 ? LOCAL_GL_RG16 : LOCAL_GL_R16;
break;
}
break;
case gfx::SurfaceFormat::P010:
MOZ_ASSERT(colorDepth == gfx::ColorDepth::COLOR_10);
internalFormat = i > 0 ? LOCAL_GL_RG16 : LOCAL_GL_R16;
break;
case gfx::SurfaceFormat::YUV422:
MOZ_ASSERT(colorDepth == gfx::ColorDepth::COLOR_8);
internalFormat = LOCAL_GL_RGB_RAW_422_APPLE;
break;
default:
MOZ_RELEASE_ASSERT(false, "Unhandled external image format");
break;
}
wr_swgl_set_texture_buffer(mContext, plane.mTexture, internalFormat,
plane.mSize.width, plane.mSize.height,
plane.mStride, plane.mData, 0, 0);
}
if (texInit) {
// Initialize the mip filters to linear by default.
for (const auto& plane : mPlanes) {
wr_swgl_set_texture_parameter(mContext, plane.mTexture,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
wr_swgl_set_texture_parameter(mContext, plane.mTexture,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
}
}
return true;
}
bool RenderTextureHostSWGL::SetContext(void* aContext) {
if (mContext != aContext) {
CleanupPlanes();
mContext = aContext;
wr_swgl_reference_context(mContext);
}
return mContext != nullptr;
}
wr::WrExternalImage RenderTextureHostSWGL::LockSWGL(
uint8_t aChannelIndex, void* aContext, RenderCompositor* aCompositor) {
if (!SetContext(aContext)) {
return InvalidToWrExternalImage();
}
if (!mLocked) {
if (!UpdatePlanes(aCompositor)) {
return InvalidToWrExternalImage();
}
mLocked = true;
}
if (aChannelIndex >= mPlanes.size()) {
return InvalidToWrExternalImage();
}
const PlaneInfo& plane = mPlanes[aChannelIndex];
const auto uvs = GetUvCoords(plane.mSize);
// Prefer native textures, unless our backend forbids it.
// If the GetUvCoords call above returned anything other than the default,
// for example if this is a RenderAndroidSurfaceTextureHost, then this won't
// be handled correctly in the RawDataToWrExternalImage path. But we shouldn't
// hit this path in practice with a RenderAndroidSurfaceTextureHost.
layers::TextureHost::NativeTexturePolicy policy =
layers::TextureHost::BackendNativeTexturePolicy(
layers::WebRenderBackend::SOFTWARE, plane.mSize);
return policy == layers::TextureHost::NativeTexturePolicy::FORBID
? RawDataToWrExternalImage((uint8_t*)plane.mData,
plane.mStride * plane.mSize.height)
: NativeTextureToWrExternalImage(plane.mTexture, uvs.first.x,
uvs.first.y, uvs.second.x,
uvs.second.y);
}
void RenderTextureHostSWGL::UnlockSWGL() {
if (mLocked) {
mLocked = false;
UnmapPlanes();
}
}
void RenderTextureHostSWGL::CleanupPlanes() {
if (!mContext) {
return;
}
if (!mPlanes.empty()) {
wr_swgl_make_current(mContext);
for (const auto& plane : mPlanes) {
wr_swgl_delete_texture(mContext, plane.mTexture);
}
mPlanes.clear();
}
wr_swgl_destroy_context(mContext);
mContext = nullptr;
}
RenderTextureHostSWGL::~RenderTextureHostSWGL() { CleanupPlanes(); }
bool RenderTextureHostSWGL::LockSWGLCompositeSurface(
void* aContext, wr::SWGLCompositeSurfaceInfo* aInfo) {
if (!SetContext(aContext)) {
return false;
}
if (!mLocked) {
if (!UpdatePlanes(nullptr)) {
return false;
}
mLocked = true;
}
MOZ_ASSERT(mPlanes.size() <= 3);
for (size_t i = 0; i < mPlanes.size(); i++) {
aInfo->textures[i] = mPlanes[i].mTexture;
}
switch (GetFormat()) {
case gfx::SurfaceFormat::YUV:
case gfx::SurfaceFormat::NV12:
case gfx::SurfaceFormat::P010:
case gfx::SurfaceFormat::YUV422: {
aInfo->yuv_planes = mPlanes.size();
auto colorSpace = GetYUVColorSpace();
aInfo->color_space = ToWrYuvRangedColorSpace(colorSpace);
auto colorDepth = GetColorDepth();
aInfo->color_depth = ToWrColorDepth(colorDepth);
break;
}
case gfx::SurfaceFormat::B8G8R8A8:
case gfx::SurfaceFormat::B8G8R8X8:
break;
default:
gfxCriticalNote << "Unhandled external image format: " << GetFormat();
MOZ_RELEASE_ASSERT(false, "Unhandled external image format");
break;
}
aInfo->size.width = mPlanes[0].mSize.width;
aInfo->size.height = mPlanes[0].mSize.height;
return true;
}
bool wr_swgl_lock_composite_surface(void* aContext, wr::ExternalImageId aId,
wr::SWGLCompositeSurfaceInfo* aInfo) {
RenderTextureHost* texture = RenderThread::Get()->GetRenderTexture(aId);
if (!texture) {
return false;
}
RenderTextureHostSWGL* swglTex = texture->AsRenderTextureHostSWGL();
if (!swglTex) {
return false;
}
return swglTex->LockSWGLCompositeSurface(aContext, aInfo);
}
void wr_swgl_unlock_composite_surface(void* aContext, wr::ExternalImageId aId) {
RenderTextureHost* texture = RenderThread::Get()->GetRenderTexture(aId);
if (!texture) {
return;
}
RenderTextureHostSWGL* swglTex = texture->AsRenderTextureHostSWGL();
if (!swglTex) {
return;
}
swglTex->UnlockSWGL();
}
} // namespace wr
} // namespace mozilla