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
232 lines
7.4 KiB
C++
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
|