hostsupport/hostopenvg/src/src/sfDynamicPixelPipe.cpp
branchbug235_bringup_0
changeset 53 c2ef9095503a
parent 24 a3f46bb01be2
equal deleted inserted replaced
52:39e5f73667ba 53:c2ef9095503a
       
     1 /* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2  *
       
     3  * Permission is hereby granted, free of charge, to any person obtaining a
       
     4  * copy of this software and /or associated documentation files
       
     5  * (the "Materials "), to deal in the Materials without restriction,
       
     6  * including without limitation the rights to use, copy, modify, merge,
       
     7  * publish, distribute, sublicense, and/or sell copies of the Materials,
       
     8  * and to permit persons to whom the Materials are furnished to do so,
       
     9  * subject to the following conditions:
       
    10  *
       
    11  * The above copyright notice and this permission notice shall be included
       
    12  * in all copies or substantial portions of the Materials.
       
    13  *
       
    14  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
       
    18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
       
    19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
       
    20  * THE USE OR OTHER DEALINGS IN THE MATERIALS.
       
    21  */
       
    22 
       
    23 // This file contains the generated pixel-pipeline code and provides
       
    24 // interface to compile and run them.
       
    25 
       
    26 #ifndef __RIRASTERIZER_H
       
    27 #   include "riRasterizer.h"
       
    28 #endif
       
    29 
       
    30 #ifndef __RIPIXELPIPE_H
       
    31 #   include "riPixelPipe.h"
       
    32 #endif
       
    33 
       
    34 #ifndef __SFDYNAMICPIXELPIPE_H
       
    35 #   include "sfDynamicPixelPipe.h"
       
    36 #endif
       
    37 
       
    38 #ifndef __RIUTILS_H
       
    39 #   include "riUtils.h"
       
    40 #endif
       
    41 
       
    42 #ifndef __SFMASK_H
       
    43 #   include "sfMask.h"
       
    44 #endif
       
    45 
       
    46 #ifndef __RIIMAGE_H
       
    47 #   include "riImage.h"
       
    48 #endif
       
    49 
       
    50 #if defined(RI_DEBUG)
       
    51 #   include <stdio.h>
       
    52 #endif
       
    53 
       
    54 namespace OpenVGRI {
       
    55 
       
    56 RI_INLINE static bool alwaysLoadDst(const PixelPipe::SignatureState& state)
       
    57 {
       
    58     if (!state.isRenderToMask)
       
    59     {
       
    60         if (state.hasImage)
       
    61             return true;
       
    62 
       
    63         VGBlendMode bm = state.blendMode;
       
    64 
       
    65         if (bm == VG_BLEND_SRC_IN ||
       
    66                 bm == VG_BLEND_DST_OVER ||
       
    67                 bm == VG_BLEND_DST_IN ||
       
    68                 bm == VG_BLEND_ADDITIVE ||
       
    69                 bm == VG_BLEND_MULTIPLY ||
       
    70                 bm == VG_BLEND_SCREEN ||
       
    71                 bm == VG_BLEND_DARKEN ||
       
    72                 bm == VG_BLEND_LIGHTEN)
       
    73         {
       
    74             return true;
       
    75         } else
       
    76         {
       
    77             return false;
       
    78         }
       
    79     }
       
    80     else
       
    81     {
       
    82         switch (state.maskOperation)
       
    83         {
       
    84         case VG_SET_MASK:
       
    85             return false;
       
    86         default:
       
    87             return true;
       
    88         }
       
    89     }
       
    90 }
       
    91 
       
    92 RI_INLINE static bool canSolidFill(const PixelPipe::SignatureState& state)
       
    93 {
       
    94     if (state.isRenderToMask)
       
    95     {
       
    96         if (state.maskOperation == VG_SET_MASK ||
       
    97             state.maskOperation == VG_UNION_MASK)
       
    98             return true;
       
    99         // \note SUBTRACT is also possible.
       
   100         return false;
       
   101     }
       
   102 
       
   103     if (state.paintType != VG_PAINT_TYPE_COLOR)
       
   104         return false;
       
   105 
       
   106     if (state.hasImage)
       
   107         return false;
       
   108 
       
   109     // Some blendmodes can use dst color even if coverage == 1.0
       
   110     if (state.blendMode != VG_BLEND_SRC && state.blendMode != VG_BLEND_SRC_OVER)
       
   111         return false;
       
   112 
       
   113     if (state.hasMasking)
       
   114         return false;
       
   115 
       
   116     if (state.fillColorTransparent)
       
   117         return false;
       
   118 
       
   119     if (state.hasColorTransform)
       
   120         return false; // \todo Trace solid color alpha -> 1.0
       
   121 
       
   122     return true;
       
   123 }
       
   124 
       
   125 RI_INLINE static int intReflectRepeat(int n, int bits)
       
   126 {
       
   127     const int mask = (1<<bits)-1;
       
   128     return (n ^ (n << (31 - bits) >> 31)) & mask;
       
   129 }
       
   130 
       
   131 RI_INLINE static void applyGradientRepeat(int& sx0, int& sx1, PixelPipe::TilingMode sm)
       
   132 {
       
   133     switch (sm)
       
   134     {
       
   135     case PixelPipe::TILING_MODE_PAD:
       
   136         sx0 = RI_INT_CLAMP(sx0, 0, PixelPipe::SAMPLE_MASK);
       
   137         sx1 = RI_INT_CLAMP(sx1, 0, PixelPipe::SAMPLE_MASK);
       
   138         break;
       
   139     case PixelPipe::TILING_MODE_REFLECT:
       
   140         sx0 = intReflectRepeat(sx0, PixelPipe::SAMPLE_BITS);
       
   141         sx1 = intReflectRepeat(sx1, PixelPipe::SAMPLE_BITS);
       
   142         break;
       
   143     default:
       
   144         RI_ASSERT(sm == PixelPipe::TILING_MODE_REPEAT);
       
   145 
       
   146         sx0 = sx0 & PixelPipe::SAMPLE_MASK;
       
   147         sx1 = sx1 & PixelPipe::SAMPLE_MASK;
       
   148         break;
       
   149     }
       
   150 
       
   151     RI_ASSERT(sx0 >= 0 && sx0 < (1<<Paint::GRADIENT_LUT_BITS));
       
   152     RI_ASSERT(sx1 >= 0 && sx1 < (1<<Paint::GRADIENT_LUT_BITS));
       
   153 
       
   154 }
       
   155 
       
   156 RI_INLINE static IntegerColor readLUTColor(const PixelPipe::PPUniforms& uniforms, int i)
       
   157 {
       
   158     RI_ASSERT(i >= 0 && i <= Paint::GRADIENT_LUT_MASK);
       
   159     return uniforms.gradientLookup[i];
       
   160 }
       
   161 
       
   162 
       
   163 /**
       
   164  * \brief   Sample linear gradient using integer-arithmetic.
       
   165  * \note    The actual gradient computation is done piecewise within the
       
   166  *          pixel-pipeline.
       
   167  */
       
   168 RI_INLINE static IntegerColor intLinearGradient(const PixelPipe::SignatureState& state, const PixelPipe::PPUniforms& u, const PixelPipe::PPVariants& v)
       
   169 {
       
   170     RIint32 sx0 = v.sx >> (PixelPipe::GRADIENT_BITS - PixelPipe::SAMPLE_BITS);
       
   171     RIint32 sx1 = sx0 + 1;
       
   172 
       
   173     applyGradientRepeat(sx0, sx1, state.paintTilingMode);
       
   174 
       
   175     IntegerColor ic0 = readLUTColor(u, sx0 >> (PixelPipe::SAMPLE_BITS - Paint::GRADIENT_LUT_BITS));
       
   176 
       
   177     if (true)
       
   178     {
       
   179         return ic0;
       
   180     } else
       
   181     {
       
   182         // bilinear interpolation
       
   183         //RIint32 f1 = sx0; 
       
   184         readLUTColor(u, sx1 >> (PixelPipe::SAMPLE_BITS - Paint::GRADIENT_LUT_BITS));
       
   185         RI_ASSERT(false);
       
   186         return IntegerColor(0,0,0,0);
       
   187     }
       
   188 } 
       
   189 
       
   190 /**
       
   191  * \brief   Radial gradient implementation for the integer-pipeline. Will use float at least
       
   192  *          for the square-root. Will return integer-color always.
       
   193  */
       
   194 RI_INLINE static IntegerColor intRadialGradient(const PixelPipe::SignatureState& state, const PixelPipe::PPUniforms& u, const PixelPipe::PPVariants& v)
       
   195 {
       
   196     RGScalar a = (v.rx * u.rfxp) + (v.ry * u.rfyp);
       
   197     RGScalar b = u.rsqrp * (RI_SQR(v.rx) + RI_SQR(v.ry));
       
   198     RGScalar c = RI_SQR((v.rx * u.rfyp) - (v.ry * u.rfxp));
       
   199     RGScalar d = b - c;
       
   200     RI_ASSERT(!RI_ISNAN(d) ? d >= 0.0f : true);
       
   201     RGScalar g = (a + sqrtf(d));
       
   202 
       
   203     int sx0 = RI_FLOAT_TO_FX(g, PixelPipe::SAMPLE_BITS);
       
   204     int sx1 = sx0 + 1;
       
   205 
       
   206     applyGradientRepeat(sx0, sx1, state.paintTilingMode);
       
   207 
       
   208     IntegerColor ic0 = readLUTColor(u, sx0 >> (PixelPipe::SAMPLE_BITS - Paint::GRADIENT_LUT_BITS));
       
   209     RI_ASSERT(ic0.r <= 255);
       
   210     RI_ASSERT(ic0.g <= 255);
       
   211     RI_ASSERT(ic0.b <= 255);
       
   212     RI_ASSERT(ic0.a <= 255);
       
   213 
       
   214     if (false)
       
   215     {
       
   216         // Linear interpolation of 2 gradient samples.
       
   217         IntegerColor ic1 = readLUTColor(u, sx1 >> (PixelPipe::SAMPLE_BITS - Paint::GRADIENT_LUT_BITS));
       
   218         //int fx0 = sx0 & PixelPipe::SAMPLE_MASK;
       
   219         //int fx1 = PixelPipe::SAMPLE_MASK - fx0;
       
   220         
       
   221     }
       
   222 
       
   223     return ic0;
       
   224 }
       
   225 
       
   226 RI_INLINE static bool applyPatternRepeat(int &x, int &y, PixelPipe::TilingMode tilingMode)
       
   227 {
       
   228     switch (tilingMode)
       
   229     {
       
   230     case PixelPipe::TILING_MODE_PAD:
       
   231         x = RI_INT_CLAMP(x, 0, PixelPipe::GRADIENT_MASK);
       
   232         y = RI_INT_CLAMP(y, 0, PixelPipe::GRADIENT_MASK);
       
   233         break; 
       
   234     case PixelPipe::TILING_MODE_REPEAT:
       
   235         x = x & PixelPipe::GRADIENT_MASK;
       
   236         y = y & PixelPipe::GRADIENT_MASK;
       
   237         break;
       
   238     case PixelPipe::TILING_MODE_REFLECT:
       
   239         x = intReflectRepeat(x, PixelPipe::GRADIENT_BITS);
       
   240         y = intReflectRepeat(y, PixelPipe::GRADIENT_BITS);
       
   241         break;
       
   242     default:
       
   243         RI_ASSERT(tilingMode == PixelPipe::TILING_MODE_FILL);
       
   244         // Do nothing -> Fill is checked on integer coordinates.
       
   245         break;
       
   246     }
       
   247     return false;
       
   248 }
       
   249 
       
   250 /**
       
   251  * \brief   Same as applyPatternRepeat, but with pattern-space integer coordinates without
       
   252  *          fractional part.
       
   253  * \note    Assumes that the coordinate is in range [0,width or height].
       
   254  */
       
   255 RI_INLINE static bool applyPatternSampleRepeat(int &x, int &y, int w, int h, PixelPipe::TilingMode tilingMode)
       
   256 {
       
   257 
       
   258     switch (tilingMode)
       
   259     {
       
   260     case PixelPipe::TILING_MODE_PAD:
       
   261         RI_ASSERT(x >= 0 && x <= w);
       
   262         RI_ASSERT(y >= 0 && y <= h);
       
   263         if (x >= w) x = w-1;
       
   264         if (y >= h) y = h-1;
       
   265         break;
       
   266     case PixelPipe::TILING_MODE_REPEAT:
       
   267         RI_ASSERT(x >= 0 && x <= w);
       
   268         RI_ASSERT(y >= 0 && y <= h);
       
   269         if (x >= w) x = 0;
       
   270         if (y >= h) y = 0;
       
   271         break;
       
   272     case PixelPipe::TILING_MODE_REFLECT:
       
   273         RI_ASSERT(x >= 0 && x <= w);
       
   274         RI_ASSERT(y >= 0 && y <= h);
       
   275         if (x >= w) x = w-1; // w-2?
       
   276         if (y >= h) y = h-1; // h-2?
       
   277         break;
       
   278     default:
       
   279         RI_ASSERT(tilingMode == PixelPipe::TILING_MODE_FILL);
       
   280         if (x < 0 || x >= w) return true;
       
   281         if (y < 0 || y >= h) return true;
       
   282         break;
       
   283     }
       
   284 
       
   285     return false;
       
   286 }
       
   287 
       
   288 RI_INLINE IntegerColor readPattern(const void* basePtr, int stride, const Color::Descriptor& desc, int ix, int iy, const IntegerColor* fillColor, bool fill)
       
   289 {
       
   290     const void* ptr = Image::calculateAddress(basePtr, desc.bitsPerPixel, ix, iy, stride);
       
   291 
       
   292     if (!fill)
       
   293         return IntegerColor(Image::readPackedPixelFromAddress(ptr, desc.bitsPerPixel, ix), desc);
       
   294     else
       
   295     {
       
   296         RI_ASSERT(fillColor);
       
   297         return *fillColor; 
       
   298     }
       
   299 
       
   300 }
       
   301 
       
   302 /**
       
   303  * \brief   Rescale the result of bilinear interpolation.
       
   304  * \todo    See if this or individual shifts and rounds are faster on x86
       
   305  */
       
   306 RI_INLINE static RIuint32 bilinearDiv(unsigned int c)
       
   307 {
       
   308     RIuint32 rcp = 33026;
       
   309 
       
   310     RIuint64 m = (RIuint64)c * rcp;
       
   311     RIuint32 d = (RIuint32)(m >> 30);
       
   312     return (d >> 1) + (d & 1);
       
   313 }
       
   314 
       
   315 /**
       
   316  * \brief   Read an optionally filtered sample from an image. For multiple samples, apply repeat
       
   317  *          for all the generated sampling points. This only implements a simple sampling: nearest
       
   318  *          or Linear filtering and is much simpler than the original RI.
       
   319  * \param   image       Image to sample from
       
   320  * \param   sx0         Sample x in .8 fixed point. MUST be within the image except for FILL.
       
   321  * \param   sy0         Sample y in .8 fixed point. MUST be within the image except for FILL.
       
   322  * \param   samplerType Type of the sampler used.
       
   323  * \param   tilingMode  Tiling mode for generated sample points, if required.
       
   324  * \param   fillColor   Color to use for TILING_MODE_FILL
       
   325  * \todo Where should we determine if a NN-sample needs to be unpacked?
       
   326  *       -> It is also easy to just read that sample separately.
       
   327  */
       
   328 RI_INLINE static IntegerColor intSampleImage(
       
   329     const void* ptr,
       
   330     int stride,
       
   331     int w,
       
   332     int h,
       
   333     const Color::Descriptor& desc,
       
   334     RIint32 sx0, 
       
   335     RIint32 sy0, 
       
   336     PixelPipe::SamplerType samplerType, 
       
   337     PixelPipe::TilingMode tilingMode, 
       
   338     const IntegerColor* fillColor)
       
   339 {
       
   340     RI_ASSERT(fillColor || (tilingMode != PixelPipe::TILING_MODE_FILL));
       
   341      
       
   342     // \todo The following code is between low- and high-level representation of sampling.
       
   343     // It should probably be modified to appear fully as low-level, since we want as many
       
   344     // optimizations as possible.
       
   345 
       
   346     const bool bilinear = samplerType == PixelPipe::SAMPLER_TYPE_LINEAR;
       
   347 
       
   348     IntegerColor retColor;
       
   349     bool maybeFill = tilingMode == PixelPipe::TILING_MODE_FILL;
       
   350     bool fillSample = false;
       
   351 
       
   352     RIint32 ix, iy;
       
   353 
       
   354     IntegerColor ic00;
       
   355 
       
   356     RIint32 fx = sx0 & 0xff;
       
   357     RIint32 fy = sy0 & 0xff;
       
   358 
       
   359     ix = sx0 >> PixelPipe::SAMPLE_BITS;
       
   360     iy = sy0 >> PixelPipe::SAMPLE_BITS;
       
   361 
       
   362     if (maybeFill)
       
   363     {
       
   364         if (ix < 0 || ix >= w)
       
   365             fillSample = true;
       
   366         if (iy < 0 || iy >= h)
       
   367             fillSample = true;
       
   368     }
       
   369 
       
   370     ic00 = readPattern(ptr, stride, desc, ix, iy, fillColor, fillSample);
       
   371 
       
   372     if (!bilinear)
       
   373     {
       
   374         retColor = ic00;
       
   375         retColor.expandColor(desc); // \todo Handling of bilinear?
       
   376     }
       
   377     else
       
   378     {
       
   379         // Bilinear filtering.
       
   380 
       
   381         IntegerColor ic01, ic10, ic11;
       
   382         IntegerColor t0, t1;
       
   383 
       
   384         int xs = ix + 1;
       
   385         int ys = iy;
       
   386 
       
   387         fillSample = applyPatternSampleRepeat(xs, ys, w, h, tilingMode);
       
   388         ic01 = readPattern(ptr, stride, desc, xs, ys, fillColor, fillSample);
       
   389 
       
   390         t0 = IntegerColor::linearBlendNS(ic00, ic01, fx);
       
   391 
       
   392         xs = ix;
       
   393         ys = iy+1;
       
   394         fillSample = applyPatternSampleRepeat(xs, ys, w, h, tilingMode);
       
   395         ic10 = readPattern(ptr, stride, desc, xs, ys, fillColor, fillSample);
       
   396 
       
   397         xs = ix+1;
       
   398         ys = iy+1;
       
   399         fillSample = applyPatternSampleRepeat(xs, ys, w, h, tilingMode);
       
   400         ic11 = readPattern(ptr, stride, desc, xs, ys, fillColor, fillSample);
       
   401     
       
   402         t1 = IntegerColor::linearBlendNS(ic10, ic11, fx);
       
   403     
       
   404         retColor = IntegerColor::linearBlendNS(t0, t1, fy);
       
   405 
       
   406         retColor.r = bilinearDiv(retColor.r);
       
   407         retColor.g = bilinearDiv(retColor.g);
       
   408         retColor.b = bilinearDiv(retColor.b);
       
   409         retColor.a = bilinearDiv(retColor.a);
       
   410 
       
   411         return retColor;
       
   412     }
       
   413 
       
   414     return retColor;
       
   415 }
       
   416 
       
   417 RI_INLINE static RIint32 gradientToFixedCoords(RIint32 gradCoord, RIint32 dim)
       
   418 {
       
   419     return (RIint32)(((RIint64)dim * gradCoord) >> (PixelPipe::GRADIENT_BITS - PixelPipe::SAMPLE_BITS));
       
   420 }
       
   421 
       
   422 
       
   423 RI_INLINE static IntegerColor intPattern(const PixelPipe::SignatureState &state, const PixelPipe::PPUniforms& u, const PixelPipe::PPVariants& v)
       
   424 {
       
   425     // \todo The following code is between low- and high-level representation of sampling.
       
   426     // It should probably be modified to appear fully as low-level, since we want as many
       
   427     // optimizations as possible.
       
   428 
       
   429     // "External" variables
       
   430     const PixelPipe::TilingMode tilingMode = state.paintTilingMode;
       
   431     const IntegerColor fillColor = u.tileFillColor;
       
   432     const int w = u.paint_width;
       
   433     const int h = u.paint_height;
       
   434 
       
   435     IntegerColor retColor;
       
   436 
       
   437     RIint32 sx0 = v.sx;
       
   438     RIint32 sy0 = v.sy;
       
   439 
       
   440     IntegerColor ic00;
       
   441 
       
   442     applyPatternRepeat(sx0, sy0, tilingMode);
       
   443     sx0 = gradientToFixedCoords(sx0, w);
       
   444     sy0 = gradientToFixedCoords(sy0, h);
       
   445     //sx0 = (RIint32)(((RIint64)w * sx0) >> (PixelPipe::GRADIENT_BITS - PixelPipe::SAMPLE_BITS));
       
   446     //sy0 = (RIint32)(((RIint64)h * sy0) >> (PixelPipe::GRADIENT_BITS - PixelPipe::SAMPLE_BITS));
       
   447 
       
   448     const void* ptr = u.patternPtr;
       
   449     const int stride = u.patternStride;
       
   450     const Color::Descriptor& desc = state.patternDesc;
       
   451 
       
   452     return intSampleImage(ptr, stride, w, h, desc, sx0, sy0, state.paintSampler, tilingMode, &fillColor);
       
   453 }
       
   454 
       
   455 RI_INLINE static bool formatPremultipliedAfterSampling(const Color::Descriptor& desc, PixelPipe::SamplerType samplerType, PixelPipe::ImageGradientType gradientType)
       
   456 {
       
   457     // Sampled at pixel centers -> no processing of colors -> does not get premultiplied
       
   458     if (gradientType == PixelPipe::GRADIENT_TYPE_INTEGER)
       
   459         return desc.isPremultiplied();
       
   460 
       
   461     if (samplerType != PixelPipe::SAMPLER_TYPE_NEAREST)
       
   462         return true;
       
   463 
       
   464     return desc.isPremultiplied();
       
   465 }
       
   466 
       
   467 RI_INLINE static bool imagePremultipliedAfterSampling(const PixelPipe::SignatureState& state)
       
   468 {
       
   469     RI_ASSERT(state.hasImage);
       
   470 
       
   471     return formatPremultipliedAfterSampling(state.imageDesc, state.imageSampler, state.imageGradientType);
       
   472 }
       
   473 
       
   474 RI_INLINE static bool gradientPremultipliedAfterSampling(const PixelPipe::SignatureState& state)
       
   475 {
       
   476     if (state.paintSampler != PixelPipe::SAMPLER_TYPE_NEAREST)
       
   477         return true;
       
   478 
       
   479     return true;
       
   480 
       
   481     // Otherwise, the gradient value is a single sample, and should be in the destination
       
   482     // color-space:
       
   483     //return state.dstDesc.isPremultiplied();
       
   484 }
       
   485 
       
   486 RI_INLINE static bool patternPremultipliedAfterSampling(const PixelPipe::SignatureState& state)
       
   487 {
       
   488     RI_ASSERT(state.paintType == VG_PAINT_TYPE_PATTERN);
       
   489 
       
   490     return formatPremultipliedAfterSampling(state.patternDesc, state.paintSampler, PixelPipe::GRADIENT_TYPE_FIXED);
       
   491 }
       
   492 
       
   493 /**
       
   494  * \brief   Returns true if generated paint will be in RGB, false if luminance.
       
   495  */
       
   496 RI_INLINE static bool paintInRGB(const PixelPipe::SignatureState& state)
       
   497 {
       
   498     if (state.paintType != VG_PAINT_TYPE_PATTERN)
       
   499         return true;
       
   500 
       
   501     return !state.patternDesc.isLuminance();
       
   502 }
       
   503 
       
   504 
       
   505 /**
       
   506  * \brief   Applies color transform to input color
       
   507  * \param   isNonlinear "true" if input is nonlinear. This only affects luminance -> RGB conversion,
       
   508  *          other conversions happen in the input color-space.
       
   509  * \note    Leaves the color unpremultiplied, in source color-space and converts luminance to RGB
       
   510  * \todo    isNonlinear is not needed. It can be deduced from the state information!
       
   511  */
       
   512 RI_INLINE static IntegerColor maybeColorTransform(const PixelPipe::SignatureState& state, const IntegerColor& c, const RIint32* colorTransformValues, bool isNonlinear)
       
   513 {
       
   514     if (!state.hasColorTransform)
       
   515         return c;
       
   516 
       
   517     RI_ASSERT(state.hasImage || state.paintType == VG_PAINT_TYPE_PATTERN);
       
   518     
       
   519     IntegerColor r = c;
       
   520 
       
   521     if (state.imageMode == VG_DRAW_IMAGE_MULTIPLY)
       
   522     {
       
   523         r.unpremultiply();
       
   524     }
       
   525     else if (state.imageMode == VG_DRAW_IMAGE_STENCIL || state.paintType == VG_PAINT_TYPE_PATTERN)
       
   526     {
       
   527         // -> Check pattern
       
   528         if (patternPremultipliedAfterSampling(state))
       
   529             r.unpremultiply(); 
       
   530     }
       
   531     else
       
   532     {
       
   533         // -> Check image
       
   534         if (imagePremultipliedAfterSampling(state))
       
   535             r.unpremultiply();
       
   536     }
       
   537 
       
   538     // Check if it is necessary to convert to RGB:
       
   539     if (state.imageMode == VG_DRAW_IMAGE_MULTIPLY)
       
   540     {
       
   541         if (state.imageDesc.isLuminance() && !paintInRGB(state))
       
   542         {
       
   543             r.fullLuminanceToRGB(false, isNonlinear, false, isNonlinear);
       
   544         }
       
   545     }
       
   546     else if (state.imageMode == VG_DRAW_IMAGE_STENCIL)
       
   547     {
       
   548         if (state.patternDesc.isLuminance())
       
   549             r.fullLuminanceToRGB(false, isNonlinear, false, isNonlinear);
       
   550     }
       
   551     
       
   552     // \todo Use lookup-tables in some cases?
       
   553     r.r = (((RIint32)r.r * colorTransformValues[0]) >> PixelPipe::COLOR_TRANSFORM_BITS) + colorTransformValues[4];
       
   554     r.g = (((RIint32)r.g * colorTransformValues[1]) >> PixelPipe::COLOR_TRANSFORM_BITS) + colorTransformValues[5];
       
   555     r.b = (((RIint32)r.b * colorTransformValues[2]) >> PixelPipe::COLOR_TRANSFORM_BITS) + colorTransformValues[6];
       
   556     r.a = (((RIint32)r.a * colorTransformValues[3]) >> PixelPipe::COLOR_TRANSFORM_BITS) + colorTransformValues[7];
       
   557 
       
   558     // Clamp (integerColor?)
       
   559     r.r = (RIuint32)RI_INT_CLAMP((int)r.r, 0, 255);
       
   560     r.g = (RIuint32)RI_INT_CLAMP((int)r.g, 0, 255);
       
   561     r.b = (RIuint32)RI_INT_CLAMP((int)r.b, 0, 255);
       
   562     r.a = (RIuint32)RI_INT_CLAMP((int)r.a, 0, 255);
       
   563 
       
   564 
       
   565     return r;
       
   566 }
       
   567 
       
   568 /// Some rounding multiplications for blends:
       
   569 
       
   570 /**
       
   571  * \brief   Multiply with rounding.
       
   572  */
       
   573 RI_INLINE static RIuint32 rMul2(RIuint32 c0, RIuint32 c1, RIuint32 k0, RIuint32 k1)
       
   574 {
       
   575     RIuint32 t = c0 * k0 + c1 * k1; 
       
   576     //RIuint32 r = (t + (t>>9)) >> 8;
       
   577     RIuint32 r = (t + (1>>7))>>8;
       
   578     RI_ASSERT(r <= 255);
       
   579     return r;
       
   580 }
       
   581 
       
   582 /**
       
   583  * \brief   Returns rounding color-multiplication: c0 + c1 * k
       
   584  */
       
   585 RI_INLINE static RIuint32 rMul1(RIuint32 c0, RIuint32 c1, RIuint32 k)
       
   586 {
       
   587     RIuint32 t = c1 * k;
       
   588     RIuint32 r = c0 + ((t + (t >> 7)) >> 8);
       
   589     RI_ASSERT(r <= 255);
       
   590     return r;
       
   591 }
       
   592 
       
   593 /**
       
   594  * \brief   Fixed-point multiplication
       
   595  */
       
   596 RI_INLINE static RIuint32 rMul(RIuint32 c0, RIuint32 f)
       
   597 {
       
   598     RIuint32 t = c0 * f;
       
   599     return (t + (1<<7))>>8;
       
   600 }
       
   601 
       
   602 /**
       
   603  * \brief   Multiply two colors [0, 255]
       
   604  */
       
   605 RI_INLINE static RIuint32 cMul(RIuint32 c0, RIuint32 c1)
       
   606 {
       
   607     RIuint32 t = c0 * c1;
       
   608     RIuint32 r = (t + (t >> 9)) >> 8;
       
   609     //RIuint32 t = c0 * c1;
       
   610     //RIuint32 r = (t + (t >> 7))>>8;
       
   611     RI_ASSERT(r <= 255);
       
   612     return r;
       
   613 }
       
   614 
       
   615 // \todo Are signed versions required?
       
   616 RI_INLINE static RIuint32 cMin(RIuint32 c0, RIuint32 c1)
       
   617 {
       
   618     return c0 <= c1 ? c0 : c1;
       
   619 }
       
   620 
       
   621 RI_INLINE static RIuint32 cMax(RIuint32 c0, RIuint32 c1)
       
   622 {
       
   623     return c0 >= c1 ? c0 : c1;
       
   624 }
       
   625 
       
   626 /**
       
   627  * \brief   Blends two integer colors. Only considers the alpha-channels within
       
   628  *          the colors themselves. There should be a separate function to do
       
   629  *          blending with individual channel-alphas.
       
   630  * \note    It is also possible that LLVM is able to detect, whether individual alpha-
       
   631  *          channels contain a single/multi alpha
       
   632  * \todo    Overall, check how much and how fast LLVM is able to optimize out unused
       
   633  *          expressions.
       
   634  */
       
   635 RI_INLINE static IntegerColor blendIntegerColors(const IntegerColor& s, const IntegerColor& d, VGBlendMode blendMode)
       
   636 {
       
   637     IntegerColor r;
       
   638 
       
   639     switch(blendMode)
       
   640     {
       
   641     case VG_BLEND_SRC:
       
   642         r = s;
       
   643         break;
       
   644 
       
   645     case VG_BLEND_SRC_OVER:
       
   646     {
       
   647         RIuint32 ia = 255 - s.a;
       
   648         r.r = rMul1(s.r, d.r, ia);
       
   649         r.g = rMul1(s.g, d.g, ia);
       
   650         r.b = rMul1(s.b, d.b, ia);
       
   651         r.a = rMul1(s.a, d.a, ia);
       
   652         break;
       
   653     }
       
   654     case VG_BLEND_DST_OVER:
       
   655     {
       
   656         RIuint32 ia = 255 - d.a;
       
   657         r.r = rMul1(d.r, s.r, ia);
       
   658         r.g = rMul1(d.g, s.g, ia);
       
   659         r.b = rMul1(d.b, s.b, ia);
       
   660         r.a = rMul1(d.a, s.a, ia);
       
   661         break;
       
   662     }
       
   663     case VG_BLEND_SRC_IN:
       
   664     {
       
   665         r.r = cMul(s.r, d.a);
       
   666         r.g = cMul(s.g, d.a);
       
   667         r.b = cMul(s.b, d.a);
       
   668         r.a = cMul(s.a, d.a);
       
   669         break;
       
   670     }
       
   671     case VG_BLEND_DST_IN:
       
   672     {
       
   673         r.r = cMul(d.r, s.a);
       
   674         r.g = cMul(d.g, s.a);
       
   675         r.b = cMul(d.b, s.a);
       
   676         r.a = cMul(d.a, s.a);
       
   677         break;
       
   678     }
       
   679     case VG_BLEND_MULTIPLY:
       
   680     {
       
   681         RIuint32 iasrc, iadst;
       
   682         iasrc = 255 - s.a;
       
   683         iadst = 255 - d.a;
       
   684         r.r = rMul2(s.r, d.r, iadst + d.r, iasrc);
       
   685         r.g = rMul2(s.g, d.g, iadst + d.g, iasrc);
       
   686         r.b = rMul2(s.b, d.b, iadst + d.b, iasrc);
       
   687         r.a = rMul1(s.a, d.a, iasrc);
       
   688         break;
       
   689     }
       
   690     case VG_BLEND_SCREEN:
       
   691     {
       
   692         r.r = rMul1(s.r, d.r, 255 - s.r);
       
   693         r.g = rMul1(s.g, d.g, 255 - s.g);
       
   694         r.b = rMul1(s.b, d.b, 255 - s.b);
       
   695         r.a = rMul1(s.a, d.a, 255 - s.a);
       
   696         break;
       
   697     }
       
   698     case VG_BLEND_DARKEN:
       
   699     {
       
   700         RIuint32 iasrc = 255 - s.a;
       
   701         RIuint32 iadst = 255 - d.a;
       
   702         r.r = cMin(rMul1(s.r, d.r, iasrc), rMul1(d.r, s.r, iadst));
       
   703         r.g = cMin(rMul1(s.g, d.g, iasrc), rMul1(d.g, s.g, iadst));
       
   704         r.b = cMin(rMul1(s.b, d.b, iasrc), rMul1(d.b, s.b, iadst));
       
   705         r.a = rMul1(s.a, d.a, iasrc);
       
   706         break;
       
   707     }
       
   708     case VG_BLEND_LIGHTEN:
       
   709     {
       
   710         // \todo Compact darken w/r lighten?
       
   711         RIuint32 iasrc = 255 - s.a;
       
   712         RIuint32 iadst = 255 - d.a;
       
   713         r.r = cMax(rMul1(s.r, d.r, iasrc), rMul1(d.r, s.r, iadst));
       
   714         r.g = cMax(rMul1(s.g, d.g, iasrc), rMul1(d.g, s.g, iadst));
       
   715         r.b = cMax(rMul1(s.b, d.b, iasrc), rMul1(d.b, s.b, iadst));
       
   716         //although the statement below is equivalent to r.a = s.a + d.a * (1.0f - s.a)
       
   717         //in practice there can be a very slight difference because
       
   718         //of the max operation in the blending formula that may cause color to exceed alpha.
       
   719         //Because of this, we compute the result both ways and return the maximum.
       
   720         r.a = cMax(rMul1(s.a, d.a, iasrc), rMul1(d.a, s.a, iadst));
       
   721         break;
       
   722     }
       
   723     default:
       
   724     {
       
   725         RI_ASSERT(blendMode == VG_BLEND_ADDITIVE);
       
   726         r.r = cMin(s.r + d.r, 255);
       
   727         r.g = cMin(s.g + d.g, 255);
       
   728         r.b = cMin(s.b + d.b, 255);
       
   729         r.a = cMin(s.a + d.a, 255);
       
   730         break;
       
   731     }
       
   732     }
       
   733     return r;
       
   734 
       
   735 }
       
   736 
       
   737 RI_INLINE static IntegerColor blendIntegerStencil(const IntegerColor& s, const IntegerColor& im, const IntegerColor& d, VGBlendMode blendMode)
       
   738 {
       
   739     IntegerColor r;
       
   740 
       
   741     switch(blendMode)
       
   742     {
       
   743     case VG_BLEND_SRC:
       
   744         r = s;
       
   745         break;
       
   746 
       
   747     case VG_BLEND_SRC_OVER:
       
   748     {
       
   749         r.r = rMul1(s.r, d.r, 255 - im.r);
       
   750         r.g = rMul1(s.g, d.g, 255 - im.g);
       
   751         r.b = rMul1(s.b, d.b, 255 - im.b);
       
   752         r.a = rMul1(s.a, d.a, 255 - s.a);
       
   753         break;
       
   754     }
       
   755     case VG_BLEND_DST_OVER:
       
   756     {
       
   757         r = blendIntegerColors(s, d, blendMode);
       
   758         break;
       
   759     }
       
   760     case VG_BLEND_SRC_IN:
       
   761     {
       
   762         r = blendIntegerColors(s, d, blendMode);
       
   763         break;
       
   764     }
       
   765     case VG_BLEND_DST_IN:
       
   766     {
       
   767         r.r = cMul(d.r, im.r);
       
   768         r.g = cMul(d.g, im.g);
       
   769         r.b = cMul(d.b, im.b);
       
   770         r.a = cMul(d.a, s.a);
       
   771         break;
       
   772     }
       
   773     case VG_BLEND_MULTIPLY:
       
   774     {
       
   775         RIuint32 iadst;
       
   776         iadst = 255 - d.a;
       
   777         r.r = rMul2(s.r, d.r, iadst + d.r, 255 - im.r);
       
   778         r.g = rMul2(s.g, d.g, iadst + d.g, 255 - im.g);
       
   779         r.b = rMul2(s.b, d.b, iadst + d.b, 255 - im.b);
       
   780         r.a = rMul1(s.a, d.a, 255 - s.a);
       
   781         break;
       
   782     }
       
   783     case VG_BLEND_SCREEN:
       
   784     {
       
   785         r = blendIntegerColors(s, d, blendMode);
       
   786         break;
       
   787     }
       
   788     case VG_BLEND_DARKEN:
       
   789     {
       
   790         RIuint32 iadst = 255 - d.a;
       
   791         r.r = cMin(rMul1(s.r, d.r, 255 - im.r), rMul1(d.r, s.r, iadst));
       
   792         r.g = cMin(rMul1(s.g, d.g, 255 - im.g), rMul1(d.g, s.g, iadst));
       
   793         r.b = cMin(rMul1(s.b, d.b, 255 - im.b), rMul1(d.b, s.b, iadst));
       
   794         r.a = rMul1(s.a, d.a, 255 - s.a);
       
   795         break;
       
   796     }
       
   797     case VG_BLEND_LIGHTEN:
       
   798     {
       
   799         // \todo Compact darken w/r lighten?
       
   800         RIuint32 iadst = 255 - d.a;
       
   801         r.r = cMax(rMul1(s.r, d.r, 255 - im.r), rMul1(d.r, s.r, iadst));
       
   802         r.g = cMax(rMul1(s.g, d.g, 255 - im.g), rMul1(d.g, s.g, iadst));
       
   803         r.b = cMax(rMul1(s.b, d.b, 255 - im.b), rMul1(d.b, s.b, iadst));
       
   804         //although the statement below is equivalent to r.a = s.a + d.a * (1.0f - s.a)
       
   805         //in practice there can be a very slight difference because
       
   806         //of the max operation in the blending formula that may cause color to exceed alpha.
       
   807         //Because of this, we compute the result both ways and return the maximum.
       
   808         r.a = cMax(rMul1(s.a, d.a, 255 - s.a), rMul1(d.a, s.a, iadst));
       
   809         break;
       
   810     }
       
   811     default:
       
   812     {
       
   813         RI_ASSERT(blendMode == VG_BLEND_ADDITIVE);
       
   814         return blendIntegerColors(s, d, blendMode);
       
   815         break;
       
   816     }
       
   817     }
       
   818     return r;
       
   819 
       
   820 }
       
   821 
       
   822 /**
       
   823  * \brief   Perform SRC_OVER and apply coverage in a single operation.
       
   824  * \note    It is possible to do optimizations like this for other blending operations,
       
   825  *          but they are not as widely used -> optimize if there is a requirement.
       
   826  * \note    Prints are included because GDB is confused about the value of r.
       
   827  */
       
   828 static RI_INLINE IntegerColor srcOverCoverage(const IntegerColor& s, const IntegerColor& d, RIuint32 cov)
       
   829 {
       
   830     IntegerColor r;
       
   831     RIuint32 ac = ((s.a + (s.a>>7)) * cov);
       
   832     ac = (ac + (1<<7))>>8;
       
   833     RIuint32 ia = 256 - ac;
       
   834 
       
   835     r.r = rMul2(s.r, d.r, cov, ia);
       
   836     r.g = rMul2(s.g, d.g, cov, ia);
       
   837     r.b = rMul2(s.b, d.b, cov, ia);
       
   838     r.a = rMul2(s.a, d.a, cov, ia);
       
   839     //r.r = (s.r * cov + d.r * ia) >> 8;
       
   840     //r.g = (s.g * cov + d.g * ia) >> 8;
       
   841     //r.b = (s.b * cov + d.b * ia) >> 8;
       
   842     //r.a = (s.a * cov + d.a * ia) >> 8;
       
   843 
       
   844 #if defined(RI_DEBUG)
       
   845     if (!(r.r <= r.a && r.g <= r.a && r.b <= r.a && r.a <= 255))
       
   846     {
       
   847         printf("r: %d, g: %d, b: %d, a: %d\n",r.r,r.g,r.b,r.a);
       
   848         RI_ASSERT(false);
       
   849     }
       
   850     //RI_ASSERT(r.r <= 255 && r.g <= 255 && r.b <= 255 && r.a <= 255);
       
   851 #endif
       
   852 
       
   853     return r;
       
   854 }
       
   855 
       
   856 /**
       
   857  * \brief   Check if converting between two color formats requires a gamma-conversion.
       
   858  * \todo    Move this to descriptor class.
       
   859  */
       
   860 static RI_INLINE bool needGammaConvert(const Color::Descriptor& srcDesc, const Color::Descriptor& dstDesc)
       
   861 {
       
   862     //if ((!srcDesc.isAlphaOnly()) && (srcDesc.isNonlinear() != dstDesc.isNonlinear()))
       
   863         //return true;
       
   864     if ((srcDesc.isNonlinear() != dstDesc.isNonlinear()))
       
   865         return true;
       
   866 
       
   867     return false;
       
   868 }
       
   869 
       
   870 
       
   871 RI_INLINE static bool preBlendPremultiplication(const PixelPipe::SignatureState& state)
       
   872 {
       
   873     // \todo Simplify the rules (see the corresponding places in the pixelpipe
       
   874     const bool colorTransform = state.hasColorTransform;
       
   875 
       
   876     if (PixelPipe::isImageOnly(state))
       
   877     {
       
   878         if (colorTransform)
       
   879             return true;
       
   880 
       
   881         // Gamma conversion will leave the result premultiplied
       
   882         if (needGammaConvert(state.imageDesc, state.dstDesc))
       
   883             return true;
       
   884         //if (state.imageDesc.isAlphaOnly())
       
   885             //return false;
       
   886 
       
   887         return !imagePremultipliedAfterSampling(state);
       
   888     }
       
   889 
       
   890     if (state.hasImage)
       
   891     {
       
   892         if (state.imageMode == VG_DRAW_IMAGE_NORMAL)
       
   893             return !imagePremultipliedAfterSampling(state);
       
   894         // Image color has been combined with the paint color and that requires premultiplication
       
   895         if (state.imageMode == VG_DRAW_IMAGE_MULTIPLY)
       
   896             return false; // Always results in a premultiplied output color
       
   897 
       
   898         return false; // ?
       
   899     }
       
   900 
       
   901     if (state.paintType == VG_PAINT_TYPE_COLOR)
       
   902         return false;
       
   903 
       
   904     if (state.paintType != VG_PAINT_TYPE_PATTERN)
       
   905         return !gradientPremultipliedAfterSampling(state);
       
   906 
       
   907     // Must be pattern
       
   908     RI_ASSERT(state.paintType == VG_PAINT_TYPE_PATTERN);
       
   909 
       
   910     if (state.hasColorTransform)
       
   911         return true;
       
   912 
       
   913     if (needGammaConvert(state.patternDesc, state.dstDesc))
       
   914         return true;
       
   915     
       
   916     return !patternPremultipliedAfterSampling(state);
       
   917 }
       
   918 
       
   919 /**
       
   920  * \brief   Apply coverage [0 .. 256] on color
       
   921  * \note    This is actually "just coverage".
       
   922  */
       
   923 RI_INLINE static IntegerColor srcCoverage(const IntegerColor& s, const IntegerColor& d, RIuint32 cov)
       
   924 {
       
   925     IntegerColor r;
       
   926     RIuint32 icov = 256-cov;
       
   927     // Make function for multiplication between fixed point values (coverage is
       
   928     // a proper [0 .. 1] value.
       
   929     r.r = (s.r * cov + d.r * icov) >> 8;
       
   930     r.g = (s.g * cov + d.g * icov) >> 8;
       
   931     r.b = (s.b * cov + d.b * icov) >> 8;
       
   932     r.a = (s.a * cov + d.a * icov) >> 8;
       
   933 
       
   934     RI_ASSERT(r.r <= 255 && r.g <= 255 && r.b <= 255 && r.a <= 255);
       
   935 
       
   936     return r;
       
   937 }
       
   938 
       
   939 /**
       
   940  * \brief   Converts color gamma only. Care must be taken concerning luminance color formats.
       
   941  * \return  Converted color in "color". This will always be unpremultiplied if gamma conversion
       
   942  *          takes place, i.e, tries to minimize the amount of further conversions.
       
   943  */
       
   944 RI_INLINE static void maybeGammaConvert(const Color::Descriptor& srcDesc, const Color::Descriptor& dstDesc, IntegerColor& color, bool inputPremultiplied)
       
   945 {
       
   946     if (needGammaConvert(srcDesc, dstDesc))
       
   947     {
       
   948         if (inputPremultiplied)
       
   949             color.unpremultiply();
       
   950             //color.unpremultiply(srcDesc.isLuminance());
       
   951 
       
   952         if (dstDesc.isNonlinear())
       
   953             color.linearToGamma();
       
   954         else
       
   955             color.gammaToLinear();
       
   956     }
       
   957     // Output always unpremultiplied if gamma conversion takes place
       
   958 }
       
   959 
       
   960 /**
       
   961  * \brief   Integer pixel-pipeline.
       
   962  * \note    See internal_formats.txt for info on how the data is passed within the pipeline
       
   963  */
       
   964 RI_INLINE static void intPixelPipe(const PixelPipe::SignatureState& signatureState, const PixelPipe::PPUniforms &uniforms, PixelPipe::PPVariants& variants)
       
   965 {
       
   966     const RIuint32 ppMaxCoverage = Rasterizer::MAX_COVERAGE << (8 - Rasterizer::SAMPLE_BITS);
       
   967     RIuint32 coverage = variants.coverage << (8 - Rasterizer::SAMPLE_BITS);
       
   968     IntegerColor out;
       
   969     IntegerColor imageColor; // imagemode != normal
       
   970     const Color::Descriptor& dstDesc = signatureState.dstDesc;
       
   971     const Color::Descriptor& patternDesc = signatureState.patternDesc;
       
   972     const Color::Descriptor& imageDesc = signatureState.imageDesc;
       
   973 
       
   974     if (!PixelPipe::isImageOnly(signatureState))
       
   975     {
       
   976         switch(signatureState.paintType)
       
   977         {
       
   978         case VG_PAINT_TYPE_COLOR:
       
   979             out = uniforms.solidColor;
       
   980             break;
       
   981         case VG_PAINT_TYPE_LINEAR_GRADIENT:
       
   982             out = intLinearGradient(signatureState, uniforms, variants);
       
   983             variants.sx += uniforms.dgdx;
       
   984             // \todo Optimize this so that the lookup is in premultiplied dst format!
       
   985             // How about image-operations?
       
   986             if ((signatureState.imageMode != VG_DRAW_IMAGE_MULTIPLY) && dstDesc.isLuminance())
       
   987             {
       
   988                 out.fullRGBToLuminance(true, dstDesc.isNonlinear(), true, dstDesc.isNonlinear());
       
   989             }
       
   990             break;
       
   991         case VG_PAINT_TYPE_RADIAL_GRADIENT:
       
   992             out = intRadialGradient(signatureState, uniforms, variants);
       
   993             variants.rx += uniforms.rdxdx;
       
   994             variants.ry += uniforms.rdydx;
       
   995 
       
   996             // \todo Optimize this so that the lookup is in premultiplied dst format!
       
   997             if ((signatureState.imageMode != VG_DRAW_IMAGE_MULTIPLY) && dstDesc.isLuminance())
       
   998             {
       
   999                 out.fullRGBToLuminance(true, dstDesc.isNonlinear(), true, dstDesc.isNonlinear());
       
  1000             }
       
  1001             break;
       
  1002         default:
       
  1003             RI_ASSERT(signatureState.paintType == VG_PAINT_TYPE_PATTERN);
       
  1004             out = intPattern(signatureState, uniforms, variants);
       
  1005             // color-space == pattern color-space, not always premultiplied, expanded
       
  1006             //
       
  1007             // \todo Only increment the proper pixel-counters. This requires detecting the
       
  1008             // transform type before generating the pixel-pipeline.
       
  1009             // \note Implement fastpaths for at least identity transform with image edges coinciding
       
  1010             // with the pixel edges. <- This has been done for images.
       
  1011             variants.sx += uniforms.paint_dxdx;
       
  1012             variants.sy += uniforms.paint_dydx;
       
  1013 
       
  1014             if (!patternDesc.hasAlpha())
       
  1015                 out.a = 255;
       
  1016 
       
  1017             if (!signatureState.hasImage)
       
  1018             {
       
  1019                 out = maybeColorTransform(signatureState, out, uniforms.colorTransformValues, patternDesc.isNonlinear());
       
  1020                 const bool tmpPre = patternPremultipliedAfterSampling(signatureState) && !signatureState.hasColorTransform;
       
  1021                 const bool outLuminance = !signatureState.hasColorTransform && imageDesc.isLuminance();
       
  1022 
       
  1023                 if (outLuminance != dstDesc.isLuminance())
       
  1024                 {
       
  1025                     if (outLuminance)
       
  1026                         out.fullLuminanceToRGB(tmpPre, patternDesc.isNonlinear(), tmpPre, patternDesc.isNonlinear());
       
  1027                     else
       
  1028                         out.fullRGBToLuminance(tmpPre, patternDesc.isNonlinear(), tmpPre, patternDesc.isNonlinear());
       
  1029                 }
       
  1030                 maybeGammaConvert(patternDesc, dstDesc, out, tmpPre);
       
  1031             }
       
  1032 
       
  1033             break;
       
  1034         }
       
  1035     }
       
  1036     
       
  1037     if (signatureState.hasImage)
       
  1038     {
       
  1039         switch (signatureState.imageGradientType)
       
  1040         {
       
  1041         case PixelPipe::GRADIENT_TYPE_INTEGER:
       
  1042         {
       
  1043             void* addr = Image::calculateAddress(uniforms.imagePtr, imageDesc.bitsPerPixel, variants.iImageX, variants.iImageY, uniforms.imageStride);
       
  1044             RIuint32 packedImageColor = Image::readPackedPixelFromAddress(addr, imageDesc.bitsPerPixel, variants.iImageX);
       
  1045             imageColor.fromPackedColor(packedImageColor, imageDesc);
       
  1046             imageColor.expandColor(imageDesc);
       
  1047             // color-space == image color-space, not always premultiplied, expanded
       
  1048 
       
  1049             // Only integer image-gradient can have unsafe image data as an input at the moment.
       
  1050             if (signatureState.unsafeImageInput)
       
  1051             {
       
  1052                 if (imageDesc.hasAlpha() && imageDesc.isPremultiplied())
       
  1053                     imageColor.clampToAlpha();
       
  1054             }
       
  1055 
       
  1056             variants.iImageX += uniforms.image_idxdx;
       
  1057             variants.iImageY += uniforms.image_idydx;
       
  1058             break;
       
  1059         }
       
  1060         case PixelPipe::GRADIENT_TYPE_FIXED:
       
  1061         {
       
  1062             RI_ASSERT(!signatureState.unsafeImageInput);
       
  1063 
       
  1064             RIint32 sx, sy;
       
  1065             sx = variants.iImageX;
       
  1066             sy = variants.iImageY;
       
  1067             applyPatternRepeat(sx, sy, PixelPipe::TILING_MODE_PAD);
       
  1068             sx = gradientToFixedCoords(sx, uniforms.image_iWidth);
       
  1069             sy = gradientToFixedCoords(sy, uniforms.image_iHeight);
       
  1070             imageColor = intSampleImage(
       
  1071                 uniforms.imagePtr,
       
  1072                 uniforms.imageStride,
       
  1073                 uniforms.image_iWidth,
       
  1074                 uniforms.image_iHeight,
       
  1075                 imageDesc,
       
  1076                 sx, sy, signatureState.imageSampler, PixelPipe::TILING_MODE_PAD, NULL);
       
  1077 
       
  1078             variants.iImageX += uniforms.image_idxdx;
       
  1079             variants.iImageY += uniforms.image_idydx;
       
  1080             break;
       
  1081         }
       
  1082         default:
       
  1083         {
       
  1084             RI_ASSERT(signatureState.imageGradientType == PixelPipe::GRADIENT_TYPE_FLOAT);
       
  1085             RI_ASSERT(!signatureState.unsafeImageInput);
       
  1086 
       
  1087             RIfloat fx, fy, fw, rw;
       
  1088             fx = variants.fImageX;
       
  1089             fy = variants.fImageY;
       
  1090             fw = variants.fImageW;
       
  1091             rw = 1.0f / fw;
       
  1092             RIint32 sx0, sy0;
       
  1093             fx = RI_CLAMP(fx * rw, 0.0f, uniforms.image_fWidth - 1.0f); // \todo fImageMaxX
       
  1094             fy = RI_CLAMP(fy * rw, 0.0f, uniforms.image_fHeight - 1.0f);
       
  1095             sx0 = RI_ROUND_TO_INT(fx * (1<<PixelPipe::SAMPLE_BITS));
       
  1096             sy0 = RI_ROUND_TO_INT(fy * (1<<PixelPipe::SAMPLE_BITS)); 
       
  1097 
       
  1098             imageColor = intSampleImage(
       
  1099                 uniforms.imagePtr,
       
  1100                 uniforms.imageStride,
       
  1101                 uniforms.image_iWidth,
       
  1102                 uniforms.image_iHeight,
       
  1103                 imageDesc,
       
  1104                 sx0, sy0, signatureState.imageSampler, PixelPipe::TILING_MODE_PAD, NULL);
       
  1105 
       
  1106             variants.fImageX += uniforms.image_fdxdx;
       
  1107             variants.fImageY += uniforms.image_fdydx;
       
  1108             variants.fImageW += uniforms.image_fdwdx;
       
  1109             break;
       
  1110         }
       
  1111         }
       
  1112 
       
  1113         if (!imageDesc.hasAlpha())
       
  1114             imageColor.a = 255;
       
  1115         
       
  1116         if (PixelPipe::isImageOnly(signatureState))
       
  1117         {
       
  1118             RI_ASSERT(signatureState.imageMode == VG_DRAW_IMAGE_NORMAL);
       
  1119             out = maybeColorTransform(signatureState, imageColor, uniforms.colorTransformValues, imageDesc.isNonlinear());
       
  1120 
       
  1121             const bool tmpPre = imagePremultipliedAfterSampling(signatureState) && !signatureState.hasColorTransform;
       
  1122             const bool outLuminance = !signatureState.hasColorTransform && imageDesc.isLuminance();
       
  1123 
       
  1124             // Color-format conversion to dst before blending.
       
  1125             if (outLuminance != dstDesc.isLuminance())
       
  1126             {
       
  1127                 if (outLuminance)
       
  1128                     out.fullLuminanceToRGB(tmpPre, imageDesc.isNonlinear(), tmpPre, imageDesc.isNonlinear());
       
  1129                 else
       
  1130                     out.fullRGBToLuminance(tmpPre, imageDesc.isNonlinear(), tmpPre, imageDesc.isNonlinear());
       
  1131             }
       
  1132             maybeGammaConvert(imageDesc, dstDesc, out, tmpPre);
       
  1133 
       
  1134             //if (!signatureState.hasColorTransform)
       
  1135                 //out.premultiply();
       
  1136         }
       
  1137         else
       
  1138         {
       
  1139             RI_ASSERT(signatureState.imageMode != VG_DRAW_IMAGE_NORMAL);
       
  1140 
       
  1141             if (!imagePremultipliedAfterSampling(signatureState))
       
  1142                 imageColor.premultiply();
       
  1143 
       
  1144             if (signatureState.imageMode == VG_DRAW_IMAGE_MULTIPLY)
       
  1145             {
       
  1146                 if (signatureState.paintType == VG_PAINT_TYPE_PATTERN && 
       
  1147                     !patternPremultipliedAfterSampling(signatureState))
       
  1148                 {
       
  1149                     out.premultiply();
       
  1150                 }
       
  1151 
       
  1152                 out.r = cMul(out.r, imageColor.r);
       
  1153                 out.g = cMul(out.g, imageColor.g);
       
  1154                 out.b = cMul(out.b, imageColor.b);
       
  1155                 out.a = cMul(out.a, imageColor.a);
       
  1156 
       
  1157                 out = maybeColorTransform(signatureState, out, uniforms.colorTransformValues, imageDesc.isNonlinear());
       
  1158                 //const bool outLuminance = !signatureState.hasColorTransform && imageDesc.isLuminance();
       
  1159                 // Color transform will always result in RGB, regardless of input.
       
  1160                 const bool outLuminance = (imageDesc.isLuminance() && !paintInRGB(signatureState)) && !signatureState.hasColorTransform;
       
  1161                 if (!outLuminance && dstDesc.isLuminance())
       
  1162                 {
       
  1163                     // Convert to destination (luminance)
       
  1164                     out.fullRGBToLuminance(!signatureState.hasColorTransform, imageDesc.isNonlinear(), true, dstDesc.isNonlinear());
       
  1165                 }
       
  1166                 else if (imageDesc.isNonlinear() != dstDesc.isNonlinear())
       
  1167                 {
       
  1168                     // Non-luminance gamma
       
  1169                     if (!signatureState.hasColorTransform)
       
  1170                         out.unpremultiply();
       
  1171 
       
  1172                     if (dstDesc.isNonlinear())
       
  1173                         out.linearToGamma();
       
  1174                     else
       
  1175                         out.gammaToLinear();
       
  1176 
       
  1177                     out.premultiply();
       
  1178                 }
       
  1179                 else if (signatureState.hasColorTransform)
       
  1180                     out.premultiply();
       
  1181 
       
  1182                 // Output dst and premultiplied.
       
  1183             } 
       
  1184             else
       
  1185             {
       
  1186                 RI_ASSERT(signatureState.imageMode == VG_DRAW_IMAGE_STENCIL);
       
  1187                 IntegerColor alphas, pr;
       
  1188                 
       
  1189                 if (signatureState.paintType == VG_PAINT_TYPE_PATTERN)
       
  1190                 {
       
  1191                     out = maybeColorTransform(signatureState, out, uniforms.colorTransformValues, patternDesc.isNonlinear());
       
  1192                     const bool isLuminance = patternDesc.isLuminance() && !signatureState.hasColorTransform;
       
  1193                     // If using pattern, convert to destination color-space
       
  1194                     // \todo If not, handle this when the lookups are generated.
       
  1195                     if (isLuminance != dstDesc.isLuminance())
       
  1196                     {
       
  1197                         out.fullRGBToLuminance(patternPremultipliedAfterSampling(signatureState) && !signatureState.hasColorTransform, patternDesc.isNonlinear(), true, dstDesc.isNonlinear());
       
  1198                     }
       
  1199                     else if (patternDesc.isNonlinear() != dstDesc.isNonlinear())
       
  1200                     {
       
  1201                         if (patternPremultipliedAfterSampling(signatureState) && !signatureState.hasColorTransform)
       
  1202                             out.unpremultiply();
       
  1203 
       
  1204                         if (dstDesc.isNonlinear())
       
  1205                             out.linearToGamma();
       
  1206                         else
       
  1207                             out.gammaToLinear();
       
  1208 
       
  1209                         out.premultiply();
       
  1210                     } else if (signatureState.hasColorTransform || !patternPremultipliedAfterSampling(signatureState))
       
  1211                         out.premultiply();
       
  1212                 }
       
  1213 
       
  1214                 if (dstDesc.isLuminance() && !imageDesc.isLuminance())
       
  1215                 {
       
  1216                     // Convert image to luminance
       
  1217                     imageColor.rgbToLuminance();
       
  1218                     imageColor.r = imageColor.b = imageColor.b = RI_INT_MIN(imageColor.r, imageColor.a);
       
  1219                 }
       
  1220 
       
  1221 #if defined(RI_DEBUG) && 0
       
  1222                 printf("stencil r: %d, g: %d, b: %d, a: %d\n",imageColor.r,imageColor.g,imageColor.b,imageColor.a);
       
  1223                 printf("input r: %d, g: %d, b: %d, a: %d\n",out.r,out.g,out.b,out.a);
       
  1224 #endif
       
  1225                 if (signatureState.paintType == VG_PAINT_TYPE_COLOR)
       
  1226                 {
       
  1227                     // Better precision for solid color input.
       
  1228                     // Compute alpha channels
       
  1229                     alphas.r = rMul(out.a, imageColor.r);
       
  1230                     alphas.g = rMul(out.a, imageColor.g);
       
  1231                     alphas.b = rMul(out.a, imageColor.b);
       
  1232                     // Premultiply
       
  1233                     pr.r = rMul(out.r, imageColor.r);
       
  1234                     pr.g = rMul(out.g, imageColor.g);
       
  1235                     pr.b = rMul(out.b, imageColor.b);
       
  1236                     pr.a = rMul(out.a, imageColor.a);
       
  1237                 }
       
  1238                 else
       
  1239                 {
       
  1240                     // Compute alpha channels
       
  1241                     alphas.r = cMul(out.a, imageColor.r);
       
  1242                     alphas.g = cMul(out.a, imageColor.g);
       
  1243                     alphas.b = cMul(out.a, imageColor.b);
       
  1244                     // Premultiply
       
  1245                     pr.r = cMul(out.r, imageColor.r);
       
  1246                     pr.g = cMul(out.g, imageColor.g);
       
  1247                     pr.b = cMul(out.b, imageColor.b);
       
  1248                     pr.a = cMul(out.a, imageColor.a);
       
  1249                 }
       
  1250 #if defined(RI_DEBUG) && 0
       
  1251                 printf("alphas r: %d, g: %d, b: %d, a: %d\n",alphas.r,alphas.g,alphas.b,alphas.a);
       
  1252                 printf("pr r: %d, g: %d, b: %d, a: %d\n",pr.r,pr.g,pr.b,pr.a);
       
  1253 #endif
       
  1254                 out = pr;
       
  1255                 imageColor = alphas;
       
  1256             }
       
  1257         }
       
  1258     }
       
  1259 
       
  1260     if (signatureState.hasMasking)
       
  1261     {
       
  1262         // \todo Read and process only the proper component of the mask pixel.
       
  1263         const int maskBpp = signatureState.maskDesc.bitsPerPixel;
       
  1264 
       
  1265         RIuint32 packedMaskColor = Image::readPackedPixelFromAddress(variants.maskPtr, maskBpp, variants.dstX);
       
  1266         IntegerColor maskColor;
       
  1267         maskColor.fromPackedMask(packedMaskColor, signatureState.maskDesc);
       
  1268         maskColor.expandMask(signatureState.maskDesc);
       
  1269 
       
  1270         RIuint32 maskCoverage = maskColor.a + (maskColor.a >> 7);
       
  1271         coverage = (coverage * maskCoverage) >> 8;
       
  1272 
       
  1273         variants.maskPtr = (void*)Image::incrementPointer(variants.maskPtr, maskBpp, variants.dstX);  
       
  1274     }
       
  1275     
       
  1276 #if defined(RI_DEBUG)
       
  1277     IntegerColor preblend = out;
       
  1278 #endif
       
  1279     // \todo Coverage check for pixelpipes != solid color with solid output colors?
       
  1280 
       
  1281     IntegerColor d(0,0,0,0);
       
  1282 
       
  1283     // All operations that depend on DST are done next. Keep it organized like that.
       
  1284     if ((coverage < ppMaxCoverage) || (out.a < 255) || alwaysLoadDst(signatureState))
       
  1285     {
       
  1286         d = IntegerColor(Image::readPackedPixelFromAddress(
       
  1287             variants.dst, dstDesc.bitsPerPixel, variants.dstX), dstDesc);
       
  1288         d.expandColor(dstDesc);
       
  1289 
       
  1290         if (!dstDesc.isPremultiplied())
       
  1291         {
       
  1292             d.premultiply();
       
  1293         }
       
  1294 
       
  1295         // Premultiply output
       
  1296 #if 0
       
  1297         if (!PixelPipe::isImageOnly(signatureState))
       
  1298         {
       
  1299             if (signatureState.paintType == VG_PAINT_TYPE_PATTERN && !patternPremultipliedAfterSampling(signatureState))
       
  1300                 out.premultiply();
       
  1301             else if (signatureState.hasImage && !imagePremultipliedAfterSampling(signatureState))
       
  1302                 out.premultiply();
       
  1303         }
       
  1304 #endif
       
  1305 
       
  1306         if (!signatureState.isRenderToMask)
       
  1307         {
       
  1308             VGBlendMode bm = signatureState.blendMode;
       
  1309 
       
  1310             // Currently SRC requires premultiplication even when only applying coverage.
       
  1311             //if (bm != VG_BLEND_SRC)
       
  1312             {
       
  1313                 // If the src color has not been premultiplied before, now's the time.
       
  1314                 // \todo Fast path for src alpha == 255 and SRC_OVER? Others?
       
  1315                 if (preBlendPremultiplication(signatureState))
       
  1316                     out.premultiply();
       
  1317             }
       
  1318 
       
  1319             if (signatureState.hasImage && signatureState.imageMode == VG_DRAW_IMAGE_STENCIL)
       
  1320             {
       
  1321                 out = blendIntegerStencil(out, imageColor, d, bm);
       
  1322             } 
       
  1323             else
       
  1324             {
       
  1325                 switch(bm)
       
  1326                 {
       
  1327                 case VG_BLEND_SRC_OVER:
       
  1328                     out = srcOverCoverage(out, d, coverage);
       
  1329                     break;
       
  1330                 case VG_BLEND_SRC:
       
  1331                     out = srcCoverage(out, d, coverage);
       
  1332                     break;
       
  1333                 default:
       
  1334                     out = blendIntegerColors(out, d, bm);
       
  1335                     out = srcCoverage(out, d, coverage);
       
  1336                     break;
       
  1337                 }
       
  1338             }
       
  1339 
       
  1340 #if defined(RI_DEBUG)
       
  1341             if (dstDesc.isPremultiplied())
       
  1342             {
       
  1343                 RI_ASSERT(out.r <= out.a);
       
  1344                 RI_ASSERT(out.g <= out.a);
       
  1345                 RI_ASSERT(out.b <= out.a);
       
  1346             }
       
  1347 #endif
       
  1348 
       
  1349         }
       
  1350         else
       
  1351         {
       
  1352             // Mask operation
       
  1353             out = intMaskOperation(coverage, d, signatureState.maskOperation);
       
  1354         }
       
  1355 
       
  1356         // out is always premultiplied at this point. Must be in destination color-space
       
  1357         if (!dstDesc.isPremultiplied())
       
  1358         { 
       
  1359             // Unpremultiply if output is not premultiplied
       
  1360             out.unpremultiply();
       
  1361         }
       
  1362     }
       
  1363     else
       
  1364     {
       
  1365         // Unpremultiply, ...
       
  1366         if (!dstDesc.isPremultiplied())
       
  1367             out.unpremultiply();
       
  1368     }
       
  1369 
       
  1370     // VG_SET_MASK does not require dst load:
       
  1371     if (signatureState.isRenderToMask && signatureState.maskOperation == VG_SET_MASK)
       
  1372         out = intMaskOperation(coverage, d, VG_SET_MASK);
       
  1373 
       
  1374     out.truncateColor(dstDesc);
       
  1375     Image::writePackedPixelToAddress(
       
  1376         variants.dst, dstDesc.bitsPerPixel, variants.dstX, out.getPackedColor(dstDesc));
       
  1377 
       
  1378     // \todo X for bpp < 8
       
  1379     variants.dst = (void*)Image::incrementPointer(variants.dst, dstDesc.bitsPerPixel, variants.dstX);
       
  1380     //variants.dst = colorBuffer->advancePointer(variants.dst);
       
  1381     variants.dstX++;
       
  1382 }
       
  1383 
       
  1384 RI_INLINE static void fillSolidSpan(const PixelPipe::SignatureState& state, const PixelPipe::PPUniforms& uniforms, int startX, int y, int nPixels, RIuint32 packedColor) 
       
  1385 {
       
  1386     Image::fillPackedPixels((void*)uniforms.dstPtr, state.dstDesc.bitsPerPixel, startX, y, uniforms.dstStride, nPixels, packedColor);
       
  1387 }
       
  1388 
       
  1389 /**
       
  1390  * \brief   This will calculate all the pixel-pipeline variants that need to be updated per-pixel.
       
  1391  * \note    There may be a need for a different, faster function for image rendering, where
       
  1392  *          there are faster methods of updating the variants.
       
  1393  */
       
  1394 RI_INLINE static void prepareSpanVariants(const PixelPipe::SignatureState& state, const PixelPipe::PPUniforms& uniforms, const Span& span, PixelPipe::PPVariants& variants)
       
  1395 {
       
  1396     //variants.dst = uniforms.dst->calculateAddress(span.x0, span.y);
       
  1397     variants.dst = Image::calculateAddress(uniforms.dstPtr, state.dstDesc.bitsPerPixel, span.x0, span.y, uniforms.dstStride);
       
  1398     variants.dstX = span.x0;
       
  1399     variants.coverage = span.coverage;
       
  1400 
       
  1401     if (state.paintType != VG_PAINT_TYPE_COLOR)
       
  1402     {
       
  1403         if (state.paintType == VG_PAINT_TYPE_LINEAR_GRADIENT)
       
  1404         {
       
  1405             // \todo Adjust pixel-center.
       
  1406             int x = uniforms.dgdx * span.x0 + uniforms.dgdy * span.y + uniforms.lgc;
       
  1407             variants.sx = x;
       
  1408         } 
       
  1409         else if (state.paintType == VG_PAINT_TYPE_RADIAL_GRADIENT)
       
  1410         {
       
  1411             RGScalar x = uniforms.rdxdx * (RGScalar)span.x0 + uniforms.rdxdy * (RGScalar)span.y;
       
  1412             RGScalar y = uniforms.rdydy * (RGScalar)span.y + uniforms.rdydx * (RGScalar)span.x0;
       
  1413 
       
  1414             variants.rx = x + uniforms.rx0;
       
  1415             variants.ry = y + uniforms.ry0;
       
  1416         }
       
  1417         else
       
  1418         {
       
  1419             RI_ASSERT(state.paintType == VG_PAINT_TYPE_PATTERN);
       
  1420             variants.sx = uniforms.paint_dxdx * span.x0 + uniforms.paint_dxdy * span.y + uniforms.paint_x0;
       
  1421             variants.sy = uniforms.paint_dydy * span.y + uniforms.paint_dydx * span.x0 + uniforms.paint_y0;
       
  1422         }
       
  1423     }
       
  1424 
       
  1425     if (state.hasMasking)
       
  1426     {
       
  1427         variants.maskPtr = Image::calculateAddress(uniforms.maskPtr, state.maskDesc.bitsPerPixel, span.x0, span.y, uniforms.maskStride);
       
  1428     }
       
  1429 
       
  1430     if (state.hasImage)
       
  1431     {
       
  1432         switch (state.imageGradientType)
       
  1433         {
       
  1434         case PixelPipe::GRADIENT_TYPE_INTEGER:
       
  1435         case PixelPipe::GRADIENT_TYPE_FIXED:
       
  1436             variants.iImageX = uniforms.image_ix0 + span.x0 * uniforms.image_idxdx + span.y * uniforms.image_idxdy;
       
  1437             variants.iImageY = uniforms.image_iy0 + span.y * uniforms.image_idydy + span.x0 * uniforms.image_idydx;
       
  1438             break;
       
  1439         default:
       
  1440             RI_ASSERT(state.imageGradientType == PixelPipe::GRADIENT_TYPE_FLOAT);
       
  1441             variants.fImageX = uniforms.image_fx0 + span.x0 * uniforms.image_fdxdx + span.y * uniforms.image_fdxdy;
       
  1442             variants.fImageY = uniforms.image_fy0 + span.y * uniforms.image_fdydy + span.x0 * uniforms.image_fdydx;
       
  1443             variants.fImageW = uniforms.image_fw0 + span.x0 * uniforms.image_fdwdx + span.y * uniforms.image_fdwdy;
       
  1444             break;
       
  1445         }
       
  1446     }
       
  1447 }
       
  1448 
       
  1449 void executePixelPipeline(const PixelPipe::SignatureState& state, const PixelPipe::PPUniforms& uniforms, PixelPipe::PPVariants& variants, const Span* spans, int nSpans)
       
  1450 {
       
  1451     RI_ASSERT(nSpans > 0);
       
  1452     for (int i = 0; i < nSpans; i++)
       
  1453     {
       
  1454         const Span& s = spans[i]; 
       
  1455 
       
  1456         if (s.coverage != Rasterizer::MAX_COVERAGE || !canSolidFill(state))
       
  1457         {
       
  1458             int n = s.len;
       
  1459             RI_ASSERT(n);
       
  1460             prepareSpanVariants(state, uniforms, s, variants);
       
  1461 
       
  1462             do {
       
  1463                 intPixelPipe(state, uniforms, variants);
       
  1464             } while (--n);
       
  1465         } else
       
  1466         {
       
  1467             fillSolidSpan(state, uniforms, s.x0, s.y, s.len, uniforms.packedSolidColor);
       
  1468         }
       
  1469     }
       
  1470     
       
  1471 }
       
  1472 
       
  1473 void calculatePPHash(PixelPipeHash& hash, const PixelPipe::SignatureState& derivedState)
       
  1474 {
       
  1475     const RIuint32 blendModeBits = 4;
       
  1476     const RIuint32 imageModeBits = 2;
       
  1477     const RIuint32 paintTypeBits = 2;
       
  1478     const RIuint32 tilingModeBits = 2;
       
  1479     const RIuint32 samplerBits = 1;
       
  1480     const RIuint32 imageGradientTypeBits = 2;
       
  1481     const RIuint32 boolBits = 1;
       
  1482     const RIuint32 descBits = 10;
       
  1483     const RIuint32 maskOperationBits = 3;
       
  1484 
       
  1485     RIuint32 blendMode = ((RIuint32)derivedState.blendMode) - ((RIuint32)VG_BLEND_SRC);
       
  1486     RIuint32 imageMode = ((RIuint32)derivedState.imageMode) - ((RIuint32)VG_DRAW_IMAGE_NORMAL);
       
  1487     RIuint32 paintType = ((RIuint32)derivedState.paintType) - ((RIuint32)VG_PAINT_TYPE_COLOR);
       
  1488     RIuint32 maskOperation = ((RIuint32)derivedState.maskOperation) - ((RIuint32)VG_CLEAR_MASK);
       
  1489     RIuint32 paintTilingMode = ((RIuint32)derivedState.paintTilingMode);
       
  1490     RIuint32 paintSampler = ((RIuint32)derivedState.paintSampler);
       
  1491     RIuint32 imageSampler = ((RIuint32)derivedState.imageSampler);
       
  1492 
       
  1493     RIuint32 imageGradientType = ((RIuint32)derivedState.imageGradientType);
       
  1494 
       
  1495     RIuint32 dstFormat = (RIuint32)(derivedState.dstDesc.toIndex());
       
  1496     RIuint32 maskFormat = (RIuint32)(derivedState.maskDesc.toIndex());
       
  1497     RIuint32 imageFormat = (RIuint32)(derivedState.imageDesc.toIndex());
       
  1498     RIuint32 patternFormat = (RIuint32)(derivedState.patternDesc.toIndex());
       
  1499 
       
  1500     RIuint32 hasMasking = derivedState.hasMasking ? 1 : 0;
       
  1501     RIuint32 hasImage = derivedState.hasImage ? 1 : 0;
       
  1502     RIuint32 hasColorTransform = derivedState.hasColorTransform ? 1 : 0;
       
  1503     RIuint32 isMaskOperation = derivedState.isRenderToMask ? 1 : 0;
       
  1504     RIuint32 fillColorTransparent = derivedState.fillColorTransparent ? 1 : 0;
       
  1505     RIuint32 unsafeImageInput = derivedState.unsafeImageInput ? 1 : 0;
       
  1506 
       
  1507     // Modify hashes according to relevant state:
       
  1508     int b = 0;
       
  1509     b = riInsertBits32(hash.value, sizeof(hash.value), blendMode, blendModeBits, b);
       
  1510     b = riInsertBits32(hash.value, sizeof(hash.value), imageMode, imageModeBits, b);
       
  1511     b = riInsertBits32(hash.value, sizeof(hash.value), paintType, paintTypeBits, b);
       
  1512     b = riInsertBits32(hash.value, sizeof(hash.value), maskOperation, maskOperationBits, b);
       
  1513     b = riInsertBits32(hash.value, sizeof(hash.value), paintTilingMode, tilingModeBits, b);
       
  1514     b = riInsertBits32(hash.value, sizeof(hash.value), paintSampler, samplerBits, b);
       
  1515     b = riInsertBits32(hash.value, sizeof(hash.value), imageSampler, samplerBits, b);
       
  1516 
       
  1517     b = riInsertBits32(hash.value, sizeof(hash.value), imageGradientType, imageGradientTypeBits, b);
       
  1518 
       
  1519     b = riInsertBits32(hash.value, sizeof(hash.value), dstFormat, descBits, b);
       
  1520     b = riInsertBits32(hash.value, sizeof(hash.value), maskFormat, descBits, b);
       
  1521     b = riInsertBits32(hash.value, sizeof(hash.value), imageFormat, descBits, b);
       
  1522     b = riInsertBits32(hash.value, sizeof(hash.value), patternFormat, descBits, b);
       
  1523 
       
  1524     b = riInsertBits32(hash.value, sizeof(hash.value), hasMasking, boolBits, b);
       
  1525     b = riInsertBits32(hash.value, sizeof(hash.value), hasImage, boolBits, b);
       
  1526     b = riInsertBits32(hash.value, sizeof(hash.value), hasColorTransform, boolBits, b);
       
  1527     b = riInsertBits32(hash.value, sizeof(hash.value), isMaskOperation, boolBits, b);
       
  1528     b = riInsertBits32(hash.value, sizeof(hash.value), fillColorTransparent, boolBits, b);
       
  1529     b = riInsertBits32(hash.value, sizeof(hash.value), unsafeImageInput, boolBits, b);
       
  1530 }
       
  1531 
       
  1532 }
       
  1533