diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/GraphicsContext3D.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/GraphicsContext3D.cpp | 1454 |
1 files changed, 1454 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp new file mode 100644 index 0000000..1224bce --- /dev/null +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -0,0 +1,1454 @@ +/* + * 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) |