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