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_state.h" 38 #include "util/u_memory.h" 39 #include "util/u_math.h" 40 #include "util/u_format.h" 41 42 #define MAX_CONSTANTS 28 43 44 struct shader { 45 struct vg_context *context; 46 47 VGboolean color_transform; 48 VGboolean masking; 49 struct vg_paint *paint; 50 struct vg_image *image; 51 52 struct matrix modelview; 53 struct matrix paint_matrix; 54 55 VGboolean drawing_image; 56 VGImageMode image_mode; 57 58 float constants[MAX_CONSTANTS]; 59 struct pipe_resource *cbuf; 60 struct pipe_shader_state fs_state; 61 void *fs; 62 }; 63 64 struct shader * shader_create(struct vg_context *ctx) 65 { 66 struct shader *shader = 0; 67 68 shader = CALLOC_STRUCT(shader); 69 shader->context = ctx; 70 71 return shader; 72 } 73 74 void shader_destroy(struct shader *shader) 75 { 76 FREE(shader); 77 } 78 79 void shader_set_color_transform(struct shader *shader, VGboolean set) 80 { 81 shader->color_transform = set; 82 } 83 84 void shader_set_masking(struct shader *shader, VGboolean set) 85 { 86 shader->masking = set; 87 } 88 89 VGboolean shader_is_masking(struct shader *shader) 90 { 91 return shader->masking; 92 } 93 94 void shader_set_paint(struct shader *shader, struct vg_paint *paint) 95 { 96 shader->paint = paint; 97 } 98 99 struct vg_paint * shader_paint(struct shader *shader) 100 { 101 return shader->paint; 102 } 103 104 static VGint setup_constant_buffer(struct shader *shader) 105 { 106 const struct vg_state *state = &shader->context->state.vg; 107 VGint param_bytes = paint_constant_buffer_size(shader->paint); 108 VGint i; 109 110 param_bytes += sizeof(VGfloat) * 8; 111 assert(param_bytes <= sizeof(shader->constants)); 112 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); 118 } 119 } 120 else { 121 memset(shader->constants, 0, sizeof(VGfloat) * 8); 122 } 123 124 paint_fill_constant_buffer(shader->paint, 125 &shader->paint_matrix, shader->constants + 8); 126 127 return param_bytes; 128 } 129 130 static VGboolean blend_use_shader(struct shader *shader) 131 { 132 struct vg_context *ctx = shader->context; 133 VGboolean advanced_blending; 134 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; 143 break; 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) { 150 advanced_blending = 151 util_format_has_alpha(shader->image->sampler_view->format); 152 } 153 break; 154 } 155 /* fall through */ 156 default: 157 advanced_blending = VG_FALSE; 158 break; 159 } 160 161 return advanced_blending; 162 } 163 164 static VGint blend_bind_samplers(struct shader *shader, 165 struct pipe_sampler_state **samplers, 166 struct pipe_sampler_view **sampler_views) 167 { 168 if (blend_use_shader(shader)) { 169 struct vg_context *ctx = shader->context; 170 171 samplers[2] = &ctx->blend_sampler; 172 sampler_views[2] = vg_prepare_blend_surface(ctx); 173 174 if (!samplers[0] || !sampler_views[0]) { 175 samplers[0] = samplers[2]; 176 sampler_views[0] = sampler_views[2]; 177 } 178 if (!samplers[1] || !sampler_views[1]) { 179 samplers[1] = samplers[0]; 180 sampler_views[1] = sampler_views[0]; 181 } 182 183 return 1; 184 } 185 return 0; 186 } 187 188 static VGint setup_samplers(struct shader *shader, 189 struct pipe_sampler_state **samplers, 190 struct pipe_sampler_view **sampler_views) 191 { 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 199 * */ 200 VGint num = 0; 201 202 samplers[0] = NULL; 203 samplers[1] = NULL; 204 samplers[2] = NULL; 205 samplers[3] = NULL; 206 sampler_views[0] = NULL; 207 sampler_views[1] = NULL; 208 sampler_views[2] = NULL; 209 sampler_views[3] = NULL; 210 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); 216 217 return (num) ? 4 : 0; 218 } 219 220 static INLINE VGboolean is_format_bw(struct shader *shader) 221 { 222 #if 0 223 struct vg_context *ctx = shader->context; 224 struct st_framebuffer *stfb = ctx->draw_buffer; 225 #endif 226 227 if (shader->drawing_image && shader->image) { 228 if (shader->image->format == VG_BW_1) 229 return VG_TRUE; 230 } 231 232 return VG_FALSE; 233 } 234 235 static void setup_shader_program(struct shader *shader) 236 { 237 struct vg_context *ctx = shader->context; 238 VGint shader_id = 0; 239 VGBlendMode blend_mode = ctx->state.vg.blend_mode; 240 VGboolean black_white = is_format_bw(shader); 241 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; 248 break; 249 case VG_PAINT_TYPE_LINEAR_GRADIENT: 250 shader_id |= VEGA_LINEAR_GRADIENT_SHADER; 251 break; 252 case VG_PAINT_TYPE_RADIAL_GRADIENT: 253 shader_id |= VEGA_RADIAL_GRADIENT_SHADER; 254 break; 255 case VG_PAINT_TYPE_PATTERN: 256 shader_id |= VEGA_PATTERN_SHADER; 257 break; 258 259 default: 260 abort(); 261 } 262 263 if (paint_is_degenerate(shader->paint)) 264 shader_id = VEGA_PAINT_DEGENERATE_SHADER; 265 } 266 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; 272 break; 273 case VG_DRAW_IMAGE_MULTIPLY: 274 shader_id |= VEGA_IMAGE_MULTIPLY_SHADER; 275 break; 276 case VG_DRAW_IMAGE_STENCIL: 277 shader_id |= VEGA_IMAGE_STENCIL_SHADER; 278 break; 279 default: 280 debug_printf("Unknown image mode!"); 281 } 282 } 283 284 if (shader->color_transform) 285 shader_id |= VEGA_COLOR_TRANSFORM_SHADER; 286 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; 290 else 291 shader_id |= VEGA_ALPHA_NORMAL_SHADER; 292 293 switch(blend_mode) { 294 case VG_BLEND_SRC: 295 shader_id |= VEGA_BLEND_SRC_SHADER; 296 break; 297 case VG_BLEND_SRC_OVER: 298 shader_id |= VEGA_BLEND_SRC_OVER_SHADER; 299 break; 300 case VG_BLEND_DST_OVER: 301 shader_id |= VEGA_BLEND_DST_OVER_SHADER; 302 break; 303 case VG_BLEND_SRC_IN: 304 shader_id |= VEGA_BLEND_SRC_IN_SHADER; 305 break; 306 case VG_BLEND_DST_IN: 307 shader_id |= VEGA_BLEND_DST_IN_SHADER; 308 break; 309 case VG_BLEND_MULTIPLY: 310 shader_id |= VEGA_BLEND_MULTIPLY_SHADER; 311 break; 312 case VG_BLEND_SCREEN: 313 shader_id |= VEGA_BLEND_SCREEN_SHADER; 314 break; 315 case VG_BLEND_DARKEN: 316 shader_id |= VEGA_BLEND_DARKEN_SHADER; 317 break; 318 case VG_BLEND_LIGHTEN: 319 shader_id |= VEGA_BLEND_LIGHTEN_SHADER; 320 break; 321 case VG_BLEND_ADDITIVE: 322 shader_id |= VEGA_BLEND_ADDITIVE_SHADER; 323 break; 324 default: 325 assert(0); 326 break; 327 } 328 } 329 else { 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; 333 } 334 335 if (shader->masking) 336 shader_id |= VEGA_MASK_SHADER; 337 338 if (black_white) 339 shader_id |= VEGA_BW_SHADER; 340 341 shader->fs = shaders_cache_fill(ctx->sc, shader_id); 342 } 343 344 345 void shader_bind(struct shader *shader) 346 { 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; 351 352 /* first resolve the real paint type */ 353 paint_resolve_type(shader->paint); 354 355 num_samplers = setup_samplers(shader, samplers, sampler_views); 356 param_bytes = setup_constant_buffer(shader); 357 setup_shader_program(shader); 358 359 renderer_validate_for_shader(ctx->renderer, 360 (const struct pipe_sampler_state **) samplers, 361 sampler_views, num_samplers, 362 &shader->modelview, 363 shader->fs, (const void *) shader->constants, param_bytes); 364 } 365 366 void shader_set_image_mode(struct shader *shader, VGImageMode image_mode) 367 { 368 shader->image_mode = image_mode; 369 } 370 371 VGImageMode shader_image_mode(struct shader *shader) 372 { 373 return shader->image_mode; 374 } 375 376 void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image) 377 { 378 shader->drawing_image = drawing_image; 379 } 380 381 VGboolean shader_drawing_image(struct shader *shader) 382 { 383 return shader->drawing_image; 384 } 385 386 void shader_set_image(struct shader *shader, struct vg_image *img) 387 { 388 shader->image = img; 389 } 390 391 /** 392 * Set the transformation to map a vertex to the surface coordinates. 393 */ 394 void shader_set_surface_matrix(struct shader *shader, 395 const struct matrix *mat) 396 { 397 shader->modelview = *mat; 398 } 399 400 /** 401 * Set the transformation to map a pixel to the paint coordinates. 402 */ 403 void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat) 404 { 405 const struct st_framebuffer *stfb = shader->context->draw_buffer; 406 const VGfloat px_center_offset = 0.5f; 407 408 memcpy(&shader->paint_matrix, mat, sizeof(*mat)); 409 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); 414 } 415