Bug 1750858 - Respect mPicSize in WebRender. r=sotaro

This makes WR properly handle mPicSize when RenderBufferTextureHost is used.
The main change is that we need to take care to pass in display().Size() from
the descriptor, and then further use that to carefully limit the size of the
CbCr texture, as it doesn't necessarily maintain an appropriate half-sized
scale with respect to the Y texture if it is padded.

Given that mPicSize should now actually work, we should no longer need any
of the previous mCroppedSize mechanisms that were added to work around this,
and so they are removed in this patch.

Differential Revision: https://phabricator.services.mozilla.com/D139267
This commit is contained in:
Lee Salzman 2022-02-22 17:56:30 +00:00
parent f38fa1efe5
commit 9ff6a3947e
12 changed files with 53 additions and 117 deletions

View File

@ -542,8 +542,6 @@ FFmpegVideoDecoder<LIBAV_VER>::CreateEmptyPlanarYCbCrData(
&paddedYSize.height);
data.mYSize = gfx::IntSize{paddedYSize.Width(), paddedYSize.Height()};
data.mYStride = data.mYSize.Width() * bytesPerChannel;
data.mCroppedYSize = Some(
gfx::IntSize{aCodecContext->coded_width, aCodecContext->coded_height});
MOZ_ASSERT(
IsColorFormatSupportedForUsingCustomizedBuffer(aCodecContext->pix_fmt));
@ -560,7 +558,6 @@ FFmpegVideoDecoder<LIBAV_VER>::CreateEmptyPlanarYCbCrData(
data.mCbCrSize =
gfx::IntSize{paddedCbCrSize.Width(), paddedCbCrSize.Height()};
data.mCbCrStride = data.mCbCrSize.Width() * bytesPerChannel;
data.mCroppedCbCrSize = Some(gfx::IntSize{uvDims.Width(), uvDims.Height()});
// Setting other attributes
data.mPicSize =
@ -585,9 +582,8 @@ FFmpegVideoDecoder<LIBAV_VER>::CreateEmptyPlanarYCbCrData(
"Created plane data, YSize=(%d, %d), CbCrSize=(%d, %d), "
"CroppedYSize=(%d, %d), CroppedCbCrSize=(%d, %d), ColorDepth=%hhu",
data.mYSize.Width(), data.mYSize.Height(), data.mCbCrSize.Width(),
data.mCbCrSize.Height(), data.mCroppedYSize->Width(),
data.mCroppedYSize->Height(), data.mCroppedCbCrSize->Width(),
data.mCroppedCbCrSize->Height(), static_cast<uint8_t>(data.mColorDepth));
data.mCbCrSize.Height(), data.mPicSize.Width(), data.mPicSize.Height(),
uvDims.Width(), uvDims.Height(), static_cast<uint8_t>(data.mColorDepth));
return data;
}

View File

@ -95,15 +95,8 @@ class ShmemTextureData : public BufferTextureData {
virtual size_t GetBufferSize() override { return mShmem.Size<uint8_t>(); }
bool CropYCbCrPlanes(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize) override;
// Restore original descriptor that might be changed by CropYCbCrPlanes();
void RestoreOriginalDescriptor() override;
protected:
mozilla::ipc::Shmem mShmem;
Maybe<BufferDescriptor> mOrigDescriptor;
};
BufferTextureData* BufferTextureData::Create(
@ -517,38 +510,5 @@ void ShmemTextureData::Deallocate(LayersIPCChannel* aAllocator) {
aAllocator->DeallocShmem(mShmem);
}
bool ShmemTextureData::CropYCbCrPlanes(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize) {
if (mDescriptor.type() != BufferDescriptor::TYCbCrDescriptor) {
return false;
}
const auto& current = mDescriptor.get_YCbCrDescriptor();
if (current.ySize() < aYSize || current.cbCrSize() < aCbCrSize) {
NS_WARNING("Cropped size should not exceed the original size!");
return false;
}
MOZ_ASSERT(mOrigDescriptor.isNothing());
// Store original descriptor.
mOrigDescriptor = Some(current);
auto newDescritor = YCbCrDescriptor(
current.display(), aYSize, current.yStride(), aCbCrSize,
current.cbCrStride(), current.yOffset(), current.cbOffset(),
current.crOffset(), current.stereoMode(), current.colorDepth(),
current.yUVColorSpace(), current.colorRange());
mDescriptor = BufferDescriptor(newDescritor);
return true;
}
void ShmemTextureData::RestoreOriginalDescriptor() {
if (mOrigDescriptor.isNothing()) {
return;
}
mDescriptor = mOrigDescriptor.ref();
mOrigDescriptor = Nothing();
}
} // namespace layers
} // namespace mozilla

View File

@ -661,12 +661,6 @@ struct PlanarYCbCrData {
}
static Maybe<PlanarYCbCrData> From(const SurfaceDescriptorBuffer&);
// We would use mPicSize, but that's not hooked up in WR for RawData
// ExternalImages, so we manually clip sizes later on. We should fix WR,
// but not in this patch. Do not use unless mPicSize doesn't work for you.
Maybe<gfx::IntSize> mCroppedYSize;
Maybe<gfx::IntSize> mCroppedCbCrSize;
};
// This type is currently only used for AVIF and therefore makes some

View File

@ -345,6 +345,11 @@ void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
aStride);
}
gfx::IntSize GetCroppedCbCrSize(const YCbCrDescriptor& aDescriptor) {
return gfx::GetCroppedCbCrSize(aDescriptor.ySize(), aDescriptor.cbCrSize(),
aDescriptor.display().Size());
}
} // namespace ImageDataSerializer
} // namespace layers
} // namespace mozilla

View File

@ -100,6 +100,8 @@ void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
unsigned char* aDestBuffer,
int32_t aStride);
gfx::IntSize GetCroppedCbCrSize(const YCbCrDescriptor& aDescriptor);
} // namespace ImageDataSerializer
} // namespace layers

View File

@ -850,14 +850,6 @@ bool TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) {
return mData ? mData->Serialize(aOutDescriptor) : false;
}
bool TextureClient::CropYCbCrPlanes(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize) {
if (!mData) {
return false;
}
return mData->CropYCbCrPlanes(aYSize, aCbCrSize);
}
// static
PTextureChild* TextureClient::CreateIPDLActor() {
TextureChild* c = new TextureChild();

View File

@ -307,17 +307,6 @@ class TextureData {
return mozilla::ipc::FileDescriptor();
}
/**
* Crop YCbCr planes to a smaller size. An use case is that we would need to
* allocate a larger size for planes in order to meet the special alignement
* requirement (eg. for ffmpeg video decoding), but crop planes to a correct
* range after allocation is done.
*/
virtual bool CropYCbCrPlanes(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize) {
return false;
}
protected:
MOZ_COUNTED_DEFAULT_CTOR(TextureData)
};
@ -480,15 +469,6 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
bool CopyToTextureClient(TextureClient* aTarget, const gfx::IntRect* aRect,
const gfx::IntPoint* aPoint);
/**
* Crop YCbCr planes to a smaller size. An use case is that we would need to
* allocate a larger size for planes in order to meet the special alignement
* requirement (eg. for ffmpeg video decoding), but crop planes to a correct
* range after allocation is done.
*/
bool CropYCbCrPlanes(const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize);
/**
* Allocate and deallocate a TextureChild actor.
*

View File

@ -529,11 +529,12 @@ void BufferTextureHost::PushResourceUpdates(
MOZ_ASSERT(aImageKeys.length() == 3);
const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
gfx::IntSize ySize = desc.display().Size();
gfx::IntSize cbcrSize = ImageDataSerializer::GetCroppedCbCrSize(desc);
wr::ImageDescriptor yDescriptor(
desc.ySize(), desc.yStride(),
SurfaceFormatForColorDepth(desc.colorDepth()));
ySize, desc.yStride(), SurfaceFormatForColorDepth(desc.colorDepth()));
wr::ImageDescriptor cbcrDescriptor(
desc.cbCrSize(), desc.cbCrStride(),
cbcrSize, desc.cbCrStride(),
SurfaceFormatForColorDepth(desc.colorDepth()));
(aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0);
(aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1);

View File

@ -132,18 +132,6 @@ bool SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData) {
return false;
}
gfx::IntSize imageYSize =
aData.mCroppedYSize ? *aData.mCroppedYSize : aData.mYSize;
gfx::IntSize imageCbCrSize =
aData.mCroppedCbCrSize ? *aData.mCroppedCbCrSize : aData.mCbCrSize;
if (aData.mCroppedYSize || aData.mCroppedCbCrSize) {
// If cropping fails, then reset Y&CbCr sizes to non-cropped sizes.
if (!mTextureClient->CropYCbCrPlanes(imageYSize, imageCbCrSize)) {
imageYSize = aData.mYSize;
imageCbCrSize = aData.mCbCrSize;
}
}
MappedYCbCrTextureData mapped;
// The locking here is sort of a lie. The SharedPlanarYCbCrImage just pulls
// pointers out of the TextureClient and keeps them around, which works only
@ -163,8 +151,8 @@ bool SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData) {
mData.mYChannel = aData.mYChannel;
mData.mCbChannel = aData.mCbChannel;
mData.mCrChannel = aData.mCrChannel;
mData.mYSize = imageYSize;
mData.mCbCrSize = imageCbCrSize;
mData.mYSize = aData.mYSize;
mData.mCbCrSize = aData.mCbCrSize;
mData.mPicX = aData.mPicX;
mData.mPicY = aData.mPicY;
mData.mPicSize = aData.mPicSize;

View File

@ -208,19 +208,21 @@ bool RenderBufferTextureHost::MapPlane(RenderCompositor* aCompositor,
aPlaneInfo.mData =
layers::ImageDataSerializer::GetYChannel(mBuffer, desc);
aPlaneInfo.mStride = desc.yStride();
aPlaneInfo.mSize = desc.ySize();
aPlaneInfo.mSize = desc.display().Size();
break;
case 1:
aPlaneInfo.mData =
layers::ImageDataSerializer::GetCbChannel(mBuffer, desc);
aPlaneInfo.mStride = desc.cbCrStride();
aPlaneInfo.mSize = desc.cbCrSize();
aPlaneInfo.mSize =
layers::ImageDataSerializer::GetCroppedCbCrSize(desc);
break;
case 2:
aPlaneInfo.mData =
layers::ImageDataSerializer::GetCrChannel(mBuffer, desc);
aPlaneInfo.mStride = desc.cbCrStride();
aPlaneInfo.mSize = desc.cbCrSize();
aPlaneInfo.mSize =
layers::ImageDataSerializer::GetCroppedCbCrSize(desc);
break;
}
break;

View File

@ -17,16 +17,40 @@ namespace gfx {
// clang-format off
IntSize GetCroppedCbCrSize(const IntSize& aYSize,
const IntSize& aCbCrSize,
const IntSize& aDisplaySize) {
// The supplied ySize and cbcrSize are dimensions that may be padded for
// alignment. display holds the intended cropped display size of the data.
// The ySize can simply be limited by the display size. The cbcrSize must
// be cropped by checking if the uncropped size is approximately half, and
// then halving the cropped ySize since the uncropped sizes may be padded
// inconsistently.
IntSize croppedCbCrSize = Min(aDisplaySize, aCbCrSize);
if (aCbCrSize.height < aYSize.height &&
aCbCrSize.height >= aYSize.height / 2) {
croppedCbCrSize.width = (aDisplaySize.width + 1) / 2;
croppedCbCrSize.height = (aDisplaySize.height + 1) / 2;
} else if (aCbCrSize.width < aYSize.width &&
aCbCrSize.width >= aYSize.width / 2) {
croppedCbCrSize.width = (aDisplaySize.width + 1) / 2;
}
return croppedCbCrSize;
}
static YUVType GetYUVType(const layers::PlanarYCbCrData& aData) {
IntSize croppedCbCrSize =
GetCroppedCbCrSize(aData.mYSize, aData.mCbCrSize, aData.mPicSize);
return TypeFromSize(aData.mPicSize.width, aData.mPicSize.height,
croppedCbCrSize.width, croppedCbCrSize.height);
}
void
GetYCbCrToRGBDestFormatAndSize(const layers::PlanarYCbCrData& aData,
SurfaceFormat& aSuggestedFormat,
IntSize& aSuggestedSize)
{
YUVType yuvtype =
TypeFromSize(aData.mYSize.width,
aData.mYSize.height,
aData.mCbCrSize.width,
aData.mCbCrSize.height);
YUVType yuvtype = GetYUVType(aData);
// 'prescale' is true if the scaling is to be done as part of the
// YCbCr to RGB conversion rather than on the RGB data when rendered.
@ -109,12 +133,7 @@ ConvertYCbCrToRGBInternal(const layers::PlanarYCbCrData& aData,
{
// ConvertYCbCrToRGB et al. assume the chroma planes are rounded up if the
// luma plane is odd sized. Monochrome images have 0-sized CbCr planes
MOZ_ASSERT(aData.mCbCrSize.width == aData.mYSize.width ||
aData.mCbCrSize.width == (aData.mYSize.width + 1) >> 1 ||
aData.mCbCrSize.width == 0);
MOZ_ASSERT(aData.mCbCrSize.height == aData.mYSize.height ||
aData.mCbCrSize.height == (aData.mYSize.height + 1) >> 1 ||
aData.mCbCrSize.height == 0);
YUVType yuvtype = GetYUVType(aData);
// Used if converting to 8 bits YUV.
UniquePtr<uint8_t[]> yChannel;
@ -185,12 +204,6 @@ ConvertYCbCrToRGBInternal(const layers::PlanarYCbCrData& aData,
}
}
YUVType yuvtype =
TypeFromSize(srcData.mYSize.width,
srcData.mYSize.height,
srcData.mCbCrSize.width,
srcData.mCbCrSize.height);
// Convert from YCbCr to RGB now, scaling the image if needed.
if (aDestSize != srcData.mPicSize) {
#if defined(HAVE_YCBCR_TO_RGB565)

View File

@ -12,6 +12,9 @@
namespace mozilla {
namespace gfx {
IntSize GetCroppedCbCrSize(const IntSize& aYSize, const IntSize& aCbCrSize,
const IntSize& aDisplaySize);
void
GetYCbCrToRGBDestFormatAndSize(const layers::PlanarYCbCrData& aData,
SurfaceFormat& aSuggestedFormat,