From 35840ab189595b817fa8b1a1df8cc92474a7c38d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 3 Dec 2012 05:36:08 +0100 Subject: [PATCH] st/dri: implement MSAA for GLX/DRI2 framebuffers 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 --- .../state_trackers/dri/common/dri_drawable.c | 61 +++++++++++++++++-- .../state_trackers/dri/common/dri_drawable.h | 6 ++ .../state_trackers/dri/common/dri_screen.c | 6 +- src/gallium/state_trackers/dri/drm/dri2.c | 48 +++++++++++++-- src/mesa/state_tracker/st_manager.c | 4 +- 5 files changed, 112 insertions(+), 13 deletions(-) diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.c b/src/gallium/state_trackers/dri/common/dri_drawable.c index dca6def284c..ee4d11d1495 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.c +++ b/src/gallium/state_trackers/dri/common/dri_drawable.c @@ -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; diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.h b/src/gallium/state_trackers/dri/common/dri_drawable.h index 6a769910fe6..caa1faa08f4 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.h +++ b/src/gallium/state_trackers/dri/common/dri_drawable.h @@ -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, diff --git a/src/gallium/state_trackers/dri/common/dri_screen.c b/src/gallium/state_trackers/dri/common/dri_screen.c index df2cd3f6b37..6d220f2ed7b 100644 --- a/src/gallium/state_trackers/dri/common/dri_screen.c +++ b/src/gallium/state_trackers/dri/common/dri_screen.c @@ -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) diff --git a/src/gallium/state_trackers/dri/drm/dri2.c b/src/gallium/state_trackers/dri/drm/dri2.c index 5ebe18480d8..7f4f2f00c77 100644 --- a/src/gallium/state_trackers/dri/drm/dri2.c +++ b/src/gallium/state_trackers/dri/drm/dri2.c @@ -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); } } diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c index da581861479..b065db0acdf 100644 --- a/src/mesa/state_tracker/st_manager.c +++ b/src/mesa/state_tracker/st_manager.c @@ -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, -- 2.30.2