shader.c revision a91128030e6c19609f6bb66a871382bbe4e3e2a4
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 44struct 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 64struct 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 74void shader_destroy(struct shader *shader) 75{ 76 FREE(shader); 77} 78 79void shader_set_color_transform(struct shader *shader, VGboolean set) 80{ 81 shader->color_transform = set; 82} 83 84void shader_set_masking(struct shader *shader, VGboolean set) 85{ 86 shader->masking = set; 87} 88 89VGboolean shader_is_masking(struct shader *shader) 90{ 91 return shader->masking; 92} 93 94void shader_set_paint(struct shader *shader, struct vg_paint *paint) 95{ 96 shader->paint = paint; 97} 98 99struct vg_paint * shader_paint(struct shader *shader) 100{ 101 return shader->paint; 102} 103 104static 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 130static VGboolean blend_use_shader(struct vg_context *ctx) 131{ 132 VGboolean advanced_blending; 133 134 switch (ctx->state.vg.blend_mode) { 135 case VG_BLEND_SRC_OVER: 136 advanced_blending = 137 util_format_has_alpha(ctx->draw_buffer->strb->format); 138 break; 139 case VG_BLEND_DST_OVER: 140 case VG_BLEND_MULTIPLY: 141 case VG_BLEND_SCREEN: 142 case VG_BLEND_DARKEN: 143 case VG_BLEND_LIGHTEN: 144 case VG_BLEND_ADDITIVE: 145 advanced_blending = VG_TRUE; 146 break; 147 default: 148 advanced_blending = VG_FALSE; 149 break; 150 } 151 152 return advanced_blending; 153} 154 155static VGint blend_bind_samplers(struct vg_context *ctx, 156 struct pipe_sampler_state **samplers, 157 struct pipe_sampler_view **sampler_views) 158{ 159 if (blend_use_shader(ctx)) { 160 samplers[2] = &ctx->blend_sampler; 161 sampler_views[2] = vg_prepare_blend_surface(ctx); 162 163 if (!samplers[0] || !sampler_views[0]) { 164 samplers[0] = samplers[2]; 165 sampler_views[0] = sampler_views[2]; 166 } 167 if (!samplers[1] || !sampler_views[1]) { 168 samplers[1] = samplers[0]; 169 sampler_views[1] = sampler_views[0]; 170 } 171 172 return 1; 173 } 174 return 0; 175} 176 177static VGint setup_samplers(struct shader *shader, 178 struct pipe_sampler_state **samplers, 179 struct pipe_sampler_view **sampler_views) 180{ 181 struct vg_context *ctx = shader->context; 182 /* a little wonky: we use the num as a boolean that just says 183 * whether any sampler/textures have been set. the actual numbering 184 * for samplers is always the same: 185 * 0 - paint sampler/texture for gradient/pattern 186 * 1 - mask sampler/texture 187 * 2 - blend sampler/texture 188 * 3 - image sampler/texture 189 * */ 190 VGint num = 0; 191 192 samplers[0] = NULL; 193 samplers[1] = NULL; 194 samplers[2] = NULL; 195 samplers[3] = NULL; 196 sampler_views[0] = NULL; 197 sampler_views[1] = NULL; 198 sampler_views[2] = NULL; 199 sampler_views[3] = NULL; 200 201 num += paint_bind_samplers(shader->paint, samplers, sampler_views); 202 num += mask_bind_samplers(samplers, sampler_views); 203 num += blend_bind_samplers(ctx, samplers, sampler_views); 204 if (shader->drawing_image && shader->image) 205 num += image_bind_samplers(shader->image, samplers, sampler_views); 206 207 return (num) ? 4 : 0; 208} 209 210static INLINE VGboolean is_format_bw(struct shader *shader) 211{ 212#if 0 213 struct vg_context *ctx = shader->context; 214 struct st_framebuffer *stfb = ctx->draw_buffer; 215#endif 216 217 if (shader->drawing_image && shader->image) { 218 if (shader->image->format == VG_BW_1) 219 return VG_TRUE; 220 } 221 222 return VG_FALSE; 223} 224 225static void setup_shader_program(struct shader *shader) 226{ 227 struct vg_context *ctx = shader->context; 228 VGint shader_id = 0; 229 VGBlendMode blend_mode = ctx->state.vg.blend_mode; 230 VGboolean black_white = is_format_bw(shader); 231 232 /* 1st stage: fill */ 233 if (!shader->drawing_image || 234 (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) { 235 switch(paint_type(shader->paint)) { 236 case VG_PAINT_TYPE_COLOR: 237 shader_id |= VEGA_SOLID_FILL_SHADER; 238 break; 239 case VG_PAINT_TYPE_LINEAR_GRADIENT: 240 shader_id |= VEGA_LINEAR_GRADIENT_SHADER; 241 break; 242 case VG_PAINT_TYPE_RADIAL_GRADIENT: 243 shader_id |= VEGA_RADIAL_GRADIENT_SHADER; 244 break; 245 case VG_PAINT_TYPE_PATTERN: 246 shader_id |= VEGA_PATTERN_SHADER; 247 break; 248 249 default: 250 abort(); 251 } 252 253 if (paint_is_degenerate(shader->paint)) 254 shader_id = VEGA_PAINT_DEGENERATE_SHADER; 255 } 256 257 /* second stage image */ 258 if (shader->drawing_image) { 259 switch(shader->image_mode) { 260 case VG_DRAW_IMAGE_NORMAL: 261 shader_id |= VEGA_IMAGE_NORMAL_SHADER; 262 break; 263 case VG_DRAW_IMAGE_MULTIPLY: 264 shader_id |= VEGA_IMAGE_MULTIPLY_SHADER; 265 break; 266 case VG_DRAW_IMAGE_STENCIL: 267 shader_id |= VEGA_IMAGE_STENCIL_SHADER; 268 break; 269 default: 270 debug_printf("Unknown image mode!"); 271 } 272 } 273 274 if (shader->color_transform) 275 shader_id |= VEGA_COLOR_TRANSFORM_SHADER; 276 277 if (blend_use_shader(ctx)) { 278 if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) 279 shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; 280 else 281 shader_id |= VEGA_ALPHA_NORMAL_SHADER; 282 283 switch(blend_mode) { 284 case VG_BLEND_SRC: 285 shader_id |= VEGA_BLEND_SRC_SHADER; 286 break; 287 case VG_BLEND_SRC_OVER: 288 shader_id |= VEGA_BLEND_SRC_OVER_SHADER; 289 break; 290 case VG_BLEND_DST_OVER: 291 shader_id |= VEGA_BLEND_DST_OVER_SHADER; 292 break; 293 case VG_BLEND_SRC_IN: 294 shader_id |= VEGA_BLEND_SRC_IN_SHADER; 295 break; 296 case VG_BLEND_DST_IN: 297 shader_id |= VEGA_BLEND_DST_IN_SHADER; 298 break; 299 case VG_BLEND_MULTIPLY: 300 shader_id |= VEGA_BLEND_MULTIPLY_SHADER; 301 break; 302 case VG_BLEND_SCREEN: 303 shader_id |= VEGA_BLEND_SCREEN_SHADER; 304 break; 305 case VG_BLEND_DARKEN: 306 shader_id |= VEGA_BLEND_DARKEN_SHADER; 307 break; 308 case VG_BLEND_LIGHTEN: 309 shader_id |= VEGA_BLEND_LIGHTEN_SHADER; 310 break; 311 case VG_BLEND_ADDITIVE: 312 shader_id |= VEGA_BLEND_ADDITIVE_SHADER; 313 break; 314 default: 315 assert(0); 316 break; 317 } 318 } 319 else { 320 /* update alpha of the source */ 321 if (shader->drawing_image && shader->image_mode == VG_DRAW_IMAGE_STENCIL) 322 shader_id |= VEGA_ALPHA_PER_CHANNEL_SHADER; 323 } 324 325 if (shader->masking) 326 shader_id |= VEGA_MASK_SHADER; 327 328 if (black_white) 329 shader_id |= VEGA_BW_SHADER; 330 331 shader->fs = shaders_cache_fill(ctx->sc, shader_id); 332} 333 334 335void shader_bind(struct shader *shader) 336{ 337 struct vg_context *ctx = shader->context; 338 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; 339 struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; 340 VGint num_samplers, param_bytes; 341 342 /* first resolve the real paint type */ 343 paint_resolve_type(shader->paint); 344 345 num_samplers = setup_samplers(shader, samplers, sampler_views); 346 param_bytes = setup_constant_buffer(shader); 347 setup_shader_program(shader); 348 349 renderer_validate_for_shader(ctx->renderer, 350 (const struct pipe_sampler_state **) samplers, 351 sampler_views, num_samplers, 352 &shader->modelview, 353 shader->fs, (const void *) shader->constants, param_bytes); 354} 355 356void shader_set_image_mode(struct shader *shader, VGImageMode image_mode) 357{ 358 shader->image_mode = image_mode; 359} 360 361VGImageMode shader_image_mode(struct shader *shader) 362{ 363 return shader->image_mode; 364} 365 366void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image) 367{ 368 shader->drawing_image = drawing_image; 369} 370 371VGboolean shader_drawing_image(struct shader *shader) 372{ 373 return shader->drawing_image; 374} 375 376void shader_set_image(struct shader *shader, struct vg_image *img) 377{ 378 shader->image = img; 379} 380 381/** 382 * Set the transformation to map a vertex to the surface coordinates. 383 */ 384void shader_set_surface_matrix(struct shader *shader, 385 const struct matrix *mat) 386{ 387 shader->modelview = *mat; 388} 389 390/** 391 * Set the transformation to map a pixel to the paint coordinates. 392 */ 393void shader_set_paint_matrix(struct shader *shader, const struct matrix *mat) 394{ 395 const struct st_framebuffer *stfb = shader->context->draw_buffer; 396 const VGfloat px_center_offset = 0.5f; 397 398 memcpy(&shader->paint_matrix, mat, sizeof(*mat)); 399 400 /* make it window-to-paint for the shaders */ 401 matrix_translate(&shader->paint_matrix, px_center_offset, 402 stfb->height - 1.0f + px_center_offset); 403 matrix_scale(&shader->paint_matrix, 1.0f, -1.0f); 404} 405