Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release
[gecko.git] / gfx / layers / ImageDataSerializer.cpp
blob70d54931853a15311363d3c9e68b47c14b429df0
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/gfx/2D.h" // for DataSourceSurface, Factory
13 #include "mozilla/gfx/Logging.h" // for gfxDebug
14 #include "mozilla/gfx/Tools.h" // for GetAlignedStride, etc
15 #include "mozilla/gfx/Types.h"
16 #include "mozilla/mozalloc.h" // for operator delete, etc
18 namespace mozilla {
19 namespace layers {
20 namespace ImageDataSerializer {
22 using namespace gfx;
24 int32_t ComputeRGBStride(SurfaceFormat aFormat, int32_t aWidth) {
25 #ifdef XP_MACOSX
26 // Some drivers require an alignment of 32 bytes for efficient texture upload.
27 return GetAlignedStride<32>(aWidth, BytesPerPixel(aFormat));
28 #else
29 return GetAlignedStride<4>(aWidth, BytesPerPixel(aFormat));
30 #endif
33 int32_t GetRGBStride(const RGBDescriptor& aDescriptor) {
34 return ComputeRGBStride(aDescriptor.format(), aDescriptor.size().width);
37 uint32_t ComputeRGBBufferSize(IntSize aSize, SurfaceFormat aFormat) {
38 MOZ_ASSERT(aSize.height >= 0 && aSize.width >= 0);
40 // This takes care of checking whether there could be overflow
41 // with enough margin for the metadata.
42 if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
43 return 0;
46 // Note we're passing height instad of the bpp parameter, but the end
47 // result is the same - and the bpp was already taken care of in the
48 // ComputeRGBStride function.
49 int32_t bufsize = GetAlignedStride<16>(ComputeRGBStride(aFormat, aSize.width),
50 aSize.height);
52 if (bufsize < 0) {
53 // This should not be possible thanks to Factory::AllowedSurfaceSize
54 return 0;
57 return bufsize;
60 // Minimum required shmem size in bytes
61 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
62 const gfx::IntSize& aCbCrSize,
63 int32_t aCbCrStride) {
64 MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
66 if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
67 aCbCrSize.width < 0 ||
68 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
69 !gfx::Factory::AllowedSurfaceSize(
70 IntSize(aCbCrStride, aCbCrSize.height))) {
71 return 0;
74 // Overflow checks are performed in AllowedSurfaceSize
75 return GetAlignedStride<4>(aYSize.height, aYStride) +
76 2 * GetAlignedStride<4>(aCbCrSize.height, aCbCrStride);
79 uint32_t ComputeYCbCrBufferSize(const gfx::IntSize& aYSize, int32_t aYStride,
80 const gfx::IntSize& aCbCrSize,
81 int32_t aCbCrStride, uint32_t aYOffset,
82 uint32_t aCbOffset, uint32_t aCrOffset) {
83 MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0);
85 if (aYSize.height < 0 || aYSize.width < 0 || aCbCrSize.height < 0 ||
86 aCbCrSize.width < 0 ||
87 !gfx::Factory::AllowedSurfaceSize(IntSize(aYStride, aYSize.height)) ||
88 !gfx::Factory::AllowedSurfaceSize(
89 IntSize(aCbCrStride, aCbCrSize.height))) {
90 return 0;
93 uint32_t yLength = GetAlignedStride<4>(aYStride, aYSize.height);
94 uint32_t cbCrLength = GetAlignedStride<4>(aCbCrStride, aCbCrSize.height);
95 if (yLength == 0 || cbCrLength == 0) {
96 return 0;
99 CheckedInt<uint32_t> yEnd = aYOffset;
100 yEnd += yLength;
101 CheckedInt<uint32_t> cbEnd = aCbOffset;
102 cbEnd += cbCrLength;
103 CheckedInt<uint32_t> crEnd = aCrOffset;
104 crEnd += cbCrLength;
106 if (!yEnd.isValid() || !cbEnd.isValid() || !crEnd.isValid() ||
107 yEnd.value() > aCbOffset || cbEnd.value() > aCrOffset) {
108 return 0;
111 return crEnd.value();
114 uint32_t ComputeYCbCrBufferSize(uint32_t aBufferSize) {
115 return GetAlignedStride<4>(aBufferSize, 1);
118 void ComputeYCbCrOffsets(int32_t yStride, int32_t yHeight, int32_t cbCrStride,
119 int32_t cbCrHeight, uint32_t& outYOffset,
120 uint32_t& outCbOffset, uint32_t& outCrOffset) {
121 outYOffset = 0;
122 outCbOffset = outYOffset + GetAlignedStride<4>(yStride, yHeight);
123 outCrOffset = outCbOffset + GetAlignedStride<4>(cbCrStride, cbCrHeight);
126 gfx::SurfaceFormat FormatFromBufferDescriptor(
127 const BufferDescriptor& aDescriptor) {
128 switch (aDescriptor.type()) {
129 case BufferDescriptor::TRGBDescriptor:
130 return aDescriptor.get_RGBDescriptor().format();
131 case BufferDescriptor::TYCbCrDescriptor:
132 return gfx::SurfaceFormat::YUV;
133 default:
134 MOZ_CRASH("GFX: FormatFromBufferDescriptor");
138 gfx::IntSize SizeFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
139 switch (aDescriptor.type()) {
140 case BufferDescriptor::TRGBDescriptor:
141 return aDescriptor.get_RGBDescriptor().size();
142 case BufferDescriptor::TYCbCrDescriptor: {
143 return aDescriptor.get_YCbCrDescriptor().display().Size();
145 default:
146 MOZ_CRASH("GFX: SizeFromBufferDescriptor");
150 gfx::IntRect RectFromBufferDescriptor(const BufferDescriptor& aDescriptor) {
151 switch (aDescriptor.type()) {
152 case BufferDescriptor::TRGBDescriptor: {
153 auto size = aDescriptor.get_RGBDescriptor().size();
154 return gfx::IntRect(0, 0, size.Width(), size.Height());
156 case BufferDescriptor::TYCbCrDescriptor:
157 return aDescriptor.get_YCbCrDescriptor().display();
158 default:
159 MOZ_CRASH("GFX: RectFromBufferDescriptor");
163 Maybe<gfx::IntSize> YSizeFromBufferDescriptor(
164 const BufferDescriptor& aDescriptor) {
165 switch (aDescriptor.type()) {
166 case BufferDescriptor::TRGBDescriptor:
167 return Nothing();
168 case BufferDescriptor::TYCbCrDescriptor:
169 return Some(aDescriptor.get_YCbCrDescriptor().ySize());
170 default:
171 MOZ_CRASH("GFX: YSizeFromBufferDescriptor");
175 Maybe<gfx::IntSize> CbCrSizeFromBufferDescriptor(
176 const BufferDescriptor& aDescriptor) {
177 switch (aDescriptor.type()) {
178 case BufferDescriptor::TRGBDescriptor:
179 return Nothing();
180 case BufferDescriptor::TYCbCrDescriptor:
181 return Some(aDescriptor.get_YCbCrDescriptor().cbCrSize());
182 default:
183 MOZ_CRASH("GFX: CbCrSizeFromBufferDescriptor");
187 Maybe<int32_t> YStrideFromBufferDescriptor(
188 const BufferDescriptor& aDescriptor) {
189 switch (aDescriptor.type()) {
190 case BufferDescriptor::TRGBDescriptor:
191 return Nothing();
192 case BufferDescriptor::TYCbCrDescriptor:
193 return Some(aDescriptor.get_YCbCrDescriptor().yStride());
194 default:
195 MOZ_CRASH("GFX: YStrideFromBufferDescriptor");
199 Maybe<int32_t> CbCrStrideFromBufferDescriptor(
200 const BufferDescriptor& aDescriptor) {
201 switch (aDescriptor.type()) {
202 case BufferDescriptor::TRGBDescriptor:
203 return Nothing();
204 case BufferDescriptor::TYCbCrDescriptor:
205 return Some(aDescriptor.get_YCbCrDescriptor().cbCrStride());
206 default:
207 MOZ_CRASH("GFX: CbCrStrideFromBufferDescriptor");
211 Maybe<gfx::YUVColorSpace> YUVColorSpaceFromBufferDescriptor(
212 const BufferDescriptor& aDescriptor) {
213 switch (aDescriptor.type()) {
214 case BufferDescriptor::TRGBDescriptor:
215 return Nothing();
216 case BufferDescriptor::TYCbCrDescriptor:
217 return Some(aDescriptor.get_YCbCrDescriptor().yUVColorSpace());
218 default:
219 MOZ_CRASH("GFX: YUVColorSpaceFromBufferDescriptor");
223 Maybe<gfx::ColorDepth> ColorDepthFromBufferDescriptor(
224 const BufferDescriptor& aDescriptor) {
225 switch (aDescriptor.type()) {
226 case BufferDescriptor::TRGBDescriptor:
227 return Nothing();
228 case BufferDescriptor::TYCbCrDescriptor:
229 return Some(aDescriptor.get_YCbCrDescriptor().colorDepth());
230 default:
231 MOZ_CRASH("GFX: ColorDepthFromBufferDescriptor");
235 Maybe<gfx::ColorRange> ColorRangeFromBufferDescriptor(
236 const BufferDescriptor& aDescriptor) {
237 switch (aDescriptor.type()) {
238 case BufferDescriptor::TRGBDescriptor:
239 return Nothing();
240 case BufferDescriptor::TYCbCrDescriptor:
241 return Some(aDescriptor.get_YCbCrDescriptor().colorRange());
242 default:
243 MOZ_CRASH("GFX: YUVFullRangeFromBufferDescriptor");
247 Maybe<StereoMode> StereoModeFromBufferDescriptor(
248 const BufferDescriptor& aDescriptor) {
249 switch (aDescriptor.type()) {
250 case BufferDescriptor::TRGBDescriptor:
251 return Nothing();
252 case BufferDescriptor::TYCbCrDescriptor:
253 return Some(aDescriptor.get_YCbCrDescriptor().stereoMode());
254 default:
255 MOZ_CRASH("GFX: StereoModeFromBufferDescriptor");
259 Maybe<gfx::ChromaSubsampling> ChromaSubsamplingFromBufferDescriptor(
260 const BufferDescriptor& aDescriptor) {
261 switch (aDescriptor.type()) {
262 case BufferDescriptor::TRGBDescriptor:
263 return Nothing();
264 case BufferDescriptor::TYCbCrDescriptor:
265 return Some(aDescriptor.get_YCbCrDescriptor().chromaSubsampling());
266 default:
267 MOZ_CRASH("GFX: ChromaSubsamplingFromBufferDescriptor");
271 uint8_t* GetYChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
272 return aBuffer + aDescriptor.yOffset();
275 uint8_t* GetCbChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
276 return aBuffer + aDescriptor.cbOffset();
279 uint8_t* GetCrChannel(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor) {
280 return aBuffer + aDescriptor.crOffset();
283 already_AddRefed<DataSourceSurface> DataSourceSurfaceFromYCbCrDescriptor(
284 uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor,
285 gfx::DataSourceSurface* aSurface) {
286 const gfx::IntRect display = aDescriptor.display();
287 const gfx::IntSize size = display.Size();
288 RefPtr<DataSourceSurface> result;
289 if (aSurface) {
290 MOZ_ASSERT(aSurface->GetSize() == size);
291 MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
292 if (aSurface->GetSize() == size &&
293 aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) {
294 result = aSurface;
298 if (!result) {
299 result =
300 Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8X8);
302 if (NS_WARN_IF(!result)) {
303 return nullptr;
306 DataSourceSurface::MappedSurface map;
307 if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) {
308 return nullptr;
311 layers::PlanarYCbCrData ycbcrData;
312 ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
313 ycbcrData.mYStride = aDescriptor.yStride();
314 ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
315 ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
316 ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
317 ycbcrData.mPictureRect = aDescriptor.display();
318 ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
319 ycbcrData.mColorDepth = aDescriptor.colorDepth();
320 ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
322 gfx::ConvertYCbCrToRGB(ycbcrData, gfx::SurfaceFormat::B8G8R8X8, size,
323 map.mData, map.mStride);
325 result->Unmap();
326 return result.forget();
329 void ConvertAndScaleFromYCbCrDescriptor(uint8_t* aBuffer,
330 const YCbCrDescriptor& aDescriptor,
331 const gfx::SurfaceFormat& aDestFormat,
332 const gfx::IntSize& aDestSize,
333 unsigned char* aDestBuffer,
334 int32_t aStride) {
335 MOZ_ASSERT(aBuffer);
337 layers::PlanarYCbCrData ycbcrData;
338 ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor);
339 ycbcrData.mYStride = aDescriptor.yStride();
340 ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor);
341 ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor);
342 ycbcrData.mCbCrStride = aDescriptor.cbCrStride();
343 ycbcrData.mPictureRect = aDescriptor.display();
344 ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace();
345 ycbcrData.mColorDepth = aDescriptor.colorDepth();
346 ycbcrData.mChromaSubsampling = aDescriptor.chromaSubsampling();
348 gfx::ConvertYCbCrToRGB(ycbcrData, aDestFormat, aDestSize, aDestBuffer,
349 aStride);
352 gfx::IntSize GetCroppedCbCrSize(const YCbCrDescriptor& aDescriptor) {
353 return ChromaSize(aDescriptor.display().Size(),
354 aDescriptor.chromaSubsampling());
357 } // namespace ImageDataSerializer
358 } // namespace layers
359 } // namespace mozilla