diff options
author | Marek Olšák <maraeo@gmail.com> | 2012-12-03 05:36:08 +0100 |
---|---|---|
committer | Marek Olšák <maraeo@gmail.com> | 2012-12-07 14:19:29 +0100 |
commit | 35840ab189595b817fa8b1a1df8cc92474a7c38d (patch) | |
tree | 8c24773dedcfc0663c1388ed77ba30dc34212ed6 | |
parent | 919f788b92362676fa368d9950532f82f762cdfb (diff) |
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 <brianp@vmware.com>
-rw-r--r-- | src/gallium/state_trackers/dri/common/dri_drawable.c | 61 | ||||
-rw-r--r-- | src/gallium/state_trackers/dri/common/dri_drawable.h | 6 | ||||
-rw-r--r-- | src/gallium/state_trackers/dri/common/dri_screen.c | 6 | ||||
-rw-r--r-- | src/gallium/state_trackers/dri/drm/dri2.c | 48 | ||||
-rw-r--r-- | 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 @@ -51,12 +51,15 @@ dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, (struct dri_drawable *) stfbi->st_manager_private; struct dri_screen *screen = dri_screen(drawable->sPriv); unsigned statt_mask, new_mask; 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++) statt_mask |= (1 << statts[i]); /* record newly allocated textures */ @@ -76,27 +79,28 @@ dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, drawable->update_drawable_info(drawable); drawable->allocate_textures(drawable, statts, count); /* add existing textures */ for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { - if (drawable->textures[i]) + if (textures[i]) statt_mask |= (1 << i); } drawable->texture_stamp = lastStamp; drawable->texture_mask = statt_mask; } } while (lastStamp != drawable->dPriv->lastStamp); 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; } static boolean @@ -163,12 +167,14 @@ dri_destroy_buffer(__DRIdrawable * dPriv) int i; pipe_surface_reference(&drawable->drisw_surface, NULL); 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); FREE(drawable); } @@ -349,12 +355,54 @@ swap_fences_unref(struct dri_drawable *draw) screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); draw->tail &= DRI_SWAP_FENCES_MASK; --draw->cur_fences; } } +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. * * \param context the context * \param drawable the drawable to flush * \param flags a combination of _DRI2_FLUSH_xxx flags @@ -378,16 +426,19 @@ dri_flush(__DRIcontext *cPriv, if (!drawable) { flags &= ~__DRI2_FLUSH_DRAWABLE; } /* 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; if (flags & __DRI2_FLUSH_CONTEXT) flush_flags |= ST_FLUSH_FRONT; 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 @@ -54,12 +54,13 @@ struct dri_drawable __DRIbuffer old[8]; unsigned old_num; unsigned old_w; 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]; unsigned int cur_fences; unsigned int head; unsigned int tail; @@ -105,12 +106,17 @@ void dri_drawable_get_format(struct dri_drawable *drawable, enum st_attachment_type statt, 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, unsigned flags, enum __DRI2throttleReason reason); extern const __DRItexBufferExtension driTexBufferExtension; 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 @@ -101,13 +101,13 @@ dri_fill_in_modes(struct dri_screen *screen) }; depth_bits_array[0] = 0; 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, PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL); pf_z24x8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_X8Z24_UNORM, @@ -203,13 +203,15 @@ dri_fill_st_visual(struct st_visual *stvis, struct dri_screen *screen, { memset(stvis, 0, sizeof(*stvis)); if (!mode) return; - stvis->samples = mode->samples; + if (mode->sampleBuffers) { + stvis->samples = mode->samples; + } if (mode->redBits == 8) { if (mode->alphaBits == 8) stvis->color_format = PIPE_FORMAT_B8G8R8A8_UNORM; else stvis->color_format = PIPE_FORMAT_B8G8R8X8_UNORM; 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 @@ -187,12 +187,14 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable, drawable->old_h == dri_drawable->h && memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * buffer_count) == 0) return; 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; templ.last_level = 0; templ.width0 = dri_drawable->w; templ.height0 = dri_drawable->h; @@ -232,12 +234,31 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable, whandle.handle = buf->name; whandle.stride = buf->pitch; 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. */ for (i = 0; i < att_count; i++) { if (atts[i] == ST_ATTACHMENT_DEPTH_STENCIL) { alloc_depthstencil = TRUE; @@ -253,14 +274,26 @@ dri2_drawable_process_buffers(struct dri_drawable *drawable, dri_drawable_get_format(drawable, ST_ATTACHMENT_DEPTH_STENCIL, &format, &bind); if (format) { 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]); + } } } drawable->old_num = buffer_count; drawable->old_w = dri_drawable->w; drawable->old_h = dri_drawable->h; @@ -377,16 +410,23 @@ dri2_flush_frontbuffer(struct dri_context *ctx, struct dri_drawable *drawable, enum st_attachment_type statt) { __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); } } static void dri2_update_tex_buffer(struct dri_drawable *drawable, 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 @@ -395,13 +395,13 @@ st_visual_to_context_mode(const struct st_visual *visual, UTIL_FORMAT_COLORSPACE_RGB, 2); mode->accumAlphaBits = util_format_get_component_bits(visual->accum_format, UTIL_FORMAT_COLORSPACE_RGB, 3); } - if (visual->samples) { + if (visual->samples > 1) { mode->sampleBuffers = 1; mode->samples = visual->samples; } } /** @@ -896,13 +896,13 @@ static const struct st_api st_gl_api = { ST_PROFILE_OPENGL_ES1_MASK | #endif #if FEATURE_ES2 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, st_api_make_current, st_api_get_current, }; |