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 "shaders_cache.h"
     28 
     29 #include "vg_context.h"
     30 
     31 #include "pipe/p_context.h"
     32 #include "pipe/p_defines.h"
     33 #include "pipe/p_shader_tokens.h"
     34 
     35 #include "tgsi/tgsi_build.h"
     36 #include "tgsi/tgsi_dump.h"
     37 #include "tgsi/tgsi_parse.h"
     38 #include "tgsi/tgsi_util.h"
     39 #include "tgsi/tgsi_text.h"
     40 
     41 #include "util/u_memory.h"
     42 #include "util/u_math.h"
     43 #include "util/u_debug.h"
     44 #include "cso_cache/cso_hash.h"
     45 #include "cso_cache/cso_context.h"
     46 
     47 #include "VG/openvg.h"
     48 
     49 #include "asm_fill.h"
     50 
     51 /* Essentially we construct an ubber-shader based on the state
     52  * of the pipeline. The stages are:
     53  * 1) Paint generation (color/gradient/pattern)
     54  * 2) Image composition (normal/multiply/stencil)
     55  * 3) Color transform
     56  * 4) Per-channel alpha generation
     57  * 5) Extended blend (multiply/screen/darken/lighten)
     58  * 6) Mask
     59  * 7) Premultiply/Unpremultiply
     60  * 8) Color transform (to black and white)
     61  */
     62 #define SHADER_STAGES 8
     63 
     64 struct cached_shader {
     65    void *driver_shader;
     66    struct pipe_shader_state state;
     67 };
     68 
     69 struct shaders_cache {
     70    struct vg_context *pipe;
     71 
     72    struct cso_hash *hash;
     73 };
     74 
     75 
     76 static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens)
     77 {
     78    struct tgsi_token *tokens;
     79 
     80    tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0]));
     81 
     82    tgsi_text_translate(txt, tokens, num_tokens);
     83 
     84 #if DEBUG_SHADERS
     85    tgsi_dump(tokens, 0);
     86 #endif
     87 
     88    return tokens;
     89 }
     90 
     91 /*
     92 static const char max_shader_preamble[] =
     93    "FRAG\n"
     94    "DCL IN[0], POSITION, LINEAR\n"
     95    "DCL IN[1], GENERIC[0], PERSPECTIVE\n"
     96    "DCL OUT[0], COLOR, CONSTANT\n"
     97    "DCL CONST[0..9], CONSTANT\n"
     98    "DCL TEMP[0..9], CONSTANT\n"
     99    "DCL SAMP[0..9], CONSTANT\n";
    100 
    101    max_shader_preamble strlen == 175
    102 */
    103 #define MAX_PREAMBLE 175
    104 
    105 static INLINE VGint range_min(VGint min, VGint current)
    106 {
    107    if (min < 0)
    108       min = current;
    109    else
    110       min = MIN2(min, current);
    111    return min;
    112 }
    113 
    114 static INLINE VGint range_max(VGint max, VGint current)
    115 {
    116    return MAX2(max, current);
    117 }
    118 
    119 static void *
    120 combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders,
    121                 struct pipe_context *pipe,
    122                 struct pipe_shader_state *shader)
    123 {
    124    VGboolean declare_input = VG_FALSE;
    125    VGint start_const   = -1, end_const   = 0;
    126    VGint start_temp    = -1, end_temp    = 0;
    127    VGint start_sampler = -1, end_sampler = 0;
    128    VGint i, current_shader = 0;
    129    VGint num_consts, num_temps, num_samplers;
    130    struct ureg_program *ureg;
    131    struct ureg_src in[2];
    132    struct ureg_src *sampler = NULL;
    133    struct ureg_src *constant = NULL;
    134    struct ureg_dst out, *temp = NULL;
    135    void *p = NULL;
    136 
    137    for (i = 0; i < num_shaders; ++i) {
    138       if (shaders[i]->num_consts)
    139          start_const = range_min(start_const, shaders[i]->start_const);
    140       if (shaders[i]->num_temps)
    141          start_temp = range_min(start_temp, shaders[i]->start_temp);
    142       if (shaders[i]->num_samplers)
    143          start_sampler = range_min(start_sampler, shaders[i]->start_sampler);
    144 
    145       end_const = range_max(end_const, shaders[i]->start_const +
    146                             shaders[i]->num_consts);
    147       end_temp = range_max(end_temp, shaders[i]->start_temp +
    148                             shaders[i]->num_temps);
    149       end_sampler = range_max(end_sampler, shaders[i]->start_sampler +
    150                             shaders[i]->num_samplers);
    151       if (shaders[i]->needs_position)
    152          declare_input = VG_TRUE;
    153    }
    154    /* if they're still unitialized, initialize them */
    155    if (start_const < 0)
    156       start_const = 0;
    157    if (start_temp < 0)
    158       start_temp = 0;
    159    if (start_sampler < 0)
    160        start_sampler = 0;
    161 
    162    num_consts   = end_const   - start_const;
    163    num_temps    = end_temp    - start_temp;
    164    num_samplers = end_sampler - start_sampler;
    165 
    166    ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
    167    if (!ureg)
    168        return NULL;
    169 
    170    if (declare_input) {
    171       in[0] = ureg_DECL_fs_input(ureg,
    172                                  TGSI_SEMANTIC_POSITION,
    173                                  0,
    174                                  TGSI_INTERPOLATE_LINEAR);
    175       in[1] = ureg_DECL_fs_input(ureg,
    176                                  TGSI_SEMANTIC_GENERIC,
    177                                  0,
    178                                  TGSI_INTERPOLATE_PERSPECTIVE);
    179    }
    180 
    181    /* we always have a color output */
    182    out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
    183 
    184    if (num_consts >= 1) {
    185       constant = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_const);
    186       for (i = start_const; i < end_const; i++) {
    187          constant[i] = ureg_DECL_constant(ureg, i);
    188       }
    189 
    190    }
    191 
    192    if (num_temps >= 1) {
    193       temp = (struct ureg_dst *) malloc(sizeof(struct ureg_dst) * end_temp);
    194       for (i = start_temp; i < end_temp; i++) {
    195          temp[i] = ureg_DECL_temporary(ureg);
    196       }
    197    }
    198 
    199    if (num_samplers >= 1) {
    200       sampler = (struct ureg_src *) malloc(sizeof(struct ureg_src) * end_sampler);
    201       for (i = start_sampler; i < end_sampler; i++) {
    202          sampler[i] = ureg_DECL_sampler(ureg, i);
    203       }
    204    }
    205 
    206    while (current_shader < num_shaders) {
    207       if ((current_shader + 1) == num_shaders) {
    208          shaders[current_shader]->func(ureg,
    209                                        &out,
    210                                        in,
    211                                        sampler,
    212                                        temp,
    213                                        constant);
    214       } else {
    215          shaders[current_shader]->func(ureg,
    216                                       &temp[0],
    217                                       in,
    218                                       sampler,
    219                                       temp,
    220                                       constant);
    221       }
    222       current_shader++;
    223    }
    224 
    225    ureg_END(ureg);
    226 
    227    shader->tokens = ureg_finalize(ureg);
    228    if(!shader->tokens)
    229       return NULL;
    230 
    231    p = pipe->create_fs_state(pipe, shader);
    232 
    233    if (num_temps >= 1) {
    234       for (i = start_temp; i < end_temp; i++) {
    235          ureg_release_temporary(ureg, temp[i]);
    236       }
    237    }
    238 
    239    ureg_destroy(ureg);
    240 
    241    if (temp)
    242       free(temp);
    243    if (constant)
    244       free(constant);
    245    if (sampler)
    246       free(sampler);
    247 
    248    return p;
    249 }
    250 
    251 static void *
    252 create_shader(struct pipe_context *pipe,
    253               int id,
    254               struct pipe_shader_state *shader)
    255 {
    256    int idx = 0, sh;
    257    const struct shader_asm_info * shaders[SHADER_STAGES];
    258 
    259    /* first stage */
    260    sh = SHADERS_GET_PAINT_SHADER(id);
    261    switch (sh << SHADERS_PAINT_SHIFT) {
    262    case VEGA_SOLID_FILL_SHADER:
    263    case VEGA_LINEAR_GRADIENT_SHADER:
    264    case VEGA_RADIAL_GRADIENT_SHADER:
    265    case VEGA_PATTERN_SHADER:
    266    case VEGA_PAINT_DEGENERATE_SHADER:
    267       shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1];
    268       assert(shaders[idx]->id == sh);
    269       idx++;
    270       break;
    271    default:
    272       break;
    273    }
    274 
    275    /* second stage */
    276    sh = SHADERS_GET_IMAGE_SHADER(id);
    277    switch (sh) {
    278    case VEGA_IMAGE_NORMAL_SHADER:
    279    case VEGA_IMAGE_MULTIPLY_SHADER:
    280    case VEGA_IMAGE_STENCIL_SHADER:
    281       shaders[idx] = &shaders_image_asm[(sh >> SHADERS_IMAGE_SHIFT) - 1];
    282       assert(shaders[idx]->id == sh);
    283       idx++;
    284       break;
    285    default:
    286       break;
    287    }
    288 
    289    /* sanity check */
    290    assert(idx == ((!sh || sh == VEGA_IMAGE_NORMAL_SHADER) ? 1 : 2));
    291 
    292    /* third stage */
    293    sh = SHADERS_GET_COLOR_TRANSFORM_SHADER(id);
    294    switch (sh) {
    295    case VEGA_COLOR_TRANSFORM_SHADER:
    296       shaders[idx] = &shaders_color_transform_asm[
    297          (sh >> SHADERS_COLOR_TRANSFORM_SHIFT) - 1];
    298       assert(shaders[idx]->id == sh);
    299       idx++;
    300       break;
    301    default:
    302       break;
    303    }
    304 
    305    /* fourth stage */
    306    sh = SHADERS_GET_ALPHA_SHADER(id);
    307    switch (sh) {
    308    case VEGA_ALPHA_NORMAL_SHADER:
    309    case VEGA_ALPHA_PER_CHANNEL_SHADER:
    310       shaders[idx] = &shaders_alpha_asm[
    311          (sh >> SHADERS_ALPHA_SHIFT) - 1];
    312       assert(shaders[idx]->id == sh);
    313       idx++;
    314       break;
    315    default:
    316       break;
    317    }
    318 
    319    /* fifth stage */
    320    sh = SHADERS_GET_BLEND_SHADER(id);
    321    switch (sh) {
    322    case VEGA_BLEND_SRC_SHADER:
    323    case VEGA_BLEND_SRC_OVER_SHADER:
    324    case VEGA_BLEND_DST_OVER_SHADER:
    325    case VEGA_BLEND_SRC_IN_SHADER:
    326    case VEGA_BLEND_DST_IN_SHADER:
    327    case VEGA_BLEND_MULTIPLY_SHADER:
    328    case VEGA_BLEND_SCREEN_SHADER:
    329    case VEGA_BLEND_DARKEN_SHADER:
    330    case VEGA_BLEND_LIGHTEN_SHADER:
    331    case VEGA_BLEND_ADDITIVE_SHADER:
    332       shaders[idx] = &shaders_blend_asm[(sh >> SHADERS_BLEND_SHIFT) - 1];
    333       assert(shaders[idx]->id == sh);
    334       idx++;
    335       break;
    336    default:
    337       break;
    338    }
    339 
    340    /* sixth stage */
    341    sh = SHADERS_GET_MASK_SHADER(id);
    342    switch (sh) {
    343    case VEGA_MASK_SHADER:
    344       shaders[idx] = &shaders_mask_asm[(sh >> SHADERS_MASK_SHIFT) - 1];
    345       assert(shaders[idx]->id == sh);
    346       idx++;
    347       break;
    348    default:
    349       break;
    350    }
    351 
    352    /* seventh stage */
    353    sh = SHADERS_GET_PREMULTIPLY_SHADER(id);
    354    switch (sh) {
    355    case VEGA_PREMULTIPLY_SHADER:
    356    case VEGA_UNPREMULTIPLY_SHADER:
    357       shaders[idx] = &shaders_premultiply_asm[
    358          (sh >> SHADERS_PREMULTIPLY_SHIFT) - 1];
    359       assert(shaders[idx]->id == sh);
    360       idx++;
    361       break;
    362    default:
    363       break;
    364    }
    365 
    366    /* eighth stage */
    367    sh = SHADERS_GET_BW_SHADER(id);
    368    switch (sh) {
    369    case VEGA_BW_SHADER:
    370       shaders[idx] = &shaders_bw_asm[(sh >> SHADERS_BW_SHIFT) - 1];
    371       assert(shaders[idx]->id == sh);
    372       idx++;
    373       break;
    374    default:
    375       break;
    376    }
    377 
    378    return combine_shaders(shaders, idx, pipe, shader);
    379 }
    380 
    381 /*************************************************/
    382 
    383 struct shaders_cache * shaders_cache_create(struct vg_context *vg)
    384 {
    385    struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache);
    386 
    387    sc->pipe = vg;
    388    sc->hash = cso_hash_create();
    389 
    390    return sc;
    391 }
    392 
    393 void shaders_cache_destroy(struct shaders_cache *sc)
    394 {
    395    struct cso_hash_iter iter = cso_hash_first_node(sc->hash);
    396 
    397    while (!cso_hash_iter_is_null(iter)) {
    398       struct cached_shader *cached =
    399          (struct cached_shader *)cso_hash_iter_data(iter);
    400       cso_delete_fragment_shader(sc->pipe->cso_context,
    401                                  cached->driver_shader);
    402       iter = cso_hash_erase(sc->hash, iter);
    403    }
    404 
    405    cso_hash_delete(sc->hash);
    406    FREE(sc);
    407 }
    408 
    409 void * shaders_cache_fill(struct shaders_cache *sc,
    410                           int shader_key)
    411 {
    412    VGint key = shader_key;
    413    struct cached_shader *cached;
    414    struct cso_hash_iter iter = cso_hash_find(sc->hash, key);
    415 
    416    if (cso_hash_iter_is_null(iter)) {
    417       cached = CALLOC_STRUCT(cached_shader);
    418       cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state);
    419 
    420       cso_hash_insert(sc->hash, key, cached);
    421 
    422       return cached->driver_shader;
    423    }
    424 
    425    cached = (struct cached_shader *)cso_hash_iter_data(iter);
    426 
    427    assert(cached->driver_shader);
    428    return cached->driver_shader;
    429 }
    430 
    431 struct vg_shader * shader_create_from_text(struct pipe_context *pipe,
    432                                            const char *txt, int num_tokens,
    433                                            int type)
    434 {
    435    struct vg_shader *shader = (struct vg_shader *)MALLOC(
    436       sizeof(struct vg_shader));
    437    struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens);
    438    struct pipe_shader_state state;
    439 
    440    debug_assert(type == PIPE_SHADER_VERTEX ||
    441                 type == PIPE_SHADER_FRAGMENT);
    442 
    443    state.tokens = tokens;
    444    memset(&state.stream_output, 0, sizeof(state.stream_output));
    445    shader->type = type;
    446    shader->tokens = tokens;
    447 
    448    if (type == PIPE_SHADER_FRAGMENT)
    449       shader->driver = pipe->create_fs_state(pipe, &state);
    450    else
    451       shader->driver = pipe->create_vs_state(pipe, &state);
    452    return shader;
    453 }
    454 
    455 void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader)
    456 {
    457    if (shader->type == PIPE_SHADER_FRAGMENT)
    458       cso_delete_fragment_shader(ctx->cso_context, shader->driver);
    459    else
    460       cso_delete_vertex_shader(ctx->cso_context, shader->driver);
    461    FREE(shader->tokens);
    462    FREE(shader);
    463 }
    464