brw_wm_sampler_state.c revision 3984372104ec6ac5986dedb07b8ca99d53dede18
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/* The brw (and related graphics cores) do not support GL_CLAMP.  The
48 * Intel drivers for "other operating systems" implement GL_CLAMP as
49 * GL_CLAMP_TO_EDGE, so the same is done here.
50 */
51GLuint
52translate_wrap_mode(GLenum wrap)
53{
54   switch( wrap ) {
55   case GL_REPEAT:
56      return BRW_TEXCOORDMODE_WRAP;
57   case GL_CLAMP:
58      return BRW_TEXCOORDMODE_CLAMP;
59   case GL_CLAMP_TO_EDGE:
60      return BRW_TEXCOORDMODE_CLAMP; /* conform likes it this way */
61   case GL_CLAMP_TO_BORDER:
62      return BRW_TEXCOORDMODE_CLAMP_BORDER;
63   case GL_MIRRORED_REPEAT:
64      return BRW_TEXCOORDMODE_MIRROR;
65   default:
66      return BRW_TEXCOORDMODE_WRAP;
67   }
68}
69
70void
71upload_default_color(struct brw_context *brw, struct gl_sampler_object *sampler,
72		     int unit)
73{
74   struct intel_context *intel = &brw->intel;
75   struct gl_context *ctx = &intel->ctx;
76   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
77   struct gl_texture_object *texObj = texUnit->_Current;
78   struct gl_texture_image *firstImage = texObj->Image[0][texObj->BaseLevel];
79   float color[4];
80
81   if (firstImage->_BaseFormat == GL_DEPTH_COMPONENT) {
82      /* GL specs that border color for depth textures is taken from the
83       * R channel, while the hardware uses A.  Spam R into all the
84       * channels for safety.
85       */
86      color[0] = sampler->BorderColor.f[0];
87      color[1] = sampler->BorderColor.f[0];
88      color[2] = sampler->BorderColor.f[0];
89      color[3] = sampler->BorderColor.f[0];
90   } else {
91      color[0] = sampler->BorderColor.f[0];
92      color[1] = sampler->BorderColor.f[1];
93      color[2] = sampler->BorderColor.f[2];
94      color[3] = sampler->BorderColor.f[3];
95   }
96
97   if (intel->gen >= 5) {
98      struct gen5_sampler_default_color *sdc;
99
100      sdc = brw_state_batch(brw, sizeof(*sdc), 32, &brw->wm.sdc_offset[unit]);
101
102      memset(sdc, 0, sizeof(*sdc));
103
104      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[0], color[0]);
105      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[1], color[1]);
106      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[2], color[2]);
107      UNCLAMPED_FLOAT_TO_UBYTE(sdc->ub[3], color[3]);
108
109      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[0], color[0]);
110      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[1], color[1]);
111      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[2], color[2]);
112      UNCLAMPED_FLOAT_TO_USHORT(sdc->us[3], color[3]);
113
114      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[0], color[0]);
115      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[1], color[1]);
116      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[2], color[2]);
117      UNCLAMPED_FLOAT_TO_SHORT(sdc->s[3], color[3]);
118
119      sdc->hf[0] = _mesa_float_to_half(color[0]);
120      sdc->hf[1] = _mesa_float_to_half(color[1]);
121      sdc->hf[2] = _mesa_float_to_half(color[2]);
122      sdc->hf[3] = _mesa_float_to_half(color[3]);
123
124      sdc->b[0] = sdc->s[0] >> 8;
125      sdc->b[1] = sdc->s[1] >> 8;
126      sdc->b[2] = sdc->s[2] >> 8;
127      sdc->b[3] = sdc->s[3] >> 8;
128
129      sdc->f[0] = color[0];
130      sdc->f[1] = color[1];
131      sdc->f[2] = color[2];
132      sdc->f[3] = color[3];
133   } else {
134      struct brw_sampler_default_color *sdc;
135
136      sdc = brw_state_batch(brw, sizeof(*sdc), 32, &brw->wm.sdc_offset[unit]);
137
138      COPY_4V(sdc->color, color);
139   }
140}
141
142/**
143 * Sets the sampler state for a single unit based off of the sampler key
144 * entry.
145 */
146static void brw_update_sampler_state(struct brw_context *brw,
147				     int unit,
148				     struct brw_sampler_state *sampler)
149{
150   struct intel_context *intel = &brw->intel;
151   struct gl_context *ctx = &intel->ctx;
152   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
153   struct gl_texture_object *texObj = texUnit->_Current;
154   struct gl_sampler_object *gl_sampler = _mesa_get_samplerobj(ctx, unit);
155
156   switch (gl_sampler->MinFilter) {
157   case GL_NEAREST:
158      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
159      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
160      break;
161   case GL_LINEAR:
162      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
163      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
164      break;
165   case GL_NEAREST_MIPMAP_NEAREST:
166      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
167      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
168      break;
169   case GL_LINEAR_MIPMAP_NEAREST:
170      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
171      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
172      break;
173   case GL_NEAREST_MIPMAP_LINEAR:
174      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
175      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
176      break;
177   case GL_LINEAR_MIPMAP_LINEAR:
178      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
179      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
180      break;
181   default:
182      break;
183   }
184
185   /* Set Anisotropy:
186    */
187   if (gl_sampler->MaxAnisotropy > 1.0) {
188      sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC;
189      sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
190
191      if (gl_sampler->MaxAnisotropy > 2.0) {
192	 sampler->ss3.max_aniso = MIN2((gl_sampler->MaxAnisotropy - 2) / 2,
193				       BRW_ANISORATIO_16);
194      }
195   }
196   else {
197      switch (gl_sampler->MagFilter) {
198      case GL_NEAREST:
199	 sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
200	 break;
201      case GL_LINEAR:
202	 sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
203	 break;
204      default:
205	 break;
206      }
207   }
208
209   sampler->ss1.r_wrap_mode = translate_wrap_mode(gl_sampler->WrapR);
210   sampler->ss1.s_wrap_mode = translate_wrap_mode(gl_sampler->WrapS);
211   sampler->ss1.t_wrap_mode = translate_wrap_mode(gl_sampler->WrapT);
212
213   if (intel->gen >= 6 &&
214       sampler->ss0.min_filter != sampler->ss0.mag_filter)
215	sampler->ss0.min_mag_neq = 1;
216
217   /* Cube-maps on 965 and later must use the same wrap mode for all 3
218    * coordinate dimensions.  Futher, only CUBE and CLAMP are valid.
219    */
220   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
221      if (ctx->Texture.CubeMapSeamless &&
222	  (gl_sampler->MinFilter != GL_NEAREST ||
223	   gl_sampler->MagFilter != GL_NEAREST)) {
224	 sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
225	 sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
226	 sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
227      } else {
228	 sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
229	 sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
230	 sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
231      }
232   } else if (texObj->Target == GL_TEXTURE_1D) {
233      /* There's a bug in 1D texture sampling - it actually pays
234       * attention to the wrap_t value, though it should not.
235       * Override the wrap_t value here to GL_REPEAT to keep
236       * any nonexistent border pixels from floating in.
237       */
238      sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_WRAP;
239   }
240
241
242   /* Set shadow function:
243    */
244   if (gl_sampler->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
245      /* Shadowing is "enabled" by emitting a particular sampler
246       * message (sample_c).  So need to recompile WM program when
247       * shadow comparison is enabled on each/any texture unit.
248       */
249      sampler->ss0.shadow_function =
250	 intel_translate_shadow_compare_func(gl_sampler->CompareFunc);
251   }
252
253   /* Set LOD bias:
254    */
255   sampler->ss0.lod_bias = S_FIXED(CLAMP(texUnit->LodBias +
256					 gl_sampler->LodBias, -16, 15), 6);
257
258   sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
259   sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
260
261   /* Set BaseMipLevel, MaxLOD, MinLOD:
262    *
263    * XXX: I don't think that using firstLevel, lastLevel works,
264    * because we always setup the surface state as if firstLevel ==
265    * level zero.  Probably have to subtract firstLevel from each of
266    * these:
267    */
268   sampler->ss0.base_level = U_FIXED(0, 1);
269
270   sampler->ss1.max_lod = U_FIXED(CLAMP(gl_sampler->MaxLod, 0, 13), 6);
271   sampler->ss1.min_lod = U_FIXED(CLAMP(gl_sampler->MinLod, 0, 13), 6);
272
273   upload_default_color(brw, gl_sampler, unit);
274
275   if (intel->gen >= 6) {
276      sampler->ss2.default_color_pointer = brw->wm.sdc_offset[unit] >> 5;
277   } else {
278      /* reloc */
279      sampler->ss2.default_color_pointer = (intel->batch.bo->offset +
280					    brw->wm.sdc_offset[unit]) >> 5;
281
282      drm_intel_bo_emit_reloc(intel->batch.bo,
283			      brw->wm.sampler_offset +
284			      unit * sizeof(struct brw_sampler_state) +
285			      offsetof(struct brw_sampler_state, ss2),
286			      intel->batch.bo, brw->wm.sdc_offset[unit],
287			      I915_GEM_DOMAIN_SAMPLER, 0);
288   }
289}
290
291
292/* All samplers must be uploaded in a single contiguous array, which
293 * complicates various things.  However, this is still too confusing -
294 * FIXME: simplify all the different new texture state flags.
295 */
296static void
297prepare_wm_samplers(struct brw_context *brw)
298{
299   struct gl_context *ctx = &brw->intel.ctx;
300   struct brw_sampler_state *samplers;
301   int i;
302
303   brw->wm.sampler_count = 0;
304   for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
305      if (ctx->Texture.Unit[i]._ReallyEnabled)
306	 brw->wm.sampler_count = i + 1;
307   }
308
309   if (brw->wm.sampler_count == 0)
310      return;
311
312   samplers = brw_state_batch(brw, brw->wm.sampler_count * sizeof(*samplers),
313			      32, &brw->wm.sampler_offset);
314   memset(samplers, 0, brw->wm.sampler_count * sizeof(*samplers));
315
316   for (i = 0; i < brw->wm.sampler_count; i++) {
317      if (ctx->Texture.Unit[i]._ReallyEnabled)
318	 brw_update_sampler_state(brw, i, &samplers[i]);
319   }
320
321   brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
322}
323
324const struct brw_tracked_state brw_wm_samplers = {
325   .dirty = {
326      .mesa = _NEW_TEXTURE,
327      .brw = BRW_NEW_BATCH,
328      .cache = 0
329   },
330   .prepare = prepare_wm_samplers,
331};
332
333
334