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