Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / s3v / s3v_texmem.c
1 /*
2 * Author: Max Lingua <sunmax@libero.it>
3 */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7
8 #include "main/glheader.h"
9 #include "main/macros.h"
10 #include "main/mtypes.h"
11 #include "main/simple_list.h"
12 #include "main/enums.h"
13
14 #include "main/mm.h"
15 #include "s3v_context.h"
16 #include "s3v_lock.h"
17 #include "s3v_tex.h"
18
19 void s3vSwapOutTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t);
20 void s3vUpdateTexLRU( s3vContextPtr vmesa, s3vTextureObjectPtr t );
21
22
23 void s3vDestroyTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t)
24 {
25 #if TEX_DEBUG_ON
26 static unsigned int times=0;
27 DEBUG_TEX(("*** s3vDestroyTexObj: #%i ***\n", ++times));
28 #endif
29
30 if (!t) return;
31
32 /* FIXME: useful? */
33 #if _TEXFLUSH
34 if (vmesa)
35 DMAFLUSH();
36 #endif
37
38 /* This is sad - need to sync *in case* we upload a texture
39 * to this newly free memory...
40 */
41 if (t->MemBlock) {
42 mmFreeMem(t->MemBlock);
43 t->MemBlock = 0;
44
45 if (vmesa && t->age > vmesa->dirtyAge)
46 vmesa->dirtyAge = t->age;
47 }
48
49 if (t->globj)
50 t->globj->DriverData = NULL;
51
52 if (vmesa) {
53 if (vmesa->CurrentTexObj[0] == t) {
54 vmesa->CurrentTexObj[0] = 0;
55 vmesa->dirty &= ~S3V_UPLOAD_TEX0;
56 }
57
58 #if 0
59 if (vmesa->CurrentTexObj[1] == t) {
60 vmesa->CurrentTexObj[1] = 0;
61 vmesa->dirty &= ~S3V_UPLOAD_TEX1;
62 }
63 #endif
64 }
65
66 remove_from_list(t);
67 FREE(t);
68 }
69
70
71 void s3vSwapOutTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t)
72 {
73 /* int i; */
74 #if TEX_DEBUG_ON
75 static unsigned int times=0;
76 DEBUG_TEX(("*** s3vSwapOutTexObj: #%i ***\n", ++times));
77 #endif
78
79 if (t->MemBlock) {
80
81 mmFreeMem(t->MemBlock);
82 t->MemBlock = 0;
83
84 if (t->age > vmesa->dirtyAge)
85 vmesa->dirtyAge = t->age;
86
87 t->dirty_images = ~0;
88 move_to_tail(&(vmesa->SwappedOut), t);
89 }
90 }
91
92
93 /* Upload an image from mesa's internal copy.
94 */
95
96 static void s3vUploadTexLevel( s3vContextPtr vmesa, s3vTextureObjectPtr t,
97 int level )
98 {
99 __DRIscreenPrivate *sPriv = vmesa->driScreen;
100 const struct gl_texture_image *image = t->image[level].image;
101 int i,j;
102 int l2d;
103 /* int offset = 0; */
104 int words;
105 GLuint* dest;
106 #if TEX_DEBUG_ON
107 static unsigned int times=0;
108 #endif
109 if ( !image ) return;
110 if (image->Data == 0) return;
111
112 DEBUG_TEX(("*** s3vUploadTexLevel: #%i ***\n", ++times));
113 DEBUG_TEX(("level = %i\n", level));
114
115 l2d = 5; /* 32bits per texel == 1<<5 */
116 /*
117 if (level == 0)
118 ;
119 */
120 DEBUG_TEX(("t->image[%i].offset = 0x%x\n",
121 level, t->image[level].offset));
122
123 t->TextureBaseAddr[level] = (GLuint)(t->BufAddr + t->image[level].offset
124 + _TEXALIGN) & (GLuint)(~_TEXALIGN);
125 dest = (GLuint*)(sPriv->pFB + t->TextureBaseAddr[level]);
126
127 DEBUG_TEX(("sPriv->pFB = 0x%x\n", sPriv->pFB));
128 DEBUG_TEX(("dest = 0x%x\n", dest));
129 DEBUG_TEX(("dest - sPriv->pFB = 0x%x\n", ((int)dest - (int)sPriv->pFB)));
130
131 /* NOTE: we implicitly suppose t->texelBytes == 2 */
132
133 words = (image->Width * image->Height) >> 1;
134
135 DEBUG_TEX(("\n\n"));
136
137 switch (t->image[level].internalFormat) {
138 case GL_RGB:
139 case 3:
140 {
141 GLubyte *src = (GLubyte *)image->Data;
142
143 DEBUG_TEX(("GL_RGB:\n"));
144 /*
145 if (level == 0)
146 ;
147 */
148 /* The UGLY way, and SLOW : use DMA FIXME ! */
149
150 for (i = 0; i < words; i++) {
151 unsigned int data;
152 /* data = PACK_COLOR_565(src[0],src[1],src[2]); */
153 data = S3VIRGEPACKCOLOR555(src[0],src[1],src[2],255)
154 |(S3VIRGEPACKCOLOR555(src[3],src[4],src[5],255)<<16);
155
156 *dest++ = data;
157 /* src += 3; */
158 src +=6;
159 }
160 }
161 break;
162
163 case GL_RGBA:
164 case 4:
165 {
166 GLubyte *src = (GLubyte *)image->Data;
167
168 DEBUG_TEX(("GL_RGBA:\n"));
169 /*
170 if (level == 0)
171 ;
172 */
173 for (i = 0; i < words; i++) {
174 unsigned int data;
175
176 /* data = PACK_COLOR_8888(src[0],src[1],src[2],src[3]); */
177 data = S3VIRGEPACKCOLOR4444(src[0], src[1],src[2], src[3])
178 | (S3VIRGEPACKCOLOR4444(src[4], src[5], src[6], src[7]) << 16);
179
180 *dest++ = data;
181 /* src += 4; */
182 src += 8;
183 }
184 }
185 break;
186
187 case GL_LUMINANCE:
188 {
189 GLubyte *src = (GLubyte *)image->Data;
190
191 DEBUG_TEX(("GL_LUMINANCE:\n"));
192 /*
193 if (level == 0)
194 ;
195 */
196 for (i = 0; i < words; i++) {
197 unsigned int data;
198
199 /* data = PACK_COLOR_888(src[0],src[0],src[0]); */
200 data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[0])
201 | (S3VIRGEPACKCOLOR4444(src[1],src[1],src[1],src[1]) << 16);
202
203 *dest++ = data;
204 /* src ++; */
205 src +=2;
206 }
207 }
208 break;
209
210 case GL_INTENSITY:
211 {
212 GLubyte *src = (GLubyte *)image->Data;
213
214 DEBUG_TEX(("GL_INTENSITY:\n"));
215 /*
216 if (level == 0)
217 ;
218 */
219 for (i = 0; i < words; i++) {
220 unsigned int data;
221
222 /* data = PACK_COLOR_8888(src[0],src[0],src[0],src[0]); */
223 data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[0])
224 | (S3VIRGEPACKCOLOR4444(src[1],src[1],src[1],src[1]) << 16);
225
226 *dest++ = data;
227 /* src ++; */
228 src += 2;
229 }
230 }
231 break;
232
233 case GL_LUMINANCE_ALPHA:
234 {
235 GLubyte *src = (GLubyte *)image->Data;
236
237 DEBUG_TEX(("GL_LUMINANCE_ALPHA:\n"));
238 /*
239 if (level == 0)
240 ;
241 */
242 for (i = 0; i < words; i++) {
243 unsigned int data;
244
245 /* data = PACK_COLOR_8888(src[0],src[0],src[0],src[1]); */
246 data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[1])
247 | (S3VIRGEPACKCOLOR4444(src[2],src[2],src[2],src[3]) << 16);
248
249 *dest++ = data;
250 /* src += 2; */
251 src += 4;
252 }
253 }
254 break;
255
256 case GL_ALPHA:
257 {
258 GLubyte *src = (GLubyte *)image->Data;
259
260 DEBUG_TEX(("GL_ALPHA:\n"));
261 /*
262 if (level == 0)
263 ;
264 */
265 for (i = 0; i < words; i++) {
266 unsigned int data;
267
268 /* data = PACK_COLOR_8888(255,255,255,src[0]); */
269 data = S3VIRGEPACKCOLOR4444(255,255,255,src[0])
270 | (S3VIRGEPACKCOLOR4444(255,255,255,src[1]) << 16);
271
272 *dest++ = data;
273 /* src += 1; */
274 src += 2;
275 }
276 }
277 break;
278
279 /* TODO: Translate color indices *now*:
280 */
281 case GL_COLOR_INDEX:
282 {
283
284 GLubyte *dst = (GLubyte *)(t->BufAddr + t->image[level].offset);
285 GLubyte *src = (GLubyte *)image->Data;
286
287 DEBUG_TEX(("GL_COLOR_INDEX:\n"));
288
289 for (j = 0 ; j < image->Height ; j++, dst += t->Pitch) {
290 for (i = 0 ; i < image->Width ; i++) {
291 dst[i] = src[0];
292 src += 1;
293 }
294 }
295 }
296 break;
297
298 default:
299 fprintf(stderr, "Not supported texture format %s\n",
300 _mesa_lookup_enum_by_nr(image->_BaseFormat));
301 }
302
303 DEBUG_TEX(("words = %i\n\n", words));
304 }
305
306 void s3vPrintLocalLRU( s3vContextPtr vmesa )
307 {
308 s3vTextureObjectPtr t;
309 int sz = 1 << (vmesa->s3vScreen->logTextureGranularity);
310
311 #if TEX_DEBUG_ON
312 static unsigned int times=0;
313 DEBUG_TEX(("*** s3vPrintLocalLRU: #%i ***\n", ++times));
314 #endif
315
316 foreach( t, &vmesa->TexObjList ) {
317 if (!t->globj)
318 fprintf(stderr, "Placeholder %d at %x sz %x\n",
319 t->MemBlock->ofs / sz,
320 t->MemBlock->ofs,
321 t->MemBlock->size);
322 else
323 fprintf(stderr, "Texture at %x sz %x\n",
324 t->MemBlock->ofs,
325 t->MemBlock->size);
326
327 }
328 }
329
330 void s3vPrintGlobalLRU( s3vContextPtr vmesa )
331 {
332 int i, j;
333 S3VTexRegionPtr list = vmesa->sarea->texList;
334 #if TEX_DEBUG_ON
335 static unsigned int times=0;
336 DEBUG_TEX(("*** s3vPrintGlobalLRU: #%i ***\n", ++times));
337 #endif
338
339 for (i = 0, j = S3V_NR_TEX_REGIONS ; i < S3V_NR_TEX_REGIONS ; i++) {
340 fprintf(stderr, "list[%d] age %d next %d prev %d\n",
341 j, list[j].age, list[j].next, list[j].prev);
342 j = list[j].next;
343 if (j == S3V_NR_TEX_REGIONS) break;
344 }
345
346 if (j != S3V_NR_TEX_REGIONS)
347 fprintf(stderr, "Loop detected in global LRU\n");
348 }
349
350
351 void s3vResetGlobalLRU( s3vContextPtr vmesa )
352 {
353 S3VTexRegionPtr list = vmesa->sarea->texList;
354 int sz = 1 << vmesa->s3vScreen->logTextureGranularity;
355 int i;
356
357 #if TEX_DEBUG_ON
358 static unsigned int times=0;
359 DEBUG_TEX(("*** s3vResetGlobalLRU: #%i ***\n", ++times));
360 #endif
361
362 /* (Re)initialize the global circular LRU list. The last element
363 * in the array (S3V_NR_TEX_REGIONS) is the sentinal. Keeping it
364 * at the end of the array allows it to be addressed rationally
365 * when looking up objects at a particular location in texture
366 * memory.
367 */
368 for (i = 0 ; (i+1) * sz <= vmesa->s3vScreen->textureSize ; i++) {
369 list[i].prev = i-1;
370 list[i].next = i+1;
371 list[i].age = 0;
372 }
373
374 i--;
375 list[0].prev = S3V_NR_TEX_REGIONS;
376 list[i].prev = i-1;
377 list[i].next = S3V_NR_TEX_REGIONS;
378 list[S3V_NR_TEX_REGIONS].prev = i;
379 list[S3V_NR_TEX_REGIONS].next = 0;
380 vmesa->sarea->texAge = 0;
381 }
382
383
384 void s3vUpdateTexLRU( s3vContextPtr vmesa, s3vTextureObjectPtr t )
385 {
386 /*
387 int i;
388 int logsz = vmesa->s3vScreen->logTextureGranularity;
389 int start = t->MemBlock->ofs >> logsz;
390 int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz;
391 S3VTexRegionPtr list = vmesa->sarea->texList;
392 */
393
394 #if TEX_DEBUG_ON
395 static unsigned int times=0;
396 DEBUG_TEX(("*** s3vUpdateTexLRU: #%i ***\n", ++times));
397 #endif
398
399 vmesa->texAge = ++vmesa->sarea->texAge;
400
401 /* Update our local LRU
402 */
403 move_to_head( &(vmesa->TexObjList), t );
404
405 /* Update the global LRU
406 */
407 #if 0
408 for (i = start ; i <= end ; i++) {
409
410 list[i].in_use = 1;
411 list[i].age = vmesa->texAge;
412
413 /* remove_from_list(i)
414 */
415 list[(unsigned)list[i].next].prev = list[i].prev;
416 list[(unsigned)list[i].prev].next = list[i].next;
417
418 /* insert_at_head(list, i)
419 */
420 list[i].prev = S3V_NR_TEX_REGIONS;
421 list[i].next = list[S3V_NR_TEX_REGIONS].next;
422 list[(unsigned)list[S3V_NR_TEX_REGIONS].next].prev = i;
423 list[S3V_NR_TEX_REGIONS].next = i;
424 }
425 #endif
426 }
427
428
429 /* Called for every shared texture region which has increased in age
430 * since we last held the lock.
431 *
432 * Figures out which of our textures have been ejected by other clients,
433 * and pushes a placeholder texture onto the LRU list to represent
434 * the other client's textures.
435 */
436 void s3vTexturesGone( s3vContextPtr vmesa,
437 GLuint offset,
438 GLuint size,
439 GLuint in_use )
440 {
441 s3vTextureObjectPtr t, tmp;
442 #if TEX_DEBUG_ON
443 static unsigned int times=0;
444 DEBUG_TEX(("*** s3vTexturesGone: #%i ***\n", ++times));
445 #endif
446
447 foreach_s ( t, tmp, &vmesa->TexObjList ) {
448
449 if (t->MemBlock->ofs >= offset + size ||
450 t->MemBlock->ofs + t->MemBlock->size <= offset)
451 continue;
452
453 /* It overlaps - kick it off. Need to hold onto the currently bound
454 * objects, however.
455 */
456 s3vSwapOutTexObj( vmesa, t );
457 }
458
459 if (in_use) {
460 t = (s3vTextureObjectPtr) calloc(1,sizeof(*t));
461 if (!t) return;
462
463 t->MemBlock = mmAllocMem( vmesa->texHeap, size, 0, offset);
464 insert_at_head( &vmesa->TexObjList, t );
465 }
466
467 /* Reload any lost textures referenced by current vertex buffer.
468 */
469 #if 0
470 if (vmesa->vertex_buffer) {
471 int i, j;
472
473 fprintf(stderr, "\n\nreload tex\n");
474
475 for (i = 0 ; i < vmesa->statenr ; i++) {
476 for (j = 0 ; j < 2 ; j++) {
477 s3vTextureObjectPtr t = vmesa->state_tex[j][i];
478 if (t) {
479 if (t->MemBlock == 0)
480 s3vUploadTexImages( vmesa, t );
481 }
482 }
483 }
484
485 /* Hard to do this with the lock held:
486 */
487 /* S3V_FIREVERTICES( vmesa ); */
488 }
489 #endif
490 }
491
492
493 /* This is called with the lock held. May have to eject our own and/or
494 * other client's texture objects to make room for the upload.
495 */
496 void s3vUploadTexImages( s3vContextPtr vmesa, s3vTextureObjectPtr t )
497 {
498 int i;
499 int ofs;
500 int numLevels;
501 #if TEX_DEBUG_ON
502 static unsigned int times=0;
503 static unsigned int try=0;
504
505 DEBUG_TEX(("*** s3vUploadTexImages: #%i ***\n", ++times));
506 DEBUG_TEX(("vmesa->texHeap = 0x%x; t->totalSize = %i\n",
507 (unsigned int)vmesa->texHeap, t->totalSize));
508 #endif
509
510 /* Do we need to eject LRU texture objects?
511 */
512 if (!t->MemBlock) {
513
514 while (1)
515 {
516 /* int try = 0; */
517 DEBUG_TEX(("trying to alloc mem for tex (try %i)\n", ++try));
518
519 t->MemBlock = mmAllocMem( vmesa->texHeap, t->totalSize, 12, 0 );
520
521 if (t->MemBlock)
522 break;
523
524 if (vmesa->TexObjList.prev == vmesa->CurrentTexObj[0]) {
525 /* || vmesa->TexObjList.prev == vmesa->CurrentTexObj[1]) {
526 fprintf(stderr, "Hit bound texture in upload\n");
527 s3vPrintLocalLRU( vmesa ); */
528 return;
529 }
530
531 if (vmesa->TexObjList.prev == &(vmesa->TexObjList)) {
532 /* fprintf(stderr, "Failed to upload texture, sz %d\n",
533 t->totalSize);
534 mmDumpMemInfo( vmesa->texHeap ); */
535 return;
536 }
537
538 DEBUG_TEX(("swapping out: %p\n", vmesa->TexObjList.prev));
539 s3vSwapOutTexObj( vmesa, vmesa->TexObjList.prev );
540 }
541
542 ofs = t->MemBlock->ofs;
543
544 t->BufAddr = vmesa->s3vScreen->texOffset + ofs;
545
546 DEBUG_TEX(("ofs = 0x%x\n", ofs));
547 DEBUG_TEX(("t->BufAddr = 0x%x\n", t->BufAddr));
548
549 /* FIXME: check if we need it */
550 #if 0
551 if (t == vmesa->CurrentTexObj[0]) {
552 vmesa->dirty |= S3V_UPLOAD_TEX0;
553 vmesa->restore_primitive = -1;
554 }
555 #endif
556
557 #if 0
558 if (t == vmesa->CurrentTexObj[1])
559 vmesa->dirty |= S3V_UPLOAD_TEX1;
560 #endif
561
562 s3vUpdateTexLRU( vmesa, t );
563 }
564
565 #if 0
566 if (vmesa->dirtyAge >= GET_DISPATCH_AGE(vmesa))
567 s3vWaitAgeLocked( vmesa, vmesa->dirtyAge );
568 #endif
569
570 #if _TEXLOCK
571 S3V_SIMPLE_FLUSH_LOCK(vmesa);
572 #endif
573 numLevels = t->lastLevel - t->firstLevel + 1;
574 for (i = 0 ; i < numLevels ; i++)
575 if (t->dirty_images & (1<<i))
576 s3vUploadTexLevel( vmesa, t, i );
577
578 t->dirty_images = 0;
579 #if _TEXLOCK
580 S3V_SIMPLE_UNLOCK(vmesa);
581 #endif
582 }