Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
4 | * All Rights Reserved. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * 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, sub license, 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 portions |
||
16 | * of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
21 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
25 | * |
||
26 | **************************************************************************/ |
||
27 | |||
28 | /* |
||
29 | * Authors: |
||
30 | * Keith Whitwell |
||
31 | * Brian Paul |
||
32 | */ |
||
33 | |||
34 | |||
35 | #include "main/macros.h" |
||
36 | #include "main/mtypes.h" |
||
37 | #include "main/samplerobj.h" |
||
38 | #include "main/texobj.h" |
||
39 | #include "program/prog_instruction.h" |
||
40 | |||
41 | #include "st_context.h" |
||
42 | #include "st_atom.h" |
||
43 | #include "st_texture.h" |
||
44 | #include "st_format.h" |
||
45 | #include "st_cb_texture.h" |
||
46 | #include "pipe/p_context.h" |
||
47 | #include "util/u_format.h" |
||
48 | #include "util/u_inlines.h" |
||
49 | #include "cso_cache/cso_context.h" |
||
50 | |||
51 | |||
52 | /** |
||
53 | * Combine depth texture mode with "swizzle" so that depth mode swizzling |
||
54 | * takes place before texture swizzling, and return the resulting swizzle. |
||
55 | * If the format is not a depth format, return "swizzle" unchanged. |
||
56 | * |
||
57 | * \param format PIPE_FORMAT_*. |
||
58 | * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. |
||
59 | * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA, GL_RED. |
||
60 | */ |
||
61 | static GLuint |
||
62 | apply_depthmode(enum pipe_format format, GLuint swizzle, GLenum depthmode) |
||
63 | { |
||
64 | const struct util_format_description *desc = |
||
65 | util_format_description(format); |
||
66 | unsigned char swiz[4]; |
||
67 | unsigned i; |
||
68 | |||
69 | if (desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS || |
||
70 | desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_NONE) { |
||
71 | /* Not a depth format. */ |
||
72 | return swizzle; |
||
73 | } |
||
74 | |||
75 | for (i = 0; i < 4; i++) |
||
76 | swiz[i] = GET_SWZ(swizzle, i); |
||
77 | |||
78 | switch (depthmode) { |
||
79 | case GL_LUMINANCE: |
||
80 | /* Rewrite reads from W to ONE, and reads from XYZ to XXX. */ |
||
81 | for (i = 0; i < 4; i++) |
||
82 | if (swiz[i] == SWIZZLE_W) |
||
83 | swiz[i] = SWIZZLE_ONE; |
||
84 | else if (swiz[i] < SWIZZLE_W) |
||
85 | swiz[i] = SWIZZLE_X; |
||
86 | break; |
||
87 | |||
88 | case GL_INTENSITY: |
||
89 | /* Rewrite reads from XYZW to XXXX. */ |
||
90 | for (i = 0; i < 4; i++) |
||
91 | if (swiz[i] <= SWIZZLE_W) |
||
92 | swiz[i] = SWIZZLE_X; |
||
93 | break; |
||
94 | |||
95 | case GL_ALPHA: |
||
96 | /* Rewrite reads from W to X, and reads from XYZ to 000. */ |
||
97 | for (i = 0; i < 4; i++) |
||
98 | if (swiz[i] == SWIZZLE_W) |
||
99 | swiz[i] = SWIZZLE_X; |
||
100 | else if (swiz[i] < SWIZZLE_W) |
||
101 | swiz[i] = SWIZZLE_ZERO; |
||
102 | break; |
||
103 | case GL_RED: |
||
104 | /* Rewrite reads W to 1, XYZ to X00 */ |
||
105 | for (i = 0; i < 4; i++) |
||
106 | if (swiz[i] == SWIZZLE_W) |
||
107 | swiz[i] = SWIZZLE_ONE; |
||
108 | else if (swiz[i] == SWIZZLE_Y || swiz[i] == SWIZZLE_Z) |
||
109 | swiz[i] = SWIZZLE_ZERO; |
||
110 | break; |
||
111 | } |
||
112 | |||
113 | return MAKE_SWIZZLE4(swiz[0], swiz[1], swiz[2], swiz[3]); |
||
114 | } |
||
115 | |||
116 | |||
117 | /** |
||
118 | * Return TRUE if the swizzling described by "swizzle" and |
||
119 | * "depthmode" (for depth textures only) is different from the swizzling |
||
120 | * set in the given sampler view. |
||
121 | * |
||
122 | * \param sv A sampler view. |
||
123 | * \param swizzle Texture swizzle, a bitmask computed using MAKE_SWIZZLE4. |
||
124 | * \param depthmode One of GL_LUMINANCE, GL_INTENSITY, GL_ALPHA. |
||
125 | */ |
||
126 | static boolean |
||
127 | check_sampler_swizzle(struct pipe_sampler_view *sv, |
||
128 | GLuint swizzle, GLenum depthmode) |
||
129 | { |
||
130 | swizzle = apply_depthmode(sv->texture->format, swizzle, depthmode); |
||
131 | |||
132 | if ((sv->swizzle_r != GET_SWZ(swizzle, 0)) || |
||
133 | (sv->swizzle_g != GET_SWZ(swizzle, 1)) || |
||
134 | (sv->swizzle_b != GET_SWZ(swizzle, 2)) || |
||
135 | (sv->swizzle_a != GET_SWZ(swizzle, 3))) |
||
136 | return TRUE; |
||
137 | return FALSE; |
||
138 | } |
||
139 | |||
140 | |||
141 | static struct pipe_sampler_view * |
||
142 | st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe, |
||
143 | struct st_texture_object *stObj, |
||
144 | const struct gl_sampler_object *samp, |
||
145 | enum pipe_format format) |
||
146 | { |
||
147 | struct pipe_sampler_view templ; |
||
148 | GLuint swizzle = apply_depthmode(stObj->pt->format, |
||
149 | stObj->base._Swizzle, |
||
150 | stObj->base.DepthMode); |
||
151 | |||
152 | u_sampler_view_default_template(&templ, |
||
153 | stObj->pt, |
||
154 | format); |
||
155 | |||
156 | if (stObj->pt->target == PIPE_BUFFER) { |
||
157 | unsigned base, size; |
||
158 | unsigned f, n; |
||
159 | const struct util_format_description *desc |
||
160 | = util_format_description(templ.format); |
||
161 | |||
162 | base = stObj->base.BufferOffset; |
||
163 | if (base >= stObj->pt->width0) |
||
164 | return NULL; |
||
165 | size = MIN2(stObj->pt->width0 - base, (unsigned)stObj->base.BufferSize); |
||
166 | |||
167 | f = ((base * 8) / desc->block.bits) * desc->block.width; |
||
168 | n = ((size * 8) / desc->block.bits) * desc->block.width; |
||
169 | if (!n) |
||
170 | return NULL; |
||
171 | templ.u.buf.first_element = f; |
||
172 | templ.u.buf.last_element = f + (n - 1); |
||
173 | } else { |
||
174 | templ.u.tex.first_level = stObj->base.BaseLevel; |
||
175 | } |
||
176 | |||
177 | if (swizzle != SWIZZLE_NOOP) { |
||
178 | templ.swizzle_r = GET_SWZ(swizzle, 0); |
||
179 | templ.swizzle_g = GET_SWZ(swizzle, 1); |
||
180 | templ.swizzle_b = GET_SWZ(swizzle, 2); |
||
181 | templ.swizzle_a = GET_SWZ(swizzle, 3); |
||
182 | } |
||
183 | |||
184 | return pipe->create_sampler_view(pipe, stObj->pt, &templ); |
||
185 | } |
||
186 | |||
187 | |||
188 | static struct pipe_sampler_view * |
||
189 | st_get_texture_sampler_view_from_stobj(struct st_texture_object *stObj, |
||
190 | struct pipe_context *pipe, |
||
191 | const struct gl_sampler_object *samp, |
||
192 | enum pipe_format format) |
||
193 | { |
||
194 | if (!stObj || !stObj->pt) { |
||
195 | return NULL; |
||
196 | } |
||
197 | |||
198 | if (!stObj->sampler_view) { |
||
199 | stObj->sampler_view = |
||
200 | st_create_texture_sampler_view_from_stobj(pipe, stObj, samp, format); |
||
201 | } |
||
202 | |||
203 | return stObj->sampler_view; |
||
204 | } |
||
205 | |||
206 | |||
207 | static GLboolean |
||
208 | update_single_texture(struct st_context *st, |
||
209 | struct pipe_sampler_view **sampler_view, |
||
210 | GLuint texUnit) |
||
211 | { |
||
212 | struct pipe_context *pipe = st->pipe; |
||
213 | struct gl_context *ctx = st->ctx; |
||
214 | const struct gl_sampler_object *samp; |
||
215 | struct gl_texture_object *texObj; |
||
216 | struct st_texture_object *stObj; |
||
217 | enum pipe_format view_format; |
||
218 | GLboolean retval; |
||
219 | |||
220 | samp = _mesa_get_samplerobj(ctx, texUnit); |
||
221 | |||
222 | texObj = ctx->Texture.Unit[texUnit]._Current; |
||
223 | |||
224 | if (!texObj) { |
||
225 | texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); |
||
226 | samp = &texObj->Sampler; |
||
227 | } |
||
228 | stObj = st_texture_object(texObj); |
||
229 | |||
230 | retval = st_finalize_texture(ctx, st->pipe, texObj); |
||
231 | if (!retval) { |
||
232 | /* out of mem */ |
||
233 | return GL_FALSE; |
||
234 | } |
||
235 | |||
236 | /* Determine the format of the texture sampler view */ |
||
237 | if (texObj->Target == GL_TEXTURE_BUFFER) { |
||
238 | view_format = |
||
239 | st_mesa_format_to_pipe_format(stObj->base._BufferObjectFormat); |
||
240 | } |
||
241 | else { |
||
242 | view_format = |
||
243 | stObj->surface_based ? stObj->surface_format : stObj->pt->format; |
||
244 | |||
245 | /* If sRGB decoding is off, use the linear format */ |
||
246 | if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) { |
||
247 | view_format = util_format_linear(view_format); |
||
248 | } |
||
249 | } |
||
250 | |||
251 | /* if sampler view has changed dereference it */ |
||
252 | if (stObj->sampler_view) { |
||
253 | if (check_sampler_swizzle(stObj->sampler_view, |
||
254 | stObj->base._Swizzle, |
||
255 | stObj->base.DepthMode) || |
||
256 | (view_format != stObj->sampler_view->format) || |
||
257 | stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { |
||
258 | pipe_sampler_view_reference(&stObj->sampler_view, NULL); |
||
259 | } |
||
260 | } |
||
261 | |||
262 | *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, |
||
263 | samp, |
||
264 | view_format); |
||
265 | return GL_TRUE; |
||
266 | } |
||
267 | |||
268 | |||
269 | |||
270 | static void |
||
271 | update_textures(struct st_context *st, |
||
272 | unsigned shader_stage, |
||
273 | const struct gl_program *prog, |
||
274 | unsigned max_units, |
||
275 | struct pipe_sampler_view **sampler_views, |
||
276 | unsigned *num_textures) |
||
277 | { |
||
278 | const GLuint old_max = *num_textures; |
||
279 | GLbitfield samplers_used = prog->SamplersUsed; |
||
280 | GLuint unit, new_count; |
||
281 | |||
282 | if (samplers_used == 0x0 && old_max == 0) |
||
283 | return; |
||
284 | |||
285 | *num_textures = 0; |
||
286 | |||
287 | /* loop over sampler units (aka tex image units) */ |
||
288 | for (unit = 0; unit < max_units; unit++, samplers_used >>= 1) { |
||
289 | struct pipe_sampler_view *sampler_view = NULL; |
||
290 | |||
291 | if (samplers_used & 1) { |
||
292 | const GLuint texUnit = prog->SamplerUnits[unit]; |
||
293 | GLboolean retval; |
||
294 | |||
295 | retval = update_single_texture(st, &sampler_view, texUnit); |
||
296 | if (retval == GL_FALSE) |
||
297 | continue; |
||
298 | |||
299 | *num_textures = unit + 1; |
||
300 | } |
||
301 | else if (samplers_used == 0 && unit >= old_max) { |
||
302 | /* if we've reset all the old views and we have no more new ones */ |
||
303 | break; |
||
304 | } |
||
305 | |||
306 | pipe_sampler_view_reference(&(sampler_views[unit]), sampler_view); |
||
307 | } |
||
308 | |||
309 | /* Ex: if old_max = 3 and *num_textures = 1, we need to pass an |
||
310 | * array of views={X, NULL, NULL} to unref the old texture views |
||
311 | * at positions [1] and [2]. |
||
312 | */ |
||
313 | new_count = MAX2(*num_textures, old_max); |
||
314 | assert(new_count <= max_units); |
||
315 | |||
316 | cso_set_sampler_views(st->cso_context, |
||
317 | shader_stage, |
||
318 | new_count, |
||
319 | sampler_views); |
||
320 | } |
||
321 | |||
322 | |||
323 | |||
324 | static void |
||
325 | update_vertex_textures(struct st_context *st) |
||
326 | { |
||
327 | const struct gl_context *ctx = st->ctx; |
||
328 | |||
329 | if (ctx->Const.VertexProgram.MaxTextureImageUnits > 0) { |
||
330 | update_textures(st, |
||
331 | PIPE_SHADER_VERTEX, |
||
332 | &ctx->VertexProgram._Current->Base, |
||
333 | ctx->Const.VertexProgram.MaxTextureImageUnits, |
||
334 | st->state.sampler_views[PIPE_SHADER_VERTEX], |
||
335 | &st->state.num_sampler_views[PIPE_SHADER_VERTEX]); |
||
336 | } |
||
337 | } |
||
338 | |||
339 | |||
340 | static void |
||
341 | update_fragment_textures(struct st_context *st) |
||
342 | { |
||
343 | const struct gl_context *ctx = st->ctx; |
||
344 | |||
345 | update_textures(st, |
||
346 | PIPE_SHADER_FRAGMENT, |
||
347 | &ctx->FragmentProgram._Current->Base, |
||
348 | ctx->Const.FragmentProgram.MaxTextureImageUnits, |
||
349 | st->state.sampler_views[PIPE_SHADER_FRAGMENT], |
||
350 | &st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); |
||
351 | } |
||
352 | |||
353 | |||
354 | static void |
||
355 | update_geometry_textures(struct st_context *st) |
||
356 | { |
||
357 | const struct gl_context *ctx = st->ctx; |
||
358 | |||
359 | if (ctx->GeometryProgram._Current) { |
||
360 | update_textures(st, |
||
361 | PIPE_SHADER_GEOMETRY, |
||
362 | &ctx->GeometryProgram._Current->Base, |
||
363 | ctx->Const.FragmentProgram.MaxTextureImageUnits, |
||
364 | st->state.sampler_views[PIPE_SHADER_GEOMETRY], |
||
365 | &st->state.num_sampler_views[PIPE_SHADER_GEOMETRY]); |
||
366 | } |
||
367 | } |
||
368 | |||
369 | |||
370 | const struct st_tracked_state st_update_fragment_texture = { |
||
371 | "st_update_texture", /* name */ |
||
372 | { /* dirty */ |
||
373 | _NEW_TEXTURE, /* mesa */ |
||
374 | ST_NEW_FRAGMENT_PROGRAM, /* st */ |
||
375 | }, |
||
376 | update_fragment_textures /* update */ |
||
377 | }; |
||
378 | |||
379 | |||
380 | const struct st_tracked_state st_update_vertex_texture = { |
||
381 | "st_update_vertex_texture", /* name */ |
||
382 | { /* dirty */ |
||
383 | _NEW_TEXTURE, /* mesa */ |
||
384 | ST_NEW_VERTEX_PROGRAM, /* st */ |
||
385 | }, |
||
386 | update_vertex_textures /* update */ |
||
387 | }; |
||
388 | |||
389 | |||
390 | const struct st_tracked_state st_update_geometry_texture = { |
||
391 | "st_update_geometry_texture", /* name */ |
||
392 | { /* dirty */ |
||
393 | _NEW_TEXTURE, /* mesa */ |
||
394 | ST_NEW_GEOMETRY_PROGRAM, /* st */ |
||
395 | }, |
||
396 | update_geometry_textures /* update */ |
||
397 | }; |
||
398 | |||
399 | |||
400 | |||
401 | static void |
||
402 | finalize_textures(struct st_context *st) |
||
403 | { |
||
404 | struct gl_context *ctx = st->ctx; |
||
405 | struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; |
||
406 | const GLboolean prev_missing_textures = st->missing_textures; |
||
407 | GLuint su; |
||
408 | |||
409 | st->missing_textures = GL_FALSE; |
||
410 | |||
411 | for (su = 0; su < ctx->Const.MaxTextureCoordUnits; su++) { |
||
412 | if (fprog->Base.SamplersUsed & (1 << su)) { |
||
413 | const GLuint texUnit = fprog->Base.SamplerUnits[su]; |
||
414 | struct gl_texture_object *texObj |
||
415 | = ctx->Texture.Unit[texUnit]._Current; |
||
416 | |||
417 | if (texObj) { |
||
418 | GLboolean retval; |
||
419 | |||
420 | retval = st_finalize_texture(ctx, st->pipe, texObj); |
||
421 | if (!retval) { |
||
422 | /* out of mem */ |
||
423 | st->missing_textures = GL_TRUE; |
||
424 | continue; |
||
425 | } |
||
426 | } |
||
427 | } |
||
428 | } |
||
429 | |||
430 | if (prev_missing_textures != st->missing_textures) |
||
431 | st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; |
||
432 | } |
||
433 | |||
434 | |||
435 | const struct st_tracked_state st_finalize_textures = { |
||
436 | "st_finalize_textures", /* name */ |
||
437 | { /* dirty */ |
||
438 | _NEW_TEXTURE, /* mesa */ |
||
439 | 0, /* st */ |
||
440 | }, |
||
441 | finalize_textures /* update */ |
||
442 | };><>>=>>>>>=>>>>> |