1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * Copyright (C) 2010 Mozilla Corporation. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29 30#if USE(3D_GRAPHICS) 31 32#include "GraphicsContext3D.h" 33 34#include "Extensions3D.h" 35#include "FormatConverter.h" 36#include "Image.h" 37#include "ImageData.h" 38#include "ImageObserver.h" 39 40namespace WebCore { 41 42namespace { 43 44GraphicsContext3D::DataFormat getDataFormat(GC3Denum destinationFormat, GC3Denum destinationType) 45{ 46 GraphicsContext3D::DataFormat dstFormat = GraphicsContext3D::DataFormatRGBA8; 47 switch (destinationType) { 48 case GraphicsContext3D::UNSIGNED_BYTE: 49 switch (destinationFormat) { 50 case GraphicsContext3D::RGB: 51 dstFormat = GraphicsContext3D::DataFormatRGB8; 52 break; 53 case GraphicsContext3D::RGBA: 54 dstFormat = GraphicsContext3D::DataFormatRGBA8; 55 break; 56 case GraphicsContext3D::ALPHA: 57 dstFormat = GraphicsContext3D::DataFormatA8; 58 break; 59 case GraphicsContext3D::LUMINANCE: 60 dstFormat = GraphicsContext3D::DataFormatR8; 61 break; 62 case GraphicsContext3D::LUMINANCE_ALPHA: 63 dstFormat = GraphicsContext3D::DataFormatRA8; 64 break; 65 default: 66 ASSERT_NOT_REACHED(); 67 } 68 break; 69 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: 70 dstFormat = GraphicsContext3D::DataFormatRGBA4444; 71 break; 72 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: 73 dstFormat = GraphicsContext3D::DataFormatRGBA5551; 74 break; 75 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: 76 dstFormat = GraphicsContext3D::DataFormatRGB565; 77 break; 78 case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float 79 switch (destinationFormat) { 80 case GraphicsContext3D::RGB: 81 dstFormat = GraphicsContext3D::DataFormatRGB16F; 82 break; 83 case GraphicsContext3D::RGBA: 84 dstFormat = GraphicsContext3D::DataFormatRGBA16F; 85 break; 86 case GraphicsContext3D::ALPHA: 87 dstFormat = GraphicsContext3D::DataFormatA16F; 88 break; 89 case GraphicsContext3D::LUMINANCE: 90 dstFormat = GraphicsContext3D::DataFormatR16F; 91 break; 92 case GraphicsContext3D::LUMINANCE_ALPHA: 93 dstFormat = GraphicsContext3D::DataFormatRA16F; 94 break; 95 default: 96 ASSERT_NOT_REACHED(); 97 } 98 break; 99 case GraphicsContext3D::FLOAT: // OES_texture_float 100 switch (destinationFormat) { 101 case GraphicsContext3D::RGB: 102 dstFormat = GraphicsContext3D::DataFormatRGB32F; 103 break; 104 case GraphicsContext3D::RGBA: 105 dstFormat = GraphicsContext3D::DataFormatRGBA32F; 106 break; 107 case GraphicsContext3D::ALPHA: 108 dstFormat = GraphicsContext3D::DataFormatA32F; 109 break; 110 case GraphicsContext3D::LUMINANCE: 111 dstFormat = GraphicsContext3D::DataFormatR32F; 112 break; 113 case GraphicsContext3D::LUMINANCE_ALPHA: 114 dstFormat = GraphicsContext3D::DataFormatRA32F; 115 break; 116 default: 117 ASSERT_NOT_REACHED(); 118 } 119 break; 120 default: 121 ASSERT_NOT_REACHED(); 122 } 123 return dstFormat; 124} 125 126} // anonymous namespace 127 128bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint unpackAlignment) 129{ 130 ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8); 131 std::unique_ptr<unsigned char[]> zero; 132 if (!isResourceSafe() && width > 0 && height > 0) { 133 unsigned int size; 134 GC3Denum error = computeImageSizeInBytes(format, type, width, height, unpackAlignment, &size, 0); 135 if (error != GraphicsContext3D::NO_ERROR) { 136 synthesizeGLError(error); 137 return false; 138 } 139 zero = std::make_unique<unsigned char[]>(size); 140 if (!zero) { 141 synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 142 return false; 143 } 144 memset(zero.get(), 0, size); 145 } 146 return texImage2D(target, level, internalformat, width, height, border, format, type, zero.get()); 147} 148 149bool GraphicsContext3D::computeFormatAndTypeParameters(GC3Denum format, GC3Denum type, unsigned int* componentsPerPixel, unsigned int* bytesPerComponent) 150{ 151 switch (format) { 152 case GraphicsContext3D::ALPHA: 153 case GraphicsContext3D::LUMINANCE: 154 case GraphicsContext3D::DEPTH_COMPONENT: 155 case GraphicsContext3D::DEPTH_STENCIL: 156 *componentsPerPixel = 1; 157 break; 158 case GraphicsContext3D::LUMINANCE_ALPHA: 159 *componentsPerPixel = 2; 160 break; 161 case GraphicsContext3D::RGB: 162 *componentsPerPixel = 3; 163 break; 164 case GraphicsContext3D::RGBA: 165 case Extensions3D::BGRA_EXT: // GL_EXT_texture_format_BGRA8888 166 *componentsPerPixel = 4; 167 break; 168 default: 169 return false; 170 } 171 switch (type) { 172 case GraphicsContext3D::UNSIGNED_BYTE: 173 *bytesPerComponent = sizeof(GC3Dubyte); 174 break; 175 case GraphicsContext3D::UNSIGNED_SHORT: 176 *bytesPerComponent = sizeof(GC3Dushort); 177 break; 178 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: 179 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: 180 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: 181 *componentsPerPixel = 1; 182 *bytesPerComponent = sizeof(GC3Dushort); 183 break; 184 case GraphicsContext3D::UNSIGNED_INT_24_8: 185 case GraphicsContext3D::UNSIGNED_INT: 186 *bytesPerComponent = sizeof(GC3Duint); 187 break; 188 case GraphicsContext3D::FLOAT: // OES_texture_float 189 *bytesPerComponent = sizeof(GC3Dfloat); 190 break; 191 case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float 192 *bytesPerComponent = sizeof(GC3Dhalffloat); 193 break; 194 default: 195 return false; 196 } 197 return true; 198} 199 200GC3Denum GraphicsContext3D::computeImageSizeInBytes(GC3Denum format, GC3Denum type, GC3Dsizei width, GC3Dsizei height, GC3Dint alignment, unsigned int* imageSizeInBytes, unsigned int* paddingInBytes) 201{ 202 ASSERT(imageSizeInBytes); 203 ASSERT(alignment == 1 || alignment == 2 || alignment == 4 || alignment == 8); 204 if (width < 0 || height < 0) 205 return GraphicsContext3D::INVALID_VALUE; 206 unsigned int bytesPerComponent, componentsPerPixel; 207 if (!computeFormatAndTypeParameters(format, type, &bytesPerComponent, &componentsPerPixel)) 208 return GraphicsContext3D::INVALID_ENUM; 209 if (!width || !height) { 210 *imageSizeInBytes = 0; 211 if (paddingInBytes) 212 *paddingInBytes = 0; 213 return GraphicsContext3D::NO_ERROR; 214 } 215 Checked<uint32_t, RecordOverflow> checkedValue = bytesPerComponent * componentsPerPixel; 216 checkedValue *= width; 217 if (checkedValue.hasOverflowed()) 218 return GraphicsContext3D::INVALID_VALUE; 219 unsigned int validRowSize = checkedValue.unsafeGet(); 220 unsigned int padding = 0; 221 unsigned int residual = validRowSize % alignment; 222 if (residual) { 223 padding = alignment - residual; 224 checkedValue += padding; 225 } 226 // Last row needs no padding. 227 checkedValue *= (height - 1); 228 checkedValue += validRowSize; 229 if (checkedValue.hasOverflowed()) 230 return GraphicsContext3D::INVALID_VALUE; 231 *imageSizeInBytes = checkedValue.unsafeGet(); 232 if (paddingInBytes) 233 *paddingInBytes = padding; 234 return GraphicsContext3D::NO_ERROR; 235} 236 237GraphicsContext3D::ImageExtractor::ImageExtractor(Image* image, ImageHtmlDomSource imageHtmlDomSource, bool premultiplyAlpha, bool ignoreGammaAndColorProfile) 238{ 239 m_image = image; 240 m_imageHtmlDomSource = imageHtmlDomSource; 241 m_extractSucceeded = extractImage(premultiplyAlpha, ignoreGammaAndColorProfile); 242} 243 244bool GraphicsContext3D::packImageData( Image* image, const void* pixels, GC3Denum format, GC3Denum type, bool flipY, AlphaOp alphaOp, DataFormat sourceFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, Vector<uint8_t>& data) 245{ 246 if (!pixels) 247 return false; 248 249 unsigned packedSize; 250 // Output data is tightly packed (alignment == 1). 251 if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) 252 return false; 253 data.resize(packedSize); 254 255 if (!packPixels(reinterpret_cast<const uint8_t*>(pixels), sourceFormat, width, height, sourceUnpackAlignment, format, type, alphaOp, data.data(), flipY)) 256 return false; 257 if (ImageObserver* observer = image->imageObserver()) 258 observer->didDraw(image); 259 return true; 260} 261 262bool GraphicsContext3D::extractImageData(ImageData* imageData, GC3Denum format, GC3Denum type, bool flipY, bool premultiplyAlpha, Vector<uint8_t>& data) 263{ 264 if (!imageData) 265 return false; 266 int width = imageData->width(); 267 int height = imageData->height(); 268 269 unsigned int packedSize; 270 // Output data is tightly packed (alignment == 1). 271 if (computeImageSizeInBytes(format, type, width, height, 1, &packedSize, 0) != GraphicsContext3D::NO_ERROR) 272 return false; 273 data.resize(packedSize); 274 275 if (!packPixels(imageData->data()->data(), DataFormatRGBA8, width, height, 0, format, type, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing, data.data(), flipY)) 276 return false; 277 278 return true; 279} 280 281bool 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) 282{ 283 // Assumes format, type, etc. have already been validated. 284 DataFormat sourceDataFormat = getDataFormat(format, type); 285 286 // Resize the output buffer. 287 unsigned int componentsPerPixel, bytesPerComponent; 288 if (!computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent)) 289 return false; 290 unsigned int bytesPerPixel = componentsPerPixel * bytesPerComponent; 291 data.resize(width * height * bytesPerPixel); 292 293 if (!packPixels(static_cast<const uint8_t*>(pixels), sourceDataFormat, width, height, unpackAlignment, format, type, (premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing), data.data(), flipY)) 294 return false; 295 296 return true; 297} 298 299ALWAYS_INLINE unsigned TexelBytesForFormat(GraphicsContext3D::DataFormat format) 300{ 301 switch (format) { 302 case GraphicsContext3D::DataFormatR8: 303 case GraphicsContext3D::DataFormatA8: 304 return 1; 305 case GraphicsContext3D::DataFormatRA8: 306 case GraphicsContext3D::DataFormatAR8: 307 case GraphicsContext3D::DataFormatRGBA5551: 308 case GraphicsContext3D::DataFormatRGBA4444: 309 case GraphicsContext3D::DataFormatRGB565: 310 case GraphicsContext3D::DataFormatA16F: 311 case GraphicsContext3D::DataFormatR16F: 312 return 2; 313 case GraphicsContext3D::DataFormatRGB8: 314 case GraphicsContext3D::DataFormatBGR8: 315 return 3; 316 case GraphicsContext3D::DataFormatRGBA8: 317 case GraphicsContext3D::DataFormatARGB8: 318 case GraphicsContext3D::DataFormatABGR8: 319 case GraphicsContext3D::DataFormatBGRA8: 320 case GraphicsContext3D::DataFormatR32F: 321 case GraphicsContext3D::DataFormatA32F: 322 case GraphicsContext3D::DataFormatRA16F: 323 return 4; 324 case GraphicsContext3D::DataFormatRGB16F: 325 return 6; 326 case GraphicsContext3D::DataFormatRA32F: 327 case GraphicsContext3D::DataFormatRGBA16F: 328 return 8; 329 case GraphicsContext3D::DataFormatRGB32F: 330 return 12; 331 case GraphicsContext3D::DataFormatRGBA32F: 332 return 16; 333 default: 334 return 0; 335 } 336} 337 338bool GraphicsContext3D::packPixels(const uint8_t* sourceData, DataFormat sourceDataFormat, unsigned width, unsigned height, unsigned sourceUnpackAlignment, unsigned destinationFormat, unsigned destinationType, AlphaOp alphaOp, void* destinationData, bool flipY) 339{ 340 int validSrc = width * TexelBytesForFormat(sourceDataFormat); 341 int remainder = sourceUnpackAlignment ? (validSrc % sourceUnpackAlignment) : 0; 342 int srcStride = remainder ? (validSrc + sourceUnpackAlignment - remainder) : validSrc; 343 344 DataFormat dstDataFormat = getDataFormat(destinationFormat, destinationType); 345 int dstStride = width * TexelBytesForFormat(dstDataFormat); 346 if (flipY) { 347 destinationData = static_cast<uint8_t*>(destinationData) + dstStride*(height - 1); 348 dstStride = -dstStride; 349 } 350 if (!hasAlpha(sourceDataFormat) || !hasColor(sourceDataFormat) || !hasColor(dstDataFormat)) 351 alphaOp = AlphaDoNothing; 352 353 if (sourceDataFormat == dstDataFormat && alphaOp == AlphaDoNothing) { 354 const uint8_t* ptr = sourceData; 355 const uint8_t* ptrEnd = sourceData + srcStride * height; 356 unsigned rowSize = (dstStride > 0) ? dstStride: -dstStride; 357 uint8_t* dst = static_cast<uint8_t*>(destinationData); 358 while (ptr < ptrEnd) { 359 memcpy(dst, ptr, rowSize); 360 ptr += srcStride; 361 dst += dstStride; 362 } 363 return true; 364 } 365 366 FormatConverter converter(width, height, sourceData, destinationData, srcStride, dstStride); 367 converter.convert(sourceDataFormat, dstDataFormat, alphaOp); 368 if (!converter.success()) 369 return false; 370 return true; 371} 372 373unsigned GraphicsContext3D::getClearBitsByAttachmentType(GC3Denum attachment) 374{ 375 switch (attachment) { 376 case GraphicsContext3D::COLOR_ATTACHMENT0: 377 case Extensions3D::COLOR_ATTACHMENT1_EXT: 378 case Extensions3D::COLOR_ATTACHMENT2_EXT: 379 case Extensions3D::COLOR_ATTACHMENT3_EXT: 380 case Extensions3D::COLOR_ATTACHMENT4_EXT: 381 case Extensions3D::COLOR_ATTACHMENT5_EXT: 382 case Extensions3D::COLOR_ATTACHMENT6_EXT: 383 case Extensions3D::COLOR_ATTACHMENT7_EXT: 384 case Extensions3D::COLOR_ATTACHMENT8_EXT: 385 case Extensions3D::COLOR_ATTACHMENT9_EXT: 386 case Extensions3D::COLOR_ATTACHMENT10_EXT: 387 case Extensions3D::COLOR_ATTACHMENT11_EXT: 388 case Extensions3D::COLOR_ATTACHMENT12_EXT: 389 case Extensions3D::COLOR_ATTACHMENT13_EXT: 390 case Extensions3D::COLOR_ATTACHMENT14_EXT: 391 case Extensions3D::COLOR_ATTACHMENT15_EXT: 392 return GraphicsContext3D::COLOR_BUFFER_BIT; 393 case GraphicsContext3D::DEPTH_ATTACHMENT: 394 return GraphicsContext3D::DEPTH_BUFFER_BIT; 395 case GraphicsContext3D::STENCIL_ATTACHMENT: 396 return GraphicsContext3D::STENCIL_BUFFER_BIT; 397 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: 398 return GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT; 399 default: 400 return 0; 401 } 402} 403 404unsigned GraphicsContext3D::getClearBitsByFormat(GC3Denum format) 405{ 406 switch (format) { 407 case GraphicsContext3D::ALPHA: 408 case GraphicsContext3D::LUMINANCE: 409 case GraphicsContext3D::LUMINANCE_ALPHA: 410 case GraphicsContext3D::RGB: 411 case GraphicsContext3D::RGB565: 412 case GraphicsContext3D::RGBA: 413 case GraphicsContext3D::RGBA4: 414 case GraphicsContext3D::RGB5_A1: 415 return GraphicsContext3D::COLOR_BUFFER_BIT; 416 case GraphicsContext3D::DEPTH_COMPONENT16: 417 case GraphicsContext3D::DEPTH_COMPONENT: 418 return GraphicsContext3D::DEPTH_BUFFER_BIT; 419 case GraphicsContext3D::STENCIL_INDEX8: 420 return GraphicsContext3D::STENCIL_BUFFER_BIT; 421 case GraphicsContext3D::DEPTH_STENCIL: 422 return GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT; 423 default: 424 return 0; 425 } 426} 427 428unsigned GraphicsContext3D::getChannelBitsByFormat(GC3Denum format) 429{ 430 switch (format) { 431 case GraphicsContext3D::ALPHA: 432 return ChannelAlpha; 433 case GraphicsContext3D::LUMINANCE: 434 return ChannelRGB; 435 case GraphicsContext3D::LUMINANCE_ALPHA: 436 return ChannelRGBA; 437 case GraphicsContext3D::RGB: 438 case GraphicsContext3D::RGB565: 439 return ChannelRGB; 440 case GraphicsContext3D::RGBA: 441 case GraphicsContext3D::RGBA4: 442 case GraphicsContext3D::RGB5_A1: 443 return ChannelRGBA; 444 case GraphicsContext3D::DEPTH_COMPONENT16: 445 case GraphicsContext3D::DEPTH_COMPONENT: 446 return ChannelDepth; 447 case GraphicsContext3D::STENCIL_INDEX8: 448 return ChannelStencil; 449 case GraphicsContext3D::DEPTH_STENCIL: 450 return ChannelDepth | ChannelStencil; 451 default: 452 return 0; 453 } 454} 455 456} // namespace WebCore 457 458#endif // USE(3D_GRAPHICS) 459