1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10
11#include "SkGr.h"
12
13/*  Fill out buffer with the compressed format Ganesh expects from a colortable
14 based bitmap. [palette (colortable) + indices].
15
16 At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
17 we could detect that the colortable.count is <= 16, and then repack the
18 indices as nibbles to save RAM, but it would take more time (i.e. a lot
19 slower than memcpy), so skipping that for now.
20
21 Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
22 as the colortable.count says it is.
23 */
24static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
25    SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
26
27    SkAutoLockPixels apl(bitmap);
28    if (!bitmap.readyToDraw()) {
29        SkDEBUGFAIL("bitmap not ready to draw!");
30        return;
31    }
32
33    SkColorTable* ctable = bitmap.getColorTable();
34    char* dst = (char*)buffer;
35
36    memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
37    ctable->unlockColors(false);
38
39    // always skip a full 256 number of entries, even if we memcpy'd fewer
40    dst += kGrColorTableSize;
41
42    if (bitmap.width() == bitmap.rowBytes()) {
43        memcpy(dst, bitmap.getPixels(), bitmap.getSize());
44    } else {
45        // need to trim off the extra bytes per row
46        size_t width = bitmap.width();
47        size_t rowBytes = bitmap.rowBytes();
48        const char* src = (const char*)bitmap.getPixels();
49        for (int y = 0; y < bitmap.height(); y++) {
50            memcpy(dst, src, width);
51            src += rowBytes;
52            dst += width;
53        }
54    }
55}
56
57////////////////////////////////////////////////////////////////////////////////
58
59GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
60                                                GrContext::TextureKey key,
61                                                const GrSamplerState* sampler,
62                                                const SkBitmap& origBitmap) {
63    SkAutoLockPixels alp(origBitmap);
64    GrContext::TextureCacheEntry entry;
65
66    if (!origBitmap.readyToDraw()) {
67        return entry;
68    }
69
70    SkBitmap tmpBitmap;
71
72    const SkBitmap* bitmap = &origBitmap;
73
74    GrTextureDesc desc = {
75        kNone_GrTextureFlags,
76        bitmap->width(),
77        bitmap->height(),
78        SkGr::Bitmap2PixelConfig(*bitmap),
79        {0} // samples
80    };
81
82    if (SkBitmap::kIndex8_Config == bitmap->config()) {
83        // build_compressed_data doesn't do npot->pot expansion
84        // and paletted textures can't be sub-updated
85        if (ctx->supportsIndex8PixelConfig(sampler,
86                                           bitmap->width(), bitmap->height())) {
87            size_t imagesize = bitmap->width() * bitmap->height() +
88                                kGrColorTableSize;
89            SkAutoMalloc storage(imagesize);
90
91            build_compressed_data(storage.get(), origBitmap);
92
93            // our compressed data will be trimmed, so pass width() for its
94            // "rowBytes", since they are the same now.
95
96            if (gUNCACHED_KEY != key) {
97                return ctx->createAndLockTexture(key, sampler, desc, storage.get(),
98                                                 bitmap->width());
99            } else {
100                entry = ctx->lockScratchTexture(desc,
101                                        GrContext::kExact_ScratchTexMatch);
102                entry.texture()->writePixels(0, 0, bitmap->width(),
103                                             bitmap->height(), desc.fConfig,
104                                             storage.get(), 0);
105                return entry;
106            }
107
108        } else {
109            origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
110            // now bitmap points to our temp, which has been promoted to 32bits
111            bitmap = &tmpBitmap;
112        }
113    }
114
115    desc.fConfig = SkGr::Bitmap2PixelConfig(*bitmap);
116    if (gUNCACHED_KEY != key) {
117        return ctx->createAndLockTexture(key, sampler, desc,
118                                         bitmap->getPixels(),
119                                         bitmap->rowBytes());
120    } else {
121        entry = ctx->lockScratchTexture(desc,
122                                        GrContext::kExact_ScratchTexMatch);
123        entry.texture()->writePixels(0, 0,
124                                     bitmap->width(), bitmap->height(),
125                                     desc.fConfig,
126                                     bitmap->getPixels(),
127                                     bitmap->rowBytes());
128        return entry;
129    }
130}
131
132///////////////////////////////////////////////////////////////////////////////
133
134void SkGrClipIterator::reset(const SkClipStack& clipStack) {
135    fClipStack = &clipStack;
136    fIter.reset(clipStack);
137    // Gr has no notion of replace, skip to the
138    // last replace in the clip stack.
139    int lastReplace = 0;
140    int curr = 0;
141    while (NULL != (fCurr = fIter.next())) {
142        if (SkRegion::kReplace_Op == fCurr->fOp) {
143            lastReplace = curr;
144        }
145        ++curr;
146    }
147    fIter.reset(clipStack);
148    for (int i = 0; i < lastReplace+1; ++i) {
149        fCurr = fIter.next();
150    }
151}
152
153GrClipType SkGrClipIterator::getType() const {
154    GrAssert(!this->isDone());
155    if (NULL == fCurr->fPath) {
156        return kRect_ClipType;
157    } else {
158        return kPath_ClipType;
159    }
160}
161
162GrSetOp SkGrClipIterator::getOp() const {
163    // we skipped to the last "replace" op
164    // when this iter was reset.
165    // GrClip doesn't allow replace, so treat it as
166    // intersect.
167    GrSetOp skToGrOps[] = {
168        kDifference_SetOp,         // kDifference_Op
169        kIntersect_SetOp,          // kIntersect_Op
170        kUnion_SetOp,              // kUnion_Op
171        kXor_SetOp,                // kXOR_Op
172        kReverseDifference_SetOp,  // kReverseDifference_Op
173        kIntersect_SetOp           // kReplace_op
174    };
175    GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
176    GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
177    GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
178    GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
179    GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
180    GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
181    return skToGrOps[fCurr->fOp];
182}
183
184GrPathFill SkGrClipIterator::getPathFill() const {
185    switch (fCurr->fPath->getFillType()) {
186        case SkPath::kWinding_FillType:
187            return kWinding_PathFill;
188        case SkPath::kEvenOdd_FillType:
189            return  kEvenOdd_PathFill;
190        case SkPath::kInverseWinding_FillType:
191            return kInverseWinding_PathFill;
192        case SkPath::kInverseEvenOdd_FillType:
193            return kInverseEvenOdd_PathFill;
194        default:
195            GrCrash("Unsupported path fill in clip.");
196            return kWinding_PathFill; // suppress warning
197    }
198}
199
200///////////////////////////////////////////////////////////////////////////////
201
202GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
203                                                    bool isOpaque) {
204    switch (config) {
205        case SkBitmap::kA8_Config:
206            return kAlpha_8_GrPixelConfig;
207        case SkBitmap::kIndex8_Config:
208            return kIndex_8_GrPixelConfig;
209        case SkBitmap::kRGB_565_Config:
210            return kRGB_565_GrPixelConfig;
211        case SkBitmap::kARGB_4444_Config:
212            return kRGBA_4444_GrPixelConfig;
213        case SkBitmap::kARGB_8888_Config:
214            return kSkia8888_PM_GrPixelConfig;
215        default:
216            return kUnknown_GrPixelConfig;
217    }
218}
219
220