fix up heights for i830/i915 texture compression
[mesa.git] / src / mesa / drivers / dri / i915 / i830_texstate.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "glheader.h"
29 #include "macros.h"
30 #include "mtypes.h"
31 #include "simple_list.h"
32 #include "enums.h"
33 #include "texformat.h"
34 #include "texstore.h"
35
36 #include "mm.h"
37
38 #include "intel_screen.h"
39 #include "intel_ioctl.h"
40 #include "intel_tex.h"
41
42 #include "i830_context.h"
43 #include "i830_reg.h"
44
45
46 #define I830_TEX_UNIT_ENABLED(unit) (1<<unit)
47
48 static GLboolean i830SetTexImages( i830ContextPtr i830,
49 struct gl_texture_object *tObj )
50 {
51 GLuint total_height, pitch, i, textureFormat;
52 i830TextureObjectPtr t = (i830TextureObjectPtr) tObj->DriverData;
53 const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel];
54 GLint firstLevel, lastLevel, numLevels;
55
56 switch( baseImage->TexFormat->MesaFormat ) {
57 case MESA_FORMAT_L8:
58 t->intel.texelBytes = 1;
59 textureFormat = MAPSURF_8BIT | MT_8BIT_L8;
60 break;
61
62 case MESA_FORMAT_I8:
63 t->intel.texelBytes = 1;
64 textureFormat = MAPSURF_8BIT | MT_8BIT_I8;
65 break;
66
67 case MESA_FORMAT_A8:
68 t->intel.texelBytes = 1;
69 textureFormat = MAPSURF_8BIT | MT_8BIT_I8; /* Kludge -- check with conform, glean */
70 break;
71
72 case MESA_FORMAT_AL88:
73 t->intel.texelBytes = 2;
74 textureFormat = MAPSURF_16BIT | MT_16BIT_AY88;
75 break;
76
77 case MESA_FORMAT_RGB565:
78 t->intel.texelBytes = 2;
79 textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565;
80 break;
81
82 case MESA_FORMAT_ARGB1555:
83 t->intel.texelBytes = 2;
84 textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555;
85 break;
86
87 case MESA_FORMAT_ARGB4444:
88 t->intel.texelBytes = 2;
89 textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB4444;
90 break;
91
92 case MESA_FORMAT_ARGB8888:
93 t->intel.texelBytes = 4;
94 textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888;
95 break;
96
97 case MESA_FORMAT_YCBCR_REV:
98 t->intel.texelBytes = 2;
99 textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL |
100 TM0S1_COLORSPACE_CONVERSION);
101 break;
102
103 case MESA_FORMAT_YCBCR:
104 t->intel.texelBytes = 2;
105 textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY | /* ??? */
106 TM0S1_COLORSPACE_CONVERSION);
107 break;
108
109 case MESA_FORMAT_RGB_FXT1:
110 case MESA_FORMAT_RGBA_FXT1:
111 t->intel.texelBytes = 2;
112 textureFormat = MAPSURF_COMPRESSED | MT_COMPRESS_FXT1;
113 break;
114
115 default:
116 fprintf(stderr, "%s: bad image format\n", __FUNCTION__);
117 abort();
118 }
119
120 /* Compute which mipmap levels we really want to send to the hardware.
121 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
122 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
123 * Yes, this looks overly complicated, but it's all needed.
124 */
125 driCalculateTextureFirstLastLevel( (driTextureObject *) t );
126
127
128 /* Figure out the amount of memory required to hold all the mipmap
129 * levels. Choose the smallest pitch to accomodate the largest
130 * mipmap:
131 */
132 firstLevel = t->intel.base.firstLevel;
133 lastLevel = t->intel.base.lastLevel;
134 numLevels = lastLevel - firstLevel + 1;
135
136 /* Pitch would be subject to additional rules if texture memory were
137 * tiled. Currently it isn't.
138 */
139 if (0) {
140 pitch = 128;
141 while (pitch < tObj->Image[0][firstLevel]->Width * t->intel.texelBytes)
142 pitch *= 2;
143 }
144 else {
145 pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes;
146 pitch = (pitch + 3) & ~3;
147 }
148
149
150 /* All images must be loaded at this pitch. Count the number of
151 * lines required:
152 */
153 for ( total_height = i = 0 ; i < numLevels ; i++ ) {
154 t->intel.image[0][i].image = tObj->Image[0][firstLevel + i];
155 if (!t->intel.image[0][i].image)
156 break;
157
158 t->intel.image[0][i].offset = total_height * pitch;
159 t->intel.image[0][i].internalFormat = baseImage->Format;
160 if (t->intel.image[0][i].image->IsCompressed)
161 {
162 if (t->intel.image[0][i].image->Height > 4)
163 total_height += t->intel.image[0][i].image->Height/4;
164 else
165 total_height += 1;
166 }
167 else
168 total_height += MAX2(2, t->intel.image[0][i].image->Height);
169 }
170
171 t->intel.Pitch = pitch;
172 t->intel.base.totalSize = total_height*pitch;
173 t->intel.max_level = i-1;
174 t->Setup[I830_TEXREG_TM0S1] =
175 (((tObj->Image[0][firstLevel]->Height - 1) << TM0S1_HEIGHT_SHIFT) |
176 ((tObj->Image[0][firstLevel]->Width - 1) << TM0S1_WIDTH_SHIFT) |
177 textureFormat);
178 t->Setup[I830_TEXREG_TM0S2] =
179 (((pitch / 4) - 1) << TM0S2_PITCH_SHIFT);
180 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAX_MIP_MASK;
181 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_MIP_MASK;
182 t->Setup[I830_TEXREG_TM0S3] |= ((numLevels - 1)*4) << TM0S3_MIN_MIP_SHIFT;
183 t->intel.dirty = I830_UPLOAD_TEX_ALL;
184
185 return intelUploadTexImages( &i830->intel, &t->intel, 0 );
186 }
187
188
189 static void i830_import_tex_unit( i830ContextPtr i830,
190 i830TextureObjectPtr t,
191 GLuint unit )
192 {
193 if(INTEL_DEBUG&DEBUG_TEXTURE)
194 fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit);
195
196 if (i830->intel.CurrentTexObj[unit])
197 i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit);
198
199 i830->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t;
200 t->intel.base.bound |= (1 << unit);
201
202 I830_STATECHANGE( i830, I830_UPLOAD_TEX(unit) );
203
204 i830->state.Tex[unit][I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
205 (LOAD_TEXTURE_MAP0 << unit) | 4);
206 i830->state.Tex[unit][I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE |
207 t->intel.TextureOffset);
208
209 i830->state.Tex[unit][I830_TEXREG_TM0S1] = t->Setup[I830_TEXREG_TM0S1];
210 i830->state.Tex[unit][I830_TEXREG_TM0S2] = t->Setup[I830_TEXREG_TM0S2];
211
212 i830->state.Tex[unit][I830_TEXREG_TM0S3] &= TM0S3_LOD_BIAS_MASK;
213 i830->state.Tex[unit][I830_TEXREG_TM0S3] |= (t->Setup[I830_TEXREG_TM0S3] &
214 ~TM0S3_LOD_BIAS_MASK);
215
216 i830->state.Tex[unit][I830_TEXREG_TM0S4] = t->Setup[I830_TEXREG_TM0S4];
217 i830->state.Tex[unit][I830_TEXREG_MCS] = (t->Setup[I830_TEXREG_MCS] &
218 ~MAP_UNIT_MASK);
219 i830->state.Tex[unit][I830_TEXREG_MCS] |= MAP_UNIT(unit);
220
221 t->intel.dirty &= ~I830_UPLOAD_TEX(unit);
222 }
223
224
225
226 static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit )
227 {
228 i830ContextPtr i830 = I830_CONTEXT(ctx);
229 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
230 struct gl_texture_object *tObj = texUnit->_Current;
231 i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData;
232
233 if (0) fprintf(stderr, "%s\n", __FUNCTION__);
234
235 /* Fallback if there's a texture border */
236 if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) {
237 fprintf(stderr, "Texture border\n");
238 return GL_FALSE;
239 }
240
241 /* Upload teximages (not pipelined)
242 */
243 if (t->intel.base.dirty_images[0]) {
244 if (!i830SetTexImages( i830, tObj )) {
245 return GL_FALSE;
246 }
247 }
248
249 /* Update state if this is a different texture object to last
250 * time.
251 */
252 if (i830->intel.CurrentTexObj[unit] != &t->intel ||
253 (t->intel.dirty & I830_UPLOAD_TEX(unit))) {
254 i830_import_tex_unit( i830, t, unit);
255 }
256
257 I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), GL_TRUE);
258
259 return GL_TRUE;
260 }
261
262 static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit )
263 {
264 i830ContextPtr i830 = I830_CONTEXT(ctx);
265 GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS];
266
267 mcs &= ~TEXCOORDS_ARE_NORMAL;
268 mcs |= TEXCOORDS_ARE_IN_TEXELUNITS;
269
270 if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) {
271 I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit));
272 i830->state.Tex[unit][I830_TEXREG_MCS] = mcs;
273 }
274
275 return GL_TRUE;
276 }
277
278
279 static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit )
280 {
281 i830ContextPtr i830 = I830_CONTEXT(ctx);
282 GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS];
283
284 mcs &= ~TEXCOORDS_ARE_IN_TEXELUNITS;
285 mcs |= TEXCOORDS_ARE_NORMAL;
286
287 if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) {
288 I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit));
289 i830->state.Tex[unit][I830_TEXREG_MCS] = mcs;
290 }
291
292 return GL_TRUE;
293 }
294
295
296 static GLboolean disable_tex( GLcontext *ctx, GLuint unit )
297 {
298 i830ContextPtr i830 = I830_CONTEXT(ctx);
299
300 /* This is happening too often. I need to conditionally send diffuse
301 * state to the card. Perhaps a diffuse dirty flag of some kind.
302 * Will need to change this logic if more than 2 texture units are
303 * used. We need to only do this up to the last unit enabled, or unit
304 * one if nothing is enabled.
305 */
306
307 if ( i830->intel.CurrentTexObj[unit] != NULL ) {
308 /* The old texture is no longer bound to this texture unit.
309 * Mark it as such.
310 */
311
312 i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0);
313 i830->intel.CurrentTexObj[unit] = NULL;
314 }
315
316 return GL_TRUE;
317 }
318
319 static GLboolean i830UpdateTexUnit( GLcontext *ctx, GLuint unit )
320 {
321 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
322
323 if (texUnit->_ReallyEnabled &&
324 INTEL_CONTEXT(ctx)->intelScreen->textureSize < 2048 * 1024)
325 return GL_FALSE;
326
327 if (texUnit->_ReallyEnabled == TEXTURE_1D_BIT ||
328 texUnit->_ReallyEnabled == TEXTURE_2D_BIT) {
329 return (enable_tex_common( ctx, unit ) &&
330 enable_tex_2d( ctx, unit ));
331 }
332 else if (texUnit->_ReallyEnabled == TEXTURE_RECT_BIT) {
333 return (enable_tex_common( ctx, unit ) &&
334 enable_tex_rect( ctx, unit ));
335 }
336 else if (texUnit->_ReallyEnabled) {
337 return GL_FALSE;
338 }
339 else {
340 return disable_tex( ctx, unit );
341 }
342 }
343
344
345 void i830UpdateTextureState( intelContextPtr intel )
346 {
347 i830ContextPtr i830 = I830_CONTEXT(intel);
348 GLcontext *ctx = &intel->ctx;
349 GLboolean ok;
350
351 if (0) fprintf(stderr, "%s\n", __FUNCTION__);
352
353 I830_ACTIVESTATE(i830, I830_UPLOAD_TEX_ALL, GL_FALSE);
354
355 ok = (i830UpdateTexUnit( ctx, 0 ) &&
356 i830UpdateTexUnit( ctx, 1 ) &&
357 i830UpdateTexUnit( ctx, 2 ) &&
358 i830UpdateTexUnit( ctx, 3 ));
359
360 FALLBACK( intel, I830_FALLBACK_TEXTURE, !ok );
361
362 if (ok)
363 i830EmitTextureBlend( i830 );
364 }
365
366
367