Skia深入分析3——skia图片绘制的实现(2)

来源:互联网 发布:算法导论 pdf 微盘 编辑:程序博客网 时间:2024/06/04 18:14
此篇讲图像采样
一、采样流程
在上一节里的流程图有写到,图像绘制的实际渲染发生在某个blitter的blitRect函数中,我们先看一个具体的blitRect实现。

[cpp] view plain copy
  1. void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {  
  2.     SkASSERT(x >= 0 && y >= 0 &&  
  3.              x + width <= fDevice.width() && y + height <= fDevice.height());  
  4.   
  5.     uint32_t*          device = fDevice.getAddr32(x, y);  
  6.     size_t             deviceRB = fDevice.rowBytes();  
  7.     SkShader::Context* shaderContext = fShaderContext;  
  8.     SkPMColor*         span = fBuffer;  
  9.   
  10.     if (fConstInY) {  
  11.         if (fShadeDirectlyIntoDevice) {  
  12.             // shade the first row directly into the device  
  13.             shaderContext->shadeSpan(x, y, device, width);  
  14.             span = device;  
  15.             while (--height > 0) {  
  16.                 device = (uint32_t*)((char*)device + deviceRB);  
  17.                 memcpy(device, span, width << 2);  
  18.             }  
  19.         } else {  
  20.             shaderContext->shadeSpan(x, y, span, width);  
  21.             SkXfermode* xfer = fXfermode;  
  22.             if (xfer) {  
  23.                 do {  
  24.                     xfer->xfer32(device, span, width, NULL);  
  25.                     y += 1;  
  26.                     device = (uint32_t*)((char*)device + deviceRB);  
  27.                 } while (--height > 0);  
  28.             } else {  
  29.                 SkBlitRow::Proc32 proc = fProc32;  
  30.                 do {  
  31.                     proc(device, span, width, 255);  
  32.                     y += 1;  
  33.                     device = (uint32_t*)((char*)device + deviceRB);  
  34.                 } while (--height > 0);  
  35.             }  
  36.         }  
  37.         return;  
  38.     }  
  39.   
  40.     if (fShadeDirectlyIntoDevice) {  
  41.         void* ctx;  
  42.         SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);  
  43.         if (shadeProc) {  
  44.             do {  
  45.                 shadeProc(ctx, x, y, device, width);  
  46.                 y += 1;  
  47.                 device = (uint32_t*)((char*)device + deviceRB);  
  48.             } while (--height > 0);  
  49.         } else {  
  50.             do {  
  51.                 shaderContext->shadeSpan(x, y, device, width);  
  52.                 y += 1;  
  53.                 device = (uint32_t*)((char*)device + deviceRB);  
  54.             } while (--height > 0);  
  55.         }  
  56.     } else {  
  57.         SkXfermode* xfer = fXfermode;  
  58.         if (xfer) {  
  59.             do {  
  60.                 shaderContext->shadeSpan(x, y, span, width);  
  61.                 xfer->xfer32(device, span, width, NULL);  
  62.                 y += 1;  
  63.                 device = (uint32_t*)((char*)device + deviceRB);  
  64.             } while (--height > 0);  
  65.         } else {  
  66.             SkBlitRow::Proc32 proc = fProc32;  
  67.             do {  
  68.                 shaderContext->shadeSpan(x, y, span, width);  
  69.                 proc(device, span, width, 255);  
  70.                 y += 1;  
  71.                 device = (uint32_t*)((char*)device + deviceRB);  
  72.             } while (--height > 0);  
  73.         }  
  74.     }  
  75. }  

其中shadeSpan用来将shader中x,y坐标处的值取n个到dst的buffer中。

对于图像绘制时,它是 SkBitmapProcShader,这里是其实现:

[cpp] view plain copy
  1. void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],  
  2.                                                             int count) {  
  3.     const SkBitmapProcState& state = *fState;  
  4.     if (state.getShaderProc32()) {  
  5.         state.getShaderProc32()(state, x, y, dstC, count);  
  6.         return;  
  7.     }  
  8.   
  9.     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];  
  10.     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();  
  11.     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();  
  12.     int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);  
  13.   
  14.     SkASSERT(state.fBitmap->getPixels());  
  15.     SkASSERT(state.fBitmap->pixelRef() == NULL ||  
  16.              state.fBitmap->pixelRef()->isLocked());  
  17.   
  18.     for (;;) {  
  19.         int n = count;  
  20.         if (n > max) {  
  21.             n = max;  
  22.         }  
  23.         SkASSERT(n > 0 && n < BUF_MAX*2);  
  24. #ifdef TEST_BUFFER_OVERRITE  
  25.         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {  
  26.             buffer[BUF_MAX + i] = TEST_PATTERN;  
  27.         }  
  28. #endif  
  29.         mproc(state, buffer, n, x, y);  
  30. #ifdef TEST_BUFFER_OVERRITE  
  31.         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {  
  32.             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);  
  33.         }  
  34. #endif  
  35.         sproc(state, buffer, n, dstC);  
  36.   
  37.         if ((count -= n) == 0) {  
  38.             break;  
  39.         }  
  40.         SkASSERT(count > 0);  
  41.         x += n;  
  42.         dstC += n;  
  43.     }  
  44. }  

流程如下:
1、存在 shaderProc,直接用
2、计算一次能处理的像素数count
3、mproc计算count个坐标,sproc根据坐标值去取色
注意到之前三个函数指针:
state.getShaderProc32
mproc = state.getMatrixProc
sproc = state.getShaderProc32
这三个函数指针在一开始创建blitter时设定:

SkBlitter::Choose -> SkShader::createContext -> SkBitmapProcShader::onCreateContext -> SkBitmapProcState::chooseProcs


这是一个相当长的函数,它做的事情如下:
1、(优化步骤)在大于SkPaint::kLow_FilterLevel的质量要求下,试图做预缩放。
2、选择matrix函数:chooseMatrixProc。
3、选择sample函数:
(1)高质量:setBitmapFilterProcs
(2)kLow_FilterLevel或kNone_FilterLevel:采取flags计算的方法,根据x,y变化矩阵情况和采样要求选择函数
4、(优化步骤)在满足条件时,选取shader函数,此函数替代matrix和sample函数
5、(优化步骤)platformProcs(),进一步选择优化版本的sample函数
对于RGB565格式的目标,使用的是SkShader的 shadeSpan16 方法。shadeSpan16的代码逻辑类似,不再说明。

[cpp] view plain copy
  1. bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {  
  2.     SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());  
  3.   
  4.     fBitmap = NULL;  
  5.     fInvMatrix = inv;  
  6.     fFilterLevel = paint.getFilterLevel();  
  7.   
  8.     SkASSERT(NULL == fScaledCacheID);  
  9.   
  10.     // possiblyScaleImage will look to see if it can rescale the image as a  
  11.     // preprocess; either by scaling up to the target size, or by selecting  
  12.     // a nearby mipmap level.  If it does, it will adjust the working  
  13.     // matrix as well as the working bitmap.  It may also adjust the filter  
  14.     // quality to avoid re-filtering an already perfectly scaled image.  
  15.     if (!this->possiblyScaleImage()) {  
  16.         if (!this->lockBaseBitmap()) {  
  17.             return false;  
  18.         }  
  19.     }  
  20.     // The above logic should have always assigned fBitmap, but in case it  
  21.     // didn't, we check for that now...  
  22.     // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?  
  23.     if (NULL == fBitmap) {  
  24.         return false;  
  25.     }  
  26.   
  27.     // If we are "still" kMedium_FilterLevel, then the request was not fulfilled by possiblyScale,  
  28.     // so we downgrade to kLow (so the rest of the sniffing code can assume that)  
  29.     if (SkPaint::kMedium_FilterLevel == fFilterLevel) {  
  30.         fFilterLevel = SkPaint::kLow_FilterLevel;  
  31.     }  
  32.   
  33.     bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;  
  34.     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&  
  35.                       SkShader::kClamp_TileMode == fTileModeY;  
  36.   
  37.     if (!(clampClamp || trivialMatrix)) {  
  38.         fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());  
  39.     }  
  40.   
  41.     // Now that all possible changes to the matrix have taken place, check  
  42.     // to see if we're really close to a no-scale matrix.  If so, explicitly  
  43.     // set it to be so.  Subsequent code may inspect this matrix to choose  
  44.     // a faster path in this case.  
  45.   
  46.     // This code will only execute if the matrix has some scale component;  
  47.     // if it's already pure translate then we won't do this inversion.  
  48.   
  49.     if (matrix_only_scale_translate(fInvMatrix)) {  
  50.         SkMatrix forward;  
  51.         if (fInvMatrix.invert(&forward)) {  
  52.             if (clampClamp ? just_trans_clamp(forward, *fBitmap)  
  53.                             : just_trans_general(forward)) {  
  54.                 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());  
  55.                 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());  
  56.                 fInvMatrix.setTranslate(tx, ty);  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     fInvProc        = fInvMatrix.getMapXYProc();  
  62.     fInvType        = fInvMatrix.getType();  
  63.     fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());  
  64.     fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());  
  65.     fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());  
  66.     fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());  
  67.   
  68.     fAlphaScale = SkAlpha255To256(paint.getAlpha());  
  69.   
  70.     fShaderProc32 = NULL;  
  71.     fShaderProc16 = NULL;  
  72.     fSampleProc32 = NULL;  
  73.     fSampleProc16 = NULL;  
  74.   
  75.     // recompute the triviality of the matrix here because we may have  
  76.     // changed it!  
  77.   
  78.     trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;  
  79.   
  80.     if (SkPaint::kHigh_FilterLevel == fFilterLevel) {  
  81.         // If this is still set, that means we wanted HQ sampling  
  82.         // but couldn't do it as a preprocess.  Let's try to install  
  83.         // the scanline version of the HQ sampler.  If that process fails,  
  84.         // downgrade to bilerp.  
  85.   
  86.         // NOTE: Might need to be careful here in the future when we want  
  87.         // to have the platform proc have a shot at this; it's possible that  
  88.         // the chooseBitmapFilterProc will fail to install a shader but a  
  89.         // platform-specific one might succeed, so it might be premature here  
  90.         // to fall back to bilerp.  This needs thought.  
  91.   
  92.         if (!this->setBitmapFilterProcs()) {  
  93.             fFilterLevel = SkPaint::kLow_FilterLevel;  
  94.         }  
  95.     }  
  96.   
  97.     if (SkPaint::kLow_FilterLevel == fFilterLevel) {  
  98.         // Only try bilerp if the matrix is "interesting" and  
  99.         // the image has a suitable size.  
  100.   
  101.         if (fInvType <= SkMatrix::kTranslate_Mask ||  
  102.                 !valid_for_filtering(fBitmap->width() | fBitmap->height())) {  
  103.             fFilterLevel = SkPaint::kNone_FilterLevel;  
  104.         }  
  105.     }  
  106.   
  107.     // At this point, we know exactly what kind of sampling the per-scanline  
  108.     // shader will perform.  
  109.   
  110.     fMatrixProc = this->chooseMatrixProc(trivialMatrix);  
  111.     // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.  
  112.     if (NULL == fMatrixProc) {  
  113.         return false;  
  114.     }  
  115.   
  116.     ///////////////////////////////////////////////////////////////////////  
  117.   
  118.     // No need to do this if we're doing HQ sampling; if filter quality is  
  119.     // still set to HQ by the time we get here, then we must have installed  
  120.     // the shader procs above and can skip all this.  
  121.   
  122.     if (fFilterLevel < SkPaint::kHigh_FilterLevel) {  
  123.   
  124.         int index = 0;  
  125.         if (fAlphaScale < 256) {  // note: this distinction is not used for D16  
  126.             index |= 1;  
  127.         }  
  128.         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {  
  129.             index |= 2;  
  130.         }  
  131.         if (fFilterLevel > SkPaint::kNone_FilterLevel) {  
  132.             index |= 4;  
  133.         }  
  134.         // bits 3,4,5 encoding the source bitmap format  
  135.         switch (fBitmap->colorType()) {  
  136.             case kN32_SkColorType:  
  137.                 index |= 0;  
  138.                 break;  
  139.             case kRGB_565_SkColorType:  
  140.                 index |= 8;  
  141.                 break;  
  142.             case kIndex_8_SkColorType:  
  143.                 index |= 16;  
  144.                 break;  
  145.             case kARGB_4444_SkColorType:  
  146.                 index |= 24;  
  147.                 break;  
  148.             case kAlpha_8_SkColorType:  
  149.                 index |= 32;  
  150.                 fPaintPMColor = SkPreMultiplyColor(paint.getColor());  
  151.                 break;  
  152.             default:  
  153.                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?  
  154.                 return false;  
  155.         }  
  156.   
  157.     #if !SK_ARM_NEON_IS_ALWAYS  
  158.         static const SampleProc32 gSkBitmapProcStateSample32[] = {  
  159.             S32_opaque_D32_nofilter_DXDY,  
  160.             S32_alpha_D32_nofilter_DXDY,  
  161.             S32_opaque_D32_nofilter_DX,  
  162.             S32_alpha_D32_nofilter_DX,  
  163.             S32_opaque_D32_filter_DXDY,  
  164.             S32_alpha_D32_filter_DXDY,  
  165.             S32_opaque_D32_filter_DX,  
  166.             S32_alpha_D32_filter_DX,  
  167.   
  168.             S16_opaque_D32_nofilter_DXDY,  
  169.             S16_alpha_D32_nofilter_DXDY,  
  170.             S16_opaque_D32_nofilter_DX,  
  171.             S16_alpha_D32_nofilter_DX,  
  172.             S16_opaque_D32_filter_DXDY,  
  173.             S16_alpha_D32_filter_DXDY,  
  174.             S16_opaque_D32_filter_DX,  
  175.             S16_alpha_D32_filter_DX,  
  176.   
  177.             SI8_opaque_D32_nofilter_DXDY,  
  178.             SI8_alpha_D32_nofilter_DXDY,  
  179.             SI8_opaque_D32_nofilter_DX,  
  180.             SI8_alpha_D32_nofilter_DX,  
  181.             SI8_opaque_D32_filter_DXDY,  
  182.             SI8_alpha_D32_filter_DXDY,  
  183.             SI8_opaque_D32_filter_DX,  
  184.             SI8_alpha_D32_filter_DX,  
  185.   
  186.             S4444_opaque_D32_nofilter_DXDY,  
  187.             S4444_alpha_D32_nofilter_DXDY,  
  188.             S4444_opaque_D32_nofilter_DX,  
  189.             S4444_alpha_D32_nofilter_DX,  
  190.             S4444_opaque_D32_filter_DXDY,  
  191.             S4444_alpha_D32_filter_DXDY,  
  192.             S4444_opaque_D32_filter_DX,  
  193.             S4444_alpha_D32_filter_DX,  
  194.   
  195.             // A8 treats alpha/opaque the same (equally efficient)  
  196.             SA8_alpha_D32_nofilter_DXDY,  
  197.             SA8_alpha_D32_nofilter_DXDY,  
  198.             SA8_alpha_D32_nofilter_DX,  
  199.             SA8_alpha_D32_nofilter_DX,  
  200.             SA8_alpha_D32_filter_DXDY,  
  201.             SA8_alpha_D32_filter_DXDY,  
  202.             SA8_alpha_D32_filter_DX,  
  203.             SA8_alpha_D32_filter_DX  
  204.         };  
  205.   
  206.         static const SampleProc16 gSkBitmapProcStateSample16[] = {  
  207.             S32_D16_nofilter_DXDY,  
  208.             S32_D16_nofilter_DX,  
  209.             S32_D16_filter_DXDY,  
  210.             S32_D16_filter_DX,  
  211.   
  212.             S16_D16_nofilter_DXDY,  
  213.             S16_D16_nofilter_DX,  
  214.             S16_D16_filter_DXDY,  
  215.             S16_D16_filter_DX,  
  216.   
  217.             SI8_D16_nofilter_DXDY,  
  218.             SI8_D16_nofilter_DX,  
  219.             SI8_D16_filter_DXDY,  
  220.             SI8_D16_filter_DX,  
  221.   
  222.             // Don't support 4444 -> 565  
  223.             NULL, NULL, NULL, NULL,  
  224.             // Don't support A8 -> 565  
  225.             NULL, NULL, NULL, NULL  
  226.         };  
  227.     #endif  
  228.   
  229.         fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];  
  230.         index >>= 1;    // shift away any opaque/alpha distinction  
  231.         fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];  
  232.   
  233.         // our special-case shaderprocs  
  234.         if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {  
  235.             if (clampClamp) {  
  236.                 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);  
  237.             } else if (SkShader::kRepeat_TileMode == fTileModeX &&  
  238.                        SkShader::kRepeat_TileMode == fTileModeY) {  
  239.                 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);  
  240.             }  
  241.         } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {  
  242.             fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);  
  243.         }  
  244.   
  245.         if (NULL == fShaderProc32) {  
  246.             fShaderProc32 = this->chooseShaderProc32();  
  247.         }  
  248.     }  
  249.   
  250.     // see if our platform has any accelerated overrides  
  251.     this->platformProcs();  
  252.   
  253.     return true;  
  254. }  

二、MatrixProc和SampleProc

MatrixProc的使命是生成坐标集。SampleProc则根据坐标集取像素,采样合成
我们先倒过来看 sampleProc 看这个坐标集是怎么使用的:
nofilter_dx系列:

nofilter_dxdy系列:

[cpp] view plain copy
  1. void MAKENAME(_nofilter_DXDY)(const SkBitmapProcState& s,  
  2.         const uint32_t* SK_RESTRICT xy,  
  3.         int count, DSTTYPE* SK_RESTRICT colors) {  
  4.     for (int i = (count >> 1); i > 0; --i) {  
  5.         XY = *xy++;  
  6.         SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&  
  7.                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());  
  8.         src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];  
  9.         *colors++ = RETURNDST(src);  
  10.   
  11.         XY = *xy++;  
  12.         SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&  
  13.                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());  
  14.         src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];  
  15.         *colors++ = RETURNDST(src);  
  16.     }  
  17.     if (count & 1) {  
  18.         XY = *xy++;  
  19.         SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&  
  20.                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());  
  21.         src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];  
  22.         *colors++ = RETURNDST(src);  
  23.     }  
  24.   
  25. }  

这两个系列是直接取了x,y坐标处的图像像素
filter_dx系列:

filter_dxdy系列:

[cpp] view plain copy
  1. void MAKENAME(_filter_DX)(const SkBitmapProcState& s,  
  2.                           const uint32_t* SK_RESTRICT xy,  
  3.                            int count, DSTTYPE* SK_RESTRICT colors) {  
  4.     SkASSERT(count > 0 && colors != NULL);  
  5.     SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);  
  6.     SkDEBUGCODE(CHECKSTATE(s);)  
  7.   
  8. #ifdef PREAMBLE  
  9.     PREAMBLE(s);  
  10. #endif  
  11.     const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();  
  12.     size_t rb = s.fBitmap->rowBytes();  
  13.     unsigned subY;  
  14.     const SRCTYPE* SK_RESTRICT row0;  
  15.     const SRCTYPE* SK_RESTRICT row1;  
  16.   
  17.     // setup row ptrs and update proc_table  
  18.     {  
  19.         uint32_t XY = *xy++;  
  20.         unsigned y0 = XY >> 14;  
  21.         row0 = (const SRCTYPE*)(srcAddr + (y0 >> 4) * rb);  
  22.         row1 = (const SRCTYPE*)(srcAddr + (XY & 0x3FFF) * rb);  
  23.         subY = y0 & 0xF;  
  24.     }  
  25.   
  26.     do {  
  27.         uint32_t XX = *xy++;    // x0:14 | 4 | x1:14  
  28.         unsigned x0 = XX >> 14;  
  29.         unsigned x1 = XX & 0x3FFF;  
  30.         unsigned subX = x0 & 0xF;  
  31.         x0 >>= 4;  
  32.   
  33.         FILTER_PROC(subX, subY,  
  34.                     SRC_TO_FILTER(row0[x0]),  
  35.                     SRC_TO_FILTER(row0[x1]),  
  36.                     SRC_TO_FILTER(row1[x0]),  
  37.                     SRC_TO_FILTER(row1[x1]),  
  38.                     colors);  
  39.         colors += 1;  
  40.   
  41.     } while (--count != 0);  
  42.   
  43. #ifdef POSTAMBLE  
  44.     POSTAMBLE(s);  
  45. #endif  
  46. }  
  47. void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s,  
  48.                             const uint32_t* SK_RESTRICT xy,  
  49.                             int count, DSTTYPE* SK_RESTRICT colors) {  
  50.     SkASSERT(count > 0 && colors != NULL);  
  51.     SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel);  
  52.     SkDEBUGCODE(CHECKSTATE(s);)  
  53.   
  54. #ifdef PREAMBLE  
  55.         PREAMBLE(s);  
  56. #endif  
  57.     const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();  
  58.     size_t rb = s.fBitmap->rowBytes();  
  59.   
  60.     do {  
  61.         uint32_t data = *xy++;  
  62.         unsigned y0 = data >> 14;  
  63.         unsigned y1 = data & 0x3FFF;  
  64.         unsigned subY = y0 & 0xF;  
  65.         y0 >>= 4;  
  66.   
  67.         data = *xy++;  
  68.         unsigned x0 = data >> 14;  
  69.         unsigned x1 = data & 0x3FFF;  
  70.         unsigned subX = x0 & 0xF;  
  71.         x0 >>= 4;  
  72.   
  73.         const SRCTYPE* SK_RESTRICT row0 = (const SRCTYPE*)(srcAddr + y0 * rb);  
  74.         const SRCTYPE* SK_RESTRICT row1 = (const SRCTYPE*)(srcAddr + y1 * rb);  
  75.   
  76.         FILTER_PROC(subX, subY,  
  77.                     SRC_TO_FILTER(row0[x0]),  
  78.                     SRC_TO_FILTER(row0[x1]),  
  79.                     SRC_TO_FILTER(row1[x0]),  
  80.                     SRC_TO_FILTER(row1[x1]),  
  81.                     colors);  
  82.         colors += 1;  
  83.     } while (--count != 0);  
  84.   
  85. #ifdef POSTAMBLE  
  86.     POSTAMBLE(s);  
  87. #endif  
  88. }  

将四个相邻像素取出来之后,作Filter处理

看晕了么,其实总结一下是这样:
nofilter_dx,第一个32位数表示y,其余的32位数包含两个x坐标。
nofilter_dxdy,用16位表示x,16位表示y。这种情况就是取的最近值,直接到x,y坐标处取值就可以了。
filter_dxdy系列,每个32位数分别表示X和Y坐标(14:4:14),交错排列,中间的差值部分是相差的小数扩大16倍而得的近似整数。
filter_dx系列,第一个数为Y坐标用14:4:14的方式存储,后面的数为X坐标,也用14:4:14的方式存储,前后为对应坐标,中间为放大16倍的距离,这个情况是一行之内y坐标相同(只做缩放或小数平移的情况),一样是作双线性插值。




下面我们来看matrixproc的实现,

先跟进 chooseMatrixProc的代码:

[cpp] view plain copy
  1. SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc(bool trivial_matrix) {  
  2. //    test_int_tileprocs();  
  3.     // check for our special case when there is no scale/affine/perspective  
  4.     if (trivial_matrix) {  
  5.         SkASSERT(SkPaint::kNone_FilterLevel == fFilterLevel);  
  6.         fIntTileProcY = choose_int_tile_proc(fTileModeY);  
  7.         switch (fTileModeX) {  
  8.             case SkShader::kClamp_TileMode:  
  9.                 return clampx_nofilter_trans;  
  10.             case SkShader::kRepeat_TileMode:  
  11.                 return repeatx_nofilter_trans;  
  12.             case SkShader::kMirror_TileMode:  
  13.                 return mirrorx_nofilter_trans;  
  14.         }  
  15.     }  
  16.   
  17.     int index = 0;  
  18.     if (fFilterLevel != SkPaint::kNone_FilterLevel) {  
  19.         index = 1;  
  20.     }  
  21.     if (fInvType & SkMatrix::kPerspective_Mask) {  
  22.         index += 4;  
  23.     } else if (fInvType & SkMatrix::kAffine_Mask) {  
  24.         index += 2;  
  25.     }  
  26.   
  27.     if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) {  
  28.         // clamp gets special version of filterOne  
  29.         fFilterOneX = SK_Fixed1;  
  30.         fFilterOneY = SK_Fixed1;  
  31.         return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];  
  32.     }  
  33.   
  34.     // all remaining procs use this form for filterOne  
  35.     fFilterOneX = SK_Fixed1 / fBitmap->width();  
  36.     fFilterOneY = SK_Fixed1 / fBitmap->height();  
  37.   
  38.     if (SkShader::kRepeat_TileMode == fTileModeX && SkShader::kRepeat_TileMode == fTileModeY) {  
  39.         return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];  
  40.     }  
  41.   
  42.     fTileProcX = choose_tile_proc(fTileModeX);  
  43.     fTileProcY = choose_tile_proc(fTileModeY);  
  44.     fTileLowBitsProcX = choose_tile_lowbits_proc(fTileModeX);  
  45.     fTileLowBitsProcY = choose_tile_lowbits_proc(fTileModeY);  
  46.     return GeneralXY_Procs[index];  
  47. }  

有些函数是找符号找不到的,我们注意到SkBitmapProcState.cpp 中包含了多次 SkBitmapProcState_matrix.h 头文件:

[cpp] view plain copy
  1. #if !SK_ARM_NEON_IS_ALWAYS  
  2. #define MAKENAME(suffix)        ClampX_ClampY ## suffix  
  3. #define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)  
  4. #define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)  
  5. #define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)  
  6. #define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)  
  7. #define CHECK_FOR_DECAL  
  8. #include "SkBitmapProcState_matrix.h"  

头文件代码如下:

[cpp] view plain copy
  1. /* 
  2.  * Copyright 2011 Google Inc. 
  3.  * 
  4.  * Use of this source code is governed by a BSD-style license that can be 
  5.  * found in the LICENSE file. 
  6.  */  
  7.   
  8. #include "SkMath.h"  
  9. #include "SkMathPriv.h"  
  10.   
  11. #define SCALE_FILTER_NAME       MAKENAME(_filter_scale)  
  12. #define AFFINE_FILTER_NAME      MAKENAME(_filter_affine)  
  13. #define PERSP_FILTER_NAME       MAKENAME(_filter_persp)  
  14.   
  15. #define PACK_FILTER_X_NAME  MAKENAME(_pack_filter_x)  
  16. #define PACK_FILTER_Y_NAME  MAKENAME(_pack_filter_y)  
  17.   
  18. #ifndef PREAMBLE  
  19.     #define PREAMBLE(state)  
  20.     #define PREAMBLE_PARAM_X  
  21.     #define PREAMBLE_PARAM_Y  
  22.     #define PREAMBLE_ARG_X  
  23.     #define PREAMBLE_ARG_Y  
  24. #endif  
  25.   
  26. // declare functions externally to suppress warnings.  
  27. void SCALE_FILTER_NAME(const SkBitmapProcState& s,  
  28.                               uint32_t xy[], int count, int x, int y);  
  29. void AFFINE_FILTER_NAME(const SkBitmapProcState& s,  
  30.                                uint32_t xy[], int count, int x, int y);  
  31. void PERSP_FILTER_NAME(const SkBitmapProcState& s,  
  32.                               uint32_t* SK_RESTRICT xy, int count,  
  33.                               int x, int y);  
  34.   
  35. static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max,  
  36.                                           SkFixed one PREAMBLE_PARAM_Y) {  
  37.     unsigned i = TILEY_PROCF(f, max);  
  38.     i = (i << 4) | TILEY_LOW_BITS(f, max);  
  39.     return (i << 14) | (TILEY_PROCF((f + one), max));  
  40. }  
  41.   
  42. static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max,  
  43.                                           SkFixed one PREAMBLE_PARAM_X) {  
  44.     unsigned i = TILEX_PROCF(f, max);  
  45.     i = (i << 4) | TILEX_LOW_BITS(f, max);  
  46.     return (i << 14) | (TILEX_PROCF((f + one), max));  
  47. }  
  48.   
  49. void SCALE_FILTER_NAME(const SkBitmapProcState& s,  
  50.                               uint32_t xy[], int count, int x, int y) {  
  51.     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |  
  52.                              SkMatrix::kScale_Mask)) == 0);  
  53.     SkASSERT(s.fInvKy == 0);  
  54.   
  55.     PREAMBLE(s);  
  56.   
  57.     const unsigned maxX = s.fBitmap->width() - 1;  
  58.     const SkFixed one = s.fFilterOneX;  
  59.     const SkFractionalInt dx = s.fInvSxFractionalInt;  
  60.     SkFractionalInt fx;  
  61.   
  62.     {  
  63.         SkPoint pt;  
  64.         s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,  
  65.                                   SkIntToScalar(y) + SK_ScalarHalf, &pt);  
  66.         const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);  
  67.         const unsigned maxY = s.fBitmap->height() - 1;  
  68.         // compute our two Y values up front  
  69.         *xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);  
  70.         // now initialize fx  
  71.         fx = SkScalarToFractionalInt(pt.fX) - (SkFixedToFractionalInt(one) >> 1);  
  72.     }  
  73.   
  74. #ifdef CHECK_FOR_DECAL  
  75.     if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) {  
  76.         decal_filter_scale(xy, SkFractionalIntToFixed(fx),  
  77.                            SkFractionalIntToFixed(dx), count);  
  78.     } else  
  79. #endif  
  80.     {  
  81.         do {  
  82.             SkFixed fixedFx = SkFractionalIntToFixed(fx);  
  83.             *xy++ = PACK_FILTER_X_NAME(fixedFx, maxX, one PREAMBLE_ARG_X);  
  84.             fx += dx;  
  85.         } while (--count != 0);  
  86.     }  
  87. }  
  88.   
  89. void AFFINE_FILTER_NAME(const SkBitmapProcState& s,  
  90.                                uint32_t xy[], int count, int x, int y) {  
  91.     SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);  
  92.     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |  
  93.                              SkMatrix::kScale_Mask |  
  94.                              SkMatrix::kAffine_Mask)) == 0);  
  95.   
  96.     PREAMBLE(s);  
  97.     SkPoint srcPt;  
  98.     s.fInvProc(s.fInvMatrix,  
  99.                SkIntToScalar(x) + SK_ScalarHalf,  
  100.                SkIntToScalar(y) + SK_ScalarHalf, &srcPt);  
  101.   
  102.     SkFixed oneX = s.fFilterOneX;  
  103.     SkFixed oneY = s.fFilterOneY;  
  104.     SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);  
  105.     SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);  
  106.     SkFixed dx = s.fInvSx;  
  107.     SkFixed dy = s.fInvKy;  
  108.     unsigned maxX = s.fBitmap->width() - 1;  
  109.     unsigned maxY = s.fBitmap->height() - 1;  
  110.   
  111.     do {  
  112.         *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);  
  113.         fy += dy;  
  114.         *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);  
  115.         fx += dx;  
  116.     } while (--count != 0);  
  117. }  
  118.   
  119. void PERSP_FILTER_NAME(const SkBitmapProcState& s,  
  120.                               uint32_t* SK_RESTRICT xy, int count,  
  121.                               int x, int y) {  
  122.     SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);  
  123.   
  124.     PREAMBLE(s);  
  125.     unsigned maxX = s.fBitmap->width() - 1;  
  126.     unsigned maxY = s.fBitmap->height() - 1;  
  127.     SkFixed oneX = s.fFilterOneX;  
  128.     SkFixed oneY = s.fFilterOneY;  
  129.   
  130.     SkPerspIter   iter(s.fInvMatrix,  
  131.                        SkIntToScalar(x) + SK_ScalarHalf,  
  132.                        SkIntToScalar(y) + SK_ScalarHalf, count);  
  133.   
  134.     while ((count = iter.next()) != 0) {  
  135.         const SkFixed* SK_RESTRICT srcXY = iter.getXY();  
  136.         do {  
  137.             *xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY,  
  138.                                        oneY PREAMBLE_ARG_Y);  
  139.             *xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX,  
  140.                                        oneX PREAMBLE_ARG_X);  
  141.             srcXY += 2;  
  142.         } while (--count != 0);  
  143.     }  
  144. }  
  145.   
  146. #undef MAKENAME  
  147. #undef TILEX_PROCF  
  148. #undef TILEY_PROCF  
  149. #ifdef CHECK_FOR_DECAL  
  150.     #undef CHECK_FOR_DECAL  
  151. #endif  
  152.   
  153. #undef SCALE_FILTER_NAME  
  154. #undef AFFINE_FILTER_NAME  
  155. #undef PERSP_FILTER_NAME  
  156.   
  157. #undef PREAMBLE  
  158. #undef PREAMBLE_PARAM_X  
  159. #undef PREAMBLE_PARAM_Y  
  160. #undef PREAMBLE_ARG_X  
  161. #undef PREAMBLE_ARG_Y  
  162.   
  163. #undef TILEX_LOW_BITS  
  164. #undef TILEY_LOW_BITS  

然后我们就清楚了,这些函数名是用宏组合出来的。(神一般的代码。。。。。)
怎么算坐标的不详述了,主要按原理去推就可以了,坐标计算有三种模式:CLAMP(越界时限制在边界)、REPEAT(越界时从开头取起)、MIRROR(越界时取样方向倒转去取)。
sampleProc函数也是类似的方法组合出来的,不详述。


三、高级插值算法
双线性插值虽然在一般情况下够用了,但在放大图片时,效果还是不够好。需要更好的效果,可以用高级插值算法,代价是性能的大幅消耗。
高级插值算法目前在Android的Java代码处是走不进去的,不知道chromium是否用到。
几个要点:
1、在 setBitmapFilterProcs 时判断高级插值是否支持,若支持,设置 shaderProc 为 highQualityFilter32/highQualityFilter16(也就是独立计算坐标和采样像素)
2、highQualityFilter先通过变换矩阵计算原始点。
3、highQualityFilter根据 SkBitmapFilter  的采样窗口,将这个窗口中的所有点按其与原始点矩离,查询对应权重值,然后相加,得到最终像素点。
4、SkBitmapFilter 采用查表法去给出权重值,预计算由子类完成。
5、目前Skia库用的是双三次插值 mitchell 法。

SK_CONF_DECLARE(const char *, c_bitmapFilter, "bitmap.filter", "mitchell", "Which scanline bitmap filter to use [mitchell, lanczos, hamming, gaussian, triangle, box]");
详细代码见 external/skia/src/core/SkBitmapFilter.cpp,尽量这部分代码几乎无用武之地,但里面的公式很值得借鉴,随便改改就能做成 glsl shader 用。

看完这段代码,可以作不负责任的猜想:Skia设计之初,只考虑了近邻插值和双线性插值两种情况,因此采用这种模板方法,可以最小化代码量。而且MatrixProc和SampleProc可以后续分别作SIMD优化(Intel的SSE和ARM的Neon),以提高性能。
但是对于线性插值,两步法(取值——采样)在算法实现上本来就不是最优的,后面又不得不引入shader函数,应对一些场景做优化。高阶插值无法在这个设计下实现,因此又像补丁一样打上去。

四、总结
看完这一部分代码,有几个感受。
第一:绘张图片看上去一件简单的事,在渲染执行时,真心不容易,如果追求效果,还会有各种各样的花样。
第二:在性能有要求的场景下,用模板真是灾难:函数改写时,遇到模板,就不得不重新定义函数,并替换之,弄得代码看上去一下子混乱不少。
第三:从图像绘制这个角度上看,skia渲染性能虽然确实很好了,但远没有达到极限,仍然是有一定的优化空间的,如果这部分出现了性能问题,还是能做一定的优化的。关于Skia性能的讨论将放到介绍Skia系列的最后一章。
第四:OpenGL+glsl确实是轻松且高效多了,软件渲染在复杂场景上性能很有限。
0 0
原创粉丝点击