Remove CVS keywords.
[mesa.git] / src / mesa / drivers / dri / gamma / gamma_texmem.c
1
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #include "glheader.h"
6 #include "colormac.h"
7 #include "macros.h"
8 #include "mtypes.h"
9 #include "simple_list.h"
10 #include "enums.h"
11
12 #include "mm.h"
13 #include "glint_dri.h"
14 #include "gamma_context.h"
15 #include "gamma_lock.h"
16
17 void gammaDestroyTexObj(gammaContextPtr gmesa, gammaTextureObjectPtr t)
18 {
19 if (!t) return;
20
21 /* This is sad - need to sync *in case* we upload a texture
22 * to this newly free memory...
23 */
24 if (t->MemBlock) {
25 mmFreeMem(t->MemBlock);
26 t->MemBlock = 0;
27
28 if (gmesa && t->age > gmesa->dirtyAge)
29 gmesa->dirtyAge = t->age;
30 }
31
32 if (t->globj)
33 t->globj->DriverData = 0;
34
35 if (gmesa) {
36 if (gmesa->CurrentTexObj[0] == t) {
37 gmesa->CurrentTexObj[0] = 0;
38 gmesa->dirty &= ~GAMMA_UPLOAD_TEX0;
39 }
40
41 #if 0
42 if (gmesa->CurrentTexObj[1] == t) {
43 gmesa->CurrentTexObj[1] = 0;
44 gmesa->dirty &= ~GAMMA_UPLOAD_TEX1;
45 }
46 #endif
47 }
48
49 remove_from_list(t);
50 free(t);
51 }
52
53
54 void gammaSwapOutTexObj(gammaContextPtr gmesa, gammaTextureObjectPtr t)
55 {
56 /* fprintf(stderr, "%s\n", __FUNCTION__); */
57
58 if (t->MemBlock) {
59 mmFreeMem(t->MemBlock);
60 t->MemBlock = 0;
61
62 if (t->age > gmesa->dirtyAge)
63 gmesa->dirtyAge = t->age;
64 }
65
66 t->dirty_images = ~0;
67 move_to_tail(&(gmesa->SwappedOut), t);
68 }
69
70
71
72 /* Upload an image from mesa's internal copy.
73 */
74 static void gammaUploadTexLevel( gammaContextPtr gmesa, gammaTextureObjectPtr t, int level )
75 {
76 const struct gl_texture_image *image = t->image[level].image;
77 int i,j;
78 int l2d;
79 #if 0
80 int offset = 0;
81 #endif
82 int words, depthLog2;
83
84 /* fprintf(stderr, "%s\n", __FUNCTION__); */
85
86 l2d = 5; /* 32bits per texel == 1<<5 */
87
88 if (level == 0) {
89 t->TextureAddressMode &= ~(TAM_WidthMask | TAM_HeightMask);
90 t->TextureAddressMode |= (image->WidthLog2 << 9) |
91 (image->HeightLog2 << 13);
92 t->TextureReadMode &= ~(TRM_WidthMask | TRM_HeightMask |
93 TRM_DepthMask | TRM_Border |
94 TRM_Patch);
95 t->TextureReadMode |= (image->WidthLog2 << 1) |
96 (image->HeightLog2 << 5) |
97 (l2d << 9);
98 t->TextureFormat &= ~(TF_CompnentsMask | TF_OneCompFmt_Mask);
99 }
100
101 t->TextureBaseAddr[level] = /* ??? */
102 (unsigned long)(t->image[level].offset + t->BufAddr) << 5;
103
104 CALC_LOG2(depthLog2, 1<<l2d);
105 words = (image->Width * image->Height) >> (5-depthLog2);
106
107 CHECK_DMA_BUFFER(gmesa, 3);
108 WRITE(gmesa->buf, LBWindowBase, t->TextureBaseAddr[level] >> 5);
109 WRITE(gmesa->buf, TextureCacheControl, (TCC_Enable | TCC_Invalidate));
110 WRITE(gmesa->buf, WaitForCompletion, 0);
111 FLUSH_DMA_BUFFER(gmesa);
112
113 switch (t->image[level].internalFormat) {
114 case GL_RGB:
115 case 3:
116 {
117 GLubyte *src = (GLubyte *)image->Data;
118
119 if (level == 0)
120 t->TextureFormat |= TF_Compnents_3;
121
122 #if 0 /* This is the texture download code we SHOULD be using */
123 /* In the routines below, but this causes an DMA overrun - WHY ? */
124 while (offset < words) {
125 int count = gmesa->bufSize;
126 int i;
127 count -= 3;
128 if (count > words-offset) count = words-offset;
129
130 gmesa->buf->i = GlintTextureDownloadOffsetTag;
131 gmesa->buf++;
132 gmesa->buf->i = offset;
133 gmesa->buf++;
134 gmesa->buf->i = (GlintTextureDataTag | ((count-1) << 16));
135 gmesa->buf++;
136
137 for (i = 0; i < count; i++) {
138 gmesa->buf->i = PACK_COLOR_565(src[0],src[1],src[2]);
139 gmesa->buf++;
140 src += 3;
141 }
142
143 gmesa->bufCount = count+3; /* texture data + 3 values */
144 offset += count;
145
146 FLUSH_DMA_BUFFER(gmesa);
147 }
148 #else
149 /* The UGLY way, and SLOW !, but the above sometimes causes
150 * a DMA overrun error ??? FIXME ! */
151
152 CHECK_DMA_BUFFER(gmesa, 1);
153 WRITE(gmesa->buf, TextureDownloadOffset, 0);
154 for (i = 0; i < words; i++) {
155 unsigned int data;
156 data = PACK_COLOR_565(src[0],src[1],src[2]);
157 CHECK_DMA_BUFFER(gmesa, 1);
158 WRITE(gmesa->buf, TextureData, data);
159 src += 3;
160 }
161 FLUSH_DMA_BUFFER(gmesa);
162 #endif
163 }
164 break;
165
166 case GL_RGBA:
167 case 4:
168 {
169 GLubyte *src = (GLubyte *)image->Data;
170
171 if (level == 0)
172 t->TextureFormat |= TF_Compnents_4;
173
174 /* The UGLY way, and SLOW !, but the above sometimes causes
175 * a DMA overrun error ??? FIXME ! */
176 CHECK_DMA_BUFFER(gmesa, 1);
177 WRITE(gmesa->buf, TextureDownloadOffset, 0);
178 for (i = 0; i < words; i++) {
179 unsigned int data;
180 data = PACK_COLOR_8888(src[0],src[1],src[2],src[3]);
181 CHECK_DMA_BUFFER(gmesa, 1);
182 WRITE(gmesa->buf, TextureData, data);
183 src += 4;
184 }
185 FLUSH_DMA_BUFFER(gmesa);
186 }
187 break;
188
189 case GL_LUMINANCE:
190 {
191 GLubyte *src = (GLubyte *)image->Data;
192
193 if (level == 0)
194 t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Lum;
195
196 /* The UGLY way, and SLOW !, but the above sometimes causes
197 * a DMA overrun error ??? FIXME ! */
198 CHECK_DMA_BUFFER(gmesa, 1);
199 WRITE(gmesa->buf, TextureDownloadOffset, 0);
200 for (i = 0; i < words; i++) {
201 unsigned int data;
202 data = PACK_COLOR_888(src[0],src[0],src[0]);
203 CHECK_DMA_BUFFER(gmesa, 1);
204 WRITE(gmesa->buf, TextureData, data);
205 src ++;
206 }
207 FLUSH_DMA_BUFFER(gmesa);
208 }
209 break;
210
211 case GL_INTENSITY:
212 {
213 GLubyte *src = (GLubyte *)image->Data;
214
215 if (level == 0)
216 t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Intensity;
217
218 /* The UGLY way, and SLOW !, but the above sometimes causes
219 * a DMA overrun error ??? FIXME ! */
220 CHECK_DMA_BUFFER(gmesa, 1);
221 WRITE(gmesa->buf, TextureDownloadOffset, 0);
222 for (i = 0; i < words; i++) {
223 unsigned int data;
224 data = PACK_COLOR_8888(src[0],src[0],src[0],src[0]);
225 CHECK_DMA_BUFFER(gmesa, 1);
226 WRITE(gmesa->buf, TextureData, data);
227 src ++;
228 }
229 FLUSH_DMA_BUFFER(gmesa);
230 }
231 break;
232
233 case GL_LUMINANCE_ALPHA:
234 {
235 GLubyte *src = (GLubyte *)image->Data;
236
237 if (level == 0)
238 t->TextureFormat |= TF_Compnents_2;
239
240 /* The UGLY way, and SLOW !, but the above sometimes causes
241 * a DMA overrun error ??? FIXME ! */
242 CHECK_DMA_BUFFER(gmesa, 1);
243 WRITE(gmesa->buf, TextureDownloadOffset, 0);
244 for (i = 0; i < words; i++) {
245 unsigned int data;
246 data = PACK_COLOR_8888(src[0],src[0],src[0],src[1]);
247 CHECK_DMA_BUFFER(gmesa, 1);
248 WRITE(gmesa->buf, TextureData, data);
249 src += 2;
250 }
251 FLUSH_DMA_BUFFER(gmesa);
252 }
253 break;
254
255 case GL_ALPHA:
256 {
257 GLubyte *src = (GLubyte *)image->Data;
258
259 if (level == 0)
260 t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Alpha;
261
262 /* The UGLY way, and SLOW !, but the above sometimes causes
263 * a DMA overrun error ??? FIXME ! */
264 CHECK_DMA_BUFFER(gmesa, 1);
265 WRITE(gmesa->buf, TextureDownloadOffset, 0);
266 for (i = 0; i < words; i++) {
267 unsigned int data;
268 data = PACK_COLOR_8888(255,255,255,src[0]);
269 CHECK_DMA_BUFFER(gmesa, 1);
270 WRITE(gmesa->buf, TextureData, data);
271 src += 1;
272 }
273 FLUSH_DMA_BUFFER(gmesa);
274 }
275 break;
276
277 /* TODO: Translate color indices *now*:
278 */
279 case GL_COLOR_INDEX:
280 {
281 GLubyte *dst = (GLubyte *)(t->BufAddr + t->image[level].offset);
282 GLubyte *src = (GLubyte *)image->Data;
283
284 for (j = 0 ; j < image->Height ; j++, dst += t->Pitch) {
285 for (i = 0 ; i < image->Width ; i++) {
286 dst[i] = src[0];
287 src += 1;
288 }
289 }
290 }
291 break;
292
293 default:
294 fprintf(stderr, "Not supported texture format %s\n",
295 _mesa_lookup_enum_by_nr(image->Format));
296 }
297
298 CHECK_DMA_BUFFER(gmesa, 2);
299 WRITE(gmesa->buf, WaitForCompletion, 0);
300 WRITE(gmesa->buf, LBWindowBase, gmesa->LBWindowBase);
301 }
302
303 void gammaPrintLocalLRU( gammaContextPtr gmesa )
304 {
305 gammaTextureObjectPtr t;
306 int sz = 1 << (gmesa->gammaScreen->logTextureGranularity);
307
308 foreach( t, &gmesa->TexObjList ) {
309 if (!t->globj)
310 fprintf(stderr, "Placeholder %d at %x sz %x\n",
311 t->MemBlock->ofs / sz,
312 t->MemBlock->ofs,
313 t->MemBlock->size);
314 else
315 fprintf(stderr, "Texture at %x sz %x\n",
316 t->MemBlock->ofs,
317 t->MemBlock->size);
318
319 }
320 }
321
322 void gammaPrintGlobalLRU( gammaContextPtr gmesa )
323 {
324 int i, j;
325 GAMMATextureRegionPtr list = gmesa->sarea->texList;
326
327 for (i = 0, j = GAMMA_NR_TEX_REGIONS ; i < GAMMA_NR_TEX_REGIONS ; i++) {
328 fprintf(stderr, "list[%d] age %d next %d prev %d\n",
329 j, list[j].age, list[j].next, list[j].prev);
330 j = list[j].next;
331 if (j == GAMMA_NR_TEX_REGIONS) break;
332 }
333
334 if (j != GAMMA_NR_TEX_REGIONS)
335 fprintf(stderr, "Loop detected in global LRU\n");
336 }
337
338
339 void gammaResetGlobalLRU( gammaContextPtr gmesa )
340 {
341 GAMMATextureRegionPtr list = gmesa->sarea->texList;
342 int sz = 1 << gmesa->gammaScreen->logTextureGranularity;
343 int i;
344
345 /* (Re)initialize the global circular LRU list. The last element
346 * in the array (GAMMA_NR_TEX_REGIONS) is the sentinal. Keeping it
347 * at the end of the array allows it to be addressed rationally
348 * when looking up objects at a particular location in texture
349 * memory.
350 */
351 for (i = 0 ; (i+1) * sz <= gmesa->gammaScreen->textureSize ; i++) {
352 list[i].prev = i-1;
353 list[i].next = i+1;
354 list[i].age = 0;
355 }
356
357 i--;
358 list[0].prev = GAMMA_NR_TEX_REGIONS;
359 list[i].prev = i-1;
360 list[i].next = GAMMA_NR_TEX_REGIONS;
361 list[GAMMA_NR_TEX_REGIONS].prev = i;
362 list[GAMMA_NR_TEX_REGIONS].next = 0;
363 gmesa->sarea->texAge = 0;
364 }
365
366
367 void gammaUpdateTexLRU( gammaContextPtr gmesa, gammaTextureObjectPtr t )
368 {
369 int i;
370 int logsz = gmesa->gammaScreen->logTextureGranularity;
371 int start = t->MemBlock->ofs >> logsz;
372 int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz;
373 GAMMATextureRegionPtr list = gmesa->sarea->texList;
374
375 gmesa->texAge = ++gmesa->sarea->texAge;
376
377 /* Update our local LRU
378 */
379 move_to_head( &(gmesa->TexObjList), t );
380
381 /* Update the global LRU
382 */
383 for (i = start ; i <= end ; i++) {
384
385 list[i].in_use = 1;
386 list[i].age = gmesa->texAge;
387
388 /* remove_from_list(i)
389 */
390 list[(unsigned)list[i].next].prev = list[i].prev;
391 list[(unsigned)list[i].prev].next = list[i].next;
392
393 /* insert_at_head(list, i)
394 */
395 list[i].prev = GAMMA_NR_TEX_REGIONS;
396 list[i].next = list[GAMMA_NR_TEX_REGIONS].next;
397 list[(unsigned)list[GAMMA_NR_TEX_REGIONS].next].prev = i;
398 list[GAMMA_NR_TEX_REGIONS].next = i;
399 }
400 }
401
402
403 /* Called for every shared texture region which has increased in age
404 * since we last held the lock.
405 *
406 * Figures out which of our textures have been ejected by other clients,
407 * and pushes a placeholder texture onto the LRU list to represent
408 * the other client's textures.
409 */
410 void gammaTexturesGone( gammaContextPtr gmesa,
411 GLuint offset,
412 GLuint size,
413 GLuint in_use )
414 {
415 gammaTextureObjectPtr t, tmp;
416
417 foreach_s ( t, tmp, &gmesa->TexObjList ) {
418
419 if (t->MemBlock->ofs >= offset + size ||
420 t->MemBlock->ofs + t->MemBlock->size <= offset)
421 continue;
422
423 /* It overlaps - kick it off. Need to hold onto the currently bound
424 * objects, however.
425 */
426 gammaSwapOutTexObj( gmesa, t );
427 }
428
429 if (in_use) {
430 t = (gammaTextureObjectPtr) calloc(1,sizeof(*t));
431 if (!t) return;
432
433 t->MemBlock = mmAllocMem( gmesa->texHeap, size, 0, offset);
434 insert_at_head( &gmesa->TexObjList, t );
435 }
436
437 /* Reload any lost textures referenced by current vertex buffer.
438 */
439 #if 0
440 if (gmesa->vertex_buffer) {
441 int i, j;
442
443 fprintf(stderr, "\n\nreload tex\n");
444
445 for (i = 0 ; i < gmesa->statenr ; i++) {
446 for (j = 0 ; j < 2 ; j++) {
447 gammaTextureObjectPtr t = gmesa->state_tex[j][i];
448 if (t) {
449 if (t->MemBlock == 0)
450 gammaUploadTexImages( gmesa, t );
451 }
452 }
453 }
454
455 /* Hard to do this with the lock held:
456 */
457 /* GAMMA_FIREVERTICES( gmesa ); */
458 }
459 #endif
460 }
461
462
463
464
465
466 /* This is called with the lock held. May have to eject our own and/or
467 * other client's texture objects to make room for the upload.
468 */
469 void gammaUploadTexImages( gammaContextPtr gmesa, gammaTextureObjectPtr t )
470 {
471 int i;
472 int ofs;
473 int numLevels;
474
475 /* /fprintf(stderr, "%s\n", __FUNCTION__); */
476 #if 0
477 LOCK_HARDWARE( gmesa );
478 #endif
479
480 /* Do we need to eject LRU texture objects?
481 */
482 if (!t->MemBlock) {
483 while (1)
484 {
485 t->MemBlock = mmAllocMem( gmesa->texHeap, t->totalSize, 12, 0 );
486 if (t->MemBlock)
487 break;
488
489 if (gmesa->TexObjList.prev == gmesa->CurrentTexObj[0] ||
490 gmesa->TexObjList.prev == gmesa->CurrentTexObj[1]) {
491 fprintf(stderr, "Hit bound texture in upload\n");
492 gammaPrintLocalLRU( gmesa );
493 return;
494 }
495
496 if (gmesa->TexObjList.prev == &(gmesa->TexObjList)) {
497 fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize);
498 mmDumpMemInfo( gmesa->texHeap );
499 return;
500 }
501
502 gammaSwapOutTexObj( gmesa, gmesa->TexObjList.prev );
503 }
504
505 ofs = t->MemBlock->ofs;
506 t->BufAddr = (char *)(unsigned long)(gmesa->LBWindowBase + ofs); /* ??? */
507
508 if (t == gmesa->CurrentTexObj[0])
509 gmesa->dirty |= GAMMA_UPLOAD_TEX0;
510
511 #if 0
512 if (t == gmesa->CurrentTexObj[1])
513 gmesa->dirty |= GAMMA_UPLOAD_TEX1;
514 #endif
515
516 gammaUpdateTexLRU( gmesa, t );
517 }
518
519 #if 0
520 if (gmesa->dirtyAge >= GET_DISPATCH_AGE(gmesa))
521 gammaWaitAgeLocked( gmesa, gmesa->dirtyAge );
522 #endif
523
524 numLevels = t->lastLevel - t->firstLevel + 1;
525 for (i = 0 ; i < numLevels ; i++)
526 if (t->dirty_images & (1<<i))
527 gammaUploadTexLevel( gmesa, t, i );
528
529 t->dirty_images = 0;
530
531 #if 0
532 UNLOCK_HARDWARE( gmesa );
533 #endif
534 }