radeonsi: remove redundant si_shader_info::images_declared
[mesa.git] / src / gallium / drivers / svga / svga_state_tss.c
index b3137945202add4bccbae2270365d8675ba4d8ff..75b0ac60f58ba676df62cab8de36ce9d29fb8aeb 100644 (file)
  *
  **********************************************************/
 
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
 #include "pipe/p_defines.h"
 #include "util/u_math.h"
 
-#include "svga_screen_texture.h"
+#include "svga_resource_texture.h"
+#include "svga_sampler_view.h"
 #include "svga_winsys.h"
 #include "svga_context.h"
+#include "svga_shader.h"
 #include "svga_state.h"
 #include "svga_cmd.h"
 
-#include "svga_hw_reg.h"
 
-
-void svga_cleanup_tss_binding(struct svga_context *svga)
+/**
+ * Called when tearing down a context to free resources and samplers.
+ */
+void
+svga_cleanup_tss_binding(struct svga_context *svga)
 {
-   int i;
-   unsigned count = MAX2( svga->curr.num_textures,
-                          svga->state.hw_draw.num_views );
+   const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
+   unsigned i;
 
-   for (i = 0; i < count; i++) {
+   for (i = 0; i < ARRAY_SIZE(svga->state.hw_draw.views); i++) {
       struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+      if (view) {
+         svga_sampler_view_reference(&view->v, NULL);
+         pipe_sampler_view_reference(&svga->curr.sampler_views[shader][i],
+                                     NULL);
+         pipe_resource_reference(&view->texture, NULL);
+         view->dirty = TRUE;
+      }
+   }
+}
+
+
+struct bind_queue {
+   struct {
+      unsigned unit;
+      struct svga_hw_view_state *view;
+   } bind[PIPE_MAX_SAMPLERS];
+
+   unsigned bind_count;
+};
+
+
+/**
+ * Update the texture binding for one texture unit.
+ */
+static void
+emit_tex_binding_unit(struct svga_context *svga,
+                      unsigned unit,
+                      const struct svga_sampler_state *s,
+                      const struct pipe_sampler_view *sv,
+                      struct svga_hw_view_state *view,
+                      boolean reemit,
+                      struct bind_queue *queue)
+{
+   struct pipe_resource *texture = NULL;
+   unsigned last_level, min_lod, max_lod;
+
+   /* get min max lod */
+   if (sv && s) {
+      if (s->mipfilter == SVGA3D_TEX_FILTER_NONE) {
+         /* just use the base level image */
+         min_lod = max_lod = sv->u.tex.first_level;
+      }
+      else {
+         last_level = MIN2(sv->u.tex.last_level, sv->texture->last_level);
+         min_lod = s->view_min_lod + sv->u.tex.first_level;
+         min_lod = MIN2(min_lod, last_level);
+         max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, last_level);
+      }
+      texture = sv->texture;
+   }
+   else {
+      min_lod = 0;
+      max_lod = 0;
+   }
+
+   if (view->texture != texture ||
+       view->min_lod != min_lod ||
+       view->max_lod != max_lod) {
 
       svga_sampler_view_reference(&view->v, NULL);
-      pipe_texture_reference( &svga->curr.texture[i], NULL );
-      pipe_texture_reference( &view->texture, NULL );
+      pipe_resource_reference(&view->texture, texture);
+
+      view->dirty = TRUE;
+      view->min_lod = min_lod;
+      view->max_lod = max_lod;
+
+      if (texture) {
+         view->v = svga_get_tex_sampler_view(&svga->pipe,
+                                             texture,
+                                             min_lod,
+                                             max_lod);
+      }
+   }
+
+   /*
+    * We need to reemit non-null texture bindings, even when they are not
+    * dirty, to ensure that the resources are paged in.
+    */
+   if (view->dirty || (reemit && view->v)) {
+      queue->bind[queue->bind_count].unit = unit;
+      queue->bind[queue->bind_count].view = view;
+      queue->bind_count++;
+   }
 
-      view->dirty = 1;
+   if (!view->dirty && view->v) {
+      svga_validate_sampler_view(svga, view->v);
    }
 }
 
 
-static int
-update_tss_binding(struct svga_context *svga, 
-                   unsigned dirty )
+static enum pipe_error
+update_tss_binding(struct svga_context *svga, uint64_t dirty )
 {
+   const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
+   boolean reemit = svga->rebind.flags.texture_samplers;
    unsigned i;
-   unsigned count = MAX2( svga->curr.num_textures,
-                          svga->state.hw_draw.num_views );
-   unsigned min_lod;
-   unsigned max_lod;
+   unsigned count = MAX2(svga->curr.num_sampler_views[shader],
+                         svga->state.hw_draw.num_views);
 
+   struct bind_queue queue;
 
-   struct {
-      struct {
-         unsigned unit;
-         struct svga_hw_view_state *view;
-      } bind[PIPE_MAX_SAMPLERS];
-
-      unsigned bind_count;
-   } queue;
+   assert(!svga_have_vgpu10(svga));
 
    queue.bind_count = 0;
-   
+
    for (i = 0; i < count; i++) {
-      const struct svga_sampler_state *s = svga->curr.sampler[i];
-      struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+      emit_tex_binding_unit(svga, i,
+                            svga->curr.sampler[shader][i],
+                            svga->curr.sampler_views[shader][i],
+                            &svga->state.hw_draw.views[i],
+                            reemit,
+                            &queue);
+   }
 
-      /* get min max lod */
-      if (svga->curr.texture[i]) {
-         min_lod = MAX2(s->view_min_lod, 0);
-         max_lod = MIN2(s->view_max_lod, svga->curr.texture[i]->last_level);
-      } else {
-         min_lod = 0;
-         max_lod = 0;
-      }
+   svga->state.hw_draw.num_views = svga->curr.num_sampler_views[shader];
+
+   /* Polygon stipple */
+   if (svga->curr.rast->templ.poly_stipple_enable) {
+      const unsigned unit =
+         svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit;
+      emit_tex_binding_unit(svga, unit,
+                            svga->polygon_stipple.sampler,
+                            &svga->polygon_stipple.sampler_view->base,
+                            &svga->state.hw_draw.views[unit],
+                            reemit,
+                            &queue);
+   }
 
-      if (view->texture != svga->curr.texture[i] ||
-          view->min_lod != min_lod ||
-          view->max_lod != max_lod) {
+   svga->state.hw_draw.num_backed_views = 0;
 
-         svga_sampler_view_reference(&view->v, NULL);
-         pipe_texture_reference( &view->texture, svga->curr.texture[i] );
+   if (queue.bind_count) {
+      SVGA3dTextureState *ts;
 
-         view->dirty = TRUE;
-         view->min_lod = min_lod;
-         view->max_lod = max_lod;
-
-         if (svga->curr.texture[i])
-            view->v = svga_get_tex_sampler_view(&svga->pipe, 
-                                                svga->curr.texture[i], 
-                                                min_lod,
-                                                max_lod);
+      if (SVGA3D_BeginSetTextureState(svga->swc, &ts,
+                                      queue.bind_count) != PIPE_OK)
+         goto fail;
+
+      for (i = 0; i < queue.bind_count; i++) {
+         struct svga_winsys_surface *handle;
+         struct svga_hw_view_state *view = queue.bind[i].view;
+
+         ts[i].stage = queue.bind[i].unit;
+         ts[i].name = SVGA3D_TS_BIND_TEXTURE;
+
+         if (view->v) {
+            handle = view->v->handle;
+
+            /* Keep track of number of views with a backing copy
+             * of texture.
+             */
+            if (handle != svga_texture(view->texture)->handle)
+               svga->state.hw_draw.num_backed_views++;
+         }
+         else {
+            handle = NULL;
+         }
+         svga->swc->surface_relocation(svga->swc,
+                                       &ts[i].value,
+                                       NULL,
+                                       handle,
+                                       SVGA_RELOC_READ);
+
+         queue.bind[i].view->dirty = FALSE;
       }
 
-      if (view->dirty) {
+      SVGA_FIFOCommitAll(svga->swc);
+   }
+
+   svga->rebind.flags.texture_samplers = FALSE;
+
+   return PIPE_OK;
+
+fail:
+   return PIPE_ERROR_OUT_OF_MEMORY;
+}
+
+
+/*
+ * Rebind textures.
+ *
+ * Similar to update_tss_binding, but without any state checking/update.
+ *
+ * Called at the beginning of every new command buffer to ensure that
+ * non-dirty textures are properly paged-in.
+ */
+enum pipe_error
+svga_reemit_tss_bindings(struct svga_context *svga)
+{
+   unsigned i;
+   enum pipe_error ret;
+   struct bind_queue queue;
+
+   assert(!svga_have_vgpu10(svga));
+   assert(svga->rebind.flags.texture_samplers);
+
+   queue.bind_count = 0;
+
+   for (i = 0; i < svga->state.hw_draw.num_views; i++) {
+      struct svga_hw_view_state *view = &svga->state.hw_draw.views[i];
+
+      if (view->v) {
          queue.bind[queue.bind_count].unit = i;
          queue.bind[queue.bind_count].view = view;
          queue.bind_count++;
-      } 
-      else if (view->v) {
-         svga_validate_sampler_view(svga, view->v);
       }
    }
 
-   svga->state.hw_draw.num_views = svga->curr.num_textures;
+   /* Polygon stipple */
+   if (svga->curr.rast && svga->curr.rast->templ.poly_stipple_enable) {
+      const unsigned unit =
+         svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit;
+      struct svga_hw_view_state *view = &svga->state.hw_draw.views[unit];
+
+      if (view->v) {
+         queue.bind[queue.bind_count].unit = unit;
+         queue.bind[queue.bind_count].view = view;
+         queue.bind_count++;
+      }
+   }
 
    if (queue.bind_count) {
       SVGA3dTextureState *ts;
 
-      if (SVGA3D_BeginSetTextureState( svga->swc,
-                                       &ts,
-                                       queue.bind_count ) != PIPE_OK)
-         goto fail;
+      ret = SVGA3D_BeginSetTextureState(svga->swc, &ts, queue.bind_count);
+      if (ret != PIPE_OK) {
+         return ret;
+      }
 
       for (i = 0; i < queue.bind_count; i++) {
+         struct svga_winsys_surface *handle;
+
          ts[i].stage = queue.bind[i].unit;
          ts[i].name = SVGA3D_TS_BIND_TEXTURE;
 
-         if (queue.bind[i].view->v) {
-            svga->swc->surface_relocation(svga->swc,
-                                          &ts[i].value,
-                                          queue.bind[i].view->v->handle,
-                                          PIPE_BUFFER_USAGE_GPU_READ);
-         }
-         else {
-            ts[i].value = SVGA3D_INVALID_ID;
-         }
-         
-         queue.bind[i].view->dirty = FALSE;
+         assert(queue.bind[i].view->v);
+         handle = queue.bind[i].view->v->handle;
+         svga->swc->surface_relocation(svga->swc,
+                                       &ts[i].value,
+                                       NULL,
+                                       handle,
+                                       SVGA_RELOC_READ);
       }
 
-      SVGA_FIFOCommitAll( svga->swc );
+      SVGA_FIFOCommitAll(svga->swc);
    }
 
-   return 0;
+   svga->rebind.flags.texture_samplers = FALSE;
 
-fail:
-   return PIPE_ERROR_OUT_OF_MEMORY;
+   return PIPE_OK;
 }
 
 
 struct svga_tracked_state svga_hw_tss_binding = {
    "texture binding emit",
+   SVGA_NEW_FRAME_BUFFER |
    SVGA_NEW_TEXTURE_BINDING |
+   SVGA_NEW_STIPPLE |
    SVGA_NEW_SAMPLER,
    update_tss_binding
 };
 
 
-/***********************************************************************
- */
 
 struct ts_queue {
    unsigned ts_count;
@@ -171,92 +317,106 @@ struct ts_queue {
 };
 
 
-#define EMIT_TS(svga, unit, val, token, fail)                           \
+static inline void
+svga_queue_tss(struct ts_queue *q, unsigned unit, unsigned tss, unsigned value)
+{
+   assert(q->ts_count < ARRAY_SIZE(q->ts));
+   q->ts[q->ts_count].stage = unit;
+   q->ts[q->ts_count].name = tss;
+   q->ts[q->ts_count].value = value;
+   q->ts_count++;
+}
+
+
+#define EMIT_TS(svga, unit, val, token)                                 \
 do {                                                                    \
+   assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
+   STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
-      svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
+      svga_queue_tss(queue, unit, SVGA3D_TS_##token, val);             \
       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    }                                                                    \
 } while (0)
 
-#define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail)                  \
+#define EMIT_TS_FLOAT(svga, unit, fvalue, token)                        \
 do {                                                                    \
    unsigned val = fui(fvalue);                                          \
+   assert(unit < ARRAY_SIZE(svga->state.hw_draw.ts));                     \
+   STATIC_ASSERT(SVGA3D_TS_##token < ARRAY_SIZE(svga->state.hw_draw.ts[unit])); \
    if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) {        \
-      svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val );           \
+      svga_queue_tss(queue, unit, SVGA3D_TS_##token, val);              \
       svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val;            \
    }                                                                    \
 } while (0)
 
 
-static INLINE void 
-svga_queue_tss( struct ts_queue *q,
-                unsigned unit,
-                unsigned tss,
-                unsigned value )
+/**
+ * Emit texture sampler state (tss) for one texture unit.
+ */
+static void
+emit_tss_unit(struct svga_context *svga, unsigned unit,
+              const struct svga_sampler_state *state,
+              struct ts_queue *queue)
 {
-   assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0]));
-   q->ts[q->ts_count].stage = unit;
-   q->ts[q->ts_count].name = tss;
-   q->ts[q->ts_count].value = value;
-   q->ts_count++;
+   EMIT_TS(svga, unit, state->mipfilter, MIPFILTER);
+   EMIT_TS(svga, unit, state->min_lod, TEXTURE_MIPMAP_LEVEL);
+   EMIT_TS(svga, unit, state->magfilter, MAGFILTER);
+   EMIT_TS(svga, unit, state->minfilter, MINFILTER);
+   EMIT_TS(svga, unit, state->aniso_level, TEXTURE_ANISOTROPIC_LEVEL);
+   EMIT_TS_FLOAT(svga, unit, state->lod_bias, TEXTURE_LOD_BIAS);
+   EMIT_TS(svga, unit, state->addressu, ADDRESSU);
+   EMIT_TS(svga, unit, state->addressw, ADDRESSW);
+   EMIT_TS(svga, unit, state->bordercolor, BORDERCOLOR);
+   // TEXCOORDINDEX -- hopefully not needed
+
+   if (svga->curr.tex_flags.flag_1d & (1 << unit))
+      EMIT_TS(svga, unit, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV);
+   else
+      EMIT_TS(svga, unit, state->addressv, ADDRESSV);
+
+   if (svga->curr.tex_flags.flag_srgb & (1 << unit))
+      EMIT_TS_FLOAT(svga, unit, 2.2f, GAMMA);
+   else
+      EMIT_TS_FLOAT(svga, unit, 1.0f, GAMMA);
 }
 
-
-static int
-update_tss(struct svga_context *svga, 
-           unsigned dirty )
+static enum pipe_error
+update_tss(struct svga_context *svga, uint64_t dirty )
 {
+   const enum pipe_shader_type shader = PIPE_SHADER_FRAGMENT;
    unsigned i;
    struct ts_queue queue;
 
-   queue.ts_count = 0;
-   for (i = 0; i < svga->curr.num_samplers; i++) {
-      if (svga->curr.sampler[i]) {
-         const struct svga_sampler_state *curr = svga->curr.sampler[i];
-
-         EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail);
-         EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail);
-         EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail);
-         EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail);
-         EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail);
-         EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail);
-         EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail);
-         EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail);
-         EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail);
-         // TEXCOORDINDEX -- hopefully not needed
-
-         if (svga->curr.tex_flags.flag_1d & (1 << i)) {
-            debug_printf("wrap 1d tex %d\n", i);
-            EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail);
-         }
-         else
-            EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail);
-
-         if (svga->curr.tex_flags.flag_srgb & (1 << i))
-            EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail);
-         else
-            EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail);
+   assert(!svga_have_vgpu10(svga));
 
+   queue.ts_count = 0;
+   for (i = 0; i < svga->curr.num_samplers[shader]; i++) {
+      if (svga->curr.sampler[shader][i]) {
+         const struct svga_sampler_state *curr = svga->curr.sampler[shader][i];
+         emit_tss_unit(svga, i, curr, &queue);
       }
    }
+
+   /* polygon stipple sampler */
+   if (svga->curr.rast->templ.poly_stipple_enable) {
+      emit_tss_unit(svga,
+                    svga_fs_variant(svga->state.hw_draw.fs)->pstipple_sampler_unit,
+                    svga->polygon_stipple.sampler,
+                    &queue);
+   }
+
    if (queue.ts_count) {
       SVGA3dTextureState *ts;
 
-      if (SVGA3D_BeginSetTextureState( svga->swc,
-                                       &ts,
-                                       queue.ts_count ) != PIPE_OK)
+      if (SVGA3D_BeginSetTextureState(svga->swc, &ts, queue.ts_count) != PIPE_OK)
          goto fail;
 
-      memcpy( ts,
-              queue.ts,
-              queue.ts_count * sizeof queue.ts[0]);
-      
-      SVGA_FIFOCommitAll( svga->swc );
+      memcpy(ts, queue.ts, queue.ts_count * sizeof queue.ts[0]);
+
+      SVGA_FIFOCommitAll(svga->swc);
    }
 
-   return 0;
+   return PIPE_OK;
 
 fail:
    /* XXX: need to poison cached hardware state on failure to ensure
@@ -273,6 +433,7 @@ fail:
 struct svga_tracked_state svga_hw_tss = {
    "texture state emit",
    (SVGA_NEW_SAMPLER |
+    SVGA_NEW_STIPPLE |
     SVGA_NEW_TEXTURE_FLAGS),
    update_tss
 };