1 /**************************************************************************
2  *
3  * Copyright 2003 VMware, Inc.
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 VMWARE 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 "main/mtypes.h"
29 #include "main/enums.h"
30 #include "main/colormac.h"
31 #include "main/macros.h"
32 #include "main/samplerobj.h"
33 
34 #include "intel_mipmap_tree.h"
35 #include "intel_tex.h"
36 
37 #include "i830_context.h"
38 #include "i830_reg.h"
39 #include "intel_chipset.h"
40 
41 
42 static GLuint
translate_texture_format(GLuint mesa_format)43 translate_texture_format(GLuint mesa_format)
44 {
45    switch (mesa_format) {
46    case MESA_FORMAT_L_UNORM8:
47       return MAPSURF_8BIT | MT_8BIT_L8;
48    case MESA_FORMAT_I_UNORM8:
49       return MAPSURF_8BIT | MT_8BIT_I8;
50    case MESA_FORMAT_LA_UNORM8:
51       return MAPSURF_16BIT | MT_16BIT_AY88;
52    case MESA_FORMAT_B5G6R5_UNORM:
53       return MAPSURF_16BIT | MT_16BIT_RGB565;
54    case MESA_FORMAT_B5G5R5A1_UNORM:
55       return MAPSURF_16BIT | MT_16BIT_ARGB1555;
56    case MESA_FORMAT_B4G4R4A4_UNORM:
57       return MAPSURF_16BIT | MT_16BIT_ARGB4444;
58    case MESA_FORMAT_B8G8R8A8_UNORM:
59       return MAPSURF_32BIT | MT_32BIT_ARGB8888;
60    case MESA_FORMAT_B8G8R8X8_UNORM:
61       return MAPSURF_32BIT | MT_32BIT_XRGB8888;
62    case MESA_FORMAT_YCBCR_REV:
63       return (MAPSURF_422 | MT_422_YCRCB_NORMAL);
64    case MESA_FORMAT_YCBCR:
65       return (MAPSURF_422 | MT_422_YCRCB_SWAPY);
66    case MESA_FORMAT_RGB_FXT1:
67    case MESA_FORMAT_RGBA_FXT1:
68       return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1);
69    case MESA_FORMAT_RGBA_DXT1:
70    case MESA_FORMAT_RGB_DXT1:
71       return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1);
72    case MESA_FORMAT_RGBA_DXT3:
73       return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3);
74    case MESA_FORMAT_RGBA_DXT5:
75       return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5);
76    default:
77       fprintf(stderr, "%s: bad image format %s\n", __func__,
78 	      _mesa_get_format_name(mesa_format));
79       abort();
80       return 0;
81    }
82 }
83 
84 
85 
86 
87 /* The i915 (and related graphics cores) do not support GL_CLAMP.  The
88  * Intel drivers for "other operating systems" implement GL_CLAMP as
89  * GL_CLAMP_TO_EDGE, so the same is done here.
90  */
91 static GLuint
translate_wrap_mode(GLenum wrap)92 translate_wrap_mode(GLenum wrap)
93 {
94    switch (wrap) {
95    case GL_REPEAT:
96       return TEXCOORDMODE_WRAP;
97    case GL_CLAMP:
98    case GL_CLAMP_TO_EDGE:
99       return TEXCOORDMODE_CLAMP;        /* not really correct */
100    case GL_CLAMP_TO_BORDER:
101       return TEXCOORDMODE_CLAMP_BORDER;
102    case GL_MIRRORED_REPEAT:
103       return TEXCOORDMODE_MIRROR;
104    default:
105       return TEXCOORDMODE_WRAP;
106    }
107 }
108 
109 
110 /* Recalculate all state from scratch.  Perhaps not the most
111  * efficient, but this has gotten complex enough that we need
112  * something which is understandable and reliable.
113  */
114 static bool
i830_update_tex_unit(struct intel_context * intel,GLuint unit,GLuint ss3)115 i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3)
116 {
117    struct gl_context *ctx = &intel->ctx;
118    struct i830_context *i830 = i830_context(ctx);
119    struct gl_texture_unit *tUnit = &ctx->Texture.Unit[unit];
120    struct gl_texture_object *tObj = tUnit->_Current;
121    struct intel_texture_object *intelObj = intel_texture_object(tObj);
122    struct gl_texture_image *firstImage;
123    struct gl_sampler_object *sampler = _mesa_get_samplerobj(ctx, unit);
124    GLuint *state = i830->state.Tex[unit], format, pitch;
125    GLint lodbias;
126    GLubyte border[4];
127    GLuint dst_x, dst_y;
128 
129    memset(state, 0, sizeof(*state));
130 
131    /*We need to refcount these. */
132 
133    if (i830->state.tex_buffer[unit] != NULL) {
134        drm_intel_bo_unreference(i830->state.tex_buffer[unit]);
135        i830->state.tex_buffer[unit] = NULL;
136    }
137 
138    if (!intel_finalize_mipmap_tree(intel, unit))
139       return false;
140 
141    /* Get first image here, since intelObj->firstLevel will get set in
142     * the intel_finalize_mipmap_tree() call above.
143     */
144    firstImage = tObj->Image[0][tObj->Attrib.BaseLevel];
145 
146    intel_miptree_get_image_offset(intelObj->mt, tObj->Attrib.BaseLevel, 0,
147 				  &dst_x, &dst_y);
148 
149    drm_intel_bo_reference(intelObj->mt->region->bo);
150    i830->state.tex_buffer[unit] = intelObj->mt->region->bo;
151    pitch = intelObj->mt->region->pitch;
152 
153    /* XXX: This calculation is probably broken for tiled images with
154     * a non-page-aligned offset.
155     */
156    i830->state.tex_offset[unit] = dst_x * intelObj->mt->cpp + dst_y * pitch;
157 
158    format = translate_texture_format(firstImage->TexFormat);
159 
160    state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
161                                (LOAD_TEXTURE_MAP0 << unit) | 4);
162 
163    state[I830_TEXREG_TM0S1] =
164       (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) |
165        ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | format);
166 
167    if (intelObj->mt->region->tiling != I915_TILING_NONE) {
168       state[I830_TEXREG_TM0S1] |= TM0S1_TILED_SURFACE;
169       if (intelObj->mt->region->tiling == I915_TILING_Y)
170 	 state[I830_TEXREG_TM0S1] |= TM0S1_TILE_WALK;
171    }
172 
173    state[I830_TEXREG_TM0S2] =
174       ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK);
175 
176    {
177       if (tObj->Target == GL_TEXTURE_CUBE_MAP)
178          state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) |
179                                     CUBE_NEGX_ENABLE |
180                                     CUBE_POSX_ENABLE |
181                                     CUBE_NEGY_ENABLE |
182                                     CUBE_POSY_ENABLE |
183                                     CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE);
184       else
185          state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit));
186    }
187 
188 
189 
190 
191    {
192       GLuint minFilt, mipFilt, magFilt;
193       float maxlod;
194       uint32_t minlod_fixed, maxlod_fixed;
195 
196       switch (sampler->Attrib.MinFilter) {
197       case GL_NEAREST:
198          minFilt = FILTER_NEAREST;
199          mipFilt = MIPFILTER_NONE;
200          break;
201       case GL_LINEAR:
202          minFilt = FILTER_LINEAR;
203          mipFilt = MIPFILTER_NONE;
204          break;
205       case GL_NEAREST_MIPMAP_NEAREST:
206          minFilt = FILTER_NEAREST;
207          mipFilt = MIPFILTER_NEAREST;
208          break;
209       case GL_LINEAR_MIPMAP_NEAREST:
210          minFilt = FILTER_LINEAR;
211          mipFilt = MIPFILTER_NEAREST;
212          break;
213       case GL_NEAREST_MIPMAP_LINEAR:
214          minFilt = FILTER_NEAREST;
215          mipFilt = MIPFILTER_LINEAR;
216          break;
217       case GL_LINEAR_MIPMAP_LINEAR:
218          minFilt = FILTER_LINEAR;
219          mipFilt = MIPFILTER_LINEAR;
220          break;
221       default:
222          return false;
223       }
224 
225       if (sampler->Attrib.MaxAnisotropy > 1.0) {
226          minFilt = FILTER_ANISOTROPIC;
227          magFilt = FILTER_ANISOTROPIC;
228          /* no trilinear + anisotropic */
229          mipFilt = MIPFILTER_NEAREST;
230       }
231       else {
232          switch (sampler->Attrib.MagFilter) {
233          case GL_NEAREST:
234             magFilt = FILTER_NEAREST;
235             break;
236          case GL_LINEAR:
237             magFilt = FILTER_LINEAR;
238             break;
239          default:
240             return false;
241          }
242       }
243 
244       lodbias = (int) ((tUnit->LodBias + sampler->Attrib.LodBias) * 16.0);
245       if (lodbias < -64)
246           lodbias = -64;
247       if (lodbias > 63)
248           lodbias = 63;
249 
250       state[I830_TEXREG_TM0S3] = ((lodbias << TM0S3_LOD_BIAS_SHIFT) &
251                                   TM0S3_LOD_BIAS_MASK);
252 #if 0
253       /* YUV conversion:
254        */
255       if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR ||
256           firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV)
257          state[I830_TEXREG_TM0S3] |= SS2_COLORSPACE_CONVERSION;
258 #endif
259 
260       /* We get one field with fraction bits for the maximum
261        * addressable (smallest resolution) LOD.  Use it to cover both
262        * MAX_LEVEL and MAX_LOD.
263        */
264       minlod_fixed = U_FIXED(CLAMP(sampler->Attrib.MinLod, 0.0, 11), 4);
265       maxlod = MIN2(sampler->Attrib.MaxLod, tObj->_MaxLevel - tObj->Attrib.BaseLevel);
266       if (intel->intelScreen->deviceID == PCI_CHIP_I855_GM ||
267 	  intel->intelScreen->deviceID == PCI_CHIP_I865_G) {
268 	 maxlod_fixed = U_FIXED(CLAMP(maxlod, 0.0, 11.75), 2);
269 	 maxlod_fixed = MAX2(maxlod_fixed, (minlod_fixed + 3) >> 2);
270 	 state[I830_TEXREG_TM0S3] |= maxlod_fixed << TM0S3_MIN_MIP_SHIFT;
271 	 state[I830_TEXREG_TM0S2] |= TM0S2_LOD_PRECLAMP;
272       } else {
273 	 maxlod_fixed = U_FIXED(CLAMP(maxlod, 0.0, 11), 0);
274 	 maxlod_fixed = MAX2(maxlod_fixed, (minlod_fixed + 15) >> 4);
275 	 state[I830_TEXREG_TM0S3] |= maxlod_fixed << TM0S3_MIN_MIP_SHIFT_830;
276       }
277       state[I830_TEXREG_TM0S3] |= minlod_fixed << TM0S3_MAX_MIP_SHIFT;
278       state[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) |
279                                    (mipFilt << TM0S3_MIP_FILTER_SHIFT) |
280                                    (magFilt << TM0S3_MAG_FILTER_SHIFT));
281    }
282 
283    {
284       GLenum ws = sampler->Attrib.WrapS;
285       GLenum wt = sampler->Attrib.WrapT;
286 
287 
288       /* 3D textures not available on i830
289        */
290       if (tObj->Target == GL_TEXTURE_3D)
291          return false;
292 
293       state[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD |
294                                 MAP_UNIT(unit) |
295                                 ENABLE_TEXCOORD_PARAMS |
296                                 ss3 |
297                                 ENABLE_ADDR_V_CNTL |
298                                 TEXCOORD_ADDR_V_MODE(translate_wrap_mode(wt))
299                                 | ENABLE_ADDR_U_CNTL |
300                                 TEXCOORD_ADDR_U_MODE(translate_wrap_mode
301                                                      (ws)));
302    }
303 
304    /* convert border color from float to ubyte */
305    CLAMPED_FLOAT_TO_UBYTE(border[0], sampler->Attrib.state.border_color.f[0]);
306    CLAMPED_FLOAT_TO_UBYTE(border[1], sampler->Attrib.state.border_color.f[1]);
307    CLAMPED_FLOAT_TO_UBYTE(border[2], sampler->Attrib.state.border_color.f[2]);
308    CLAMPED_FLOAT_TO_UBYTE(border[3], sampler->Attrib.state.border_color.f[3]);
309 
310    state[I830_TEXREG_TM0S4] = PACK_COLOR_8888(border[3],
311 					      border[0],
312 					      border[1],
313 					      border[2]);
314 
315    I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), true);
316    /* memcmp was already disabled, but definitely won't work as the
317     * region might now change and that wouldn't be detected:
318     */
319    I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit));
320    return true;
321 }
322 
323 
324 
325 
326 void
i830UpdateTextureState(struct intel_context * intel)327 i830UpdateTextureState(struct intel_context *intel)
328 {
329    struct i830_context *i830 = i830_context(&intel->ctx);
330    bool ok = true;
331    GLuint i;
332 
333    for (i = 0; i < I830_TEX_UNITS && ok; i++) {
334       if (intel->ctx.Texture.Unit[i]._Current) {
335          switch (intel->ctx.Texture.Unit[i]._Current->Target) {
336          case GL_TEXTURE_1D:
337          case GL_TEXTURE_2D:
338          case GL_TEXTURE_CUBE_MAP:
339             ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_NORMAL);
340             break;
341          case GL_TEXTURE_RECTANGLE:
342             ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_IN_TEXELUNITS);
343             break;
344          case GL_TEXTURE_3D:
345          default:
346             ok = false;
347             break;
348          }
349       } else {
350          struct i830_context *i830 = i830_context(&intel->ctx);
351          if (i830->state.active & I830_UPLOAD_TEX(i))
352             I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(i), false);
353 
354          if (i830->state.tex_buffer[i] != NULL) {
355             drm_intel_bo_unreference(i830->state.tex_buffer[i]);
356             i830->state.tex_buffer[i] = NULL;
357          }
358       }
359    }
360 
361    FALLBACK(intel, I830_FALLBACK_TEXTURE, !ok);
362 
363    if (ok)
364       i830EmitTextureBlend(i830);
365 }
366