|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef WebGLImageConversion_h | 
|  | #define WebGLImageConversion_h | 
|  |  | 
|  | #include "base/memory/scoped_refptr.h" | 
|  | #include "platform/PlatformExport.h" | 
|  | #include "platform/graphics/Image.h" | 
|  | #include "platform/graphics/skia/ImagePixelLocker.h" | 
|  | #include "platform/heap/Heap.h" | 
|  | #include "platform/wtf/Allocator.h" | 
|  | #include "platform/wtf/Optional.h" | 
|  | #include "third_party/khronos/GLES2/gl2.h" | 
|  | #include "third_party/khronos/GLES2/gl2ext.h" | 
|  | #include "third_party/khronos/GLES3/gl3.h" | 
|  |  | 
|  | namespace blink { | 
|  | class Image; | 
|  | class IntSize; | 
|  |  | 
|  | // Helper functions for texture uploading and pixel readback. | 
|  | class PLATFORM_EXPORT WebGLImageConversion final { | 
|  | STATIC_ONLY(WebGLImageConversion); | 
|  |  | 
|  | public: | 
|  | // Attempt to enumerate all possible native image formats to | 
|  | // reduce the amount of temporary allocations during texture | 
|  | // uploading. This enum must be public because it is accessed | 
|  | // by non-member functions. | 
|  | // "_S" postfix indicates signed type. | 
|  | enum DataFormat { | 
|  | kDataFormatRGBA8 = 0, | 
|  | kDataFormatRGBA8_S, | 
|  | kDataFormatRGBA16, | 
|  | kDataFormatRGBA16_S, | 
|  | kDataFormatRGBA32, | 
|  | kDataFormatRGBA32_S, | 
|  | kDataFormatRGBA16F, | 
|  | kDataFormatRGBA32F, | 
|  | kDataFormatRGBA2_10_10_10, | 
|  | kDataFormatRGB8, | 
|  | kDataFormatRGB8_S, | 
|  | kDataFormatRGB16, | 
|  | kDataFormatRGB16_S, | 
|  | kDataFormatRGB32, | 
|  | kDataFormatRGB32_S, | 
|  | kDataFormatRGB16F, | 
|  | kDataFormatRGB32F, | 
|  | kDataFormatBGR8, | 
|  | kDataFormatBGRA8, | 
|  | kDataFormatARGB8, | 
|  | kDataFormatABGR8, | 
|  | kDataFormatRGBA5551, | 
|  | kDataFormatRGBA4444, | 
|  | kDataFormatRGB565, | 
|  | kDataFormatRGB10F11F11F, | 
|  | kDataFormatRGB5999, | 
|  | kDataFormatRG8, | 
|  | kDataFormatRG8_S, | 
|  | kDataFormatRG16, | 
|  | kDataFormatRG16_S, | 
|  | kDataFormatRG32, | 
|  | kDataFormatRG32_S, | 
|  | kDataFormatRG16F, | 
|  | kDataFormatRG32F, | 
|  | kDataFormatR8, | 
|  | kDataFormatR8_S, | 
|  | kDataFormatR16, | 
|  | kDataFormatR16_S, | 
|  | kDataFormatR32, | 
|  | kDataFormatR32_S, | 
|  | kDataFormatR16F, | 
|  | kDataFormatR32F, | 
|  | kDataFormatRA8, | 
|  | kDataFormatRA16F, | 
|  | kDataFormatRA32F, | 
|  | kDataFormatAR8, | 
|  | kDataFormatA8, | 
|  | kDataFormatA16F, | 
|  | kDataFormatA32F, | 
|  | kDataFormatD16, | 
|  | kDataFormatD32, | 
|  | kDataFormatD32F, | 
|  | kDataFormatDS24_8, | 
|  | kDataFormatNumFormats | 
|  | }; | 
|  |  | 
|  | enum ChannelBits { | 
|  | kChannelRed = 1, | 
|  | kChannelGreen = 2, | 
|  | kChannelBlue = 4, | 
|  | kChannelAlpha = 8, | 
|  | kChannelDepth = 16, | 
|  | kChannelStencil = 32, | 
|  | kChannelRG = kChannelRed | kChannelGreen, | 
|  | kChannelRGB = kChannelRed | kChannelGreen | kChannelBlue, | 
|  | kChannelRGBA = kChannelRGB | kChannelAlpha, | 
|  | kChannelDepthStencil = kChannelDepth | kChannelStencil, | 
|  | }; | 
|  |  | 
|  | // Possible alpha operations that may need to occur during | 
|  | // pixel packing. FIXME: kAlphaDoUnmultiply is lossy and must | 
|  | // be removed. | 
|  | enum AlphaOp { | 
|  | kAlphaDoNothing = 0, | 
|  | kAlphaDoPremultiply = 1, | 
|  | kAlphaDoUnmultiply = 2 | 
|  | }; | 
|  |  | 
|  | enum ImageHtmlDomSource { | 
|  | kHtmlDomImage = 0, | 
|  | kHtmlDomCanvas = 1, | 
|  | kHtmlDomVideo = 2, | 
|  | kHtmlDomNone = 3 | 
|  | }; | 
|  |  | 
|  | struct PLATFORM_EXPORT PixelStoreParams final { | 
|  | PixelStoreParams(); | 
|  |  | 
|  | GLint alignment; | 
|  | GLint row_length; | 
|  | GLint image_height; | 
|  | GLint skip_pixels; | 
|  | GLint skip_rows; | 
|  | GLint skip_images; | 
|  | }; | 
|  |  | 
|  | class PLATFORM_EXPORT ImageExtractor final { | 
|  | STACK_ALLOCATED(); | 
|  | WTF_MAKE_NONCOPYABLE(ImageExtractor); | 
|  |  | 
|  | public: | 
|  | ImageExtractor(Image*, | 
|  | ImageHtmlDomSource, | 
|  | bool premultiply_alpha, | 
|  | bool ignore_color_space); | 
|  |  | 
|  | const void* ImagePixelData() { | 
|  | return image_pixel_locker_ ? image_pixel_locker_->Pixels() : nullptr; | 
|  | } | 
|  | unsigned ImageWidth() { return image_width_; } | 
|  | unsigned ImageHeight() { return image_height_; } | 
|  | DataFormat ImageSourceFormat() { return image_source_format_; } | 
|  | AlphaOp ImageAlphaOp() { return alpha_op_; } | 
|  | unsigned ImageSourceUnpackAlignment() { | 
|  | return image_source_unpack_alignment_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Extracts the image and keeps track of its status, such as width, height, | 
|  | // Source Alignment, format, AlphaOp, etc. This needs to lock the resources | 
|  | // or relevant data if needed. | 
|  | void ExtractImage(bool premultiply_alpha, bool ignore_color_space); | 
|  |  | 
|  | Image* image_; | 
|  | Optional<ImagePixelLocker> image_pixel_locker_; | 
|  | ImageHtmlDomSource image_html_dom_source_; | 
|  | unsigned image_width_; | 
|  | unsigned image_height_; | 
|  | DataFormat image_source_format_; | 
|  | AlphaOp alpha_op_; | 
|  | unsigned image_source_unpack_alignment_; | 
|  | }; | 
|  |  | 
|  | // Computes the components per pixel and bytes per component | 
|  | // for the given format and type combination. Returns false if | 
|  | // either was an invalid enum. | 
|  | static bool ComputeFormatAndTypeParameters(GLenum format, | 
|  | GLenum type, | 
|  | unsigned* components_per_pixel, | 
|  | unsigned* bytes_per_component); | 
|  |  | 
|  | // Computes the image size in bytes. If paddingInBytes is not null, padding | 
|  | // is also calculated in return. Returns NO_ERROR if succeed, otherwise | 
|  | // return the suggested GL error indicating the cause of the failure: | 
|  | //   INVALID_VALUE if width/height/depth is negative or overflow happens. | 
|  | //   INVALID_ENUM if format/type is illegal. | 
|  | // Note that imageSizeBytes does not include skipSizeInBytes, but it is | 
|  | // guaranteed if NO_ERROR is returned, adding the two sizes won't cause | 
|  | // overflow. | 
|  | // |paddingInBytes| and |skipSizeInBytes| are optional and can be null, but | 
|  | // the overflow validation is still performed. | 
|  | static GLenum ComputeImageSizeInBytes(GLenum format, | 
|  | GLenum type, | 
|  | GLsizei width, | 
|  | GLsizei height, | 
|  | GLsizei depth, | 
|  | const PixelStoreParams&, | 
|  | unsigned* image_size_in_bytes, | 
|  | unsigned* padding_in_bytes, | 
|  | unsigned* skip_size_in_bytes); | 
|  |  | 
|  | // Check if the format is one of the formats from the ImageData or DOM | 
|  | // elements. The format from ImageData is always RGBA8. The formats from DOM | 
|  | // elements vary with Graphics ports, but can only be RGBA8 or BGRA8. | 
|  | static ALWAYS_INLINE bool SrcFormatComeFromDOMElementOrImageData( | 
|  | DataFormat src_format) { | 
|  | return src_format == kDataFormatBGRA8 || src_format == kDataFormatRGBA8; | 
|  | } | 
|  |  | 
|  | // The input can be either format or internalformat. | 
|  | static unsigned GetChannelBitsByFormat(GLenum); | 
|  |  | 
|  | // The Following functions are implemented in | 
|  | // GraphicsContext3DImagePacking.cpp. | 
|  |  | 
|  | // Packs the contents of the given Image, which is passed in |pixels|, into | 
|  | // the passed Vector according to the given format and type, and obeying the | 
|  | // flipY and AlphaOp flags. Returns true upon success. | 
|  | static bool PackImageData(Image*, | 
|  | const void* pixels, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | bool flip_y, | 
|  | AlphaOp, | 
|  | DataFormat source_format, | 
|  | unsigned source_image_width, | 
|  | unsigned source_image_height, | 
|  | const IntRect& source_image_sub_rectangle, | 
|  | int depth, | 
|  | unsigned source_unpack_alignment, | 
|  | int unpack_image_height, | 
|  | Vector<uint8_t>& data); | 
|  |  | 
|  | // Extracts the contents of the given ImageData into the passed Vector, | 
|  | // packing the pixel data according to the given format and type, | 
|  | // and obeying the flipY and premultiplyAlpha flags. Returns true | 
|  | // upon success. | 
|  | static bool ExtractImageData(const uint8_t* image_data, | 
|  | DataFormat source_data_format, | 
|  | const IntSize& image_data_size, | 
|  | const IntRect& source_image_sub_rectangle, | 
|  | int depth, | 
|  | int unpack_image_height, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | bool flip_y, | 
|  | bool premultiply_alpha, | 
|  | Vector<uint8_t>& data); | 
|  |  | 
|  | // Helper function which extracts the user-supplied texture | 
|  | // data, applying the flipY and premultiplyAlpha parameters. | 
|  | // If the data is not tightly packed according to the passed | 
|  | // unpackAlignment, the output data will be tightly packed. | 
|  | // Returns true if successful, false if any error occurred. | 
|  | static bool ExtractTextureData(unsigned width, | 
|  | unsigned height, | 
|  | GLenum format, | 
|  | GLenum type, | 
|  | const PixelStoreParams& unpack_params, | 
|  | bool flip_y, | 
|  | bool premultiply_alpha, | 
|  | const void* pixels, | 
|  | Vector<uint8_t>& data); | 
|  |  | 
|  | // End GraphicsContext3DImagePacking.cpp functions | 
|  |  | 
|  | private: | 
|  | friend class WebGLImageConversionTest; | 
|  | // Helper for packImageData/extractImageData/extractTextureData, which | 
|  | // implement packing of pixel data into the specified OpenGL destination | 
|  | // format and type. A sourceUnpackAlignment of zero indicates that the source | 
|  | // data is tightly packed. Non-zero values may take a slow path. Destination | 
|  | // data will have no gaps between rows. Implemented in | 
|  | // GraphicsContext3DImagePacking.cpp. | 
|  | static bool PackPixels(const uint8_t* source_data, | 
|  | DataFormat source_data_format, | 
|  | unsigned source_data_width, | 
|  | unsigned source_data_height, | 
|  | const IntRect& source_data_sub_rectangle, | 
|  | int depth, | 
|  | unsigned source_unpack_alignment, | 
|  | int unpack_image_height, | 
|  | unsigned destination_format, | 
|  | unsigned destination_type, | 
|  | AlphaOp, | 
|  | void* destination_data, | 
|  | bool flip_y); | 
|  | static void UnpackPixels(const uint16_t* source_data, | 
|  | DataFormat source_data_format, | 
|  | unsigned pixels_per_row, | 
|  | uint8_t* destination_data); | 
|  | static void PackPixels(const uint8_t* source_data, | 
|  | DataFormat source_data_format, | 
|  | unsigned pixels_per_row, | 
|  | uint8_t* destination_data); | 
|  | }; | 
|  |  | 
|  | }  // namespace blink | 
|  |  | 
|  | #endif  // WebGLImageConversion_h |