nv50: support vertex program textures
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>
Thu, 10 Dec 2009 19:50:02 +0000 (20:50 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 12 Dec 2009 15:38:59 +0000 (16:38 +0100)
src/gallium/drivers/nv50/nv50_context.h
src/gallium/drivers/nv50/nv50_screen.c
src/gallium/drivers/nv50/nv50_state.c
src/gallium/drivers/nv50/nv50_state_validate.c
src/gallium/drivers/nv50/nv50_tex.c

index 79135f2f3628f0e28d0bdcf37177f452b220a6ed..5578a5838fb4e32254129907b7550c6c44112c71 100644 (file)
@@ -126,7 +126,7 @@ struct nv50_state {
        unsigned viewport_bypass;
        struct nouveau_stateobj *tsc_upload;
        struct nouveau_stateobj *tic_upload;
-       unsigned miptree_nr;
+       unsigned miptree_nr[PIPE_SHADER_TYPES];
        struct nouveau_stateobj *vertprog;
        struct nouveau_stateobj *fragprog;
        struct nouveau_stateobj *programs;
@@ -162,10 +162,10 @@ struct nv50_context {
        unsigned vtxbuf_nr;
        struct pipe_vertex_element vtxelt[PIPE_MAX_ATTRIBS];
        unsigned vtxelt_nr;
-       struct nv50_sampler_stateobj *sampler[PIPE_MAX_SAMPLERS];
-       unsigned sampler_nr;
-       struct nv50_miptree *miptree[PIPE_MAX_SAMPLERS];
-       unsigned miptree_nr;
+       struct nv50_sampler_stateobj *sampler[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
+       unsigned sampler_nr[PIPE_SHADER_TYPES];
+       struct nv50_miptree *miptree[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
+       unsigned miptree_nr[PIPE_SHADER_TYPES];
 
        uint16_t vbo_fifo;
 };
@@ -218,7 +218,7 @@ extern void nv50_state_flush_notify(struct nouveau_channel *chan);
 extern void nv50_so_init_sifc(struct nv50_context *nv50,
                              struct nouveau_stateobj *so,
                              struct nouveau_bo *bo, unsigned reloc,
-                             unsigned size);
+                             unsigned offset, unsigned size);
 
 /* nv50_tex.c */
 extern void nv50_tex_validate(struct nv50_context *);
index e1b2f11239a4e1cc3859c98d112d3b59818878ce..862be46a9ec393029a84d47556dc6209ec2edff2 100644 (file)
@@ -97,6 +97,10 @@ nv50_screen_get_param(struct pipe_screen *pscreen, int param)
        switch (param) {
        case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
                return 32;
+       case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS:
+               return 32;
+       case PIPE_CAP_MAX_COMBINED_SAMPLERS:
+               return 64;
        case PIPE_CAP_NPOT_TEXTURES:
                return 1;
        case PIPE_CAP_TWO_SIDED_STENCIL:
@@ -122,8 +126,6 @@ nv50_screen_get_param(struct pipe_screen *pscreen, int param)
        case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
        case PIPE_CAP_TEXTURE_MIRROR_REPEAT:
                return 1;
-       case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS:
-               return 0;
        case PIPE_CAP_TGSI_CONT_SUPPORTED:
                return 0;
        case PIPE_CAP_BLEND_EQUATION_SEPARATE:
@@ -315,6 +317,9 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        so_method(so, screen->tesla, 0x1400, 1);
        so_data  (so, 0xf);
 
+       /* max TIC (bits 4:8) & TSC (ignored) bindings, per program type */
+       so_method(so, screen->tesla, 0x13b4, 1);
+       so_data  (so, 0x54);
        so_method(so, screen->tesla, 0x13bc, 1);
        so_data  (so, 0x54);
        /* origin is top left (set to 1 for bottom left) */
@@ -387,7 +392,8 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
        so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
        so_data  (so, 0x00000131 | (NV50_CB_PFP << 12));
 
-       ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 64*8*4, &screen->tic);
+       ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32,
+                            &screen->tic);
        if (ret) {
                nv50_screen_destroy(pscreen);
                return NULL;
@@ -398,9 +404,10 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
                  NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
        so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM |
                  NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
-       so_data  (so, 0x000007ff);
+       so_data  (so, PIPE_SHADER_TYPES * 32 - 1);
 
-       ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 64*8*4, &screen->tsc);
+       ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32,
+                            &screen->tsc);
        if (ret) {
                nv50_screen_destroy(pscreen);
                return NULL;
index 07318f23947bc34ba33d37527e2729e885e8b18e..9c8c0c261e54af42f1b3532c61ee1b6165896047 100644 (file)
@@ -215,41 +215,66 @@ nv50_sampler_state_create(struct pipe_context *pipe,
        return (void *)sso;
 }
 
-static void
-nv50_sampler_state_bind(struct pipe_context *pipe, unsigned nr, void **sampler)
+static INLINE void
+nv50_sampler_state_bind(struct pipe_context *pipe, unsigned type,
+                       unsigned nr, void **sampler)
 {
        struct nv50_context *nv50 = nv50_context(pipe);
-       int i;
 
-       nv50->sampler_nr = nr;
-       for (i = 0; i < nv50->sampler_nr; i++)
-               nv50->sampler[i] = sampler[i];
+       memcpy(nv50->sampler[type], sampler, nr * sizeof(void *));
 
+       nv50->sampler_nr[type] = nr;
        nv50->dirty |= NV50_NEW_SAMPLER;
 }
 
+static void
+nv50_vp_sampler_state_bind(struct pipe_context *pipe, unsigned nr, void **s)
+{
+       nv50_sampler_state_bind(pipe, PIPE_SHADER_VERTEX, nr, s);
+}
+
+static void
+nv50_fp_sampler_state_bind(struct pipe_context *pipe, unsigned nr, void **s)
+{
+       nv50_sampler_state_bind(pipe, PIPE_SHADER_FRAGMENT, nr, s);
+}
+
 static void
 nv50_sampler_state_delete(struct pipe_context *pipe, void *hwcso)
 {
        FREE(hwcso);
 }
 
-static void
-nv50_set_sampler_texture(struct pipe_context *pipe, unsigned nr,
-                        struct pipe_texture **pt)
+static INLINE void
+nv50_set_sampler_texture(struct pipe_context *pipe, unsigned type,
+                        unsigned nr, struct pipe_texture **pt)
 {
        struct nv50_context *nv50 = nv50_context(pipe);
-       int i;
+       unsigned i;
 
        for (i = 0; i < nr; i++)
-               pipe_texture_reference((void *)&nv50->miptree[i], pt[i]);
-       for (i = nr; i < nv50->miptree_nr; i++)
-               pipe_texture_reference((void *)&nv50->miptree[i], NULL);
+               pipe_texture_reference((void *)&nv50->miptree[type][i], pt[i]);
+       for (i = nr; i < nv50->miptree_nr[type]; i++)
+               pipe_texture_reference((void *)&nv50->miptree[type][i], NULL);
 
-       nv50->miptree_nr = nr;
+       nv50->miptree_nr[type] = nr;
        nv50->dirty |= NV50_NEW_TEXTURE;
 }
 
+static void
+nv50_set_vp_sampler_textures(struct pipe_context *pipe,
+                            unsigned nr, struct pipe_texture **pt)
+{
+       nv50_set_sampler_texture(pipe, PIPE_SHADER_VERTEX, nr, pt);
+}
+
+static void
+nv50_set_fp_sampler_textures(struct pipe_context *pipe,
+                            unsigned nr, struct pipe_texture **pt)
+{
+       nv50_set_sampler_texture(pipe, PIPE_SHADER_FRAGMENT, nr, pt);
+}
+
 static void *
 nv50_rasterizer_state_create(struct pipe_context *pipe,
                             const struct pipe_rasterizer_state *cso)
@@ -648,9 +673,11 @@ nv50_init_state_functions(struct nv50_context *nv50)
        nv50->pipe.delete_blend_state = nv50_blend_state_delete;
 
        nv50->pipe.create_sampler_state = nv50_sampler_state_create;
-       nv50->pipe.bind_fragment_sampler_states = nv50_sampler_state_bind;
        nv50->pipe.delete_sampler_state = nv50_sampler_state_delete;
-       nv50->pipe.set_fragment_sampler_textures = nv50_set_sampler_texture;
+       nv50->pipe.bind_fragment_sampler_states = nv50_fp_sampler_state_bind;
+       nv50->pipe.bind_vertex_sampler_states   = nv50_vp_sampler_state_bind;
+       nv50->pipe.set_fragment_sampler_textures = nv50_set_fp_sampler_textures;
+       nv50->pipe.set_vertex_sampler_textures   = nv50_set_vp_sampler_textures;
 
        nv50->pipe.create_rasterizer_state = nv50_rasterizer_state_create;
        nv50->pipe.bind_rasterizer_state = nv50_rasterizer_state_bind;
index c871acaab8deacafe238c991c9eebb44f5bd7092..871e8097b65a9650485c512946b4e6c1adad7dfa 100644 (file)
@@ -155,6 +155,30 @@ nv50_state_validate_fb(struct nv50_context *nv50)
        so_ref(NULL, &so);
 }
 
+static void
+nv50_validate_samplers(struct nv50_context *nv50, struct nouveau_stateobj *so,
+                      unsigned p)
+{
+       struct nouveau_grobj *eng2d = nv50->screen->eng2d;
+       unsigned i, j, dw = nv50->sampler_nr[p] * 8;
+
+       if (!dw)
+               return;
+       nv50_so_init_sifc(nv50, so, nv50->screen->tsc, NOUVEAU_BO_VRAM,
+                         p * (32 * 8 * 4), dw * 4);
+
+       so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), dw);
+
+       for (i = 0; i < nv50->sampler_nr[p]; ++i) {
+               if (nv50->sampler[p][i])
+                       so_datap(so, nv50->sampler[p][i]->tsc, 8);
+               else {
+                       for (j = 0; j < 8; ++j) /* you get punished */
+                               so_data(so, 0); /* ... for leaving holes */
+               }
+       }
+}
+
 static void
 nv50_state_emit(struct nv50_context *nv50)
 {
@@ -246,7 +270,6 @@ boolean
 nv50_state_validate(struct nv50_context *nv50)
 {
        struct nouveau_grobj *tesla = nv50->screen->tesla;
-       struct nouveau_grobj *eng2d = nv50->screen->eng2d;
        struct nouveau_stateobj *so;
        unsigned i;
 
@@ -369,22 +392,16 @@ scissor_uptodate:
 viewport_uptodate:
 
        if (nv50->dirty & NV50_NEW_SAMPLER) {
-               unsigned i;
+               unsigned nr = 0;
 
-               so = so_new(nv50->sampler_nr * 9 + 23 + 4, 2);
+               for (i = 0; i < PIPE_SHADER_TYPES; ++i)
+                       nr += nv50->sampler_nr[i];
 
-               nv50_so_init_sifc(nv50, so, nv50->screen->tsc, NOUVEAU_BO_VRAM,
-                                 nv50->sampler_nr * 8 * 4);
+               so = so_new(nr * 8 + 24 * PIPE_SHADER_TYPES + 2, 4);
 
-               for (i = 0; i < nv50->sampler_nr; i++) {
-                       if (!nv50->sampler[i])
-                               continue;
-                       so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), 8);
-                       so_datap (so, nv50->sampler[i]->tsc, 8);
-               }
+               nv50_validate_samplers(nv50, so, PIPE_SHADER_VERTEX);
+               nv50_validate_samplers(nv50, so, PIPE_SHADER_FRAGMENT);
 
-               so_method(so, tesla, 0x1440, 1); /* sync SIFC */
-               so_data  (so, 0);
                so_method(so, tesla, 0x1334, 1); /* flush TSC */
                so_data  (so, 0);
 
@@ -407,10 +424,13 @@ viewport_uptodate:
 
 void nv50_so_init_sifc(struct nv50_context *nv50,
                       struct nouveau_stateobj *so,
-                      struct nouveau_bo *bo, unsigned reloc, unsigned size)
+                      struct nouveau_bo *bo, unsigned reloc,
+                      unsigned offset, unsigned size)
 {
        struct nouveau_grobj *eng2d = nv50->screen->eng2d;
 
+       reloc |= NOUVEAU_BO_WR;
+
        so_method(so, eng2d, NV50_2D_DST_FORMAT, 2);
        so_data  (so, NV50_2D_DST_FORMAT_R8_UNORM);
        so_data  (so, 1);
@@ -418,8 +438,8 @@ void nv50_so_init_sifc(struct nv50_context *nv50,
        so_data  (so, 262144);
        so_data  (so, 65536);
        so_data  (so, 1);
-       so_reloc (so, bo, 0, reloc | NOUVEAU_BO_WR | NOUVEAU_BO_HIGH, 0, 0);
-       so_reloc (so, bo, 0, reloc | NOUVEAU_BO_WR | NOUVEAU_BO_LOW, 0, 0);
+       so_reloc (so, bo, offset, reloc | NOUVEAU_BO_HIGH, 0, 0);
+       so_reloc (so, bo, offset, reloc | NOUVEAU_BO_LOW, 0, 0);
        so_method(so, eng2d, NV50_2D_SIFC_UNK0800, 2);
        so_data  (so, 0);
        so_data  (so, NV50_2D_SIFC_FORMAT_R8_UNORM);
index 417d367942284f44a587e2ffa3b19a4593ab1fa5..60b0ca7159052f2cdfb960f3b038c41a57c45cdc 100644 (file)
@@ -85,7 +85,7 @@ static const struct nv50_texture_format nv50_tex_format_list[] =
 
 static int
 nv50_tex_construct(struct nv50_context *nv50, struct nouveau_stateobj *so,
-                  struct nv50_miptree *mt, int unit)
+                  struct nv50_miptree *mt, int unit, unsigned p)
 {
        unsigned i;
        uint32_t mode;
@@ -96,7 +96,7 @@ nv50_tex_construct(struct nv50_context *nv50, struct nouveau_stateobj *so,
        if (i == NV50_TEX_FORMAT_LIST_SIZE)
                 return 1;
 
-       if (nv50->sampler[unit]->normalized)
+       if (nv50->sampler[p][unit]->normalized)
                mode = 0x50001000 | (1 << 31);
        else {
                mode = 0x50001000 | (7 << 14);
@@ -140,48 +140,78 @@ nv50_tex_construct(struct nv50_context *nv50, struct nouveau_stateobj *so,
        return 0;
 }
 
-void
-nv50_tex_validate(struct nv50_context *nv50)
+#ifndef NV50TCL_BIND_TIC
+#define NV50TCL_BIND_TIC(n) (0x1448 + 8 * n)
+#endif
+
+static boolean
+nv50_validate_textures(struct nv50_context *nv50, struct nouveau_stateobj *so,
+                      unsigned p)
 {
+       static const unsigned p_remap[PIPE_SHADER_TYPES] = { 0, 2 };
+
        struct nouveau_grobj *eng2d = nv50->screen->eng2d;
        struct nouveau_grobj *tesla = nv50->screen->tesla;
-       struct nouveau_stateobj *so;
-       unsigned i, unit, push;
-
-       push = MAX2(nv50->miptree_nr, nv50->state.miptree_nr) * 2 + 23 + 6;
-       so = so_new(nv50->miptree_nr * 9 + push, nv50->miptree_nr * 2 + 2);
+       unsigned unit, j, p_hw = p_remap[p];
 
        nv50_so_init_sifc(nv50, so, nv50->screen->tic, NOUVEAU_BO_VRAM,
-                         nv50->miptree_nr * 8 * 4);
+                         p * (32 * 8 * 4), nv50->miptree_nr[p] * 8 * 4);
 
-       for (i = 0, unit = 0; unit < nv50->miptree_nr; ++unit) {
-               struct nv50_miptree *mt = nv50->miptree[unit];
-
-               if (!mt)
-                       continue;
+       for (unit = 0; unit < nv50->miptree_nr[p]; ++unit) {
+               struct nv50_miptree *mt = nv50->miptree[p][unit];
 
                so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), 8);
-               if (nv50_tex_construct(nv50, so, mt, unit)) {
-                       NOUVEAU_ERR("failed tex validate\n");
-                       so_ref(NULL, &so);
-                       return;
+               if (mt) {
+                       if (nv50_tex_construct(nv50, so, mt, unit, p))
+                               return FALSE;
+                       /* Set TEX insn $t src binding $unit in program type p
+                        * to TIC, TSC entry (32 * p + unit), mark valid (1).
+                        */
+                       so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
+                       so_data  (so, ((32 * p + unit) << 9) | (unit << 1) | 1);
+               } else {
+                       for (j = 0; j < 8; ++j)
+                               so_data(so, 0);
+                       so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
+                       so_data  (so, (unit << 1) | 0);
                }
+       }
+
+       for (; unit < nv50->state.miptree_nr[p]; unit++) {
+               /* Make other bindings invalid. */
+               so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
+               so_data  (so, (unit << 1) | 0);
+       }
+
+       nv50->state.miptree_nr[p] = nv50->miptree_nr[p];
+       return TRUE;
+}
 
-               so_method(so, tesla, NV50TCL_SET_SAMPLER_TEX, 1);
-               so_data  (so, (i++ << NV50TCL_SET_SAMPLER_TEX_TIC_SHIFT) |
-                         (unit << NV50TCL_SET_SAMPLER_TEX_SAMPLER_SHIFT) |
-                         NV50TCL_SET_SAMPLER_TEX_VALID);
+void
+nv50_tex_validate(struct nv50_context *nv50)
+{
+       struct nouveau_stateobj *so;
+       struct nouveau_grobj *tesla = nv50->screen->tesla;
+       unsigned p, push, nrlc;
+
+       for (nrlc = 0, push = 0, p = 0; p < PIPE_SHADER_TYPES; ++p) {
+               push += MAX2(nv50->miptree_nr[p], nv50->state.miptree_nr[p]);
+               nrlc += nv50->miptree_nr[p];
        }
+       push = push * 11 + 23 * PIPE_SHADER_TYPES + 4;
+       nrlc = nrlc * 2 + 2 * PIPE_SHADER_TYPES;
+
+       so = so_new(push, nrlc);
+
+       if (nv50_validate_textures(nv50, so, PIPE_SHADER_VERTEX) == FALSE ||
+           nv50_validate_textures(nv50, so, PIPE_SHADER_FRAGMENT) == FALSE) {
+               so_ref(NULL, &so);
 
-       for (; unit < nv50->state.miptree_nr; unit++) {
-               so_method(so, tesla, NV50TCL_SET_SAMPLER_TEX, 1);
-               so_data  (so,
-                         (unit << NV50TCL_SET_SAMPLER_TEX_SAMPLER_SHIFT) | 0);
+               NOUVEAU_ERR("failed tex validate\n");
+               return;
        }
 
        /* not sure if the following really do what I think: */
-       so_method(so, tesla, 0x1440, 1); /* sync SIFC */
-       so_data  (so, 0);
        so_method(so, tesla, 0x1330, 1); /* flush TIC */
        so_data  (so, 0);
        so_method(so, tesla, 0x1338, 1); /* flush texture caches */
@@ -189,6 +219,4 @@ nv50_tex_validate(struct nv50_context *nv50)
 
        so_ref(so, &nv50->state.tic_upload);
        so_ref(NULL, &so);
-       nv50->state.miptree_nr = nv50->miptree_nr;
 }
-