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
47uint32_t
48translate_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 */
81void
82upload_default_color(struct brw_context *brw, struct gl_sampler_object *sampler,
83		     int unit, int ss_index)
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, AUB_TRACE_SAMPLER_DEFAULT_COLOR,
112			    sizeof(*sdc), 32, &brw->wm.sdc_offset[ss_index]);
113
114      memset(sdc, 0, sizeof(*sdc));
115
116      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[0], color[0]);
117      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[1], color[1]);
118      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[2], color[2]);
119      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[3], color[3]);
120
121      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[0], color[0]);
122      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[1], color[1]);
123      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[2], color[2]);
124      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[3], color[3]);
125
126      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[0], color[0]);
127      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[1], color[1]);
128      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[2], color[2]);
129      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[3], color[3]);
130
131      sdc->hf[0] = _mesa_float_to_half(color[0]);
132      sdc->hf[1] = _mesa_float_to_half(color[1]);
133      sdc->hf[2] = _mesa_float_to_half(color[2]);
134      sdc->hf[3] = _mesa_float_to_half(color[3]);
135
136      sdc->b[0] = sdc->s[0] >> 8;
137      sdc->b[1] = sdc->s[1] >> 8;
138      sdc->b[2] = sdc->s[2] >> 8;
139      sdc->b[3] = sdc->s[3] >> 8;
140
141      sdc->f[0] = color[0];
142      sdc->f[1] = color[1];
143      sdc->f[2] = color[2];
144      sdc->f[3] = color[3];
145   } else {
146      struct brw_sampler_default_color *sdc;
147
148      sdc = brw_state_batch(brw, AUB_TRACE_SAMPLER_DEFAULT_COLOR,
149			    sizeof(*sdc), 32, &brw->wm.sdc_offset[ss_index]);
150
151      COPY_4V(sdc->color, color);
152   }
153}
154
155/**
156 * Sets the sampler state for a single unit based off of the sampler key
157 * entry.
158 */
159static void brw_update_sampler_state(struct brw_context *brw,
160				     int unit,
161                                     int ss_index,
162				     struct brw_sampler_state *sampler)
163{
164   struct intel_context *intel = &brw->intel;
165   struct gl_context *ctx = &intel->ctx;
166   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
167   struct gl_texture_object *texObj = texUnit->_Current;
168   struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit);
169   bool using_nearest = false;
170
171   /* These don't use samplers at all. */
172   if (texObj->Target == GL_TEXTURE_BUFFER)
173      return;
174
175   switch (gl_sampler->MinFilter) {
176   case GL_NEAREST:
177      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
178      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
179      using_nearest = true;
180      break;
181   case GL_LINEAR:
182      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
183      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
184      break;
185   case GL_NEAREST_MIPMAP_NEAREST:
186      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
187      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
188      break;
189   case GL_LINEAR_MIPMAP_NEAREST:
190      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
191      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
192      break;
193   case GL_NEAREST_MIPMAP_LINEAR:
194      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
195      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
196      break;
197   case GL_LINEAR_MIPMAP_LINEAR:
198      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
199      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
200      break;
201   default:
202      break;
203   }
204
205   /* Set Anisotropy:
206    */
207   if (gl_sampler->MaxAnisotropy > 1.0) {
208      sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC;
209      sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
210
211      if (gl_sampler->MaxAnisotropy > 2.0) {
212	 sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2,
213				       BRW_ANISORATIO_16);
214      }
215   }
216   else {
217      switch (gl_sampler->MagFilter) {
218      case GL_NEAREST:
219	 sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
220	 using_nearest = true;
221	 break;
222      case GL_LINEAR:
223	 sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
224	 break;
225      default:
226	 break;
227      }
228   }
229
230   sampler->ss1.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR,
231						  using_nearest);
232   sampler->ss1.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS,
233						  using_nearest);
234   sampler->ss1.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT,
235						  using_nearest);
236
237   if (intel->gen >= 6 &&
238       sampler->ss0.min_filter != sampler->ss0.mag_filter)
239	sampler->ss0.min_mag_neq = 1;
240
241   /* Cube-maps on 965 and later must use the same wrap mode for all 3
242    * coordinate dimensions.  Futher, only CUBE and CLAMP are valid.
243    */
244   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
245      if (ctx->Texture.CubeMapSeamless &&
246	  (gl_sampler->MinFilter != GL_NEAREST ||
247	   gl_sampler->MagFilter != GL_NEAREST)) {
248	 sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
249	 sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
250	 sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
251      } else {
252	 sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
253	 sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
254	 sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
255      }
256   } else if (texObj->Target == GL_TEXTURE_1D) {
257      /* There's a bug in 1D texture sampling - it actually pays
258       * attention to the wrap_t value, though it should not.
259       * Override the wrap_t value here to GL_REPEAT to keep
260       * any nonexistent border pixels from floating in.
261       */
262      sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
263   }
264
265
266   /* Set shadow function:
267    */
268   if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
269      /* Shadowing is "enabled" by emitting a particular sampler
270       * message (sample_c).  So need to recompile WM program when
271       * shadow comparison is enabled on each/any texture unit.
272       */
273      sampler->ss0.shadow_function =
274	 intel_translate_shadow_compare_func(gl_sampler->CompareFunc);
275   }
276
277   /* Set LOD bias:
278    */
279   sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias +
280					 gl_sampler->LodBias, -16, 15), 6);
281
282   sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
283   sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
284
285   /* Set BaseMipLevel, MaxLOD, MinLOD:
286    *
287    * XXX: I don't think that using firstLevel, lastLevel works,
288    * because we always setup the surface state as if firstLevel ==
289    * level zero.  Probably have to subtract firstLevel from each of
290    * these:
291    */
292   sampler->ss0.base_level = U_FIXED(0, 1);
293
294   sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 6);
295   sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 6);
296
297   /* On Gen6+, the sampler can handle non-normalized texture
298    * rectangle coordinates natively
299    */
300   if (intel->gen >= 6 && texObj->Target == GL_TEXTURE_RECTANGLE) {
301      sampler->ss3.non_normalized_coord = 1;
302   }
303
304   upload_default_color(brw, gl_sampler, unit, ss_index);
305
306   if (intel->gen >= 6) {
307      sampler->ss2.default_color_pointer = brw->wm.sdc_offset[ss_index] >> 5;
308   } else {
309      /* reloc */
310      sampler->ss2.default_color_pointer = (intel->batch.bo->offset +
311					    brw->wm.sdc_offset[ss_index]) >> 5;
312
313      drm_intel_bo_emit_reloc(intel->batch.bo,
314			      brw->sampler.offset +
315			      ss_index * sizeof(struct brw_sampler_state) +
316			      offsetof(struct brw_sampler_state, ss2),
317			      intel->batch.bo, brw->wm.sdc_offset[ss_index],
318			      I915_GEM_DOMAIN_SAMPLER, 0);
319   }
320
321   if (sampler->ss0.min_filter != BRW_MAPFILTER_NEAREST)
322      sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN |
323                                    BRW_ADDRESS_ROUNDING_ENABLE_V_MIN |
324                                    BRW_ADDRESS_ROUNDING_ENABLE_R_MIN;
325   if (sampler->ss0.mag_filter != BRW_MAPFILTER_NEAREST)
326      sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG |
327                                    BRW_ADDRESS_ROUNDING_ENABLE_V_MAG |
328                                    BRW_ADDRESS_ROUNDING_ENABLE_R_MAG;
329}
330
331
332static void
333brw_upload_samplers(struct brw_context *brw)
334{
335   struct gl_context *ctx = &brw->intel.ctx;
336   struct brw_sampler_state *samplers;
337
338   /* BRW_NEW_VERTEX_PROGRAM and BRW_NEW_FRAGMENT_PROGRAM */
339   struct gl_program *vs = (struct gl_program *) brw->vertex_program;
340   struct gl_program *fs = (struct gl_program *) brw->fragment_program;
341
342   GLbitfield SamplersUsed = vs->SamplersUsed | fs->SamplersUsed;
343
344   /* ARB programs use the texture unit number as the sampler index, so we
345    * need to find the highest unit used.  A bit-count will not work.
346    */
347   brw->sampler.count = _mesa_fls(SamplersUsed);
348
349   if (brw->sampler.count == 0)
350      return;
351
352   samplers = brw_state_batch(brw, AUB_TRACE_SAMPLER_STATE,
353			      brw->sampler.count * sizeof(*samplers),
354			      32, &brw->sampler.offset);
355   memset(samplers, 0, brw->sampler.count * sizeof(*samplers));
356
357   for (unsigned s = 0; s < brw->sampler.count; s++) {
358      if (SamplersUsed & (1 << s)) {
359         const unsigned unit = (fs->SamplersUsed & (1 << s)) ?
360            fs->SamplerUnits[s] : vs->SamplerUnits[s];
361         if (ctx->Texture.Unit[unit]._ReallyEnabled)
362            brw_update_sampler_state(brw, unit, s, &samplers[s]);
363      }
364   }
365
366   brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
367}
368
369const struct brw_tracked_state brw_samplers = {
370   .dirty = {
371      .mesa = _NEW_TEXTURE,
372      .brw = BRW_NEW_BATCH |
373             BRW_NEW_VERTEX_PROGRAM |
374             BRW_NEW_FRAGMENT_PROGRAM,
375      .cache = 0
376   },
377   .emit = brw_upload_samplers,
378};
379
380
381