blob: d469ac6dfa5f05149fb9eb81849273f4df626692 [file] [log] [blame]
// 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