st/dri: implement MSAA for GLX/DRI2 framebuffers
authorMarek Olšák <maraeo@gmail.com>
Mon, 3 Dec 2012 04:36:08 +0000 (05:36 +0100)
committerMarek Olšák <maraeo@gmail.com>
Fri, 7 Dec 2012 13:19:29 +0000 (14:19 +0100)
All MSAA buffers are allocated privately and resolved into the DRI-provided
back and front buffers.

If an MSAA visual is chosen, the buffers st/mesa receives are all
multi-sample. st/mesa doesn't have access to the single-sample buffers
in that case.

This makes MSAA work in games like Nexuiz.

Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/state_trackers/dri/common/dri_drawable.c
src/gallium/state_trackers/dri/common/dri_drawable.h
src/gallium/state_trackers/dri/common/dri_screen.c
src/gallium/state_trackers/dri/drm/dri2.c
src/mesa/state_tracker/st_manager.c

index dca6def284c8c83ac9d50a8fb4d6ce6a36cc2662..ee4d11d1495c23c0f77cd378d3d78901225d0d86 100644 (file)
@@ -54,6 +54,9 @@ dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
    boolean new_stamp;
    int i;
    unsigned int lastStamp;
+   struct pipe_resource **textures =
+      drawable->stvis.samples > 1 ? drawable->msaa_textures
+                                  : drawable->textures;
 
    statt_mask = 0x0;
    for (i = 0; i < count; i++)
@@ -79,7 +82,7 @@ dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
 
          /* add existing textures */
          for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
-            if (drawable->textures[i])
+            if (textures[i])
                statt_mask |= (1 << i);
          }
 
@@ -91,9 +94,10 @@ dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
    if (!out)
       return TRUE;
 
+   /* Set the window-system buffers for the state tracker. */
    for (i = 0; i < count; i++) {
       out[i] = NULL;
-      pipe_resource_reference(&out[i], drawable->textures[statts[i]]);
+      pipe_resource_reference(&out[i], textures[statts[i]]);
    }
 
    return TRUE;
@@ -166,6 +170,8 @@ dri_destroy_buffer(__DRIdrawable * dPriv)
 
    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
       pipe_resource_reference(&drawable->textures[i], NULL);
+   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+      pipe_resource_reference(&drawable->msaa_textures[i], NULL);
 
    swap_fences_unref(drawable);
 
@@ -352,6 +358,48 @@ swap_fences_unref(struct dri_drawable *draw)
    }
 }
 
+void
+dri_msaa_resolve(struct dri_context *ctx,
+                 struct dri_drawable *drawable,
+                 enum st_attachment_type att)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct pipe_resource *dst = drawable->textures[att];
+   struct pipe_resource *src = drawable->msaa_textures[att];
+   struct pipe_blit_info blit;
+
+   if (!dst || !src)
+      return;
+
+   memset(&blit, 0, sizeof(blit));
+   blit.dst.resource = dst;
+   blit.dst.box.width = dst->width0;
+   blit.dst.box.height = dst->width0;
+   blit.dst.box.depth = 1;
+   blit.dst.format = util_format_linear(dst->format);
+   blit.src.resource = src;
+   blit.src.box.width = src->width0;
+   blit.src.box.height = src->width0;
+   blit.src.box.depth = 1;
+   blit.src.format = util_format_linear(src->format);
+   blit.mask = PIPE_MASK_RGBA;
+   blit.filter = PIPE_TEX_FILTER_NEAREST;
+
+   pipe->blit(pipe, &blit);
+}
+
+static void
+dri_postprocessing(struct dri_context *ctx,
+                   struct dri_drawable *drawable,
+                   enum st_attachment_type att)
+{
+   struct pipe_resource *src = drawable->textures[att];
+   struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
+
+   if (ctx->pp && src && zsbuf)
+      pp_run(ctx->pp, src, src, zsbuf);
+}
+
 /**
  * DRI2 flush extension, the flush_with_flags function.
  *
@@ -381,10 +429,13 @@ dri_flush(__DRIcontext *cPriv,
 
    /* Flush the drawable. */
    if (flags & __DRI2_FLUSH_DRAWABLE) {
-      struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
+      /* Resolve MSAA buffers. */
+      if (drawable->stvis.samples > 1) {
+         dri_msaa_resolve(ctx, drawable, ST_ATTACHMENT_BACK_LEFT);
+         /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
+      }
 
-      if (ptex && ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
-         pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
+      dri_postprocessing(ctx, drawable, ST_ATTACHMENT_BACK_LEFT);
    }
 
    flush_flags = 0;
index 6a769910fe6574a0d9574ba164cd486f73ed0ede..caa1faa08f4e19f79c582606b8173f647cc297de 100644 (file)
@@ -57,6 +57,7 @@ struct dri_drawable
    unsigned old_h;
 
    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
+   struct pipe_resource *msaa_textures[ST_ATTACHMENT_COUNT];
    unsigned int texture_mask, texture_stamp;
 
    struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX];
@@ -107,6 +108,11 @@ dri_drawable_get_format(struct dri_drawable *drawable,
                         enum pipe_format *format,
                         unsigned *bind);
 
+void
+dri_msaa_resolve(struct dri_context *ctx,
+                 struct dri_drawable *drawable,
+                 enum st_attachment_type att);
+
 void
 dri_flush(__DRIcontext *cPriv,
           __DRIdrawable *dPriv,
index df2cd3f6b379ca8d446d19616f28b4a48ca563d5..6d220f2ed7bc97d3768ca0c0089c0fa27bc3413d 100644 (file)
@@ -104,7 +104,7 @@ dri_fill_in_modes(struct dri_screen *screen)
    stencil_bits_array[0] = 0;
    depth_buffer_factor = 1;
 
-   msaa_samples_max = (screen->st_api->feature_mask & ST_API_FEATURE_MS_VISUALS)
+   msaa_samples_max = (screen->st_api->feature_mask & ST_API_FEATURE_MS_VISUALS_MASK)
       ? MSAA_VISUAL_MAX_SAMPLES : 1;
 
    pf_x8z24 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z24X8_UNORM,
@@ -206,7 +206,9 @@ dri_fill_st_visual(struct st_visual *stvis, struct dri_screen *screen,
    if (!mode)
       return;
 
-   stvis->samples = mode->samples;
+   if (mode->sampleBuffers) {
+      stvis->samples = mode->samples;
+   }
 
    if (mode->redBits == 8) {
       if (mode->alphaBits == 8)
index 5ebe18480d891b15cd9e3b6682b84ff56b079bc3..7f4f2f00c776f236049d8fe0ade033302e8f473d 100644 (file)
@@ -190,6 +190,8 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable,
 
    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
       pipe_resource_reference(&drawable->textures[i], NULL);
+   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
+      pipe_resource_reference(&drawable->msaa_textures[i], NULL);
 
    memset(&templ, 0, sizeof(templ));
    templ.target = screen->target;
@@ -235,6 +237,25 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable,
       drawable->textures[statt] =
          screen->base.screen->resource_from_handle(screen->base.screen,
                &templ, &whandle);
+      assert(drawable->textures[statt]);
+   }
+
+   /* Allocate private MSAA colorbuffers. */
+   if (drawable->stvis.samples > 1) {
+      for (i = 0; i < att_count; i++) {
+         enum st_attachment_type att = atts[i];
+
+         if (drawable->textures[att]) {
+            templ.format = drawable->textures[att]->format;
+            templ.bind = drawable->textures[att]->bind;
+            templ.nr_samples = drawable->stvis.samples;
+
+            drawable->msaa_textures[att] =
+               screen->base.screen->resource_create(screen->base.screen,
+                                                    &templ);
+            assert(drawable->msaa_textures[att]);
+         }
+      }
    }
 
    /* See if we need a depth-stencil buffer. */
@@ -256,8 +277,20 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable,
          templ.format = format;
          templ.bind = bind;
 
-         drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL] =
-            screen->base.screen->resource_create(screen->base.screen, &templ);
+         if (drawable->stvis.samples > 1) {
+            templ.nr_samples = drawable->stvis.samples;
+            drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL] =
+               screen->base.screen->resource_create(screen->base.screen,
+                                                    &templ);
+            assert(drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
+         }
+         else {
+            templ.nr_samples = 0;
+            drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL] =
+               screen->base.screen->resource_create(screen->base.screen,
+                                                    &templ);
+            assert(drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
+         }
       }
    }
 
@@ -380,10 +413,17 @@ dri2_flush_frontbuffer(struct dri_context *ctx,
    __DRIdrawable *dri_drawable = drawable->dPriv;
    struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
 
-   if (loader->flushFrontBuffer == NULL)
+   if (statt != ST_ATTACHMENT_FRONT_LEFT)
       return;
 
-   if (statt == ST_ATTACHMENT_FRONT_LEFT) {
+   if (drawable->stvis.samples > 1) {
+      struct pipe_context *pipe = ctx->st->pipe;
+
+      dri_msaa_resolve(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
+      pipe->flush(pipe, NULL);
+   }
+
+   if (loader->flushFrontBuffer) {
       loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
    }
 }
index da58186147990b937be0132d2ebe923d4a2ffc0a..b065db0acdf58b4be4bbf91461879aa4e9536fd5 100644 (file)
@@ -398,7 +398,7 @@ st_visual_to_context_mode(const struct st_visual *visual,
                UTIL_FORMAT_COLORSPACE_RGB, 3);
    }
 
-   if (visual->samples) {
+   if (visual->samples > 1) {
       mode->sampleBuffers = 1;
       mode->samples = visual->samples;
    }
@@ -899,7 +899,7 @@ static const struct st_api st_gl_api = {
    ST_PROFILE_OPENGL_ES2_MASK |
 #endif
    0,
-   0,
+   ST_API_FEATURE_MS_VISUALS_MASK,
    st_api_destroy,
    st_api_get_proc_address,
    st_api_create_context,