1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_
6 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_
7 
8 #include "base/macros.h"
9 #include "base/memory/scoped_refptr.h"
10 #include "base/optional.h"
11 #include "third_party/blink/renderer/platform/graphics/image.h"
12 #include "third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h"
13 #include "third_party/blink/renderer/platform/heap/heap.h"
14 #include "third_party/blink/renderer/platform/platform_export.h"
15 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
16 #include "third_party/khronos/GLES2/gl2.h"
17 #include "third_party/khronos/GLES2/gl2ext.h"
18 #include "third_party/khronos/GLES3/gl3.h"
19 
20 namespace blink {
21 class Image;
22 class IntSize;
23 
24 // Helper functions for texture uploading and pixel readback.
25 class PLATFORM_EXPORT WebGLImageConversion final {
26   STATIC_ONLY(WebGLImageConversion);
27 
28  public:
29   // Attempt to enumerate all possible native image formats to
30   // reduce the amount of temporary allocations during texture
31   // uploading. This enum must be public because it is accessed
32   // by non-member functions.
33   // "_S" postfix indicates signed type.
34   enum DataFormat {
35     kDataFormatRGBA8 = 0,
36     kDataFormatRGBA8_S,
37     kDataFormatRGBA16,
38     kDataFormatRGBA16_S,
39     kDataFormatRGBA32,
40     kDataFormatRGBA32_S,
41     kDataFormatRGBA16F,
42     kDataFormatRGBA32F,
43     kDataFormatRGBA2_10_10_10,
44     kDataFormatRGB8,
45     kDataFormatRGB8_S,
46     kDataFormatRGB16,
47     kDataFormatRGB16_S,
48     kDataFormatRGB32,
49     kDataFormatRGB32_S,
50     kDataFormatRGB16F,
51     kDataFormatRGB32F,
52     kDataFormatBGR8,
53     kDataFormatBGRA8,
54     kDataFormatARGB8,
55     kDataFormatABGR8,
56     kDataFormatRGBA5551,
57     kDataFormatRGBA4444,
58     kDataFormatRGB565,
59     kDataFormatRGB10F11F11F,
60     kDataFormatRGB5999,
61     kDataFormatRG8,
62     kDataFormatRG8_S,
63     kDataFormatRG16,
64     kDataFormatRG16_S,
65     kDataFormatRG32,
66     kDataFormatRG32_S,
67     kDataFormatRG16F,
68     kDataFormatRG32F,
69     kDataFormatR8,
70     kDataFormatR8_S,
71     kDataFormatR16,
72     kDataFormatR16_S,
73     kDataFormatR32,
74     kDataFormatR32_S,
75     kDataFormatR16F,
76     kDataFormatR32F,
77     kDataFormatRA8,
78     kDataFormatRA16F,
79     kDataFormatRA32F,
80     kDataFormatAR8,
81     kDataFormatA8,
82     kDataFormatA16F,
83     kDataFormatA32F,
84     kDataFormatD16,
85     kDataFormatD32,
86     kDataFormatD32F,
87     kDataFormatDS24_8,
88     kDataFormatNumFormats
89   };
90 
91   enum ChannelBits {
92     kChannelRed = 1,
93     kChannelGreen = 2,
94     kChannelBlue = 4,
95     kChannelAlpha = 8,
96     kChannelDepth = 16,
97     kChannelStencil = 32,
98     kChannelRG = kChannelRed | kChannelGreen,
99     kChannelRGB = kChannelRed | kChannelGreen | kChannelBlue,
100     kChannelRGBA = kChannelRGB | kChannelAlpha,
101     kChannelDepthStencil = kChannelDepth | kChannelStencil,
102   };
103 
104   // Possible alpha operations that may need to occur during
105   // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must
106   // be removed.
107   enum AlphaOp {
108     kAlphaDoNothing = 0,
109     kAlphaDoPremultiply = 1,
110     kAlphaDoUnmultiply = 2
111   };
112 
113   enum ImageHtmlDomSource {
114     kHtmlDomImage = 0,
115     kHtmlDomCanvas = 1,
116     kHtmlDomVideo = 2,
117     kHtmlDomNone = 3
118   };
119 
120   struct PLATFORM_EXPORT PixelStoreParams final {
121     PixelStoreParams();
122 
123     GLint alignment;
124     GLint row_length;
125     GLint image_height;
126     GLint skip_pixels;
127     GLint skip_rows;
128     GLint skip_images;
129   };
130 
131   class PLATFORM_EXPORT ImageExtractor final {
132     STACK_ALLOCATED();
133 
134    public:
135     ImageExtractor(Image*,
136                    ImageHtmlDomSource,
137                    bool premultiply_alpha,
138                    bool ignore_color_space);
139 
ImagePixelData()140     const void* ImagePixelData() {
141       return image_pixel_locker_ ? image_pixel_locker_->Pixels() : nullptr;
142     }
ImageWidth()143     unsigned ImageWidth() { return image_width_; }
ImageHeight()144     unsigned ImageHeight() { return image_height_; }
ImageSourceFormat()145     DataFormat ImageSourceFormat() { return image_source_format_; }
ImageAlphaOp()146     AlphaOp ImageAlphaOp() { return alpha_op_; }
ImageSourceUnpackAlignment()147     unsigned ImageSourceUnpackAlignment() {
148       return image_source_unpack_alignment_;
149     }
150 
151    private:
152     // Extracts the image and keeps track of its status, such as width, height,
153     // Source Alignment, format, AlphaOp, etc. This needs to lock the resources
154     // or relevant data if needed.
155     void ExtractImage(bool premultiply_alpha, bool ignore_color_space);
156 
157     Image* image_;
158     base::Optional<ImagePixelLocker> image_pixel_locker_;
159     ImageHtmlDomSource image_html_dom_source_;
160     unsigned image_width_;
161     unsigned image_height_;
162     DataFormat image_source_format_;
163     AlphaOp alpha_op_;
164     unsigned image_source_unpack_alignment_;
165 
166     DISALLOW_COPY_AND_ASSIGN(ImageExtractor);
167   };
168 
169   // Computes the components per pixel and bytes per component
170   // for the given format and type combination. Returns false if
171   // either was an invalid enum.
172   static bool ComputeFormatAndTypeParameters(GLenum format,
173                                              GLenum type,
174                                              unsigned* components_per_pixel,
175                                              unsigned* bytes_per_component);
176 
177   // Computes the image size in bytes. If paddingInBytes is not null, padding
178   // is also calculated in return. Returns NO_ERROR if succeed, otherwise
179   // return the suggested GL error indicating the cause of the failure:
180   //   INVALID_VALUE if width/height/depth is negative or overflow happens.
181   //   INVALID_ENUM if format/type is illegal.
182   // Note that imageSizeBytes does not include skipSizeInBytes, but it is
183   // guaranteed if NO_ERROR is returned, adding the two sizes won't cause
184   // overflow.
185   // |paddingInBytes| and |skipSizeInBytes| are optional and can be null, but
186   // the overflow validation is still performed.
187   static GLenum ComputeImageSizeInBytes(GLenum format,
188                                         GLenum type,
189                                         GLsizei width,
190                                         GLsizei height,
191                                         GLsizei depth,
192                                         const PixelStoreParams&,
193                                         unsigned* image_size_in_bytes,
194                                         unsigned* padding_in_bytes,
195                                         unsigned* skip_size_in_bytes);
196 
197   // Check if the format is one of the formats from the ImageData or DOM
198   // elements. The format from ImageData is always RGBA8. The formats from DOM
199   // elements vary with Graphics ports, but can only be RGBA8 or BGRA8.
SrcFormatComeFromDOMElementOrImageData(DataFormat src_format)200   static ALWAYS_INLINE bool SrcFormatComeFromDOMElementOrImageData(
201       DataFormat src_format) {
202     return src_format == kDataFormatBGRA8 || src_format == kDataFormatRGBA8;
203   }
204 
205   // The input can be either format or internalformat.
206   static unsigned GetChannelBitsByFormat(GLenum);
207 
208   // The Following functions are implemented in
209   // GraphicsContext3DImagePacking.cpp.
210 
211   // Packs the contents of the given Image, which is passed in |pixels|, into
212   // the passed Vector according to the given format and type, and obeying the
213   // flipY and AlphaOp flags. Returns true upon success.
214   static bool PackImageData(Image*,
215                             const void* pixels,
216                             GLenum format,
217                             GLenum type,
218                             bool flip_y,
219                             AlphaOp,
220                             DataFormat source_format,
221                             unsigned source_image_width,
222                             unsigned source_image_height,
223                             const IntRect& source_image_sub_rectangle,
224                             int depth,
225                             unsigned source_unpack_alignment,
226                             int unpack_image_height,
227                             Vector<uint8_t>& data);
228 
229   // Extracts the contents of the given ImageData into the passed Vector,
230   // packing the pixel data according to the given format and type,
231   // and obeying the flipY and premultiplyAlpha flags. Returns true
232   // upon success.
233   static bool ExtractImageData(const uint8_t* image_data,
234                                DataFormat source_data_format,
235                                const IntSize& image_data_size,
236                                const IntRect& source_image_sub_rectangle,
237                                int depth,
238                                int unpack_image_height,
239                                GLenum format,
240                                GLenum type,
241                                bool flip_y,
242                                bool premultiply_alpha,
243                                Vector<uint8_t>& data);
244 
245   // Helper function which extracts the user-supplied texture
246   // data, applying the flipY and premultiplyAlpha parameters.
247   // If the data is not tightly packed according to the passed
248   // unpackAlignment, the output data will be tightly packed.
249   // Returns true if successful, false if any error occurred.
250   static bool ExtractTextureData(unsigned width,
251                                  unsigned height,
252                                  GLenum format,
253                                  GLenum type,
254                                  const PixelStoreParams& unpack_params,
255                                  bool flip_y,
256                                  bool premultiply_alpha,
257                                  const void* pixels,
258                                  Vector<uint8_t>& data);
259 
260   // End GraphicsContext3DImagePacking.cpp functions
261 
262  private:
263   friend class WebGLImageConversionTest;
264   // Helper for packImageData/extractImageData/extractTextureData, which
265   // implement packing of pixel data into the specified OpenGL destination
266   // format and type. A sourceUnpackAlignment of zero indicates that the source
267   // data is tightly packed. Non-zero values may take a slow path. Destination
268   // data will have no gaps between rows. Implemented in
269   // GraphicsContext3DImagePacking.cpp.
270   static bool PackPixels(const uint8_t* source_data,
271                          DataFormat source_data_format,
272                          unsigned source_data_width,
273                          unsigned source_data_height,
274                          const IntRect& source_data_sub_rectangle,
275                          int depth,
276                          unsigned source_unpack_alignment,
277                          int unpack_image_height,
278                          unsigned destination_format,
279                          unsigned destination_type,
280                          AlphaOp,
281                          void* destination_data,
282                          bool flip_y);
283   static void UnpackPixels(const uint16_t* source_data,
284                            DataFormat source_data_format,
285                            unsigned pixels_per_row,
286                            uint8_t* destination_data);
287   static void PackPixels(const uint8_t* source_data,
288                          DataFormat source_data_format,
289                          unsigned pixels_per_row,
290                          uint8_t* destination_data);
291 };
292 
293 }  // namespace blink
294 
295 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_
296