util: Move os_misc to util
[mesa.git] / src / gallium / auxiliary / util / u_framebuffer.c
index 7803ec6a8b501f77e21f6cfcd612ee7680b05f6a..5bafddc726fb73d86bb68467dda9f28a2545ea80 100644 (file)
@@ -55,16 +55,20 @@ util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
        dst->height != src->height)
       return FALSE;
 
-   for (i = 0; i < Elements(src->cbufs); i++) {
-      if (dst->cbufs[i] != src->cbufs[i]) {
-         return FALSE;
-      }
-   }
+   if (dst->samples != src->samples ||
+       dst->layers  != src->layers)
+      return FALSE;
 
    if (dst->nr_cbufs != src->nr_cbufs) {
       return FALSE;
    }
 
+   for (i = 0; i < src->nr_cbufs; i++) {
+      if (dst->cbufs[i] != src->cbufs[i]) {
+         return FALSE;
+      }
+   }
+
    if (dst->zsbuf != src->zsbuf) {
       return FALSE;
    }
@@ -82,18 +86,37 @@ util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
 {
    unsigned i;
 
-   dst->width = src->width;
-   dst->height = src->height;
+   if (src) {
+      dst->width = src->width;
+      dst->height = src->height;
+
+      dst->samples = src->samples;
+      dst->layers  = src->layers;
+
+      for (i = 0; i < src->nr_cbufs; i++)
+         pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
+
+      /* Set remaining dest cbuf pointers to NULL */
+      for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
+         pipe_surface_reference(&dst->cbufs[i], NULL);
+
+      dst->nr_cbufs = src->nr_cbufs;
 
-   for (i = 0; i < src->nr_cbufs; i++)
-      pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
+      pipe_surface_reference(&dst->zsbuf, src->zsbuf);
+   } else {
+      dst->width = 0;
+      dst->height = 0;
 
-   for (i = src->nr_cbufs; i < dst->nr_cbufs; i++)
-      pipe_surface_reference(&dst->cbufs[i], NULL);
+      dst->samples = 0;
+      dst->layers  = 0;
 
-   dst->nr_cbufs = src->nr_cbufs;
+      for (i = 0 ; i < ARRAY_SIZE(dst->cbufs); i++)
+         pipe_surface_reference(&dst->cbufs[i], NULL);
 
-   pipe_surface_reference(&dst->zsbuf, src->zsbuf);
+      dst->nr_cbufs = 0;
+
+      pipe_surface_reference(&dst->zsbuf, NULL);
+   }
 }
 
 
@@ -108,6 +131,7 @@ util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
 
    pipe_surface_reference(&fb->zsbuf, NULL);
 
+   fb->samples = fb->layers = 0;
    fb->width = fb->height = 0;
    fb->nr_cbufs = 0;
 }
@@ -126,6 +150,9 @@ util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
    unsigned i;
 
    for (i = 0; i < fb->nr_cbufs; i++) {
+      if (!fb->cbufs[i])
+         continue;
+
       w = MIN2(w, fb->cbufs[i]->width);
       h = MIN2(h, fb->cbufs[i]->height);
    }
@@ -135,7 +162,7 @@ util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
       h = MIN2(h, fb->zsbuf->height);
    }
 
-   if (w == ~0) {
+   if (w == ~0u) {
       *width = 0;
       *height = 0;
       return FALSE;
@@ -146,3 +173,100 @@ util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
       return TRUE;
    }
 }
+
+
+/**
+ * Return the number of layers set in the framebuffer state.
+ */
+unsigned
+util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
+{
+       unsigned i, num_layers = 0;
+
+       /**
+        * In the case of ARB_framebuffer_no_attachment
+        * we obtain the number of layers directly from
+        * the framebuffer state.
+        */
+       if (!(fb->nr_cbufs || fb->zsbuf))
+               return fb->layers;
+
+       for (i = 0; i < fb->nr_cbufs; i++) {
+               if (fb->cbufs[i]) {
+                       unsigned num = fb->cbufs[i]->u.tex.last_layer -
+                                      fb->cbufs[i]->u.tex.first_layer + 1;
+                       num_layers = MAX2(num_layers, num);
+               }
+       }
+       if (fb->zsbuf) {
+               unsigned num = fb->zsbuf->u.tex.last_layer -
+                              fb->zsbuf->u.tex.first_layer + 1;
+               num_layers = MAX2(num_layers, num);
+       }
+       return num_layers;
+}
+
+
+/**
+ * Return the number of MSAA samples.
+ */
+unsigned
+util_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
+{
+   unsigned i;
+
+   /**
+    * In the case of ARB_framebuffer_no_attachment
+    * we obtain the number of samples directly from
+    * the framebuffer state.
+    *
+    * NOTE: fb->samples may wind up as zero due to memset()'s on internal
+    *       driver structures on their initialization and so we take the
+    *       MAX here to ensure we have a valid number of samples. However,
+    *       if samples is legitimately not getting set somewhere
+    *       multi-sampling will evidently break.
+    */
+   if (!(fb->nr_cbufs || fb->zsbuf))
+      return MAX2(fb->samples, 1);
+
+   for (i = 0; i < fb->nr_cbufs; i++) {
+      if (fb->cbufs[i]) {
+         return MAX2(1, fb->cbufs[i]->texture->nr_samples);
+      }
+   }
+   if (fb->zsbuf) {
+      return MAX2(1, fb->zsbuf->texture->nr_samples);
+   }
+
+   return 1;
+}
+
+
+/**
+ * Flip the sample location state along the Y axis.
+ */
+void
+util_sample_locations_flip_y(struct pipe_screen *screen, unsigned fb_height,
+                             unsigned samples, uint8_t *locations)
+{
+   unsigned row, i, shift, grid_width, grid_height;
+   uint8_t new_locations[
+      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
+      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
+
+   screen->get_sample_pixel_grid(screen, samples, &grid_width, &grid_height);
+
+   shift = fb_height % grid_height;
+
+   for (row = 0; row < grid_height; row++) {
+      unsigned row_size = grid_width * samples;
+      for (i = 0; i < row_size; i++) {
+         unsigned dest_row = grid_height - row - 1;
+         /* this relies on unsigned integer wraparound behaviour */
+         dest_row = (dest_row - shift) % grid_height;
+         new_locations[dest_row * row_size + i] = locations[row * row_size + i];
+      }
+   }
+
+   memcpy(locations, new_locations, grid_width * grid_height * samples);
+}