Source/WebCore/ChangeLog

 12012-05-15 Kenneth Russell <kbr@google.com>
 2
 3 Assertion failure running Mozilla's WebGL performance regression tests
 4 https://bugs.webkit.org/show_bug.cgi?id=85942
 5
 6 Reviewed by Stephen White.
 7
 8 Fixed incorrect assumptions about source formats and buffer sizes
 9 when uploading to floating-point textures. Added code paths
 10 supporting the necessary conversions.
 11
 12 Tests have been added to the WebGL conformance suite which cover
 13 these new code paths; they verify uploads of HTMLCanvasElement,
 14 HTMLImageElement, HTMLVideoElement, and ImageData to
 15 floating-point textures. However, because floating-point texture
 16 support is optional, and generally only supported on bots which
 17 run with real GPUs and not in virtual machines, it isn't feasible
 18 to incorporate these tests as layout tests.
 19
 20 Ran the new WebGL conformance tests in Chromium on Linux; all
 21 pass.
 22
 23 * platform/graphics/GraphicsContext3D.cpp:
 24 (WebCore::GraphicsContext3D::extractImageData):
 25 Properly compute size of destination buffer.
 26
 27 (WebCore):
 28 Add pack/unpack routines for converting RGBA8/BGRA8 to floating point.
 29
 30 (WebCore::doFloatingPointPacking):
 31 Support RGBA8 and BGRA8 source formats.
 32
 33 (WebCore::isFloatingPointSource):
 34 Factored out logic for assertions.
 35
 36 (WebCore::GraphicsContext3D::packPixels):
 37 Generalized assertions and logic.
 38
 39 * platform/graphics/cairo/GraphicsContext3DCairo.cpp:
 40 (WebCore::GraphicsContext3D::getImageData):
 41 Properly compute size of destination buffer.
 42
 43 * platform/graphics/cg/GraphicsContext3DCG.cpp:
 44 (WebCore::GraphicsContext3D::getImageData):
 45 Properly compute size of destination buffer.
 46
 47 * platform/graphics/qt/GraphicsContext3DQt.cpp:
 48 (WebCore::GraphicsContext3D::getImageData):
 49 Properly compute size of destination buffer.
 50
 51 * platform/graphics/skia/GraphicsContext3DSkia.cpp:
 52 (WebCore::GraphicsContext3D::getImageData):
 53 Properly compute size of destination buffer.
 54
1552012-05-15 Darin Adler <darin@apple.com>
256
357 Optimize save/restore with no drawing operations between them (shows up on some canvas benchmarks)

Source/WebCore/platform/graphics/GraphicsContext3D.cpp

@@bool GraphicsContext3D::extractImageData(ImageData* imageData,
200200 return false;
201201 int width = imageData->width();
202202 int height = imageData->height();
203  int dataBytes = width * height * 4;
204  data.resize(dataBytes);
 203
 204 unsigned int packedSize;
 205 // Output data is tightly packed (alignment == 1).
 206 if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
 207 return false;
 208 data.resize(packedSize);
 209
205210 if (!packPixels(imageData->data()->data(),
206211 SourceFormatRGBA8,
207212 width,

@@void unpackOneRowOfA16BigToRGBA8(const uint16_t* source, uint8_t* destination, u
704709 }
705710}
706711
 712void unpackOneRowOfRGBA8ToRGBA32F(const uint8_t* source, float* destination, unsigned int pixelsPerRow)
 713{
 714 const float scaleFactor = 1.0f / 255.0f;
 715 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 716 destination[0] = source[0] * scaleFactor;
 717 destination[1] = source[1] * scaleFactor;
 718 destination[2] = source[2] * scaleFactor;
 719 destination[3] = source[3] * scaleFactor;
 720 source += 4;
 721 destination += 4;
 722 }
 723}
 724
 725void unpackOneRowOfBGRA8ToRGBA32F(const uint8_t* source, float* destination, unsigned int pixelsPerRow)
 726{
 727 const float scaleFactor = 1.0f / 255.0f;
 728 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 729 destination[0] = source[2] * scaleFactor;
 730 destination[1] = source[1] * scaleFactor;
 731 destination[2] = source[0] * scaleFactor;
 732 destination[3] = source[3] * scaleFactor;
 733 source += 4;
 734 destination += 4;
 735 }
 736}
 737
707738void unpackOneRowOfRGB32FToRGBA32F(const float* source, float* destination, unsigned int pixelsPerRow)
708739{
709740 for (unsigned int i = 0; i < pixelsPerRow; ++i) {

@@void packOneRowOfRGBA32FToRGB32FPremultiply(const float* source, float* destinat
10621093 }
10631094}
10641095
 1096void packOneRowOfRGBA32FToRGB32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow)
 1097{
 1098 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 1099 float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
 1100 destination[0] = source[0] * scaleFactor;
 1101 destination[1] = source[1] * scaleFactor;
 1102 destination[2] = source[2] * scaleFactor;
 1103 source += 4;
 1104 destination += 3;
 1105 }
 1106}
 1107
 1108// Used only during RGBA8 or BGRA8 -> floating-point uploads.
 1109void packOneRowOfRGBA32FToRGBA32F(const float* source, float* destination, unsigned int pixelsPerRow)
 1110{
 1111 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 1112 destination[0] = source[0];
 1113 destination[1] = source[1];
 1114 destination[2] = source[2];
 1115 destination[3] = source[3];
 1116 source += 4;
 1117 destination += 4;
 1118 }
 1119}
 1120
10651121void packOneRowOfRGBA32FToRGBA32FPremultiply(const float* source, float* destination, unsigned int pixelsPerRow)
10661122{
10671123 for (unsigned int i = 0; i < pixelsPerRow; ++i) {

@@void packOneRowOfRGBA32FToRGBA32FPremultiply(const float* source, float* destina
10751131 }
10761132}
10771133
 1134void packOneRowOfRGBA32FToRGBA32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow)
 1135{
 1136 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 1137 float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
 1138 destination[0] = source[0] * scaleFactor;
 1139 destination[1] = source[1] * scaleFactor;
 1140 destination[2] = source[2] * scaleFactor;
 1141 destination[3] = source[3];
 1142 source += 4;
 1143 destination += 4;
 1144 }
 1145}
 1146
10781147void packOneRowOfRGBA32FToA32F(const float* source, float* destination, unsigned int pixelsPerRow)
10791148{
10801149 for (unsigned int i = 0; i < pixelsPerRow; ++i) {

@@void packOneRowOfRGBA32FToR32FPremultiply(const float* source, float* destinatio
11031172 }
11041173}
11051174
 1175void packOneRowOfRGBA32FToR32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow)
 1176{
 1177 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 1178 float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
 1179 destination[0] = source[0] * scaleFactor;
 1180 source += 4;
 1181 destination += 1;
 1182 }
 1183}
11061184
11071185void packOneRowOfRGBA32FToRA32F(const float* source, float* destination, unsigned int pixelsPerRow)
11081186{

@@void packOneRowOfRGBA32FToRA32FPremultiply(const float* source, float* destinati
11191197 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
11201198 float scaleFactor = source[3];
11211199 destination[0] = source[0] * scaleFactor;
1122  destination[1] = scaleFactor;
 1200 destination[1] = source[3];
 1201 source += 4;
 1202 destination += 2;
 1203 }
 1204}
 1205
 1206void packOneRowOfRGBA32FToRA32FUnmultiply(const float* source, float* destination, unsigned int pixelsPerRow)
 1207{
 1208 for (unsigned int i = 0; i < pixelsPerRow; ++i) {
 1209 float scaleFactor = source[3] ? 1.0f / source[3] : 1.0f;
 1210 destination[0] = source[0] * scaleFactor;
 1211 destination[1] = source[3];
11231212 source += 4;
11241213 destination += 2;
11251214 }

@@static void doFloatingPointPacking(const void* sourceData,
13671456{
13681457 switch (sourceDataFormat) {
13691458 case GraphicsContext3D::SourceFormatRGBA8: {
 1459 unsigned int sourceElementsPerRow = computeSourceElementsPerRow<uint8_t>(width, 4, sourceUnpackAlignment);
 1460 doUnpackingAndPacking<uint8_t, float, float>(static_cast<const uint8_t*>(sourceData), unpackOneRowOfRGBA8ToRGBA32F, width, height, sourceElementsPerRow, destinationData, rowPackingFunc, destinationElementsPerPixel);
 1461 break;
 1462 }
 1463 case GraphicsContext3D::SourceFormatBGRA8: {
 1464 unsigned int sourceElementsPerRow = computeSourceElementsPerRow<uint8_t>(width, 4, sourceUnpackAlignment);
 1465 doUnpackingAndPacking<uint8_t, float, float>(static_cast<const uint8_t*>(sourceData), unpackOneRowOfBGRA8ToRGBA32F, width, height, sourceElementsPerRow, destinationData, rowPackingFunc, destinationElementsPerPixel);
 1466 break;
 1467 }
 1468 case GraphicsContext3D::SourceFormatRGBA32F: {
13701469 unsigned int sourceElementsPerRow = computeSourceElementsPerRow<float>(width, 4, sourceUnpackAlignment);
13711470 const float* source = static_cast<const float*>(sourceData);
13721471 const float* endPointer = source + height * sourceElementsPerRow;

@@static void doFloatingPointPacking(const void* sourceData,
14031502 }
14041503}
14051504
 1505
 1506#if !ASSERT_DISABLED
 1507static bool isFloatingPointSource(GraphicsContext3D::SourceDataFormat format)
 1508{
 1509 switch (format) {
 1510 case GraphicsContext3D::SourceFormatRGBA32F:
 1511 case GraphicsContext3D::SourceFormatRGB32F:
 1512 case GraphicsContext3D::SourceFormatRA32F:
 1513 case GraphicsContext3D::SourceFormatR32F:
 1514 case GraphicsContext3D::SourceFormatA32F:
 1515 return true;
 1516 default:
 1517 return false;
 1518 }
 1519}
 1520#endif
 1521
14061522bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
14071523 GraphicsContext3D::SourceDataFormat sourceDataFormat,
14081524 unsigned int width,

@@bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
15391655 }
15401656 case FLOAT: {
15411657 // OpenGL ES, and therefore WebGL, require that the format and
1542  // internalformat be identical, which implies that the source and
1543  // destination formats will both be floating-point in this branch -- at
1544  // least, until WebKit supports floating-point image formats natively.
1545  ASSERT(sourceDataFormat == SourceFormatRGBA32F || sourceDataFormat == SourceFormatRGB32F
1546  || sourceDataFormat == SourceFormatRA32F || sourceDataFormat == SourceFormatR32F
1547  || sourceDataFormat == SourceFormatA32F);
1548  // Because WebKit doesn't use floating-point color channels for anything
1549  // internally, there's no chance we have to do a (lossy) unmultiply
1550  // operation.
1551  ASSERT(alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply);
 1658 // internalformat be identical. This means that whenever the
 1659 // developer supplies an ArrayBufferView on this code path,
 1660 // the source data will be in a floating-point format.
 1661 //
 1662 // The only time the source data will not be floating-point is
 1663 // when uploading a DOM element or ImageData as a
 1664 // floating-point texture. Only RGBA8 and BGRA8 are handled in
 1665 // this case.
 1666 ASSERT(isFloatingPointSource(sourceDataFormat)
 1667 || sourceDataFormat == SourceFormatRGBA8
 1668 || sourceDataFormat == SourceFormatBGRA8);
 1669 // When uploading a canvas into a floating-point texture,
 1670 // unmultiplication may be necessary.
 1671 ASSERT((alphaOp == AlphaDoNothing || alphaOp == AlphaDoPremultiply)
 1672 || !isFloatingPointSource(sourceDataFormat));
15521673 // For the source formats with an even number of channels (RGBA32F,
15531674 // RA32F) it is guaranteed that the pixel data is tightly packed because
15541675 // unpack alignment <= sizeof(float) * number of channels.

@@bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
15701691 case AlphaDoPremultiply:
15711692 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGB32FPremultiply, 3);
15721693 break;
1573  default:
1574  ASSERT_NOT_REACHED();
 1694 case AlphaDoUnmultiply:
 1695 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGB32FUnmultiply, 3);
 1696 break;
15751697 }
15761698 break;
15771699 case RGBA:
1578  // AlphaDoNothing is handled above with fast path.
1579  ASSERT(alphaOp == AlphaDoPremultiply);
1580  doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FPremultiply, 4);
 1700 // AlphaDoNothing for RGBA32F -> RGBA is handled above with fast path.
 1701 ASSERT(alphaOp != AlphaDoNothing || sourceDataFormat != SourceFormatRGBA32F);
 1702 switch (alphaOp) {
 1703 case AlphaDoNothing:
 1704 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32F, 4);
 1705 break;
 1706 case AlphaDoPremultiply:
 1707 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FPremultiply, 4);
 1708 break;
 1709 case AlphaDoUnmultiply:
 1710 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRGBA32FUnmultiply, 4);
 1711 break;
 1712 }
15811713 break;
15821714 case ALPHA:
15831715 // From the desktop OpenGL conversion rules (OpenGL 2.1

@@bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
15961728 case AlphaDoPremultiply:
15971729 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToR32FPremultiply, 1);
15981730 break;
1599  default:
1600  ASSERT_NOT_REACHED();
 1731 case AlphaDoUnmultiply:
 1732 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToR32FUnmultiply, 1);
 1733 break;
16011734 }
16021735 break;
16031736 case LUMINANCE_ALPHA:

@@bool GraphicsContext3D::packPixels(const uint8_t* sourceData,
16111744 case AlphaDoPremultiply:
16121745 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRA32FPremultiply, 2);
16131746 break;
1614  default:
1615  ASSERT_NOT_REACHED();
 1747 case AlphaDoUnmultiply:
 1748 doFloatingPointPacking(sourceData, sourceDataFormat, width, height, sourceUnpackAlignment, destination, packOneRowOfRGBA32FToRA32FUnmultiply, 2);
 1749 break;
16161750 }
16171751 break;
16181752 }

Source/WebCore/platform/graphics/cairo/GraphicsContext3DCairo.cpp

@@bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned
185185 ++srcUnpackAlignment;
186186 }
187187
188  outputVector.resize(width * height * 4);
 188 unsigned int packedSize;
 189 // Output data is tightly packed (alignment == 1).
 190 if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
 191 return false;
 192 outputVector.resize(packedSize);
 193
189194 return packPixels(cairo_image_surface_get_data(imageSurface.get()), SourceFormatBGRA8,
190195 width, height, srcUnpackAlignment, format, type, alphaOp, outputVector.data());
191196}

Source/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp

@@bool GraphicsContext3D::getImageData(Image* image,
240240 if (!pixelData)
241241 return false;
242242 const UInt8* rgba = CFDataGetBytePtr(pixelData.get());
243  outputVector.resize(width * height * 4);
 243
 244 unsigned int packedSize;
 245 // Output data is tightly packed (alignment == 1).
 246 if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
 247 return false;
 248 outputVector.resize(packedSize);
 249
244250 unsigned int srcUnpackAlignment = 0;
245251 size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
246252 unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width;

Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp

@@bool GraphicsContext3D::getImageData(Image* image,
16141614 AlphaOp neededAlphaOp = AlphaDoNothing;
16151615 if (premultiplyAlpha)
16161616 neededAlphaOp = AlphaDoPremultiply;
1617  outputVector.resize(nativeImage.byteCount());
 1617
 1618 unsigned int packedSize;
 1619 // Output data is tightly packed (alignment == 1).
 1620 if (computeImageSizeInBytes(format, type, image->width(), image->height(), 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
 1621 return false;
 1622 outputVector.resize(packedSize);
 1623
16181624 return packPixels(nativeImage.bits(), SourceFormatBGRA8, image->width(), image->height(), 0, format, type, neededAlphaOp, outputVector.data());
16191625}
16201626

Source/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp

@@bool GraphicsContext3D::getImageData(Image* image,
7979 const SkBitmap& skiaImageRef = skiaImage->bitmap();
8080 SkAutoLockPixels lock(skiaImageRef);
8181 ASSERT(skiaImageRef.rowBytes() == skiaImageRef.width() * 4);
82  outputVector.resize(skiaImageRef.rowBytes() * skiaImageRef.height());
 82 unsigned int packedSize;
 83 // Output data is tightly packed (alignment == 1).
 84 if (computeImageSizeInBytes(format, type, skiaImageRef.width(), skiaImageRef.height(), 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR)
 85 return false;
 86 outputVector.resize(packedSize);
8387 return packPixels(reinterpret_cast<const uint8_t*>(skiaImageRef.getPixels()),
8488 SK_B32_SHIFT ? SourceFormatRGBA8 : SourceFormatBGRA8,
8589 skiaImageRef.width(), skiaImageRef.height(), 0,