Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / i965 / brw_wm_sampler_state.c
1 /*
2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4  develop this 3D driver.
5  
6  Permission is hereby granted, free of charge, to any person obtaining
7  a 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, sublicense, 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
16  portions of the Software.
17  
18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  
26  **********************************************************************/
27  /*
28   * Authors:
29   *   Keith Whitwell <keith@tungstengraphics.com>
30   */
31                    
32
33 #include "brw_context.h"
34 #include "brw_state.h"
35 #include "brw_defines.h"
36
37 #include "main/macros.h"
38 #include "main/samplerobj.h"
39
40
41 /* Samplers aren't strictly wm state from the hardware's perspective,
42  * but that is the only situation in which we use them in this driver.
43  */
44
45
46
47 uint32_t
48 translate_wrap_mode(GLenum wrap, bool using_nearest)
49 {
50    switch( wrap ) {
51    case GL_REPEAT: 
52       return BRW_TEXCOORDMODE_WRAP;
53    case GL_CLAMP:
54       /* GL_CLAMP is the weird mode where coordinates are clamped to
55        * [0.0, 1.0], so linear filtering of coordinates outside of
56        * [0.0, 1.0] give you half edge texel value and half border
57        * color.  The fragment shader will clamp the coordinates, and
58        * we set clamp_border here, which gets the result desired.  We
59        * just use clamp(_to_edge) for nearest, because for nearest
60        * clamping to 1.0 gives border color instead of the desired
61        * edge texels.
62        */
63       if (using_nearest)
64          return BRW_TEXCOORDMODE_CLAMP;
65       else
66          return BRW_TEXCOORDMODE_CLAMP_BORDER;
67    case GL_CLAMP_TO_EDGE: 
68       return BRW_TEXCOORDMODE_CLAMP;
69    case GL_CLAMP_TO_BORDER: 
70       return BRW_TEXCOORDMODE_CLAMP_BORDER;
71    case GL_MIRRORED_REPEAT: 
72       return BRW_TEXCOORDMODE_MIRROR;
73    default: 
74       return BRW_TEXCOORDMODE_WRAP;
75    }
76 }
77
78 /**
79  * Upload SAMPLER_BORDER_COLOR_STATE.
80  */
81 void
82 upload_default_color(struct brw_context *brw, struct gl_sampler_object *sampler,
83                      int unit)
84 {
85    struct intel_context *intel = &brw->intel;
86    struct gl_context *ctx = &intel->ctx;
87    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
88    struct gl_texture_object *texObj = texUnit->_Current;
89    struct gl_texture_image *firstImage = texObj->Image[0][texObj->BaseLevel];
90    float color[4];
91
92    if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) {
93       /* GL specs that border color for depth textures is taken from the
94        * R channel, while the hardware uses A.  Spam R into all the
95        * channels for safety.
96        */
97       color[0] = sampler->BorderColor.f[0];
98       color[1] = sampler->BorderColor.f[0];
99       color[2] = sampler->BorderColor.f[0];
100       color[3] = sampler->BorderColor.f[0];
101    } else {
102       color[0] = sampler->BorderColor.f[0];
103       color[1] = sampler->BorderColor.f[1];
104       color[2] = sampler->BorderColor.f[2];
105       color[3] = sampler->BorderColor.f[3];
106    }
107
108    if (intel->gen == 5 || intel->gen == 6) {
109       struct gen5_sampler_default_color *sdc;
110
111       sdc = brw_state_batch(brw, sizeof(*sdc), 32, &brw->wm.sdc_offset[unit]);
112
113       memset(sdc, 0, sizeof(*sdc));
114
115       UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[0], color[0]);
116       UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[1], color[1]);
117       UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[2], color[2]);
118       UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[3], color[3]);
119
120       UNCLAMPED_FLOAT_TO_USHORT(sdc->us[0], color[0]);
121       UNCLAMPED_FLOAT_TO_USHORT(sdc->us[1], color[1]);
122       UNCLAMPED_FLOAT_TO_USHORT(sdc->us[2], color[2]);
123       UNCLAMPED_FLOAT_TO_USHORT(sdc->us[3], color[3]);
124
125       UNCLAMPED_FLOAT_TO_SHORT(sdc->s[0], color[0]);
126       UNCLAMPED_FLOAT_TO_SHORT(sdc->s[1], color[1]);
127       UNCLAMPED_FLOAT_TO_SHORT(sdc->s[2], color[2]);
128       UNCLAMPED_FLOAT_TO_SHORT(sdc->s[3], color[3]);
129
130       sdc->hf[0] = _mesa_float_to_half(color[0]);
131       sdc->hf[1] = _mesa_float_to_half(color[1]);
132       sdc->hf[2] = _mesa_float_to_half(color[2]);
133       sdc->hf[3] = _mesa_float_to_half(color[3]);
134
135       sdc->b[0] = sdc->s[0] >> 8;
136       sdc->b[1] = sdc->s[1] >> 8;
137       sdc->b[2] = sdc->s[2] >> 8;
138       sdc->b[3] = sdc->s[3] >> 8;
139
140       sdc->f[0] = color[0];
141       sdc->f[1] = color[1];
142       sdc->f[2] = color[2];
143       sdc->f[3] = color[3];
144    } else {
145       struct brw_sampler_default_color *sdc;
146
147       sdc = brw_state_batch(brw, sizeof(*sdc), 32, &brw->wm.sdc_offset[unit]);
148
149       COPY_4V(sdc->color, color);
150    }
151 }
152
153 /**
154  * Sets the sampler state for a single unit based off of the sampler key
155  * entry.
156  */
157 static void brw_update_sampler_state(struct brw_context *brw,
158                                      int unit,
159                                      struct brw_sampler_state *sampler)
160 {
161    struct intel_context *intel = &brw->intel;
162    struct gl_context *ctx = &intel->ctx;
163    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
164    struct gl_texture_object *texObj = texUnit->_Current;
165    struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit);
166    bool using_nearest = false;
167
168    switch (gl_sampler->MinFilter) {
169    case GL_NEAREST:
170       sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
171       sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
172       using_nearest = true;
173       break;
174    case GL_LINEAR:
175       sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
176       sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
177       break;
178    case GL_NEAREST_MIPMAP_NEAREST:
179       sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
180       sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
181       break;
182    case GL_LINEAR_MIPMAP_NEAREST:
183       sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
184       sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
185       break;
186    case GL_NEAREST_MIPMAP_LINEAR:
187       sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
188       sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
189       break;
190    case GL_LINEAR_MIPMAP_LINEAR:
191       sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
192       sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
193       break;
194    default:
195       break;
196    }
197
198    /* Set Anisotropy: 
199     */
200    if (gl_sampler->MaxAnisotropy > 1.0) {
201       sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC; 
202       sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
203
204       if (gl_sampler->MaxAnisotropy > 2.0) {
205          sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2,
206                                        BRW_ANISORATIO_16);
207       }
208    }
209    else {
210       switch (gl_sampler->MagFilter) {
211       case GL_NEAREST:
212          sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
213          using_nearest = true;
214          break;
215       case GL_LINEAR:
216          sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
217          break;
218       default:
219          break;
220       }  
221    }
222
223    sampler->ss1.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR,
224                                                   using_nearest);
225    sampler->ss1.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS,
226                                                   using_nearest);
227    sampler->ss1.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT,
228                                                   using_nearest);
229
230    if (intel->gen >= 6 &&
231        sampler->ss0.min_filter != sampler->ss0.mag_filter)
232         sampler->ss0.min_mag_neq = 1;
233
234    /* Cube-maps on 965 and later must use the same wrap mode for all 3
235     * coordinate dimensions.  Futher, only CUBE and CLAMP are valid.
236     */
237    if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
238       if (ctx->Texture.CubeMapSeamless &&
239           (gl_sampler->MinFilter != GL_NEAREST ||
240            gl_sampler->MagFilter != GL_NEAREST)) {
241          sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
242          sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
243          sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
244       } else {
245          sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
246          sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
247          sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
248       }
249    } else if (texObj->Target == GL_TEXTURE_1D) {
250       /* There's a bug in 1D texture sampling - it actually pays
251        * attention to the wrap_t value, though it should not.
252        * Override the wrap_t value here to GL_REPEAT to keep
253        * any nonexistent border pixels from floating in.
254        */
255       sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
256    }
257
258
259    /* Set shadow function: 
260     */
261    if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
262       /* Shadowing is "enabled" by emitting a particular sampler
263        * message (sample_c).  So need to recompile WM program when
264        * shadow comparison is enabled on each/any texture unit.
265        */
266       sampler->ss0.shadow_function =
267          intel_translate_shadow_compare_func(gl_sampler->CompareFunc);
268    }
269
270    /* Set LOD bias: 
271     */
272    sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias +
273                                          gl_sampler->LodBias, -16, 15), 6);
274
275    sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
276    sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
277
278    /* Set BaseMipLevel, MaxLOD, MinLOD: 
279     *
280     * XXX: I don't think that using firstLevel, lastLevel works,
281     * because we always setup the surface state as if firstLevel ==
282     * level zero.  Probably have to subtract firstLevel from each of
283     * these:
284     */
285    sampler->ss0.base_level = U_FIXED(0, 1);
286
287    sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 6);
288    sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 6);
289
290    upload_default_color(brw, gl_sampler, unit);
291
292    if (intel->gen >= 6) {
293       sampler->ss2.default_color_pointer = brw->wm.sdc_offset[unit] >> 5;
294    } else {
295       /* reloc */
296       sampler->ss2.default_color_pointer = (intel->batch.bo->offset +
297                                             brw->wm.sdc_offset[unit]) >> 5;
298
299       drm_intel_bo_emit_reloc(intel->batch.bo,
300                               brw->wm.sampler_offset +
301                               unit * sizeof(struct brw_sampler_state) +
302                               offsetof(struct brw_sampler_state, ss2),
303                               intel->batch.bo, brw->wm.sdc_offset[unit],
304                               I915_GEM_DOMAIN_SAMPLER, 0);
305    }
306
307    if (sampler->ss0.min_filter != BRW_MAPFILTER_NEAREST)
308       sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN |
309                                     BRW_ADDRESS_ROUNDING_ENABLE_V_MIN |
310                                     BRW_ADDRESS_ROUNDING_ENABLE_R_MIN;
311    if (sampler->ss0.mag_filter != BRW_MAPFILTER_NEAREST)
312       sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG |
313                                     BRW_ADDRESS_ROUNDING_ENABLE_V_MAG |
314                                     BRW_ADDRESS_ROUNDING_ENABLE_R_MAG;
315 }
316
317
318 /* All samplers must be uploaded in a single contiguous array, which
319  * complicates various things.  However, this is still too confusing -
320  * FIXME: simplify all the different new texture state flags.
321  */
322 static void
323 prepare_wm_samplers(struct brw_context *brw)
324 {
325    struct gl_context *ctx = &brw->intel.ctx;
326    struct brw_sampler_state *samplers;
327    int i;
328
329    brw->wm.sampler_count = 0;
330    for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
331       if (ctx->Texture.Unit[i]._ReallyEnabled)
332          brw->wm.sampler_count = i + 1;
333    }
334
335    if (brw->wm.sampler_count == 0)
336       return;
337
338    samplers = brw_state_batch(brw, brw->wm.sampler_count * sizeof(*samplers),
339                               32, &brw->wm.sampler_offset);
340    memset(samplers, 0, brw->wm.sampler_count * sizeof(*samplers));
341
342    for (i = 0; i < brw->wm.sampler_count; i++) {
343       if (ctx->Texture.Unit[i]._ReallyEnabled)
344          brw_update_sampler_state(brw, i, &samplers[i]);
345    }
346
347    brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
348 }
349
350 const struct brw_tracked_state brw_wm_samplers = {
351    .dirty = {
352       .mesa = _NEW_TEXTURE,
353       .brw = BRW_NEW_BATCH,
354       .cache = 0
355    },
356    .prepare = prepare_wm_samplers,
357 };
358
359