1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 * Generate fragment programs to implement pixel transfer ops, such as
30 * scale/bias, colormatrix, colortable, convolution...
36 #include "main/imports.h"
37 #include "main/image.h"
38 #include "main/macros.h"
39 #include "shader/program.h"
40 #include "shader/prog_instruction.h"
41 #include "shader/prog_parameter.h"
42 #include "shader/prog_print.h"
44 #include "st_context.h"
45 #include "st_format.h"
46 #include "st_program.h"
47 #include "st_texture.h"
49 #include "pipe/p_screen.h"
50 #include "pipe/p_context.h"
51 #include "pipe/p_inlines.h"
52 #include "util/u_pack_color.h"
57 GLuint scaleAndBias
:1;
59 GLuint colorMatrixPostScaleBias
:1;
63 GLfloat Maps
[3][256][4];
66 pipeline_stage Stages
[STAGE_MAX
];
67 GLboolean StagesUsed
[STAGE_MAX
];
68 GLfloat Scale1
[4], Bias1
[4];
69 GLfloat Scale2
[4], Bias2
[4];
75 is_identity(const GLfloat m
[16])
78 for (i
= 0; i
< 16; i
++) {
79 const int row
= i
% 4, col
= i
/ 4;
80 const float val
= (GLfloat
)(row
== col
);
89 make_state_key(GLcontext
*ctx
, struct state_key
*key
)
91 static const GLfloat zero
[4] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
};
92 static const GLfloat one
[4] = { 1.0f
, 1.0f
, 1.0f
, 1.0f
};
94 memset(key
, 0, sizeof(*key
));
96 if (ctx
->Pixel
.RedBias
!= 0.0 || ctx
->Pixel
.RedScale
!= 1.0 ||
97 ctx
->Pixel
.GreenBias
!= 0.0 || ctx
->Pixel
.GreenScale
!= 1.0 ||
98 ctx
->Pixel
.BlueBias
!= 0.0 || ctx
->Pixel
.BlueScale
!= 1.0 ||
99 ctx
->Pixel
.AlphaBias
!= 0.0 || ctx
->Pixel
.AlphaScale
!= 1.0) {
100 key
->scaleAndBias
= 1;
103 if (!is_identity(ctx
->ColorMatrixStack
.Top
->m
)) {
104 key
->colorMatrix
= 1;
107 if (!TEST_EQ_4V(ctx
->Pixel
.PostColorMatrixScale
, one
) ||
108 !TEST_EQ_4V(ctx
->Pixel
.PostColorMatrixBias
, zero
)) {
109 key
->colorMatrixPostScaleBias
= 1;
112 key
->pixelMaps
= ctx
->Pixel
.MapColorFlag
;
116 static struct pipe_texture
*
117 create_color_map_texture(GLcontext
*ctx
)
119 struct pipe_context
*pipe
= ctx
->st
->pipe
;
120 struct pipe_texture
*pt
;
121 enum pipe_format format
;
122 const uint texSize
= 256; /* simple, and usually perfect */
124 /* find an RGBA texture format */
125 format
= st_choose_format(pipe
, GL_RGBA
, PIPE_TEXTURE_2D
, PIPE_TEXTURE_USAGE_SAMPLER
);
127 /* create texture for color map/table */
128 pt
= st_texture_create(ctx
->st
, PIPE_TEXTURE_2D
, format
, 0,
129 texSize
, texSize
, 1, 0,
130 PIPE_TEXTURE_USAGE_SAMPLER
);
136 * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
139 load_color_map_texture(GLcontext
*ctx
, struct pipe_texture
*pt
)
141 struct pipe_context
*pipe
= ctx
->st
->pipe
;
142 struct pipe_screen
*screen
= pipe
->screen
;
143 struct pipe_surface
*surface
;
144 const GLuint rSize
= ctx
->PixelMaps
.RtoR
.Size
;
145 const GLuint gSize
= ctx
->PixelMaps
.GtoG
.Size
;
146 const GLuint bSize
= ctx
->PixelMaps
.BtoB
.Size
;
147 const GLuint aSize
= ctx
->PixelMaps
.AtoA
.Size
;
148 const uint texSize
= pt
->width
[0];
152 surface
= screen
->get_tex_surface(screen
, pt
, 0, 0, 0,
153 PIPE_BUFFER_USAGE_CPU_WRITE
);
154 dest
= (uint
*) screen
->surface_map(screen
, surface
,
155 PIPE_BUFFER_USAGE_CPU_WRITE
);
157 /* Pack four 1D maps into a 2D texture:
158 * R map is placed horizontally, indexed by S, in channel 0
159 * G map is placed vertically, indexed by T, in channel 1
160 * B map is placed horizontally, indexed by S, in channel 2
161 * A map is placed vertically, indexed by T, in channel 3
163 for (i
= 0; i
< texSize
; i
++) {
164 for (j
= 0; j
< texSize
; j
++) {
165 int k
= (i
* texSize
+ j
);
166 ubyte r
= ctx
->PixelMaps
.RtoR
.Map8
[j
* rSize
/ texSize
];
167 ubyte g
= ctx
->PixelMaps
.GtoG
.Map8
[i
* gSize
/ texSize
];
168 ubyte b
= ctx
->PixelMaps
.BtoB
.Map8
[j
* bSize
/ texSize
];
169 ubyte a
= ctx
->PixelMaps
.AtoA
.Map8
[i
* aSize
/ texSize
];
170 util_pack_color_ub(r
, g
, b
, a
, pt
->format
, dest
+ k
);
174 screen
->surface_unmap(screen
, surface
);
175 pipe_surface_reference(&surface
, NULL
);
183 * Returns a fragment program which implements the current pixel transfer ops.
185 static struct gl_fragment_program
*
186 get_pixel_transfer_program(GLcontext
*ctx
, const struct state_key
*key
)
188 struct st_context
*st
= ctx
->st
;
189 struct prog_instruction inst
[MAX_INST
];
190 struct gl_program_parameter_list
*params
;
191 struct gl_fragment_program
*fp
;
193 const GLuint colorTemp
= 0;
195 fp
= (struct gl_fragment_program
*)
196 ctx
->Driver
.NewProgram(ctx
, GL_FRAGMENT_PROGRAM_ARB
, 0);
200 params
= _mesa_new_parameter_list();
203 * Get initial pixel color from the texture.
204 * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
206 _mesa_init_instructions(inst
+ ic
, 1);
207 inst
[ic
].Opcode
= OPCODE_TEX
;
208 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
209 inst
[ic
].DstReg
.Index
= colorTemp
;
210 inst
[ic
].SrcReg
[0].File
= PROGRAM_INPUT
;
211 inst
[ic
].SrcReg
[0].Index
= FRAG_ATTRIB_TEX0
;
212 inst
[ic
].TexSrcUnit
= 0;
213 inst
[ic
].TexSrcTarget
= TEXTURE_2D_INDEX
;
215 fp
->Base
.InputsRead
= (1 << FRAG_ATTRIB_TEX0
);
216 fp
->Base
.OutputsWritten
= (1 << FRAG_RESULT_COLR
);
217 fp
->Base
.SamplersUsed
= 0x1; /* sampler 0 (bit 0) is used */
219 if (key
->scaleAndBias
) {
220 static const gl_state_index scale_state
[STATE_LENGTH
] =
221 { STATE_INTERNAL
, STATE_PT_SCALE
, 0, 0, 0 };
222 static const gl_state_index bias_state
[STATE_LENGTH
] =
223 { STATE_INTERNAL
, STATE_PT_BIAS
, 0, 0, 0 };
224 GLfloat scale
[4], bias
[4];
225 GLint scale_p
, bias_p
;
227 scale
[0] = ctx
->Pixel
.RedScale
;
228 scale
[1] = ctx
->Pixel
.GreenScale
;
229 scale
[2] = ctx
->Pixel
.BlueScale
;
230 scale
[3] = ctx
->Pixel
.AlphaScale
;
231 bias
[0] = ctx
->Pixel
.RedBias
;
232 bias
[1] = ctx
->Pixel
.GreenBias
;
233 bias
[2] = ctx
->Pixel
.BlueBias
;
234 bias
[3] = ctx
->Pixel
.AlphaBias
;
236 scale_p
= _mesa_add_state_reference(params
, scale_state
);
237 bias_p
= _mesa_add_state_reference(params
, bias_state
);
239 /* MAD colorTemp, colorTemp, scale, bias; */
240 _mesa_init_instructions(inst
+ ic
, 1);
241 inst
[ic
].Opcode
= OPCODE_MAD
;
242 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
243 inst
[ic
].DstReg
.Index
= colorTemp
;
244 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
245 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
246 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
247 inst
[ic
].SrcReg
[1].Index
= scale_p
;
248 inst
[ic
].SrcReg
[2].File
= PROGRAM_STATE_VAR
;
249 inst
[ic
].SrcReg
[2].Index
= bias_p
;
253 if (key
->pixelMaps
) {
254 const GLuint temp
= 1;
256 /* create the colormap/texture now if not already done */
257 if (!st
->pixel_xfer
.pixelmap_texture
) {
258 st
->pixel_xfer
.pixelmap_texture
= create_color_map_texture(ctx
);
261 /* with a little effort, we can do four pixel map look-ups with
262 * two TEX instructions:
265 /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
266 _mesa_init_instructions(inst
+ ic
, 1);
267 inst
[ic
].Opcode
= OPCODE_TEX
;
268 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
269 inst
[ic
].DstReg
.Index
= temp
;
270 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_XY
; /* write R,G */
271 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
272 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
273 inst
[ic
].TexSrcUnit
= 1;
274 inst
[ic
].TexSrcTarget
= TEXTURE_2D_INDEX
;
277 /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
278 _mesa_init_instructions(inst
+ ic
, 1);
279 inst
[ic
].Opcode
= OPCODE_TEX
;
280 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
281 inst
[ic
].DstReg
.Index
= temp
;
282 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_ZW
; /* write B,A */
283 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
284 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
285 inst
[ic
].SrcReg
[0].Swizzle
= MAKE_SWIZZLE4(SWIZZLE_Z
, SWIZZLE_W
,
286 SWIZZLE_Z
, SWIZZLE_W
);
287 inst
[ic
].TexSrcUnit
= 1;
288 inst
[ic
].TexSrcTarget
= TEXTURE_2D_INDEX
;
291 /* MOV colorTemp, temp; */
292 _mesa_init_instructions(inst
+ ic
, 1);
293 inst
[ic
].Opcode
= OPCODE_MOV
;
294 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
295 inst
[ic
].DstReg
.Index
= colorTemp
;
296 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
297 inst
[ic
].SrcReg
[0].Index
= temp
;
300 fp
->Base
.SamplersUsed
|= (1 << 1); /* sampler 1 is used */
303 if (key
->colorMatrix
) {
304 static const gl_state_index row0_state
[STATE_LENGTH
] =
305 { STATE_COLOR_MATRIX
, 0, 0, 0, 0 };
306 static const gl_state_index row1_state
[STATE_LENGTH
] =
307 { STATE_COLOR_MATRIX
, 0, 1, 1, 0 };
308 static const gl_state_index row2_state
[STATE_LENGTH
] =
309 { STATE_COLOR_MATRIX
, 0, 2, 2, 0 };
310 static const gl_state_index row3_state
[STATE_LENGTH
] =
311 { STATE_COLOR_MATRIX
, 0, 3, 3, 0 };
313 GLint row0_p
= _mesa_add_state_reference(params
, row0_state
);
314 GLint row1_p
= _mesa_add_state_reference(params
, row1_state
);
315 GLint row2_p
= _mesa_add_state_reference(params
, row2_state
);
316 GLint row3_p
= _mesa_add_state_reference(params
, row3_state
);
317 const GLuint temp
= 1;
319 /* DP4 temp.x, colorTemp, matrow0; */
320 _mesa_init_instructions(inst
+ ic
, 1);
321 inst
[ic
].Opcode
= OPCODE_DP4
;
322 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
323 inst
[ic
].DstReg
.Index
= temp
;
324 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_X
;
325 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
326 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
327 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
328 inst
[ic
].SrcReg
[1].Index
= row0_p
;
331 /* DP4 temp.y, colorTemp, matrow1; */
332 _mesa_init_instructions(inst
+ ic
, 1);
333 inst
[ic
].Opcode
= OPCODE_DP4
;
334 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
335 inst
[ic
].DstReg
.Index
= temp
;
336 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_Y
;
337 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
338 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
339 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
340 inst
[ic
].SrcReg
[1].Index
= row1_p
;
343 /* DP4 temp.z, colorTemp, matrow2; */
344 _mesa_init_instructions(inst
+ ic
, 1);
345 inst
[ic
].Opcode
= OPCODE_DP4
;
346 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
347 inst
[ic
].DstReg
.Index
= temp
;
348 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_Z
;
349 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
350 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
351 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
352 inst
[ic
].SrcReg
[1].Index
= row2_p
;
355 /* DP4 temp.w, colorTemp, matrow3; */
356 _mesa_init_instructions(inst
+ ic
, 1);
357 inst
[ic
].Opcode
= OPCODE_DP4
;
358 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
359 inst
[ic
].DstReg
.Index
= temp
;
360 inst
[ic
].DstReg
.WriteMask
= WRITEMASK_W
;
361 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
362 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
363 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
364 inst
[ic
].SrcReg
[1].Index
= row3_p
;
367 /* MOV colorTemp, temp; */
368 _mesa_init_instructions(inst
+ ic
, 1);
369 inst
[ic
].Opcode
= OPCODE_MOV
;
370 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
371 inst
[ic
].DstReg
.Index
= colorTemp
;
372 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
373 inst
[ic
].SrcReg
[0].Index
= temp
;
377 if (key
->colorMatrixPostScaleBias
) {
378 static const gl_state_index scale_state
[STATE_LENGTH
] =
379 { STATE_INTERNAL
, STATE_PT_SCALE
, 0, 0, 0 };
380 static const gl_state_index bias_state
[STATE_LENGTH
] =
381 { STATE_INTERNAL
, STATE_PT_BIAS
, 0, 0, 0 };
382 GLint scale_param
, bias_param
;
384 scale_param
= _mesa_add_state_reference(params
, scale_state
);
385 bias_param
= _mesa_add_state_reference(params
, bias_state
);
387 _mesa_init_instructions(inst
+ ic
, 1);
388 inst
[ic
].Opcode
= OPCODE_MAD
;
389 inst
[ic
].DstReg
.File
= PROGRAM_TEMPORARY
;
390 inst
[ic
].DstReg
.Index
= colorTemp
;
391 inst
[ic
].SrcReg
[0].File
= PROGRAM_TEMPORARY
;
392 inst
[ic
].SrcReg
[0].Index
= colorTemp
;
393 inst
[ic
].SrcReg
[1].File
= PROGRAM_STATE_VAR
;
394 inst
[ic
].SrcReg
[1].Index
= scale_param
;
395 inst
[ic
].SrcReg
[2].File
= PROGRAM_STATE_VAR
;
396 inst
[ic
].SrcReg
[2].Index
= bias_param
;
400 /* Modify last instruction's dst reg to write to result.color */
402 struct prog_instruction
*last
= &inst
[ic
- 1];
403 last
->DstReg
.File
= PROGRAM_OUTPUT
;
404 last
->DstReg
.Index
= FRAG_RESULT_COLR
;
408 _mesa_init_instructions(inst
+ ic
, 1);
409 inst
[ic
].Opcode
= OPCODE_END
;
412 assert(ic
<= MAX_INST
);
415 fp
->Base
.Instructions
= _mesa_alloc_instructions(ic
);
416 if (!fp
->Base
.Instructions
) {
417 _mesa_error(ctx
, GL_OUT_OF_MEMORY
,
418 "generating pixel transfer program");
422 _mesa_copy_instructions(fp
->Base
.Instructions
, inst
, ic
);
423 fp
->Base
.NumInstructions
= ic
;
424 fp
->Base
.Parameters
= params
;
427 printf("========= pixel transfer prog\n");
428 _mesa_print_program(&fp
->Base
);
429 _mesa_print_parameter_list(fp
->Base
.Parameters
);
438 * Update st->pixel_xfer.program in response to new pixel-transfer state.
441 update_pixel_transfer(struct st_context
*st
)
443 GLcontext
*ctx
= st
->ctx
;
444 struct state_key key
;
445 struct gl_fragment_program
*fp
;
447 make_state_key(st
->ctx
, &key
);
449 fp
= (struct gl_fragment_program
*)
450 _mesa_search_program_cache(st
->pixel_xfer
.cache
, &key
, sizeof(key
));
452 fp
= get_pixel_transfer_program(st
->ctx
, &key
);
453 _mesa_program_cache_insert(st
->ctx
, st
->pixel_xfer
.cache
,
454 &key
, sizeof(key
), &fp
->Base
);
457 if (ctx
->Pixel
.MapColorFlag
) {
458 load_color_map_texture(ctx
, st
->pixel_xfer
.pixelmap_texture
);
460 st
->pixel_xfer
.pixelmap_enabled
= ctx
->Pixel
.MapColorFlag
;
462 st
->pixel_xfer
.program
= (struct st_fragment_program
*) fp
;
467 const struct st_tracked_state st_update_pixel_transfer
= {
468 "st_update_pixel_transfer", /* name */
470 _NEW_PIXEL
| _NEW_COLOR_MATRIX
, /* mesa */
473 update_pixel_transfer
/* update */