diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c index 3b67f87c21a..759fead2d42 100644 --- a/src/mesa/drivers/dri/intel/intel_context.c +++ b/src/mesa/drivers/dri/intel/intel_context.c @@ -926,14 +926,24 @@ intel_process_dri2_buffer(struct intel_context *intel, if (!rb) return; + unsigned num_samples = rb->Base.Base.NumSamples; + /* We try to avoid closing and reopening the same BO name, because the first * use of a mapping of the buffer involves a bunch of page faulting which is * moderately expensive. */ - if (rb->mt && - rb->mt->region && - rb->mt->region->name == buffer->name) - return; + if (num_samples == 0) { + if (rb->mt && + rb->mt->region && + rb->mt->region->name == buffer->name) + return; + } else { + if (rb->mt && + rb->mt->singlesample_mt && + rb->mt->singlesample_mt->region && + rb->mt->singlesample_mt->region->name == buffer->name) + return; + } if (unlikely(INTEL_DEBUG & DEBUG_DRI)) { fprintf(stderr, @@ -953,9 +963,10 @@ intel_process_dri2_buffer(struct intel_context *intel, if (!region) return; - rb->mt = intel_miptree_create_for_region(intel, - GL_TEXTURE_2D, - intel_rb_format(rb), - region); + rb->mt = intel_miptree_create_for_dri2_buffer(intel, + buffer->attachment, + intel_rb_format(rb), + num_samples, + region); intel_region_release(®ion); } diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c index b6ecbca9162..5da24f2c9c6 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c @@ -25,6 +25,9 @@ * **************************************************************************/ +#include +#include + #include "intel_batchbuffer.h" #include "intel_context.h" #include "intel_mipmap_tree.h" @@ -324,6 +327,62 @@ compute_msaa_layout(struct intel_context *intel, gl_format format) } } +/** + * For a singlesample DRI2 buffer, this simply wraps the given region with a miptree. + * + * For a multisample DRI2 buffer, this wraps the given region with + * a singlesample miptree, then creates a multisample miptree into which the + * singlesample miptree is embedded as a child. + */ +struct intel_mipmap_tree* +intel_miptree_create_for_dri2_buffer(struct intel_context *intel, + unsigned dri_attachment, + gl_format format, + uint32_t num_samples, + struct intel_region *region) +{ + struct intel_mipmap_tree *singlesample_mt = NULL; + struct intel_mipmap_tree *multisample_mt = NULL; + GLenum base_format = _mesa_get_format_base_format(format); + + /* Only the front and back buffers, which are color buffers, are shared + * through DRI2. + */ + assert(dri_attachment == __DRI_BUFFER_BACK_LEFT || + dri_attachment == __DRI_BUFFER_FRONT_LEFT || + dri_attachment == __DRI_BUFFER_FAKE_FRONT_LEFT); + assert(base_format == GL_RGB || base_format == GL_RGBA); + + singlesample_mt = intel_miptree_create_for_region(intel, GL_TEXTURE_2D, + format, region); + if (!singlesample_mt) + return NULL; + + if (num_samples == 0) + return singlesample_mt; + + multisample_mt = intel_miptree_create_for_renderbuffer(intel, + format, + region->width, + region->height, + num_samples); + if (!multisample_mt) { + intel_miptree_release(&singlesample_mt); + return NULL; + } + + multisample_mt->singlesample_mt = singlesample_mt; + multisample_mt->need_downsample = false; + + if (intel->is_front_buffer_rendering && + (dri_attachment == __DRI_BUFFER_FRONT_LEFT || + dri_attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)) { + intel_miptree_upsample(intel, multisample_mt); + } + + return multisample_mt; +} + struct intel_mipmap_tree* intel_miptree_create_for_renderbuffer(struct intel_context *intel, gl_format format, @@ -454,6 +513,7 @@ intel_miptree_release(struct intel_mipmap_tree **mt) intel_miptree_release(&(*mt)->stencil_mt); intel_miptree_release(&(*mt)->hiz_mt); intel_miptree_release(&(*mt)->mcs_mt); + intel_miptree_release(&(*mt)->singlesample_mt); intel_resolve_map_clear(&(*mt)->hiz_map); for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { @@ -899,6 +959,30 @@ intel_miptree_all_slices_resolve_depth(struct intel_context *intel, GEN6_HIZ_OP_DEPTH_RESOLVE); } +/** + * \brief Downsample from mt to mt->singlesample_mt. + * + * If the miptree needs no downsample, then skip. + */ +void +intel_miptree_downsample(struct intel_context *intel, + struct intel_mipmap_tree *mt) +{ + /* TODO: stub */ +} + +/** + * \brief Upsample from mt->singlesample_mt to mt. + * + * The upsample is done unconditionally. + */ +void +intel_miptree_upsample(struct intel_context *intel, + struct intel_mipmap_tree *mt) +{ + /* TODO: stub */ +} + static void intel_miptree_map_gtt(struct intel_context *intel, struct intel_mipmap_tree *mt, diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h index bfeb69c36f8..12c7b6afcb7 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h @@ -247,6 +247,50 @@ struct intel_mipmap_tree */ uint32_t offset; + /** + * \brief Singlesample miptree. + * + * This is used under two cases. + * + * --- Case 1: As persistent singlesample storage for multisample window + * system front and back buffers --- + * + * Suppose that the window system FBO was created with a multisample + * config. Let `back_irb` be the `intel_renderbuffer` for the FBO's back + * buffer. Then `back_irb` contains two miptrees: a parent multisample + * miptree (back_irb->mt) and a child singlesample miptree + * (back_irb->mt->singlesample_mt). The DRM buffer shared with DRI2 + * belongs to `back_irb->mt->singlesample_mt` and contains singlesample + * data. The singlesample miptree is created at the same time as and + * persists for the lifetime of its parent multisample miptree. + * + * When access to the singlesample data is needed, such as at + * eglSwapBuffers and glReadPixels, an automatic downsample occurs from + * `back_rb->mt` to `back_rb->mt->singlesample_mt` when necessary. + * + * This description of the back buffer applies analogously to the front + * buffer. + * + * + * --- Case 2: As temporary singlesample storage for mapping multisample + * miptrees --- + * + * Suppose the intel_miptree_map is called on a multisample miptree, `mt`, + * for which case 1 does not apply (that is, `mt` does not belong to + * a front or back buffer). Then `mt->singlesample_mt` is null at the + * start of the call. intel_miptree_map will create a temporary + * singlesample miptree, store it at `mt->singlesample_mt`, downsample from + * `mt` to `mt->singlesample_mt` if necessary, then map + * `mt->singlesample_mt`. The temporary miptree is later deleted during + * intel_miptree_unmap. + */ + struct intel_mipmap_tree *singlesample_mt; + + /** + * \brief A downsample is needed from this miptree to singlesample_mt. + */ + bool need_downsample; + /** * \brief HiZ miptree * @@ -325,6 +369,13 @@ intel_miptree_create_for_region(struct intel_context *intel, gl_format format, struct intel_region *region); +struct intel_mipmap_tree* +intel_miptree_create_for_dri2_buffer(struct intel_context *intel, + unsigned dri_attachment, + gl_format format, + uint32_t num_samples, + struct intel_region *region); + /** * Create a miptree appropriate as the storage for a non-texture renderbuffer. * The miptree has the following properties: @@ -484,6 +535,14 @@ intel_miptree_all_slices_resolve_depth(struct intel_context *intel, /**\}*/ +void +intel_miptree_downsample(struct intel_context *intel, + struct intel_mipmap_tree *mt); + +void +intel_miptree_upsample(struct intel_context *intel, + struct intel_mipmap_tree *mt); + /* i915_mipmap_tree.c: */ void i915_miptree_layout(struct intel_mipmap_tree *mt);