Bug 1917491 - Part 3: Introduce call-like syntax for resource disposal in DisposableS...
[gecko.git] / gfx / layers / ImageDataSerializer.cpp
blob12918e92c28396b1a8f0e31fd7b32863977719c8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImageDataSerializer.h"
9 #include "YCbCrUtils.h" // for YCbCr conversions
10 #include "gfx2DGlue.h" // for SurfaceFormatToImageFormat
11 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
12 #include "mozilla/DebugOnly.h" // for DebugOnly
13 #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
14 #include "mozilla/gfx/Logging.h" // for gfxDebug
15 #include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
16 #include "mozilla/gfx/Types.h"
17 #include "mozilla/mozalloc.h" // for operator delete, etc
19 namespace mozilla {
20 namespace layers {
21 namespace ImageDataSerializer {
23 using namespace gfx;
25 int32_t ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth) {
26 #ifdef XP_MACOSX
27 // Some drivers require an alignment of 32 bytes for efficient texture upload.
28 return GetAlignedStride<32>(aWidth, BytesPerPixel(aFormat));
29 #else
30 return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
31 #endif
34 int32_t GetRGBStride(const RGBDescriptor& aDescriptor) {
35 return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
38 uint32_t ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat) {
39 MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
41 // This takes care of checking whether there could be overflow
42 // with enough margin for the metadata.
43 if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
44 return 0;
47 // Note we're passing height instad of the bpp parameter, but the end
48 // result is the same - and the bpp was already taken care of in the
49 // ComputeRGBStride function.
50 int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
51 aSize.height);
53 if (bufsize < 0) {
54 // This should not be possible thanks to Factory::AllowedSurfaceSize
55 return 0;
58 return bufsize;
61 // Minimum required shmem size in bytes
62 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
63 const gfx::IntSize& aCbCrSize,
64 int32_t aCbCrStride) {
65 MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
67 if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
68 aCbCrSize.width < 0 ||
69 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
70 !gfx::Factory::AllowedSurfaceSize(
71 IntSize(aCbCrStride, aCbCrSize.height))) {
72 return 0;
75 // Overflow checks are performed in AllowedSurfaceSize
76 return GetAlignedStride<4>(aYSize.height, aYStride) +
77 2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
80 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
81 const gfx::IntSize& aCbCrSize,
82 int32_t aCbCrStride, uint32_t aYOffset,
83 uint32_t aCbOffset, uint32_t aCrOffset) {
84 MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
86 if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
87 aCbCrSize.width < 0 ||
88 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
89 !gfx::Factory::AllowedSurfaceSize(
90 IntSize(aCbCrStride, aCbCrSize.height))) {
91 return 0;
94 uint32_t yLength = GetAlignedStride<4>(aYStride, aYSize.height);
95 uint32_t cbCrLength = GetAlignedStride<4>(aCbCrStride, aCbCrSize.height);
96 if (yLength == 0 || cbCrLength == 0) {
97 return 0;
100 CheckedInt<uint32_t> yEnd = aYOffset;
101 yEnd += yLength;
102 CheckedInt<uint32_t> cbEnd = aCbOffset;
103 cbEnd += cbCrLength;
104 CheckedInt<uint32_t> crEnd = aCrOffset;
105 crEnd += cbCrLength;
107 if (!yEnd.isValid() || !cbEnd.isValid() || !crEnd.isValid() ||
108 yEnd.value() > aCbOffset || cbEnd.value() > aCrOffset) {
109 return 0;
112 return crEnd.value();
115 uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize) {
116 return GetAlignedStride<4>(aBufferSize, 1);
119 void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight, int32_t cbCrStride,
120 int32_t cbCrHeight, uint32_t& outYOffset,
121 uint32_t& outCbOffset, uint32_t& outCrOffset) {
122 outYOffset = 0;
123 outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
124 outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
127 gfx::SurfaceFormat FormatFromBufferDescriptor(
128 const BufferDescriptor& aDescriptor) {
129 switch (aDescriptor.type()) {
130 case BufferDescriptor::TRGBDescriptor:
131 return aDescriptor.get_RGBDescriptor().format();
132 case BufferDescriptor::TYCbCrDescriptor:
133 return gfx::SurfaceFormat::YUV420;
134 default:
135 MOZ_CRASH("GFX: FormatFromBufferDescriptor");
139 gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
140 switch (aDescriptor.type()) {
141 case BufferDescriptor::TRGBDescriptor:
142 return aDescriptor.get_RGBDescriptor().size();
143 case BufferDescriptor::TYCbCrDescriptor: {
144 return aDescriptor.get_YCbCrDescriptor().display().Size();
146 default:
147 MOZ_CRASH("GFX: SizeFromBufferDescriptor");
151 gfx::IntRect RectFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
152 switch (aDescriptor.type()) {
153 case BufferDescriptor::TRGBDescriptor: {
154 auto size = aDescriptor.get_RGBDescriptor().size();
155 return gfx::IntRect(0, 0, size.Width(), size.Height());
157 case BufferDescriptor::TYCbCrDescriptor:
158 return aDescriptor.get_YCbCrDescriptor().display();
159 default:
160 MOZ_CRASH("GFX: RectFromBufferDescriptor");
164 Maybe<gfx::IntSize> YSizeFromBufferDescriptor(
165 const BufferDescriptor& aDescriptor) {
166 switch (aDescriptor.type()) {
167 case BufferDescriptor::TRGBDescriptor:
168 return Nothing();
169 case BufferDescriptor::TYCbCrDescriptor:
170 return Some(aDescriptor.get_YCbCrDescriptor().ySize());
171 default:
172 MOZ_CRASH("GFX: YSizeFromBufferDescriptor");
176 Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(
177 const BufferDescriptor& aDescriptor) {
178 switch (aDescriptor.type()) {
179 case BufferDescriptor::TRGBDescriptor:
180 return Nothing();
181 case BufferDescriptor::TYCbCrDescriptor:
182 return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
183 default:
184 MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
188 Maybe<int32_t> YStrideFromBufferDescriptor(
189 const BufferDescriptor& aDescriptor) {
190 switch (aDescriptor.type()) {
191 case BufferDescriptor::TRGBDescriptor:
192 return Nothing();
193 case BufferDescriptor::TYCbCrDescriptor:
194 return Some(aDescriptor.get_YCbCrDescriptor().yStride());
195 default:
196 MOZ_CRASH("GFX: YStrideFromBufferDescriptor");
200 Maybe<int32_t> CbCrStrideFromBufferDescriptor(
201 const BufferDescriptor& aDescriptor) {
202 switch (aDescriptor.type()) {
203 case BufferDescriptor::TRGBDescriptor:
204 return Nothing();
205 case BufferDescriptor::TYCbCrDescriptor:
206 return Some(aDescriptor.get_YCbCrDescriptor().cbCrStride());
207 default:
208 MOZ_CRASH("GFX: CbCrStrideFromBufferDescriptor");
212 Maybe<gfx::YUVColorSpace> YUVColorSpaceFromBufferDescriptor(
213 const BufferDescriptor& aDescriptor) {
214 switch (aDescriptor.type()) {
215 case BufferDescriptor::TRGBDescriptor:
216 return Nothing();
217 case BufferDescriptor::TYCbCrDescriptor:
218 return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
219 default:
220 MOZ_CRASH("GFX: YUVColorSpaceFromBufferDescriptor");
224 Maybe<gfx::ColorDepth> ColorDepthFromBufferDescriptor(
225 const BufferDescriptor& aDescriptor) {
226 switch (aDescriptor.type()) {
227 case BufferDescriptor::TRGBDescriptor:
228 return Nothing();
229 case BufferDescriptor::TYCbCrDescriptor:
230 return Some(aDescriptor.get_YCbCrDescriptor().colorDepth());
231 default:
232 MOZ_CRASH("GFX: ColorDepthFromBufferDescriptor");
236 Maybe<gfx::ColorRange> ColorRangeFromBufferDescriptor(
237 const BufferDescriptor& aDescriptor) {
238 switch (aDescriptor.type()) {
239 case BufferDescriptor::TRGBDescriptor:
240 return Nothing();
241 case BufferDescriptor::TYCbCrDescriptor:
242 return Some(aDescriptor.get_YCbCrDescriptor().colorRange());
243 default:
244 MOZ_CRASH("GFX: YUVFullRangeFromBufferDescriptor");
248 Maybe<StereoMode> StereoModeFromBufferDescriptor(
249 const BufferDescriptor& aDescriptor) {
250 switch (aDescriptor.type()) {
251 case BufferDescriptor::TRGBDescriptor:
252 return Nothing();
253 case BufferDescriptor::TYCbCrDescriptor:
254 return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
255 default:
256 MOZ_CRASH("GFX: StereoModeFromBufferDescriptor");
260 Maybe<gfx::ChromaSubsampling> ChromaSubsamplingFromBufferDescriptor(
261 const BufferDescriptor& aDescriptor) {
262 switch (aDescriptor.type()) {
263 case BufferDescriptor::TRGBDescriptor:
264 return Nothing();
265 case BufferDescriptor::TYCbCrDescriptor:
266 return Some(aDescriptor.get_YCbCrDescriptor().chromaSubsampling());
267 default:
268 MOZ_CRASH("GFX: ChromaSubsamplingFromBufferDescriptor");
272 uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
273 return aBuffer + aDescriptor.yOffset();
276 uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
277 return aBuffer + aDescriptor.cbOffset();
280 uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
281 return aBuffer + aDescriptor.crOffset();
284 already_AddRefed<DataSourceSurface> DataSourceSurfaceFromYCbCrDescriptor(
285 uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor,
286 gfx::DataSourceSurface* aSurface) {
287 const gfx::IntRect display = aDescriptor.display();
288 const gfx::IntSize size = display.Size();
289 RefPtr<DataSourceSurface> result;
290 if (aSurface) {
291 MOZ_ASSERT(aSurface->GetSize() == size);
292 MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
293 if (aSurface->GetSize() == size &&
294 aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
295 result = aSurface;
299 if (!result) {
300 result =
301 Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8X8);
303 if (NS_WARN_IF(!result)) {
304 return nullptr;
307 DataSourceSurface::MappedSurface map;
308 if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
309 return nullptr;
312 layers::PlanarYCbCrData ycbcrData;
313 ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
314 ycbcrData.mYStride = aDescriptor.yStride();
315 ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
316 ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
317 ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
318 ycbcrData.mPictureRect = aDescriptor.display();
319 ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
320 ycbcrData.mColorDepth = aDescriptor.colorDepth();
321 ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
323 if (NS_WARN_IF(NS_FAILED(
324 gfx::ConvertYCbCrToRGB(ycbcrData, gfx::SurfaceFormat::B8G8R8X8, size,
325 map.mData, map.mStride)))) {
326 MOZ_ASSERT_UNREACHABLE("Failed to convert YUV into RGB data");
327 return nullptr;
330 result->Unmap();
331 return result.forget();
334 void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
335 const YCbCrDescriptor& aDescriptor,
336 const gfx::SurfaceFormat& aDestFormat,
337 const gfx::IntSize& aDestSize,
338 unsigned char* aDestBuffer,
339 int32_t aStride) {
340 MOZ_ASSERT(aBuffer);
342 layers::PlanarYCbCrData ycbcrData;
343 ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
344 ycbcrData.mYStride = aDescriptor.yStride();
345 ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
346 ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
347 ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
348 ycbcrData.mPictureRect = aDescriptor.display();
349 ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
350 ycbcrData.mColorDepth = aDescriptor.colorDepth();
351 ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
353 DebugOnly<nsresult> result = gfx::ConvertYCbCrToRGB(
354 ycbcrData, aDestFormat, aDestSize, aDestBuffer, aStride);
355 MOZ_ASSERT(NS_SUCCEEDED(result), "Failed to convert YUV into RGB data");
358 gfx::IntSize GetCroppedCbCrSize(const YCbCrDescriptor& aDescriptor) {
359 return ChromaSize(aDescriptor.display().Size(),
360 aDescriptor.chromaSubsampling());
363 } // namespace ImageDataSerializer
364 } // namespace layers
365 } // namespace mozilla