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