blob: 1224bcea2a5aa13efc42078177abe6c46fe0341a [file] [log] [blame]
/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#if ENABLE(3D_CANVAS)
#include "GraphicsContext3D.h"
#include "ArrayBufferView.h"
#include "CheckedInt.h"
#include "DrawingBuffer.h"
#include "Image.h"
#include "ImageData.h"
#include <wtf/OwnArrayPtr.h>
#include <wtf/PassOwnArrayPtr.h>
namespace WebCore {
namespace {
unsigned int bytesPerComponent(GC3Denum type)
{
switch (type) {
case GraphicsContext3D::UNSIGNED_BYTE:
return 1;
case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
return 2;
case GraphicsContext3D::FLOAT:
return 4;
default:
return 1;
}
}
unsigned int componentsPerPixel(GC3Denum format, GC3Denum type)
{
switch (type) {
case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
case GraphicsContext3D::FLOAT:
return 1;
default:
break;
}
switch (format) {
case GraphicsContext3D::ALPHA:
case GraphicsContext3D::LUMINANCE:
return 1;
case GraphicsContext3D::LUMINANCE_ALPHA:
return 2;
case GraphicsContext3D::RGB:
return 3;
case GraphicsContext3D::RGBA:
return 4;
default:
return 4;
}
}
// This function should only be called if width and height is non-zero and
// format/type are valid. Return 0 if overflow happens.
unsigned int imageSizeInBytes(GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type)
{
ASSERT(width > 0 && height > 0);
CheckedInt<uint32_t> checkedWidth(width);
CheckedInt<uint32_t> checkedHeight(height);
CheckedInt<uint32_t> checkedBytesPerPixel(bytesPerComponent(type) * componentsPerPixel(format, type));
CheckedInt<uint32_t> checkedSize = checkedWidth * checkedHeight * checkedBytesPerPixel;
if (checkedSize.valid())
return checkedSize.value();
return 0;
}
uint8_t convertColor16LittleTo8(uint16_t value)
{
return value >> 8;
}
uint8_t convertColor16BigTo8(uint16_t value)
{
return static_cast<uint8_t>(value & 0x00FF);
}
} // anonymous namespace
PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size)
{
return DrawingBuffer::create(this, size);
}
bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type)
{
OwnArrayPtr<unsigned char> zero;
if (width > 0 && height > 0) {
unsigned int size = imageSizeInBytes(width, height, format, type);
if (!size) {
synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return false;
}
zero = adoptArrayPtr(new unsigned char[size]);
if (!zero.get()) {
synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return false;
}
memset(zero.get(), 0, size);
}
return texImage2D(target, level, internalformat, width, height, border, format, type, zero.get());
}
bool GraphicsContext3D::computeFormatAndTypeParameters(GC3Denum format,
GC3Denum type,
unsigned int* componentsPerPixel,
unsigned int* bytesPerComponent)
{
switch (format) {
case GraphicsContext3D::ALPHA:
*componentsPerPixel = 1;
break;
case GraphicsContext3D::LUMINANCE:
*componentsPerPixel = 1;
break;
case GraphicsContext3D::LUMINANCE_ALPHA:
*componentsPerPixel = 2;
break;
case GraphicsContext3D::RGB:
*componentsPerPixel = 3;
break;
case GraphicsContext3D::RGBA:
*componentsPerPixel = 4;
break;
default:
return false;
}
switch (type) {
case GraphicsContext3D::UNSIGNED_BYTE:
*bytesPerComponent = sizeof(unsigned char);
break;
case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
*componentsPerPixel = 1;
*bytesPerComponent = sizeof(unsigned short);
break;
case GraphicsContext3D::FLOAT: // OES_texture_float
*bytesPerComponent = sizeof(float);
break;
default:
return false;
}
return true;
}
bool GraphicsContext3D::extractImageData(Image* image,
GC3Denum format,
GC3Denum type,
bool flipY,
bool premultiplyAlpha,
bool ignoreGammaAndColorProfile,
Vector<uint8_t>& data)
{
if (!image)
return false;
if (!getImageData(image, format, type, premultiplyAlpha, ignoreGammaAndColorProfile, data))
return false;
if (flipY) {
unsigned int componentsPerPixel, bytesPerComponent;
if (!computeFormatAndTypeParameters(format, type,
&componentsPerPixel,
&bytesPerComponent))
return false;
// The image data is tightly packed, and we upload it as such.
unsigned int unpackAlignment = 1;
flipVertically(data.data(), image->width(), image->height(),
componentsPerPixel * bytesPerComponent,
unpackAlignment);
}
return true;
}
bool GraphicsContext3D::extractImageData(ImageData* imageData,
GC3Denum format,
GC3Denum type,
bool flipY,
bool premultiplyAlpha,
Vector<uint8_t>& data)
{
if (!imageData)
return false;
int width = imageData->width();
int height = imageData->height();
int dataBytes = width * height * 4;
data.resize(dataBytes);
if (!packPixels(imageData->data()->data()->data(),
SourceFormatRGBA8,
width,
height,
0,
format,
type,
premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing,
data.data()))
return false;
if (flipY) {
unsigned int componentsPerPixel, bytesPerComponent;
if (!computeFormatAndTypeParameters(format, type,
&componentsPerPixel,
&bytesPerComponent))
return false;
// The image data is tightly packed, and we upload it as such.
unsigned int unpackAlignment = 1;
flipVertically(data.data(), width, height,
componentsPerPixel * bytesPerComponent,
unpackAlignment);
}
return true;
}
bool GraphicsContext3D::extractTextureData(unsigned int width, unsigned int height,
GC3Denum format, GC3Denum type,
unsigned int unpackAlignment,
bool flipY, bool premultiplyAlpha,
const void* pixels,
Vector<uint8_t>& data)
{
// Assumes format, type, etc. have already been validated.
SourceDataFormat sourceDataFormat = SourceFormatRGBA8;
switch (type) {
case UNSIGNED_BYTE:
switch (format) {
case RGBA:
sourceDataFormat = SourceFormatRGBA8;
break;
case RGB:
sourceDataFormat = SourceFormatRGB8;
break;
case ALPHA:
sourceDataFormat = SourceFormatA8;
break;
case LUMINANCE:
sourceDataFormat = SourceFormatR8;
break;
case LUMINANCE_ALPHA:
sourceDataFormat = SourceFormatRA8;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case FLOAT: // OES_texture_float
switch (format) {
case RGBA:
sourceDataFormat = SourceFormatRGBA32F;
break;
case RGB:
sourceDataFormat = SourceFormatRGB32F;
break;
case ALPHA:
sourceDataFormat = SourceFormatA32F;
break;
case LUMINANCE:
sourceDataFormat = SourceFormatR32F;
break;
case LUMINANCE_ALPHA:
sourceDataFormat = SourceFormatRA32F;
break;
default:
ASSERT_NOT_REACHED();
}
break;
case UNSIGNED_SHORT_5_5_5_1:
sourceDataFormat = SourceFormatRGBA5551;
break;
case UNSIGNED_SHORT_4_4_4_4:
sourceDataFormat = SourceFormatRGBA4444;
break;
case UNSIGNED_SHORT_5_6_5:
sourceDataFormat = SourceFormatRGB565;
break;
default:
ASSERT_NOT_REACHED();
}
// Resize the output buffer.
unsigned int componentsPerPixel, bytesPerComponent;
if (!computeFormatAndTypeParameters(format, type,
&componentsPerPixel,
&bytesPerComponent))
return false;
unsigned int 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()))
return false;
// The pixel data is now tightly packed.
if (flipY)
flipVertically(data.data(), width, height, bytesPerPixel, 1);
return true;
}
void GraphicsContext3D::flipVertically(void* imageData,
unsigned int width,
unsigned int height,
unsigned int bytesPerPixel,
unsigned int unpackAlignment)
{
if (!width || !height)
return;
unsigned int validRowBytes = width * bytesPerPixel;
unsigned int totalRowBytes = validRowBytes;
unsigned int remainder = validRowBytes % unpackAlignment;
if (remainder)
totalRowBytes += (unpackAlignment - remainder);
uint8_t* tempRow = new uint8_t[validRowBytes];
uint8_t* data = static_cast<uint8_t*>(imageData);
for (unsigned i = 0; i < height / 2; i++) {
uint8_t* lowRow = data + (totalRowBytes * i);
uint8_t* highRow = data + (totalRowBytes * (height - i - 1));
memcpy(tempRow, lowRow, validRowBytes);
memcpy(lowRow, highRow, validRowBytes);
memcpy(highRow, tempRow, validRowBytes);
}
delete[] tempRow;
}
// These functions can not be static, or gcc will not allow them to be
// used as template parameters. Use an anonymous namespace to prevent
// the need to declare prototypes for them.
namespace {
//----------------------------------------------------------------------
// Pixel unpacking routines.
void unpackRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
destination[3] = source[3];
}
void unpackRGBA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[0]);
destination[1] = convertColor16LittleTo8(source[1]);
destination[2] = convertColor16LittleTo8(source[2]);
destination[3] = convertColor16LittleTo8(source[3]);
}
void unpackRGBA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[0]);
destination[1] = convertColor16BigTo8(source[1]);
destination[2] = convertColor16BigTo8(source[2]);
destination[3] = convertColor16BigTo8(source[3]);
}
void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
destination[3] = 0xFF;
}
void unpackRGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[0]);
destination[1] = convertColor16LittleTo8(source[1]);
destination[2] = convertColor16LittleTo8(source[2]);
destination[3] = 0xFF;
}
void unpackRGB16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[0]);
destination[1] = convertColor16BigTo8(source[1]);
destination[2] = convertColor16BigTo8(source[2]);
destination[3] = 0xFF;
}
void unpackBGR8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[2];
destination[1] = source[1];
destination[2] = source[0];
destination[3] = 0xFF;
}
void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[1];
destination[1] = source[2];
destination[2] = source[3];
destination[3] = source[0];
}
void unpackARGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[1]);
destination[1] = convertColor16LittleTo8(source[2]);
destination[2] = convertColor16LittleTo8(source[3]);
destination[3] = convertColor16LittleTo8(source[0]);
}
void unpackARGB16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[1]);
destination[1] = convertColor16BigTo8(source[2]);
destination[2] = convertColor16BigTo8(source[3]);
destination[3] = convertColor16BigTo8(source[0]);
}
void unpackABGR8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[3];
destination[1] = source[2];
destination[2] = source[1];
destination[3] = source[0];
}
void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[2];
destination[1] = source[1];
destination[2] = source[0];
destination[3] = source[3];
}
void unpackBGRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[2]);
destination[1] = convertColor16LittleTo8(source[1]);
destination[2] = convertColor16LittleTo8(source[0]);
destination[3] = convertColor16LittleTo8(source[3]);
}
void unpackBGRA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[2]);
destination[1] = convertColor16BigTo8(source[1]);
destination[2] = convertColor16BigTo8(source[0]);
destination[3] = convertColor16BigTo8(source[3]);
}
void unpackRGBA5551ToRGBA8(const uint16_t* source, uint8_t* destination)
{
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;
}
void unpackRGBA4444ToRGBA8(const uint16_t* source, uint8_t* destination)
{
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;
}
void unpackRGB565ToRGBA8(const uint16_t* source, uint8_t* destination)
{
uint16_t packedValue = source[0];
uint8_t r = packedValue >> 11;
uint8_t g = (packedValue >> 5) & 0x3F;
uint8_t b = packedValue & 0x1F;
destination[0] = (r << 3) | (r & 0x7);
destination[1] = (g << 2) | (g & 0x3);
destination[2] = (b << 3) | (b & 0x7);
destination[3] = 0xFF;
}
void unpackR8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = 0xFF;
}
void unpackR16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[0]);
destination[1] = convertColor16LittleTo8(source[0]);
destination[2] = convertColor16LittleTo8(source[0]);
destination[3] = 0xFF;
}
void unpackR16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[0]);
destination[1] = convertColor16BigTo8(source[0]);
destination[2] = convertColor16BigTo8(source[0]);
destination[3] = 0xFF;
}
void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = source[1];
}
void unpackRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[0]);
destination[1] = convertColor16LittleTo8(source[0]);
destination[2] = convertColor16LittleTo8(source[0]);
destination[3] = convertColor16LittleTo8(source[1]);
}
void unpackRA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[0]);
destination[1] = convertColor16BigTo8(source[0]);
destination[2] = convertColor16BigTo8(source[0]);
destination[3] = convertColor16BigTo8(source[1]);
}
void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[1];
destination[1] = source[1];
destination[2] = source[1];
destination[3] = source[0];
}
void unpackAR16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16LittleTo8(source[1]);
destination[1] = convertColor16LittleTo8(source[1]);
destination[2] = convertColor16LittleTo8(source[1]);
destination[3] = convertColor16LittleTo8(source[0]);
}
void unpackAR16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = convertColor16BigTo8(source[1]);
destination[1] = convertColor16BigTo8(source[1]);
destination[2] = convertColor16BigTo8(source[1]);
destination[3] = convertColor16BigTo8(source[0]);
}
void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = 0x0;
destination[1] = 0x0;
destination[2] = 0x0;
destination[3] = source[0];
}
void unpackA16LittleToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = 0x0;
destination[1] = 0x0;
destination[2] = 0x0;
destination[3] = convertColor16LittleTo8(source[0]);
}
void unpackA16BigToRGBA8(const uint16_t* source, uint8_t* destination)
{
destination[0] = 0x0;
destination[1] = 0x0;
destination[2] = 0x0;
destination[3] = convertColor16BigTo8(source[0]);
}
void unpackRGB32FToRGBA32F(const float* source, float* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
destination[3] = 1;
}
void unpackR32FToRGBA32F(const float* source, float* destination)
{
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = 1;
}
void unpackRA32FToRGBA32F(const float* source, float* destination)
{
destination[0] = source[0];
destination[1] = source[0];
destination[2] = source[0];
destination[3] = source[1];
}
void unpackA32FToRGBA32F(const float* source, float* destination)
{
destination[0] = 0;
destination[1] = 0;
destination[2] = 0;
destination[3] = source[0];
}
//----------------------------------------------------------------------
// Pixel packing routines.
//
void packRGBA8ToA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[3];
}
void packRGBA8ToR8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
}
void packRGBA8ToR8Premultiply(const uint8_t* source, uint8_t* destination)
{
float scaleFactor = source[3] / 255.0f;
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToR8Unmultiply(const uint8_t* source, uint8_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
}
void packRGBA8ToRA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[3];
}
void packRGBA8ToRA8Premultiply(const uint8_t* source, uint8_t* destination)
{
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];
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToRA8Unmultiply(const uint8_t* source, uint8_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 1.0f);
uint8_t sourceR = static_cast<uint8_t>(static_cast<float>(source[0]) * scaleFactor);
destination[0] = sourceR;
destination[1] = source[3];
}
void packRGBA8ToRGB8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
}
void packRGBA8ToRGB8Premultiply(const uint8_t* source, uint8_t* destination)
{
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;
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToRGB8Unmultiply(const uint8_t* source, uint8_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 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;
}
// This is only used when the source format is different than SourceFormatRGBA8.
void packRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
destination[3] = source[3];
}
void packRGBA8ToRGBA8Premultiply(const uint8_t* source, uint8_t* destination)
{
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];
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToRGBA8Unmultiply(const uint8_t* source, uint8_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 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];
}
void packRGBA8ToUnsignedShort4444(const uint8_t* source, uint16_t* destination)
{
*destination = (((source[0] & 0xF0) << 8)
| ((source[1] & 0xF0) << 4)
| (source[2] & 0xF0)
| (source[3] >> 4));
}
void packRGBA8ToUnsignedShort4444Premultiply(const uint8_t* source, uint16_t* destination)
{
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));
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToUnsignedShort4444Unmultiply(const uint8_t* source, uint16_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 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));
}
void packRGBA8ToUnsignedShort5551(const uint8_t* source, uint16_t* destination)
{
*destination = (((source[0] & 0xF8) << 8)
| ((source[1] & 0xF8) << 3)
| ((source[2] & 0xF8) >> 2)
| (source[3] >> 7));
}
void packRGBA8ToUnsignedShort5551Premultiply(const uint8_t* source, uint16_t* destination)
{
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));
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToUnsignedShort5551Unmultiply(const uint8_t* source, uint16_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 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));
}
void packRGBA8ToUnsignedShort565(const uint8_t* source, uint16_t* destination)
{
*destination = (((source[0] & 0xF8) << 8)
| ((source[1] & 0xFC) << 3)
| ((source[2] & 0xF8) >> 3));
}
void packRGBA8ToUnsignedShort565Premultiply(const uint8_t* source, uint16_t* destination)
{
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));
}
// FIXME: this routine is lossy and must be removed.
void packRGBA8ToUnsignedShort565Unmultiply(const uint8_t* source, uint16_t* destination)
{
float scaleFactor = 1.0f / (source[3] ? source[3] / 255.0f : 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));
}
void packRGBA32FToRGB32F(const float* source, float* destination)
{
destination[0] = source[0];
destination[1] = source[1];
destination[2] = source[2];
}
void packRGBA32FToRGB32FPremultiply(const float* source, float* destination)
{
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
}
void packRGBA32FToRGBA32FPremultiply(const float* source, float* destination)
{
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = source[1] * scaleFactor;
destination[2] = source[2] * scaleFactor;
destination[3] = source[3];
}
void packRGBA32FToA32F(const float* source, float* destination)
{
destination[0] = source[3];
}
void packRGBA32FToR32F(const float* source, float* destination)
{
destination[0] = source[0];
}
void packRGBA32FToR32FPremultiply(const float* source, float* destination)
{
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
}
void packRGBA32FToRA32F(const float* source, float* destination)
{
destination[0] = source[0];
destination[1] = source[3];
}
void packRGBA32FToRA32FPremultiply(const float* source, float* destination)
{
float scaleFactor = source[3];
destination[0] = source[0] * scaleFactor;
destination[1] = scaleFactor;
}
} // anonymous namespace
// This is used whenever unpacking is necessary; i.e., the source data
// is not in RGBA8/RGBA32F format, or the unpack alignment specifies
// that rows are not tightly packed.
template<typename SourceType, typename IntermediateType, typename DestType,
void unpackingFunc(const SourceType*, IntermediateType*),
void packingFunc(const IntermediateType*, DestType*)>
static void doUnpackingAndPacking(const SourceType* sourceData,
unsigned int width,
unsigned int height,
unsigned int sourceElementsPerPixel,
unsigned int sourceElementsPerRow,
DestType* destinationData,
unsigned int destinationElementsPerPixel)
{
if (!sourceElementsPerRow) {
unsigned int numElements = width * height * sourceElementsPerPixel;
const SourceType* endPointer = sourceData + numElements;
IntermediateType temporaryRGBAData[4];
while (sourceData < endPointer) {
unpackingFunc(sourceData, temporaryRGBAData);
packingFunc(temporaryRGBAData, destinationData);
sourceData += sourceElementsPerPixel;
destinationData += destinationElementsPerPixel;
}
} else {
IntermediateType temporaryRGBAData[4];
for (unsigned int y = 0; y < height; ++y) {
const SourceType* currentSource = sourceData;
for (unsigned int x = 0; x < width; ++x) {
unpackingFunc(currentSource, temporaryRGBAData);
packingFunc(temporaryRGBAData, destinationData);
currentSource += sourceElementsPerPixel;
destinationData += destinationElementsPerPixel;
}
sourceData += sourceElementsPerRow;
}
}
}
template<typename SourceType>
static void computeIncrementParameters(unsigned int width,
unsigned int bytesPerPixel,
unsigned int unpackAlignment,
unsigned int* sourceElementsPerPixel,
unsigned int* sourceElementsPerRow)
{
unsigned int elementSizeInBytes = sizeof(SourceType);
ASSERT(elementSizeInBytes <= bytesPerPixel);
ASSERT(!(bytesPerPixel % elementSizeInBytes));
unsigned int validRowBytes = width * bytesPerPixel;
unsigned int totalRowBytes = validRowBytes;
if (unpackAlignment) {
unsigned int remainder = validRowBytes % unpackAlignment;
if (remainder)
totalRowBytes += (unpackAlignment - remainder);
}
*sourceElementsPerPixel = bytesPerPixel / elementSizeInBytes;
if (validRowBytes == totalRowBytes)
*sourceElementsPerRow = 0;
else
*sourceElementsPerRow = totalRowBytes / elementSizeInBytes;
}
// This handles all conversions with a faster path for tightly packed RGBA8 source data.
template<typename DestType, void packingFunc(const uint8_t*, DestType*)>
static void doPacking(const void* sourceData,
GraphicsContext3D::SourceDataFormat sourceDataFormat,
unsigned int width,
unsigned int height,
unsigned int sourceUnpackAlignment,
DestType* destinationData,
unsigned int destinationElementsPerPixel)
{
switch (sourceDataFormat) {
case GraphicsContext3D::SourceFormatRGBA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
if (!sourceElementsPerRow) {
const uint8_t* source = static_cast<const uint8_t*>(sourceData);
unsigned int numElements = width * height * 4;
const uint8_t* endPointer = source + numElements;
while (source < endPointer) {
packingFunc(source, destinationData);
source += sourceElementsPerPixel;
destinationData += destinationElementsPerPixel;
}
} else {
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGBA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
}
break;
}
case GraphicsContext3D::SourceFormatRGBA16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGBA16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGB8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGB16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGB16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatBGR8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatARGB8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatARGB16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatARGB16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatABGR8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackABGR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatBGRA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatBGRA16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatBGRA16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGBA5551: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA5551ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGBA4444: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGBA4444ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRGB565: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRGB565ToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatR8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatR16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatR16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRA16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRA16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatAR8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatAR16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatAR16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint8_t, uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatA16Little: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatA16Big: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<uint16_t, uint8_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
default:
ASSERT(false);
}
}
// This specialized routine is used only for floating-point texture uploads. It
// does not need to be as general as doPacking, above; because there are
// currently no native floating-point image formats in WebKit, there are only a
// few upload paths.
template<void packingFunc(const float*, float*)>
static void doFloatingPointPacking(const void* sourceData,
GraphicsContext3D::SourceDataFormat sourceDataFormat,
unsigned int width,
unsigned int height,
unsigned int sourceUnpackAlignment,
float* destinationData,
unsigned int destinationElementsPerPixel)
{
switch (sourceDataFormat) {
case GraphicsContext3D::SourceFormatRGBA8: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<float>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
ASSERT(!sourceElementsPerRow); // Guaranteed because each color channel is sizeof(float) bytes.
const float* source = static_cast<const float*>(sourceData);
unsigned int numElements = width * height * 4;
const float* endPointer = source + numElements;
while (source < endPointer) {
packingFunc(source, destinationData);
source += sourceElementsPerPixel;
destinationData += destinationElementsPerPixel;
}
break;
}
case GraphicsContext3D::SourceFormatRGB32F: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<float>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<float, float, float, unpackRGB32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatR32F: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<float, float, float, unpackR32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatRA32F: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<float>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<float, float, float, unpackRA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
case GraphicsContext3D::SourceFormatA32F: {
unsigned int sourceElementsPerPixel, sourceElementsPerRow;
computeIncrementParameters<float>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow);
doUnpackingAndPacking<float, float, float, unpackA32FToRGBA32F, packingFunc>(static_cast<const float*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel);
break;
}
default:
ASSERT_NOT_REACHED();
}
}
bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
GraphicsContext3D::SourceDataFormat sourceDataFormat,
unsigned int width,
unsigned int height,
unsigned int sourceUnpackAlignment,
unsigned int destinationFormat,
unsigned int destinationType,
AlphaOp alphaOp,
void* destinationData)
{
switch (destinationType) {
case UNSIGNED_BYTE: {
uint8_t* destination = static_cast<uint8_t*>(destinationData);
if (sourceDataFormat == SourceFormatRGBA8 && destinationFormat == RGBA && sourceUnpackAlignment <= 4 && alphaOp == AlphaDoNothing) {
// No conversion necessary.
memcpy(destinationData, sourceData, width * height * 4);
break;
}
switch (destinationFormat) {
case RGB:
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint8_t, packRGBA8ToRGB8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
break;
case AlphaDoPremultiply:
doPacking<uint8_t, packRGBA8ToRGB8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
break;
case AlphaDoUnmultiply:
doPacking<uint8_t, packRGBA8ToRGB8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
break;
}
break;
case RGBA:
switch (alphaOp) {
case AlphaDoNothing:
ASSERT(sourceDataFormat != SourceFormatRGBA8 || sourceUnpackAlignment > 4); // Handled above with fast case.
doPacking<uint8_t, packRGBA8ToRGBA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
break;
case AlphaDoPremultiply:
doPacking<uint8_t, packRGBA8ToRGBA8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
break;
case AlphaDoUnmultiply:
doPacking<uint8_t, packRGBA8ToRGBA8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
break;
default:
ASSERT_NOT_REACHED();
}
break;
case ALPHA:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the alpha channel is chosen
// from the RGBA data.
doPacking<uint8_t, packRGBA8ToA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case LUMINANCE:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the red channel is chosen
// from the RGBA data.
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint8_t, packRGBA8ToR8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoPremultiply:
doPacking<uint8_t, packRGBA8ToR8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoUnmultiply:
doPacking<uint8_t, packRGBA8ToR8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
}
break;
case LUMINANCE_ALPHA:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the red and alpha channels
// are chosen from the RGBA data.
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint8_t, packRGBA8ToRA8>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
break;
case AlphaDoPremultiply:
doPacking<uint8_t, packRGBA8ToRA8Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
break;
case AlphaDoUnmultiply:
doPacking<uint8_t, packRGBA8ToRA8Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
break;
}
break;
}
break;
}
case UNSIGNED_SHORT_4_4_4_4: {
uint16_t* destination = static_cast<uint16_t*>(destinationData);
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint16_t, packRGBA8ToUnsignedShort4444>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoPremultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort4444Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoUnmultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort4444Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
}
break;
}
case UNSIGNED_SHORT_5_5_5_1: {
uint16_t* destination = static_cast<uint16_t*>(destinationData);
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint16_t, packRGBA8ToUnsignedShort5551>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoPremultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort5551Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoUnmultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort5551Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
}
break;
}
case UNSIGNED_SHORT_5_6_5: {
uint16_t* destination = static_cast<uint16_t*>(destinationData);
switch (alphaOp) {
case AlphaDoNothing:
doPacking<uint16_t, packRGBA8ToUnsignedShort565>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoPremultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort565Premultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoUnmultiply:
doPacking<uint16_t, packRGBA8ToUnsignedShort565Unmultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
}
break;
}
case FLOAT: {
// OpenGL ES, and therefore WebGL, require that the format and
// internalformat be identical, which implies that the source and
// destination formats will both be floating-point in this branch -- at
// least, until WebKit supports floating-point image formats natively.
ASSERT(sourceDataFormat == SourceFormatRGBA32F || sourceDataFormat == SourceFormatRGB32F
|| sourceDataFormat == SourceFormatRA32F || sourceDataFormat == SourceFormatR32F
|| sourceDataFormat == SourceFormatA32F);
// Because WebKit doesn't use floating-point color channels for anything
// internally, there's no chance we have to do a (lossy) unmultiply
// operation.
ASSERT(alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply);
// For the source formats with an even number of channels (RGBA32F,
// RA32F) it is guaranteed that the pixel data is tightly packed because
// unpack alignment <= sizeof(float) * number of channels.
float* destination = static_cast<float*>(destinationData);
if (alphaOp == AlphaDoNothing
&& ((sourceDataFormat == SourceFormatRGBA32F && destinationFormat == RGBA)
|| (sourceDataFormat == SourceFormatRA32F && destinationFormat == LUMINANCE_ALPHA))) {
// No conversion necessary.
int numChannels = (sourceDataFormat == SourceFormatRGBA32F ? 4 : 2);
memcpy(destinationData, sourceData, width * height * numChannels * sizeof(float));
break;
}
switch (destinationFormat) {
case RGB:
switch (alphaOp) {
case AlphaDoNothing:
doFloatingPointPacking<packRGBA32FToRGB32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
break;
case AlphaDoPremultiply:
doFloatingPointPacking<packRGBA32FToRGB32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 3);
break;
default:
ASSERT_NOT_REACHED();
}
break;
case RGBA:
// AlphaDoNothing is handled above with fast path.
ASSERT(alphaOp == AlphaDoPremultiply);
doFloatingPointPacking<packRGBA32FToRGBA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 4);
break;
case ALPHA:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the alpha channel is chosen
// from the RGBA data.
doFloatingPointPacking<packRGBA32FToA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case LUMINANCE:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the red channel is chosen
// from the RGBA data.
switch (alphaOp) {
case AlphaDoNothing:
doFloatingPointPacking<packRGBA32FToR32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
case AlphaDoPremultiply:
doFloatingPointPacking<packRGBA32FToR32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 1);
break;
default:
ASSERT_NOT_REACHED();
}
break;
case LUMINANCE_ALPHA:
// From the desktop OpenGL conversion rules (OpenGL 2.1
// specification, Table 3.15), the red and alpha channels
// are chosen from the RGBA data.
switch (alphaOp) {
case AlphaDoNothing:
doFloatingPointPacking<packRGBA32FToRA32F>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
break;
case AlphaDoPremultiply:
doFloatingPointPacking<packRGBA32FToRA32FPremultiply>(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, 2);
break;
default:
ASSERT_NOT_REACHED();
}
break;
}
break;
}
}
return true;
}
} // namespace WebCore
#endif // ENABLE(3D_CANVAS)