st/mesa: add support for ARB_sample_locations
[mesa.git] / src / mesa / state_tracker / st_atom_msaa.c
index 556c7c5889e02225b281185452a6590d659f4012..c6affec5525150568525820db90d19138f84b467 100644 (file)
 #include "st_program.h"
 
 #include "cso_cache/cso_context.h"
+#include "util/u_framebuffer.h"
 #include "main/framebuffer.h"
 
 
-/* Update the sample mask for MSAA.
+/**
+ * Update the sample locations
+ */
+static void
+update_sample_locations(struct st_context *st)
+{
+   struct gl_framebuffer *fb = st->ctx->DrawBuffer;
+
+   if (!st->ctx->Extensions.ARB_sample_locations)
+      return;
+
+   if (fb->ProgrammableSampleLocations) {
+      unsigned grid_width, grid_height, size, pixel, sample_index;
+      unsigned samples = st->state.fb_num_samples;
+      bool sample_location_pixel_grid = fb->SampleLocationPixelGrid;
+      uint8_t locations[
+         PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
+         PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
+
+      st->pipe->screen->get_sample_pixel_grid(
+         st->pipe->screen, samples, &grid_width, &grid_height);
+      size = grid_width * grid_height * samples;
+
+      /**
+       * when a dimension is greater than MAX_SAMPLE_LOCATION_GRID_SIZE,
+       * st->ctx->Driver.GetSamplePixelGrid() returns 1 for both dimensions.
+       */
+      if (grid_width > MAX_SAMPLE_LOCATION_GRID_SIZE ||
+          grid_height > MAX_SAMPLE_LOCATION_GRID_SIZE)
+         sample_location_pixel_grid = false;
+
+      for (pixel = 0; pixel < grid_width * grid_height; pixel++) {
+         for (sample_index = 0; sample_index < samples; sample_index++) {
+            int table_index = sample_index;
+            float x = 0.5f, y = 0.5f;
+            uint8_t loc;
+            if (sample_location_pixel_grid)
+               table_index = pixel * samples + sample_index;
+            if (fb->SampleLocationTable) {
+               x = fb->SampleLocationTable[table_index*2];
+               y = fb->SampleLocationTable[table_index*2+1];
+            }
+            if (st->state.fb_orientation == Y_0_BOTTOM)
+               y = 1.0 - y;
+
+            loc = roundf(CLAMP(x * 16.0f, 0.0f, 15.0f));
+            loc |= (int)roundf(CLAMP(y * 16.0f, 0.0f, 15.0f)) << 4;
+            locations[pixel * samples + sample_index] = loc;
+         }
+      }
+
+      util_sample_locations_flip_y(
+         st->pipe->screen, st->state.fb_height, samples, locations);
+
+      if (!st->state.enable_sample_locations ||
+          st->state.sample_locations_samples != samples ||
+          memcmp(locations, st->state.sample_locations, size) != 0) {
+         st->pipe->set_sample_locations( st->pipe, size, locations);
+         
+         st->state.sample_locations_samples = samples;
+         memcpy(st->state.sample_locations, locations, size);
+      }
+   } else if (st->state.enable_sample_locations) {
+      st->pipe->set_sample_locations(st->pipe, 0, NULL);
+   }
+
+   st->state.enable_sample_locations = fb->ProgrammableSampleLocations;
+}
+
+
+/* Update the sample mask and locations for MSAA.
  */
 void
-st_update_sample_mask(struct st_context *st)
+st_update_sample_state(struct st_context *st)
 {
    unsigned sample_mask = 0xffffffff;
    unsigned sample_count = st->state.fb_num_samples;
@@ -64,6 +135,8 @@ st_update_sample_mask(struct st_context *st)
    }
 
    cso_set_sample_mask(st->cso_context, sample_mask);
+
+   update_sample_locations(st);
 }