summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/GraphicsContext3D.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/GraphicsContext3D.cpp')
-rw-r--r--Source/WebCore/platform/graphics/GraphicsContext3D.cpp1454
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)