Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "WebGLContext.h" |
michael@0 | 6 | #include "WebGLTexelConversions.h" |
michael@0 | 7 | |
michael@0 | 8 | namespace mozilla { |
michael@0 | 9 | |
michael@0 | 10 | using namespace WebGLTexelConversions; |
michael@0 | 11 | |
michael@0 | 12 | namespace { |
michael@0 | 13 | |
michael@0 | 14 | /** @class WebGLImageConverter |
michael@0 | 15 | * |
michael@0 | 16 | * This class is just a helper to implement WebGLContext::ConvertImage below. |
michael@0 | 17 | * |
michael@0 | 18 | * Design comments: |
michael@0 | 19 | * |
michael@0 | 20 | * WebGLContext::ConvertImage has to handle hundreds of format conversion paths. |
michael@0 | 21 | * It is important to minimize executable code size here. Instead of passing around |
michael@0 | 22 | * a large number of function parameters hundreds of times, we create a |
michael@0 | 23 | * WebGLImageConverter object once, storing these parameters, and then we call |
michael@0 | 24 | * the run() method on it. |
michael@0 | 25 | */ |
michael@0 | 26 | class WebGLImageConverter |
michael@0 | 27 | { |
michael@0 | 28 | const size_t mWidth, mHeight; |
michael@0 | 29 | const void* const mSrcStart; |
michael@0 | 30 | void* const mDstStart; |
michael@0 | 31 | const ptrdiff_t mSrcStride, mDstStride; |
michael@0 | 32 | bool mAlreadyRun; |
michael@0 | 33 | bool mSuccess; |
michael@0 | 34 | |
michael@0 | 35 | /* |
michael@0 | 36 | * Returns sizeof(texel)/sizeof(type). The point is that we will iterate over |
michael@0 | 37 | * texels with typed pointers and this value will tell us by how much we need |
michael@0 | 38 | * to increment these pointers to advance to the next texel. |
michael@0 | 39 | */ |
michael@0 | 40 | template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format> |
michael@0 | 41 | static size_t NumElementsPerTexelForFormat() { |
michael@0 | 42 | switch (Format) { |
michael@0 | 43 | case WebGLTexelFormat::R8: |
michael@0 | 44 | case WebGLTexelFormat::A8: |
michael@0 | 45 | case WebGLTexelFormat::R16F: |
michael@0 | 46 | case WebGLTexelFormat::A16F: |
michael@0 | 47 | case WebGLTexelFormat::R32F: |
michael@0 | 48 | case WebGLTexelFormat::A32F: |
michael@0 | 49 | case WebGLTexelFormat::RGBA5551: |
michael@0 | 50 | case WebGLTexelFormat::RGBA4444: |
michael@0 | 51 | case WebGLTexelFormat::RGB565: |
michael@0 | 52 | return 1; |
michael@0 | 53 | case WebGLTexelFormat::RA8: |
michael@0 | 54 | case WebGLTexelFormat::RA16F: |
michael@0 | 55 | case WebGLTexelFormat::RA32F: |
michael@0 | 56 | return 2; |
michael@0 | 57 | case WebGLTexelFormat::RGB8: |
michael@0 | 58 | case WebGLTexelFormat::RGB16F: |
michael@0 | 59 | case WebGLTexelFormat::RGB32F: |
michael@0 | 60 | return 3; |
michael@0 | 61 | case WebGLTexelFormat::RGBA8: |
michael@0 | 62 | case WebGLTexelFormat::BGRA8: |
michael@0 | 63 | case WebGLTexelFormat::BGRX8: |
michael@0 | 64 | case WebGLTexelFormat::RGBA16F: |
michael@0 | 65 | case WebGLTexelFormat::RGBA32F: |
michael@0 | 66 | return 4; |
michael@0 | 67 | default: |
michael@0 | 68 | MOZ_ASSERT(false, "Unknown texel format. Coding mistake?"); |
michael@0 | 69 | return 0; |
michael@0 | 70 | } |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | /* |
michael@0 | 74 | * This is the completely format-specific templatized conversion function, |
michael@0 | 75 | * that will be instantiated hundreds of times for all different combinations. |
michael@0 | 76 | * It is important to avoid generating useless code here. In particular, many |
michael@0 | 77 | * instantiations of this function template will never be called, so we try |
michael@0 | 78 | * to return immediately in these cases to allow the compiler to avoid generating |
michael@0 | 79 | * useless code. |
michael@0 | 80 | */ |
michael@0 | 81 | template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat, |
michael@0 | 82 | MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) DstFormat, |
michael@0 | 83 | MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp> |
michael@0 | 84 | void run() |
michael@0 | 85 | { |
michael@0 | 86 | // check for never-called cases. We early-return to allow the compiler |
michael@0 | 87 | // to avoid generating this code. It would be tempting to abort() instead, |
michael@0 | 88 | // as returning early does leave the destination surface with uninitialized |
michael@0 | 89 | // data, but that would not allow the compiler to avoid generating this code. |
michael@0 | 90 | // So instead, we return early, so Success() will return false, and the caller |
michael@0 | 91 | // must check that and abort in that case. See WebGLContext::ConvertImage. |
michael@0 | 92 | |
michael@0 | 93 | if (SrcFormat == DstFormat && |
michael@0 | 94 | PremultiplicationOp == WebGLTexelPremultiplicationOp::None) |
michael@0 | 95 | { |
michael@0 | 96 | // Should have used a fast exit path earlier, rather than entering this function. |
michael@0 | 97 | // we explicitly return here to allow the compiler to avoid generating this code |
michael@0 | 98 | return; |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | // Only textures uploaded from DOM elements or ImageData can allow DstFormat != SrcFormat. |
michael@0 | 102 | // DOM elements can only give BGRA8, BGRX8, A8, RGB565 formats. See DOMElementToImageSurface. |
michael@0 | 103 | // ImageData is always RGBA8. So all other SrcFormat will always satisfy DstFormat==SrcFormat, |
michael@0 | 104 | // so we can avoid compiling the code for all the unreachable paths. |
michael@0 | 105 | const bool CanSrcFormatComeFromDOMElementOrImageData |
michael@0 | 106 | = SrcFormat == WebGLTexelFormat::BGRA8 || |
michael@0 | 107 | SrcFormat == WebGLTexelFormat::BGRX8 || |
michael@0 | 108 | SrcFormat == WebGLTexelFormat::A8 || |
michael@0 | 109 | SrcFormat == WebGLTexelFormat::RGB565 || |
michael@0 | 110 | SrcFormat == WebGLTexelFormat::RGBA8; |
michael@0 | 111 | if (!CanSrcFormatComeFromDOMElementOrImageData && |
michael@0 | 112 | SrcFormat != DstFormat) |
michael@0 | 113 | { |
michael@0 | 114 | return; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | // Likewise, only textures uploaded from DOM elements or ImageData can possibly have to be unpremultiplied. |
michael@0 | 118 | if (!CanSrcFormatComeFromDOMElementOrImageData && |
michael@0 | 119 | PremultiplicationOp == WebGLTexelPremultiplicationOp::Unpremultiply) |
michael@0 | 120 | { |
michael@0 | 121 | return; |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | // there is no point in premultiplication/unpremultiplication |
michael@0 | 125 | // in the following cases: |
michael@0 | 126 | // - the source format has no alpha |
michael@0 | 127 | // - the source format has no color |
michael@0 | 128 | // - the destination format has no color |
michael@0 | 129 | if (!HasAlpha(SrcFormat) || |
michael@0 | 130 | !HasColor(SrcFormat) || |
michael@0 | 131 | !HasColor(DstFormat)) |
michael@0 | 132 | { |
michael@0 | 133 | |
michael@0 | 134 | if (PremultiplicationOp != WebGLTexelPremultiplicationOp::None) |
michael@0 | 135 | { |
michael@0 | 136 | return; |
michael@0 | 137 | } |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | // end of early return cases. |
michael@0 | 141 | |
michael@0 | 142 | MOZ_ASSERT(!mAlreadyRun, "converter should be run only once!"); |
michael@0 | 143 | mAlreadyRun = true; |
michael@0 | 144 | |
michael@0 | 145 | // gather some compile-time meta-data about the formats at hand. |
michael@0 | 146 | |
michael@0 | 147 | typedef |
michael@0 | 148 | typename DataTypeForFormat<SrcFormat>::Type |
michael@0 | 149 | SrcType; |
michael@0 | 150 | typedef |
michael@0 | 151 | typename DataTypeForFormat<DstFormat>::Type |
michael@0 | 152 | DstType; |
michael@0 | 153 | |
michael@0 | 154 | const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) IntermediateSrcFormat |
michael@0 | 155 | = IntermediateFormat<SrcFormat>::Value; |
michael@0 | 156 | const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) IntermediateDstFormat |
michael@0 | 157 | = IntermediateFormat<DstFormat>::Value; |
michael@0 | 158 | typedef |
michael@0 | 159 | typename DataTypeForFormat<IntermediateSrcFormat>::Type |
michael@0 | 160 | IntermediateSrcType; |
michael@0 | 161 | typedef |
michael@0 | 162 | typename DataTypeForFormat<IntermediateDstFormat>::Type |
michael@0 | 163 | IntermediateDstType; |
michael@0 | 164 | |
michael@0 | 165 | const size_t NumElementsPerSrcTexel = NumElementsPerTexelForFormat<SrcFormat>(); |
michael@0 | 166 | const size_t NumElementsPerDstTexel = NumElementsPerTexelForFormat<DstFormat>(); |
michael@0 | 167 | const size_t MaxElementsPerTexel = 4; |
michael@0 | 168 | MOZ_ASSERT(NumElementsPerSrcTexel <= MaxElementsPerTexel, "unhandled format"); |
michael@0 | 169 | MOZ_ASSERT(NumElementsPerDstTexel <= MaxElementsPerTexel, "unhandled format"); |
michael@0 | 170 | |
michael@0 | 171 | // we assume that the strides are multiples of the sizeof of respective types. |
michael@0 | 172 | // this assumption will allow us to iterate over src and dst images using typed |
michael@0 | 173 | // pointers, e.g. uint8_t* or uint16_t* or float*, instead of untyped pointers. |
michael@0 | 174 | // So this assumption allows us to write cleaner and safer code, but it might |
michael@0 | 175 | // not be true forever and if it eventually becomes wrong, we'll have to revert |
michael@0 | 176 | // to always iterating using uint8_t* pointers regardless of the types at hand. |
michael@0 | 177 | MOZ_ASSERT(mSrcStride % sizeof(SrcType) == 0 && |
michael@0 | 178 | mDstStride % sizeof(DstType) == 0, |
michael@0 | 179 | "Unsupported: texture stride is not a multiple of sizeof(type)"); |
michael@0 | 180 | const ptrdiff_t srcStrideInElements = mSrcStride / sizeof(SrcType); |
michael@0 | 181 | const ptrdiff_t dstStrideInElements = mDstStride / sizeof(DstType); |
michael@0 | 182 | |
michael@0 | 183 | const SrcType *srcRowStart = static_cast<const SrcType*>(mSrcStart); |
michael@0 | 184 | DstType *dstRowStart = static_cast<DstType*>(mDstStart); |
michael@0 | 185 | |
michael@0 | 186 | // the loop performing the texture format conversion |
michael@0 | 187 | for (size_t i = 0; i < mHeight; ++i) { |
michael@0 | 188 | const SrcType *srcRowEnd = srcRowStart + mWidth * NumElementsPerSrcTexel; |
michael@0 | 189 | const SrcType *srcPtr = srcRowStart; |
michael@0 | 190 | DstType *dstPtr = dstRowStart; |
michael@0 | 191 | while (srcPtr != srcRowEnd) { |
michael@0 | 192 | // convert a single texel. We proceed in 3 steps: unpack the source texel |
michael@0 | 193 | // so the corresponding interchange format (e.g. unpack RGB565 to RGBA8), |
michael@0 | 194 | // convert the resulting data type to the destination type (e.g. convert |
michael@0 | 195 | // from RGBA8 to RGBA32F), and finally pack the destination texel |
michael@0 | 196 | // (e.g. pack RGBA32F to RGB32F). |
michael@0 | 197 | IntermediateSrcType unpackedSrc[MaxElementsPerTexel]; |
michael@0 | 198 | IntermediateDstType unpackedDst[MaxElementsPerTexel]; |
michael@0 | 199 | |
michael@0 | 200 | // unpack a src texel to corresponding intermediate src format. |
michael@0 | 201 | // for example, unpack RGB565 to RGBA8 |
michael@0 | 202 | unpack<SrcFormat>(srcPtr, unpackedSrc); |
michael@0 | 203 | // convert the data type to the destination type, if needed. |
michael@0 | 204 | // for example, convert RGBA8 to RGBA32F |
michael@0 | 205 | convertType(unpackedSrc, unpackedDst); |
michael@0 | 206 | // pack the destination texel. |
michael@0 | 207 | // for example, pack RGBA32F to RGB32F |
michael@0 | 208 | pack<DstFormat, PremultiplicationOp>(unpackedDst, dstPtr); |
michael@0 | 209 | |
michael@0 | 210 | srcPtr += NumElementsPerSrcTexel; |
michael@0 | 211 | dstPtr += NumElementsPerDstTexel; |
michael@0 | 212 | } |
michael@0 | 213 | srcRowStart += srcStrideInElements; |
michael@0 | 214 | dstRowStart += dstStrideInElements; |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | mSuccess = true; |
michael@0 | 218 | return; |
michael@0 | 219 | } |
michael@0 | 220 | |
michael@0 | 221 | template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat, |
michael@0 | 222 | MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) DstFormat> |
michael@0 | 223 | void run(WebGLTexelPremultiplicationOp premultiplicationOp) |
michael@0 | 224 | { |
michael@0 | 225 | #define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \ |
michael@0 | 226 | case PremultiplicationOp: \ |
michael@0 | 227 | return run<SrcFormat, DstFormat, PremultiplicationOp>(); |
michael@0 | 228 | |
michael@0 | 229 | switch (premultiplicationOp) { |
michael@0 | 230 | WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::None) |
michael@0 | 231 | WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Premultiply) |
michael@0 | 232 | WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(WebGLTexelPremultiplicationOp::Unpremultiply) |
michael@0 | 233 | default: |
michael@0 | 234 | MOZ_ASSERT(false, "unhandled case. Coding mistake?"); |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | #undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat> |
michael@0 | 241 | void run(WebGLTexelFormat dstFormat, |
michael@0 | 242 | WebGLTexelPremultiplicationOp premultiplicationOp) |
michael@0 | 243 | { |
michael@0 | 244 | #define WEBGLIMAGECONVERTER_CASE_DSTFORMAT(DstFormat) \ |
michael@0 | 245 | case DstFormat: \ |
michael@0 | 246 | return run<SrcFormat, DstFormat>(premultiplicationOp); |
michael@0 | 247 | |
michael@0 | 248 | switch (dstFormat) { |
michael@0 | 249 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R8) |
michael@0 | 250 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A8) |
michael@0 | 251 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R16F) |
michael@0 | 252 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A16F) |
michael@0 | 253 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R32F) |
michael@0 | 254 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A32F) |
michael@0 | 255 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA8) |
michael@0 | 256 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA16F) |
michael@0 | 257 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA32F) |
michael@0 | 258 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB8) |
michael@0 | 259 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB565) |
michael@0 | 260 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB16F) |
michael@0 | 261 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB32F) |
michael@0 | 262 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA8) |
michael@0 | 263 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA5551) |
michael@0 | 264 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA4444) |
michael@0 | 265 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA16F) |
michael@0 | 266 | WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA32F) |
michael@0 | 267 | default: |
michael@0 | 268 | MOZ_ASSERT(false, "unhandled case. Coding mistake?"); |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | #undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | public: |
michael@0 | 275 | |
michael@0 | 276 | void run(WebGLTexelFormat srcFormat, |
michael@0 | 277 | WebGLTexelFormat dstFormat, |
michael@0 | 278 | WebGLTexelPremultiplicationOp premultiplicationOp) |
michael@0 | 279 | { |
michael@0 | 280 | #define WEBGLIMAGECONVERTER_CASE_SRCFORMAT(SrcFormat) \ |
michael@0 | 281 | case SrcFormat: \ |
michael@0 | 282 | return run<SrcFormat>(dstFormat, premultiplicationOp); |
michael@0 | 283 | |
michael@0 | 284 | switch (srcFormat) { |
michael@0 | 285 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R8) |
michael@0 | 286 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A8) |
michael@0 | 287 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R16F) |
michael@0 | 288 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A16F) |
michael@0 | 289 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R32F) |
michael@0 | 290 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A32F) |
michael@0 | 291 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA8) |
michael@0 | 292 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA16F) |
michael@0 | 293 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA32F) |
michael@0 | 294 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB8) |
michael@0 | 295 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRX8) // source format only |
michael@0 | 296 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB565) |
michael@0 | 297 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB16F) |
michael@0 | 298 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB32F) |
michael@0 | 299 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA8) |
michael@0 | 300 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRA8) |
michael@0 | 301 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA5551) |
michael@0 | 302 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA4444) |
michael@0 | 303 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA16F) |
michael@0 | 304 | WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA32F) |
michael@0 | 305 | default: |
michael@0 | 306 | MOZ_ASSERT(false, "unhandled case. Coding mistake?"); |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | #undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT |
michael@0 | 310 | } |
michael@0 | 311 | |
michael@0 | 312 | WebGLImageConverter(size_t width, size_t height, |
michael@0 | 313 | const void* srcStart, void* dstStart, |
michael@0 | 314 | ptrdiff_t srcStride, ptrdiff_t dstStride) |
michael@0 | 315 | : mWidth(width), mHeight(height), |
michael@0 | 316 | mSrcStart(srcStart), mDstStart(dstStart), |
michael@0 | 317 | mSrcStride(srcStride), mDstStride(dstStride), |
michael@0 | 318 | mAlreadyRun(false), mSuccess(false) |
michael@0 | 319 | {} |
michael@0 | 320 | |
michael@0 | 321 | bool Success() const { |
michael@0 | 322 | return mSuccess; |
michael@0 | 323 | } |
michael@0 | 324 | }; |
michael@0 | 325 | |
michael@0 | 326 | } // end anonymous namespace |
michael@0 | 327 | |
michael@0 | 328 | void |
michael@0 | 329 | WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride, |
michael@0 | 330 | const uint8_t* src, uint8_t *dst, |
michael@0 | 331 | WebGLTexelFormat srcFormat, bool srcPremultiplied, |
michael@0 | 332 | WebGLTexelFormat dstFormat, bool dstPremultiplied, |
michael@0 | 333 | size_t dstTexelSize) |
michael@0 | 334 | { |
michael@0 | 335 | if (width <= 0 || height <= 0) |
michael@0 | 336 | return; |
michael@0 | 337 | |
michael@0 | 338 | const bool FormatsRequireNoPremultiplicationOp = |
michael@0 | 339 | !HasAlpha(srcFormat) || |
michael@0 | 340 | !HasColor(srcFormat) || |
michael@0 | 341 | !HasColor(dstFormat); |
michael@0 | 342 | |
michael@0 | 343 | if (srcFormat == dstFormat && |
michael@0 | 344 | (FormatsRequireNoPremultiplicationOp || srcPremultiplied == dstPremultiplied)) |
michael@0 | 345 | { |
michael@0 | 346 | // fast exit path: we just have to memcpy all the rows. |
michael@0 | 347 | // |
michael@0 | 348 | // The case where absolutely nothing needs to be done is supposed to have |
michael@0 | 349 | // been handled earlier (in TexImage2D_base, etc). |
michael@0 | 350 | // |
michael@0 | 351 | // So the case we're handling here is when even though no format conversion is needed, |
michael@0 | 352 | // we still might have to flip vertically and/or to adjust to a different stride. |
michael@0 | 353 | |
michael@0 | 354 | MOZ_ASSERT(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy"); |
michael@0 | 355 | |
michael@0 | 356 | size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree |
michael@0 | 357 | const uint8_t* ptr = src; |
michael@0 | 358 | const uint8_t* src_end = src + height * srcStride; |
michael@0 | 359 | |
michael@0 | 360 | uint8_t* dst_row = mPixelStoreFlipY |
michael@0 | 361 | ? dst + (height-1) * dstStride |
michael@0 | 362 | : dst; |
michael@0 | 363 | ptrdiff_t dstStrideSigned(dstStride); |
michael@0 | 364 | ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned; |
michael@0 | 365 | |
michael@0 | 366 | while(ptr != src_end) { |
michael@0 | 367 | memcpy(dst_row, ptr, row_size); |
michael@0 | 368 | ptr += srcStride; |
michael@0 | 369 | dst_row += dst_delta; |
michael@0 | 370 | } |
michael@0 | 371 | return; |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | uint8_t* dstStart = dst; |
michael@0 | 375 | ptrdiff_t signedDstStride = dstStride; |
michael@0 | 376 | if (mPixelStoreFlipY) { |
michael@0 | 377 | dstStart = dst + (height - 1) * dstStride; |
michael@0 | 378 | signedDstStride = -signedDstStride; |
michael@0 | 379 | } |
michael@0 | 380 | |
michael@0 | 381 | WebGLImageConverter converter(width, height, src, dstStart, srcStride, signedDstStride); |
michael@0 | 382 | |
michael@0 | 383 | const WebGLTexelPremultiplicationOp premultiplicationOp |
michael@0 | 384 | = FormatsRequireNoPremultiplicationOp ? WebGLTexelPremultiplicationOp::None |
michael@0 | 385 | : (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply |
michael@0 | 386 | : (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unpremultiply |
michael@0 | 387 | : WebGLTexelPremultiplicationOp::None; |
michael@0 | 388 | |
michael@0 | 389 | converter.run(srcFormat, dstFormat, premultiplicationOp); |
michael@0 | 390 | |
michael@0 | 391 | if (!converter.Success()) { |
michael@0 | 392 | // the dst image may be left uninitialized, so we better not try to |
michael@0 | 393 | // continue even in release builds. This should never happen anyway, |
michael@0 | 394 | // and would be a bug in our code. |
michael@0 | 395 | NS_RUNTIMEABORT("programming mistake in WebGL texture conversions"); |
michael@0 | 396 | } |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | } // end namespace mozilla |