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