1 /*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18 #include "GrRectanizer.h"
19 #include "GrTBSearch.h"
20
21 #define MIN_HEIGHT_POW2 2
22
23 class GrRectanizerFIFO : public GrRectanizer {
24 public:
GrRectanizerFIFO(int w,int h)25 GrRectanizerFIFO(int w, int h) : GrRectanizer(w, h) {
26 fNextStripY = 0;
27 fAreaSoFar = 0;
28 Gr_bzero(fRows, sizeof(fRows));
29 }
30
~GrRectanizerFIFO()31 virtual ~GrRectanizerFIFO() {
32 }
33
34 virtual bool addRect(int w, int h, GrIPoint16* loc);
35
percentFull() const36 virtual float percentFull() const {
37 return fAreaSoFar / ((float)this->width() * this->height());
38 }
39
stripToPurge(int height) const40 virtual int stripToPurge(int height) const { return -1; }
purgeStripAtY(int yCoord)41 virtual void purgeStripAtY(int yCoord) { }
42
43 ///////////////////////////////////////////////////////////////////////////
44
45 struct Row {
46 GrIPoint16 fLoc;
47 int fRowHeight;
48
canAddWidthGrRectanizerFIFO::Row49 bool canAddWidth(int width, int containerWidth) const {
50 return fLoc.fX + width <= containerWidth;
51 }
52 };
53
54 Row fRows[16];
55
HeightToRowIndex(int height)56 static int HeightToRowIndex(int height) {
57 GrAssert(height >= MIN_HEIGHT_POW2);
58 return 32 - Gr_clz(height - 1);
59 }
60
61 int fNextStripY;
62 int32_t fAreaSoFar;
63
canAddStrip(int height) const64 bool canAddStrip(int height) const {
65 return fNextStripY + height <= this->height();
66 }
67
initRow(Row * row,int rowHeight)68 void initRow(Row* row, int rowHeight) {
69 row->fLoc.set(0, fNextStripY);
70 row->fRowHeight = rowHeight;
71 fNextStripY += rowHeight;
72 }
73 };
74
addRect(int width,int height,GrIPoint16 * loc)75 bool GrRectanizerFIFO::addRect(int width, int height, GrIPoint16* loc) {
76 if ((unsigned)width > (unsigned)this->width() ||
77 (unsigned)height > (unsigned)this->height()) {
78 return false;
79 }
80
81 int32_t area = width * height;
82
83 /*
84 We use bsearch, but there may be more than one row with the same height,
85 so we actually search for height-1, which can only be a pow2 itself if
86 height == 2. Thus we set a minimum height.
87 */
88 height = GrNextPow2(height);
89 if (height < MIN_HEIGHT_POW2) {
90 height = MIN_HEIGHT_POW2;
91 }
92
93 Row* row = &fRows[HeightToRowIndex(height)];
94 GrAssert(row->fRowHeight == 0 || row->fRowHeight == height);
95
96 if (0 == row->fRowHeight) {
97 if (!this->canAddStrip(height)) {
98 return false;
99 }
100 this->initRow(row, height);
101 } else {
102 if (!row->canAddWidth(width, this->width())) {
103 if (!this->canAddStrip(height)) {
104 return false;
105 }
106 // that row is now "full", so retarget our Row record for
107 // another one
108 this->initRow(row, height);
109 }
110 }
111
112 GrAssert(row->fRowHeight == height);
113 GrAssert(row->canAddWidth(width, this->width()));
114 *loc = row->fLoc;
115 row->fLoc.fX += width;
116
117 GrAssert(row->fLoc.fX <= this->width());
118 GrAssert(row->fLoc.fY <= this->height());
119 GrAssert(fNextStripY <= this->height());
120 fAreaSoFar += area;
121 return true;
122 }
123
124 ///////////////////////////////////////////////////////////////////////////////
125
Factory(int width,int height)126 GrRectanizer* GrRectanizer::Factory(int width, int height) {
127 return new GrRectanizerFIFO(width, height);
128 }
129
130
131