1d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski/* 2d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * Copyright 2014 Google Inc. 3d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * 4d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * Use of this source code is governed by a BSD-style license that can be 5d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * found in the LICENSE file. 6d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski */ 7d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 8d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#ifndef SkTextureCompressor_Blitter_DEFINED 9d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#define SkTextureCompressor_Blitter_DEFINED 10d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 11d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#include "SkTypes.h" 12d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#include "SkBlitter.h" 13d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 14d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevskinamespace SkTextureCompressor { 15d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 16a10555a354cf294bde217044472d33c3161df249krajcevski// Ostensibly, SkBlitter::BlitRect is supposed to set a rect of pixels to full 17a10555a354cf294bde217044472d33c3161df249krajcevski// alpha. This becomes problematic when using compressed texture blitters, since 18a10555a354cf294bde217044472d33c3161df249krajcevski// the rect rarely falls along block boundaries. The proper way to handle this is 19a10555a354cf294bde217044472d33c3161df249krajcevski// to update the compressed encoding of a block by resetting the proper parameters 20a10555a354cf294bde217044472d33c3161df249krajcevski// (and even recompressing the block) where a rect falls inbetween block boundaries. 21a10555a354cf294bde217044472d33c3161df249krajcevski// PEDANTIC_BLIT_RECT attempts to do this by requiring the struct passed to 22a10555a354cf294bde217044472d33c3161df249krajcevski// SkTCompressedAlphaBlitter to implement an UpdateBlock function call. 23a10555a354cf294bde217044472d33c3161df249krajcevski// 24a10555a354cf294bde217044472d33c3161df249krajcevski// However, the way that BlitRect gets used almost exclusively is to bracket inverse 25a10555a354cf294bde217044472d33c3161df249krajcevski// fills for paths. In other words, the top few rows and bottom few rows of a path 26a10555a354cf294bde217044472d33c3161df249krajcevski// that's getting inverse filled are called using blitRect. The rest are called using 27a10555a354cf294bde217044472d33c3161df249krajcevski// the standard blitAntiH. As a result, we can just call blitAntiH with a faux RLE 28a10555a354cf294bde217044472d33c3161df249krajcevski// of full alpha values, and then check in our flush() call that we don't run off the 29a10555a354cf294bde217044472d33c3161df249krajcevski// edge of the buffer. This is why we do not need this flag to be turned on. 30d211c547cbe49d824e4923933e8a4955e6c65e37krajcevski// 31d211c547cbe49d824e4923933e8a4955e6c65e37krajcevski// NOTE: This code is unfinished, but is inteded as a starting point if an when 32d211c547cbe49d824e4923933e8a4955e6c65e37krajcevski// bugs are introduced from the existing code. 33d211c547cbe49d824e4923933e8a4955e6c65e37krajcevski#define PEDANTIC_BLIT_RECT 0 34a10555a354cf294bde217044472d33c3161df249krajcevski 35d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski// This class implements a blitter that blits directly into a buffer that will 36d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski// be used as an compressed alpha texture. We compute this buffer by 37d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski// buffering scan lines and then outputting them all at once. The number of 38d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski// scan lines buffered is controlled by kBlockSize 3945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// 4045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// The CompressorType is a struct with a bunch of static methods that provides 4145a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// the specialized compression functionality of the blitter. A complete CompressorType 4245a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// will implement the following static functions; 4345a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// 4445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// struct CompressorType { 4545a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// // The function used to compress an A8 block. The layout of the 4645a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// // block is also expected to be in column-major order. 4745a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// static void CompressA8Vertical(uint8_t* dst, const uint8_t block[]); 4845a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// 4945a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// // The function used to compress an A8 block. The layout of the 5045a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// // block is also expected to be in row-major order. 51a10555a354cf294bde217044472d33c3161df249krajcevski// static void CompressA8Horizontal(uint8_t* dst, const uint8_t* src, int srcRowBytes); 5245a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// 53a10555a354cf294bde217044472d33c3161df249krajcevski#if PEDANTIC_BLIT_RECT 5445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// // The function used to update an already compressed block. This will 55a10555a354cf294bde217044472d33c3161df249krajcevski// // most likely be implementation dependent. The mask variable will have 56a10555a354cf294bde217044472d33c3161df249krajcevski// // 0xFF in positions where the block should be updated and 0 in positions 57a10555a354cf294bde217044472d33c3161df249krajcevski// // where it shouldn't. src contains an uncompressed buffer of pixels. 58a10555a354cf294bde217044472d33c3161df249krajcevski// static void UpdateBlock(uint8_t* dst, const uint8_t* src, int srcRowBytes, 59a10555a354cf294bde217044472d33c3161df249krajcevski// const uint8_t* mask); 60a10555a354cf294bde217044472d33c3161df249krajcevski#endif 6145a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski// }; 6245a0bf505914adf0ee8c69e2647230618bbb3a63krajcevskitemplate<int BlockDim, int EncodedBlockSize, typename CompressorType> 63d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevskiclass SkTCompressedAlphaBlitter : public SkBlitter { 64d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevskipublic: 65d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkTCompressedAlphaBlitter(int width, int height, void *compressedBuffer) 66d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 0x7FFE is one minus the largest positive 16-bit int. We use it for 67d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // debugging to make sure that we're properly setting the nextX distance 68d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // in flushRuns(). 69dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski#ifdef SK_DEBUG 70a10555a354cf294bde217044472d33c3161df249krajcevski : fCalledOnceWithNonzeroY(false) 71a10555a354cf294bde217044472d33c3161df249krajcevski , fBlitMaskCalled(false), 72dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski#else 73dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski : 74dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski#endif 75dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski kLongestRun(0x7FFE), kZeroAlpha(0) 76d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski , fNextRun(0) 77d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski , fWidth(width) 78d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski , fHeight(height) 79d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski , fBuffer(compressedBuffer) 80d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski { 81d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT((width % BlockDim) == 0); 82d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT((height % BlockDim) == 0); 83d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 84d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 85d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual ~SkTCompressedAlphaBlitter() { this->flushRuns(); } 86d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 87d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Blit a horizontal run of one or more pixels. 88d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual void blitH(int x, int y, int width) SK_OVERRIDE { 89d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This function is intended to be called from any standard RGB 90d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // buffer, so we should never encounter it. However, if some code 91d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // path does end up here, then this needs to be investigated. 92d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkFAIL("Not implemented!"); 93d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 94d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 95d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Blit a horizontal run of antialiased pixels; runs[] is a *sparse* 96d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // zero-terminated run-length encoding of spans of constant alpha values. 97d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual void blitAntiH(int x, int y, 98d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const SkAlpha antialias[], 99d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int16_t runs[]) SK_OVERRIDE { 100a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(0 == x); 101a10555a354cf294bde217044472d33c3161df249krajcevski 102d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Make sure that the new row to blit is either the first 103d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // row that we're blitting, or it's exactly the next scan row 104d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // since the last row that we blit. This is to ensure that when 105d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // we go to flush the runs, that they are all the same four 106d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // runs. 107d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if (fNextRun > 0 && 108d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski ((x != fBufferedRuns[fNextRun-1].fX) || 109d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski (y-1 != fBufferedRuns[fNextRun-1].fY))) { 110d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski this->flushRuns(); 111d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 112d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 113d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Align the rows to a block boundary. If we receive rows that 114d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // are not on a block boundary, then fill in the preceding runs 115d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // with zeros. We do this by producing a single RLE that says 116d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // that we have 0x7FFE pixels of zero (0x7FFE = 32766). 117d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int row = BlockDim * (y / BlockDim); 118d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski while ((row + fNextRun) < y) { 119d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fAlphas = &kZeroAlpha; 120d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fRuns = &kLongestRun; 121d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fX = 0; 122d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fY = row + fNextRun; 123d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski ++fNextRun; 124d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 125d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 126d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Make sure that our assumptions aren't violated... 127d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(fNextRun == (y % BlockDim)); 128d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(fNextRun == 0 || fBufferedRuns[fNextRun - 1].fY < y); 129d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 130d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Set the values of the next run 131d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fAlphas = antialias; 132d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fRuns = runs; 133d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fX = x; 134d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[fNextRun].fY = y; 135d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 136d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we've output a block of scanlines in a row that don't violate our 137d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // assumptions, then it's time to flush them... 138d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if (BlockDim == ++fNextRun) { 139d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski this->flushRuns(); 140d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 141d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 142d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 143d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Blit a vertical run of pixels with a constant alpha value. 144d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE { 145d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This function is currently not implemented. It is not explicitly 146d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // required by the contract, but if at some time a code path runs into 147d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // this function (which is entirely possible), it needs to be implemented. 148d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 149d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // TODO (krajcevski): 150d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This function will be most easily implemented in one of two ways: 151d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 1. Buffer each vertical column value and then construct a list 152d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // of alpha values and output all of the blocks at once. This only 153d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // requires a write to the compressed buffer 154d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 2. Replace the indices of each block with the proper indices based 155d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // on the alpha value. This requires a read and write of the compressed 156d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // buffer, but much less overhead. 157d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkFAIL("Not implemented!"); 158d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 159d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 160a10555a354cf294bde217044472d33c3161df249krajcevski // Blit a solid rectangle one or more pixels wide. It's assumed that blitRect 161a10555a354cf294bde217044472d33c3161df249krajcevski // is called as a way to bracket blitAntiH where above and below the path the 162a10555a354cf294bde217044472d33c3161df249krajcevski // called path just needs a solid rectangle to fill in the mask. 163a10555a354cf294bde217044472d33c3161df249krajcevski#ifdef SK_DEBUG 164a10555a354cf294bde217044472d33c3161df249krajcevski bool fCalledOnceWithNonzeroY; 165a10555a354cf294bde217044472d33c3161df249krajcevski#endif 166d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE { 167a10555a354cf294bde217044472d33c3161df249krajcevski 168a10555a354cf294bde217044472d33c3161df249krajcevski // Assumptions: 169a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(0 == x); 170a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(width <= fWidth); 171a10555a354cf294bde217044472d33c3161df249krajcevski 172a10555a354cf294bde217044472d33c3161df249krajcevski // Make sure that we're only ever bracketing calls to blitAntiH. 173a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT((0 == y) || (!fCalledOnceWithNonzeroY && (fCalledOnceWithNonzeroY = true))); 174a10555a354cf294bde217044472d33c3161df249krajcevski 175a10555a354cf294bde217044472d33c3161df249krajcevski#if !(PEDANTIC_BLIT_RECT) 176a10555a354cf294bde217044472d33c3161df249krajcevski for (int i = 0; i < height; ++i) { 177a10555a354cf294bde217044472d33c3161df249krajcevski const SkAlpha kFullAlpha = 0xFF; 178a10555a354cf294bde217044472d33c3161df249krajcevski this->blitAntiH(x, y+i, &kFullAlpha, &kLongestRun); 179a10555a354cf294bde217044472d33c3161df249krajcevski } 180a10555a354cf294bde217044472d33c3161df249krajcevski#else 181a10555a354cf294bde217044472d33c3161df249krajcevski const int startBlockX = (x / BlockDim) * BlockDim; 182a10555a354cf294bde217044472d33c3161df249krajcevski const int startBlockY = (y / BlockDim) * BlockDim; 183a10555a354cf294bde217044472d33c3161df249krajcevski 184a10555a354cf294bde217044472d33c3161df249krajcevski const int endBlockX = ((x + width) / BlockDim) * BlockDim; 185a10555a354cf294bde217044472d33c3161df249krajcevski const int endBlockY = ((y + height) / BlockDim) * BlockDim; 186a10555a354cf294bde217044472d33c3161df249krajcevski 187a10555a354cf294bde217044472d33c3161df249krajcevski // If start and end are the same, then we only need to update a single block... 188a10555a354cf294bde217044472d33c3161df249krajcevski if (startBlockY == endBlockY && startBlockX == endBlockX) { 189a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t mask[BlockDim*BlockDim]; 190a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask, 0, sizeof(mask)); 191a10555a354cf294bde217044472d33c3161df249krajcevski 192a10555a354cf294bde217044472d33c3161df249krajcevski const int xoff = x - startBlockX; 193a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT((xoff + width) <= BlockDim); 194a10555a354cf294bde217044472d33c3161df249krajcevski 195a10555a354cf294bde217044472d33c3161df249krajcevski const int yoff = y - startBlockY; 196a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT((yoff + height) <= BlockDim); 197a10555a354cf294bde217044472d33c3161df249krajcevski 198a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = 0; j < height; ++j) { 199a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + (j + yoff)*BlockDim + xoff, 0xFF, width); 200a10555a354cf294bde217044472d33c3161df249krajcevski } 201a10555a354cf294bde217044472d33c3161df249krajcevski 202a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t* dst = this->getBlock(startBlockX, startBlockY); 203a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(dst, mask, BlockDim, mask); 204a10555a354cf294bde217044472d33c3161df249krajcevski 205a10555a354cf294bde217044472d33c3161df249krajcevski // If start and end are the same in the y dimension, then we can freely update an 206a10555a354cf294bde217044472d33c3161df249krajcevski // entire row of blocks... 207a10555a354cf294bde217044472d33c3161df249krajcevski } else if (startBlockY == endBlockY) { 208a10555a354cf294bde217044472d33c3161df249krajcevski 209a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockRow(x, y, width, height, startBlockY, startBlockX, endBlockX); 210a10555a354cf294bde217044472d33c3161df249krajcevski 211a10555a354cf294bde217044472d33c3161df249krajcevski // Similarly, if the start and end are in the same column, then we can just update 212a10555a354cf294bde217044472d33c3161df249krajcevski // an entire column of blocks... 213a10555a354cf294bde217044472d33c3161df249krajcevski } else if (startBlockX == endBlockX) { 214a10555a354cf294bde217044472d33c3161df249krajcevski 215a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockCol(x, y, width, height, startBlockX, startBlockY, endBlockY); 216a10555a354cf294bde217044472d33c3161df249krajcevski 217a10555a354cf294bde217044472d33c3161df249krajcevski // Otherwise, the rect spans a non-trivial region of blocks, and we have to construct 218a10555a354cf294bde217044472d33c3161df249krajcevski // a kind of 9-patch to update each of the pieces of the rect. The top and bottom 219a10555a354cf294bde217044472d33c3161df249krajcevski // rows are updated using updateBlockRow, and the left and right columns are updated 220a10555a354cf294bde217044472d33c3161df249krajcevski // using updateBlockColumn. Anything in the middle is simply memset to an opaque block 221a10555a354cf294bde217044472d33c3161df249krajcevski // encoding. 222a10555a354cf294bde217044472d33c3161df249krajcevski } else { 223a10555a354cf294bde217044472d33c3161df249krajcevski 224a10555a354cf294bde217044472d33c3161df249krajcevski const int innerStartBlockX = startBlockX + BlockDim; 225a10555a354cf294bde217044472d33c3161df249krajcevski const int innerStartBlockY = startBlockY + BlockDim; 226a10555a354cf294bde217044472d33c3161df249krajcevski 227a10555a354cf294bde217044472d33c3161df249krajcevski // Blit top row 228a10555a354cf294bde217044472d33c3161df249krajcevski const int topRowHeight = innerStartBlockY - y; 229a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockRow(x, y, width, topRowHeight, startBlockY, 230a10555a354cf294bde217044472d33c3161df249krajcevski startBlockX, endBlockX); 231a10555a354cf294bde217044472d33c3161df249krajcevski 232a10555a354cf294bde217044472d33c3161df249krajcevski // Advance y 233a10555a354cf294bde217044472d33c3161df249krajcevski y += topRowHeight; 234a10555a354cf294bde217044472d33c3161df249krajcevski height -= topRowHeight; 235a10555a354cf294bde217044472d33c3161df249krajcevski 236a10555a354cf294bde217044472d33c3161df249krajcevski // Blit middle 237a10555a354cf294bde217044472d33c3161df249krajcevski if (endBlockY > innerStartBlockY) { 238a10555a354cf294bde217044472d33c3161df249krajcevski 239a10555a354cf294bde217044472d33c3161df249krajcevski // Update left row 240a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockCol(x, y, innerStartBlockX - x, endBlockY, startBlockY, 241a10555a354cf294bde217044472d33c3161df249krajcevski startBlockX, innerStartBlockX); 242a10555a354cf294bde217044472d33c3161df249krajcevski 243a10555a354cf294bde217044472d33c3161df249krajcevski // Update the middle with an opaque encoding... 244a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t mask[BlockDim*BlockDim]; 245a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask, 0xFF, sizeof(mask)); 246a10555a354cf294bde217044472d33c3161df249krajcevski 247a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t opaqueEncoding[EncodedBlockSize]; 248a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::CompressA8Horizontal(opaqueEncoding, mask, BlockDim); 249a10555a354cf294bde217044472d33c3161df249krajcevski 250a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = innerStartBlockY; j < endBlockY; j += BlockDim) { 251a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t* opaqueDst = this->getBlock(innerStartBlockX, j); 252a10555a354cf294bde217044472d33c3161df249krajcevski for (int i = innerStartBlockX; i < endBlockX; i += BlockDim) { 253a10555a354cf294bde217044472d33c3161df249krajcevski memcpy(opaqueDst, opaqueEncoding, EncodedBlockSize); 254a10555a354cf294bde217044472d33c3161df249krajcevski opaqueDst += EncodedBlockSize; 255a10555a354cf294bde217044472d33c3161df249krajcevski } 256a10555a354cf294bde217044472d33c3161df249krajcevski } 257a10555a354cf294bde217044472d33c3161df249krajcevski 258a10555a354cf294bde217044472d33c3161df249krajcevski // If we need to update the right column, do that too 259a10555a354cf294bde217044472d33c3161df249krajcevski if (x + width > endBlockX) { 260a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockCol(endBlockX, y, x + width - endBlockX, endBlockY, 261a10555a354cf294bde217044472d33c3161df249krajcevski endBlockX, innerStartBlockY, endBlockY); 262a10555a354cf294bde217044472d33c3161df249krajcevski } 263a10555a354cf294bde217044472d33c3161df249krajcevski 264a10555a354cf294bde217044472d33c3161df249krajcevski // Advance y 265a10555a354cf294bde217044472d33c3161df249krajcevski height = y + height - endBlockY; 266a10555a354cf294bde217044472d33c3161df249krajcevski y = endBlockY; 267a10555a354cf294bde217044472d33c3161df249krajcevski } 268a10555a354cf294bde217044472d33c3161df249krajcevski 269a10555a354cf294bde217044472d33c3161df249krajcevski // If we need to update the last row, then do that, too. 270a10555a354cf294bde217044472d33c3161df249krajcevski if (height > 0) { 271a10555a354cf294bde217044472d33c3161df249krajcevski this->updateBlockRow(x, y, width, height, endBlockY, 272a10555a354cf294bde217044472d33c3161df249krajcevski startBlockX, endBlockX); 273a10555a354cf294bde217044472d33c3161df249krajcevski } 274a10555a354cf294bde217044472d33c3161df249krajcevski } 275a10555a354cf294bde217044472d33c3161df249krajcevski#endif 276d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 277d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 278d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Blit a rectangle with one alpha-blended column on the left, 279d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // width (zero or more) opaque pixels, and one alpha-blended column 280d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // on the right. The result will always be at least two pixels wide. 281d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual void blitAntiRect(int x, int y, int width, int height, 282d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE { 283d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This function is currently not implemented. It is not explicitly 284d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // required by the contract, but if at some time a code path runs into 285d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // this function (which is entirely possible), it needs to be implemented. 286d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 287d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // TODO (krajcevski): 288d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This function will be most easily implemented as follows: 289d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 1. If width/height are smaller than a block, then update the 290d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // indices of the affected blocks. 291d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 2. If width/height are larger than a block, then construct a 9-patch 292d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // of block encodings that represent the rectangle, and write them 293d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // to the compressed buffer as necessary. Whether or not the blocks 294d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // are overwritten by zeros or just their indices are updated is up 295d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // to debate. 296d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkFAIL("Not implemented!"); 297d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 298d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 299dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Blit a pattern of pixels defined by a rectangle-clipped mask; We make an 300dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // assumption here that if this function gets called, then it will replace all 301dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // of the compressed texture blocks that it touches. Hence, two separate calls 302dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // to blitMask that have clips next to one another will cause artifacts. Most 303dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // of the time, however, this function gets called because constructing the mask 304dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // was faster than constructing the RLE for blitAntiH, and this function will 305dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // only be called once. 306dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski#ifdef SK_DEBUG 307dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski bool fBlitMaskCalled; 308dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski#endif 309dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski virtual void blitMask(const SkMask& mask, const SkIRect& clip) SK_OVERRIDE { 310dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 311dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Assumptions: 312dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(!fBlitMaskCalled && (fBlitMaskCalled = true)); 313dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(SkMask::kA8_Format == mask.fFormat); 314dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(mask.fBounds.contains(clip)); 315dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 316dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Start from largest block boundary less than the clip boundaries. 317dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int startI = BlockDim * (clip.left() / BlockDim); 318dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int startJ = BlockDim * (clip.top() / BlockDim); 319dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 320dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski for (int j = startJ; j < clip.bottom(); j += BlockDim) { 321dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 322dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Get the destination for this block row 323dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski uint8_t* dst = this->getBlock(startI, j); 324dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski for (int i = startI; i < clip.right(); i += BlockDim) { 325dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 326dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // At this point, the block should intersect the clip. 327dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(SkIRect::IntersectsNoEmptyCheck( 328dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkIRect::MakeXYWH(i, j, BlockDim, BlockDim), clip)); 329dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 330dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Do we need to pad it? 331dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski if (i < clip.left() || j < clip.top() || 332dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski i + BlockDim > clip.right() || j + BlockDim > clip.bottom()) { 333dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 334dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski uint8_t block[BlockDim*BlockDim]; 335dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski memset(block, 0, sizeof(block)); 336dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 337dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int startX = SkMax32(i, clip.left()); 338dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int startY = SkMax32(j, clip.top()); 339dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 340dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int endX = SkMin32(i + BlockDim, clip.right()); 341dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int endY = SkMin32(j + BlockDim, clip.bottom()); 342dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 343dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski for (int y = startY; y < endY; ++y) { 344dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int col = startX - i; 345dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int row = y - j; 346dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const int valsWide = endX - startX; 347dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(valsWide <= BlockDim); 348dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(0 <= col && col < BlockDim); 349dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski SkASSERT(0 <= row && row < BlockDim); 350dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski memcpy(block + row*BlockDim + col, 351dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski mask.getAddr8(startX, j + row), valsWide); 352dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski } 353dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 354dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski CompressorType::CompressA8Horizontal(dst, block, BlockDim); 355dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski } else { 356dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski // Otherwise, just compress it. 357dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski uint8_t*const src = mask.getAddr8(i, j); 358dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski const uint32_t rb = mask.fRowBytes; 359dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski CompressorType::CompressA8Horizontal(dst, src, rb); 360dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski } 361dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski 362dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski dst += EncodedBlockSize; 363dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski } 364dff491ba3eab17d5ae631e8c46f83a82390213b8krajcevski } 365d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 366d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 367d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If the blitter just sets a single value for each pixel, return the 368d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // bitmap it draws into, and assign value. If not, return NULL and ignore 369d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // the value parameter. 370d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE { 371d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski return NULL; 372d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 373d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 374d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski /** 375d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * Compressed texture blitters only really work correctly if they get 376d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * BlockDim rows at a time. That being said, this blitter tries it's best 377d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * to preserve semantics if blitAntiH doesn't get called in too many 378d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski * weird ways... 379d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski */ 380d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski virtual int requestRowsPreserved() const { return BlockDim; } 381d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 382d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevskiprivate: 383d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski static const int kPixelsPerBlock = BlockDim * BlockDim; 384d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 385d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The longest possible run of pixels that this blitter will receive. 386d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This is initialized in the constructor to 0x7FFE, which is one less 387d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // than the largest positive 16-bit integer. We make sure that it's one 388d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // less for debugging purposes. We also don't make this variable static 389d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // in order to make sure that we can construct a valid pointer to it. 390d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int16_t kLongestRun; 391d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 392d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Usually used in conjunction with kLongestRun. This is initialized to 393d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // zero. 394d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const SkAlpha kZeroAlpha; 395d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 396d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // This is the information that we buffer whenever we're asked to blit 397d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // a row with this blitter. 398d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski struct BufferedRun { 399d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const SkAlpha* fAlphas; 400d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int16_t* fRuns; 401d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int fX, fY; 402d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } fBufferedRuns[BlockDim]; 403d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 404d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The next row [0, BlockDim) that we need to blit. 405d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int fNextRun; 406d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 407d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The width and height of the image that we're blitting 408d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int fWidth; 409d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int fHeight; 410d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 411d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The compressed buffer that we're blitting into. It is assumed that the buffer 412d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // is large enough to store a compressed image of size fWidth*fHeight. 413d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski void* const fBuffer; 414d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 415d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Various utility functions 416d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int blocksWide() const { return fWidth / BlockDim; } 417d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int blocksTall() const { return fHeight / BlockDim; } 418d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int totalBlocks() const { return (fWidth * fHeight) / kPixelsPerBlock; } 419d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 420d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Returns the block index for the block containing pixel (x, y). Block 421d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // indices start at zero and proceed in raster order. 422d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int getBlockOffset(int x, int y) const { 423d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(x < fWidth); 424d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(y < fHeight); 425d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int blockCol = x / BlockDim; 426d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int blockRow = y / BlockDim; 427d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski return blockRow * this->blocksWide() + blockCol; 428d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 429d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 430d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Returns a pointer to the block containing pixel (x, y) 431d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski uint8_t *getBlock(int x, int y) const { 432d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski uint8_t* ptr = reinterpret_cast<uint8_t*>(fBuffer); 433d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski return ptr + EncodedBlockSize*this->getBlockOffset(x, y); 434d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 435d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 436d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Updates the block whose columns are stored in block. curAlphai is expected 437d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // to store the alpha values that will be placed within each of the columns in 438d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // the range [col, col+colsLeft). 439d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski typedef uint32_t Column[BlockDim/4]; 440d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski typedef uint32_t Block[BlockDim][BlockDim/4]; 441d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski inline void updateBlockColumns(Block block, const int col, 442d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int colsLeft, const Column curAlphai) { 44349f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(block); 44410a350c32826d10349bc3647e83d623259805b62krajcevski SkASSERT(col + colsLeft <= BlockDim); 445d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 446d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski for (int i = col; i < (col + colsLeft); ++i) { 447d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski memcpy(block[i], curAlphai, sizeof(Column)); 448d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 449d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 450d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 451d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The following function writes the buffered runs to compressed blocks. 452d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If fNextRun < BlockDim, then we fill the runs that we haven't buffered with 453d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // the constant zero buffer. 454d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski void flushRuns() { 455d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we don't have any runs, then just return. 456d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if (0 == fNextRun) { 457d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski return; 458d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 459d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 460d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#ifndef NDEBUG 461d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Make sure that if we have any runs, they all match 462d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski for (int i = 1; i < fNextRun; ++i) { 463d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(fBufferedRuns[i].fY == fBufferedRuns[i-1].fY + 1); 464d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(fBufferedRuns[i].fX == fBufferedRuns[i-1].fX); 465d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 466d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#endif 467d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 468d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we don't have as many runs as we have rows, fill in the remaining 469d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // runs with constant zeros. 470d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski for (int i = fNextRun; i < BlockDim; ++i) { 471d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[i].fY = fBufferedRuns[0].fY + i; 472d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[i].fX = fBufferedRuns[0].fX; 473d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[i].fAlphas = &kZeroAlpha; 474d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fBufferedRuns[i].fRuns = &kLongestRun; 475d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 476d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 477d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Make sure that our assumptions aren't violated. 478d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(fNextRun > 0 && fNextRun <= BlockDim); 479d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT((fBufferedRuns[0].fY % BlockDim) == 0); 480d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 481d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // The following logic walks BlockDim rows at a time and outputs compressed 482d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // blocks to the buffer passed into the constructor. 483d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // We do the following: 484d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 485d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // c1 c2 c3 c4 486d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ----------------------------------------------------------------------- 487d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ... | | | | | ----> fBufferedRuns[0] 488d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ----------------------------------------------------------------------- 489d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ... | | | | | ----> fBufferedRuns[1] 490d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ----------------------------------------------------------------------- 491d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ... | | | | | ----> fBufferedRuns[2] 492d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ----------------------------------------------------------------------- 493d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ... | | | | | ----> fBufferedRuns[3] 494d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // ----------------------------------------------------------------------- 495d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 496d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // curX -- the macro X value that we've gotten to. 497d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // c[BlockDim] -- the buffers that represent the columns of the current block 498d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // that we're operating on 499d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // curAlphaColumn -- buffer containing the column of alpha values from fBufferedRuns. 500d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // nextX -- for each run, the next point at which we need to update curAlphaColumn 501d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // after the value of curX. 502d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // finalX -- the minimum of all the nextX values. 503d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // 504d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // curX advances to finalX outputting any blocks that it passes along 505d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // the way. Since finalX will not change when we reach the end of a 506d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // run, the termination criteria will be whenever curX == finalX at the 507d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // end of a loop. 508d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 509d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Setup: 510d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski Block block; 511d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski sk_bzero(block, sizeof(block)); 512d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 513d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski Column curAlphaColumn; 514d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski sk_bzero(curAlphaColumn, sizeof(curAlphaColumn)); 515d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 516d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkAlpha *curAlpha = reinterpret_cast<SkAlpha*>(&curAlphaColumn); 517d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 518d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int nextX[BlockDim]; 519d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski for (int i = 0; i < BlockDim; ++i) { 520d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski nextX[i] = 0x7FFFFF; 521d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 522d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 523d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski uint8_t* outPtr = this->getBlock(fBufferedRuns[0].fX, fBufferedRuns[0].fY); 524d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 525d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Populate the first set of runs and figure out how far we need to 526d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // advance on the first step 527d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int curX = 0; 528d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski int finalX = 0xFFFFF; 529d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski for (int i = 0; i < BlockDim; ++i) { 530d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski nextX[i] = *(fBufferedRuns[i].fRuns); 531d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski curAlpha[i] = *(fBufferedRuns[i].fAlphas); 532d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 533d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski finalX = SkMin32(nextX[i], finalX); 534d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 535d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 536d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Make sure that we have a valid right-bound X value 537d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(finalX < 0xFFFFF); 538d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 539a10555a354cf294bde217044472d33c3161df249krajcevski // If the finalX is the longest run, then just blit until we have 540a10555a354cf294bde217044472d33c3161df249krajcevski // width... 541a10555a354cf294bde217044472d33c3161df249krajcevski if (kLongestRun == finalX) { 542a10555a354cf294bde217044472d33c3161df249krajcevski finalX = fWidth; 543a10555a354cf294bde217044472d33c3161df249krajcevski } 544a10555a354cf294bde217044472d33c3161df249krajcevski 545d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Run the blitter... 546d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski while (curX != finalX) { 547d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(finalX >= curX); 548d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 549d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Do we need to populate the rest of the block? 550d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if ((finalX - (BlockDim*(curX / BlockDim))) >= BlockDim) { 551d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int col = curX % BlockDim; 552d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int colsLeft = BlockDim - col; 553d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(curX + colsLeft <= finalX); 554d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 555d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); 556d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 557d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Write this block 55845a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski CompressorType::CompressA8Vertical(outPtr, reinterpret_cast<uint8_t*>(block)); 559d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski outPtr += EncodedBlockSize; 560d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski curX += colsLeft; 561d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 562d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 563d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we can advance even further, then just keep memsetting the block 564d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if ((finalX - curX) >= BlockDim) { 565d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT((curX % BlockDim) == 0); 566d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 567d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int col = 0; 568d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int colsLeft = BlockDim; 569d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 570d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); 571d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 572d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // While we can keep advancing, just keep writing the block. 573d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski uint8_t lastBlock[EncodedBlockSize]; 57445a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski CompressorType::CompressA8Vertical(lastBlock, reinterpret_cast<uint8_t*>(block)); 575d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski while((finalX - curX) >= BlockDim) { 576d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski memcpy(outPtr, lastBlock, EncodedBlockSize); 577d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski outPtr += EncodedBlockSize; 578d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski curX += BlockDim; 579d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 580d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 581d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 582d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we haven't advanced within the block then do so. 583d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski if (curX < finalX) { 584d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int col = curX % BlockDim; 585d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski const int colsLeft = finalX - curX; 586d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 587d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); 588d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski curX += colsLeft; 589d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 590d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 591d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski SkASSERT(curX == finalX); 592d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 593d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // Figure out what the next advancement is... 594a10555a354cf294bde217044472d33c3161df249krajcevski if (finalX < fWidth) { 595a10555a354cf294bde217044472d33c3161df249krajcevski for (int i = 0; i < BlockDim; ++i) { 596a10555a354cf294bde217044472d33c3161df249krajcevski if (nextX[i] == finalX) { 597a10555a354cf294bde217044472d33c3161df249krajcevski const int16_t run = *(fBufferedRuns[i].fRuns); 598a10555a354cf294bde217044472d33c3161df249krajcevski fBufferedRuns[i].fRuns += run; 599a10555a354cf294bde217044472d33c3161df249krajcevski fBufferedRuns[i].fAlphas += run; 600a10555a354cf294bde217044472d33c3161df249krajcevski curAlpha[i] = *(fBufferedRuns[i].fAlphas); 601a10555a354cf294bde217044472d33c3161df249krajcevski nextX[i] += *(fBufferedRuns[i].fRuns); 602a10555a354cf294bde217044472d33c3161df249krajcevski } 603d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 604d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 605a10555a354cf294bde217044472d33c3161df249krajcevski finalX = 0xFFFFF; 606a10555a354cf294bde217044472d33c3161df249krajcevski for (int i = 0; i < BlockDim; ++i) { 607a10555a354cf294bde217044472d33c3161df249krajcevski finalX = SkMin32(nextX[i], finalX); 608a10555a354cf294bde217044472d33c3161df249krajcevski } 609a10555a354cf294bde217044472d33c3161df249krajcevski } else { 610a10555a354cf294bde217044472d33c3161df249krajcevski curX = finalX; 611d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 612d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 613d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 614d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski // If we didn't land on a block boundary, output the block... 615ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski if ((curX % BlockDim) > 0) { 616ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski#ifdef SK_DEBUG 617ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski for (int i = 0; i < BlockDim; ++i) { 618ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski SkASSERT(nextX[i] == kLongestRun || nextX[i] == curX); 619ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski } 620ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski#endif 621ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski const int col = curX % BlockDim; 622ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski const int colsLeft = BlockDim - col; 623ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski 624ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski memset(curAlphaColumn, 0, sizeof(curAlphaColumn)); 625ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski this->updateBlockColumns(block, col, colsLeft, curAlphaColumn); 626ab4c71101489e62f22df6926dd3afcb699f5a164krajcevski 62745a0bf505914adf0ee8c69e2647230618bbb3a63krajcevski CompressorType::CompressA8Vertical(outPtr, reinterpret_cast<uint8_t*>(block)); 628d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 629d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 630d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski fNextRun = 0; 631d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski } 632a10555a354cf294bde217044472d33c3161df249krajcevski 633a10555a354cf294bde217044472d33c3161df249krajcevski#if PEDANTIC_BLIT_RECT 634a10555a354cf294bde217044472d33c3161df249krajcevski void updateBlockRow(int x, int y, int width, int height, 635a10555a354cf294bde217044472d33c3161df249krajcevski int blockRow, int startBlockX, int endBlockX) { 636a10555a354cf294bde217044472d33c3161df249krajcevski if (0 == width || 0 == height || startBlockX == endBlockX) { 637a10555a354cf294bde217044472d33c3161df249krajcevski return; 638a10555a354cf294bde217044472d33c3161df249krajcevski } 639a10555a354cf294bde217044472d33c3161df249krajcevski 640a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t* dst = this->getBlock(startBlockX, BlockDim * (y / BlockDim)); 641a10555a354cf294bde217044472d33c3161df249krajcevski 642a10555a354cf294bde217044472d33c3161df249krajcevski // One horizontal strip to update 643a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t mask[BlockDim*BlockDim]; 644a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask, 0, sizeof(mask)); 645a10555a354cf294bde217044472d33c3161df249krajcevski 646a10555a354cf294bde217044472d33c3161df249krajcevski // Update the left cap 647a10555a354cf294bde217044472d33c3161df249krajcevski int blockX = startBlockX; 648a10555a354cf294bde217044472d33c3161df249krajcevski const int yoff = y - blockRow; 649a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = 0; j < height; ++j) { 650a10555a354cf294bde217044472d33c3161df249krajcevski const int xoff = x - blockX; 651a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + (j + yoff)*BlockDim + xoff, 0xFF, BlockDim - xoff); 652a10555a354cf294bde217044472d33c3161df249krajcevski } 653a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(dst, mask, BlockDim, mask); 654a10555a354cf294bde217044472d33c3161df249krajcevski dst += EncodedBlockSize; 655a10555a354cf294bde217044472d33c3161df249krajcevski blockX += BlockDim; 656a10555a354cf294bde217044472d33c3161df249krajcevski 657a10555a354cf294bde217044472d33c3161df249krajcevski // Update the middle 658a10555a354cf294bde217044472d33c3161df249krajcevski if (blockX < endBlockX) { 659a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = 0; j < height; ++j) { 660a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + (j + yoff)*BlockDim, 0xFF, BlockDim); 661a10555a354cf294bde217044472d33c3161df249krajcevski } 662a10555a354cf294bde217044472d33c3161df249krajcevski while (blockX < endBlockX) { 663a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(dst, mask, BlockDim, mask); 664a10555a354cf294bde217044472d33c3161df249krajcevski dst += EncodedBlockSize; 665a10555a354cf294bde217044472d33c3161df249krajcevski blockX += BlockDim; 666a10555a354cf294bde217044472d33c3161df249krajcevski } 667a10555a354cf294bde217044472d33c3161df249krajcevski } 668a10555a354cf294bde217044472d33c3161df249krajcevski 669a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(endBlockX == blockX); 670a10555a354cf294bde217044472d33c3161df249krajcevski 671a10555a354cf294bde217044472d33c3161df249krajcevski // Update the right cap (if we need to) 672a10555a354cf294bde217044472d33c3161df249krajcevski if (x + width > endBlockX) { 673a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask, 0, sizeof(mask)); 674a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = 0; j < height; ++j) { 675a10555a354cf294bde217044472d33c3161df249krajcevski const int xoff = (x+width-blockX); 676a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + (j+yoff)*BlockDim, 0xFF, xoff); 677a10555a354cf294bde217044472d33c3161df249krajcevski } 678a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(dst, mask, BlockDim, mask); 679a10555a354cf294bde217044472d33c3161df249krajcevski } 680a10555a354cf294bde217044472d33c3161df249krajcevski } 681a10555a354cf294bde217044472d33c3161df249krajcevski 682a10555a354cf294bde217044472d33c3161df249krajcevski void updateBlockCol(int x, int y, int width, int height, 683a10555a354cf294bde217044472d33c3161df249krajcevski int blockCol, int startBlockY, int endBlockY) { 684a10555a354cf294bde217044472d33c3161df249krajcevski if (0 == width || 0 == height || startBlockY == endBlockY) { 685a10555a354cf294bde217044472d33c3161df249krajcevski return; 686a10555a354cf294bde217044472d33c3161df249krajcevski } 687a10555a354cf294bde217044472d33c3161df249krajcevski 688a10555a354cf294bde217044472d33c3161df249krajcevski // One vertical strip to update 689a10555a354cf294bde217044472d33c3161df249krajcevski uint8_t mask[BlockDim*BlockDim]; 690a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask, 0, sizeof(mask)); 691a10555a354cf294bde217044472d33c3161df249krajcevski const int maskX0 = x - blockCol; 692a10555a354cf294bde217044472d33c3161df249krajcevski const int maskWidth = maskX0 + width; 693a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(maskWidth <= BlockDim); 694a10555a354cf294bde217044472d33c3161df249krajcevski 695a10555a354cf294bde217044472d33c3161df249krajcevski // Update the top cap 696a10555a354cf294bde217044472d33c3161df249krajcevski int blockY = startBlockY; 697a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = (y - blockY); j < BlockDim; ++j) { 698a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + maskX0 + j*BlockDim, 0xFF, maskWidth); 699a10555a354cf294bde217044472d33c3161df249krajcevski } 700a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), mask, BlockDim, mask); 701a10555a354cf294bde217044472d33c3161df249krajcevski blockY += BlockDim; 702a10555a354cf294bde217044472d33c3161df249krajcevski 703a10555a354cf294bde217044472d33c3161df249krajcevski // Update middle 704a10555a354cf294bde217044472d33c3161df249krajcevski if (blockY < endBlockY) { 705a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = 0; j < BlockDim; ++j) { 706a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + maskX0 + j*BlockDim, 0xFF, maskWidth); 707a10555a354cf294bde217044472d33c3161df249krajcevski } 708a10555a354cf294bde217044472d33c3161df249krajcevski while (blockY < endBlockY) { 709a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), 710a10555a354cf294bde217044472d33c3161df249krajcevski mask, BlockDim, mask); 711a10555a354cf294bde217044472d33c3161df249krajcevski blockY += BlockDim; 712a10555a354cf294bde217044472d33c3161df249krajcevski } 713a10555a354cf294bde217044472d33c3161df249krajcevski } 714a10555a354cf294bde217044472d33c3161df249krajcevski 715a10555a354cf294bde217044472d33c3161df249krajcevski SkASSERT(endBlockY == blockY); 716a10555a354cf294bde217044472d33c3161df249krajcevski 717a10555a354cf294bde217044472d33c3161df249krajcevski // Update bottom 718a10555a354cf294bde217044472d33c3161df249krajcevski if (y + height > endBlockY) { 719a10555a354cf294bde217044472d33c3161df249krajcevski for (int j = y+height; j < endBlockY + BlockDim; ++j) { 720a10555a354cf294bde217044472d33c3161df249krajcevski memset(mask + (j-endBlockY)*BlockDim, 0, BlockDim); 721a10555a354cf294bde217044472d33c3161df249krajcevski } 722a10555a354cf294bde217044472d33c3161df249krajcevski CompressorType::UpdateBlock(this->getBlock(blockCol, blockY), 723a10555a354cf294bde217044472d33c3161df249krajcevski mask, BlockDim, mask); 724a10555a354cf294bde217044472d33c3161df249krajcevski } 725a10555a354cf294bde217044472d33c3161df249krajcevski } 726a10555a354cf294bde217044472d33c3161df249krajcevski#endif // PEDANTIC_BLIT_RECT 727a10555a354cf294bde217044472d33c3161df249krajcevski 728d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski}; 729d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 730d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski} // namespace SkTextureCompressor 731d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski 732d5e46c7893afdd5976c1581a2ae81168252f5deckrajcevski#endif // SkTextureCompressor_Blitter_DEFINED 733