blob: 481b12dc21773bee30f9914b5ec177f2180c1026 [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.
#include "platform/graphics/gpu/WebGLImageConversion.h"
#include "platform/graphics/ImageObserver.h"
#include "platform/graphics/cpu/arm/WebGLImageConversionNEON.h"
#include "platform/graphics/cpu/mips/WebGLImageConversionMSA.h"
#include "platform/graphics/cpu/x86/WebGLImageConversionSSE.h"
#include "platform/graphics/skia/SkiaUtils.h"
#include "platform/image-decoders/ImageDecoder.h"
#include "third_party/skia/include/core/SkImage.h"
#include "wtf/CheckedNumeric.h"
#include "wtf/PtrUtil.h"
#include <memory>
namespace blink {
namespace {
const float maxInt8Value = INT8_MAX;
const float maxUInt8Value = UINT8_MAX;
const float maxInt16Value = INT16_MAX;
const float maxUInt16Value = UINT16_MAX;
const double maxInt32Value = INT32_MAX;
const double maxUInt32Value = UINT32_MAX;
int8_t ClampMin(int8_t value) {
const static int8_t minInt8Value = INT8_MIN + 1;
return value < minInt8Value ? minInt8Value : value;
}
int16_t ClampMin(int16_t value) {
const static int16_t minInt16Value = INT16_MIN + 1;
return value < minInt16Value ? minInt16Value : value;
}
int32_t ClampMin(int32_t value) {
const static int32_t minInt32Value = INT32_MIN + 1;
return value < minInt32Value ? minInt32Value : value;
}
WebGLImageConversion::DataFormat getDataFormat(GLenum destinationFormat,
GLenum destinationType) {
WebGLImageConversion::DataFormat dstFormat =
WebGLImageConversion::DataFormatRGBA8;
switch (destinationType) {
case GL_BYTE:
switch (destinationFormat) {
case GL_RED:
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR8_S;
break;
case GL_RG:
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG8_S;
break;
case GL_RGB:
case GL_RGB_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGB8_S;
break;
case GL_RGBA:
case GL_RGBA_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGBA8_S;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_UNSIGNED_BYTE:
switch (destinationFormat) {
case GL_RGB:
case GL_RGB_INTEGER:
case GL_SRGB_EXT:
dstFormat = WebGLImageConversion::DataFormatRGB8;
break;
case GL_RGBA:
case GL_RGBA_INTEGER:
case GL_SRGB_ALPHA_EXT:
dstFormat = WebGLImageConversion::DataFormatRGBA8;
break;
case GL_ALPHA:
dstFormat = WebGLImageConversion::DataFormatA8;
break;
case GL_LUMINANCE:
case GL_RED:
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR8;
break;
case GL_RG:
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG8;
break;
case GL_LUMINANCE_ALPHA:
dstFormat = WebGLImageConversion::DataFormatRA8;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_SHORT:
switch (destinationFormat) {
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR16_S;
break;
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG16_S;
break;
case GL_RGB_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGB16_S;
case GL_RGBA_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGBA16_S;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_UNSIGNED_SHORT:
switch (destinationFormat) {
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR16;
break;
case GL_DEPTH_COMPONENT:
dstFormat = WebGLImageConversion::DataFormatD16;
break;
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG16;
break;
case GL_RGB_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGB16;
break;
case GL_RGBA_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGBA16;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_INT:
switch (destinationFormat) {
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR32_S;
break;
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG32_S;
break;
case GL_RGB_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGB32_S;
break;
case GL_RGBA_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGBA32_S;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_UNSIGNED_INT:
switch (destinationFormat) {
case GL_RED_INTEGER:
dstFormat = WebGLImageConversion::DataFormatR32;
break;
case GL_DEPTH_COMPONENT:
dstFormat = WebGLImageConversion::DataFormatD32;
break;
case GL_RG_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRG32;
break;
case GL_RGB_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGB32;
break;
case GL_RGBA_INTEGER:
dstFormat = WebGLImageConversion::DataFormatRGBA32;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_HALF_FLOAT_OES: // OES_texture_half_float
case GL_HALF_FLOAT:
switch (destinationFormat) {
case GL_RGBA:
dstFormat = WebGLImageConversion::DataFormatRGBA16F;
break;
case GL_RGB:
dstFormat = WebGLImageConversion::DataFormatRGB16F;
break;
case GL_RG:
dstFormat = WebGLImageConversion::DataFormatRG16F;
break;
case GL_ALPHA:
dstFormat = WebGLImageConversion::DataFormatA16F;
break;
case GL_LUMINANCE:
case GL_RED:
dstFormat = WebGLImageConversion::DataFormatR16F;
break;
case GL_LUMINANCE_ALPHA:
dstFormat = WebGLImageConversion::DataFormatRA16F;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_FLOAT: // OES_texture_float
switch (destinationFormat) {
case GL_RGBA:
dstFormat = WebGLImageConversion::DataFormatRGBA32F;
break;
case GL_RGB:
dstFormat = WebGLImageConversion::DataFormatRGB32F;
break;
case GL_RG:
dstFormat = WebGLImageConversion::DataFormatRG32F;
break;
case GL_ALPHA:
dstFormat = WebGLImageConversion::DataFormatA32F;
break;
case GL_LUMINANCE:
case GL_RED:
dstFormat = WebGLImageConversion::DataFormatR32F;
break;
case GL_DEPTH_COMPONENT:
dstFormat = WebGLImageConversion::DataFormatD32F;
break;
case GL_LUMINANCE_ALPHA:
dstFormat = WebGLImageConversion::DataFormatRA32F;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case GL_UNSIGNED_SHORT_4_4_4_4:
dstFormat = WebGLImageConversion::DataFormatRGBA4444;
break;
case GL_UNSIGNED_SHORT_5_5_5_1:
dstFormat = WebGLImageConversion::DataFormatRGBA5551;
break;
case GL_UNSIGNED_SHORT_5_6_5:
dstFormat = WebGLImageConversion::DataFormatRGB565;
break;
case GL_UNSIGNED_INT_5_9_9_9_REV:
dstFormat = WebGLImageConversion::DataFormatRGB5999;
break;
case GL_UNSIGNED_INT_24_8:
dstFormat = WebGLImageConversion::DataFormatDS24_8;
break;
case GL_UNSIGNED_INT_10F_11F_11F_REV:
dstFormat = WebGLImageConversion::DataFormatRGB10F11F11F;
break;
case GL_UNSIGNED_INT_2_10_10_10_REV:
dstFormat = WebGLImageConversion::DataFormatRGBA2_10_10_10;
break;
default:
ASSERT_NOT_REACHED();
}
return dstFormat;
}
// The following Float to Half-Float conversion code is from the implementation
// of ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf, "Fast Half
// Float Conversions" by Jeroen van der Zijp, November 2008 (Revised September
// 2010). Specially, the basetable[512] and shifttable[512] are generated as
// follows:
/*
unsigned short basetable[512];
unsigned char shifttable[512];
void generatetables(){
unsigned int i;
int e;
for (i = 0; i < 256; ++i){
e = i - 127;
if (e < -24){ // Very small numbers map to zero
basetable[i | 0x000] = 0x0000;
basetable[i | 0x100] = 0x8000;
shifttable[i | 0x000] = 24;
shifttable[i | 0x100] = 24;
}
else if (e < -14) { // Small numbers map to denorms
basetable[i | 0x000] = (0x0400>>(-e-14));
basetable[i | 0x100] = (0x0400>>(-e-14)) | 0x8000;
shifttable[i | 0x000] = -e-1;
shifttable[i | 0x100] = -e-1;
}
else if (e <= 15){ // Normal numbers just lose precision
basetable[i | 0x000] = ((e+15)<<10);
basetable[i| 0x100] = ((e+15)<<10) | 0x8000;
shifttable[i|0x000] = 13;
shifttable[i|0x100] = 13;
}
else if (e<128){ // Large numbers map to Infinity
basetable[i|0x000] = 0x7C00;
basetable[i|0x100] = 0xFC00;
shifttable[i|0x000] = 24;
shifttable[i|0x100] = 24;
}
else { // Infinity and NaN's stay Infinity and NaN's
basetable[i|0x000] = 0x7C00;
basetable[i|0x100] = 0xFC00;
shifttable[i|0x000] = 13;
shifttable[i|0x100] = 13;
}
}
}
*/
unsigned short baseTable[512] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 17408, 18432, 19456,
20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744,
31744, 31744, 31744, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768,
32768, 32768, 32768, 32768, 32768, 32768, 32768, 32769, 32770, 32772, 32776,
32784, 32800, 32832, 32896, 33024, 33280, 33792, 34816, 35840, 36864, 37888,
38912, 39936, 40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128, 49152,
50176, 51200, 52224, 53248, 54272, 55296, 56320, 57344, 58368, 59392, 60416,
61440, 62464, 63488, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512,
64512, 64512, 64512, 64512, 64512, 64512};
unsigned char shiftTable[512] = {
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 22,
21, 20, 19, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13};
unsigned short convertFloatToHalfFloat(float f) {
unsigned temp = *(reinterpret_cast<unsigned*>(&f));
unsigned signexp = (temp >> 23) & 0x1ff;
return baseTable[signexp] + ((temp & 0x007fffff) >> shiftTable[signexp]);
}
/* BEGIN CODE SHARED WITH MOZILLA FIREFOX */
// The following packing and unpacking routines are expressed in terms of
// function templates and inline functions to achieve generality and speedup.
// Explicit template specializations correspond to the cases that would occur.
// Some code are merged back from Mozilla code in
// http://mxr.mozilla.org/mozilla-central/source/content/canvas/src/WebGLTexelConversions.h
//----------------------------------------------------------------------
// Pixel unpacking routines.
template <int format, typename SourceType, typename DstType>
void unpack(const SourceType*, DstType*, unsigned) {
ASSERT_NOT_REACHED();
}
template <>
void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, uint8_t>(
const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[1];
destination[1] = source[2];
destination[2] = source[3];
destination[3] = source[0];
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, uint8_t>(
const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[3];
destination[1] = source[2];
destination[2] = source[1];
destination[3] = source[0];
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, uint8_t>(
const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
const uint32_t* source32 = reinterpret_cast_ptr<const uint32_t*>(source);
uint32_t* destination32 = reinterpret_cast_ptr<uint32_t*>(destination);
#if CPU(X86) || CPU(X86_64)
SIMD::unpackOneRowOfBGRA8LittleToRGBA8(source32, destination32, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::unpackOneRowOfBGRA8LittleToRGBA8MSA(source32, destination32,
pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
uint32_t bgra = source32[i];
#if CPU(BIG_ENDIAN)
uint32_t brMask = 0xff00ff00;
uint32_t gaMask = 0x00ff00ff;
#else
uint32_t brMask = 0x00ff00ff;
uint32_t gaMask = 0xff00ff00;
#endif
uint32_t rgba = (((bgra >> 16) | (bgra << 16)) & brMask) | (bgra & gaMask);
destination32[i] = rgba;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRGBA5551, uint16_t, uint8_t>(
const uint16_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
#if CPU(X86) || CPU(X86_64)
SIMD::unpackOneRowOfRGBA5551LittleToRGBA8(source, destination, pixelsPerRow);
#endif
#if HAVE(ARM_NEON_INTRINSICS)
SIMD::unpackOneRowOfRGBA5551ToRGBA8(source, destination, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::unpackOneRowOfRGBA5551ToRGBA8MSA(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
uint16_t packedValue = source[0];
uint8_t r = packedValue >> 11;
uint8_t g = (packedValue >> 6) & 0x1F;
uint8_t b = (packedValue >> 1) & 0x1F;
destination[0] = (r << 3) | (r & 0x7);
destination[1] = (g << 3) | (g & 0x7);
destination[2] = (b << 3) | (b & 0x7);
destination[3] = (packedValue & 0x1) ? 0xFF : 0x0;
source += 1;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRGBA4444, uint16_t, uint8_t>(
const uint16_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
#if CPU(X86) || CPU(X86_64)
SIMD::unpackOneRowOfRGBA4444LittleToRGBA8(source, destination, pixelsPerRow);
#endif
#if HAVE(ARM_NEON_INTRINSICS)
SIMD::unpackOneRowOfRGBA4444ToRGBA8(source, destination, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::unpackOneRowOfRGBA4444ToRGBA8MSA(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
uint16_t packedValue = source[0];
uint8_t r = packedValue >> 12;
uint8_t g = (packedValue >> 8) & 0x0F;
uint8_t b = (packedValue >> 4) & 0x0F;
uint8_t a = packedValue & 0x0F;
destination[0] = r << 4 | r;
destination[1] = g << 4 | g;
destination[2] = b << 4 | b;
destination[3] = a << 4 | a;
source += 1;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRA8, uint8_t, uint8_t>(
const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = source[1];
source += 2;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatAR8, uint8_t, uint8_t>(
const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[1];
destination[1] = source[1];
destination[2] = source[1];
destination[3] = source[0];
source += 2;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRGBA8, uint8_t, float>(
const uint8_t* source,
float* destination,
unsigned pixelsPerRow) {
const float scaleFactor = 1.0f / 255.0f;
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
destination[3] = source[3] * scaleFactor;
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatBGRA8, uint8_t, float>(
const uint8_t* source,
float* destination,
unsigned pixelsPerRow) {
const float scaleFactor = 1.0f / 255.0f;
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[2] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[0] * scaleFactor;
destination[3] = source[3] * scaleFactor;
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatABGR8, uint8_t, float>(
const uint8_t* source,
float* destination,
unsigned pixelsPerRow) {
const float scaleFactor = 1.0f / 255.0f;
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[3] * scaleFactor;
destination[1] = source[2] * scaleFactor;
destination[2] = source[1] * scaleFactor;
destination[3] = source[0] * scaleFactor;
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatARGB8, uint8_t, float>(
const uint8_t* source,
float* destination,
unsigned pixelsPerRow) {
const float scaleFactor = 1.0f / 255.0f;
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[1] * scaleFactor;
destination[1] = source[2] * scaleFactor;
destination[2] = source[3] * scaleFactor;
destination[3] = source[0] * scaleFactor;
source += 4;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRA32F, float, float>(
const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = source[1];
source += 2;
destination += 4;
}
}
template <>
void unpack<WebGLImageConversion::DataFormatRGBA2_10_10_10, uint32_t, float>(
const uint32_t* source,
float* destination,
unsigned pixelsPerRow) {
static const float rgbScaleFactor = 1.0f / 1023.0f;
static const float alphaScaleFactor = 1.0f / 3.0f;
for (unsigned i = 0; i < pixelsPerRow; ++i) {
uint32_t packedValue = source[0];
destination[0] = static_cast<float>(packedValue & 0x3FF) * rgbScaleFactor;
destination[1] =
static_cast<float>((packedValue >> 10) & 0x3FF) * rgbScaleFactor;
destination[2] =
static_cast<float>((packedValue >> 20) & 0x3FF) * rgbScaleFactor;
destination[3] = static_cast<float>(packedValue >> 30) * alphaScaleFactor;
source += 1;
destination += 4;
}
}
//----------------------------------------------------------------------
// Pixel packing routines.
//
template <int format, int alphaOp, typename SourceType, typename DstType>
void pack(const SourceType*, DstType*, unsigned) {
ASSERT_NOT_REACHED();
}
template <>
void pack<WebGLImageConversion::DataFormatA8,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[3];
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR8,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR8,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
source += 4;
destination += 1;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatR8,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
#if CPU(X86) || CPU(X86_64)
SIMD::packOneRowOfRGBA8LittleToR8(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA8,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[3];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA8,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
destination[1] = source[3];
source += 4;
destination += 2;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRA8,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
#if CPU(X86) || CPU(X86_64)
SIMD::packOneRowOfRGBA8LittleToRA8(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
destination[1] = source[3];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB8,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB8,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
destination[0] = sourceR;
destination[1] = sourceG;
destination[2] = sourceB;
source += 4;
destination += 3;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRGB8,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
destination[0] = sourceR;
destination[1] = sourceG;
destination[2] = sourceB;
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA8,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
destination[0] = sourceR;
destination[1] = sourceG;
destination[2] = sourceB;
destination[3] = source[3];
source += 4;
destination += 4;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRGBA8,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
#if CPU(X86) || CPU(X86_64)
SIMD::packOneRowOfRGBA8LittleToRGBA8(source, destination, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::packOneRowOfRGBA8LittleToRGBA8MSA(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
destination[0] = sourceR;
destination[1] = sourceG;
destination[2] = sourceB;
destination[3] = source[3];
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA4444,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
#if HAVE(ARM_NEON_INTRINSICS)
SIMD::packOneRowOfRGBA8ToUnsignedShort4444(source, destination, pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
*destination = (((source[0] & 0xF0) << 8) | ((source[1] & 0xF0) << 4) |
(source[2] & 0xF0) | (source[3] >> 4));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA4444,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF0) << 8) | ((sourceG & 0xF0) << 4) |
(sourceB & 0xF0) | (source[3] >> 4));
source += 4;
destination += 1;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRGBA4444,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF0) << 8) | ((sourceG & 0xF0) << 4) |
(sourceB & 0xF0) | (source[3] >> 4));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA5551,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
#if HAVE(ARM_NEON_INTRINSICS)
SIMD::packOneRowOfRGBA8ToUnsignedShort5551(source, destination, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::packOneRowOfRGBA8ToUnsignedShort5551MSA(source, destination,
pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
*destination = (((source[0] & 0xF8) << 8) | ((source[1] & 0xF8) << 3) |
((source[2] & 0xF8) >> 2) | (source[3] >> 7));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA5551,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF8) << 8) | ((sourceG & 0xF8) << 3) |
((sourceB & 0xF8) >> 2) | (source[3] >> 7));
source += 4;
destination += 1;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRGBA5551,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF8) << 8) | ((sourceG & 0xF8) << 3) |
((sourceB & 0xF8) >> 2) | (source[3] >> 7));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB565,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
#if HAVE(ARM_NEON_INTRINSICS)
SIMD::packOneRowOfRGBA8ToUnsignedShort565(source, destination, pixelsPerRow);
#endif
#if HAVE(MIPS_MSA_INTRINSICS)
SIMD::packOneRowOfRGBA8ToUnsignedShort565MSA(source, destination,
pixelsPerRow);
#endif
for (unsigned i = 0; i < pixelsPerRow; ++i) {
*destination = (((source[0] & 0xF8) << 8) | ((source[1] & 0xFC) << 3) |
((source[2] & 0xF8) >> 3));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB565,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF8) << 8) | ((sourceG & 0xFC) << 3) |
((sourceB & 0xF8) >> 3));
source += 4;
destination += 1;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRGB565,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint16_t>(const uint8_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 255.0f / source[3] : 1.0f;
uint8_t sourceR =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
uint8_t sourceG =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
uint8_t sourceB =
static_cast<uint8_t>(static_cast<float>(source[2]) * scaleFactor);
*destination = (((sourceR & 0xF8) << 8) | ((sourceG & 0xFC) << 3) |
((sourceB & 0xF8) >> 3));
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB32F,
WebGLImageConversion::AlphaDoNothing,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB32F,
WebGLImageConversion::AlphaDoPremultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB32F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA32F,
WebGLImageConversion::AlphaDoPremultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
destination[3] = source[3];
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA32F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
destination[3] = source[3];
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatA32F,
WebGLImageConversion::AlphaDoNothing,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[3];
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR32F,
WebGLImageConversion::AlphaDoNothing,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR32F,
WebGLImageConversion::AlphaDoPremultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR32F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = source[0] * scaleFactor;
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA32F,
WebGLImageConversion::AlphaDoNothing,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[3];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA32F,
WebGLImageConversion::AlphaDoPremultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[3];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA32F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = source[0] * scaleFactor;
destination[1] = source[3];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[0]);
destination[1] = convertFloatToHalfFloat(source[1]);
destination[2] = convertFloatToHalfFloat(source[2]);
destination[3] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA16F,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
destination[3] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA16F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
destination[3] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[0]);
destination[1] = convertFloatToHalfFloat(source[1]);
destination[2] = convertFloatToHalfFloat(source[2]);
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB16F,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGB16F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
destination[2] = convertFloatToHalfFloat(source[2] * scaleFactor);
source += 4;
destination += 3;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[0]);
destination[1] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA16F,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRA16F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[0]);
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR16F,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatR16F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatA16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[3]);
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA8_S,
WebGLImageConversion::AlphaDoPremultiply,
int8_t,
int8_t>(const int8_t* source,
int8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[3] = ClampMin(source[3]);
float scaleFactor = static_cast<float>(destination[3]) / maxInt8Value;
destination[0] = static_cast<int8_t>(
static_cast<float>(ClampMin(source[0])) * scaleFactor);
destination[1] = static_cast<int8_t>(
static_cast<float>(ClampMin(source[1])) * scaleFactor);
destination[2] = static_cast<int8_t>(
static_cast<float>(ClampMin(source[2])) * scaleFactor);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA16,
WebGLImageConversion::AlphaDoPremultiply,
uint16_t,
uint16_t>(const uint16_t* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = static_cast<float>(source[3]) / maxUInt16Value;
destination[0] =
static_cast<uint16_t>(static_cast<float>(source[0]) * scaleFactor);
destination[1] =
static_cast<uint16_t>(static_cast<float>(source[1]) * scaleFactor);
destination[2] =
static_cast<uint16_t>(static_cast<float>(source[2]) * scaleFactor);
destination[3] = source[3];
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA16_S,
WebGLImageConversion::AlphaDoPremultiply,
int16_t,
int16_t>(const int16_t* source,
int16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[3] = ClampMin(source[3]);
float scaleFactor = static_cast<float>(destination[3]) / maxInt16Value;
destination[0] = static_cast<int16_t>(
static_cast<float>(ClampMin(source[0])) * scaleFactor);
destination[1] = static_cast<int16_t>(
static_cast<float>(ClampMin(source[1])) * scaleFactor);
destination[2] = static_cast<int16_t>(
static_cast<float>(ClampMin(source[2])) * scaleFactor);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA32,
WebGLImageConversion::AlphaDoPremultiply,
uint32_t,
uint32_t>(const uint32_t* source,
uint32_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
double scaleFactor = static_cast<double>(source[3]) / maxUInt32Value;
destination[0] =
static_cast<uint32_t>(static_cast<double>(source[0]) * scaleFactor);
destination[1] =
static_cast<uint32_t>(static_cast<double>(source[1]) * scaleFactor);
destination[2] =
static_cast<uint32_t>(static_cast<double>(source[2]) * scaleFactor);
destination[3] = source[3];
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA32_S,
WebGLImageConversion::AlphaDoPremultiply,
int32_t,
int32_t>(const int32_t* source,
int32_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[3] = ClampMin(source[3]);
double scaleFactor = static_cast<double>(destination[3]) / maxInt32Value;
destination[0] = static_cast<int32_t>(
static_cast<double>(ClampMin(source[0])) * scaleFactor);
destination[1] = static_cast<int32_t>(
static_cast<double>(ClampMin(source[1])) * scaleFactor);
destination[2] = static_cast<int32_t>(
static_cast<double>(ClampMin(source[2])) * scaleFactor);
source += 4;
destination += 4;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRGBA2_10_10_10,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint32_t>(const float* source,
uint32_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
uint32_t r = static_cast<uint32_t>(source[0] * source[3] * 1023.0f);
uint32_t g = static_cast<uint32_t>(source[1] * source[3] * 1023.0f);
uint32_t b = static_cast<uint32_t>(source[2] * source[3] * 1023.0f);
uint32_t a = static_cast<uint32_t>(source[3] * 3.0f);
destination[0] = (a << 30) | (b << 20) | (g << 10) | r;
source += 4;
destination += 1;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG8,
WebGLImageConversion::AlphaDoNothing,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[1];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG8,
WebGLImageConversion::AlphaDoPremultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = static_cast<float>(source[3]) / maxUInt8Value;
destination[0] =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[1] =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
source += 4;
destination += 2;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRG8,
WebGLImageConversion::AlphaDoUnmultiply,
uint8_t,
uint8_t>(const uint8_t* source,
uint8_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor =
source[3] ? maxUInt8Value / static_cast<float>(source[3]) : 1.0f;
destination[0] =
static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[1] =
static_cast<uint8_t>(static_cast<float>(source[1]) * scaleFactor);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG16F,
WebGLImageConversion::AlphaDoNothing,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = convertFloatToHalfFloat(source[0]);
destination[1] = convertFloatToHalfFloat(source[1]);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG16F,
WebGLImageConversion::AlphaDoPremultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
source += 4;
destination += 2;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRG16F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
uint16_t>(const float* source,
uint16_t* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = convertFloatToHalfFloat(source[0] * scaleFactor);
destination[1] = convertFloatToHalfFloat(source[1] * scaleFactor);
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG32F,
WebGLImageConversion::AlphaDoNothing,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
destination[0] = source[0];
destination[1] = source[1];
source += 4;
destination += 2;
}
}
template <>
void pack<WebGLImageConversion::DataFormatRG32F,
WebGLImageConversion::AlphaDoPremultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
source += 4;
destination += 2;
}
}
// FIXME: this routine is lossy and must be removed.
template <>
void pack<WebGLImageConversion::DataFormatRG32F,
WebGLImageConversion::AlphaDoUnmultiply,
float,
float>(const float* source,
float* destination,
unsigned pixelsPerRow) {
for (unsigned i = 0; i < pixelsPerRow; ++i) {
float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
source += 4;
destination += 2;
}
}
bool HasAlpha(int format) {
return format == WebGLImageConversion::DataFormatA8 ||
format == WebGLImageConversion::DataFormatA16F ||
format == WebGLImageConversion::DataFormatA32F ||
format == WebGLImageConversion::DataFormatRA8 ||
format == WebGLImageConversion::DataFormatAR8 ||
format == WebGLImageConversion::DataFormatRA16F ||
format == WebGLImageConversion::DataFormatRA32F ||
format == WebGLImageConversion::DataFormatRGBA8 ||
format == WebGLImageConversion::DataFormatBGRA8 ||
format == WebGLImageConversion::DataFormatARGB8 ||
format == WebGLImageConversion::DataFormatABGR8 ||
format == WebGLImageConversion::DataFormatRGBA16F ||
format == WebGLImageConversion::DataFormatRGBA32F ||
format == WebGLImageConversion::DataFormatRGBA4444 ||
format == WebGLImageConversion::DataFormatRGBA5551 ||
format == WebGLImageConversion::DataFormatRGBA8_S ||
format == WebGLImageConversion::DataFormatRGBA16 ||
format == WebGLImageConversion::DataFormatRGBA16_S ||
format == WebGLImageConversion::DataFormatRGBA32 ||
format == WebGLImageConversion::DataFormatRGBA32_S ||
format == WebGLImageConversion::DataFormatRGBA2_10_10_10;
}
bool HasColor(int format) {
return format == WebGLImageConversion::DataFormatRGBA8 ||
format == WebGLImageConversion::DataFormatRGBA16F ||
format == WebGLImageConversion::DataFormatRGBA32F ||
format == WebGLImageConversion::DataFormatRGB8 ||
format == WebGLImageConversion::DataFormatRGB16F ||
format == WebGLImageConversion::DataFormatRGB32F ||
format == WebGLImageConversion::DataFormatBGR8 ||
format == WebGLImageConversion::DataFormatBGRA8 ||
format == WebGLImageConversion::DataFormatARGB8 ||
format == WebGLImageConversion::DataFormatABGR8 ||
format == WebGLImageConversion::DataFormatRGBA5551 ||
format == WebGLImageConversion::DataFormatRGBA4444 ||
format == WebGLImageConversion::DataFormatRGB565 ||
format == WebGLImageConversion::DataFormatR8 ||
format == WebGLImageConversion::DataFormatR16F ||
format == WebGLImageConversion::DataFormatR32F ||
format == WebGLImageConversion::DataFormatRA8 ||
format == WebGLImageConversion::DataFormatRA16F ||
format == WebGLImageConversion::DataFormatRA32F ||
format == WebGLImageConversion::DataFormatAR8 ||
format == WebGLImageConversion::DataFormatRGBA8_S ||
format == WebGLImageConversion::DataFormatRGBA16 ||
format == WebGLImageConversion::DataFormatRGBA16_S ||
format == WebGLImageConversion::DataFormatRGBA32 ||
format == WebGLImageConversion::DataFormatRGBA32_S ||
format == WebGLImageConversion::DataFormatRGBA2_10_10_10 ||
format == WebGLImageConversion::DataFormatRGB8_S ||
format == WebGLImageConversion::DataFormatRGB16 ||
format == WebGLImageConversion::DataFormatRGB16_S ||
format == WebGLImageConversion::DataFormatRGB32 ||
format == WebGLImageConversion::DataFormatRGB32_S ||
format == WebGLImageConversion::DataFormatRGB10F11F11F ||
format == WebGLImageConversion::DataFormatRGB5999 ||
format == WebGLImageConversion::DataFormatRG8 ||
format == WebGLImageConversion::DataFormatRG8_S ||
format == WebGLImageConversion::DataFormatRG16 ||
format == WebGLImageConversion::DataFormatRG16_S ||
format == WebGLImageConversion::DataFormatRG32 ||
format == WebGLImageConversion::DataFormatRG32_S ||
format == WebGLImageConversion::DataFormatRG16F ||
format == WebGLImageConversion::DataFormatRG32F ||
format == WebGLImageConversion::DataFormatR8_S ||
format == WebGLImageConversion::DataFormatR16 ||
format == WebGLImageConversion::DataFormatR16_S ||
format == WebGLImageConversion::DataFormatR32 ||
format == WebGLImageConversion::DataFormatR32_S;
}
template <int Format>
struct IsInt8Format {
STATIC_ONLY(IsInt8Format);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA8_S ||
Format == WebGLImageConversion::DataFormatRGB8_S ||
Format == WebGLImageConversion::DataFormatRG8_S ||
Format == WebGLImageConversion::DataFormatR8_S;
};
template <int Format>
struct IsInt16Format {
STATIC_ONLY(IsInt16Format);
static const bool value =
Format == WebGLImageConversion::DataFormatRGBA16_S ||
Format == WebGLImageConversion::DataFormatRGB16_S ||
Format == WebGLImageConversion::DataFormatRG16_S ||
Format == WebGLImageConversion::DataFormatR16_S;
};
template <int Format>
struct IsInt32Format {
STATIC_ONLY(IsInt32Format);
static const bool value =
Format == WebGLImageConversion::DataFormatRGBA32_S ||
Format == WebGLImageConversion::DataFormatRGB32_S ||
Format == WebGLImageConversion::DataFormatRG32_S ||
Format == WebGLImageConversion::DataFormatR32_S;
};
template <int Format>
struct IsUInt8Format {
STATIC_ONLY(IsUInt8Format);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA8 ||
Format == WebGLImageConversion::DataFormatRGB8 ||
Format == WebGLImageConversion::DataFormatRG8 ||
Format == WebGLImageConversion::DataFormatR8 ||
Format == WebGLImageConversion::DataFormatBGRA8 ||
Format == WebGLImageConversion::DataFormatBGR8 ||
Format == WebGLImageConversion::DataFormatARGB8 ||
Format == WebGLImageConversion::DataFormatABGR8 ||
Format == WebGLImageConversion::DataFormatRA8 ||
Format == WebGLImageConversion::DataFormatAR8 ||
Format == WebGLImageConversion::DataFormatA8;
};
template <int Format>
struct IsUInt16Format {
STATIC_ONLY(IsUInt16Format);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA16 ||
Format == WebGLImageConversion::DataFormatRGB16 ||
Format == WebGLImageConversion::DataFormatRG16 ||
Format == WebGLImageConversion::DataFormatR16;
};
template <int Format>
struct IsUInt32Format {
STATIC_ONLY(IsUInt32Format);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA32 ||
Format == WebGLImageConversion::DataFormatRGB32 ||
Format == WebGLImageConversion::DataFormatRG32 ||
Format == WebGLImageConversion::DataFormatR32;
};
template <int Format>
struct IsFloatFormat {
STATIC_ONLY(IsFloatFormat);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA32F ||
Format == WebGLImageConversion::DataFormatRGB32F ||
Format == WebGLImageConversion::DataFormatRA32F ||
Format == WebGLImageConversion::DataFormatR32F ||
Format == WebGLImageConversion::DataFormatA32F ||
Format == WebGLImageConversion::DataFormatRG32F;
};
template <int Format>
struct IsHalfFloatFormat {
STATIC_ONLY(IsHalfFloatFormat);
static const bool value = Format == WebGLImageConversion::DataFormatRGBA16F ||
Format == WebGLImageConversion::DataFormatRGB16F ||
Format == WebGLImageConversion::DataFormatRA16F ||
Format == WebGLImageConversion::DataFormatR16F ||
Format == WebGLImageConversion::DataFormatA16F ||
Format == WebGLImageConversion::DataFormatRG16F;
};
template <int Format>
struct Is32bppFormat {
STATIC_ONLY(Is32bppFormat);
static const bool value =
Format == WebGLImageConversion::DataFormatRGBA2_10_10_10 ||
Format == WebGLImageConversion::DataFormatRGB5999 ||
Format == WebGLImageConversion::DataFormatRGB10F11F11F;
};
template <int Format>
struct Is16bppFormat {
STATIC_ONLY(Is16bppFormat);
static const bool value =
Format == WebGLImageConversion::DataFormatRGBA5551 ||
Format == WebGLImageConversion::DataFormatRGBA4444 ||
Format == WebGLImageConversion::DataFormatRGB565;
};
template <int Format,
bool IsInt8Format = IsInt8Format<Format>::value,
bool IsUInt8Format = IsUInt8Format<Format>::value,
bool IsInt16Format = IsInt16Format<Format>::value,
bool IsUInt16Format = IsUInt16Format<Format>::value,
bool IsInt32Format = IsInt32Format<Format>::value,
bool IsUInt32Format = IsUInt32Format<Format>::value,
bool IsFloat = IsFloatFormat<Format>::value,
bool IsHalfFloat = IsHalfFloatFormat<Format>::value,
bool Is16bpp = Is16bppFormat<Format>::value,
bool Is32bpp = Is32bppFormat<Format>::value>
struct DataTypeForFormat {
STATIC_ONLY(DataTypeForFormat);
typedef double Type; // Use a type that's not used in unpack/pack.
};
template <int Format>
struct DataTypeForFormat<Format,
true,
false,
false,
false,
false,
false,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef int8_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef uint8_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
true,
false,
false,
false,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef int16_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
true,
false,
false,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef uint16_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef int32_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef uint32_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef float Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef uint16_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false> {
STATIC_ONLY(DataTypeForFormat);
typedef uint16_t Type;
};
template <int Format>
struct DataTypeForFormat<Format,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true> {
STATIC_ONLY(DataTypeForFormat);
typedef uint32_t Type;
};
template <int Format>
struct UsesFloatIntermediateFormat {
STATIC_ONLY(UsesFloatIntermediateFormat);
static const bool value =
IsFloatFormat<Format>::value || IsHalfFloatFormat<Format>::value ||
Format == WebGLImageConversion::DataFormatRGBA2_10_10_10 ||
Format == WebGLImageConversion::DataFormatRGB10F11F11F ||
Format == WebGLImageConversion::DataFormatRGB5999;
};
template <int Format>
struct IntermediateFormat {
STATIC_ONLY(IntermediateFormat);
static const int value =
UsesFloatIntermediateFormat<Format>::value
? WebGLImageConversion::DataFormatRGBA32F
: IsInt32Format<Format>::value
? WebGLImageConversion::DataFormatRGBA32_S
: IsUInt32Format<Format>::value
? WebGLImageConversion::DataFormatRGBA32
: IsInt16Format<Format>::value
? WebGLImageConversion::DataFormatRGBA16_S
: (IsUInt16Format<Format>::value ||
Is32bppFormat<Format>::value)
? WebGLImageConversion::DataFormatRGBA16
: IsInt8Format<Format>::value
? WebGLImageConversion::
DataFormatRGBA8_S
: WebGLImageConversion::DataFormatRGBA8;
};
unsigned TexelBytesForFormat(WebGLImageConversion::DataFormat format) {
switch (format) {
case WebGLImageConversion::DataFormatR8:
case WebGLImageConversion::DataFormatR8_S:
case WebGLImageConversion::DataFormatA8:
return 1;
case WebGLImageConversion::DataFormatRG8:
case WebGLImageConversion::DataFormatRG8_S:
case WebGLImageConversion::DataFormatRA8:
case WebGLImageConversion::DataFormatAR8:
case WebGLImageConversion::DataFormatRGBA5551:
case WebGLImageConversion::DataFormatRGBA4444:
case WebGLImageConversion::DataFormatRGB565:
case WebGLImageConversion::DataFormatA16F:
case WebGLImageConversion::DataFormatR16:
case WebGLImageConversion::DataFormatR16_S:
case WebGLImageConversion::DataFormatR16F:
case WebGLImageConversion::DataFormatD16:
return 2;
case WebGLImageConversion::DataFormatRGB8:
case WebGLImageConversion::DataFormatRGB8_S:
case WebGLImageConversion::DataFormatBGR8:
return 3;
case WebGLImageConversion::DataFormatRGBA8:
case WebGLImageConversion::DataFormatRGBA8_S:
case WebGLImageConversion::DataFormatARGB8:
case WebGLImageConversion::DataFormatABGR8:
case WebGLImageConversion::DataFormatBGRA8:
case WebGLImageConversion::DataFormatR32:
case WebGLImageConversion::DataFormatR32_S:
case WebGLImageConversion::DataFormatR32F:
case WebGLImageConversion::DataFormatA32F:
case WebGLImageConversion::DataFormatRA16F:
case WebGLImageConversion::DataFormatRGBA2_10_10_10:
case WebGLImageConversion::DataFormatRGB10F11F11F:
case WebGLImageConversion::DataFormatRGB5999:
case WebGLImageConversion::DataFormatRG16:
case WebGLImageConversion::DataFormatRG16_S:
case WebGLImageConversion::DataFormatRG16F:
case WebGLImageConversion::DataFormatD32:
case WebGLImageConversion::DataFormatD32F:
case WebGLImageConversion::DataFormatDS24_8:
return 4;
case WebGLImageConversion::DataFormatRGB16:
case WebGLImageConversion::DataFormatRGB16_S:
case WebGLImageConversion::DataFormatRGB16F:
return 6;
case WebGLImageConversion::DataFormatRGBA16:
case WebGLImageConversion::DataFormatRGBA16_S:
case WebGLImageConversion::DataFormatRA32F:
case WebGLImageConversion::DataFormatRGBA16F:
case WebGLImageConversion::DataFormatRG32:
case WebGLImageConversion::DataFormatRG32_S:
case WebGLImageConversion::DataFormatRG32F:
return 8;
case WebGLImageConversion::DataFormatRGB32:
case WebGLImageConversion::DataFormatRGB32_S:
case WebGLImageConversion::DataFormatRGB32F:
return 12;
case WebGLImageConversion::DataFormatRGBA32:
case WebGLImageConversion::DataFormatRGBA32_S:
case WebGLImageConversion::DataFormatRGBA32F:
return 16;
default:
return 0;
}
}
/* END CODE SHARED WITH MOZILLA FIREFOX */
class FormatConverter {
STACK_ALLOCATED();
public:
FormatConverter(unsigned width,
unsigned height,
const void* srcStart,
void* dstStart,
int srcStride,
int dstStride)
: m_width(width),
m_height(height),
m_srcStart(srcStart),
m_dstStart(dstStart),
m_srcStride(srcStride),
m_dstStride(dstStride),
m_success(false) {
const unsigned MaxNumberOfComponents = 4;
const unsigned MaxBytesPerComponent = 4;
m_unpackedIntermediateSrcData = wrapArrayUnique(
new uint8_t[m_width * MaxNumberOfComponents * MaxBytesPerComponent]);
ASSERT(m_unpackedIntermediateSrcData.get());
}
void convert(WebGLImageConversion::DataFormat srcFormat,
WebGLImageConversion::DataFormat dstFormat,
WebGLImageConversion::AlphaOp);
bool Success() const { return m_success; }
private:
template <WebGLImageConversion::DataFormat SrcFormat>
void convert(WebGLImageConversion::DataFormat dstFormat,
WebGLImageConversion::AlphaOp);
template <WebGLImageConversion::DataFormat SrcFormat,
WebGLImageConversion::DataFormat DstFormat>
void convert(WebGLImageConversion::AlphaOp);
template <WebGLImageConversion::DataFormat SrcFormat,
WebGLImageConversion::DataFormat DstFormat,
WebGLImageConversion::AlphaOp alphaOp>
void convert();
const unsigned m_width, m_height;
const void* const m_srcStart;
void* const m_dstStart;
const int m_srcStride, m_dstStride;
bool m_success;
std::unique_ptr<uint8_t[]> m_unpackedIntermediateSrcData;
};
void FormatConverter::convert(WebGLImageConversion::DataFormat srcFormat,
WebGLImageConversion::DataFormat dstFormat,
WebGLImageConversion::AlphaOp alphaOp) {
#define FORMATCONVERTER_CASE_SRCFORMAT(SrcFormat) \
case SrcFormat: \
return convert<SrcFormat>(dstFormat, alphaOp);
switch (srcFormat) {
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRA32F)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatARGB8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatABGR8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatAR8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatBGRA8)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA5551)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA4444)
FORMATCONVERTER_CASE_SRCFORMAT(WebGLImageConversion::DataFormatRGBA32F)
FORMATCONVERTER_CASE_SRCFORMAT(
WebGLImageConversion::DataFormatRGBA2_10_10_10)
default:
ASSERT_NOT_REACHED();
}
#undef FORMATCONVERTER_CASE_SRCFORMAT
}
template <WebGLImageConversion::DataFormat SrcFormat>
void FormatConverter::convert(WebGLImageConversion::DataFormat dstFormat,
WebGLImageConversion::AlphaOp alphaOp) {
#define FORMATCONVERTER_CASE_DSTFORMAT(DstFormat) \
case DstFormat: \
return convert<SrcFormat, DstFormat>(alphaOp);
switch (dstFormat) {
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatR32F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatA32F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRA32F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB565)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGB32F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA5551)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA4444)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA32F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA8_S)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA16)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA16_S)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA32)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRGBA32_S)
FORMATCONVERTER_CASE_DSTFORMAT(
WebGLImageConversion::DataFormatRGBA2_10_10_10)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRG8)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRG16F)
FORMATCONVERTER_CASE_DSTFORMAT(WebGLImageConversion::DataFormatRG32F)
default:
ASSERT_NOT_REACHED();
}
#undef FORMATCONVERTER_CASE_DSTFORMAT
}
template <WebGLImageConversion::DataFormat SrcFormat,
WebGLImageConversion::DataFormat DstFormat>
void FormatConverter::convert(WebGLImageConversion::AlphaOp alphaOp) {
#define FORMATCONVERTER_CASE_ALPHAOP(alphaOp) \
case alphaOp: \
return convert<SrcFormat, DstFormat, alphaOp>();
switch (alphaOp) {
FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoNothing)
FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoPremultiply)
FORMATCONVERTER_CASE_ALPHAOP(WebGLImageConversion::AlphaDoUnmultiply)
default:
ASSERT_NOT_REACHED();
}
#undef FORMATCONVERTER_CASE_ALPHAOP
}
template <int Format>
struct SupportsConversionFromDomElements {
STATIC_ONLY(SupportsConversionFromDomElements);
static const bool value =
Format == WebGLImageConversion::DataFormatRGBA8 ||
Format == WebGLImageConversion::DataFormatRGB8 ||
Format == WebGLImageConversion::DataFormatRG8 ||
Format == WebGLImageConversion::DataFormatRA8 ||
Format == WebGLImageConversion::DataFormatR8 ||
Format == WebGLImageConversion::DataFormatRGBA32F ||
Format == WebGLImageConversion::DataFormatRGB32F ||
Format == WebGLImageConversion::DataFormatRG32F ||
Format == WebGLImageConversion::DataFormatRA32F ||
Format == WebGLImageConversion::DataFormatR32F ||
Format == WebGLImageConversion::DataFormatRGBA16F ||
Format == WebGLImageConversion::DataFormatRGB16F ||
Format == WebGLImageConversion::DataFormatRG16F ||
Format == WebGLImageConversion::DataFormatRA16F ||
Format == WebGLImageConversion::DataFormatR16F ||
Format == WebGLImageConversion::DataFormatRGBA5551 ||
Format == WebGLImageConversion::DataFormatRGBA4444 ||
Format == WebGLImageConversion::DataFormatRGB565;
};
template <WebGLImageConversion::DataFormat SrcFormat,
WebGLImageConversion::DataFormat DstFormat,
WebGLImageConversion::AlphaOp alphaOp>
void FormatConverter::convert() {
// Many instantiations of this template function will never be entered, so we
// try to return immediately in these cases to avoid generating useless code.
if (SrcFormat == DstFormat &&
alphaOp == WebGLImageConversion::AlphaDoNothing) {
ASSERT_NOT_REACHED();
return;
}
if (!IsFloatFormat<DstFormat>::value && IsFloatFormat<SrcFormat>::value) {
ASSERT_NOT_REACHED();
return;
}
// Only textures uploaded from DOM elements or ImageData can allow DstFormat
// != SrcFormat.
const bool srcFormatComesFromDOMElementOrImageData =
WebGLImageConversion::srcFormatComeFromDOMElementOrImageData(SrcFormat);
if (!srcFormatComesFromDOMElementOrImageData && SrcFormat != DstFormat) {
ASSERT_NOT_REACHED();
return;
}
// Likewise, only textures uploaded from DOM elements or ImageData can
// possibly need to be unpremultiplied.
if (!srcFormatComesFromDOMElementOrImageData &&
alphaOp == WebGLImageConversion::AlphaDoUnmultiply) {
ASSERT_NOT_REACHED();
return;
}
if (srcFormatComesFromDOMElementOrImageData &&
alphaOp == WebGLImageConversion::AlphaDoUnmultiply &&
!SupportsConversionFromDomElements<DstFormat>::value) {
ASSERT_NOT_REACHED();
return;
}
if ((!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) &&
alphaOp != WebGLImageConversion::AlphaDoNothing) {
ASSERT_NOT_REACHED();
return;
}
// If converting DOM element data to UNSIGNED_INT_5_9_9_9_REV or
// UNSIGNED_INT_10F_11F_11F_REV, we should always switch to FLOAT instead to
// avoid unpacking/packing these two types.
if (srcFormatComesFromDOMElementOrImageData && SrcFormat != DstFormat &&
(DstFormat == WebGLImageConversion::DataFormatRGB5999 ||
DstFormat == WebGLImageConversion::DataFormatRGB10F11F11F)) {
ASSERT_NOT_REACHED();
return;
}
typedef typename DataTypeForFormat<SrcFormat>::Type SrcType;
typedef typename DataTypeForFormat<DstFormat>::Type DstType;
const int IntermFormat = IntermediateFormat<DstFormat>::value;
typedef typename DataTypeForFormat<IntermFormat>::Type IntermType;
const ptrdiff_t srcStrideInElements = m_srcStride / sizeof(SrcType);
const ptrdiff_t dstStrideInElements = m_dstStride / sizeof(DstType);
const bool trivialUnpack = SrcFormat == IntermFormat;
const bool trivialPack = DstFormat == IntermFormat &&
alphaOp == WebGLImageConversion::AlphaDoNothing;
ASSERT(!trivialUnpack || !trivialPack);
const SrcType* srcRowStart = static_cast<const SrcType*>(m_srcStart);
DstType* dstRowStart = static_cast<DstType*>(m_dstStart);
if (trivialUnpack) {
for (size_t i = 0; i < m_height; ++i) {
pack<DstFormat, alphaOp>(srcRowStart, dstRowStart, m_width);
srcRowStart += srcStrideInElements;
dstRowStart += dstStrideInElements;
}
} else if (trivialPack) {
for (size_t i = 0; i < m_height; ++i) {
unpack<SrcFormat>(srcRowStart, dstRowStart, m_width);
srcRowStart += srcStrideInElements;
dstRowStart += dstStrideInElements;
}
} else {
for (size_t i = 0; i < m_height; ++i) {
unpack<SrcFormat>(srcRowStart, reinterpret_cast<IntermType*>(
m_unpackedIntermediateSrcData.get()),
m_width);
pack<DstFormat, alphaOp>(
reinterpret_cast<IntermType*>(m_unpackedIntermediateSrcData.get()),
dstRowStart, m_width);
srcRowStart += srcStrideInElements;
dstRowStart += dstStrideInElements;
}
}
m_success = true;
return;
}
bool frameIsValid(const SkBitmap& frameBitmap) {
return !frameBitmap.isNull() && !frameBitmap.empty() &&
frameBitmap.colorType() == kN32_SkColorType;
}
} // anonymous namespace
WebGLImageConversion::PixelStoreParams::PixelStoreParams()
: alignment(4),
rowLength(0),
imageHeight(0),
skipPixels(0),
skipRows(0),
skipImages(0) {}
bool WebGLImageConversion::computeFormatAndTypeParameters(
GLenum format,
GLenum type,
unsigned* componentsPerPixel,
unsigned* bytesPerComponent) {
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_RED:
case GL_RED_INTEGER:
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL: // Treat it as one component.
*componentsPerPixel = 1;
break;
case GL_LUMINANCE_ALPHA:
case GL_RG:
case GL_RG_INTEGER:
*componentsPerPixel = 2;
break;
case GL_RGB:
case GL_RGB_INTEGER:
case GL_SRGB_EXT: // GL_EXT_sRGB
*componentsPerPixel = 3;
break;
case GL_RGBA:
case GL_RGBA_INTEGER:
case GL_BGRA_EXT: // GL_EXT_texture_format_BGRA8888
case GL_SRGB_ALPHA_EXT: // GL_EXT_sRGB
*componentsPerPixel = 4;
break;
default:
return false;
}
switch (type) {
case GL_BYTE:
*bytesPerComponent = sizeof(GLbyte);
break;
case GL_UNSIGNED_BYTE:
*bytesPerComponent = sizeof(GLubyte);
break;
case GL_SHORT:
*bytesPerComponent = sizeof(GLshort);
break;
case GL_UNSIGNED_SHORT:
*bytesPerComponent = sizeof(GLushort);
break;
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
*componentsPerPixel = 1;
*bytesPerComponent = sizeof(GLushort);
break;
case GL_INT:
*bytesPerComponent = sizeof(GLint);
break;
case GL_UNSIGNED_INT:
*bytesPerComponent = sizeof(GLuint);
break;
case GL_UNSIGNED_INT_24_8_OES:
case GL_UNSIGNED_INT_10F_11F_11F_REV:
case GL_UNSIGNED_INT_5_9_9_9_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
*componentsPerPixel = 1;
*bytesPerComponent = sizeof(GLuint);
break;
case GL_FLOAT: // OES_texture_float
*bytesPerComponent = sizeof(GLfloat);
break;
case GL_HALF_FLOAT:
case GL_HALF_FLOAT_OES: // OES_texture_half_float
*bytesPerComponent = sizeof(GLushort);
break;
default:
return false;
}
return true;
}
GLenum WebGLImageConversion::computeImageSizeInBytes(
GLenum format,
GLenum type,
GLsizei width,
GLsizei height,
GLsizei depth,
const PixelStoreParams& params,
unsigned* imageSizeInBytes,
unsigned* paddingInBytes,
unsigned* skipSizeInBytes) {
ASSERT(imageSizeInBytes);
ASSERT(params.alignment == 1 || params.alignment == 2 ||
params.alignment == 4 || params.alignment == 8);
ASSERT(params.rowLength >= 0 && params.imageHeight >= 0);
ASSERT(params.skipPixels >= 0 && params.skipRows >= 0 &&
params.skipImages >= 0);
if (width < 0 || height < 0 || depth < 0)
return GL_INVALID_VALUE;
if (!width || !height || !depth) {
*imageSizeInBytes = 0;
if (paddingInBytes)
*paddingInBytes = 0;
if (skipSizeInBytes)
*skipSizeInBytes = 0;
return GL_NO_ERROR;
}
int rowLength = params.rowLength > 0 ? params.rowLength : width;
int imageHeight = params.imageHeight > 0 ? params.imageHeight : height;
unsigned bytesPerComponent, componentsPerPixel;
if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent,
&componentsPerPixel))
return GL_INVALID_ENUM;
unsigned bytesPerGroup = bytesPerComponent * componentsPerPixel;
CheckedNumeric<uint32_t> checkedValue = static_cast<uint32_t>(rowLength);
checkedValue *= bytesPerGroup;
if (!checkedValue.IsValid())
return GL_INVALID_VALUE;
unsigned lastRowSize;
if (params.rowLength > 0 && params.rowLength != width) {
CheckedNumeric<uint32_t> tmp = width;
tmp *= bytesPerGroup;
if (!tmp.IsValid())
return GL_INVALID_VALUE;
lastRowSize = tmp.ValueOrDie();
} else {
lastRowSize = checkedValue.ValueOrDie();
}
unsigned padding = 0;
unsigned residual = checkedValue.ValueOrDie() % params.alignment;
if (residual) {
padding = params.alignment - residual;
checkedValue += padding;
}
if (!checkedValue.IsValid())
return GL_INVALID_VALUE;
unsigned paddedRowSize = checkedValue.ValueOrDie();
CheckedNumeric<uint32_t> rows = imageHeight;
rows *= (depth - 1);
// Last image is not affected by IMAGE_HEIGHT parameter.
rows += height;
if (!rows.IsValid())
return GL_INVALID_VALUE;
checkedValue *= (rows.ValueOrDie() - 1);
// Last row is not affected by ROW_LENGTH parameter.
checkedValue += lastRowSize;
if (!checkedValue.IsValid())
return GL_INVALID_VALUE;
*imageSizeInBytes = checkedValue.ValueOrDie();
if (paddingInBytes)
*paddingInBytes = padding;
CheckedNumeric<uint32_t> skipSize = 0;
if (params.skipImages > 0) {
CheckedNumeric<uint32_t> tmp = paddedRowSize;
tmp *= imageHeight;
tmp *= params.skipImages;
if (!tmp.IsValid())
return GL_INVALID_VALUE;
skipSize += tmp.ValueOrDie();
}
if (params.skipRows > 0) {
CheckedNumeric<uint32_t> tmp = paddedRowSize;
tmp *= params.skipRows;
if (!tmp.IsValid())
return GL_INVALID_VALUE;
skipSize += tmp.ValueOrDie();
}
if (params.skipPixels > 0) {
CheckedNumeric<uint32_t> tmp = bytesPerGroup;
tmp *= params.skipPixels;
if (!tmp.IsValid())
return GL_INVALID_VALUE;
skipSize += tmp.ValueOrDie();
}
if (!skipSize.IsValid())
return GL_INVALID_VALUE;
if (skipSizeInBytes)
*skipSizeInBytes = skipSize.ValueOrDie();
checkedValue += skipSize.ValueOrDie();
if (!checkedValue.IsValid())
return GL_INVALID_VALUE;
return GL_NO_ERROR;
}
WebGLImageConversion::ImageExtractor::ImageExtractor(
Image* image,
ImageHtmlDomSource imageHtmlDomSource,
bool premultiplyAlpha,
bool ignoreGammaAndColorProfile) {
m_image = image;
m_imageHtmlDomSource = imageHtmlDomSource;
extractImage(premultiplyAlpha, ignoreGammaAndColorProfile);
}
void WebGLImageConversion::ImageExtractor::extractImage(
bool premultiplyAlpha,
bool ignoreGammaAndColorProfile) {
ASSERT(!m_imagePixelLocker);
if (!m_image)
return;
sk_sp<SkImage> skiaImage = m_image->imageForCurrentFrame();
SkImageInfo info = skiaImage ? SkImageInfo::MakeN32Premul(m_image->width(),
m_image->height())
: SkImageInfo::MakeUnknown();
m_alphaOp = AlphaDoNothing;
bool hasAlpha = skiaImage ? !skiaImage->isOpaque() : true;
if ((!skiaImage || ignoreGammaAndColorProfile ||
(hasAlpha && !premultiplyAlpha)) &&
m_image->data()) {
// Attempt to get raw unpremultiplied image data.
std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create(
m_image->data(), true, ImageDecoder::AlphaNotPremultiplied,
ignoreGammaAndColorProfile
? ImageDecoder::GammaAndColorProfileIgnored
: ImageDecoder::GammaAndColorProfileApplied));
if (!decoder || !decoder->frameCount())
return;
ImageFrame* frame = decoder->frameBufferAtIndex(0);
if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
return;
hasAlpha = frame->hasAlpha();
SkBitmap bitmap = frame->bitmap();
if (!frameIsValid(bitmap))
return;
// TODO(fmalita): Partial frames are not supported currently: only fully
// decoded frames make it through. We could potentially relax this and
// use SkImage::MakeFromBitmap(bitmap) to make a copy.
skiaImage = frame->finalizePixelsAndGetImage();
info = bitmap.info();
if (hasAlpha && premultiplyAlpha)
m_alphaOp = AlphaDoPremultiply;
} else if (!premultiplyAlpha && hasAlpha) {
// 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha
// had been applied and the alpha value for each pixel is 0xFF. This is
// true at present; if it is changed in the future it will need
// adjustment accordingly.
// 2. For texImage2D with HTMLCanvasElement input in which alpha is already
// premultiplied in this port, do AlphaDoUnmultiply if
// UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false.
if (m_imageHtmlDomSource != HtmlDomVideo)
m_alphaOp = AlphaDoUnmultiply;
}
if (!skiaImage)
return;
m_imageSourceFormat = SK_B32_SHIFT ? DataFormatRGBA8 : DataFormatBGRA8;
m_imageSourceUnpackAlignment =
0; // FIXME: this seems to always be zero - why use at all?
ASSERT(skiaImage->width() && skiaImage->height());
m_imageWidth = skiaImage->width();
m_imageHeight = skiaImage->height();
// Fail if the image was downsampled because of memory limits.
if (m_imageWidth != (unsigned)m_image->width() ||
m_imageHeight != (unsigned)m_image->height())
return;
m_imagePixelLocker.emplace(std::move(skiaImage), info.alphaType(),
kN32_SkColorType);
}
unsigned WebGLImageConversion::getChannelBitsByFormat(GLenum format) {
switch (format) {
case GL_ALPHA:
return ChannelAlpha;
case GL_RED:
case GL_RED_INTEGER:
case GL_R8:
case GL_R8_SNORM:
case GL_R8UI:
case GL_R8I:
case GL_R16UI:
case GL_R16I:
case GL_R32UI:
case GL_R32I:
case GL_R16F:
case GL_R32F:
return ChannelRed;
case GL_RG:
case GL_RG_INTEGER:
case GL_RG8:
case GL_RG8_SNORM:
case GL_RG8UI:
case GL_RG8I:
case GL_RG16UI:
case GL_RG16I:
case GL_RG32UI:
case GL_RG32I:
case GL_RG16F:
case GL_RG32F:
return ChannelRG;
case GL_LUMINANCE:
return ChannelRGB;
case GL_LUMINANCE_ALPHA:
return ChannelRGBA;
case GL_RGB:
case GL_RGB_INTEGER:
case GL_RGB8:
case GL_RGB8_SNORM:
case GL_RGB8UI:
case GL_RGB8I:
case GL_RGB16UI:
case GL_RGB16I:
case GL_RGB32UI:
case GL_RGB32I:
case GL_RGB16F:
case GL_RGB32F:
case GL_RGB565:
case GL_R11F_G11F_B10F:
case GL_RGB9_E5:
case GL_SRGB_EXT:
case GL_SRGB8:
return ChannelRGB;
case GL_RGBA:
case GL_RGBA_INTEGER:
case GL_RGBA8:
case GL_RGBA8_SNORM:
case GL_RGBA8UI:
case GL_RGBA8I:
case GL_RGBA16UI:
case GL_RGBA16I:
case GL_RGBA32UI:
case GL_RGBA32I:
case GL_RGBA16F:
case GL_RGBA32F:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGB10_A2:
case GL_RGB10_A2UI:
case GL_SRGB_ALPHA_EXT:
case GL_SRGB8_ALPHA8:
return ChannelRGBA;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32F:
return ChannelDepth;
case GL_STENCIL:
case GL_STENCIL_INDEX8:
return ChannelStencil;
case GL_DEPTH_STENCIL:
case GL_DEPTH24_STENCIL8:
case GL_DEPTH32F_STENCIL8:
return ChannelDepthStencil;
default:
return 0;
}
}
bool WebGLImageConversion::packImageData(Image* image,
const void* pixels,
GLenum format,
GLenum type,
bool flipY,
AlphaOp alphaOp,
DataFormat sourceFormat,
unsigned width,
unsigned height,
unsigned sourceUnpackAlignment,
Vector<uint8_t>& data) {
if (!pixels)
return false;
unsigned packedSize;
// Output data is tightly packed (alignment == 1).
PixelStoreParams params;
params.alignment = 1;
if (computeImageSizeInBytes(format, type, width, height, 1, params,
&packedSize, 0, 0) != GL_NO_ERROR)
return false;
data.resize(packedSize);
if (!packPixels(reinterpret_cast<const uint8_t*>(pixels), sourceFormat, width,
height, sourceUnpackAlignment, format, type, alphaOp,
data.data(), flipY))
return false;
if (ImageObserver* observer = image->getImageObserver())
observer->didDraw(image);
return true;
}
bool WebGLImageConversion::extractImageData(const uint8_t* imageData,
DataFormat sourceDataFormat,
const IntSize& imageDataSize,
GLenum format,
GLenum type,
bool flipY,
bool premultiplyAlpha,
Vector<uint8_t>& data) {
if (!imageData)
return false;
int width = imageDataSize.width();
int height = imageDataSize.height();
unsigned packedSize;
// Output data is tightly packed (alignment == 1).
PixelStoreParams params;
params.alignment = 1;
if (computeImageSizeInBytes(format, type, width, height, 1, params,
&packedSize, 0, 0) != GL_NO_ERROR)
return false;
data.resize(packedSize);
if (!packPixels(imageData, sourceDataFormat, width, height, 0, format, type,
premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing,
data.data(), flipY))
return false;
return true;
}
bool WebGLImageConversion::extractTextureData(unsigned width,
unsigned height,
GLenum format,
GLenum type,
unsigned unpackAlignment,
bool flipY,
bool premultiplyAlpha,
const void* pixels,
Vector<uint8_t>& data) {
// Assumes format, type, etc. have already been validated.
DataFormat sourceDataFormat = getDataFormat(format, type);
// Resize the output buffer.
unsigned int componentsPerPixel, bytesPerComponent;
if (!computeFormatAndTypeParameters(format, type, &componentsPerPixel,
&bytesPerComponent))
return false;
unsigned bytesPerPixel = componentsPerPixel * bytesPerComponent;
data.resize(width * height * bytesPerPixel);
if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width,
height, unpackAlignment, format, type,
(premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing),
data.data(), flipY))
return false;
return true;
}
bool WebGLImageConversion::packPixels(const uint8_t* sourceData,
DataFormat sourceDataFormat,
unsigned width,
unsigned height,
unsigned sourceUnpackAlignment,
unsigned destinationFormat,
unsigned destinationType,
AlphaOp alphaOp,
void* destinationData,
bool flipY) {
int validSrc = width * TexelBytesForFormat(sourceDataFormat);
int remainder =
sourceUnpackAlignment ? (validSrc % sourceUnpackAlignment) : 0;
int srcStride =
remainder ? (validSrc + sourceUnpackAlignment - remainder) : validSrc;
DataFormat dstDataFormat = getDataFormat(destinationFormat, destinationType);
int dstStride = width * TexelBytesForFormat(dstDataFormat);
if (flipY) {
destinationData =
static_cast<uint8_t*>(destinationData) + dstStride * (height - 1);
dstStride = -dstStride;
}
if (!HasAlpha(sourceDataFormat) || !HasColor(sourceDataFormat) ||
!HasColor(dstDataFormat))
alphaOp = AlphaDoNothing;
if (sourceDataFormat == dstDataFormat && alphaOp == AlphaDoNothing) {
const uint8_t* ptr = sourceData;
const uint8_t* ptrEnd = sourceData + srcStride * height;
unsigned rowSize = (dstStride > 0) ? dstStride : -dstStride;
uint8_t* dst = static_cast<uint8_t*>(destinationData);
while (ptr < ptrEnd) {
memcpy(dst, ptr, rowSize);
ptr += srcStride;
dst += dstStride;
}
return true;
}
FormatConverter converter(width, height, sourceData, destinationData,
srcStride, dstStride);
converter.convert(sourceDataFormat, dstDataFormat, alphaOp);
if (!converter.Success())
return false;
return true;
}
void WebGLImageConversion::unpackPixels(const uint16_t* sourceData,
DataFormat sourceDataFormat,
unsigned pixelsPerRow,
uint8_t* destinationData) {
switch (sourceDataFormat) {
case DataFormatRGBA4444: {
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA4444>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
unpack<WebGLImageConversion::DataFormatRGBA4444>(
srcRowStart, destinationData, pixelsPerRow);
} break;
case DataFormatRGBA5551: {
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA5551>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
unpack<WebGLImageConversion::DataFormatRGBA5551>(
srcRowStart, destinationData, pixelsPerRow);
} break;
case DataFormatBGRA8: {
const uint8_t* psrc = (const uint8_t*)sourceData;
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatBGRA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(psrc);
unpack<WebGLImageConversion::DataFormatBGRA8>(
srcRowStart, destinationData, pixelsPerRow);
} break;
default:
break;
}
}
void WebGLImageConversion::packPixels(const uint8_t* sourceData,
DataFormat sourceDataFormat,
unsigned pixelsPerRow,
uint8_t* destinationData) {
switch (sourceDataFormat) {
case DataFormatRA8: {
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
pack<WebGLImageConversion::DataFormatRA8,
WebGLImageConversion::AlphaDoUnmultiply>(
srcRowStart, destinationData, pixelsPerRow);
} break;
case DataFormatR8: {
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
pack<WebGLImageConversion::DataFormatR8,
WebGLImageConversion::AlphaDoUnmultiply>(
srcRowStart, destinationData, pixelsPerRow);
} break;
case DataFormatRGBA8: {
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
pack<WebGLImageConversion::DataFormatRGBA8,
WebGLImageConversion::AlphaDoUnmultiply>(
srcRowStart, destinationData, pixelsPerRow);
} break;
case DataFormatRGBA4444: {
uint16_t* pdst = (uint16_t*)destinationData;
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA4444>::Type DstType;
DstType* dstRowStart = static_cast<DstType*>(pdst);
pack<WebGLImageConversion::DataFormatRGBA4444,
WebGLImageConversion::AlphaDoNothing>(srcRowStart, dstRowStart,
pixelsPerRow);
} break;
case DataFormatRGBA5551: {
uint16_t* pdst = (uint16_t*)destinationData;
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA5551>::Type DstType;
DstType* dstRowStart = static_cast<DstType*>(pdst);
pack<WebGLImageConversion::DataFormatRGBA5551,
WebGLImageConversion::AlphaDoNothing>(srcRowStart, dstRowStart,
pixelsPerRow);
} break;
case DataFormatRGB565: {
uint16_t* pdst = (uint16_t*)destinationData;
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGBA8>::Type SrcType;
const SrcType* srcRowStart = static_cast<const SrcType*>(sourceData);
typedef typename DataTypeForFormat<
WebGLImageConversion::DataFormatRGB565>::Type DstType;
DstType* dstRowStart = static_cast<DstType*>(pdst);
pack<WebGLImageConversion::DataFormatRGB565,
WebGLImageConversion::AlphaDoNothing>(srcRowStart, dstRowStart,
pixelsPerRow);
} break;
default:
break;
}
}
} // namespace blink