Home | History | Annotate | Download | only in vega
      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