Small optimization for big-endian (e.g., PowerPC) systems.
[mesa.git] / src / mesa / drivers / dri / r128 / r128_texmem.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_texmem.c,v 1.1 2002/02/22 21:44:58 dawes Exp $ */
2 /**************************************************************************
3
4 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
5 Cedar Park, Texas.
6 All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
17 Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Gareth Hughes <gareth@valinux.com>
32 * Kevin E. Martin <martin@valinux.com>
33 * Brian Paul <brianp@valinux.com>
34 */
35
36 #include "r128_context.h"
37 #include "r128_state.h"
38 #include "r128_ioctl.h"
39 #include "r128_tris.h"
40 #include "r128_tex.h"
41
42 #include "context.h"
43 #include "macros.h"
44 #include "simple_list.h"
45 #include "texformat.h"
46 #include "imports.h"
47
48 #define TEX_0 1
49 #define TEX_1 2
50
51
52 /* Destroy hardware state associated with texture `t'.
53 */
54 void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t )
55 {
56 unsigned i;
57
58
59 /* See if it was the driver's current object.
60 */
61
62 if ( rmesa != NULL )
63 {
64 for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ )
65 {
66 if ( t == rmesa->CurrentTexObj[ i ] ) {
67 assert( t->base.bound & (1 << i) );
68 rmesa->CurrentTexObj[ i ] = NULL;
69 }
70 }
71 }
72 }
73
74
75 /**
76 * Upload the texture image associated with texture \a t at the specified
77 * level at the address relative to \a start.
78 */
79 static void uploadSubImage( r128ContextPtr rmesa, r128TexObjPtr t,
80 GLint level,
81 GLint x, GLint y, GLint width, GLint height )
82 {
83 struct gl_texture_image *image;
84 int texelsPerDword = 0;
85 int imageWidth, imageHeight;
86 int remaining, rows;
87 int format, dwords;
88 uint32_t pitch, offset;
89 int i;
90
91 /* Ensure we have a valid texture to upload */
92 if ( ( level < 0 ) || ( level > R128_MAX_TEXTURE_LEVELS ) )
93 return;
94
95 image = t->base.tObj->Image[0][level];
96 if ( !image )
97 return;
98
99 switch ( image->TexFormat->TexelBytes ) {
100 case 1: texelsPerDword = 4; break;
101 case 2: texelsPerDword = 2; break;
102 case 4: texelsPerDword = 1; break;
103 }
104
105 #if 1
106 /* FIXME: The subimage index calcs are wrong... */
107 x = 0;
108 y = 0;
109 width = image->Width;
110 height = image->Height;
111 #endif
112
113 imageWidth = image->Width;
114 imageHeight = image->Height;
115
116 format = t->textureFormat >> 16;
117
118 /* The texel upload routines have a minimum width, so force the size
119 * if needed.
120 */
121 if ( imageWidth < texelsPerDword ) {
122 int factor;
123
124 factor = texelsPerDword / imageWidth;
125 imageWidth = texelsPerDword;
126 imageHeight /= factor;
127 if ( imageHeight == 0 ) {
128 /* In this case, the texel converter will actually walk a
129 * texel or two off the end of the image, but normal malloc
130 * alignment should prevent it from ever causing a fault.
131 */
132 imageHeight = 1;
133 }
134 }
135
136 /* We can't upload to a pitch less than 8 texels so we will need to
137 * linearly upload all modified rows for textures smaller than this.
138 * This makes the x/y/width/height different for the blitter and the
139 * texture walker.
140 */
141 if ( imageWidth >= 8 ) {
142 /* The texture walker and the blitter look identical */
143 pitch = imageWidth >> 3;
144 } else {
145 int factor;
146 int y2;
147 int start, end;
148
149 start = (y * imageWidth) & ~7;
150 end = (y + height) * imageWidth;
151
152 if ( end - start < 8 ) {
153 /* Handle the case where the total number of texels
154 * uploaded is < 8.
155 */
156 x = 0;
157 y = start / 8;
158 width = end - start;
159 height = 1;
160 } else {
161 /* Upload some number of full 8 texel blit rows */
162 factor = 8 / imageWidth;
163
164 y2 = y + height - 1;
165 y /= factor;
166 y2 /= factor;
167
168 x = 0;
169 width = 8;
170 height = y2 - y + 1;
171 }
172
173 /* Fixed pitch of 8 */
174 pitch = 1;
175 }
176
177 dwords = width * height / texelsPerDword;
178 offset = t->bufAddr + t->image[level - t->base.firstLevel].offset;
179
180 #if ENABLE_PERF_BOXES
181 /* Bump the performace counter */
182 rmesa->c_textureBytes += (dwords << 2);
183 #endif
184
185 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
186 fprintf( stderr, "r128UploadSubImage: %d,%d of %d,%d at %d,%d\n",
187 width, height, image->Width, image->Height, x, y );
188 fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d "
189 "level: %d format: %x\n",
190 (GLuint)offset, (GLuint)pitch, dwords, level, format );
191 }
192
193 /* Subdivide the texture if required */
194 if ( dwords <= R128_BUFFER_MAX_DWORDS / 2 ) {
195 rows = height;
196 } else {
197 rows = (R128_BUFFER_MAX_DWORDS * texelsPerDword) / (2 * width);
198 }
199
200 for ( i = 0, remaining = height ;
201 remaining > 0 ;
202 remaining -= rows, y += rows, i++ )
203 {
204 uint32_t *dst;
205 drmBufPtr buffer;
206
207 assert(image->Data);
208
209 height = MIN2(remaining, rows);
210
211 /* Grab the indirect buffer for the texture blit */
212 LOCK_HARDWARE( rmesa );
213 buffer = r128GetBufferLocked( rmesa );
214
215 dst = (uint32_t *)((char *)buffer->address + R128_HOSTDATA_BLIT_OFFSET);
216
217 /* Copy the next chunck of the texture image into the blit buffer */
218 {
219 const GLubyte *src = (const GLubyte *) image->Data +
220 (y * image->Width + x) * image->TexFormat->TexelBytes;
221 const GLuint bytes = width * height * image->TexFormat->TexelBytes;
222 memcpy(dst, src, bytes);
223 }
224
225 r128FireBlitLocked( rmesa, buffer,
226 offset, pitch, format,
227 x, y, width, height );
228 UNLOCK_HARDWARE( rmesa );
229 }
230
231 rmesa->new_state |= R128_NEW_CONTEXT;
232 rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
233 }
234
235
236 /* Upload the texture images associated with texture `t'. This might
237 * require removing our own and/or other client's texture objects to
238 * make room for these images.
239 */
240 void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t )
241 {
242 const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1;
243 GLint i;
244
245 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
246 fprintf( stderr, "%s( %p, %p )\n",
247 __FUNCTION__, (void *) rmesa->glCtx, (void *) t );
248 }
249
250 assert(t);
251
252 LOCK_HARDWARE( rmesa );
253
254 if ( !t->base.memBlock ) {
255 int heap;
256
257
258 heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps,
259 (driTextureObject *) t );
260 if ( heap == -1 ) {
261 UNLOCK_HARDWARE( rmesa );
262 return;
263 }
264
265 /* Set the base offset of the texture image */
266 t->bufAddr = rmesa->r128Screen->texOffset[heap]
267 + t->base.memBlock->ofs;
268
269 /* Set texture offsets for each mipmap level */
270 if ( t->setup.tex_cntl & R128_MIP_MAP_DISABLE ) {
271 for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) {
272 t->setup.tex_offset[i] = t->bufAddr;
273 }
274 } else {
275 for ( i = 0; i < numLevels; i++ ) {
276 const int j = numLevels - i - 1;
277 t->setup.tex_offset[j] = t->bufAddr + t->image[i].offset;
278 }
279 }
280 }
281
282 /* Let the world know we've used this memory recently.
283 */
284 driUpdateTextureLRU( (driTextureObject *) t );
285 UNLOCK_HARDWARE( rmesa );
286
287 /* Upload any images that are new */
288 if ( t->base.dirty_images[0] ) {
289 for ( i = 0 ; i < numLevels; i++ ) {
290 const GLint j = t->base.firstLevel + i; /* the texObj's level */
291 if ( t->base.dirty_images[0] & (1 << j) ) {
292 uploadSubImage( rmesa, t, j, 0, 0,
293 t->image[i].width, t->image[i].height );
294 }
295 }
296
297 rmesa->setup.tex_cntl_c |= R128_TEX_CACHE_FLUSH;
298 rmesa->dirty |= R128_UPLOAD_CONTEXT;
299 t->base.dirty_images[0] = 0;
300 }
301 }