switch to X86_SOURCES
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_subset_tex.c
1 /**
2 * \file radeon_subset_tex.c
3 * \brief Texturing.
4 *
5 * \author Gareth Hughes <gareth@valinux.com>
6 * \author Brian Paul <brianp@valinux.com>
7 */
8
9 /*
10 * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
11 * VA Linux Systems Inc., Fremont, California.
12 *
13 * All Rights Reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * on the rights to use, copy, modify, merge, publish, distribute, sub
19 * license, and/or sell copies of the Software, and to permit persons to whom
20 * the Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
29 * ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
30 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
31 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
32 * USE OR OTHER DEALINGS IN THE SOFTWARE.
33 */
34
35 /* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */
36
37 #include "glheader.h"
38 #include "imports.h"
39 #include "colormac.h"
40 #include "context.h"
41 #include "enums.h"
42 #include "image.h"
43 #include "simple_list.h"
44 #include "texformat.h"
45 #include "texstore.h"
46
47 #include "radeon_context.h"
48 #include "radeon_state.h"
49 #include "radeon_ioctl.h"
50 #include "radeon_subset.h"
51
52 #include <errno.h>
53 #include <stdio.h>
54
55
56 /**
57 * \brief Destroy hardware state associated with a texture.
58 *
59 * \param rmesa Radeon context.
60 * \param t Radeon texture object to be destroyed.
61 *
62 * Frees the memory associated with the texture and if the texture is bound to
63 * a texture unit cleans the associated hardware state.
64 */
65 void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
66 {
67 if ( t->memBlock ) {
68 mmFreeMem( t->memBlock );
69 t->memBlock = NULL;
70 }
71
72 if ( t->tObj )
73 t->tObj->DriverData = NULL;
74
75 if ( rmesa ) {
76 if ( t == rmesa->state.texture.unit[0].texobj ) {
77 rmesa->state.texture.unit[0].texobj = NULL;
78 remove_from_list( &rmesa->hw.tex[0] );
79 make_empty_list( &rmesa->hw.tex[0] );
80 }
81 }
82
83 remove_from_list( t );
84 FREE( t );
85 }
86
87
88 /**
89 * \brief Keep track of swapped out texture objects.
90 *
91 * \param rmesa Radeon context.
92 * \param t Radeon texture object.
93 *
94 * Frees the memory associated with the texture, marks all mipmap images in
95 * the texture as dirty and add it to the radeon_texture::swapped list.
96 */
97 static void radeonSwapOutTexObj( radeonContextPtr rmesa, radeonTexObjPtr t )
98 {
99 if ( t->memBlock ) {
100 mmFreeMem( t->memBlock );
101 t->memBlock = NULL;
102 }
103
104 t->dirty_images = ~0;
105 move_to_tail( &rmesa->texture.swapped, t );
106 }
107
108
109 /**
110 * Texture space has been invalidated.
111 *
112 * \param rmesa Radeon context.
113 * \param heap texture heap number.
114 *
115 * Swaps out every texture in the specified heap.
116 */
117 void radeonAgeTextures( radeonContextPtr rmesa, int heap )
118 {
119 radeonTexObjPtr t, tmp;
120
121 foreach_s ( t, tmp, &rmesa->texture.objects[heap] )
122 radeonSwapOutTexObj( rmesa, t );
123 }
124
125
126 /***************************************************************/
127 /** \name Texture image conversions
128 */
129 /*@{*/
130
131 /**
132 * \brief Upload texture image.
133 *
134 * \param rmesa Radeon context.
135 * \param t Radeon texture object.
136 * \param level level of the image to take the sub-image.
137 * \param x sub-image abscissa.
138 * \param y sub-image ordinate.
139 * \param width sub-image width.
140 * \param height sub-image height.
141 *
142 * Fills in a drmRadeonTexture and drmRadeonTexImage structures and uploads the
143 * texture via the DRM_RADEON_TEXTURE ioctl, aborting in case of failure.
144 */
145 static void radeonUploadSubImage( radeonContextPtr rmesa,
146 radeonTexObjPtr t, GLint level,
147 GLint x, GLint y, GLint width, GLint height )
148 {
149 struct gl_texture_image *texImage;
150 GLint ret;
151 drmRadeonTexture tex;
152 drmRadeonTexImage tmp;
153
154 level += t->firstLevel;
155 texImage = t->tObj->Image[0][level];
156
157 if ( !texImage || !texImage->Data )
158 return;
159
160 t->image[level].data = texImage->Data;
161
162 tex.offset = t->bufAddr;
163 tex.pitch = (t->image[0].width * texImage->TexFormat->TexelBytes) / 64;
164 tex.format = t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK;
165 tex.width = texImage->Width;
166 tex.height = texImage->Height;
167 tex.image = &tmp;
168
169 memcpy( &tmp, &t->image[level], sizeof(drmRadeonTexImage) );
170
171 do {
172 ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE,
173 &tex, sizeof(drmRadeonTexture) );
174 } while ( ret && errno == EAGAIN );
175
176 if ( ret ) {
177 UNLOCK_HARDWARE( rmesa );
178 fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret );
179 exit( 1 );
180 }
181 }
182
183 /**
184 * \brief Upload texture images.
185 *
186 * This might require removing our own and/or other client's texture objects to
187 * make room for these images.
188 *
189 * \param rmesa Radeon context.
190 * \param tObj texture object to upload.
191 *
192 * Sets the matching hardware texture format. Calculates which mipmap levels to
193 * send, depending of the base image size, GL_TEXTURE_MIN_LOD,
194 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL and the
195 * Radeon offset rules. Kicks out textures until the requested texture fits,
196 * sets the texture hardware state and, while holding the hardware lock,
197 * uploads any images that are new.
198 */
199 static void radeonSetTexImages( radeonContextPtr rmesa,
200 struct gl_texture_object *tObj )
201 {
202 radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData;
203 const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel];
204 GLint totalSize;
205 GLint texelsPerDword = 0, blitWidth = 0, blitPitch = 0;
206 GLint x, y, width, height;
207 GLint i;
208 GLint firstLevel, lastLevel, numLevels;
209 GLint log2Width, log2Height;
210 GLuint txformat = 0;
211
212 /* This code cannot be reached once we have lost focus
213 */
214 assert(rmesa->radeonScreen->buffers);
215
216 /* Set the hardware texture format
217 */
218 switch (baseImage->TexFormat->MesaFormat) {
219 case MESA_FORMAT_I8:
220 txformat = RADEON_TXFORMAT_I8;
221 texelsPerDword = 4;
222 blitPitch = 64;
223 break;
224 case MESA_FORMAT_RGBA8888:
225 txformat = RADEON_TXFORMAT_RGBA8888 | RADEON_TXFORMAT_ALPHA_IN_MAP;
226 texelsPerDword = 1;
227 blitPitch = 16;
228 break;
229 case MESA_FORMAT_RGB565:
230 txformat = RADEON_TXFORMAT_RGB565;
231 texelsPerDword = 2;
232 blitPitch = 32;
233 break;
234 default:
235 _mesa_problem(NULL, "unexpected texture format in radeonTexImage2D");
236 return;
237 }
238
239 t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK |
240 RADEON_TXFORMAT_ALPHA_IN_MAP);
241 t->pp_txformat |= txformat;
242
243
244 /* Select the larger of the two widths for our global texture image
245 * coordinate space. As the Radeon has very strict offset rules, we
246 * can't upload mipmaps directly and have to reference their location
247 * from the aligned start of the whole image.
248 */
249 blitWidth = MAX2( baseImage->Width, blitPitch );
250
251 /* Calculate mipmap offsets and dimensions.
252 */
253 totalSize = 0;
254 x = 0;
255 y = 0;
256
257 /* Compute which mipmap levels we really want to send to the hardware.
258 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
259 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
260 * Yes, this looks overly complicated, but it's all needed.
261 */
262 firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5);
263 firstLevel = MAX2(firstLevel, tObj->BaseLevel);
264 lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5);
265 lastLevel = MAX2(lastLevel, tObj->BaseLevel);
266 lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
267 lastLevel = MIN2(lastLevel, tObj->MaxLevel);
268 lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
269
270 /* save these values */
271 t->firstLevel = firstLevel;
272 t->lastLevel = lastLevel;
273
274 numLevels = lastLevel - firstLevel + 1;
275
276 log2Width = tObj->Image[0][firstLevel]->WidthLog2;
277 log2Height = tObj->Image[0][firstLevel]->HeightLog2;
278
279 for ( i = 0 ; i < numLevels ; i++ ) {
280 const struct gl_texture_image *texImage = tObj->Image[0][i + firstLevel];
281 if ( !texImage )
282 break;
283
284 width = texImage->Width;
285 height = texImage->Height;
286
287 /* Texture images have a minimum pitch of 32 bytes (half of the
288 * 64-byte minimum pitch for blits). For images that have a
289 * width smaller than this, we must pad each texture image
290 * scanline out to this amount.
291 */
292 if ( width < blitPitch / 2 ) {
293 width = blitPitch / 2;
294 }
295
296 totalSize += width * height * baseImage->TexFormat->TexelBytes;
297 ASSERT( (totalSize & 31) == 0 );
298
299 while ( width < blitWidth && height > 1 ) {
300 width *= 2;
301 height /= 2;
302 }
303
304 ASSERT(i < RADEON_MAX_TEXTURE_LEVELS);
305 t->image[i].x = x;
306 t->image[i].y = y;
307 t->image[i].width = width;
308 t->image[i].height = height;
309
310 /* While blits must have a pitch of at least 64 bytes, mipmaps
311 * must be aligned on a 32-byte boundary (just like each texture
312 * image scanline).
313 */
314 if ( width >= blitWidth ) {
315 y += height;
316 } else {
317 x += width;
318 if ( x >= blitWidth ) {
319 x = 0;
320 y++;
321 }
322 }
323 }
324
325 /* Align the total size of texture memory block.
326 */
327 t->totalSize = (totalSize + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK;
328
329 /* Hardware state:
330 */
331 t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK;
332 t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT;
333
334 t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK |
335 RADEON_TXFORMAT_HEIGHT_MASK);
336 t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) |
337 (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT));
338 t->dirty_state = TEX_ALL;
339
340 /* Update the local texture LRU.
341 */
342 move_to_head( &rmesa->texture.objects[0], t );
343
344 LOCK_HARDWARE( rmesa );
345
346 /* Kick out textures until the requested texture fits */
347 while ( !t->memBlock ) {
348 t->memBlock = mmAllocMem( rmesa->texture.heap[0], t->totalSize, 12, 0);
349
350 if (!t->memBlock)
351 radeonSwapOutTexObj( rmesa, rmesa->texture.objects[0].prev );
352
353 }
354
355 /* Set the base offset of the texture image */
356 t->bufAddr = rmesa->radeonScreen->texOffset[0] + t->memBlock->ofs;
357 t->pp_txoffset = t->bufAddr;
358
359 /* Upload any images that are new
360 */
361 for ( i = 0 ; i < numLevels ; i++ ) {
362 if ( t->dirty_images & (1 << i) ) {
363 radeonUploadSubImage( rmesa, t, i, 0, 0,
364 t->image[i].width, t->image[i].height );
365 }
366 }
367
368 rmesa->texture.age[0] = ++rmesa->sarea->texAge[0];
369 UNLOCK_HARDWARE( rmesa );
370 t->dirty_images = 0;
371 }
372
373 /*@}*/
374
375
376 /******************************************************************/
377 /** \name Texture combine functions
378 */
379 /*@{*/
380
381 enum {
382 RADEON_DISABLE = 0, /**< \brief disabled */
383 RADEON_REPLACE = 1, /**< \brief replace function */
384 RADEON_MODULATE = 2, /**< \brief modulate function */
385 RADEON_DECAL = 3, /**< \brief decal function */
386 RADEON_BLEND = 4, /**< \brief blend function */
387 RADEON_MAX_COMBFUNC = 5 /**< \brief max number of combine functions */
388 } ;
389
390
391 /**
392 * \brief Color combine function hardware state table.
393 */
394 static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] =
395 {
396 /* Unit 0:
397 */
398 {
399 /* Disable combiner stage
400 */
401 (RADEON_COLOR_ARG_A_ZERO |
402 RADEON_COLOR_ARG_B_ZERO |
403 RADEON_COLOR_ARG_C_CURRENT_COLOR |
404 RADEON_BLEND_CTL_ADD |
405 RADEON_SCALE_1X |
406 RADEON_CLAMP_TX),
407
408 /* GL_REPLACE = 0x00802800
409 */
410 (RADEON_COLOR_ARG_A_ZERO |
411 RADEON_COLOR_ARG_B_ZERO |
412 RADEON_COLOR_ARG_C_T0_COLOR |
413 RADEON_BLEND_CTL_ADD |
414 RADEON_SCALE_1X |
415 RADEON_CLAMP_TX),
416
417 /* GL_MODULATE = 0x00800142
418 */
419 (RADEON_COLOR_ARG_A_CURRENT_COLOR |
420 RADEON_COLOR_ARG_B_T0_COLOR |
421 RADEON_COLOR_ARG_C_ZERO |
422 RADEON_BLEND_CTL_ADD |
423 RADEON_SCALE_1X |
424 RADEON_CLAMP_TX),
425
426 /* GL_DECAL = 0x008c2d42
427 */
428 (RADEON_COLOR_ARG_A_CURRENT_COLOR |
429 RADEON_COLOR_ARG_B_T0_COLOR |
430 RADEON_COLOR_ARG_C_T0_ALPHA |
431 RADEON_BLEND_CTL_BLEND |
432 RADEON_SCALE_1X |
433 RADEON_CLAMP_TX),
434
435 /* GL_BLEND = 0x008c2902
436 */
437 (RADEON_COLOR_ARG_A_CURRENT_COLOR |
438 RADEON_COLOR_ARG_B_TFACTOR_COLOR |
439 RADEON_COLOR_ARG_C_T0_COLOR |
440 RADEON_BLEND_CTL_BLEND |
441 RADEON_SCALE_1X |
442 RADEON_CLAMP_TX),
443 },
444
445 };
446
447 /**
448 * \brief Alpha combine function hardware state table.
449 */
450 static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] =
451 {
452 /* Unit 0:
453 */
454 {
455 /* Disable combiner stage
456 */
457 (RADEON_ALPHA_ARG_A_ZERO |
458 RADEON_ALPHA_ARG_B_ZERO |
459 RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
460 RADEON_BLEND_CTL_ADD |
461 RADEON_SCALE_1X |
462 RADEON_CLAMP_TX),
463
464 /* GL_REPLACE = 0x00800500
465 */
466 (RADEON_ALPHA_ARG_A_ZERO |
467 RADEON_ALPHA_ARG_B_ZERO |
468 RADEON_ALPHA_ARG_C_T0_ALPHA |
469 RADEON_BLEND_CTL_ADD |
470 RADEON_SCALE_1X |
471 RADEON_CLAMP_TX),
472
473 /* GL_MODULATE = 0x00800051
474 */
475 (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
476 RADEON_ALPHA_ARG_B_T0_ALPHA |
477 RADEON_ALPHA_ARG_C_ZERO |
478 RADEON_BLEND_CTL_ADD |
479 RADEON_SCALE_1X |
480 RADEON_CLAMP_TX),
481
482 /* GL_DECAL = 0x00800100
483 */
484 (RADEON_ALPHA_ARG_A_ZERO |
485 RADEON_ALPHA_ARG_B_ZERO |
486 RADEON_ALPHA_ARG_C_CURRENT_ALPHA |
487 RADEON_BLEND_CTL_ADD |
488 RADEON_SCALE_1X |
489 RADEON_CLAMP_TX),
490
491 /* GL_BLEND = 0x00800051
492 */
493 (RADEON_ALPHA_ARG_A_CURRENT_ALPHA |
494 RADEON_ALPHA_ARG_B_TFACTOR_ALPHA |
495 RADEON_ALPHA_ARG_C_T0_ALPHA |
496 RADEON_BLEND_CTL_BLEND |
497 RADEON_SCALE_1X |
498 RADEON_CLAMP_TX),
499
500 },
501
502 };
503
504 /*@}*/
505
506
507 /******************************************************************/
508 /** \name Texture unit state management
509 */
510 /*@{*/
511
512 /**
513 * \brief Update the texture environment.
514 *
515 * \param ctx GL context
516 * \param unit texture unit to update.
517 *
518 * Sets the state of the RADEON_TEX_PP_TXCBLEND and RADEON_TEX_PP_TXABLEND
519 * registers using the ::radeon_color_combine and ::radeon_alpha_combine tables,
520 * and informs of the state change.
521 */
522 static void radeonUpdateTextureEnv( GLcontext *ctx, int unit )
523 {
524 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
525 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
526 const struct gl_texture_object *tObj = texUnit->_Current;
527 const GLenum format = tObj->Image[0][tObj->BaseLevel]->Format;
528 GLuint color_combine = radeon_color_combine[unit][RADEON_DISABLE];
529 GLuint alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
530
531
532 /* Set the texture environment state. Isn't this nice and clean?
533 * The Radeon will automagically set the texture alpha to 0xff when
534 * the texture format does not include an alpha component. This
535 * reduces the amount of special-casing we have to do, alpha-only
536 * textures being a notable exception.
537 */
538 switch ( texUnit->EnvMode ) {
539 case GL_REPLACE:
540 switch ( format ) {
541 case GL_RGBA:
542 case GL_INTENSITY:
543 color_combine = radeon_color_combine[unit][RADEON_REPLACE];
544 alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE];
545 break;
546 case GL_RGB:
547 color_combine = radeon_color_combine[unit][RADEON_REPLACE];
548 alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
549 break;
550 default:
551 break;
552 }
553 break;
554
555 case GL_MODULATE:
556 switch ( format ) {
557 case GL_RGBA:
558 case GL_INTENSITY:
559 color_combine = radeon_color_combine[unit][RADEON_MODULATE];
560 alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
561 break;
562 case GL_RGB:
563 color_combine = radeon_color_combine[unit][RADEON_MODULATE];
564 alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
565 break;
566 default:
567 break;
568 }
569 break;
570
571 case GL_DECAL:
572 switch ( format ) {
573 case GL_RGBA:
574 case GL_RGB:
575 color_combine = radeon_color_combine[unit][RADEON_DECAL];
576 alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
577 break;
578 case GL_INTENSITY:
579 color_combine = radeon_color_combine[unit][RADEON_DISABLE];
580 alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE];
581 break;
582 default:
583 break;
584 }
585 break;
586
587 case GL_BLEND:
588 switch ( format ) {
589 case GL_RGBA:
590 case GL_RGB:
591 color_combine = radeon_color_combine[unit][RADEON_BLEND];
592 alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE];
593 break;
594 case GL_INTENSITY:
595 color_combine = radeon_color_combine[unit][RADEON_BLEND];
596 alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND];
597 break;
598 default:
599 break;
600 }
601 break;
602
603 default:
604 break;
605 }
606
607 if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine ||
608 rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) {
609 RADEON_STATECHANGE( rmesa, tex[unit] );
610 rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine;
611 rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine;
612 }
613 }
614
615
616 #define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \
617 RADEON_MIN_FILTER_MASK | \
618 RADEON_MAG_FILTER_MASK | \
619 RADEON_MAX_ANISO_MASK | \
620 RADEON_CLAMP_S_MASK | \
621 RADEON_CLAMP_T_MASK)
622
623 #define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \
624 RADEON_TXFORMAT_HEIGHT_MASK | \
625 RADEON_TXFORMAT_FORMAT_MASK | \
626 RADEON_TXFORMAT_ALPHA_IN_MAP)
627
628
629
630 void radeonUpdateTextureState( GLcontext *ctx )
631 {
632 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
633 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[0];
634
635 if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) {
636 struct gl_texture_object *tObj = texUnit->_Current;
637 radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData;
638
639 /* Upload teximages (not pipelined)
640 */
641 if ( t->dirty_images ) {
642 RADEON_FIREVERTICES( rmesa );
643 radeonSetTexImages( rmesa, tObj );
644 }
645
646 /* Update state if this is a different texture object to last
647 * time.
648 */
649 if ( rmesa->state.texture.unit[0].texobj != t ) {
650 rmesa->state.texture.unit[0].texobj = t;
651 t->dirty_state |= 1<<0;
652 move_to_head( &rmesa->texture.objects[0], t );
653 }
654
655 if (t->dirty_state) {
656 GLuint *cmd = RADEON_DB_STATE( tex[0] );
657
658 cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK;
659 cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK;
660 cmd[TEX_PP_TXFILTER] |= t->pp_txfilter & TEXOBJ_TXFILTER_MASK;
661 cmd[TEX_PP_TXFORMAT] |= t->pp_txformat & TEXOBJ_TXFORMAT_MASK;
662 cmd[TEX_PP_TXOFFSET] = t->pp_txoffset;
663 cmd[TEX_PP_BORDER_COLOR] = t->pp_border_color;
664
665 RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[0] );
666 t->dirty_state = 0;
667 }
668
669 /* Newly enabled?
670 */
671 if (!(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & RADEON_TEX_0_ENABLE)) {
672 RADEON_STATECHANGE( rmesa, ctx );
673 rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (RADEON_TEX_0_ENABLE |
674 RADEON_TEX_BLEND_0_ENABLE);
675
676 RADEON_STATECHANGE( rmesa, tcl );
677 rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0;
678 }
679
680 radeonUpdateTextureEnv( ctx, 0 );
681 }
682 else if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<0)) {
683 /* Texture unit disabled */
684 rmesa->state.texture.unit[0].texobj = 0;
685 RADEON_STATECHANGE( rmesa, ctx );
686 rmesa->hw.ctx.cmd[CTX_PP_CNTL] &=
687 ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << 0);
688
689 RADEON_STATECHANGE( rmesa, tcl );
690 rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 |
691 RADEON_TCL_VTX_Q0);
692 }
693 }
694
695
696
697 /**
698 * \brief Choose texture format.
699 *
700 * \param ctx GL context.
701 * \param internalFormat texture internal format.
702 * \param format pixel format. Not used.
703 * \param type pixel data type. Not used.
704 *
705 * \return pointer to chosen texture format.
706 *
707 * Returns a pointer to one of the Mesa texture formats which is supported by
708 * Radeon and matches the internal format.
709 */
710 static const struct gl_texture_format *
711 radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
712 GLenum format, GLenum type )
713 {
714 switch ( internalFormat ) {
715 case GL_RGBA:
716 case GL_RGBA8:
717 return &_mesa_texformat_rgba8888;
718
719 case GL_RGB:
720 case GL_RGB5:
721 return &_mesa_texformat_rgb565;
722
723 case GL_INTENSITY:
724 case GL_INTENSITY8:
725 return &_mesa_texformat_i8;
726
727 default:
728 _mesa_problem(ctx, "unexpected texture format in radeonChoosTexFormat");
729 return NULL;
730 }
731 }
732
733 /**
734 * \brief Allocate a Radeon texture object.
735 *
736 * \param texObj texture object.
737 *
738 * \return pointer to the device specific texture object on success, or NULL on failure.
739 *
740 * Allocates and initializes a radeon_tex_obj structure to connect it to the
741 * driver private data pointer in \p texObj.
742 */
743 static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
744 {
745 radeonTexObjPtr t;
746
747 t = CALLOC_STRUCT( radeon_tex_obj );
748 if (!t)
749 return NULL;
750
751 t->tObj = texObj;
752 texObj->DriverData = t;
753 make_empty_list( t );
754 t->dirty_images = ~0;
755 return t;
756 }
757
758
759 /**
760 * \brief Load a texture image.
761 *
762 * \param ctx GL context.
763 * \param texObj texture object
764 * \param target target texture.
765 * \param level level of detail number.
766 * \param internalFormat internal format.
767 * \param width texture image width.
768 * \param height texture image height.
769 * \param border border width.
770 * \param format pixel format.
771 * \param type pixel data type.
772 * \param pixels image data.
773 * \param packing passed to _mesa_store_teximage2d() unchanged.
774 * \param texImage passed to _mesa_store_teximage2d() unchanged.
775 *
776 * If there is a device specific texture object associated with the given
777 * texture object then swaps that texture out. Calls _mesa_store_teximage2d()
778 * with all other parameters unchanged.
779 */
780 static void radeonTexImage2D( GLcontext *ctx, GLenum target, GLint level,
781 GLint internalFormat,
782 GLint width, GLint height, GLint border,
783 GLenum format, GLenum type, const GLvoid *pixels,
784 const struct gl_pixelstore_attrib *packing,
785 struct gl_texture_object *texObj,
786 struct gl_texture_image *texImage )
787 {
788 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
789 radeonTexObjPtr t = (radeonTexObjPtr)texObj->DriverData;
790
791 if ( t )
792 radeonSwapOutTexObj( rmesa, t );
793
794 /* Note, this will call radeonChooseTextureFormat */
795 _mesa_store_teximage2d(ctx, target, level, internalFormat,
796 width, height, border, format, type, pixels,
797 &ctx->Unpack, texObj, texImage);
798 }
799
800 /**
801 * \brief Set texture environment parameters.
802 *
803 * \param ctx GL context.
804 * \param target texture environment.
805 * \param pname texture parameter. Accepted value is GL_TEXTURE_ENV_COLOR.
806 * \param param parameter value.
807 *
808 * Updates the current unit's RADEON_TEX_PP_TFACTOR register and informs of the
809 * state change.
810 */
811 static void radeonTexEnv( GLcontext *ctx, GLenum target,
812 GLenum pname, const GLfloat *param )
813 {
814 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
815 GLuint unit = ctx->Texture.CurrentUnit;
816 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
817
818 switch ( pname ) {
819 case GL_TEXTURE_ENV_COLOR: {
820 GLubyte c[4];
821 GLuint envColor;
822 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
823 envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
824 if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
825 RADEON_STATECHANGE( rmesa, tex[unit] );
826 rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
827 }
828 break;
829 }
830
831 default:
832 return;
833 }
834 }
835
836 /**
837 * \brief Set texture parameter.
838 *
839 * \param ctx GL context.
840 * \param target target texture.
841 * \param texObj texture object.
842 * \param pname texture parameter.
843 * \param params parameter value.
844 *
845 * Allocates the device specific texture object data if it doesn't exist
846 * already.
847 *
848 * Updates the texture object radeon_tex_obj::pp_txfilter register and marks
849 * the texture state (radeon_tex_obj::dirty_state) as dirty.
850 */
851 static void radeonTexParameter( GLcontext *ctx, GLenum target,
852 struct gl_texture_object *texObj,
853 GLenum pname, const GLfloat *params )
854 {
855 radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
856
857 if (!t)
858 t = radeonAllocTexObj( texObj );
859
860 switch ( pname ) {
861 case GL_TEXTURE_MIN_FILTER:
862 t->pp_txfilter &= ~RADEON_MIN_FILTER_MASK;
863 switch ( texObj->MinFilter ) {
864 case GL_NEAREST:
865 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
866 break;
867 case GL_LINEAR:
868 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
869 break;
870 case GL_NEAREST_MIPMAP_NEAREST:
871 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
872 break;
873 case GL_NEAREST_MIPMAP_LINEAR:
874 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
875 break;
876 case GL_LINEAR_MIPMAP_NEAREST:
877 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
878 break;
879 case GL_LINEAR_MIPMAP_LINEAR:
880 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
881 break;
882 }
883 break;
884
885 case GL_TEXTURE_MAG_FILTER:
886 t->pp_txfilter &= ~RADEON_MAG_FILTER_MASK;
887 switch ( texObj->MagFilter ) {
888 case GL_NEAREST:
889 t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
890 break;
891 case GL_LINEAR:
892 t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
893 break;
894 }
895 break;
896
897 case GL_TEXTURE_WRAP_S:
898 t->pp_txfilter &= ~RADEON_CLAMP_S_MASK;
899 switch ( texObj->WrapS ) {
900 case GL_REPEAT:
901 t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
902 break;
903 case GL_CLAMP_TO_EDGE:
904 t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
905 break;
906 }
907 break;
908
909 case GL_TEXTURE_WRAP_T:
910 t->pp_txfilter &= ~RADEON_CLAMP_T_MASK;
911 switch ( texObj->WrapT ) {
912 case GL_REPEAT:
913 t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
914 break;
915 case GL_CLAMP_TO_EDGE:
916 t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
917 break;
918 }
919 break;
920
921 default:
922 return;
923 }
924
925 /* Mark this texobj as dirty (one bit per tex unit)
926 */
927 t->dirty_state = TEX_ALL;
928 }
929
930 /**
931 * \brief Bind texture.
932 *
933 * \param ctx GL context.
934 * \param target not used.
935 * \param texObj texture object.
936 *
937 * Allocates the device specific texture data if it doesn't exist already.
938 */
939 static void radeonBindTexture( GLcontext *ctx, GLenum target,
940 struct gl_texture_object *texObj )
941 {
942 if ( !texObj->DriverData )
943 radeonAllocTexObj( texObj );
944 }
945
946 /**
947 * \brief Delete texture.
948 *
949 * \param ctx GL context.
950 * \param texObj texture object.
951 *
952 * Fires any outstanding vertices and destroy the device specific texture
953 * object.
954 */
955 static void radeonDeleteTexture( GLcontext *ctx,
956 struct gl_texture_object *texObj )
957 {
958 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
959 radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
960
961 if ( t ) {
962 if ( rmesa )
963 RADEON_FIREVERTICES( rmesa );
964 radeonDestroyTexObj( rmesa, t );
965 }
966 }
967
968 /**
969 * \brief Initialize context texture object data.
970 *
971 * \param ctx GL context.
972 *
973 * Called by radeonInitTextureFuncs() to setup the context initial texture
974 * objects.
975 */
976 static void radeonInitTextureObjects( GLcontext *ctx )
977 {
978 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
979 struct gl_texture_object *texObj;
980 GLuint tmp = ctx->Texture.CurrentUnit;
981
982 ctx->Texture.CurrentUnit = 0;
983
984 texObj = ctx->Texture.Unit[0].Current2D;
985 radeonBindTexture( ctx, GL_TEXTURE_2D, texObj );
986 move_to_tail( &rmesa->texture.swapped,
987 (radeonTexObjPtr)texObj->DriverData );
988
989
990 ctx->Texture.CurrentUnit = tmp;
991 }
992
993 /**
994 * \brief Setup the GL context driver callbacks.
995 *
996 * \param ctx GL context.
997 *
998 * \sa Called by radeonCreateContext().
999 */
1000 void radeonInitTextureFuncs( GLcontext *ctx )
1001 {
1002 ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat;
1003 ctx->Driver.TexImage2D = radeonTexImage2D;
1004
1005 ctx->Driver.BindTexture = radeonBindTexture;
1006 ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
1007 ctx->Driver.DeleteTexture = radeonDeleteTexture;
1008 ctx->Driver.PrioritizeTexture = NULL;
1009 ctx->Driver.ActiveTexture = NULL;
1010 ctx->Driver.UpdateTexturePalette = NULL;
1011
1012 ctx->Driver.TexEnv = radeonTexEnv;
1013 ctx->Driver.TexParameter = radeonTexParameter;
1014
1015 radeonInitTextureObjects( ctx );
1016 }
1017
1018 /*@}*/