Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL
[WebKit-https.git] / Source / WebCore / platform / graphics / GraphicsContext3D.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  * Copyright (C) 2010 Mozilla Corporation. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29
30 #if ENABLE(GRAPHICS_CONTEXT_3D)
31
32 #include "GraphicsContext3D.h"
33
34 #include "Extensions3D.h"
35 #include "FormatConverter.h"
36 #include "Image.h"
37 #include "ImageData.h"
38 #include "ImageObserver.h"
39
40 namespace WebCore {
41
42 namespace {
43
44 GraphicsContext3D::DataFormat getDataFormat(GC3Denum destinationFormat, GC3Denum destinationType)
45 {
46     GraphicsContext3D::DataFormat dstFormat = GraphicsContext3D::DataFormatRGBA8;
47     switch (destinationType) {
48     case GraphicsContext3D::UNSIGNED_BYTE:
49         switch (destinationFormat) {
50         case GraphicsContext3D::RGB:
51             dstFormat = GraphicsContext3D::DataFormatRGB8;
52             break;
53         case GraphicsContext3D::RGBA:
54             dstFormat = GraphicsContext3D::DataFormatRGBA8;
55             break;
56         case GraphicsContext3D::ALPHA:
57             dstFormat = GraphicsContext3D::DataFormatA8;
58             break;
59         case GraphicsContext3D::LUMINANCE:
60             dstFormat = GraphicsContext3D::DataFormatR8;
61             break;
62         case GraphicsContext3D::LUMINANCE_ALPHA:
63             dstFormat = GraphicsContext3D::DataFormatRA8;
64             break;
65         case GraphicsContext3D::SRGB:
66             dstFormat = GraphicsContext3D::DataFormatRGB8;
67             break;
68         case GraphicsContext3D::SRGB_ALPHA:
69             dstFormat = GraphicsContext3D::DataFormatRGBA8;
70             break;
71         default:
72             ASSERT_NOT_REACHED();
73         }
74         break;
75     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
76         dstFormat = GraphicsContext3D::DataFormatRGBA4444;
77         break;
78     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
79         dstFormat = GraphicsContext3D::DataFormatRGBA5551;
80         break;
81     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
82         dstFormat = GraphicsContext3D::DataFormatRGB565;
83         break;
84     case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
85         switch (destinationFormat) {
86         case GraphicsContext3D::RGB:
87             dstFormat = GraphicsContext3D::DataFormatRGB16F;
88             break;
89         case GraphicsContext3D::RGBA:
90             dstFormat = GraphicsContext3D::DataFormatRGBA16F;
91             break;
92         case GraphicsContext3D::ALPHA:
93             dstFormat = GraphicsContext3D::DataFormatA16F;
94             break;
95         case GraphicsContext3D::LUMINANCE:
96             dstFormat = GraphicsContext3D::DataFormatR16F;
97             break;
98         case GraphicsContext3D::LUMINANCE_ALPHA:
99             dstFormat = GraphicsContext3D::DataFormatRA16F;
100             break;
101         case GraphicsContext3D::SRGB:
102             dstFormat = GraphicsContext3D::DataFormatRGB16F;
103             break;
104         case GraphicsContext3D::SRGB_ALPHA:
105             dstFormat = GraphicsContext3D::DataFormatRGBA16F;
106             break;
107         default:
108             ASSERT_NOT_REACHED();
109         }
110         break;
111     case GraphicsContext3D::FLOAT: // OES_texture_float
112         switch (destinationFormat) {
113         case GraphicsContext3D::RGB:
114             dstFormat = GraphicsContext3D::DataFormatRGB32F;
115             break;
116         case GraphicsContext3D::RGBA:
117             dstFormat = GraphicsContext3D::DataFormatRGBA32F;
118             break;
119         case GraphicsContext3D::ALPHA:
120             dstFormat = GraphicsContext3D::DataFormatA32F;
121             break;
122         case GraphicsContext3D::LUMINANCE:
123             dstFormat = GraphicsContext3D::DataFormatR32F;
124             break;
125         case GraphicsContext3D::LUMINANCE_ALPHA:
126             dstFormat = GraphicsContext3D::DataFormatRA32F;
127             break;
128         case GraphicsContext3D::SRGB:
129             dstFormat = GraphicsContext3D::DataFormatRGB32F;
130             break;
131         case GraphicsContext3D::SRGB_ALPHA:
132             dstFormat = GraphicsContext3D::DataFormatRGBA32F;
133             break;
134         default:
135             ASSERT_NOT_REACHED();
136         }
137         break;
138     default:
139         ASSERT_NOT_REACHED();
140     }
141     return dstFormat;
142 }
143
144 } // anonymous namespace
145
146 bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint unpackAlignment)
147 {
148     ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8);
149     std::unique_ptr<unsigned char[]> zero;
150     if (!isResourceSafe() && width > 0 && height > 0) {
151         unsigned int size;
152         GC3Denum error = computeImageSizeInBytes(format, type, width, height, unpackAlignment, &size, 0);
153         if (error != GraphicsContext3D::NO_ERROR) {
154             synthesizeGLError(error);
155             return false;
156         }
157         zero = std::make_unique<unsigned char[]>(size);
158         if (!zero) {
159             synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
160             return false;
161         }
162         memset(zero.get(), 0, size);
163     }
164     return texImage2D(target, level, internalformat, width, height, border, format, type, zero.get());
165 }
166
167 bool GraphicsContext3D::computeFormatAndTypeParameters(GC3Denum format, GC3Denum type, unsigned int* componentsPerPixel, unsigned int* bytesPerComponent)
168 {
169     switch (format) {
170     case GraphicsContext3D::ALPHA:
171     case GraphicsContext3D::LUMINANCE:
172     case GraphicsContext3D::DEPTH_COMPONENT:
173     case GraphicsContext3D::DEPTH_STENCIL:
174         *componentsPerPixel = 1;
175         break;
176     case GraphicsContext3D::LUMINANCE_ALPHA:
177         *componentsPerPixel = 2;
178         break;
179     case GraphicsContext3D::RGB:
180     case Extensions3D::SRGB_EXT:
181         *componentsPerPixel = 3;
182         break;
183     case GraphicsContext3D::RGBA:
184     case Extensions3D::BGRA_EXT: // GL_EXT_texture_format_BGRA8888
185     case Extensions3D::SRGB_ALPHA_EXT:
186         *componentsPerPixel = 4;
187         break;
188     default:
189         return false;
190     }
191     switch (type) {
192     case GraphicsContext3D::UNSIGNED_BYTE:
193         *bytesPerComponent = sizeof(GC3Dubyte);
194         break;
195     case GraphicsContext3D::UNSIGNED_SHORT:
196         *bytesPerComponent = sizeof(GC3Dushort);
197         break;
198     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
199     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
200     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
201         *componentsPerPixel = 1;
202         *bytesPerComponent = sizeof(GC3Dushort);
203         break;
204     case GraphicsContext3D::UNSIGNED_INT_24_8:
205     case GraphicsContext3D::UNSIGNED_INT:
206         *bytesPerComponent = sizeof(GC3Duint);
207         break;
208     case GraphicsContext3D::FLOAT: // OES_texture_float
209         *bytesPerComponent = sizeof(GC3Dfloat);
210         break;
211     case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
212         *bytesPerComponent = sizeof(GC3Dhalffloat);
213         break;
214     default:
215         return false;
216     }
217     return true;
218 }
219
220 GC3Denum GraphicsContext3D::computeImageSizeInBytes(GC3Denum format, GC3Denum type, GC3Dsizei width, GC3Dsizei height, GC3Dint alignment, unsigned int* imageSizeInBytes, unsigned int* paddingInBytes)
221 {
222     ASSERT(imageSizeInBytes);
223     ASSERT(alignment == 1 || alignment == 2 || alignment == 4 || alignment == 8);
224     if (width < 0 || height < 0)
225         return GraphicsContext3D::INVALID_VALUE;
226     unsigned int bytesPerComponent, componentsPerPixel;
227     if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent, &componentsPerPixel))
228         return GraphicsContext3D::INVALID_ENUM;
229     if (!width || !height) {
230         *imageSizeInBytes = 0;
231         if (paddingInBytes)
232             *paddingInBytes = 0;
233         return GraphicsContext3D::NO_ERROR;
234     }
235     Checked<uint32_t, RecordOverflow> checkedValue = bytesPerComponent * componentsPerPixel;
236     checkedValue *=  width;
237     if (checkedValue.hasOverflowed())
238         return GraphicsContext3D::INVALID_VALUE;
239     unsigned int validRowSize = checkedValue.unsafeGet();
240     unsigned int padding = 0;
241     unsigned int residual = validRowSize % alignment;
242     if (residual) {
243         padding = alignment - residual;
244         checkedValue += padding;
245     }
246     // Last row needs no padding.
247     checkedValue *= (height - 1);
248     checkedValue += validRowSize;
249     if (checkedValue.hasOverflowed())
250         return GraphicsContext3D::INVALID_VALUE;
251     *imageSizeInBytes = checkedValue.unsafeGet();
252     if (paddingInBytes)
253         *paddingInBytes = padding;
254     return GraphicsContext3D::NO_ERROR;
255 }
256
257 GraphicsContext3D::ImageExtractor::ImageExtractor(Image* image, ImageHtmlDomSource imageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile)
258 {
259     m_image = image;
260     m_imageHtmlDomSource = imageHtmlDomSource;
261     m_extractSucceeded = extractImage(premultiplyAlpha, ignoreGammaAndColorProfile);
262 }
263
264 bool GraphicsContext3D::packImageData( Image* image, const void* pixels, GC3Denum format, GC3Denum type, bool flipY, AlphaOp alphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector<uint8_t>& data)
265 {
266     if (!pixels)
267         return false;
268
269     unsigned packedSize;
270     // Output data is tightly packed (alignment == 1).
271     if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
272         return false;
273     data.resize(packedSize);
274
275     if (!packPixels(reinterpret_cast<const uint8_t*>(pixels), sourceFormat, width, height, sourceUnpackAlignment, format, type, alphaOp, data.data(), flipY))
276         return false;
277     if (ImageObserver* observer = image->imageObserver())
278         observer->didDraw(image);
279     return true;
280 }
281
282 bool GraphicsContext3D::extractImageData(ImageData* imageData, GC3Denum format, GC3Denum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data)
283 {
284     if (!imageData)
285         return false;
286     int width = imageData->width();
287     int height = imageData->height();
288
289     unsigned int packedSize;
290     // Output data is tightly packed (alignment == 1).
291     if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
292         return false;
293     data.resize(packedSize);
294
295     if (!packPixels(imageData->data()->data(), DataFormatRGBA8, width, height, 0, format, type, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing, data.data(), flipY))
296         return false;
297
298     return true;
299 }
300
301 bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int height, GC3Denum format, GC3Denum type, unsigned int unpackAlignment, bool flipY, bool premultiplyAlpha, const void* pixels, Vector<uint8_t>& data)
302 {
303     // Assumes format, type, etc. have already been validated.
304     DataFormat sourceDataFormat = getDataFormat(format, type);
305
306     // Resize the output buffer.
307     unsigned int componentsPerPixel, bytesPerComponent;
308     if (!computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent))
309         return false;
310     unsigned int bytesPerPixel = componentsPerPixel * bytesPerComponent;
311     data.resize(width * height * bytesPerPixel);
312
313     if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width, height, unpackAlignment, format, type, (premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing), data.data(), flipY))
314         return false;
315
316     return true;
317 }
318
319 ALWAYS_INLINE unsigned TexelBytesForFormat(GraphicsContext3D::DataFormat format)
320 {
321     switch (format) {
322     case GraphicsContext3D::DataFormatR8:
323     case GraphicsContext3D::DataFormatA8:
324         return 1;
325     case GraphicsContext3D::DataFormatRA8:
326     case GraphicsContext3D::DataFormatAR8:
327     case GraphicsContext3D::DataFormatRGBA5551:
328     case GraphicsContext3D::DataFormatRGBA4444:
329     case GraphicsContext3D::DataFormatRGB565:
330     case GraphicsContext3D::DataFormatA16F:
331     case GraphicsContext3D::DataFormatR16F:
332         return 2;
333     case GraphicsContext3D::DataFormatRGB8:
334     case GraphicsContext3D::DataFormatBGR8:
335         return 3;
336     case GraphicsContext3D::DataFormatRGBA8:
337     case GraphicsContext3D::DataFormatARGB8:
338     case GraphicsContext3D::DataFormatABGR8:
339     case GraphicsContext3D::DataFormatBGRA8:
340     case GraphicsContext3D::DataFormatR32F:
341     case GraphicsContext3D::DataFormatA32F:
342     case GraphicsContext3D::DataFormatRA16F:
343         return 4;
344     case GraphicsContext3D::DataFormatRGB16F:
345         return 6;
346     case GraphicsContext3D::DataFormatRA32F:
347     case GraphicsContext3D::DataFormatRGBA16F:
348         return 8;
349     case GraphicsContext3D::DataFormatRGB32F:
350         return 12;
351     case GraphicsContext3D::DataFormatRGBA32F:
352         return 16;
353     default:
354         return 0;
355     }
356 }
357
358 bool GraphicsContext3D::packPixels(const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, unsigned destinationFormat, unsigned destinationType, AlphaOp alphaOp, void* destinationData, bool flipY)
359 {
360     int validSrc = width * TexelBytesForFormat(sourceDataFormat);
361     int remainder = sourceUnpackAlignment ? (validSrc % sourceUnpackAlignment) : 0;
362     int srcStride = remainder ? (validSrc + sourceUnpackAlignment - remainder) : validSrc;
363
364     DataFormat dstDataFormat = getDataFormat(destinationFormat, destinationType);
365     int dstStride = width * TexelBytesForFormat(dstDataFormat);
366     if (flipY) {
367         destinationData = static_cast<uint8_t*>(destinationData) + dstStride*(height - 1);
368         dstStride = -dstStride;
369     }
370     if (!hasAlpha(sourceDataFormat) || !hasColor(sourceDataFormat) || !hasColor(dstDataFormat))
371         alphaOp = AlphaDoNothing;
372
373     if (sourceDataFormat == dstDataFormat && alphaOp == AlphaDoNothing) {
374         const uint8_t* ptr = sourceData;
375         const uint8_t* ptrEnd = sourceData + srcStride * height;
376         unsigned rowSize = (dstStride > 0) ? dstStride: -dstStride;
377         uint8_t* dst = static_cast<uint8_t*>(destinationData);
378         while (ptr < ptrEnd) {
379             memcpy(dst, ptr, rowSize);
380             ptr += srcStride;
381             dst += dstStride;
382         }
383         return true;
384     }
385
386     FormatConverter converter(width, height, sourceData, destinationData, srcStride, dstStride);
387     converter.convert(sourceDataFormat, dstDataFormat, alphaOp);
388     if (!converter.success())
389         return false;
390     return true;
391 }
392
393 unsigned GraphicsContext3D::getClearBitsByAttachmentType(GC3Denum attachment)
394 {
395     switch (attachment) {
396     case GraphicsContext3D::COLOR_ATTACHMENT0:
397     case Extensions3D::COLOR_ATTACHMENT1_EXT:
398     case Extensions3D::COLOR_ATTACHMENT2_EXT:
399     case Extensions3D::COLOR_ATTACHMENT3_EXT:
400     case Extensions3D::COLOR_ATTACHMENT4_EXT:
401     case Extensions3D::COLOR_ATTACHMENT5_EXT:
402     case Extensions3D::COLOR_ATTACHMENT6_EXT:
403     case Extensions3D::COLOR_ATTACHMENT7_EXT:
404     case Extensions3D::COLOR_ATTACHMENT8_EXT:
405     case Extensions3D::COLOR_ATTACHMENT9_EXT:
406     case Extensions3D::COLOR_ATTACHMENT10_EXT:
407     case Extensions3D::COLOR_ATTACHMENT11_EXT:
408     case Extensions3D::COLOR_ATTACHMENT12_EXT:
409     case Extensions3D::COLOR_ATTACHMENT13_EXT:
410     case Extensions3D::COLOR_ATTACHMENT14_EXT:
411     case Extensions3D::COLOR_ATTACHMENT15_EXT:
412         return GraphicsContext3D::COLOR_BUFFER_BIT;
413     case GraphicsContext3D::DEPTH_ATTACHMENT:
414         return GraphicsContext3D::DEPTH_BUFFER_BIT;
415     case GraphicsContext3D::STENCIL_ATTACHMENT:
416         return GraphicsContext3D::STENCIL_BUFFER_BIT;
417     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
418         return GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT;
419     default:
420         return 0;
421     }
422 }
423
424 unsigned GraphicsContext3D::getClearBitsByFormat(GC3Denum format)
425 {
426     switch (format) {
427     case GraphicsContext3D::ALPHA:
428     case GraphicsContext3D::LUMINANCE:
429     case GraphicsContext3D::LUMINANCE_ALPHA:
430     case GraphicsContext3D::RGB:
431     case GraphicsContext3D::RGB565:
432     case GraphicsContext3D::RGBA:
433     case GraphicsContext3D::RGBA4:
434     case GraphicsContext3D::RGB5_A1:
435     case Extensions3D::SRGB_EXT:
436     case Extensions3D::SRGB_ALPHA_EXT:
437     case Extensions3D::SRGB8_ALPHA8_EXT:
438         return GraphicsContext3D::COLOR_BUFFER_BIT;
439     case GraphicsContext3D::DEPTH_COMPONENT16:
440     case GraphicsContext3D::DEPTH_COMPONENT:
441         return GraphicsContext3D::DEPTH_BUFFER_BIT;
442     case GraphicsContext3D::STENCIL_INDEX8:
443         return GraphicsContext3D::STENCIL_BUFFER_BIT;
444     case GraphicsContext3D::DEPTH_STENCIL:
445         return GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT;
446     default:
447         return 0;
448     }
449 }
450
451 unsigned GraphicsContext3D::getChannelBitsByFormat(GC3Denum format)
452 {
453     switch (format) {
454     case GraphicsContext3D::ALPHA:
455         return ChannelAlpha;
456     case GraphicsContext3D::LUMINANCE:
457         return ChannelRGB;
458     case GraphicsContext3D::LUMINANCE_ALPHA:
459         return ChannelRGBA;
460     case GraphicsContext3D::RGB:
461     case GraphicsContext3D::RGB565:
462     case Extensions3D::SRGB_EXT:
463         return ChannelRGB;
464     case GraphicsContext3D::RGBA:
465     case GraphicsContext3D::RGBA4:
466     case GraphicsContext3D::RGB5_A1:
467     case Extensions3D::SRGB_ALPHA_EXT:
468         return ChannelRGBA;
469     case GraphicsContext3D::DEPTH_COMPONENT16:
470     case GraphicsContext3D::DEPTH_COMPONENT:
471         return ChannelDepth;
472     case GraphicsContext3D::STENCIL_INDEX8:
473         return ChannelStencil;
474     case GraphicsContext3D::DEPTH_STENCIL:
475         return ChannelDepth | ChannelStencil;
476     default:
477         return 0;
478     }
479 }
480
481 } // namespace WebCore
482
483 #endif // ENABLE(GRAPHICS_CONTEXT_3D)