WebGLTexelConversions.cpp (21172B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "WebGLTexelConversions.h" 6 7 #include "GLBlitHelper.h" 8 #include "WebGLContext.h" 9 10 namespace mozilla { 11 12 using namespace WebGLTexelConversions; 13 14 namespace { 15 16 /** @class WebGLImageConverter 17 * 18 * This class is just a helper to implement WebGLContext::ConvertImage below. 19 * 20 * Design comments: 21 * 22 * WebGLContext::ConvertImage has to handle hundreds of format conversion paths. 23 * It is important to minimize executable code size here. Instead of passing 24 * around a large number of function parameters hundreds of times, we create a 25 * WebGLImageConverter object once, storing these parameters, and then we call 26 * the run() method on it. 27 */ 28 class WebGLImageConverter { 29 const size_t mWidth, mHeight; 30 const void* const mSrcStart; 31 void* const mDstStart; 32 const ptrdiff_t mSrcStride, mDstStride; 33 bool mAlreadyRun; 34 bool mSuccess; 35 36 /* 37 * Returns sizeof(texel)/sizeof(type). The point is that we will iterate over 38 * texels with typed pointers and this value will tell us by how much we need 39 * to increment these pointers to advance to the next texel. 40 */ 41 template <WebGLTexelFormat Format> 42 static size_t NumElementsPerTexelForFormat() { 43 switch (Format) { 44 case WebGLTexelFormat::A8: 45 case WebGLTexelFormat::A16F: 46 case WebGLTexelFormat::A32F: 47 case WebGLTexelFormat::R8: 48 case WebGLTexelFormat::R16F: 49 case WebGLTexelFormat::R32F: 50 case WebGLTexelFormat::RGB565: 51 case WebGLTexelFormat::RGB11F11F10F: 52 case WebGLTexelFormat::RGBA4444: 53 case WebGLTexelFormat::RGBA5551: 54 return 1; 55 case WebGLTexelFormat::RA8: 56 case WebGLTexelFormat::RA16F: 57 case WebGLTexelFormat::RA32F: 58 case WebGLTexelFormat::RG8: 59 case WebGLTexelFormat::RG16F: 60 case WebGLTexelFormat::RG32F: 61 return 2; 62 case WebGLTexelFormat::RGB8: 63 case WebGLTexelFormat::RGB16F: 64 case WebGLTexelFormat::RGB32F: 65 return 3; 66 case WebGLTexelFormat::RGBA8: 67 case WebGLTexelFormat::RGBA16F: 68 case WebGLTexelFormat::RGBA32F: 69 case WebGLTexelFormat::BGRX8: 70 case WebGLTexelFormat::BGRA8: 71 return 4; 72 default: 73 MOZ_ASSERT(false, "Unknown texel format. Coding mistake?"); 74 return 0; 75 } 76 } 77 78 /* 79 * This is the completely format-specific templatized conversion function, 80 * that will be instantiated hundreds of times for all different combinations. 81 * It is important to avoid generating useless code here. In particular, many 82 * instantiations of this function template will never be called, so we try 83 * to return immediately in these cases to allow the compiler to avoid 84 * generating useless code. 85 */ 86 template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat, 87 WebGLTexelPremultiplicationOp PremultiplicationOp, 88 dom::PredefinedColorSpace SrcColorSpace, 89 dom::PredefinedColorSpace DstColorSpace> 90 void run() { 91 // check for never-called cases. We early-return to allow the compiler 92 // to avoid generating this code. It would be tempting to abort() instead, 93 // as returning early does leave the destination surface with uninitialized 94 // data, but that would not allow the compiler to avoid generating this 95 // code. So instead, we return early, so Success() will return false, and 96 // the caller must check that and abort in that case. See 97 // WebGLContext::ConvertImage. 98 99 bool sameColorSpace = (SrcColorSpace == DstColorSpace); 100 101 if (SrcFormat == DstFormat && 102 PremultiplicationOp == WebGLTexelPremultiplicationOp::None && 103 sameColorSpace) { 104 // Should have used a fast exit path earlier, rather than entering this 105 // function. we explicitly return here to allow the compiler to avoid 106 // generating this code 107 return; 108 } 109 110 // Only textures uploaded from DOM elements or ImageData can allow DstFormat 111 // != SrcFormat. DOM elements can only give BGRA8, BGRX8, A8, RGB565 112 // formats. See DOMElementToImageSurface. ImageData is always RGBA8. So all 113 // other SrcFormat will always satisfy DstFormat==SrcFormat, so we can avoid 114 // compiling the code for all the unreachable paths. 115 const bool CanSrcFormatComeFromDOMElementOrImageData = 116 SrcFormat == WebGLTexelFormat::BGRA8 || 117 SrcFormat == WebGLTexelFormat::BGRX8 || 118 SrcFormat == WebGLTexelFormat::A8 || 119 SrcFormat == WebGLTexelFormat::RGB565 || 120 SrcFormat == WebGLTexelFormat::RGBA8; 121 if (!CanSrcFormatComeFromDOMElementOrImageData && SrcFormat != DstFormat) { 122 return; 123 } 124 125 // Likewise, only textures uploaded from DOM elements or ImageData can 126 // possibly have to be unpremultiplied. 127 if (!CanSrcFormatComeFromDOMElementOrImageData && 128 PremultiplicationOp == WebGLTexelPremultiplicationOp::Unpremultiply) { 129 return; 130 } 131 132 // there is no point in premultiplication/unpremultiplication 133 // in the following cases: 134 // - the source format has no alpha 135 // - the source format has no color 136 // - the destination format has no color 137 if (!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) { 138 if (PremultiplicationOp != WebGLTexelPremultiplicationOp::None) { 139 return; 140 } 141 } 142 143 // end of early return cases. 144 145 MOZ_ASSERT(!mAlreadyRun, "converter should be run only once!"); 146 mAlreadyRun = true; 147 148 // gather some compile-time meta-data about the formats at hand. 149 150 using SrcType = typename DataTypeForFormat<SrcFormat>::Type; 151 using DstType = typename DataTypeForFormat<DstFormat>::Type; 152 153 const WebGLTexelFormat IntermediateSrcFormat = 154 IntermediateFormat<SrcFormat>::Value; 155 const WebGLTexelFormat IntermediateDstFormat = 156 IntermediateFormat<DstFormat>::Value; 157 using IntermediateSrcType = 158 typename DataTypeForFormat<IntermediateSrcFormat>::Type; 159 using IntermediateDstType = 160 typename DataTypeForFormat<IntermediateDstFormat>::Type; 161 162 const size_t NumElementsPerSrcTexel = 163 NumElementsPerTexelForFormat<SrcFormat>(); 164 const size_t NumElementsPerDstTexel = 165 NumElementsPerTexelForFormat<DstFormat>(); 166 const size_t MaxElementsPerTexel = 4; 167 MOZ_ASSERT(NumElementsPerSrcTexel <= MaxElementsPerTexel, 168 "unhandled format"); 169 MOZ_ASSERT(NumElementsPerDstTexel <= MaxElementsPerTexel, 170 "unhandled format"); 171 172 // we assume that the strides are multiples of the sizeof of respective 173 // types. this assumption will allow us to iterate over src and dst images 174 // using typed pointers, e.g. uint8_t* or uint16_t* or float*, instead of 175 // untyped pointers. So this assumption allows us to write cleaner and safer 176 // code, but it might not be true forever and if it eventually becomes 177 // wrong, we'll have to revert to always iterating using uint8_t* pointers 178 // regardless of the types at hand. 179 MOZ_ASSERT( 180 mSrcStride % sizeof(SrcType) == 0 && mDstStride % sizeof(DstType) == 0, 181 "Unsupported: texture stride is not a multiple of sizeof(type)"); 182 const ptrdiff_t srcStrideInElements = 183 mSrcStride / static_cast<ptrdiff_t>(sizeof(SrcType)); 184 const ptrdiff_t dstStrideInElements = 185 mDstStride / static_cast<ptrdiff_t>(sizeof(DstType)); 186 // Pop quiz: What's `ptrdiff_t(-16) / sizeof(int32_t)`? 187 // Did you guess +4611686018427387900? 188 MOZ_ASSERT(bool(srcStrideInElements < 0) == bool(mSrcStride < 0)); 189 MOZ_ASSERT(bool(dstStrideInElements < 0) == bool(mDstStride < 0)); 190 191 const SrcType* srcRowStart = static_cast<const SrcType*>(mSrcStart); 192 DstType* dstRowStart = static_cast<DstType*>(mDstStart); 193 194 static auto inColorSpace2 = gfx::ToColorSpace2(SrcColorSpace); 195 static auto outColorSpace2 = gfx::ToColorSpace2(DstColorSpace); 196 197 auto inColorProfile = gl::GLBlitHelper::ToColorProfileDesc(inColorSpace2); 198 auto outColorProfile = gl::GLBlitHelper::ToColorProfileDesc(outColorSpace2); 199 200 const auto conversion = color::ColorProfileConversionDesc::From({ 201 .src = *inColorProfile, 202 .dst = *outColorProfile, 203 }); 204 205 // the loop performing the texture format conversion 206 for (size_t i = 0; i < mHeight; ++i) { 207 const SrcType* srcRowEnd = srcRowStart + mWidth * NumElementsPerSrcTexel; 208 const SrcType* srcPtr = srcRowStart; 209 DstType* dstPtr = dstRowStart; 210 while (srcPtr != srcRowEnd) { 211 // convert a single texel. We proceed in 4 steps: unpack the source 212 // texel so the corresponding interchange format (e.g. unpack RGB565 to 213 // RGBA8), do colorSpace conversion if necessary, convert the resulting 214 // data type to the destination type (e.g. convert from RGBA8 to 215 // RGBA32F), and finally pack the destination texel (e.g. pack RGBA32F 216 // to RGB32F). 217 IntermediateSrcType unpackedSrc[MaxElementsPerTexel]; 218 IntermediateDstType unpackedDst[MaxElementsPerTexel]; 219 220 // unpack a src texel to corresponding intermediate src format. 221 // for example, unpack RGB565 to RGBA8 222 unpack<SrcFormat>(srcPtr, unpackedSrc); 223 224 if (!sameColorSpace) { 225 // do colorSpace conversion, which leaves alpha untouched 226 float srcAsFloat[MaxElementsPerTexel]; 227 convertType(unpackedSrc, srcAsFloat); 228 auto inTexelVec = 229 color::vec3({srcAsFloat[0], srcAsFloat[1], srcAsFloat[2]}); 230 auto outTexelVec = conversion.DstFromSrc(inTexelVec); 231 srcAsFloat[0] = outTexelVec[0]; 232 srcAsFloat[1] = outTexelVec[1]; 233 srcAsFloat[2] = outTexelVec[2]; 234 convertType(srcAsFloat, unpackedSrc); 235 } 236 237 // convert the data type to the destination type, if needed. 238 // for example, convert RGBA8 to RGBA32F 239 convertType(unpackedSrc, unpackedDst); 240 // pack the destination texel. 241 // for example, pack RGBA32F to RGB32F 242 pack<DstFormat, PremultiplicationOp>(unpackedDst, dstPtr); 243 244 srcPtr += NumElementsPerSrcTexel; 245 dstPtr += NumElementsPerDstTexel; 246 } 247 srcRowStart += srcStrideInElements; 248 dstRowStart += dstStrideInElements; 249 } 250 251 mSuccess = true; 252 } 253 254 template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat, 255 WebGLTexelPremultiplicationOp PremultiplicationOp, 256 dom::PredefinedColorSpace SrcColorSpace> 257 void run(dom::PredefinedColorSpace dstColorSpace) { 258 #define WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE(DstColorSpace) \ 259 case DstColorSpace: \ 260 return run<SrcFormat, DstFormat, PremultiplicationOp, SrcColorSpace, \ 261 DstColorSpace>(); 262 263 switch (dstColorSpace) { 264 WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE(dom::PredefinedColorSpace::Srgb) 265 WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE( 266 dom::PredefinedColorSpace::Display_p3) 267 default: 268 MOZ_ASSERT(false, "unhandled case. Coding mistake?"); 269 } 270 271 #undef WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE 272 } 273 274 template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat, 275 WebGLTexelPremultiplicationOp PremultiplicationOp> 276 void run(dom::PredefinedColorSpace srcColorSpace, 277 dom::PredefinedColorSpace dstColorSpace) { 278 #define WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE(SrcColorSpace) \ 279 case SrcColorSpace: \ 280 return run<SrcFormat, DstFormat, PremultiplicationOp, SrcColorSpace>( \ 281 dstColorSpace); 282 283 switch (srcColorSpace) { 284 WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE(dom::PredefinedColorSpace::Srgb) 285 WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE( 286 dom::PredefinedColorSpace::Display_p3) 287 default: 288 MOZ_ASSERT(false, "unhandled case. Coding mistake?"); 289 } 290 291 #undef WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE 292 } 293 294 template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat> 295 void run(WebGLTexelPremultiplicationOp premultiplicationOp, 296 dom::PredefinedColorSpace srcColorSpace, 297 dom::PredefinedColorSpace dstColorSpace) { 298 #define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \ 299 case PremultiplicationOp: \ 300 return run<SrcFormat, DstFormat, PremultiplicationOp>(srcColorSpace, \ 301 dstColorSpace); 302 303 switch (premultiplicationOp) { 304 WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP( 305 WebGLTexelPremultiplicationOp::None) 306 WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP( 307 WebGLTexelPremultiplicationOp::Premultiply) 308 WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP( 309 WebGLTexelPremultiplicationOp::Unpremultiply) 310 default: 311 MOZ_ASSERT(false, "unhandled case. Coding mistake?"); 312 } 313 314 #undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP 315 } 316 317 template <WebGLTexelFormat SrcFormat> 318 void run(WebGLTexelFormat dstFormat, 319 WebGLTexelPremultiplicationOp premultiplicationOp, 320 dom::PredefinedColorSpace srcColorSpace, 321 dom::PredefinedColorSpace dstColorSpace) { 322 #define WEBGLIMAGECONVERTER_CASE_DSTFORMAT(DstFormat) \ 323 case DstFormat: \ 324 return run<SrcFormat, DstFormat>(premultiplicationOp, srcColorSpace, \ 325 dstColorSpace); 326 327 switch (dstFormat) { 328 // 1-channel formats 329 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A8) 330 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A16F) 331 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A32F) 332 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R8) 333 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R16F) 334 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R32F) 335 // 2-channel formats 336 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA8) 337 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA16F) 338 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA32F) 339 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG8) 340 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG16F) 341 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG32F) 342 // 3-channel formats 343 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB8) 344 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB565) 345 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB11F11F10F) 346 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB16F) 347 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB32F) 348 // 4-channel formats 349 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA8) 350 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA5551) 351 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA4444) 352 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA16F) 353 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA32F) 354 // DOM element source formats 355 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBX8) 356 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::BGRX8) 357 WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::BGRA8) 358 359 default: 360 MOZ_ASSERT(false, "unhandled case. Coding mistake?"); 361 } 362 363 #undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT 364 } 365 366 public: 367 void run(WebGLTexelFormat srcFormat, WebGLTexelFormat dstFormat, 368 WebGLTexelPremultiplicationOp premultiplicationOp, 369 dom::PredefinedColorSpace srcColorSpace, 370 dom::PredefinedColorSpace dstColorSpace) { 371 #define WEBGLIMAGECONVERTER_CASE_SRCFORMAT(SrcFormat) \ 372 case SrcFormat: \ 373 return run<SrcFormat>(dstFormat, premultiplicationOp, srcColorSpace, \ 374 dstColorSpace); 375 376 switch (srcFormat) { 377 // 1-channel formats 378 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A8) 379 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A16F) 380 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A32F) 381 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R8) 382 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R16F) 383 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R32F) 384 // 2-channel formats 385 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA8) 386 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA16F) 387 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA32F) 388 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG8) 389 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG16F) 390 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG32F) 391 // 3-channel formats 392 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB8) 393 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB565) 394 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB11F11F10F) 395 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB16F) 396 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB32F) 397 // 4-channel formats 398 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA8) 399 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA5551) 400 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA4444) 401 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA16F) 402 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA32F) 403 // DOM element source formats 404 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBX8) 405 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRX8) 406 WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRA8) 407 408 default: 409 MOZ_ASSERT(false, "unhandled case. Coding mistake?"); 410 } 411 412 #undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT 413 } 414 415 WebGLImageConverter(size_t width, size_t height, const void* srcStart, 416 void* dstStart, ptrdiff_t srcStride, ptrdiff_t dstStride) 417 : mWidth(width), 418 mHeight(height), 419 mSrcStart(srcStart), 420 mDstStart(dstStart), 421 mSrcStride(srcStride), 422 mDstStride(dstStride), 423 mAlreadyRun(false), 424 mSuccess(false) {} 425 426 bool Success() const { return mSuccess; } 427 }; 428 429 } // end anonymous namespace 430 431 bool ConvertImage(size_t width, size_t height, const void* srcBegin, 432 size_t srcStride, gl::OriginPos srcOrigin, 433 WebGLTexelFormat srcFormat, bool srcPremultiplied, 434 void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin, 435 WebGLTexelFormat dstFormat, bool dstPremultiplied, 436 dom::PredefinedColorSpace srcColorSpace, 437 dom::PredefinedColorSpace dstColorSpace, 438 bool* const out_wasTrivial) { 439 *out_wasTrivial = true; 440 441 if (srcFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion || 442 dstFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion) { 443 return false; 444 } 445 446 if (!width || !height) return true; 447 448 const bool shouldYFlip = (srcOrigin != dstOrigin); 449 450 const bool canSkipPremult = 451 (!HasAlpha(srcFormat) || !HasColor(srcFormat) || !HasColor(dstFormat)); 452 453 WebGLTexelPremultiplicationOp premultOp; 454 if (canSkipPremult) { 455 premultOp = WebGLTexelPremultiplicationOp::None; 456 } else if (!srcPremultiplied && dstPremultiplied) { 457 premultOp = WebGLTexelPremultiplicationOp::Premultiply; 458 } else if (srcPremultiplied && !dstPremultiplied) { 459 premultOp = WebGLTexelPremultiplicationOp::Unpremultiply; 460 } else { 461 premultOp = WebGLTexelPremultiplicationOp::None; 462 } 463 464 const uint8_t* srcItr = (const uint8_t*)srcBegin; 465 const uint8_t* const srcEnd = srcItr + srcStride * height; 466 uint8_t* dstItr = (uint8_t*)dstBegin; 467 ptrdiff_t dstItrStride = dstStride; 468 if (shouldYFlip) { 469 dstItr = dstItr + dstStride * (height - 1); 470 dstItrStride = -dstItrStride; 471 } 472 473 bool sameColorSpace = (srcColorSpace == dstColorSpace); 474 475 if (srcFormat == dstFormat && 476 premultOp == WebGLTexelPremultiplicationOp::None && sameColorSpace) { 477 // Fast exit path: we just have to memcpy all the rows. 478 479 const auto bytesPerPixel = TexelBytesForFormat(srcFormat); 480 const size_t bytesPerRow = bytesPerPixel * width; 481 482 while (srcItr != srcEnd) { 483 memcpy(dstItr, srcItr, bytesPerRow); 484 srcItr += srcStride; 485 dstItr += dstItrStride; 486 } 487 return true; 488 } 489 490 *out_wasTrivial = false; 491 492 WebGLImageConverter converter(width, height, srcItr, dstItr, srcStride, 493 dstItrStride); 494 converter.run(srcFormat, dstFormat, premultOp, srcColorSpace, dstColorSpace); 495 if (!converter.Success()) { 496 // the dst image may be left uninitialized, so we better not try to 497 // continue even in release builds. This should never happen anyway, 498 // and would be a bug in our code. 499 MOZ_CRASH("programming mistake in WebGL texture conversions"); 500 } 501 502 return true; 503 } 504 505 } // end namespace mozilla