Tizen 2.0 Release
[profile/ivi/osmesa.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 }