blob: 0c36f49bf6494c7406384922b4123ed0defe3cdd [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrRectanizer.h"
12#include "GrTBSearch.h"
13
14#define MIN_HEIGHT_POW2 2
15
16class GrRectanizerFIFO : public GrRectanizer {
17public:
18 GrRectanizerFIFO(int w, int h) : GrRectanizer(w, h) {
19 fNextStripY = 0;
20 fAreaSoFar = 0;
21 Gr_bzero(fRows, sizeof(fRows));
22 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000023
reed@google.comac10a2d2010-12-22 21:39:39 +000024 virtual ~GrRectanizerFIFO() {
25 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000026
reed@google.comac10a2d2010-12-22 21:39:39 +000027 virtual bool addRect(int w, int h, GrIPoint16* loc);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000028
reed@google.comac10a2d2010-12-22 21:39:39 +000029 virtual float percentFull() const {
30 return fAreaSoFar / ((float)this->width() * this->height());
31 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000032
reed@google.comac10a2d2010-12-22 21:39:39 +000033 virtual int stripToPurge(int height) const { return -1; }
34 virtual void purgeStripAtY(int yCoord) { }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000035
reed@google.comac10a2d2010-12-22 21:39:39 +000036 ///////////////////////////////////////////////////////////////////////////
rmistry@google.comfbfcd562012-08-23 18:09:54 +000037
reed@google.comac10a2d2010-12-22 21:39:39 +000038 struct Row {
39 GrIPoint16 fLoc;
40 int fRowHeight;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000041
reed@google.comac10a2d2010-12-22 21:39:39 +000042 bool canAddWidth(int width, int containerWidth) const {
43 return fLoc.fX + width <= containerWidth;
44 }
45 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +000046
reed@google.comac10a2d2010-12-22 21:39:39 +000047 Row fRows[16];
rmistry@google.comfbfcd562012-08-23 18:09:54 +000048
reed@google.comac10a2d2010-12-22 21:39:39 +000049 static int HeightToRowIndex(int height) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000050 SkASSERT(height >= MIN_HEIGHT_POW2);
reed@google.comac10a2d2010-12-22 21:39:39 +000051 return 32 - Gr_clz(height - 1);
52 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000053
reed@google.comac10a2d2010-12-22 21:39:39 +000054 int fNextStripY;
55 int32_t fAreaSoFar;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000056
reed@google.comac10a2d2010-12-22 21:39:39 +000057 bool canAddStrip(int height) const {
58 return fNextStripY + height <= this->height();
59 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000060
reed@google.comac10a2d2010-12-22 21:39:39 +000061 void initRow(Row* row, int rowHeight) {
62 row->fLoc.set(0, fNextStripY);
63 row->fRowHeight = rowHeight;
64 fNextStripY += rowHeight;
65 }
66};
67
68bool GrRectanizerFIFO::addRect(int width, int height, GrIPoint16* loc) {
69 if ((unsigned)width > (unsigned)this->width() ||
70 (unsigned)height > (unsigned)this->height()) {
71 return false;
72 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000073
reed@google.comac10a2d2010-12-22 21:39:39 +000074 int32_t area = width * height;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000075
reed@google.comac10a2d2010-12-22 21:39:39 +000076 /*
77 We use bsearch, but there may be more than one row with the same height,
78 so we actually search for height-1, which can only be a pow2 itself if
79 height == 2. Thus we set a minimum height.
80 */
81 height = GrNextPow2(height);
82 if (height < MIN_HEIGHT_POW2) {
83 height = MIN_HEIGHT_POW2;
84 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000085
reed@google.comac10a2d2010-12-22 21:39:39 +000086 Row* row = &fRows[HeightToRowIndex(height)];
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000087 SkASSERT(row->fRowHeight == 0 || row->fRowHeight == height);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000088
reed@google.comac10a2d2010-12-22 21:39:39 +000089 if (0 == row->fRowHeight) {
90 if (!this->canAddStrip(height)) {
91 return false;
92 }
93 this->initRow(row, height);
94 } else {
95 if (!row->canAddWidth(width, this->width())) {
96 if (!this->canAddStrip(height)) {
97 return false;
98 }
99 // that row is now "full", so retarget our Row record for
100 // another one
101 this->initRow(row, height);
102 }
103 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000104
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000105 SkASSERT(row->fRowHeight == height);
106 SkASSERT(row->canAddWidth(width, this->width()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 *loc = row->fLoc;
108 row->fLoc.fX += width;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000109
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000110 SkASSERT(row->fLoc.fX <= this->width());
111 SkASSERT(row->fLoc.fY <= this->height());
112 SkASSERT(fNextStripY <= this->height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000113 fAreaSoFar += area;
114 return true;
115}
116
117///////////////////////////////////////////////////////////////////////////////
118
119GrRectanizer* GrRectanizer::Factory(int width, int height) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000120 return SkNEW_ARGS(GrRectanizerFIFO, (width, height));
reed@google.comac10a2d2010-12-22 21:39:39 +0000121}