mesa: move max texture image unit constants to gl_program_constants
[mesa.git] / src / mesa / swrast / s_texcombine.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.5
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions 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 MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #include "main/glheader.h"
29 #include "main/context.h"
30 #include "main/colormac.h"
31 #include "main/imports.h"
32 #include "main/pixeltransfer.h"
33 #include "main/samplerobj.h"
34 #include "program/prog_instruction.h"
35
36 #include "s_context.h"
37 #include "s_texcombine.h"
38
39
40 /**
41 * Pointer to array of float[4]
42 * This type makes the code below more concise and avoids a lot of casting.
43 */
44 typedef float (*float4_array)[4];
45
46
47 /**
48 * Return array of texels for given unit.
49 */
50 static inline float4_array
51 get_texel_array(SWcontext *swrast, GLuint unit)
52 {
53 #ifdef _OPENMP
54 return (float4_array) (swrast->TexelBuffer + unit * SWRAST_MAX_WIDTH * 4 * omp_get_num_threads() + (SWRAST_MAX_WIDTH * 4 * omp_get_thread_num()));
55 #else
56 return (float4_array) (swrast->TexelBuffer + unit * SWRAST_MAX_WIDTH * 4);
57 #endif
58 }
59
60
61
62 /**
63 * Do texture application for:
64 * GL_EXT_texture_env_combine
65 * GL_ARB_texture_env_combine
66 * GL_EXT_texture_env_dot3
67 * GL_ARB_texture_env_dot3
68 * GL_ATI_texture_env_combine3
69 * GL_NV_texture_env_combine4
70 * conventional GL texture env modes
71 *
72 * \param ctx rendering context
73 * \param unit the texture combiner unit
74 * \param primary_rgba incoming fragment color array
75 * \param texelBuffer pointer to texel colors for all texture units
76 *
77 * \param span two fields are used in this function:
78 * span->end: number of fragments to process
79 * span->array->rgba: incoming/result fragment colors
80 */
81 static void
82 texture_combine( struct gl_context *ctx, GLuint unit,
83 const float4_array primary_rgba,
84 const GLfloat *texelBuffer,
85 SWspan *span )
86 {
87 SWcontext *swrast = SWRAST_CONTEXT(ctx);
88 const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
89 const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine;
90 float4_array argRGB[MAX_COMBINER_TERMS];
91 float4_array argA[MAX_COMBINER_TERMS];
92 const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB);
93 const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA);
94 const GLuint numArgsRGB = combine->_NumArgsRGB;
95 const GLuint numArgsA = combine->_NumArgsA;
96 float4_array ccolor[4], rgba;
97 GLuint i, term;
98 GLuint n = span->end;
99 GLchan (*rgbaChan)[4] = span->array->rgba;
100
101 /* alloc temp pixel buffers */
102 rgba = malloc(4 * n * sizeof(GLfloat));
103 if (!rgba) {
104 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
105 return;
106 }
107
108 for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
109 ccolor[i] = malloc(4 * n * sizeof(GLfloat));
110 if (!ccolor[i]) {
111 while (i) {
112 free(ccolor[i]);
113 i--;
114 }
115 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
116 free(rgba);
117 return;
118 }
119 }
120
121 for (i = 0; i < n; i++) {
122 rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]);
123 rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]);
124 rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]);
125 rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]);
126 }
127
128 /*
129 printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
130 combine->ModeRGB,
131 combine->ModeA,
132 combine->SourceRGB[0],
133 combine->SourceA[0],
134 combine->SourceRGB[1],
135 combine->SourceA[1]);
136 */
137
138 /*
139 * Do operand setup for up to 4 operands. Loop over the terms.
140 */
141 for (term = 0; term < numArgsRGB; term++) {
142 const GLenum srcRGB = combine->SourceRGB[term];
143 const GLenum operandRGB = combine->OperandRGB[term];
144
145 switch (srcRGB) {
146 case GL_TEXTURE:
147 argRGB[term] = get_texel_array(swrast, unit);
148 break;
149 case GL_PRIMARY_COLOR:
150 argRGB[term] = primary_rgba;
151 break;
152 case GL_PREVIOUS:
153 argRGB[term] = rgba;
154 break;
155 case GL_CONSTANT:
156 {
157 float4_array c = ccolor[term];
158 GLfloat red = textureUnit->EnvColor[0];
159 GLfloat green = textureUnit->EnvColor[1];
160 GLfloat blue = textureUnit->EnvColor[2];
161 GLfloat alpha = textureUnit->EnvColor[3];
162 for (i = 0; i < n; i++) {
163 ASSIGN_4V(c[i], red, green, blue, alpha);
164 }
165 argRGB[term] = ccolor[term];
166 }
167 break;
168 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
169 */
170 case GL_ZERO:
171 {
172 float4_array c = ccolor[term];
173 for (i = 0; i < n; i++) {
174 ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F);
175 }
176 argRGB[term] = ccolor[term];
177 }
178 break;
179 case GL_ONE:
180 {
181 float4_array c = ccolor[term];
182 for (i = 0; i < n; i++) {
183 ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F);
184 }
185 argRGB[term] = ccolor[term];
186 }
187 break;
188 default:
189 /* ARB_texture_env_crossbar source */
190 {
191 const GLuint srcUnit = srcRGB - GL_TEXTURE0;
192 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
193 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
194 goto end;
195 argRGB[term] = get_texel_array(swrast, srcUnit);
196 }
197 }
198
199 if (operandRGB != GL_SRC_COLOR) {
200 float4_array src = argRGB[term];
201 float4_array dst = ccolor[term];
202
203 /* point to new arg[term] storage */
204 argRGB[term] = ccolor[term];
205
206 switch (operandRGB) {
207 case GL_ONE_MINUS_SRC_COLOR:
208 for (i = 0; i < n; i++) {
209 dst[i][RCOMP] = 1.0F - src[i][RCOMP];
210 dst[i][GCOMP] = 1.0F - src[i][GCOMP];
211 dst[i][BCOMP] = 1.0F - src[i][BCOMP];
212 }
213 break;
214 case GL_SRC_ALPHA:
215 for (i = 0; i < n; i++) {
216 dst[i][RCOMP] =
217 dst[i][GCOMP] =
218 dst[i][BCOMP] = src[i][ACOMP];
219 }
220 break;
221 case GL_ONE_MINUS_SRC_ALPHA:
222 for (i = 0; i < n; i++) {
223 dst[i][RCOMP] =
224 dst[i][GCOMP] =
225 dst[i][BCOMP] = 1.0F - src[i][ACOMP];
226 }
227 break;
228 default:
229 _mesa_problem(ctx, "Bad operandRGB");
230 }
231 }
232 }
233
234 /*
235 * Set up the argA[term] pointers
236 */
237 for (term = 0; term < numArgsA; term++) {
238 const GLenum srcA = combine->SourceA[term];
239 const GLenum operandA = combine->OperandA[term];
240
241 switch (srcA) {
242 case GL_TEXTURE:
243 argA[term] = get_texel_array(swrast, unit);
244 break;
245 case GL_PRIMARY_COLOR:
246 argA[term] = primary_rgba;
247 break;
248 case GL_PREVIOUS:
249 argA[term] = rgba;
250 break;
251 case GL_CONSTANT:
252 {
253 float4_array c = ccolor[term];
254 GLfloat alpha = textureUnit->EnvColor[3];
255 for (i = 0; i < n; i++)
256 c[i][ACOMP] = alpha;
257 argA[term] = ccolor[term];
258 }
259 break;
260 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
261 */
262 case GL_ZERO:
263 {
264 float4_array c = ccolor[term];
265 for (i = 0; i < n; i++)
266 c[i][ACOMP] = 0.0F;
267 argA[term] = ccolor[term];
268 }
269 break;
270 case GL_ONE:
271 {
272 float4_array c = ccolor[term];
273 for (i = 0; i < n; i++)
274 c[i][ACOMP] = 1.0F;
275 argA[term] = ccolor[term];
276 }
277 break;
278 default:
279 /* ARB_texture_env_crossbar source */
280 {
281 const GLuint srcUnit = srcA - GL_TEXTURE0;
282 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
283 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
284 goto end;
285 argA[term] = get_texel_array(swrast, srcUnit);
286 }
287 }
288
289 if (operandA == GL_ONE_MINUS_SRC_ALPHA) {
290 float4_array src = argA[term];
291 float4_array dst = ccolor[term];
292 argA[term] = ccolor[term];
293 for (i = 0; i < n; i++) {
294 dst[i][ACOMP] = 1.0F - src[i][ACOMP];
295 }
296 }
297 }
298
299 /* RGB channel combine */
300 {
301 float4_array arg0 = argRGB[0];
302 float4_array arg1 = argRGB[1];
303 float4_array arg2 = argRGB[2];
304 float4_array arg3 = argRGB[3];
305
306 switch (combine->ModeRGB) {
307 case GL_REPLACE:
308 for (i = 0; i < n; i++) {
309 rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB;
310 rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB;
311 rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB;
312 }
313 break;
314 case GL_MODULATE:
315 for (i = 0; i < n; i++) {
316 rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB;
317 rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB;
318 rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB;
319 }
320 break;
321 case GL_ADD:
322 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
323 /* (a * b) + (c * d) */
324 for (i = 0; i < n; i++) {
325 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
326 arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB;
327 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
328 arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB;
329 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
330 arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB;
331 }
332 }
333 else {
334 /* 2-term addition */
335 for (i = 0; i < n; i++) {
336 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB;
337 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB;
338 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB;
339 }
340 }
341 break;
342 case GL_ADD_SIGNED:
343 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
344 /* (a * b) + (c * d) - 0.5 */
345 for (i = 0; i < n; i++) {
346 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
347 arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB;
348 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
349 arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB;
350 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
351 arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB;
352 }
353 }
354 else {
355 for (i = 0; i < n; i++) {
356 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB;
357 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB;
358 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB;
359 }
360 }
361 break;
362 case GL_INTERPOLATE:
363 for (i = 0; i < n; i++) {
364 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
365 arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB;
366 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
367 arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB;
368 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
369 arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB;
370 }
371 break;
372 case GL_SUBTRACT:
373 for (i = 0; i < n; i++) {
374 rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB;
375 rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB;
376 rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB;
377 }
378 break;
379 case GL_DOT3_RGB_EXT:
380 case GL_DOT3_RGBA_EXT:
381 /* Do not scale the result by 1 2 or 4 */
382 for (i = 0; i < n; i++) {
383 GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
384 (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
385 (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
386 * 4.0F;
387 dot = CLAMP(dot, 0.0F, 1.0F);
388 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
389 }
390 break;
391 case GL_DOT3_RGB:
392 case GL_DOT3_RGBA:
393 /* DO scale the result by 1 2 or 4 */
394 for (i = 0; i < n; i++) {
395 GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
396 (arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
397 (arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
398 * 4.0F * scaleRGB;
399 dot = CLAMP(dot, 0.0F, 1.0F);
400 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
401 }
402 break;
403 case GL_MODULATE_ADD_ATI:
404 for (i = 0; i < n; i++) {
405 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
406 arg1[i][RCOMP]) * scaleRGB;
407 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
408 arg1[i][GCOMP]) * scaleRGB;
409 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
410 arg1[i][BCOMP]) * scaleRGB;
411 }
412 break;
413 case GL_MODULATE_SIGNED_ADD_ATI:
414 for (i = 0; i < n; i++) {
415 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
416 arg1[i][RCOMP] - 0.5F) * scaleRGB;
417 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
418 arg1[i][GCOMP] - 0.5F) * scaleRGB;
419 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
420 arg1[i][BCOMP] - 0.5F) * scaleRGB;
421 }
422 break;
423 case GL_MODULATE_SUBTRACT_ATI:
424 for (i = 0; i < n; i++) {
425 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) -
426 arg1[i][RCOMP]) * scaleRGB;
427 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) -
428 arg1[i][GCOMP]) * scaleRGB;
429 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) -
430 arg1[i][BCOMP]) * scaleRGB;
431 }
432 break;
433 case GL_BUMP_ENVMAP_ATI:
434 /* this produces a fixed rgba color, and the coord calc is done elsewhere */
435 for (i = 0; i < n; i++) {
436 /* rgba result is 0,0,0,1 */
437 rgba[i][RCOMP] = 0.0;
438 rgba[i][GCOMP] = 0.0;
439 rgba[i][BCOMP] = 0.0;
440 rgba[i][ACOMP] = 1.0;
441 }
442 goto end; /* no alpha processing */
443 default:
444 _mesa_problem(ctx, "invalid combine mode");
445 }
446 }
447
448 /* Alpha channel combine */
449 {
450 float4_array arg0 = argA[0];
451 float4_array arg1 = argA[1];
452 float4_array arg2 = argA[2];
453 float4_array arg3 = argA[3];
454
455 switch (combine->ModeA) {
456 case GL_REPLACE:
457 for (i = 0; i < n; i++) {
458 rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA;
459 }
460 break;
461 case GL_MODULATE:
462 for (i = 0; i < n; i++) {
463 rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA;
464 }
465 break;
466 case GL_ADD:
467 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
468 /* (a * b) + (c * d) */
469 for (i = 0; i < n; i++) {
470 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
471 arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA;
472 }
473 }
474 else {
475 /* two-term add */
476 for (i = 0; i < n; i++) {
477 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA;
478 }
479 }
480 break;
481 case GL_ADD_SIGNED:
482 if (textureUnit->EnvMode == GL_COMBINE4_NV) {
483 /* (a * b) + (c * d) - 0.5 */
484 for (i = 0; i < n; i++) {
485 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
486 arg2[i][ACOMP] * arg3[i][ACOMP] -
487 0.5F) * scaleA;
488 }
489 }
490 else {
491 /* a + b - 0.5 */
492 for (i = 0; i < n; i++) {
493 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA;
494 }
495 }
496 break;
497 case GL_INTERPOLATE:
498 for (i = 0; i < n; i++) {
499 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
500 arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP]))
501 * scaleA;
502 }
503 break;
504 case GL_SUBTRACT:
505 for (i = 0; i < n; i++) {
506 rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA;
507 }
508 break;
509 case GL_MODULATE_ADD_ATI:
510 for (i = 0; i < n; i++) {
511 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
512 + arg1[i][ACOMP]) * scaleA;
513 }
514 break;
515 case GL_MODULATE_SIGNED_ADD_ATI:
516 for (i = 0; i < n; i++) {
517 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) +
518 arg1[i][ACOMP] - 0.5F) * scaleA;
519 }
520 break;
521 case GL_MODULATE_SUBTRACT_ATI:
522 for (i = 0; i < n; i++) {
523 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
524 - arg1[i][ACOMP]) * scaleA;
525 }
526 break;
527 default:
528 _mesa_problem(ctx, "invalid combine mode");
529 }
530 }
531
532 /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
533 * This is kind of a kludge. It would have been better if the spec
534 * were written such that the GL_COMBINE_ALPHA value could be set to
535 * GL_DOT3.
536 */
537 if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
538 combine->ModeRGB == GL_DOT3_RGBA) {
539 for (i = 0; i < n; i++) {
540 rgba[i][ACOMP] = rgba[i][RCOMP];
541 }
542 }
543
544 for (i = 0; i < n; i++) {
545 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]);
546 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]);
547 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]);
548 UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]);
549 }
550 /* The span->array->rgba values are of CHAN type so set
551 * span->array->ChanType field accordingly.
552 */
553 span->array->ChanType = CHAN_TYPE;
554
555 end:
556 for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
557 free(ccolor[i]);
558 }
559 free(rgba);
560 }
561
562
563 /**
564 * Apply X/Y/Z/W/0/1 swizzle to an array of colors/texels.
565 * See GL_EXT_texture_swizzle.
566 */
567 static void
568 swizzle_texels(GLuint swizzle, GLuint count, float4_array texels)
569 {
570 const GLuint swzR = GET_SWZ(swizzle, 0);
571 const GLuint swzG = GET_SWZ(swizzle, 1);
572 const GLuint swzB = GET_SWZ(swizzle, 2);
573 const GLuint swzA = GET_SWZ(swizzle, 3);
574 GLfloat vector[6];
575 GLuint i;
576
577 vector[SWIZZLE_ZERO] = 0;
578 vector[SWIZZLE_ONE] = 1.0F;
579
580 for (i = 0; i < count; i++) {
581 vector[SWIZZLE_X] = texels[i][0];
582 vector[SWIZZLE_Y] = texels[i][1];
583 vector[SWIZZLE_Z] = texels[i][2];
584 vector[SWIZZLE_W] = texels[i][3];
585 texels[i][RCOMP] = vector[swzR];
586 texels[i][GCOMP] = vector[swzG];
587 texels[i][BCOMP] = vector[swzB];
588 texels[i][ACOMP] = vector[swzA];
589 }
590 }
591
592
593 /**
594 * Apply texture mapping to a span of fragments.
595 */
596 void
597 _swrast_texture_span( struct gl_context *ctx, SWspan *span )
598 {
599 SWcontext *swrast = SWRAST_CONTEXT(ctx);
600 float4_array primary_rgba;
601 GLuint unit;
602
603 if (!swrast->TexelBuffer) {
604 #ifdef _OPENMP
605 const GLint maxThreads = omp_get_max_threads();
606 #else
607 const GLint maxThreads = 1;
608 #endif
609
610 /* TexelBuffer is also global and normally shared by all SWspan
611 * instances; when running with multiple threads, create one per
612 * thread.
613 */
614 swrast->TexelBuffer =
615 malloc(ctx->Const.FragmentProgram.MaxTextureImageUnits * maxThreads *
616 SWRAST_MAX_WIDTH * 4 * sizeof(GLfloat));
617 if (!swrast->TexelBuffer) {
618 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
619 return;
620 }
621 }
622
623 primary_rgba = malloc(span->end * 4 * sizeof(GLfloat));
624
625 if (!primary_rgba) {
626 _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span");
627 return;
628 }
629
630 ASSERT(span->end <= SWRAST_MAX_WIDTH);
631
632 /*
633 * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
634 */
635 if (swrast->_TextureCombinePrimary) {
636 GLuint i;
637 for (i = 0; i < span->end; i++) {
638 primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]);
639 primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]);
640 primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]);
641 primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]);
642 }
643 }
644
645 /* First must sample all bump maps */
646 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
647 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
648
649 if (texUnit->_ReallyEnabled &&
650 texUnit->_CurrentCombine->ModeRGB == GL_BUMP_ENVMAP_ATI) {
651 const GLfloat (*texcoords)[4] = (const GLfloat (*)[4])
652 span->array->attribs[VARYING_SLOT_TEX0 + unit];
653 float4_array targetcoords =
654 span->array->attribs[VARYING_SLOT_TEX0 +
655 ctx->Texture.Unit[unit].BumpTarget - GL_TEXTURE0];
656
657 const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
658 GLfloat *lambda = span->array->lambda[unit];
659 float4_array texels = get_texel_array(swrast, unit);
660 GLuint i;
661 GLfloat rotMatrix00 = ctx->Texture.Unit[unit].RotMatrix[0];
662 GLfloat rotMatrix01 = ctx->Texture.Unit[unit].RotMatrix[1];
663 GLfloat rotMatrix10 = ctx->Texture.Unit[unit].RotMatrix[2];
664 GLfloat rotMatrix11 = ctx->Texture.Unit[unit].RotMatrix[3];
665
666 /* adjust texture lod (lambda) */
667 if (span->arrayMask & SPAN_LAMBDA) {
668 if (texUnit->LodBias + samp->LodBias != 0.0F) {
669 /* apply LOD bias, but don't clamp yet */
670 const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias,
671 -ctx->Const.MaxTextureLodBias,
672 ctx->Const.MaxTextureLodBias);
673 GLuint i;
674 for (i = 0; i < span->end; i++) {
675 lambda[i] += bias;
676 }
677 }
678
679 if (samp->MinLod != -1000.0 ||
680 samp->MaxLod != 1000.0) {
681 /* apply LOD clamping to lambda */
682 const GLfloat min = samp->MinLod;
683 const GLfloat max = samp->MaxLod;
684 GLuint i;
685 for (i = 0; i < span->end; i++) {
686 GLfloat l = lambda[i];
687 lambda[i] = CLAMP(l, min, max);
688 }
689 }
690 }
691
692 /* Sample the texture (span->end = number of fragments) */
693 swrast->TextureSample[unit]( ctx, samp,
694 ctx->Texture.Unit[unit]._Current,
695 span->end, texcoords, lambda, texels );
696
697 /* manipulate the span values of the bump target
698 not sure this can work correctly even ignoring
699 the problem that channel is unsigned */
700 for (i = 0; i < span->end; i++) {
701 targetcoords[i][0] += (texels[i][0] * rotMatrix00 + texels[i][1] *
702 rotMatrix01) / targetcoords[i][3];
703 targetcoords[i][1] += (texels[i][0] * rotMatrix10 + texels[i][1] *
704 rotMatrix11) / targetcoords[i][3];
705 }
706 }
707 }
708
709 /*
710 * Must do all texture sampling before combining in order to
711 * accomodate GL_ARB_texture_env_crossbar.
712 */
713 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
714 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
715 if (texUnit->_ReallyEnabled &&
716 texUnit->_CurrentCombine->ModeRGB != GL_BUMP_ENVMAP_ATI) {
717 const GLfloat (*texcoords)[4] = (const GLfloat (*)[4])
718 span->array->attribs[VARYING_SLOT_TEX0 + unit];
719 const struct gl_texture_object *curObj = texUnit->_Current;
720 const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
721 GLfloat *lambda = span->array->lambda[unit];
722 float4_array texels = get_texel_array(swrast, unit);
723
724 /* adjust texture lod (lambda) */
725 if (span->arrayMask & SPAN_LAMBDA) {
726 if (texUnit->LodBias + samp->LodBias != 0.0F) {
727 /* apply LOD bias, but don't clamp yet */
728 const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias,
729 -ctx->Const.MaxTextureLodBias,
730 ctx->Const.MaxTextureLodBias);
731 GLuint i;
732 for (i = 0; i < span->end; i++) {
733 lambda[i] += bias;
734 }
735 }
736
737 if (samp->MinLod != -1000.0 ||
738 samp->MaxLod != 1000.0) {
739 /* apply LOD clamping to lambda */
740 const GLfloat min = samp->MinLod;
741 const GLfloat max = samp->MaxLod;
742 GLuint i;
743 for (i = 0; i < span->end; i++) {
744 GLfloat l = lambda[i];
745 lambda[i] = CLAMP(l, min, max);
746 }
747 }
748 }
749 else if (samp->MaxAnisotropy > 1.0 &&
750 samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
751 /* sample_lambda_2d_aniso is beeing used as texture_sample_func,
752 * it requires the current SWspan *span as an additional parameter.
753 * In order to keep the same function signature, the unused lambda
754 * parameter will be modified to actually contain the SWspan pointer.
755 * This is a Hack. To make it right, the texture_sample_func
756 * signature and all implementing functions need to be modified.
757 */
758 /* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */
759 lambda = (GLfloat *)span;
760 }
761
762 /* Sample the texture (span->end = number of fragments) */
763 swrast->TextureSample[unit]( ctx, samp,
764 ctx->Texture.Unit[unit]._Current,
765 span->end, texcoords, lambda, texels );
766
767 /* GL_EXT_texture_swizzle */
768 if (curObj->_Swizzle != SWIZZLE_NOOP) {
769 swizzle_texels(curObj->_Swizzle, span->end, texels);
770 }
771 }
772 }
773
774 /*
775 * OK, now apply the texture (aka texture combine/blend).
776 * We modify the span->color.rgba values.
777 */
778 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
779 if (ctx->Texture.Unit[unit]._ReallyEnabled)
780 texture_combine(ctx, unit, primary_rgba, swrast->TexelBuffer, span);
781 }
782
783 free(primary_rgba);
784 }