nv50/ir/opt: improve post-multiply and check target for support
[mesa.git] / src / gallium / drivers / nv50 / nv50_state.c
index 17f272bb3bf3e6a7a5df6d6dd22b9b7490833fe0..bf554427ca0d59a1a2f6cfa7e5622785b0bf06e5 100644 (file)
 
 #include "nouveau/nouveau_gldefs.h"
 
+/* Caveats:
+ *  ! pipe_sampler_state.normalized_coords is ignored - rectangle textures will
+ *     use non-normalized coordinates, everything else won't
+ *    (The relevant bit is in the TIC entry and not the TSC entry.)
+ *
+ *  ! pipe_sampler_state.seamless_cube_map is ignored - seamless filtering is
+ *     always activated on NVA0 +
+ *    (Give me the global bit, otherwise it's not worth the CPU work.)
+ *
+ *  ! pipe_sampler_state.border_color is not swizzled according to the texture
+ *     swizzle in pipe_sampler_view
+ *    (This will be ugly with indirect independent texture/sampler access,
+ *     we'd have to emulate the logic in the shader. GL doesn't have that,
+ *     D3D doesn't have swizzle, if we knew what we were implementing we'd be
+ *     good.)
+ *
+ *  ! pipe_rasterizer_state.line_last_pixel is ignored - it is never drawn
+ *
+ *  ! pipe_rasterizer_state.flatshade_first also applies to QUADS
+ *    (There's a GL query for that, forcing an exception is just ridiculous.)
+ *
+ *  ! pipe_rasterizer_state.gl_rasterization_rules is ignored - pixel centers
+ *     are always at half integer coordinates and the top-left rule applies
+ *    (There does not seem to be a hardware switch for this.)
+ *
+ *  ! pipe_rasterizer_state.sprite_coord_enable is masked with 0xff on NVC0
+ *    (The hardware only has 8 slots meant for TexCoord and we have to assign
+ *     in advance to maintain elegant separate shader objects.)
+ */
+
 static INLINE uint32_t
 nv50_colormask(unsigned mask)
 {
@@ -88,23 +118,51 @@ nv50_blend_state_create(struct pipe_context *pipe,
 {
    struct nv50_blend_stateobj *so = CALLOC_STRUCT(nv50_blend_stateobj);
    int i;
-   boolean blend_enabled = cso->rt[0].blend_enable;
+   boolean emit_common_func = cso->rt[0].blend_enable;
+   uint32_t ms;
+
+   if (nv50_context(pipe)->screen->tesla->oclass >= NVA3_3D_CLASS) {
+      SB_BEGIN_3D(so, BLEND_INDEPENDENT, 1);
+      SB_DATA    (so, cso->independent_blend_enable);
+   }
 
    so->pipe = *cso;
 
-   SB_BEGIN_3D(so, BLEND_ENABLE(0), 8);
+   SB_BEGIN_3D(so, COLOR_MASK_COMMON, 1);
+   SB_DATA    (so, !cso->independent_blend_enable);
+
+   SB_BEGIN_3D(so, BLEND_ENABLE_COMMON, 1);
+   SB_DATA    (so, !cso->independent_blend_enable);
+
    if (cso->independent_blend_enable) {
+      SB_BEGIN_3D(so, BLEND_ENABLE(0), 8);
       for (i = 0; i < 8; ++i) {
          SB_DATA(so, cso->rt[i].blend_enable);
          if (cso->rt[i].blend_enable)
-            blend_enabled = TRUE;
+            emit_common_func = TRUE;
+      }
+
+      if (nv50_context(pipe)->screen->tesla->oclass >= NVA3_3D_CLASS) {
+         emit_common_func = FALSE;
+
+         for (i = 0; i < 8; ++i) {
+            if (!cso->rt[i].blend_enable)
+               continue;
+            SB_BEGIN_3D_(so, NVA3_3D_IBLEND_EQUATION_RGB(i), 6);
+            SB_DATA     (so, nvgl_blend_eqn(cso->rt[i].rgb_func));
+            SB_DATA     (so, nv50_blend_fac(cso->rt[i].rgb_src_factor));
+            SB_DATA     (so, nv50_blend_fac(cso->rt[i].rgb_dst_factor));
+            SB_DATA     (so, nvgl_blend_eqn(cso->rt[i].alpha_func));
+            SB_DATA     (so, nv50_blend_fac(cso->rt[i].alpha_src_factor));
+            SB_DATA     (so, nv50_blend_fac(cso->rt[i].alpha_dst_factor));
+         }
       }
    } else {
-      for (i = 0; i < 8; ++i)
-         SB_DATA(so, blend_enabled);
+      SB_BEGIN_3D(so, BLEND_ENABLE(0), 1);
+      SB_DATA    (so, cso->rt[0].blend_enable);
    }
 
-   if (blend_enabled) {
+   if (emit_common_func) {
       SB_BEGIN_3D(so, BLEND_EQUATION_RGB, 5);
       SB_DATA    (so, nvgl_blend_eqn(cso->rt[0].rgb_func));
       SB_DATA    (so, nv50_blend_fac(cso->rt[0].rgb_src_factor));
@@ -124,17 +182,25 @@ nv50_blend_state_create(struct pipe_context *pipe,
       SB_DATA    (so, 0);
    }
 
-   SB_BEGIN_3D(so, COLOR_MASK(0), 8);
    if (cso->independent_blend_enable) {
+      SB_BEGIN_3D(so, COLOR_MASK(0), 8);
       for (i = 0; i < 8; ++i)
          SB_DATA(so, nv50_colormask(cso->rt[i].colormask));
    } else {
-      uint32_t cmask = nv50_colormask(cso->rt[0].colormask);
-      for (i = 0; i < 8; ++i)
-         SB_DATA(so, cmask);
+      SB_BEGIN_3D(so, COLOR_MASK(0), 1);
+      SB_DATA    (so, nv50_colormask(cso->rt[0].colormask));
    }
 
-   assert(so->size < (sizeof(so->state) / sizeof(so->state[0])));
+   ms = 0;
+   if (cso->alpha_to_coverage)
+      ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE;
+   if (cso->alpha_to_one)
+      ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE;
+
+   SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1);
+   SB_DATA    (so, ms);
+
+   assert(so->size <= (sizeof(so->state) / sizeof(so->state[0])));
    return so;
 }
 
@@ -153,11 +219,13 @@ nv50_blend_state_delete(struct pipe_context *pipe, void *hwcso)
    FREE(hwcso);
 }
 
+/* NOTE: ignoring line_last_pixel, using FALSE (set on screen init) */
 static void *
 nv50_rasterizer_state_create(struct pipe_context *pipe,
                              const struct pipe_rasterizer_state *cso)
 {
    struct nv50_rasterizer_stateobj *so;
+   uint32_t reg;
 
    so = CALLOC_STRUCT(nv50_rasterizer_stateobj);
    if (!so)
@@ -177,6 +245,12 @@ nv50_rasterizer_state_create(struct pipe_context *pipe,
    SB_BEGIN_3D(so, VERTEX_TWO_SIDE_ENABLE, 1);
    SB_DATA    (so, cso->light_twoside);
 
+   SB_BEGIN_3D(so, FRAG_COLOR_CLAMP_EN, 1);
+   SB_DATA    (so, cso->clamp_fragment_color ? 0x11111111 : 0x00000000);
+
+   SB_BEGIN_3D(so, MULTISAMPLE_ENABLE, 1);
+   SB_DATA    (so, cso->multisample);
+
    SB_BEGIN_3D(so, LINE_WIDTH, 1);
    SB_DATA    (so, fui(cso->line_width));
    SB_BEGIN_3D(so, LINE_SMOOTH_ENABLE, 1);
@@ -235,9 +309,27 @@ nv50_rasterizer_state_create(struct pipe_context *pipe,
       SB_DATA    (so, fui(cso->offset_scale));
       SB_BEGIN_3D(so, POLYGON_OFFSET_UNITS, 1);
       SB_DATA    (so, fui(cso->offset_units * 2.0f));
+      SB_BEGIN_3D(so, POLYGON_OFFSET_CLAMP, 1);
+      SB_DATA    (so, fui(cso->offset_clamp));
    }
 
-   assert(so->size < (sizeof(so->state) / sizeof(so->state[0])));
+   if (cso->depth_clip) {
+      reg = 0;
+   } else {
+      reg =
+         NV50_3D_VIEW_VOLUME_CLIP_CTRL_DEPTH_CLAMP_NEAR |
+         NV50_3D_VIEW_VOLUME_CLIP_CTRL_DEPTH_CLAMP_FAR |
+         NV50_3D_VIEW_VOLUME_CLIP_CTRL_UNK12_UNK1;
+   }
+#ifndef NV50_SCISSORS_CLIPPING
+   reg |=
+      NV50_3D_VIEW_VOLUME_CLIP_CTRL_UNK7 |
+      NV50_3D_VIEW_VOLUME_CLIP_CTRL_UNK12_UNK1;
+#endif
+   SB_BEGIN_3D(so, VIEW_VOLUME_CLIP_CTRL, 1);
+   SB_DATA    (so, reg);
+
+   assert(so->size <= (sizeof(so->state) / sizeof(so->state[0])));
    return (void *)so;
 }
 
@@ -316,7 +408,7 @@ nv50_zsa_state_create(struct pipe_context *pipe,
       SB_DATA    (so, 0);
    }
 
-   assert(so->size < (sizeof(so->state) / sizeof(so->state[0])));
+   assert(so->size <= (sizeof(so->state) / sizeof(so->state[0])));
    return (void *)so;
 }
 
@@ -359,7 +451,7 @@ nv50_tsc_wrap_mode(unsigned wrap)
    }
 }
 
-static void *
+void *
 nv50_sampler_state_create(struct pipe_context *pipe,
                           const struct pipe_sampler_state *cso)
 {
@@ -435,10 +527,10 @@ nv50_sampler_state_create(struct pipe_context *pipe,
    so->tsc[2] |=
       (((int)(f[1] * 256.0f) & 0xfff) << 12) | ((int)(f[0] * 256.0f) & 0xfff);
 
-   so->tsc[4] = fui(cso->border_color[0]);
-   so->tsc[5] = fui(cso->border_color[1]);
-   so->tsc[6] = fui(cso->border_color[2]);
-   so->tsc[7] = fui(cso->border_color[3]);
+   so->tsc[4] = fui(cso->border_color.f[0]);
+   so->tsc[5] = fui(cso->border_color.f[1]);
+   so->tsc[6] = fui(cso->border_color.f[2]);
+   so->tsc[7] = fui(cso->border_color.f[3]);
 
    return (void *)so;
 }
@@ -448,7 +540,7 @@ nv50_sampler_state_delete(struct pipe_context *pipe, void *hwcso)
 {
    unsigned s, i;
 
-   for (s = 0; s < 5; ++s)
+   for (s = 0; s < 3; ++s)
       for (i = 0; i < nv50_context(pipe)->num_samplers[s]; ++i)
          if (nv50_context(pipe)->samplers[s][i] == hwcso)
             nv50_context(pipe)->samplers[s][i] = NULL;
@@ -536,7 +628,7 @@ nv50_stage_set_sampler_views(struct nv50_context *nv50, int s,
 
    nv50->num_textures[s] = nr;
 
-   nv50_bufctx_reset(nv50, NV50_BUFCTX_TEXTURES);
+   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_TEXTURES);
 
    nv50->dirty |= NV50_NEW_TEXTURES;
 }
@@ -649,13 +741,15 @@ nv50_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index,
 {
    struct nv50_context *nv50 = nv50_context(pipe);
 
-   if (nv50->constbuf[shader][index])
-      nv50_bufctx_del_resident(nv50, NV50_BUFCTX_CONSTANT,
-                              nv04_resource(nv50->constbuf[shader][index]));
-
    pipe_resource_reference(&nv50->constbuf[shader][index], res);
 
    nv50->constbuf_dirty[shader] |= 1 << index;
+   if (res)
+      nv50->constbuf_valid[shader] |= 1 << index;
+   else
+      nv50->constbuf_valid[shader] &= ~(1 << index);
+
+   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_CB(shader, index));
 
    nv50->dirty |= NV50_NEW_CONSTBUF;
 }
@@ -688,12 +782,8 @@ nv50_set_clip_state(struct pipe_context *pipe,
                     const struct pipe_clip_state *clip)
 {
    struct nv50_context *nv50 = nv50_context(pipe);
-   const unsigned size = clip->nr * sizeof(clip->ucp[0]);
 
-   memcpy(&nv50->clip.ucp[0][0], &clip->ucp[0][0], size);
-   nv50->clip.nr = clip->nr;
-
-   nv50->clip.depth_clamp = clip->depth_clamp;
+   memcpy(nv50->clip.ucp, clip->ucp, sizeof(clip->ucp));
 
    nv50->dirty |= NV50_NEW_CLIP;
 }
@@ -713,8 +803,22 @@ nv50_set_framebuffer_state(struct pipe_context *pipe,
                            const struct pipe_framebuffer_state *fb)
 {
    struct nv50_context *nv50 = nv50_context(pipe);
+   unsigned i;
+
+   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_FB);
+
+   for (i = 0; i < fb->nr_cbufs; ++i)
+      pipe_surface_reference(&nv50->framebuffer.cbufs[i], fb->cbufs[i]);
+   for (; i < nv50->framebuffer.nr_cbufs; ++i)
+      pipe_surface_reference(&nv50->framebuffer.cbufs[i], NULL);
+
+   nv50->framebuffer.nr_cbufs = fb->nr_cbufs;
+
+   nv50->framebuffer.width = fb->width;
+   nv50->framebuffer.height = fb->height;
+
+   pipe_surface_reference(&nv50->framebuffer.zsbuf, fb->zsbuf);
 
-   nv50->framebuffer = *fb;
    nv50->dirty |= NV50_NEW_FRAMEBUFFER;
 }
 
@@ -764,7 +868,7 @@ nv50_set_vertex_buffers(struct pipe_context *pipe,
    memcpy(nv50->vtxbuf, vb, sizeof(*vb) * count);
    nv50->num_vtxbufs = count;
 
-   nv50_bufctx_reset(nv50, NV50_BUFCTX_VERTEX);
+   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_VERTEX);
 
    nv50->dirty |= NV50_NEW_ARRAYS;
 }
@@ -775,10 +879,18 @@ nv50_set_index_buffer(struct pipe_context *pipe,
 {
    struct nv50_context *nv50 = nv50_context(pipe);
 
-   if (ib)
-      memcpy(&nv50->idxbuf, ib, sizeof(nv50->idxbuf));
-   else
-      nv50->idxbuf.buffer = NULL;
+   if (nv50->idxbuf.buffer)
+      nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_INDEX);
+
+   if (ib && ib->buffer) {
+      pipe_resource_reference(&nv50->idxbuf.buffer, ib->buffer);
+      nv50->idxbuf.offset = ib->offset;
+      nv50->idxbuf.index_size = ib->index_size;
+      if (nouveau_resource_mapped_by_gpu(ib->buffer))
+         BCTX_REFN(nv50->bufctx_3d, INDEX, nv04_resource(ib->buffer), RD);
+   } else {
+      pipe_resource_reference(&nv50->idxbuf.buffer, NULL);
+   }
 }
 
 static void
@@ -845,5 +957,7 @@ nv50_init_state_functions(struct nv50_context *nv50)
 
    pipe->set_vertex_buffers = nv50_set_vertex_buffers;
    pipe->set_index_buffer = nv50_set_index_buffer;
+
+   pipe->redefine_user_buffer = u_default_redefine_user_buffer;
 }