shader.c revision 0ee73edeccd21034e03e9e43dd0d09fa6fbf7842
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. All Rights Reserved. 4 * 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: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 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. 24 * 25 **************************************************************************/ 26 27#include "shader.h" 28 29#include "vg_context.h" 30#include "shaders_cache.h" 31#include "paint.h" 32#include "mask.h" 33#include "image.h" 34#include "renderer.h" 35 36#include "pipe/p_context.h" 37#include "pipe/p_screen.h" 38#include "pipe/p_state.h" 39#include "util/u_inlines.h" 40#include "util/u_memory.h" 41#include "util/u_math.h" 42 43#define MAX_CONSTANTS 28 44 45struct shader { 46 struct vg_context *context; 47 48 VGboolean color_transform; 49 VGboolean masking; 50 struct vg_paint *paint; 51 struct vg_image *image; 52 53 struct matrix modelview; 54 struct matrix paint_matrix; 55 56 VGboolean drawing_image; 57 VGImageMode image_mode; 58 59 float constants[MAX_CONSTANTS]; 60 struct pipe_resource *cbuf; 61 struct pipe_shader_state fs_state; 62 void *fs; 63}; 64 65struct shader * shader_create(struct vg_context *ctx) 66{ 67 struct shader *shader = 0; 68 69 shader = CALLOC_STRUCT(shader); 70 shader->context = ctx; 71 72 return shader; 73} 74 75void shader_destroy(struct shader *shader) 76{ 77 FREE(shader); 78} 79 80void shader_set_color_transform(struct shader *shader, VGboolean set) 81{ 82 shader->color_transform = set; 83} 84 85void shader_set_masking(struct shader *shader, VGboolean set) 86{ 87 shader->masking = set; 88} 89 90VGboolean shader_is_masking(struct shader *shader) 91{ 92 return shader->masking; 93} 94 95void shader_set_paint(struct shader *shader, struct vg_paint *paint) 96{ 97 shader->paint = paint; 98} 99 100struct vg_paint * shader_paint(struct shader *shader) 101{ 102 return shader->paint; 103} 104 105static VGint setup_constant_buffer(struct shader *shader) 106{ 107 const struct vg_state *state = &shader->context->state.vg; 108 VGint param_bytes = paint_constant_buffer_size(shader->paint); 109 VGint i; 110 111 param_bytes += sizeof(VGfloat) * 8; 112 assert(param_bytes <= sizeof(shader->constants)); 113 114 if (state->color_transform) { 115 for (i = 0; i < 8; i++) { 116 VGfloat val = (i < 4) ? 127.0f : 1.0f; 117 shader->constants[i] = 118 CLAMP(state->color_transform_values[i], -val, val); 119 } 120 } 121 else { 122 memset(shader->constants, 0, sizeof(VGfloat) * 8); 123 } 124 125 paint_fill_constant_buffer(shader->paint, 126 &shader->paint_matrix, shader->constants + 8); 127 128 return param_bytes; 129} 130 131static VGboolean blend_use_shader(struct vg_context *ctx) 132{ 133 VGboolean advanced_blending; 134 135 switch (ctx->state.vg.blend_mode) { 136 case VG_BLEND_MULTIPLY: 137 case VG_BLEND_SCREEN: 138 case VG_BLEND_DARKEN: 139 case VG_BLEND_LIGHTEN: 140 advanced_blending = VG_TRUE; 141 break; 142 default: 143 advanced_blending = VG_FALSE; 144 break; 145 } 146 147 return advanced_blending; 148} 149 150static VGint blend_bind_samplers(struct vg_context *ctx, 151 struct pipe_sampler_state **samplers, 152 struct pipe_sampler_view **sampler_views) 153{ 154 if (blend_use_shader(ctx)) { 155 samplers[2] = &ctx->blend_sampler; 156 sampler_views[2] = vg_prepare_blend_surface(ctx); 157 158 if (!samplers[0] || !sampler_views[0]) { 159 samplers[0] = samplers[2]; 160 sampler_views[0] = sampler_views[2]; 161 } 162 if (!samplers[1] || !sampler_views[1]) { 163 samplers[1] = samplers[0]; 164 sampler_views[1] = sampler_views[0]; 165 } 166 167 return 1; 168 } 169 return 0; 170} 171 172static VGint setup_samplers(struct shader *shader, 173 struct pipe_sampler_state **samplers, 174 struct pipe_sampler_view **sampler_views) 175{ 176 struct vg_context *ctx = shader->context; 177 /* a little wonky: we use the num as a boolean that just says 178 * whether any sampler/textures have been set. the actual numbering 179 * for samplers is always the same: 180 * 0 - paint sampler/texture for gradient/pattern 181 * 1 - mask sampler/texture 182 * 2 - blend sampler/texture 183 * 3 - image sampler/texture 184 * */ 185 VGint num = 0; 186 187 samplers[0] = NULL; 188 samplers[1] = NULL; 189 samplers[2] = NULL; 190 samplers[3] = NULL; 191 sampler_views[0] = NULL; 192 sampler_views[1] = NULL; 193 sampler_views[2] = NULL; 194 sampler_views[3] = NULL; 195 196 num += paint_bind_samplers(shader->paint, samplers, sampler_views); 197 num += mask_bind_samplers(samplers, sampler_views); 198 num += blend_bind_samplers(ctx, samplers, sampler_views); 199 if (shader->drawing_image && shader->image) 200 num += image_bind_samplers(shader->image, samplers, sampler_views); 201 202 return (num) ? 4 : 0; 203} 204 205static INLINE VGboolean is_format_bw(struct shader *shader) 206{ 207#if 0 208 struct vg_context *ctx = shader->context; 209 struct st_framebuffer *stfb = ctx->draw_buffer; 210#endif 211 212 if (shader->drawing_image && shader->image) { 213 if (shader->image->format == VG_BW_1) 214 return VG_TRUE; 215 } 216 217 return VG_FALSE; 218} 219 220static void setup_shader_program(struct shader *shader) 221{ 222 struct vg_context *ctx = shader->context; 223 VGint shader_id = 0; 224 VGBlendMode blend_mode = ctx->state.vg.blend_mode; 225 VGboolean black_white = is_format_bw(shader); 226 227 /* 1st stage: fill */ 228 if (!shader->drawing_image || 229 (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) { 230 switch(paint_type(shader->paint)) { 231 case VG_PAINT_TYPE_COLOR: 232 shader_id |= VEGA_SOLID_FILL_SHADER; 233 break; 234 case VG_PAINT_TYPE_LINEAR_GRADIENT: 235 shader_id |= VEGA_LINEAR_GRADIENT_SHADER; 236 break; 237 case VG_PAINT_TYPE_RADIAL_GRADIENT: 238 shader_id |= VEGA_RADIAL_GRADIENT_SHADER; 239 break; 240 case VG_PAINT_TYPE_PATTERN: 241 shader_id |= VEGA_PATTERN_SHADER; 242 break; 243 244 default: 245 abort(); 246 } 247 248 if (paint_is_degenerate(shader->paint)) 249 shader_id = VEGA_PAINT_DEGENERATE_SHADER; 250 } 251 252 /* second stage image */ 253 if (shader->drawing_image) { 254 switch(shader->image_mode) { 255 case VG_DRAW_IMAGE_NORMAL: 256 shader_id |= VEGA_IMAGE_NORMAL_SHADER; 257 break; 258 case VG_DRAW_IMAGE_MULTIPLY: 259 shader_id |= VEGA_IMAGE_MULTIPLY_SHADER; 260 break; 261 case VG_DRAW_IMAGE_STENCIL: 262 shader_id |= VEGA_IMAGE_STENCIL_SHADER; 263 break; 264 default: 265 debug_printf("Unknown image mode!"); 266 } 267 } 268 269 if (shader->color_transform) 270 shader_id |= VEGA_COLOR_TRANSFORM_SHADER; 271 272 if (blend_use_shader(ctx)) { 273 if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) 274 shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; 275 else 276 shader_id |= VEGA_ALPHA_NORMAL_SHADER; 277 278 switch(blend_mode) { 279 case VG_BLEND_SRC: 280 shader_id |= VEGA_BLEND_SRC_SHADER; 281 break; 282 case VG_BLEND_SRC_OVER: 283 shader_id |= VEGA_BLEND_SRC_OVER_SHADER; 284 break; 285 case VG_BLEND_DST_OVER: 286 shader_id |= VEGA_BLEND_DST_OVER_SHADER; 287 break; 288 case VG_BLEND_SRC_IN: 289 shader_id |= VEGA_BLEND_SRC_IN_SHADER; 290 break; 291 case VG_BLEND_DST_IN: 292 shader_id |= VEGA_BLEND_DST_IN_SHADER; 293 break; 294 case VG_BLEND_MULTIPLY: 295 shader_id |= VEGA_BLEND_MULTIPLY_SHADER; 296 break; 297 case VG_BLEND_SCREEN: 298 shader_id |= VEGA_BLEND_SCREEN_SHADER; 299 break; 300 case VG_BLEND_DARKEN: 301 shader_id |= VEGA_BLEND_DARKEN_SHADER; 302 break; 303 case VG_BLEND_LIGHTEN: 304 shader_id |= VEGA_BLEND_LIGHTEN_SHADER; 305 break; 306 case VG_BLEND_ADDITIVE: 307 shader_id |= VEGA_BLEND_ADDITIVE_SHADER; 308 break; 309 default: 310 assert(0); 311 break; 312 } 313 } 314 else { 315 /* update alpha of the source */ 316 if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) 317 shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; 318 } 319 320 if (shader->masking) 321 shader_id |= VEGA_MASK_SHADER; 322 323 if (black_white) 324 shader_id |= VEGA_BW_SHADER; 325 326 shader->fs = shaders_cache_fill(ctx->sc, shader_id); 327} 328 329 330void shader_bind(struct shader *shader) 331{ 332 struct vg_context *ctx = shader->context; 333 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 334 struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; 335 VGint num_samplers, param_bytes; 336 337 /* first resolve the real paint type */ 338 paint_resolve_type(shader->paint); 339 340 num_samplers = setup_samplers(shader, samplers, sampler_views); 341 param_bytes = setup_constant_buffer(shader); 342 setup_shader_program(shader); 343 344 renderer_validate_for_shader(ctx->renderer, 345 (const struct pipe_sampler_state **) samplers, 346 sampler_views, num_samplers, 347 &shader->modelview, 348 shader->fs, (const void *) shader->constants, param_bytes); 349} 350 351void shader_set_image_mode(struct shader *shader, VGImageMode image_mode) 352{ 353 shader->image_mode = image_mode; 354} 355 356VGImageMode shader_image_mode(struct shader *shader) 357{ 358 return shader->image_mode; 359} 360 361void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image) 362{ 363 shader->drawing_image = drawing_image; 364} 365 366VGboolean shader_drawing_image(struct shader *shader) 367{ 368 return shader->drawing_image; 369} 370 371void shader_set_image(struct shader *shader, struct vg_image *img) 372{ 373 shader->image = img; 374} 375 376/** 377 * Set the transformation to map a vertex to the surface coordinates. 378 */ 379void shader_set_surface_matrix(struct shader *shader, 380 const struct matrix *mat) 381{ 382 shader->modelview = *mat; 383} 384 385/** 386 * Set the transformation to map a pixel to the paint coordinates. 387 */ 388void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat) 389{ 390 const struct st_framebuffer *stfb = shader->context->draw_buffer; 391 const VGfloat px_center_offset = 0.5f; 392 393 memcpy(&shader->paint_matrix, mat, sizeof(*mat)); 394 395 /* make it window-to-paint for the shaders */ 396 matrix_translate(&shader->paint_matrix, px_center_offset, 397 stfb->height - 1.0f + px_center_offset); 398 matrix_scale(&shader->paint_matrix, 1.0f, -1.0f); 399} 400