Index: Source/WebCore/platform/graphics/GraphicsContext3D.cpp |
=================================================================== |
--- Source/WebCore/platform/graphics/GraphicsContext3D.cpp (revision 118409) |
+++ Source/WebCore/platform/graphics/GraphicsContext3D.cpp (working copy) |
@@ -200,8 +200,13 @@ |
return false; |
int width = imageData->width(); |
int height = imageData->height(); |
- int dataBytes = width * height * 4; |
- data.resize(dataBytes); |
+ |
+ unsigned int packedSize; |
+ // Output data is tightly packed (alignment == 1). |
+ if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) |
+ return false; |
+ data.resize(packedSize); |
+ |
if (!packPixels(imageData->data()->data(), |
SourceFormatRGBA8, |
width, |
@@ -704,6 +709,32 @@ |
} |
} |
+void unpackOneRowOfRGBA8ToRGBA32F(const uint8_t* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ const float scaleFactor = 1.0f / 255.0f; |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ destination[0] = source[0] * scaleFactor; |
+ destination[1] = source[1] * scaleFactor; |
+ destination[2] = source[2] * scaleFactor; |
+ destination[3] = source[3] * scaleFactor; |
+ source += 4; |
+ destination += 4; |
+ } |
+} |
+ |
+void unpackOneRowOfBGRA8ToRGBA32F(const uint8_t* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ const float scaleFactor = 1.0f / 255.0f; |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ destination[0] = source[2] * scaleFactor; |
+ destination[1] = source[1] * scaleFactor; |
+ destination[2] = source[0] * scaleFactor; |
+ destination[3] = source[3] * scaleFactor; |
+ source += 4; |
+ destination += 4; |
+ } |
+} |
+ |
void unpackOneRowOfRGB32FToRGBA32F(const float* source, float* destination, unsigned int pixelsPerRow) |
{ |
for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
@@ -1062,6 +1093,31 @@ |
} |
} |
+void packOneRowOfRGBA32FToRGB32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; |
+ destination[0] = source[0] * scaleFactor; |
+ destination[1] = source[1] * scaleFactor; |
+ destination[2] = source[2] * scaleFactor; |
+ source += 4; |
+ destination += 3; |
+ } |
+} |
+ |
+// Used only during RGBA8 or BGRA8 -> floating-point uploads. |
+void packOneRowOfRGBA32FToRGBA32F(const float* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ destination[0] = source[0]; |
+ destination[1] = source[1]; |
+ destination[2] = source[2]; |
+ destination[3] = source[3]; |
+ source += 4; |
+ destination += 4; |
+ } |
+} |
+ |
void packOneRowOfRGBA32FToRGBA32FPremultiply(const float* source, float* destination, unsigned int pixelsPerRow) |
{ |
for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
@@ -1075,6 +1131,19 @@ |
} |
} |
+void packOneRowOfRGBA32FToRGBA32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; |
+ destination[0] = source[0] * scaleFactor; |
+ destination[1] = source[1] * scaleFactor; |
+ destination[2] = source[2] * scaleFactor; |
+ destination[3] = source[3]; |
+ source += 4; |
+ destination += 4; |
+ } |
+} |
+ |
void packOneRowOfRGBA32FToA32F(const float* source, float* destination, unsigned int pixelsPerRow) |
{ |
for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
@@ -1103,6 +1172,15 @@ |
} |
} |
+void packOneRowOfRGBA32FToR32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; |
+ destination[0] = source[0] * scaleFactor; |
+ source += 4; |
+ destination += 1; |
+ } |
+} |
void packOneRowOfRGBA32FToRA32F(const float* source, float* destination, unsigned int pixelsPerRow) |
{ |
@@ -1119,12 +1197,23 @@ |
for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
float scaleFactor = source[3]; |
destination[0] = source[0] * scaleFactor; |
- destination[1] = scaleFactor; |
+ destination[1] = source[3]; |
source += 4; |
destination += 2; |
} |
} |
+void packOneRowOfRGBA32FToRA32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow) |
+{ |
+ for (unsigned int i = 0; i < pixelsPerRow; ++i) { |
+ float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f; |
+ destination[0] = source[0] * scaleFactor; |
+ destination[1] = source[3]; |
+ source += 4; |
+ destination += 2; |
+ } |
+} |
+ |
} // anonymous namespace |
// This is used whenever unpacking is necessary; i.e., the source data |
@@ -1367,6 +1456,16 @@ |
{ |
switch (sourceDataFormat) { |
case GraphicsContext3D::SourceFormatRGBA8: { |
+ unsigned int sourceElementsPerRow = computeSourceElementsPerRow<uint8_t>(width, 4, sourceUnpackAlignment); |
+ doUnpackingAndPacking<uint8_t, float, float>(static_cast<const uint8_t*>(sourceData), unpackOneRowOfRGBA8ToRGBA32F, width, height, sourceElementsPerRow, destinationData, rowPackingFunc, destinationElementsPerPixel); |
+ break; |
+ } |
+ case GraphicsContext3D::SourceFormatBGRA8: { |
+ unsigned int sourceElementsPerRow = computeSourceElementsPerRow<uint8_t>(width, 4, sourceUnpackAlignment); |
+ doUnpackingAndPacking<uint8_t, float, float>(static_cast<const uint8_t*>(sourceData), unpackOneRowOfBGRA8ToRGBA32F, width, height, sourceElementsPerRow, destinationData, rowPackingFunc, destinationElementsPerPixel); |
+ break; |
+ } |
+ case GraphicsContext3D::SourceFormatRGBA32F: { |
unsigned int sourceElementsPerRow = computeSourceElementsPerRow<float>(width, 4, sourceUnpackAlignment); |
const float* source = static_cast<const float*>(sourceData); |
const float* endPointer = source + height * sourceElementsPerRow; |
@@ -1403,6 +1502,23 @@ |
} |
} |
+ |
+#if !ASSERT_DISABLED |
+static bool isFloatingPointSource(GraphicsContext3D::SourceDataFormat format) |
+{ |
+ switch (format) { |
+ case GraphicsContext3D::SourceFormatRGBA32F: |
+ case GraphicsContext3D::SourceFormatRGB32F: |
+ case GraphicsContext3D::SourceFormatRA32F: |
+ case GraphicsContext3D::SourceFormatR32F: |
+ case GraphicsContext3D::SourceFormatA32F: |
+ return true; |
+ default: |
+ return false; |
+ } |
+} |
+#endif |
+ |
bool GraphicsContext3D::packPixels(const uint8_t* sourceData, |
GraphicsContext3D::SourceDataFormat sourceDataFormat, |
unsigned int width, |
@@ -1539,16 +1655,21 @@ |
} |
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); |
+ // internalformat be identical. This means that whenever the |
+ // developer supplies an ArrayBufferView on this code path, |
+ // the source data will be in a floating-point format. |
+ // |
+ // The only time the source data will not be floating-point is |
+ // when uploading a DOM element or ImageData as a |
+ // floating-point texture. Only RGBA8 and BGRA8 are handled in |
+ // this case. |
+ ASSERT(isFloatingPointSource(sourceDataFormat) |
+ || sourceDataFormat == SourceFormatRGBA8 |
+ || sourceDataFormat == SourceFormatBGRA8); |
+ // When uploading a canvas into a floating-point texture, |
+ // unmultiplication may be necessary. |
+ ASSERT((alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply) |
+ || !isFloatingPointSource(sourceDataFormat)); |
// 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. |
@@ -1570,14 +1691,25 @@ |
case AlphaDoPremultiply: |
doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGB32FPremultiply, 3); |
break; |
- default: |
- ASSERT_NOT_REACHED(); |
+ case AlphaDoUnmultiply: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGB32FUnmultiply, 3); |
+ break; |
} |
break; |
case RGBA: |
- // AlphaDoNothing is handled above with fast path. |
- ASSERT(alphaOp == AlphaDoPremultiply); |
- doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FPremultiply, 4); |
+ // AlphaDoNothing for RGBA32F -> RGBA is handled above with fast path. |
+ ASSERT(alphaOp != AlphaDoNothing || sourceDataFormat != SourceFormatRGBA32F); |
+ switch (alphaOp) { |
+ case AlphaDoNothing: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32F, 4); |
+ break; |
+ case AlphaDoPremultiply: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FPremultiply, 4); |
+ break; |
+ case AlphaDoUnmultiply: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FUnmultiply, 4); |
+ break; |
+ } |
break; |
case ALPHA: |
// From the desktop OpenGL conversion rules (OpenGL 2.1 |
@@ -1596,8 +1728,9 @@ |
case AlphaDoPremultiply: |
doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToR32FPremultiply, 1); |
break; |
- default: |
- ASSERT_NOT_REACHED(); |
+ case AlphaDoUnmultiply: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToR32FUnmultiply, 1); |
+ break; |
} |
break; |
case LUMINANCE_ALPHA: |
@@ -1611,8 +1744,9 @@ |
case AlphaDoPremultiply: |
doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRA32FPremultiply, 2); |
break; |
- default: |
- ASSERT_NOT_REACHED(); |
+ case AlphaDoUnmultiply: |
+ doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRA32FUnmultiply, 2); |
+ break; |
} |
break; |
} |