blob: c4349be79d9c0696bad4bf34c3d5c5841f8dd6ae [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_
#include "base/memory/scoped_refptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/khronos/GLES3/gl3.h"
namespace gfx {
class Size;
}
namespace blink {
class Image;
// 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
};
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();
public:
// Extract an SkImage from an Image. If the alpha channel will ultimately
// be premultiplied, then `premultiply_alpha` should be true. If the color
// space of image is to be ignored then `target_color_space` is to be
// nullptr. Otherwise, `target_color_space` should be set to the color space
// that the image will ultimately be converted to.
ImageExtractor(Image*,
bool premultiply_alpha,
sk_sp<SkColorSpace> target_color_space);
ImageExtractor(const ImageExtractor&) = delete;
ImageExtractor& operator=(const ImageExtractor&) = delete;
sk_sp<SkImage> GetSkImage() { return sk_image_; }
private:
sk_sp<SkImage> sk_image_;
};
// Convert a GL format and GL type to a DataFormat. This will return
// kDataFormatNumFormats if combination is invalid.
static DataFormat GetDataFormat(GLenum format, GLenum type);
// Convert a DataFormat to an SkColorType. If there is no exactly matching
// SkColorType, return the specified `default_color_type`.
static SkColorType DataFormatToSkColorType(DataFormat data_format,
SkColorType default_color_type);
// Convert an SkColorType to the most appropriate DataFormat.
static DataFormat SkColorTypeToDataFormat(SkColorType color_type);
// 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 ImageData DOM elements, or
// ImageBitmap. The format from ImageData is always RGBA8. The formats from
// DOM elements vary with Graphics ports, but can only be RGBA8 or BGRA8.
// ImageBitmap can use RGBA16F when colorspace conversion is performed.
static ALWAYS_INLINE bool SrcFormatComesFromDOMElementOrImageData(
DataFormat src_format) {
return src_format == kDataFormatBGRA8 || src_format == kDataFormatRGBA8 ||
src_format == kDataFormatRGBA16F;
}
// 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 SkPixmap into the passed Vector according
// to the given format and type, and obeying the flipY and AlphaOp flags.
// Returns true upon success.
static bool PackSkPixmap(const SkPixmap* source,
GLenum format,
GLenum type,
bool flip_y,
AlphaOp,
const gfx::Rect& source_image_sub_rectangle,
int depth,
unsigned source_unpack_alignment,
int unpack_image_height,
Vector<uint8_t>& data);
// 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 gfx::Rect& 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 void* image_data,
DataFormat source_data_format,
const gfx::Size& image_data_size,
const gfx::Rect& 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 void* source_data,
DataFormat source_data_format,
unsigned source_data_width,
unsigned source_data_height,
const gfx::Rect& 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 // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_GPU_WEBGL_IMAGE_CONVERSION_H_