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