1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 **************************************************************************/
29 #include "vg_context.h"
30 #include "shaders_cache.h"
36 #include "pipe/p_context.h"
37 #include "pipe/p_state.h"
38 #include "util/u_memory.h"
39 #include "util/u_math.h"
40 #include "util/u_format.h"
42 #define MAX_CONSTANTS 28
45 struct vg_context
*context
;
47 VGboolean color_transform
;
49 struct vg_paint
*paint
;
50 struct vg_image
*image
;
52 struct matrix modelview
;
53 struct matrix paint_matrix
;
55 VGboolean drawing_image
;
56 VGImageMode image_mode
;
58 float constants
[MAX_CONSTANTS
];
59 struct pipe_resource
*cbuf
;
60 struct pipe_shader_state fs_state
;
64 struct shader
* shader_create(struct vg_context
*ctx
)
66 struct shader
*shader
= 0;
68 shader
= CALLOC_STRUCT(shader
);
69 shader
->context
= ctx
;
74 void shader_destroy(struct shader
*shader
)
79 void shader_set_color_transform(struct shader
*shader
, VGboolean set
)
81 shader
->color_transform
= set
;
84 void shader_set_masking(struct shader
*shader
, VGboolean set
)
86 shader
->masking
= set
;
89 VGboolean
shader_is_masking(struct shader
*shader
)
91 return shader
->masking
;
94 void shader_set_paint(struct shader
*shader
, struct vg_paint
*paint
)
96 shader
->paint
= paint
;
99 struct vg_paint
* shader_paint(struct shader
*shader
)
101 return shader
->paint
;
104 static VGint
setup_constant_buffer(struct shader
*shader
)
106 const struct vg_state
*state
= &shader
->context
->state
.vg
;
107 VGint param_bytes
= paint_constant_buffer_size(shader
->paint
);
110 param_bytes
+= sizeof(VGfloat
) * 8;
111 assert(param_bytes
<= sizeof(shader
->constants
));
113 if (state
->color_transform
) {
114 for (i
= 0; i
< 8; i
++) {
115 VGfloat val
= (i
< 4) ? 127.0f
: 1.0f
;
116 shader
->constants
[i
] =
117 CLAMP(state
->color_transform_values
[i
], -val
, val
);
121 memset(shader
->constants
, 0, sizeof(VGfloat
) * 8);
124 paint_fill_constant_buffer(shader
->paint
,
125 &shader
->paint_matrix
, shader
->constants
+ 8);
130 static VGboolean
blend_use_shader(struct vg_context
*ctx
)
132 VGboolean advanced_blending
;
134 switch (ctx
->state
.vg
.blend_mode
) {
135 case VG_BLEND_SRC_OVER
:
137 (!paint_is_opaque(ctx
->state
.vg
.fill_paint
) ||
138 !paint_is_opaque(ctx
->state
.vg
.stroke_paint
)) &&
139 util_format_has_alpha(ctx
->draw_buffer
->strb
->format
);
141 case VG_BLEND_DST_OVER
:
142 case VG_BLEND_MULTIPLY
:
143 case VG_BLEND_SCREEN
:
144 case VG_BLEND_DARKEN
:
145 case VG_BLEND_LIGHTEN
:
146 case VG_BLEND_ADDITIVE
:
147 advanced_blending
= VG_TRUE
;
150 advanced_blending
= VG_FALSE
;
154 return advanced_blending
;
157 static VGint
blend_bind_samplers(struct vg_context
*ctx
,
158 struct pipe_sampler_state
**samplers
,
159 struct pipe_sampler_view
**sampler_views
)
161 if (blend_use_shader(ctx
)) {
162 samplers
[2] = &ctx
->blend_sampler
;
163 sampler_views
[2] = vg_prepare_blend_surface(ctx
);
165 if (!samplers
[0] || !sampler_views
[0]) {
166 samplers
[0] = samplers
[2];
167 sampler_views
[0] = sampler_views
[2];
169 if (!samplers
[1] || !sampler_views
[1]) {
170 samplers
[1] = samplers
[0];
171 sampler_views
[1] = sampler_views
[0];
179 static VGint
setup_samplers(struct shader
*shader
,
180 struct pipe_sampler_state
**samplers
,
181 struct pipe_sampler_view
**sampler_views
)
183 struct vg_context
*ctx
= shader
->context
;
184 /* a little wonky: we use the num as a boolean that just says
185 * whether any sampler/textures have been set. the actual numbering
186 * for samplers is always the same:
187 * 0 - paint sampler/texture for gradient/pattern
188 * 1 - mask sampler/texture
189 * 2 - blend sampler/texture
190 * 3 - image sampler/texture
198 sampler_views
[0] = NULL
;
199 sampler_views
[1] = NULL
;
200 sampler_views
[2] = NULL
;
201 sampler_views
[3] = NULL
;
203 num
+= paint_bind_samplers(shader
->paint
, samplers
, sampler_views
);
204 num
+= mask_bind_samplers(samplers
, sampler_views
);
205 num
+= blend_bind_samplers(ctx
, samplers
, sampler_views
);
206 if (shader
->drawing_image
&& shader
->image
)
207 num
+= image_bind_samplers(shader
->image
, samplers
, sampler_views
);
209 return (num
) ? 4 : 0;
212 static INLINE VGboolean
is_format_bw(struct shader
*shader
)
215 struct vg_context
*ctx
= shader
->context
;
216 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
219 if (shader
->drawing_image
&& shader
->image
) {
220 if (shader
->image
->format
== VG_BW_1
)
227 static void setup_shader_program(struct shader
*shader
)
229 struct vg_context
*ctx
= shader
->context
;
231 VGBlendMode blend_mode
= ctx
->state
.vg
.blend_mode
;
232 VGboolean black_white
= is_format_bw(shader
);
234 /* 1st stage: fill */
235 if (!shader
->drawing_image
||
236 (shader
->image_mode
== VG_DRAW_IMAGE_MULTIPLY
|| shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)) {
237 switch(paint_type(shader
->paint
)) {
238 case VG_PAINT_TYPE_COLOR
:
239 shader_id
|= VEGA_SOLID_FILL_SHADER
;
241 case VG_PAINT_TYPE_LINEAR_GRADIENT
:
242 shader_id
|= VEGA_LINEAR_GRADIENT_SHADER
;
244 case VG_PAINT_TYPE_RADIAL_GRADIENT
:
245 shader_id
|= VEGA_RADIAL_GRADIENT_SHADER
;
247 case VG_PAINT_TYPE_PATTERN
:
248 shader_id
|= VEGA_PATTERN_SHADER
;
255 if (paint_is_degenerate(shader
->paint
))
256 shader_id
= VEGA_PAINT_DEGENERATE_SHADER
;
259 /* second stage image */
260 if (shader
->drawing_image
) {
261 switch(shader
->image_mode
) {
262 case VG_DRAW_IMAGE_NORMAL
:
263 shader_id
|= VEGA_IMAGE_NORMAL_SHADER
;
265 case VG_DRAW_IMAGE_MULTIPLY
:
266 shader_id
|= VEGA_IMAGE_MULTIPLY_SHADER
;
268 case VG_DRAW_IMAGE_STENCIL
:
269 shader_id
|= VEGA_IMAGE_STENCIL_SHADER
;
272 debug_printf("Unknown image mode!");
276 if (shader
->color_transform
)
277 shader_id
|= VEGA_COLOR_TRANSFORM_SHADER
;
279 if (blend_use_shader(ctx
)) {
280 if (shader
->drawing_image
&& shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)
281 shader_id
|= VEGA_ALPHA_PER_CHANNEL_SHADER
;
283 shader_id
|= VEGA_ALPHA_NORMAL_SHADER
;
287 shader_id
|= VEGA_BLEND_SRC_SHADER
;
289 case VG_BLEND_SRC_OVER
:
290 shader_id
|= VEGA_BLEND_SRC_OVER_SHADER
;
292 case VG_BLEND_DST_OVER
:
293 shader_id
|= VEGA_BLEND_DST_OVER_SHADER
;
295 case VG_BLEND_SRC_IN
:
296 shader_id
|= VEGA_BLEND_SRC_IN_SHADER
;
298 case VG_BLEND_DST_IN
:
299 shader_id
|= VEGA_BLEND_DST_IN_SHADER
;
301 case VG_BLEND_MULTIPLY
:
302 shader_id
|= VEGA_BLEND_MULTIPLY_SHADER
;
304 case VG_BLEND_SCREEN
:
305 shader_id
|= VEGA_BLEND_SCREEN_SHADER
;
307 case VG_BLEND_DARKEN
:
308 shader_id
|= VEGA_BLEND_DARKEN_SHADER
;
310 case VG_BLEND_LIGHTEN
:
311 shader_id
|= VEGA_BLEND_LIGHTEN_SHADER
;
313 case VG_BLEND_ADDITIVE
:
314 shader_id
|= VEGA_BLEND_ADDITIVE_SHADER
;
322 /* update alpha of the source */
323 if (shader
->drawing_image
&& shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)
324 shader_id
|= VEGA_ALPHA_PER_CHANNEL_SHADER
;
328 shader_id
|= VEGA_MASK_SHADER
;
331 shader_id
|= VEGA_BW_SHADER
;
333 shader
->fs
= shaders_cache_fill(ctx
->sc
, shader_id
);
337 void shader_bind(struct shader
*shader
)
339 struct vg_context
*ctx
= shader
->context
;
340 struct pipe_sampler_state
*samplers
[PIPE_MAX_SAMPLERS
];
341 struct pipe_sampler_view
*sampler_views
[PIPE_MAX_SAMPLERS
];
342 VGint num_samplers
, param_bytes
;
344 /* first resolve the real paint type */
345 paint_resolve_type(shader
->paint
);
347 num_samplers
= setup_samplers(shader
, samplers
, sampler_views
);
348 param_bytes
= setup_constant_buffer(shader
);
349 setup_shader_program(shader
);
351 renderer_validate_for_shader(ctx
->renderer
,
352 (const struct pipe_sampler_state
**) samplers
,
353 sampler_views
, num_samplers
,
355 shader
->fs
, (const void *) shader
->constants
, param_bytes
);
358 void shader_set_image_mode(struct shader
*shader
, VGImageMode image_mode
)
360 shader
->image_mode
= image_mode
;
363 VGImageMode
shader_image_mode(struct shader
*shader
)
365 return shader
->image_mode
;
368 void shader_set_drawing_image(struct shader
*shader
, VGboolean drawing_image
)
370 shader
->drawing_image
= drawing_image
;
373 VGboolean
shader_drawing_image(struct shader
*shader
)
375 return shader
->drawing_image
;
378 void shader_set_image(struct shader
*shader
, struct vg_image
*img
)
384 * Set the transformation to map a vertex to the surface coordinates.
386 void shader_set_surface_matrix(struct shader
*shader
,
387 const struct matrix
*mat
)
389 shader
->modelview
= *mat
;
393 * Set the transformation to map a pixel to the paint coordinates.
395 void shader_set_paint_matrix(struct shader
*shader
, const struct matrix
*mat
)
397 const struct st_framebuffer
*stfb
= shader
->context
->draw_buffer
;
398 const VGfloat px_center_offset
= 0.5f
;
400 memcpy(&shader
->paint_matrix
, mat
, sizeof(*mat
));
402 /* make it window-to-paint for the shaders */
403 matrix_translate(&shader
->paint_matrix
, px_center_offset
,
404 stfb
->height
- 1.0f
+ px_center_offset
);
405 matrix_scale(&shader
->paint_matrix
, 1.0f
, -1.0f
);