brw_wm_sampler_state.c revision 8abffada70fcd62e3c2dcbcdc6d00d258805326b
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 "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 wrap_r, wrap_s, wrap_t;
99      float maxlod, minlod;
100      float lod_bias;
101      float max_aniso;
102      GLenum minfilter, magfilter;
103      GLenum comparemode;
104      dri_bo *sdc_bo;
105   } sampler[BRW_MAX_TEX_UNIT];
106};
107
108/**
109 * Sets the sampler state for a single unit based off of the sampler key
110 * entry.
111 */
112static void brw_update_sampler_state(struct wm_sampler_entry *key,
113				     dri_bo *sdc_bo,
114				     struct brw_sampler_state *sampler)
115{
116   _mesa_memset(sampler, 0, sizeof(*sampler));
117
118   switch (key->minfilter) {
119   case GL_NEAREST:
120      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
121      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
122      break;
123   case GL_LINEAR:
124      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
125      sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
126      break;
127   case GL_NEAREST_MIPMAP_NEAREST:
128      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
129      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
130      break;
131   case GL_LINEAR_MIPMAP_NEAREST:
132      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
133      sampler->ss0.mip_filter = BRW_MIPFILTER_NEAREST;
134      break;
135   case GL_NEAREST_MIPMAP_LINEAR:
136      sampler->ss0.min_filter = BRW_MAPFILTER_NEAREST;
137      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
138      break;
139   case GL_LINEAR_MIPMAP_LINEAR:
140      sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
141      sampler->ss0.mip_filter = BRW_MIPFILTER_LINEAR;
142      break;
143   default:
144      break;
145   }
146
147   /* Set Anisotropy:
148    */
149   if (key->max_aniso > 1.0) {
150      sampler->ss0.min_filter = BRW_MAPFILTER_ANISOTROPIC;
151      sampler->ss0.mag_filter = BRW_MAPFILTER_ANISOTROPIC;
152
153      if (key->max_aniso > 2.0) {
154	 sampler->ss3.max_aniso = MAX2((key->max_aniso - 2) / 2,
155				       BRW_ANISORATIO_16);
156      }
157   }
158   else {
159      switch (key->magfilter) {
160      case GL_NEAREST:
161	 sampler->ss0.mag_filter = BRW_MAPFILTER_NEAREST;
162	 break;
163      case GL_LINEAR:
164	 sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
165	 break;
166      default:
167	 break;
168      }
169   }
170
171   sampler->ss1.r_wrap_mode = translate_wrap_mode(key->wrap_r);
172   sampler->ss1.s_wrap_mode = translate_wrap_mode(key->wrap_s);
173   sampler->ss1.t_wrap_mode = translate_wrap_mode(key->wrap_t);
174
175   /* Fulsim complains if I don't do this.  Hardware doesn't mind:
176    */
177#if 0
178   if (texObj->Target == GL_TEXTURE_CUBE_MAP_ARB) {
179      sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CUBE;
180      sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CUBE;
181      sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CUBE;
182   }
183#endif
184
185   /* Set shadow function:
186    */
187   if (key->comparemode == GL_COMPARE_R_TO_TEXTURE_ARB) {
188      /* Shadowing is "enabled" by emitting a particular sampler
189       * message (sample_c).  So need to recompile WM program when
190       * shadow comparison is enabled on each/any texture unit.
191       */
192      sampler->ss0.shadow_function =
193	 intel_translate_shadow_compare_func(key->comparemode);
194   }
195
196   /* Set LOD bias:
197    */
198   sampler->ss0.lod_bias = S_FIXED(CLAMP(key->lod_bias, -16, 15), 6);
199
200   sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
201   sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
202
203   /* Set BaseMipLevel, MaxLOD, MinLOD:
204    *
205    * XXX: I don't think that using firstLevel, lastLevel works,
206    * because we always setup the surface state as if firstLevel ==
207    * level zero.  Probably have to subtract firstLevel from each of
208    * these:
209    */
210   sampler->ss0.base_level = U_FIXED(0, 1);
211
212   sampler->ss1.max_lod = U_FIXED(MIN2(MAX2(key->maxlod, 0), 13), 6);
213   sampler->ss1.min_lod = U_FIXED(MIN2(MAX2(key->minlod, 0), 13), 6);
214
215   sampler->ss2.default_color_pointer = sdc_bo->offset >> 5; /* reloc */
216}
217
218/** Sets up the cache key for sampler state for all texture units */
219static void
220brw_wm_sampler_populate_key(struct brw_context *brw,
221			    struct wm_sampler_key *key)
222{
223   int unit;
224
225   memset(key, 0, sizeof(*key));
226
227   for (unit = 0; unit < BRW_MAX_TEX_UNIT; unit++) {
228      if (brw->attribs.Texture->Unit[unit]._ReallyEnabled) {
229	 struct wm_sampler_entry *entry = &key->sampler[unit];
230	 struct gl_texture_unit *texUnit = &brw->attribs.Texture->Unit[unit];
231	 struct gl_texture_object *texObj = texUnit->_Current;
232
233	 entry->wrap_r = texObj->WrapR;
234	 entry->wrap_s = texObj->WrapS;
235	 entry->wrap_t = texObj->WrapT;
236
237	 entry->maxlod = texObj->MaxLod;
238	 entry->minlod = texObj->MinLod;
239	 entry->lod_bias = texUnit->LodBias + texObj->LodBias;
240	 entry->max_aniso = texObj->MaxAnisotropy;
241	 entry->minfilter = texObj->MinFilter;
242	 entry->magfilter = texObj->MagFilter;
243	 entry->comparemode = texObj->CompareMode;
244
245	 dri_bo_unreference(brw->wm.sdc_bo[unit]);
246	 brw->wm.sdc_bo[unit] = upload_default_color(brw, texObj->BorderColor);
247
248	 key->sampler_count = unit + 1;
249      }
250   }
251}
252
253/* All samplers must be uploaded in a single contiguous array, which
254 * complicates various things.  However, this is still too confusing -
255 * FIXME: simplify all the different new texture state flags.
256 */
257static void upload_wm_samplers( struct brw_context *brw )
258{
259   struct wm_sampler_key key;
260   int i;
261
262   brw_wm_sampler_populate_key(brw, &key);
263
264   if (brw->wm.sampler_count != key.sampler_count) {
265      brw->wm.sampler_count = key.sampler_count;
266      brw->state.dirty.cache |= CACHE_NEW_SAMPLER;
267   }
268
269   dri_bo_unreference(brw->wm.sampler_bo);
270   brw->wm.sampler_bo = NULL;
271   if (brw->wm.sampler_count == 0)
272      return;
273
274   brw->wm.sampler_bo = brw_search_cache(&brw->cache, BRW_SAMPLER,
275					 &key, sizeof(key),
276					 brw->wm.sdc_bo, key.sampler_count,
277					 NULL);
278
279   /* If we didnt find it in the cache, compute the state and put it in the
280    * cache.
281    */
282   if (brw->wm.sampler_bo == NULL) {
283      struct brw_sampler_state sampler[BRW_MAX_TEX_UNIT];
284
285      memset(sampler, 0, sizeof(sampler));
286      for (i = 0; i < key.sampler_count; i++) {
287	 if (brw->wm.sdc_bo[i] == NULL)
288	    continue;
289
290	 brw_update_sampler_state(&key.sampler[i], brw->wm.sdc_bo[i],
291				  &sampler[i]);
292      }
293
294      brw->wm.sampler_bo = brw_upload_cache(&brw->cache, BRW_SAMPLER,
295					    &key, sizeof(key),
296					    brw->wm.sdc_bo, key.sampler_count,
297					    &sampler, sizeof(sampler),
298					    NULL, NULL);
299
300      /* Emit SDC relocations */
301      for (i = 0; i < BRW_MAX_TEX_UNIT; i++) {
302	 if (!brw->attribs.Texture->Unit[i]._ReallyEnabled)
303	    continue;
304
305	 dri_emit_reloc(brw->wm.sampler_bo,
306			DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ,
307			0,
308			i * sizeof(struct brw_sampler_state) +
309			offsetof(struct brw_sampler_state, ss2),
310			brw->wm.sdc_bo[i]);
311      }
312   }
313}
314
315const struct brw_tracked_state brw_wm_samplers = {
316   .dirty = {
317      .mesa = _NEW_TEXTURE,
318      .brw = 0,
319      .cache = 0
320   },
321   .update = upload_wm_samplers,
322};
323
324
325