Fixed off by one errors in clipping.
[mesa.git] / src / mesa / drivers / dri / unichrome / via_texmem.c
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #include "glheader.h"
30 #include "macros.h"
31 #include "mtypes.h"
32 #include "simple_list.h"
33 #include "enums.h"
34 #include "texformat.h"
35
36 #include "mm.h"
37 #include "via_context.h"
38 #include "via_tex.h"
39 #include "via_state.h"
40 #include "via_ioctl.h"
41 #include "via_fb.h"
42 /*=* John Sheng [2003.5.31] agp tex *=*/
43 GLuint agpFullCount = 0;
44
45 void viaDestroyTexObj(viaContextPtr vmesa, viaTextureObjectPtr t)
46 {
47 #ifdef DEBUG
48 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
49 #endif
50 if (!t)
51 return;
52
53 /* This is sad - need to sync *in case* we upload a texture
54 * to this newly free memory...
55 */
56 if (t->bufAddr) {
57 via_free_texture(vmesa, t);
58
59 if (vmesa && t->age > vmesa->dirtyAge)
60 vmesa->dirtyAge = t->age;
61 }
62
63 if (t->globj)
64 t->globj->DriverData = 0;
65
66 if (vmesa) {
67 if (vmesa->CurrentTexObj[0] == t) {
68 vmesa->CurrentTexObj[0] = 0;
69 vmesa->dirty &= ~VIA_UPLOAD_TEX0;
70 }
71
72 if (vmesa->CurrentTexObj[1] == t) {
73 vmesa->CurrentTexObj[1] = 0;
74 vmesa->dirty &= ~VIA_UPLOAD_TEX1;
75 }
76 }
77
78 remove_from_list(t);
79 free(t);
80 #ifdef DEBUG
81 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
82 #endif
83 }
84
85 void viaSwapOutTexObj(viaContextPtr vmesa, viaTextureObjectPtr t)
86 {
87 #ifdef DEBUG
88 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
89 #endif
90 if (t->bufAddr) {
91 via_free_texture(vmesa, t);
92
93 if (t->age > vmesa->dirtyAge)
94 vmesa->dirtyAge = t->age;
95 }
96
97 t->dirtyImages = ~0;
98 move_to_tail(&(vmesa->SwappedOut), t);
99 #ifdef DEBUG
100 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
101 #endif
102 }
103
104 /* Upload an image from mesa's internal copy.
105 */
106 static void viaUploadTexLevel(viaTextureObjectPtr t, int level)
107 {
108 const struct gl_texture_image *image = t->image[level].image;
109 int i, j;
110 #ifdef DEBUG
111 if (VIA_DEBUG) {
112 fprintf(stderr, "%s - in\n", __FUNCTION__);
113 fprintf(stderr, "width = %d, height = %d \n", image->Width, image->Height);
114 }
115 #endif
116 switch (t->image[level].internalFormat) {
117 case GL_RGB:
118 {
119 if (image->TexFormat->MesaFormat == MESA_FORMAT_ARGB8888) {
120 GLuint *dst = (GLuint *)(t->bufAddr + t->image[level].offset);
121 GLuint *src = (GLuint *)image->Data;
122 #ifdef DEBUG
123 if (VIA_DEBUG) fprintf(stderr, "GL_RGB MESA_FORMAT_ARGB8888\n");
124 #endif
125 if (image->Width < 8) {
126 for (i = 0; i < image->Height ; i++) {
127 for (j = 0; j < image->Width ; j++) {
128 dst[j] = *src;
129 src++;
130 }
131 dst += 8;
132 }
133 }
134 else {
135 for (j = 0; j < image->Height * image->Width; j++) {
136 *dst = *src;
137 dst++;
138 src++;
139 }
140 }
141 /*memcpy(dst, src, image->Height * image->Width * sizeof(GLuint));*/
142 }
143 else {
144 GLushort *dst = (GLushort *)(t->bufAddr + t->image[level].offset);
145 GLushort *src = (GLushort *)image->Data;
146 #ifdef DEBUG
147 if (VIA_DEBUG) fprintf(stderr, "GL_RGB !MESA_FORMAT_ARGB8888\n");
148 #endif
149 if (image->Width < 16) {
150 for (i = 0; i < image->Height ; i++) {
151 for (j = 0; j < image->Width ; j++) {
152 dst[j] = *src;
153 src++;
154 }
155 dst += 16;
156 }
157 }
158 else {
159 for (j = 0; j < image->Height * image->Width; j++) {
160 *dst = *src;
161 dst++;
162 src++;
163 }
164 }
165 /*memcpy(dst, src, image->Height * image->Width * sizeof(GLushort));*/
166 }
167 }
168 break;
169
170 case GL_RGBA:
171 {
172 if (image->TexFormat->MesaFormat == MESA_FORMAT_ARGB4444) {
173
174 GLushort *dst = (GLushort *)(t->bufAddr + t->image[level].offset);
175 GLushort *src = (GLushort *)image->Data;
176 if (image->Width < 16) {
177 for (i = 0; i < image->Height ; i++) {
178 for (j = 0; j < image->Width ; j++) {
179 dst[j] = *src;
180 src++;
181 }
182 dst += 16;
183 }
184 }
185 else {
186 for (j = 0; j < image->Height * image->Width; j++) {
187 *dst = *src;
188 src++;
189 dst++;
190 }
191 }
192 /*memcpy(dst, src, image->Height * image->Width * sizeof(GLushort));*/
193 #ifdef DEBUG
194 if (VIA_DEBUG) fprintf(stderr, "GL_RGBA MESA_FORMAT_ARGB4444\n");
195 #endif
196 }
197 else if(image->TexFormat->MesaFormat == MESA_FORMAT_ARGB8888) {
198 GLuint *dst = (GLuint *)(t->bufAddr + t->image[level].offset);
199 GLuint *src = (GLuint *)image->Data;
200 #ifdef DEBUG
201 if (VIA_DEBUG) fprintf(stderr, "GL_RGBA !MESA_FORMAT_ARGB4444\n");
202 #endif
203 if (image->Width < 8) {
204 for (i = 0; i < image->Height ; i++) {
205 for (j = 0; j < image->Width ; j++) {
206 dst[j] = *src;
207 src++;
208 }
209 dst += 8;
210 }
211 }
212 else {
213 for (j = 0; j < image->Height * image->Width; j++) {
214 *dst = *src;
215 dst++;
216 src++;
217 }
218 }
219 /*memcpy(dst, src, image->Height * image->Width * sizeof(GLuint));*/
220 }
221 else if(image->TexFormat->MesaFormat == MESA_FORMAT_ARGB1555) {
222 GLushort *dst = (GLushort *)(t->bufAddr + t->image[level].offset);
223 GLushort *src = (GLushort *)image->Data;
224 if (image->Width < 16) {
225 for (i = 0; i < image->Height ; i++) {
226 for (j = 0; j < image->Width ; j++) {
227 dst[j] = *src;
228 src++;
229 }
230 dst += 16;
231 }
232 }
233 else {
234 for (j = 0; j < image->Height * image->Width; j++) {
235 *dst = *src;
236 src++;
237 dst++;
238 }
239 }
240 /*memcpy(dst, src, image->Height * image->Width * sizeof(GLushort));*/
241 #ifdef DEBUG
242 if (VIA_DEBUG) fprintf(stderr, "GL_RGBA MESA_FORMAT_ARGB1555\n");
243 #endif
244 }
245 }
246 break;
247
248 case GL_LUMINANCE:
249 {
250 GLubyte *dst = (GLubyte *)(t->bufAddr + t->image[level].offset);
251 GLubyte *src = (GLubyte *)image->Data;
252
253 for (j = 0; j < image->Height * image->Width; j++) {
254 *dst = *src;
255 dst++;
256 src++;
257 }
258 }
259 break;
260
261 case GL_INTENSITY:
262 {
263 GLubyte *dst = (GLubyte *)(t->bufAddr + t->image[level].offset);
264 GLubyte *src = (GLubyte *)image->Data;
265
266 for (j = 0; j < image->Height * image->Width; j++) {
267 *dst = *src;
268 dst++;
269 src++;
270 }
271 }
272 break;
273
274 case GL_LUMINANCE_ALPHA:
275 {
276 GLushort *dst = (GLushort *)(t->bufAddr + t->image[level].offset);
277 GLushort *src = (GLushort *)image->Data;
278
279 for (j = 0; j < image->Height * image->Width; j++) {
280 *dst = *src;
281 dst++;
282 src++;
283 }
284 }
285 break;
286
287 case GL_ALPHA:
288 {
289 GLubyte *dst = (GLubyte *)(t->bufAddr + t->image[level].offset);
290 GLubyte *src = (GLubyte *)image->Data;
291
292 for (j = 0; j < image->Height * image->Width; j++) {
293 *dst = *src;
294 dst++;
295 src++;
296 }
297 }
298 break;
299
300 /* TODO: Translate color indices *now*:
301 */
302 case GL_COLOR_INDEX:
303 {
304 GLubyte *dst = (GLubyte *)(t->bufAddr + t->image[level].offset);
305 GLubyte *src = (GLubyte *)image->Data;
306
307 for (j = 0; j < image->Height * image->Width; j++) {
308 *dst = *src;
309 dst++;
310 src++;
311 }
312 }
313 break;
314
315 default:;
316 #ifdef DEBUG
317 if (VIA_DEBUG) fprintf(stderr, "Not supported texture format %s\n",
318 _mesa_lookup_enum_by_nr(image->Format));
319 #endif
320 }
321 #ifdef DEBUG
322 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
323 #endif
324 }
325
326 void viaPrintLocalLRU(viaContextPtr vmesa)
327 {
328 viaTextureObjectPtr t;
329
330 foreach (t, &vmesa->TexObjList) {
331 if (!t->globj) {
332 #ifdef DEBUG
333 if (VIA_DEBUG) {
334 fprintf(stderr, "offset = %x, index = %x, size = %x\n",
335 t->texMem.offset,
336 t->texMem.index,
337 t->texMem.size);
338 }
339 else {
340 if (VIA_DEBUG) {
341 fprintf(stderr, "offset = %x, siez = %x\n",
342 t->texMem.offset,
343 t->texMem.size);
344 }
345 }
346 #endif
347 }
348 }
349 }
350
351 void viaPrintGlobalLRU(viaContextPtr vmesa)
352 {
353 int i, j;
354 drm_via_tex_region_t *list = vmesa->sarea->texList;
355
356 for (i = 0, j = VIA_NR_TEX_REGIONS; i < VIA_NR_TEX_REGIONS; i++) {
357 #ifdef DEBUG
358 if (VIA_DEBUG) fprintf(stderr, "list[%d] age %d next %d prev %d\n",
359 j, list[j].age, list[j].next, list[j].prev);
360 #endif
361 j = list[j].next;
362 if (j == VIA_NR_TEX_REGIONS) break;
363 }
364 #ifdef DEBUG
365 if (j != VIA_NR_TEX_REGIONS)
366 if (VIA_DEBUG) fprintf(stderr, "Loop detected in global LRU\n");
367 #endif
368 }
369
370 void viaResetGlobalLRU(viaContextPtr vmesa)
371 {
372 drm_via_tex_region_t *list = vmesa->sarea->texList;
373 int sz = 1 << vmesa->viaScreen->logTextureGranularity;
374 int i;
375
376 /* (Re)initialize the global circular LRU list. The last element
377 * in the array (VIA_NR_TEX_REGIONS) is the sentinal. Keeping it
378 * at the end of the array allows it to be addressed rationally
379 * when looking up objects at a particular location in texture
380 * memory.
381 */
382 for (i = 0; (i + 1) * sz <= vmesa->viaScreen->textureSize; i++) {
383 list[i].prev = i - 1;
384 list[i].next = i + 1;
385 list[i].age = 0;
386 }
387
388 i--;
389 list[0].prev = VIA_NR_TEX_REGIONS;
390 list[i].prev = i - 1;
391 list[i].next = VIA_NR_TEX_REGIONS;
392 list[VIA_NR_TEX_REGIONS].prev = i;
393 list[VIA_NR_TEX_REGIONS].next = 0;
394 vmesa->sarea->texAge = 0;
395 }
396
397 void viaUpdateTexLRU(viaContextPtr vmesa, viaTextureObjectPtr t)
398 {
399 vmesa->texAge = ++vmesa->sarea->texAge;
400 move_to_head(&(vmesa->TexObjList), t);
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 viaTexturesGone(viaContextPtr vmesa,
411 GLuint offset,
412 GLuint size,
413 GLuint inUse)
414 {
415 viaTextureObjectPtr t, tmp;
416 #ifdef DEBUG
417 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
418 #endif
419 foreach_s (t, tmp, &vmesa->TexObjList) {
420 viaSwapOutTexObj(vmesa, t);
421 }
422 #ifdef DEBUG
423 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
424 #endif
425 }
426
427 /* This is called with the lock held. May have to eject our own and/or
428 * other client's texture objects to make room for the upload.
429 */
430 void viaUploadTexImages(viaContextPtr vmesa, viaTextureObjectPtr t)
431 {
432 int i, j;
433 int numLevels;
434 #ifdef DEBUG
435 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
436 #endif
437 LOCK_HARDWARE(vmesa);
438
439 j = 0;
440 if (!t->bufAddr) {
441 while (1) {
442
443 /*=* John Sheng [2003.5.31] agp tex *=*/
444 via_alloc_texture(vmesa, t);
445 /*via_alloc_texture_agp(vmesa, t);*/
446
447 if (t->texMem.offset)
448 break;
449 else
450 agpFullCount++;
451
452 if (vmesa->TexObjList.prev == vmesa->CurrentTexObj[0] ||
453 vmesa->TexObjList.prev == vmesa->CurrentTexObj[1]) {
454 #ifdef DEBUG
455 if (VIA_DEBUG) fprintf(stderr, "Hit bound texture in upload\n");
456 #endif
457 viaPrintLocalLRU(vmesa);
458 UNLOCK_HARDWARE(vmesa);
459 return;
460 }
461
462 if (vmesa->TexObjList.prev == &(vmesa->TexObjList)) {
463 #ifdef DEBUG
464 if (VIA_DEBUG) fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize);
465 #endif
466 mmDumpMemInfo(vmesa->texHeap);
467 UNLOCK_HARDWARE(vmesa);
468 return;
469 }
470
471 viaSwapOutTexObj(vmesa, vmesa->TexObjList.prev);
472 }
473 /*=* John Sheng [2003.5.31] agp tex *=*/
474 /*t->bufAddr = (char *)((GLuint)vmesa->driScreen->pFB + t->texMem.offset);*/
475
476 if (t == vmesa->CurrentTexObj[0])
477 VIA_STATECHANGE(vmesa, VIA_UPLOAD_TEX0);
478
479 if (t == vmesa->CurrentTexObj[1])
480 VIA_STATECHANGE(vmesa, VIA_UPLOAD_TEX1);
481
482 viaUpdateTexLRU(vmesa, t);
483
484 j++;
485 }
486
487 numLevels = t->lastLevel - t->firstLevel + 1;
488
489 for (i = 0; i < numLevels; i++)
490 if (t->dirtyImages & (1 << i))
491 viaUploadTexLevel(t, i);
492
493 t->dirtyImages = 0;
494
495 UNLOCK_HARDWARE(vmesa);
496 #ifdef DEBUG
497 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
498 #endif
499 }