gecko-dev/gfx/webrender_bindings/RenderMacIOSurfaceTextureHost.cpp
Andrew Osmond 3b047c7ae8 Bug 1918778 - Correct ownership/recycling issues with MacIOSurface. a=diannaS
This patch corrects a few different issues related to recycling
MacIOSurface objects.

1) When recycling a surface, we must check that the cached surfaces
   match all of the requested parameters, not just the size. If we do
   not, we should just flush the whole cache immediately since they
   should all be created with the same parameters.

2) Allocations can fail, and we should check for failing to get a
   surface from the allocator and fall back if so.

3) Locking can fail, and we should check that return value at all of the
   call sites.

This may help resolve a number of otherwise difficult to understand
crash signatures. It may also solve display corruption issues in rare
cases where the parameters that changed were roughly equivalent such
that everything appears to work, but they differ enough to change the
presentation.

Differential Revision: https://phabricator.services.mozilla.com/D222775
2024-09-19 15:49:27 +00:00

165 lines
5.6 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 "RenderMacIOSurfaceTextureHost.h"
#ifdef XP_MACOSX
# include "GLContextCGL.h"
#else
# include "GLContextEAGL.h"
#endif
#include "mozilla/gfx/Logging.h"
#include "ScopedGLHelpers.h"
namespace mozilla {
namespace wr {
static bool CreateTextureForPlane(uint8_t aPlaneID, gl::GLContext* aGL,
MacIOSurface* aSurface, GLuint* aTexture) {
MOZ_ASSERT(aGL && aSurface && aTexture);
aGL->fGenTextures(1, aTexture);
ActivateBindAndTexParameteri(aGL, LOCAL_GL_TEXTURE0,
LOCAL_GL_TEXTURE_RECTANGLE_ARB, *aTexture);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
gfx::SurfaceFormat readFormat = gfx::SurfaceFormat::UNKNOWN;
bool result = aSurface->BindTexImage(aGL, aPlaneID, &readFormat);
// If this is a yuv format, the Webrender only supports YUV422 interleaving
// format.
MOZ_ASSERT(aSurface->GetFormat() != gfx::SurfaceFormat::YUV422 ||
readFormat == gfx::SurfaceFormat::YUV422);
return result;
}
RenderMacIOSurfaceTextureHost::RenderMacIOSurfaceTextureHost(
MacIOSurface* aSurface)
: mSurface(aSurface), mTextureHandles{0, 0, 0} {
MOZ_COUNT_CTOR_INHERITED(RenderMacIOSurfaceTextureHost, RenderTextureHost);
}
RenderMacIOSurfaceTextureHost::~RenderMacIOSurfaceTextureHost() {
MOZ_COUNT_DTOR_INHERITED(RenderMacIOSurfaceTextureHost, RenderTextureHost);
DeleteTextureHandle();
}
GLuint RenderMacIOSurfaceTextureHost::GetGLHandle(uint8_t aChannelIndex) const {
MOZ_ASSERT(mSurface);
MOZ_ASSERT((mSurface->GetPlaneCount() == 0)
? (aChannelIndex == mSurface->GetPlaneCount())
: (aChannelIndex < mSurface->GetPlaneCount()));
return mTextureHandles[aChannelIndex];
}
gfx::IntSize RenderMacIOSurfaceTextureHost::GetSize(
uint8_t aChannelIndex) const {
MOZ_ASSERT(mSurface);
MOZ_ASSERT((mSurface->GetPlaneCount() == 0)
? (aChannelIndex == mSurface->GetPlaneCount())
: (aChannelIndex < mSurface->GetPlaneCount()));
if (!mSurface) {
return gfx::IntSize();
}
return gfx::IntSize(mSurface->GetDevicePixelWidth(aChannelIndex),
mSurface->GetDevicePixelHeight(aChannelIndex));
}
size_t RenderMacIOSurfaceTextureHost::Bytes() {
return mSurface->GetAllocSize();
}
wr::WrExternalImage RenderMacIOSurfaceTextureHost::Lock(uint8_t aChannelIndex,
gl::GLContext* aGL) {
if (mGL.get() != aGL) {
// release the texture handle in the previous gl context
DeleteTextureHandle();
mGL = aGL;
mGL->MakeCurrent();
}
if (!mSurface || !mGL || !mGL->MakeCurrent()) {
return InvalidToWrExternalImage();
}
if (!mTextureHandles[0]) {
#ifdef XP_MACOSX
MOZ_ASSERT(gl::GLContextCGL::Cast(mGL.get())->GetCGLContext());
#else
MOZ_ASSERT(gl::GLContextEAGL::Cast(mGL.get())->GetEAGLContext());
#endif
// The result of GetPlaneCount() is 0 for single plane format, but it will
// be 2 if the format has 2 planar data.
CreateTextureForPlane(0, mGL, mSurface, &(mTextureHandles[0]));
for (size_t i = 1; i < mSurface->GetPlaneCount(); ++i) {
CreateTextureForPlane(i, mGL, mSurface, &(mTextureHandles[i]));
}
}
const auto uvs = GetUvCoords(GetSize(aChannelIndex));
return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), uvs.first.x,
uvs.first.y, uvs.second.x,
uvs.second.y);
}
void RenderMacIOSurfaceTextureHost::Unlock() {}
void RenderMacIOSurfaceTextureHost::DeleteTextureHandle() {
if (mTextureHandles[0] != 0 && mGL && mGL->MakeCurrent()) {
// Calling glDeleteTextures on 0 isn't an error. So, just make them a single
// call.
mGL->fDeleteTextures(3, mTextureHandles);
for (size_t i = 0; i < 3; ++i) {
mTextureHandles[i] = 0;
}
}
}
size_t RenderMacIOSurfaceTextureHost::GetPlaneCount() const {
size_t planeCount = mSurface->GetPlaneCount();
return planeCount > 0 ? planeCount : 1;
}
gfx::SurfaceFormat RenderMacIOSurfaceTextureHost::GetFormat() const {
return mSurface->GetFormat();
}
gfx::ColorDepth RenderMacIOSurfaceTextureHost::GetColorDepth() const {
return mSurface->GetColorDepth();
}
gfx::YUVRangedColorSpace RenderMacIOSurfaceTextureHost::GetYUVColorSpace()
const {
return ToYUVRangedColorSpace(mSurface->GetYUVColorSpace(),
mSurface->GetColorRange());
}
bool RenderMacIOSurfaceTextureHost::MapPlane(RenderCompositor* aCompositor,
uint8_t aChannelIndex,
PlaneInfo& aPlaneInfo) {
if (!aChannelIndex) {
if (NS_WARN_IF(!mSurface->Lock())) {
return false;
}
}
aPlaneInfo.mData = mSurface->GetBaseAddressOfPlane(aChannelIndex);
aPlaneInfo.mStride = mSurface->GetBytesPerRow(aChannelIndex);
aPlaneInfo.mSize =
gfx::IntSize(mSurface->GetDevicePixelWidth(aChannelIndex),
mSurface->GetDevicePixelHeight(aChannelIndex));
return true;
}
void RenderMacIOSurfaceTextureHost::UnmapPlanes() { mSurface->Unlock(); }
} // namespace wr
} // namespace mozilla