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