Home | History | Annotate | Download | only in state_tracker
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /*
     29  * Generate fragment programs to implement pixel transfer ops, such as
     30  * scale/bias, colortable, convolution...
     31  *
     32  * Authors:
     33  *   Brian Paul
     34  */
     35 
     36 #include "main/imports.h"
     37 #include "main/image.h"
     38 #include "main/macros.h"
     39 #include "program/program.h"
     40 #include "program/prog_cache.h"
     41 #include "program/prog_instruction.h"
     42 #include "program/prog_parameter.h"
     43 #include "program/prog_print.h"
     44 
     45 #include "st_context.h"
     46 #include "st_format.h"
     47 #include "st_texture.h"
     48 
     49 #include "pipe/p_screen.h"
     50 #include "pipe/p_context.h"
     51 #include "util/u_inlines.h"
     52 #include "util/u_pack_color.h"
     53 
     54 
     55 struct state_key
     56 {
     57    GLuint scaleAndBias:1;
     58    GLuint pixelMaps:1;
     59 
     60 #if 0
     61    GLfloat Maps[3][256][4];
     62    int NumMaps;
     63    GLint NumStages;
     64    pipeline_stage Stages[STAGE_MAX];
     65    GLboolean StagesUsed[STAGE_MAX];
     66    GLfloat Scale1[4], Bias1[4];
     67    GLfloat Scale2[4], Bias2[4];
     68 #endif
     69 };
     70 
     71 static void
     72 make_state_key(struct gl_context *ctx,  struct state_key *key)
     73 {
     74    memset(key, 0, sizeof(*key));
     75 
     76    if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 ||
     77        ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 ||
     78        ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 ||
     79        ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) {
     80       key->scaleAndBias = 1;
     81    }
     82 
     83    key->pixelMaps = ctx->Pixel.MapColorFlag;
     84 }
     85 
     86 
     87 /**
     88  * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
     89  */
     90 static void
     91 load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt)
     92 {
     93    struct st_context *st = st_context(ctx);
     94    struct pipe_context *pipe = st->pipe;
     95    struct pipe_transfer *transfer;
     96    const GLuint rSize = ctx->PixelMaps.RtoR.Size;
     97    const GLuint gSize = ctx->PixelMaps.GtoG.Size;
     98    const GLuint bSize = ctx->PixelMaps.BtoB.Size;
     99    const GLuint aSize = ctx->PixelMaps.AtoA.Size;
    100    const uint texSize = pt->width0;
    101    uint *dest;
    102    uint i, j;
    103 
    104    transfer = pipe_get_transfer(pipe,
    105                                 pt, 0, 0, PIPE_TRANSFER_WRITE,
    106                                 0, 0, texSize, texSize);
    107    dest = (uint *) pipe_transfer_map(pipe, transfer);
    108 
    109    /* Pack four 1D maps into a 2D texture:
    110     * R map is placed horizontally, indexed by S, in channel 0
    111     * G map is placed vertically, indexed by T, in channel 1
    112     * B map is placed horizontally, indexed by S, in channel 2
    113     * A map is placed vertically, indexed by T, in channel 3
    114     */
    115    for (i = 0; i < texSize; i++) {
    116       for (j = 0; j < texSize; j++) {
    117          union util_color uc;
    118          int k = (i * texSize + j);
    119          float rgba[4];
    120          rgba[0] = ctx->PixelMaps.RtoR.Map[j * rSize / texSize];
    121          rgba[1] = ctx->PixelMaps.GtoG.Map[i * gSize / texSize];
    122          rgba[2] = ctx->PixelMaps.BtoB.Map[j * bSize / texSize];
    123          rgba[3] = ctx->PixelMaps.AtoA.Map[i * aSize / texSize];
    124          util_pack_color(rgba, pt->format, &uc);
    125          *(dest + k) = uc.ui;
    126       }
    127    }
    128 
    129    pipe_transfer_unmap(pipe, transfer);
    130    pipe->transfer_destroy(pipe, transfer);
    131 }
    132 
    133 
    134 
    135 #define MAX_INST 100
    136 
    137 /**
    138  * Returns a fragment program which implements the current pixel transfer ops.
    139  */
    140 static struct gl_fragment_program *
    141 get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key)
    142 {
    143    struct st_context *st = st_context(ctx);
    144    struct prog_instruction inst[MAX_INST];
    145    struct gl_program_parameter_list *params;
    146    struct gl_fragment_program *fp;
    147    GLuint ic = 0;
    148    const GLuint colorTemp = 0;
    149 
    150    fp = (struct gl_fragment_program *)
    151       ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
    152    if (!fp)
    153       return NULL;
    154 
    155    params = _mesa_new_parameter_list();
    156 
    157    /*
    158     * Get initial pixel color from the texture.
    159     * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
    160     */
    161    _mesa_init_instructions(inst + ic, 1);
    162    inst[ic].Opcode = OPCODE_TEX;
    163    inst[ic].DstReg.File = PROGRAM_TEMPORARY;
    164    inst[ic].DstReg.Index = colorTemp;
    165    inst[ic].SrcReg[0].File = PROGRAM_INPUT;
    166    inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
    167    inst[ic].TexSrcUnit = 0;
    168    inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
    169    ic++;
    170    fp->Base.InputsRead = BITFIELD64_BIT(FRAG_ATTRIB_TEX0);
    171    fp->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
    172    fp->Base.SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */
    173 
    174    if (key->scaleAndBias) {
    175       static const gl_state_index scale_state[STATE_LENGTH] =
    176          { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
    177       static const gl_state_index bias_state[STATE_LENGTH] =
    178          { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 };
    179       GLint scale_p, bias_p;
    180 
    181       scale_p = _mesa_add_state_reference(params, scale_state);
    182       bias_p = _mesa_add_state_reference(params, bias_state);
    183 
    184       /* MAD colorTemp, colorTemp, scale, bias; */
    185       _mesa_init_instructions(inst + ic, 1);
    186       inst[ic].Opcode = OPCODE_MAD;
    187       inst[ic].DstReg.File = PROGRAM_TEMPORARY;
    188       inst[ic].DstReg.Index = colorTemp;
    189       inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
    190       inst[ic].SrcReg[0].Index = colorTemp;
    191       inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR;
    192       inst[ic].SrcReg[1].Index = scale_p;
    193       inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR;
    194       inst[ic].SrcReg[2].Index = bias_p;
    195       ic++;
    196    }
    197 
    198    if (key->pixelMaps) {
    199       const GLuint temp = 1;
    200 
    201       /* create the colormap/texture now if not already done */
    202       if (!st->pixel_xfer.pixelmap_texture) {
    203          st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx);
    204          st->pixel_xfer.pixelmap_sampler_view =
    205             st_create_texture_sampler_view(st->pipe,
    206                                            st->pixel_xfer.pixelmap_texture);
    207       }
    208 
    209       /* with a little effort, we can do four pixel map look-ups with
    210        * two TEX instructions:
    211        */
    212 
    213       /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
    214       _mesa_init_instructions(inst + ic, 1);
    215       inst[ic].Opcode = OPCODE_TEX;
    216       inst[ic].DstReg.File = PROGRAM_TEMPORARY;
    217       inst[ic].DstReg.Index = temp;
    218       inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
    219       inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
    220       inst[ic].SrcReg[0].Index = colorTemp;
    221       inst[ic].TexSrcUnit = 1;
    222       inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
    223       ic++;
    224 
    225       /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
    226       _mesa_init_instructions(inst + ic, 1);
    227       inst[ic].Opcode = OPCODE_TEX;
    228       inst[ic].DstReg.File = PROGRAM_TEMPORARY;
    229       inst[ic].DstReg.Index = temp;
    230       inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
    231       inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
    232       inst[ic].SrcReg[0].Index = colorTemp;
    233       inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
    234                                                  SWIZZLE_Z, SWIZZLE_W);
    235       inst[ic].TexSrcUnit = 1;
    236       inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
    237       ic++;
    238 
    239       /* MOV colorTemp, temp; */
    240       _mesa_init_instructions(inst + ic, 1);
    241       inst[ic].Opcode = OPCODE_MOV;
    242       inst[ic].DstReg.File = PROGRAM_TEMPORARY;
    243       inst[ic].DstReg.Index = colorTemp;
    244       inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
    245       inst[ic].SrcReg[0].Index = temp;
    246       ic++;
    247 
    248       fp->Base.SamplersUsed |= (1 << 1);  /* sampler 1 is used */
    249    }
    250 
    251    /* Modify last instruction's dst reg to write to result.color */
    252    {
    253       struct prog_instruction *last = &inst[ic - 1];
    254       last->DstReg.File = PROGRAM_OUTPUT;
    255       last->DstReg.Index = FRAG_RESULT_COLOR;
    256    }
    257 
    258    /* END; */
    259    _mesa_init_instructions(inst + ic, 1);
    260    inst[ic].Opcode = OPCODE_END;
    261    ic++;
    262 
    263    assert(ic <= MAX_INST);
    264 
    265 
    266    fp->Base.Instructions = _mesa_alloc_instructions(ic);
    267    if (!fp->Base.Instructions) {
    268       _mesa_error(ctx, GL_OUT_OF_MEMORY,
    269                   "generating pixel transfer program");
    270       _mesa_free_parameter_list(params);
    271       return NULL;
    272    }
    273 
    274    _mesa_copy_instructions(fp->Base.Instructions, inst, ic);
    275    fp->Base.NumInstructions = ic;
    276    fp->Base.Parameters = params;
    277 
    278 #if 0
    279    printf("========= pixel transfer prog\n");
    280    _mesa_print_program(&fp->Base);
    281    _mesa_print_parameter_list(fp->Base.Parameters);
    282 #endif
    283 
    284    return fp;
    285 }
    286 
    287 
    288 
    289 /**
    290  * Update st->pixel_xfer.program in response to new pixel-transfer state.
    291  */
    292 static void
    293 update_pixel_transfer(struct st_context *st)
    294 {
    295    struct gl_context *ctx = st->ctx;
    296    struct state_key key;
    297    struct gl_fragment_program *fp;
    298 
    299    make_state_key(st->ctx, &key);
    300 
    301    fp = (struct gl_fragment_program *)
    302       _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key));
    303    if (!fp) {
    304       fp = get_pixel_transfer_program(st->ctx, &key);
    305       _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache,
    306                                  &key, sizeof(key), &fp->Base);
    307    }
    308 
    309    if (ctx->Pixel.MapColorFlag) {
    310       load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture);
    311    }
    312    st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag;
    313 
    314    st->pixel_xfer.program = (struct st_fragment_program *) fp;
    315 }
    316 
    317 
    318 
    319 const struct st_tracked_state st_update_pixel_transfer = {
    320    "st_update_pixel_transfer",				/* name */
    321    {							/* dirty */
    322       _NEW_PIXEL,					/* mesa */
    323       0,						/* st */
    324    },
    325    update_pixel_transfer				/* update */
    326 };
    327