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 shader
*shader
)
132 struct vg_context
*ctx
= shader
->context
;
133 VGboolean advanced_blending
;
135 switch (ctx
->state
.vg
.blend_mode
) {
136 case VG_BLEND_DST_OVER
:
137 case VG_BLEND_MULTIPLY
:
138 case VG_BLEND_SCREEN
:
139 case VG_BLEND_DARKEN
:
140 case VG_BLEND_LIGHTEN
:
141 case VG_BLEND_ADDITIVE
:
142 advanced_blending
= VG_TRUE
;
144 case VG_BLEND_SRC_OVER
:
145 if (util_format_has_alpha(ctx
->draw_buffer
->strb
->format
)) {
146 /* no blending is required if the paints and the image are opaque */
147 advanced_blending
= !paint_is_opaque(ctx
->state
.vg
.fill_paint
) ||
148 !paint_is_opaque(ctx
->state
.vg
.stroke_paint
);
149 if (!advanced_blending
&& shader
->drawing_image
) {
151 util_format_has_alpha(shader
->image
->sampler_view
->format
);
157 advanced_blending
= VG_FALSE
;
161 return advanced_blending
;
164 static VGint
blend_bind_samplers(struct shader
*shader
,
165 struct pipe_sampler_state
**samplers
,
166 struct pipe_sampler_view
**sampler_views
)
168 if (blend_use_shader(shader
)) {
169 struct vg_context
*ctx
= shader
->context
;
171 samplers
[2] = &ctx
->blend_sampler
;
172 sampler_views
[2] = vg_prepare_blend_surface(ctx
);
174 if (!samplers
[0] || !sampler_views
[0]) {
175 samplers
[0] = samplers
[2];
176 sampler_views
[0] = sampler_views
[2];
178 if (!samplers
[1] || !sampler_views
[1]) {
179 samplers
[1] = samplers
[0];
180 sampler_views
[1] = sampler_views
[0];
188 static VGint
setup_samplers(struct shader
*shader
,
189 struct pipe_sampler_state
**samplers
,
190 struct pipe_sampler_view
**sampler_views
)
192 /* a little wonky: we use the num as a boolean that just says
193 * whether any sampler/textures have been set. the actual numbering
194 * for samplers is always the same:
195 * 0 - paint sampler/texture for gradient/pattern
196 * 1 - mask sampler/texture
197 * 2 - blend sampler/texture
198 * 3 - image sampler/texture
206 sampler_views
[0] = NULL
;
207 sampler_views
[1] = NULL
;
208 sampler_views
[2] = NULL
;
209 sampler_views
[3] = NULL
;
211 num
+= paint_bind_samplers(shader
->paint
, samplers
, sampler_views
);
212 num
+= mask_bind_samplers(samplers
, sampler_views
);
213 num
+= blend_bind_samplers(shader
, samplers
, sampler_views
);
214 if (shader
->drawing_image
&& shader
->image
)
215 num
+= image_bind_samplers(shader
->image
, samplers
, sampler_views
);
217 return (num
) ? 4 : 0;
220 static INLINE VGboolean
is_format_bw(struct shader
*shader
)
223 struct vg_context
*ctx
= shader
->context
;
224 struct st_framebuffer
*stfb
= ctx
->draw_buffer
;
227 if (shader
->drawing_image
&& shader
->image
) {
228 if (shader
->image
->format
== VG_BW_1
)
235 static void setup_shader_program(struct shader
*shader
)
237 struct vg_context
*ctx
= shader
->context
;
239 VGBlendMode blend_mode
= ctx
->state
.vg
.blend_mode
;
240 VGboolean black_white
= is_format_bw(shader
);
242 /* 1st stage: fill */
243 if (!shader
->drawing_image
||
244 (shader
->image_mode
== VG_DRAW_IMAGE_MULTIPLY
|| shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)) {
245 switch(paint_type(shader
->paint
)) {
246 case VG_PAINT_TYPE_COLOR
:
247 shader_id
|= VEGA_SOLID_FILL_SHADER
;
249 case VG_PAINT_TYPE_LINEAR_GRADIENT
:
250 shader_id
|= VEGA_LINEAR_GRADIENT_SHADER
;
252 case VG_PAINT_TYPE_RADIAL_GRADIENT
:
253 shader_id
|= VEGA_RADIAL_GRADIENT_SHADER
;
255 case VG_PAINT_TYPE_PATTERN
:
256 shader_id
|= VEGA_PATTERN_SHADER
;
263 if (paint_is_degenerate(shader
->paint
))
264 shader_id
= VEGA_PAINT_DEGENERATE_SHADER
;
267 /* second stage image */
268 if (shader
->drawing_image
) {
269 switch(shader
->image_mode
) {
270 case VG_DRAW_IMAGE_NORMAL
:
271 shader_id
|= VEGA_IMAGE_NORMAL_SHADER
;
273 case VG_DRAW_IMAGE_MULTIPLY
:
274 shader_id
|= VEGA_IMAGE_MULTIPLY_SHADER
;
276 case VG_DRAW_IMAGE_STENCIL
:
277 shader_id
|= VEGA_IMAGE_STENCIL_SHADER
;
280 debug_printf("Unknown image mode!");
284 if (shader
->color_transform
)
285 shader_id
|= VEGA_COLOR_TRANSFORM_SHADER
;
287 if (blend_use_shader(shader
)) {
288 if (shader
->drawing_image
&& shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)
289 shader_id
|= VEGA_ALPHA_PER_CHANNEL_SHADER
;
291 shader_id
|= VEGA_ALPHA_NORMAL_SHADER
;
295 shader_id
|= VEGA_BLEND_SRC_SHADER
;
297 case VG_BLEND_SRC_OVER
:
298 shader_id
|= VEGA_BLEND_SRC_OVER_SHADER
;
300 case VG_BLEND_DST_OVER
:
301 shader_id
|= VEGA_BLEND_DST_OVER_SHADER
;
303 case VG_BLEND_SRC_IN
:
304 shader_id
|= VEGA_BLEND_SRC_IN_SHADER
;
306 case VG_BLEND_DST_IN
:
307 shader_id
|= VEGA_BLEND_DST_IN_SHADER
;
309 case VG_BLEND_MULTIPLY
:
310 shader_id
|= VEGA_BLEND_MULTIPLY_SHADER
;
312 case VG_BLEND_SCREEN
:
313 shader_id
|= VEGA_BLEND_SCREEN_SHADER
;
315 case VG_BLEND_DARKEN
:
316 shader_id
|= VEGA_BLEND_DARKEN_SHADER
;
318 case VG_BLEND_LIGHTEN
:
319 shader_id
|= VEGA_BLEND_LIGHTEN_SHADER
;
321 case VG_BLEND_ADDITIVE
:
322 shader_id
|= VEGA_BLEND_ADDITIVE_SHADER
;
330 /* update alpha of the source */
331 if (shader
->drawing_image
&& shader
->image_mode
== VG_DRAW_IMAGE_STENCIL
)
332 shader_id
|= VEGA_ALPHA_PER_CHANNEL_SHADER
;
336 shader_id
|= VEGA_MASK_SHADER
;
339 shader_id
|= VEGA_BW_SHADER
;
341 shader
->fs
= shaders_cache_fill(ctx
->sc
, shader_id
);
345 void shader_bind(struct shader
*shader
)
347 struct vg_context
*ctx
= shader
->context
;
348 struct pipe_sampler_state
*samplers
[PIPE_MAX_SAMPLERS
];
349 struct pipe_sampler_view
*sampler_views
[PIPE_MAX_SAMPLERS
];
350 VGint num_samplers
, param_bytes
;
352 /* first resolve the real paint type */
353 paint_resolve_type(shader
->paint
);
355 num_samplers
= setup_samplers(shader
, samplers
, sampler_views
);
356 param_bytes
= setup_constant_buffer(shader
);
357 setup_shader_program(shader
);
359 renderer_validate_for_shader(ctx
->renderer
,
360 (const struct pipe_sampler_state
**) samplers
,
361 sampler_views
, num_samplers
,
363 shader
->fs
, (const void *) shader
->constants
, param_bytes
);
366 void shader_set_image_mode(struct shader
*shader
, VGImageMode image_mode
)
368 shader
->image_mode
= image_mode
;
371 VGImageMode
shader_image_mode(struct shader
*shader
)
373 return shader
->image_mode
;
376 void shader_set_drawing_image(struct shader
*shader
, VGboolean drawing_image
)
378 shader
->drawing_image
= drawing_image
;
381 VGboolean
shader_drawing_image(struct shader
*shader
)
383 return shader
->drawing_image
;
386 void shader_set_image(struct shader
*shader
, struct vg_image
*img
)
392 * Set the transformation to map a vertex to the surface coordinates.
394 void shader_set_surface_matrix(struct shader
*shader
,
395 const struct matrix
*mat
)
397 shader
->modelview
= *mat
;
401 * Set the transformation to map a pixel to the paint coordinates.
403 void shader_set_paint_matrix(struct shader
*shader
, const struct matrix
*mat
)
405 const struct st_framebuffer
*stfb
= shader
->context
->draw_buffer
;
406 const VGfloat px_center_offset
= 0.5f
;
408 memcpy(&shader
->paint_matrix
, mat
, sizeof(*mat
));
410 /* make it window-to-paint for the shaders */
411 matrix_translate(&shader
->paint_matrix
, px_center_offset
,
412 stfb
->height
- 1.0f
+ px_center_offset
);
413 matrix_scale(&shader
->paint_matrix
, 1.0f
, -1.0f
);