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 "GrAtlas.h"
12#include "GrContext.h"
13#include "GrGpu.h"
14#include "GrRectanizer.h"
15#include "GrPlotMgr.h"
16
17#if 0
18#define GR_PLOT_WIDTH   8
19#define GR_PLOT_HEIGHT  4
20#define GR_ATLAS_WIDTH  256
21#define GR_ATLAS_HEIGHT 256
22
23#define GR_ATLAS_TEXTURE_WIDTH  (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
24#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
25
26#else
27
28#define GR_ATLAS_TEXTURE_WIDTH  1024
29#define GR_ATLAS_TEXTURE_HEIGHT 2048
30
31#define GR_ATLAS_WIDTH  341
32#define GR_ATLAS_HEIGHT 341
33
34#define GR_PLOT_WIDTH   (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
35#define GR_PLOT_HEIGHT  (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
36
37#endif
38
39///////////////////////////////////////////////////////////////////////////////
40
41#define BORDER      1
42
43#if GR_DEBUG
44    static int gCounter;
45#endif
46
47GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
48    fAtlasMgr = mgr;    // just a pointer, not an owner
49    fNext = NULL;
50    fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
51    fPlot.set(plotX, plotY);
52
53    fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
54                                   GR_ATLAS_HEIGHT - BORDER);
55
56    fMaskFormat = format;
57
58#if GR_DEBUG
59//    GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
60    gCounter += 1;
61#endif
62}
63
64GrAtlas::~GrAtlas() {
65    fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
66
67    delete fRects;
68
69#if GR_DEBUG
70    --gCounter;
71//    GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
72#endif
73}
74
75static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
76    loc->fX += plot.fX * GR_ATLAS_WIDTH;
77    loc->fY += plot.fY * GR_ATLAS_HEIGHT;
78}
79
80static uint8_t* zerofill(uint8_t* ptr, int count) {
81    while (--count >= 0) {
82        *ptr++ = 0;
83    }
84    return ptr;
85}
86
87bool GrAtlas::addSubImage(int width, int height, const void* image,
88                          GrIPoint16* loc) {
89    if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
90        return false;
91    }
92
93    SkAutoSMalloc<1024> storage;
94    int dstW = width + 2*BORDER;
95    int dstH = height + 2*BORDER;
96    if (BORDER) {
97        const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
98        const size_t dstRB = dstW * bpp;
99        uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
100        Gr_bzero(dst, dstRB);                // zero top row
101        dst += dstRB;
102        for (int y = 0; y < height; y++) {
103            dst = zerofill(dst, bpp);   // zero left edge
104            memcpy(dst, image, width * bpp);
105            dst += width * bpp;
106            dst = zerofill(dst, bpp);   // zero right edge
107            image = (const void*)((const char*)image + width * bpp);
108        }
109        Gr_bzero(dst, dstRB);                // zero bottom row
110        image = storage.get();
111    }
112    adjustForPlot(loc, fPlot);
113    GrContext* context = fTexture->getContext();
114    // We call the internal version so that we don't force a flush. We assume
115    // our caller is smart and hasn't referenced the part of the texture we're
116    // about to update since the last flush.
117    context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY,
118                                        dstW, dstH, fTexture->config(),
119                                        image, 0,
120                                        GrContext::kDontFlush_PixelOpsFlag);
121
122    // now tell the caller to skip the top/left BORDER
123    loc->fX += BORDER;
124    loc->fY += BORDER;
125    return true;
126}
127
128///////////////////////////////////////////////////////////////////////////////
129
130GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
131    fGpu = gpu;
132    gpu->ref();
133    Gr_bzero(fTexture, sizeof(fTexture));
134    fPlotMgr = new GrPlotMgr(GR_PLOT_WIDTH, GR_PLOT_HEIGHT);
135}
136
137GrAtlasMgr::~GrAtlasMgr() {
138    for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) {
139        GrSafeUnref(fTexture[i]);
140    }
141    delete fPlotMgr;
142    fGpu->unref();
143}
144
145static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
146    switch (format) {
147        case kA8_GrMaskFormat:
148            return kAlpha_8_GrPixelConfig;
149        case kA565_GrMaskFormat:
150            return kRGB_565_GrPixelConfig;
151        case kA888_GrMaskFormat:
152            return kSkia8888_PM_GrPixelConfig;
153        default:
154            GrAssert(!"unknown maskformat");
155    }
156    return kUnknown_GrPixelConfig;
157}
158
159GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
160                                int width, int height, const void* image,
161                                GrMaskFormat format,
162                                GrIPoint16* loc) {
163    GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
164
165    if (atlas && atlas->addSubImage(width, height, image, loc)) {
166        return atlas;
167    }
168
169    // If the above fails, then either we have no starting atlas, or the current
170    // one is full. Either way we need to allocate a new atlas
171
172    GrIPoint16 plot;
173    if (!fPlotMgr->newPlot(&plot)) {
174        return NULL;
175    }
176
177    GrAssert(0 == kA8_GrMaskFormat);
178    GrAssert(1 == kA565_GrMaskFormat);
179    if (NULL == fTexture[format]) {
180        GrTextureDesc desc = {
181            kDynamicUpdate_GrTextureFlagBit,
182            GR_ATLAS_TEXTURE_WIDTH,
183            GR_ATLAS_TEXTURE_HEIGHT,
184            maskformat2pixelconfig(format),
185            {0} // samples
186        };
187        fTexture[format] = fGpu->createTexture(desc, NULL, 0);
188        if (NULL == fTexture[format]) {
189            return NULL;
190        }
191    }
192
193    GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
194    if (!newAtlas->addSubImage(width, height, image, loc)) {
195        delete newAtlas;
196        return NULL;
197    }
198
199    newAtlas->fNext = atlas;
200    return newAtlas;
201}
202
203void GrAtlasMgr::freePlot(int x, int y) {
204    GrAssert(fPlotMgr->isBusy(x, y));
205    fPlotMgr->freePlot(x, y);
206}
207
208
209