I have also tried the +1 rounding trick, but have seen overflows (wrapping back to 0) in some modes, since we are asymmetrically applying the add to only one of the alpha components.
On Feb 27, 10:22 am, Eric <[email protected]> wrote: > For a great article about this please > seehttp://www.stereopsis.com/doubleblend.html > by Michael Herf (from Picasa) > > For the default blending function it describes an optimized version of > the one Mike Reed mentions but also the one I referred to which I > think is the fastest one possible. For this case it does satisfy the > OpenGL criteria and I imagine for Android that speed is more > important. > > On Feb 27, 2:05 pm, [email protected] wrote: > > > static inline U8CPU SkMulDiv255Round(U8CPU a, U8CPU b) { > > SkASSERT((uint8_t)a == a); > > SkASSERT((uint8_t)b == b); > > unsigned prod = SkMulS16(a, b) + 128; > > return (prod + (prod >> 8)) >> 8; > > > } > > > This is used in some places for blending. I think it has even smaller > > error than (a + (a >> 7)), though it is slower. > > > On Feb 27, 6:29 am, pixelflinger <[email protected]> wrote: > > > > The problem in the code you pointed to can be improved by rounding the > > > result (add 0x80 before shifting by 8). > > > > result = S + D * (((256 - (A + (A>>7))) + 0x80) >> 8) > > > > What you're proposing is interesting, essentially: > > > > result = S + (D * (256 - A))>>8 > > > > Basically, this has a bigger error, but it is biased on the "opaque" > > > side, so it never causes a pixel to become more transparent. It looks > > > like it works very well for the premultiplied alpha case above. I'll > > > put this on the list of stuff to investigate further :-) > > > Thanks for the feedback. > > > > Mathias > > > > On Feb 27, 1:56 am, Eric <[email protected]> wrote: > > > > > Correct, that is why I mentioned it cannot be used in all cases. The > > > > fact is that for some PorterDuff modes (see the SrcOver example > > > > above ) the current implementation with the shift optimization > > > > produces incorrect results because fully opaque pixels (with alpha > > > > 255) that should remain fully opaque turn into partially transparent > > > > pixels (with alpha 254). It is only a very slight difference but it > > > > can be avoided. > > > > > On Feb 27, 8:52 am, pixelflinger <[email protected]> wrote: > > > > > > Hello, > > > > > > If you compute the errors, that is: > > > > > > a*float(256/255) - (a + (a>>7)) > > > > > > and > > > > > > a*float(256/255) - (a + 1) > > > > > > you'll see that the former is a better choice; the maximum error is > > > > > smaller (0.5 instead of 1.0) > > > > > > The later is also incorrect per the OpenGL blending specification > > > > > because it doesn't map "0" to "0" (you're lucky in that specific > > > > > example, but if you were to dither the result, it wouldn't work). > > > > > > Additionally, doing the actual computation in integer: > > > > > > (a * 256)/255 > > > > > > will give you the same result than with the equation used in skia. > > > > > > Mathias > > > > > > On Feb 26, 11:04 am, Eric <[email protected]> wrote: > > > > > > > When using some of the PorterDuff modes in the Android SDK incorrect > > > > > > alpha values are produced. For example the following: > > > > > > > Bitmap bitmap = Bitmap.createBitmap(100, 100, > > > > > > Bitmap.Config.ARGB_8888); > > > > > > bitmap.eraseColor(0xff000000); // Black with alpha 255 > > > > > > Canvas canvas = new Canvas(bitmap); > > > > > > canvas.drawColor(0x80000000, PorterDuff.Mode.SRC_OVER); // Black > > > > > > with > > > > > > alpha 128 > > > > > > > results in 0xfe000000 so an alpha value of 254 instead of 255 > > > > > > > After some digging in the source code I traced it back to incorrect > > > > > > use of SkAlpha255To256 defined in > > > > > > > platform/external/skia.git/include/core/SkColorPriv.h > > > > > > > 34 static inline unsigned SkAlpha255To256(U8CPU alpha) { > > > > > > 35 SkASSERT(SkToU8(alpha) == alpha); > > > > > > 36 return alpha + (alpha >> 7); > > > > > > 37 } > > > > > > > It is frequently used in the PorterDuff blending functions, below is > > > > > > SRC_OVER from: > > > > > > > platform/external/skia.git/src/core/SkXfermode.cpp > > > > > > > 347 // kSrcOver_Mode, //!< [Sa + (1 - Sa)*Da, Sc + (1 - Sa)*Dc] > > > > > > 348 static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) > > > > > > { > > > > > > 349 return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - > > > > > > SkGetPackedA32(src))); > > > > > > 350 } > > > > > > > Running the above numbers for alpha it produces 128 + (255 * 127) > > > > > > >> 8 > > > > > > = 254. Doing it without the shift optimization returns 128 + (255 * > > > > > > 127) / 255 = 255. > > > > > > > Fro some of these functions (not all) it would be better to use a > > > > > > SkAlpha255To256 defined as > > > > > > > static inline unsigned SkAlpha255To256(U8CPU alpha) { > > > > > > SkASSERT(SkToU8(alpha) == alpha); > > > > > > return alpha + 1; > > > > > > > } > > > > > > > which is not 100% accurate either but you can still use the shift > > > > > > trick and it does produce correct result when alpha is 0 and when > > > > > > alpha is 255. Any thoughts? --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "android-framework" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/android-framework?hl=en -~----------~----~----~----~------~----~------~--~---
