1 | /* Copyright (c) 2001, Stanford University
|
---|
2 | * All rights reserved
|
---|
3 | *
|
---|
4 | * See the file LICENSE.txt for information on redistributing this software.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "server_dispatch.h"
|
---|
8 | #include "server.h"
|
---|
9 | #include "cr_error.h"
|
---|
10 | #include "cr_unpack.h"
|
---|
11 | #include "cr_mem.h"
|
---|
12 | #include "state/cr_statetypes.h"
|
---|
13 |
|
---|
14 | /* This code copied from the tilesorter (fooey) */
|
---|
15 |
|
---|
16 | typedef struct BucketRegion *BucketRegion_ptr;
|
---|
17 | typedef struct BucketRegion {
|
---|
18 | CRbitvalue id;
|
---|
19 | CRrecti extents;
|
---|
20 | BucketRegion_ptr right;
|
---|
21 | BucketRegion_ptr up;
|
---|
22 | } BucketRegion;
|
---|
23 |
|
---|
24 | #define HASHRANGE 256
|
---|
25 |
|
---|
26 | #define BKT_DOWNHASH(a, range) ((a)*HASHRANGE/(range))
|
---|
27 | #define BKT_UPHASH(a, range) ((a)*HASHRANGE/(range) + ((a)*HASHRANGE%(range)?1:0))
|
---|
28 |
|
---|
29 | struct BucketingInfo {
|
---|
30 | BucketRegion *rhash[HASHRANGE][HASHRANGE];
|
---|
31 | BucketRegion *rlist;
|
---|
32 | };
|
---|
33 |
|
---|
34 |
|
---|
35 | /*
|
---|
36 | * At this point we know that the tiles are uniformly sized so we can use
|
---|
37 | * a hash-based bucketing method. Setup the hash table now.
|
---|
38 | */
|
---|
39 | static GLboolean
|
---|
40 | fillBucketingHash(CRMuralInfo *mural)
|
---|
41 | {
|
---|
42 | int i, j, k, m;
|
---|
43 | int r_len = 0;
|
---|
44 | int xinc, yinc;
|
---|
45 | int rlist_alloc = 64 * 128;
|
---|
46 | BucketRegion *rptr;
|
---|
47 | struct BucketingInfo *bucketInfo;
|
---|
48 |
|
---|
49 | if (mural->bucketInfo) {
|
---|
50 | crFree(mural->bucketInfo->rlist);
|
---|
51 | crFree(mural->bucketInfo);
|
---|
52 | mural->bucketInfo = NULL;
|
---|
53 | }
|
---|
54 |
|
---|
55 | bucketInfo = (struct BucketingInfo *) crCalloc(sizeof(struct BucketingInfo));
|
---|
56 | if (!bucketInfo)
|
---|
57 | return GL_FALSE;
|
---|
58 |
|
---|
59 | /* Allocate rlist (don't free it!!!) */
|
---|
60 | bucketInfo->rlist = (BucketRegion *) crAlloc(rlist_alloc * sizeof(BucketRegion));
|
---|
61 |
|
---|
62 | for ( i = 0; i < HASHRANGE; i++ )
|
---|
63 | {
|
---|
64 | for ( j = 0; j < HASHRANGE; j++ )
|
---|
65 | {
|
---|
66 | bucketInfo->rhash[i][j] = NULL;
|
---|
67 | }
|
---|
68 | }
|
---|
69 |
|
---|
70 | /* Fill the rlist */
|
---|
71 | xinc = mural->extents[0].imagewindow.x2 - mural->extents[0].imagewindow.x1;
|
---|
72 | yinc = mural->extents[0].imagewindow.y2 - mural->extents[0].imagewindow.y1;
|
---|
73 | CRASSERT(xinc > 0 || mural->width == 0);
|
---|
74 | CRASSERT(yinc > 0 || mural->height == 0);
|
---|
75 |
|
---|
76 | rptr = bucketInfo->rlist;
|
---|
77 | for (i=0; i < (int) mural->width; i+=xinc)
|
---|
78 | {
|
---|
79 | for (j=0; j < (int) mural->height; j+=yinc)
|
---|
80 | {
|
---|
81 | for (k=0; k < mural->numExtents; k++)
|
---|
82 | {
|
---|
83 | if (mural->extents[k].imagewindow.x1 == i &&
|
---|
84 | mural->extents[k].imagewindow.y1 == j)
|
---|
85 | {
|
---|
86 | rptr->extents = mural->extents[k].imagewindow; /* x1,y1,x2,y2 */
|
---|
87 | rptr->id = k;
|
---|
88 | break;
|
---|
89 | }
|
---|
90 | }
|
---|
91 | if (k == mural->numExtents)
|
---|
92 | {
|
---|
93 | rptr->extents.x1 = i;
|
---|
94 | rptr->extents.y1 = j;
|
---|
95 | rptr->extents.x2 = i + xinc;
|
---|
96 | rptr->extents.y2 = j + yinc;
|
---|
97 | rptr->id = -1;
|
---|
98 | }
|
---|
99 | rptr++;
|
---|
100 | }
|
---|
101 | }
|
---|
102 | r_len = rptr - bucketInfo->rlist;
|
---|
103 |
|
---|
104 | /* Fill hash table */
|
---|
105 | for (i = 0; i < r_len; i++)
|
---|
106 | {
|
---|
107 | BucketRegion *r = &bucketInfo->rlist[i];
|
---|
108 |
|
---|
109 | for (k=BKT_DOWNHASH(r->extents.x1, (int)mural->width);
|
---|
110 | k<=BKT_UPHASH(r->extents.x2, (int)mural->width) &&
|
---|
111 | k < HASHRANGE;
|
---|
112 | k++)
|
---|
113 | {
|
---|
114 | for (m=BKT_DOWNHASH(r->extents.y1, (int)mural->height);
|
---|
115 | m<=BKT_UPHASH(r->extents.y2, (int)mural->height) &&
|
---|
116 | m < HASHRANGE;
|
---|
117 | m++)
|
---|
118 | {
|
---|
119 | if ( bucketInfo->rhash[m][k] == NULL ||
|
---|
120 | (bucketInfo->rhash[m][k]->extents.x1 > r->extents.x1 &&
|
---|
121 | bucketInfo->rhash[m][k]->extents.y1 > r->extents.y1))
|
---|
122 | {
|
---|
123 | bucketInfo->rhash[m][k] = r;
|
---|
124 | }
|
---|
125 | }
|
---|
126 | }
|
---|
127 | }
|
---|
128 |
|
---|
129 | /* Initialize links */
|
---|
130 | for (i=0; i<r_len; i++)
|
---|
131 | {
|
---|
132 | BucketRegion *r = &bucketInfo->rlist[i];
|
---|
133 | r->right = NULL;
|
---|
134 | r->up = NULL;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /* Build links */
|
---|
138 | for (i=0; i<r_len; i++)
|
---|
139 | {
|
---|
140 | BucketRegion *r = &bucketInfo->rlist[i];
|
---|
141 | for (j=0; j<r_len; j++)
|
---|
142 | {
|
---|
143 | BucketRegion *q = &bucketInfo->rlist[j];
|
---|
144 | if (r==q)
|
---|
145 | continue;
|
---|
146 |
|
---|
147 | /* Right Edge */
|
---|
148 | if (r->extents.x2 == q->extents.x1 &&
|
---|
149 | r->extents.y1 == q->extents.y1 &&
|
---|
150 | r->extents.y2 == q->extents.y2)
|
---|
151 | {
|
---|
152 | r->right = q;
|
---|
153 | }
|
---|
154 |
|
---|
155 | /* Upper Edge */
|
---|
156 | if (r->extents.y2 == q->extents.y1 &&
|
---|
157 | r->extents.x1 == q->extents.x1 &&
|
---|
158 | r->extents.x2 == q->extents.x2)
|
---|
159 | {
|
---|
160 | r->up = q;
|
---|
161 | }
|
---|
162 | }
|
---|
163 | }
|
---|
164 |
|
---|
165 | mural->bucketInfo = bucketInfo;
|
---|
166 | return GL_TRUE;
|
---|
167 | }
|
---|
168 |
|
---|
169 |
|
---|
170 | /*
|
---|
171 | * Check if the tiles are the same size. If so, initialize hash-based
|
---|
172 | * bucketing.
|
---|
173 | */
|
---|
174 | GLboolean
|
---|
175 | crServerInitializeBucketing(CRMuralInfo *mural)
|
---|
176 | {
|
---|
177 | int optTileWidth = 0, optTileHeight = 0;
|
---|
178 | int i;
|
---|
179 |
|
---|
180 | for (i = 0; i < mural->numExtents; i++)
|
---|
181 | {
|
---|
182 | const int w = mural->extents[i].imagewindow.x2 -
|
---|
183 | mural->extents[i].imagewindow.x1;
|
---|
184 | const int h = mural->extents[i].imagewindow.y2 -
|
---|
185 | mural->extents[i].imagewindow.y1;
|
---|
186 |
|
---|
187 | if (optTileWidth == 0 && optTileHeight == 0) {
|
---|
188 | /* First tile */
|
---|
189 | optTileWidth = w;
|
---|
190 | optTileHeight = h;
|
---|
191 | }
|
---|
192 | else
|
---|
193 | {
|
---|
194 | /* Subsequent tile - make sure it's the same size as first and
|
---|
195 | * falls on the expected x/y location.
|
---|
196 | */
|
---|
197 | if (w != optTileWidth || h != optTileHeight) {
|
---|
198 | crWarning("Tile %d, %d .. %d, %d is not the right size!",
|
---|
199 | mural->extents[i].imagewindow.x1, mural->extents[i].imagewindow.y1,
|
---|
200 | mural->extents[i].imagewindow.x2, mural->extents[i].imagewindow.y2);
|
---|
201 | crWarning("All tiles must be same size with optimize_bucket.");
|
---|
202 | crWarning("Turning off optimize_bucket for this mural.");
|
---|
203 | return GL_FALSE;
|
---|
204 | }
|
---|
205 | else if ((mural->extents[i].imagewindow.x1 % optTileWidth) != 0 ||
|
---|
206 | (mural->extents[i].imagewindow.x2 % optTileWidth) != 0 ||
|
---|
207 | (mural->extents[i].imagewindow.y1 % optTileHeight) != 0 ||
|
---|
208 | (mural->extents[i].imagewindow.y2 % optTileHeight) != 0)
|
---|
209 | {
|
---|
210 | crWarning("Tile %d, %d .. %d, %d is not positioned correctly "
|
---|
211 | "to use optimize_bucket.",
|
---|
212 | mural->extents[i].imagewindow.x1, mural->extents[i].imagewindow.y1,
|
---|
213 | mural->extents[i].imagewindow.x2, mural->extents[i].imagewindow.y2);
|
---|
214 | crWarning("Turning off optimize_bucket for this mural.");
|
---|
215 | return GL_FALSE;
|
---|
216 | }
|
---|
217 | }
|
---|
218 | }
|
---|
219 |
|
---|
220 | return fillBucketingHash(mural);
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 | /**
|
---|
225 | * Process a crBoundsInfoCR message/function. This is a bounding box
|
---|
226 | * followed by a payload of arbitrary Chromium rendering commands.
|
---|
227 | * The tilesort SPU will send this.
|
---|
228 | * Note: the bounding box is in mural pixel coordinates (y=0=bottom)
|
---|
229 | */
|
---|
230 | void SERVER_DISPATCH_APIENTRY
|
---|
231 | crServerDispatchBoundsInfoCR( const CRrecti *bounds, const GLbyte *payload,
|
---|
232 | GLint len, GLint num_opcodes )
|
---|
233 | {
|
---|
234 | CRMuralInfo *mural = cr_server.curClient->currentMural;
|
---|
235 | char *data_ptr = (char*)(payload + ((num_opcodes + 3 ) & ~0x03));
|
---|
236 | unsigned int bx, by;
|
---|
237 |
|
---|
238 | /* Save current unpacker state */
|
---|
239 | crUnpackPush();
|
---|
240 |
|
---|
241 | /* pass bounds info to first SPU */
|
---|
242 | {
|
---|
243 | /* bias bounds to extent/window coords */
|
---|
244 | CRrecti bounds2;
|
---|
245 | const int dx = mural->extents[0].imagewindow.x1;
|
---|
246 | const int dy = mural->extents[0].imagewindow.y1;
|
---|
247 | if (bounds->x1 == -CR_MAXINT) {
|
---|
248 | /* "infinite" bounds: convert to full image bounds */
|
---|
249 | bounds2.x1 = 0;
|
---|
250 | bounds2.y1 = 0;
|
---|
251 | bounds2.x2 = mural->extents[0].imagewindow.x2 - dx; /* width */
|
---|
252 | bounds2.y2 = mural->extents[0].imagewindow.y2 - dy; /* height */
|
---|
253 | }
|
---|
254 | else {
|
---|
255 | bounds2.x1 = bounds->x1 - dx;
|
---|
256 | bounds2.y1 = bounds->y1 - dy;
|
---|
257 | bounds2.x2 = bounds->x2 - dx;
|
---|
258 | bounds2.y2 = bounds->y2 - dy;
|
---|
259 | }
|
---|
260 | cr_server.head_spu->dispatch_table.BoundsInfoCR(&bounds2, NULL, 0, 0);
|
---|
261 | }
|
---|
262 |
|
---|
263 | if (!mural->viewportValidated) {
|
---|
264 | crServerComputeViewportBounds(&(cr_server.curClient->currentCtx->viewport),
|
---|
265 | mural);
|
---|
266 | }
|
---|
267 |
|
---|
268 | bx = BKT_DOWNHASH(bounds->x1, mural->width);
|
---|
269 | by = BKT_DOWNHASH(bounds->y1, mural->height);
|
---|
270 |
|
---|
271 | /* Check for out of bounds, and optimizeBucket to enable */
|
---|
272 | if (mural->optimizeBucket && (bx <= HASHRANGE) && (by <= HASHRANGE))
|
---|
273 | {
|
---|
274 | const struct BucketingInfo *bucketInfo = mural->bucketInfo;
|
---|
275 | const BucketRegion *r;
|
---|
276 | const BucketRegion *p;
|
---|
277 |
|
---|
278 | CRASSERT(bucketInfo);
|
---|
279 |
|
---|
280 | for (r = bucketInfo->rhash[by][bx]; r && bounds->y2 >= r->extents.y1;
|
---|
281 | r = r->up)
|
---|
282 | {
|
---|
283 | for (p=r; p && bounds->x2 >= p->extents.x1; p = p->right)
|
---|
284 | {
|
---|
285 | if ( p->id != (unsigned int) -1 &&
|
---|
286 | bounds->x1 < p->extents.x2 &&
|
---|
287 | bounds->y1 < p->extents.y2 &&
|
---|
288 | bounds->y2 >= p->extents.y1 )
|
---|
289 | {
|
---|
290 | mural->curExtent = p->id;
|
---|
291 | if (cr_server.run_queue->client->currentCtx) {
|
---|
292 | crServerSetOutputBounds( mural, mural->curExtent );
|
---|
293 | }
|
---|
294 | crUnpack( data_ptr, data_ptr-1, num_opcodes, &(cr_server.dispatch) );
|
---|
295 | }
|
---|
296 | }
|
---|
297 | }
|
---|
298 | }
|
---|
299 | else
|
---|
300 | {
|
---|
301 | /* non-optimized bucketing - unpack/render for each tile/extent */
|
---|
302 | int i;
|
---|
303 | for ( i = 0; i < mural->numExtents; i++ )
|
---|
304 | {
|
---|
305 | CRExtent *extent = &mural->extents[i];
|
---|
306 |
|
---|
307 | if (cr_server.localTileSpec ||
|
---|
308 | (extent->imagewindow.x2 > bounds->x1 &&
|
---|
309 | extent->imagewindow.x1 < bounds->x2 &&
|
---|
310 | extent->imagewindow.y2 > bounds->y1 &&
|
---|
311 | extent->imagewindow.y1 < bounds->y2))
|
---|
312 | {
|
---|
313 | mural->curExtent = i;
|
---|
314 | if (cr_server.run_queue->client->currentCtx) {
|
---|
315 | crServerSetOutputBounds( mural, i );
|
---|
316 | }
|
---|
317 | crUnpack( data_ptr, data_ptr-1, num_opcodes, &(cr_server.dispatch) );
|
---|
318 | }
|
---|
319 | }
|
---|
320 | }
|
---|
321 |
|
---|
322 | /* Restore previous unpacker state */
|
---|
323 | crUnpackPop();
|
---|
324 | }
|
---|