Home | History | Annotate | Download | only in nv30
      1 /*
      2  * Copyright 2012 Red Hat Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * Authors: Ben Skeggs
     23  *
     24  */
     25 
     26 #include "draw/draw_context.h"
     27 #include "tgsi/tgsi_parse.h"
     28 
     29 #include "nv_object.xml.h"
     30 #include "nv30/nv30-40_3d.xml.h"
     31 #include "nv30/nv30_context.h"
     32 #include "nv30/nvfx_shader.h"
     33 
     34 static void
     35 nv30_fragprog_upload(struct nv30_context *nv30)
     36 {
     37    struct nouveau_context *nv = &nv30->base;
     38    struct nv30_fragprog *fp = nv30->fragprog.program;
     39    struct pipe_context *pipe = &nv30->base.pipe;
     40 
     41    if (unlikely(!fp->buffer))
     42       fp->buffer = pipe_buffer_create(pipe->screen, 0, 0, fp->insn_len * 4);
     43 
     44 #ifndef PIPE_ARCH_BIG_ENDIAN
     45    pipe_buffer_write(pipe, fp->buffer, 0, fp->insn_len * 4, fp->insn);
     46 #else
     47    {
     48       struct pipe_transfer *transfer;
     49       uint32_t *map;
     50       int i;
     51 
     52       map = pipe_buffer_map(pipe, fp->buffer,
     53                             PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
     54                             &transfer);
     55       for (i = 0; i < fp->insn_len; i++)
     56          *map++ = (fp->insn[i] >> 16) | (fp->insn[i] << 16);
     57       pipe_buffer_unmap(pipe, transfer);
     58    }
     59 #endif
     60 
     61    if (nv04_resource(fp->buffer)->domain != NOUVEAU_BO_VRAM)
     62       nouveau_buffer_migrate(nv, nv04_resource(fp->buffer), NOUVEAU_BO_VRAM);
     63 }
     64 
     65 void
     66 nv30_fragprog_validate(struct nv30_context *nv30)
     67 {
     68    struct nouveau_pushbuf *push = nv30->base.pushbuf;
     69    struct nouveau_object *eng3d = nv30->screen->eng3d;
     70    struct nv30_fragprog *fp = nv30->fragprog.program;
     71    bool upload = false;
     72    int i;
     73 
     74    if (!fp->translated) {
     75       _nvfx_fragprog_translate(eng3d->oclass, fp);
     76       if (!fp->translated)
     77          return;
     78 
     79       upload = true;
     80    }
     81 
     82    /* update constants, also needs to be done on every fp switch as we
     83     * have no idea whether the constbuf changed in the meantime
     84     */
     85    if (nv30->fragprog.constbuf) {
     86       struct pipe_resource *constbuf = nv30->fragprog.constbuf;
     87       uint32_t *cbuf = (uint32_t *)nv04_resource(constbuf)->data;
     88 
     89       for (i = 0; i < fp->nr_consts; i++) {
     90          unsigned off = fp->consts[i].offset;
     91          unsigned idx = fp->consts[i].index * 4;
     92 
     93          if (!memcmp(&fp->insn[off], &cbuf[idx], 4 * 4))
     94             continue;
     95          memcpy(&fp->insn[off], &cbuf[idx], 4 * 4);
     96          upload = true;
     97       }
     98    }
     99 
    100    if (upload)
    101       nv30_fragprog_upload(nv30);
    102 
    103    /* FP_ACTIVE_PROGRAM needs to be done again even if only the consts
    104     * were updated.  TEX_CACHE_CTL magic is not enough to convince the
    105     * GPU that it should re-read the fragprog from VRAM... sigh.
    106     */
    107    if (nv30->state.fragprog != fp || upload) {
    108       struct nv04_resource *r = nv04_resource(fp->buffer);
    109 
    110       if (!PUSH_SPACE(push, 8))
    111          return;
    112       PUSH_RESET(push, BUFCTX_FRAGPROG);
    113 
    114       BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1);
    115       PUSH_RESRC(push, NV30_3D(FP_ACTIVE_PROGRAM), BUFCTX_FRAGPROG, r, 0,
    116                        NOUVEAU_BO_LOW | NOUVEAU_BO_RD | NOUVEAU_BO_OR,
    117                        NV30_3D_FP_ACTIVE_PROGRAM_DMA0,
    118                        NV30_3D_FP_ACTIVE_PROGRAM_DMA1);
    119       BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1);
    120       PUSH_DATA (push, fp->fp_control);
    121       if (eng3d->oclass < NV40_3D_CLASS) {
    122          BEGIN_NV04(push, NV30_3D(FP_REG_CONTROL), 1);
    123          PUSH_DATA (push, 0x00010004);
    124          BEGIN_NV04(push, NV30_3D(TEX_UNITS_ENABLE), 1);
    125          PUSH_DATA (push, fp->texcoords);
    126       } else {
    127          BEGIN_NV04(push, SUBC_3D(0x0b40), 1);
    128          PUSH_DATA (push, 0x00000000);
    129       }
    130 
    131       nv30->state.fragprog = fp;
    132    }
    133 }
    134 
    135 static void *
    136 nv30_fp_state_create(struct pipe_context *pipe,
    137                      const struct pipe_shader_state *cso)
    138 {
    139    struct nv30_fragprog *fp = CALLOC_STRUCT(nv30_fragprog);
    140    if (!fp)
    141       return NULL;
    142 
    143    fp->pipe.tokens = tgsi_dup_tokens(cso->tokens);
    144    tgsi_scan_shader(fp->pipe.tokens, &fp->info);
    145    return fp;
    146 }
    147 
    148 static void
    149 nv30_fp_state_delete(struct pipe_context *pipe, void *hwcso)
    150 {
    151    struct nv30_fragprog *fp = hwcso;
    152 
    153    pipe_resource_reference(&fp->buffer, NULL);
    154 
    155    if (fp->draw)
    156       draw_delete_fragment_shader(nv30_context(pipe)->draw, fp->draw);
    157 
    158    FREE((void *)fp->pipe.tokens);
    159    FREE(fp->insn);
    160    FREE(fp->consts);
    161    FREE(fp);
    162 }
    163 
    164 static void
    165 nv30_fp_state_bind(struct pipe_context *pipe, void *hwcso)
    166 {
    167    struct nv30_context *nv30 = nv30_context(pipe);
    168    struct nv30_fragprog *fp = hwcso;
    169 
    170    /* reset the bucftx so that we don't keep a dangling reference to the fp
    171     * code
    172     */
    173    if (fp != nv30->state.fragprog)
    174       PUSH_RESET(nv30->base.pushbuf, BUFCTX_FRAGPROG);
    175 
    176    nv30->fragprog.program = fp;
    177    nv30->dirty |= NV30_NEW_FRAGPROG;
    178 }
    179 
    180 void
    181 nv30_fragprog_init(struct pipe_context *pipe)
    182 {
    183    pipe->create_fs_state = nv30_fp_state_create;
    184    pipe->bind_fs_state = nv30_fp_state_bind;
    185    pipe->delete_fs_state = nv30_fp_state_delete;
    186 }
    187