#include "main/renderbuffer.h"
#include "main/context.h"
#include "main/teximage.h"
+#include "main/image.h"
+
#include "swrast/swrast.h"
#include "drivers/common/meta.h"
intel_draw_buffer(ctx);
}
+static struct intel_renderbuffer*
+intel_renderbuffer_wrap_miptree(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t layer,
+ gl_format format,
+ GLenum internal_format);
+
/**
- * NOTE: The 'att' parameter is a kludge that will soon be removed. Its
- * presence allows us to refactor the wrapping of depthstencil textures that
- * use separate stencil in two easily manageable steps, rather than in one
- * large, hairy step. First, refactor the common wrapping code used by all
- * texture formats. Second, refactor the separate stencil code paths.
+ * \par Special case for separate stencil
+ *
+ * When wrapping a depthstencil texture that uses separate stencil, this
+ * function is recursively called twice: once to create \c
+ * irb->wrapped_depth and again to create \c irb->wrapped_stencil. On the
+ * call to create \c irb->wrapped_depth, the \c format and \c
+ * internal_format parameters do not match \c mt->format. In that case, \c
+ * mt->format is MESA_FORMAT_S8_Z24 and \c format is \c
+ * MESA_FORMAT_X8_Z24.
+ *
+ * @return true on success
*/
static bool
intel_renderbuffer_update_wrapper(struct intel_context *intel,
uint32_t level,
uint32_t layer,
gl_format format,
- GLenum internal_format,
- struct gl_renderbuffer_attachment *att)
+ GLenum internal_format)
{
struct gl_renderbuffer *rb = &irb->Base;
- /* The image variables are a kludge. See the note above for the att
- * parameter.
- */
- struct gl_texture_image *texImage = _mesa_get_attachment_teximage(att);
- struct intel_texture_image *intel_image = intel_texture_image(texImage);
-
rb->Format = format;
if (!intel_span_supports_format(rb->Format)) {
DBG("Render to texture BAD FORMAT %s\n",
irb->mt_level = level;
irb->mt_layer = layer;
- if (intel_image->stencil_rb) {
- /* The tex image has packed depth/stencil format, but is using separate
- * stencil. It shares its embedded depth and stencil renderbuffers with
- * the renderbuffer wrapper.
- *
- * FIXME: glFramebufferTexture*() is broken for depthstencil textures
- * FIXME: with separate stencil. To fix this, we must create a separate
- * FIXME: pair of depth/stencil renderbuffers for each attached slice
- * FIXME: of the miptree.
- */
+ if (mt->stencil_mt && _mesa_is_depthstencil_format(rb->InternalFormat)) {
+ assert((irb->wrapped_depth == NULL) == (irb->wrapped_stencil == NULL));
+
struct intel_renderbuffer *depth_irb;
struct intel_renderbuffer *stencil_irb;
- _mesa_reference_renderbuffer(&irb->wrapped_depth,
- intel_image->depth_rb);
- _mesa_reference_renderbuffer(&irb->wrapped_stencil,
- intel_image->stencil_rb);
-
- depth_irb = intel_renderbuffer(intel_image->depth_rb);
- depth_irb->mt_level = irb->mt_level;
- depth_irb->mt_layer = irb->mt_layer;
- intel_renderbuffer_set_draw_offset(depth_irb);
-
- stencil_irb = intel_renderbuffer(intel_image->stencil_rb);
- stencil_irb->mt_level = irb->mt_level;
- stencil_irb->mt_layer = irb->mt_layer;
- intel_renderbuffer_set_draw_offset(stencil_irb);
+ if (!irb->wrapped_depth) {
+ depth_irb = intel_renderbuffer_wrap_miptree(intel,
+ mt, level, layer,
+ MESA_FORMAT_X8_Z24,
+ GL_DEPTH_COMPONENT24);
+ stencil_irb = intel_renderbuffer_wrap_miptree(intel,
+ mt->stencil_mt,
+ level, layer,
+ MESA_FORMAT_S8,
+ GL_STENCIL_INDEX8);
+ _mesa_reference_renderbuffer(&irb->wrapped_depth, &depth_irb->Base);
+ _mesa_reference_renderbuffer(&irb->wrapped_stencil, &stencil_irb->Base);
+
+ if (!irb->wrapped_depth || !irb->wrapped_stencil)
+ return false;
+ } else {
+ bool ok = true;
+
+ depth_irb = intel_renderbuffer(irb->wrapped_depth);
+ stencil_irb = intel_renderbuffer(irb->wrapped_stencil);
+
+ ok &= intel_renderbuffer_update_wrapper(intel,
+ depth_irb,
+ mt,
+ level, layer,
+ MESA_FORMAT_X8_Z24,
+ GL_DEPTH_COMPONENT24);
+ ok &= intel_renderbuffer_update_wrapper(intel,
+ stencil_irb,
+ mt->stencil_mt,
+ level, layer,
+ MESA_FORMAT_S8,
+ GL_STENCIL_INDEX8);
+ if (!ok)
+ return false;
+ }
} else {
- intel_miptree_reference(&irb->mt, intel_image->mt);
+ intel_miptree_reference(&irb->mt, mt);
intel_renderbuffer_set_draw_offset(irb);
}
* ``struct intel_renderbuffer`` then calls
* intel_renderbuffer_update_wrapper() to do the real work.
*
- * NOTE: The 'att' parameter is a kludge that will soon be removed. Its
- * presence allows us to refactor the wrapping of depthstencil textures that
- * use separate stencil in two easily manageable steps, rather than in one
- * large, hairy step. First, refactor the common wrapping code used by all
- * texture formats. Second, refactor the separate stencil code paths.
- *
* \see intel_renderbuffer_update_wrapper()
*/
static struct intel_renderbuffer*
uint32_t level,
uint32_t layer,
gl_format format,
- GLenum internal_format,
- struct gl_renderbuffer_attachment *att)
+ GLenum internal_format)
{
const GLuint name = ~0; /* not significant, but distinct for debugging */
if (!intel_renderbuffer_update_wrapper(intel, irb,
mt, level, layer,
- format, internal_format,
- att)) {
+ format, internal_format)) {
free(irb);
return NULL;
}
att->TextureLevel,
layer,
image->TexFormat,
- image->InternalFormat,
- att);
+ image->InternalFormat);
if (irb) {
/* bind the wrapper to the attachment point */
if (!intel_renderbuffer_update_wrapper(intel, irb,
mt, att->TextureLevel, layer,
image->TexFormat,
- image->InternalFormat,
- att)) {
+ image->InternalFormat)) {
_mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
_swrast_render_texture(ctx, fb, att);
return;
*
**************************************************************************/
+#include "intel_batchbuffer.h"
#include "intel_context.h"
#include "intel_mipmap_tree.h"
#include "intel_regions.h"
+#include "intel_span.h"
#include "intel_tex_layout.h"
#include "intel_tex.h"
#include "intel_blit.h"
+
#include "main/enums.h"
#include "main/formats.h"
+#include "main/image.h"
#include "main/teximage.h"
#define FILE_DEBUG_FLAG DEBUG_MIPTREE
}
}
-
static struct intel_mipmap_tree *
intel_miptree_create_internal(struct intel_context *intel,
GLenum target,
mt->depth0 = depth0;
}
+ if (format == MESA_FORMAT_S8) {
+ /* The stencil buffer has quirky pitch requirements. From Vol 2a,
+ * 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface Pitch":
+ * The pitch must be set to 2x the value computed based on width, as
+ * the stencil buffer is stored with two rows interleaved.
+ */
+ assert(intel->has_separate_stencil);
+ mt->cpp = 2;
+ }
+
#ifdef I915
(void) intel;
if (intel->is_945)
brw_miptree_layout(intel, mt);
#endif
+ if (intel->must_use_separate_stencil &&
+ _mesa_is_depthstencil_format(_mesa_get_format_base_format(format))) {
+ mt->stencil_mt = intel_miptree_create(intel,
+ mt->target,
+ MESA_FORMAT_S8,
+ mt->first_level,
+ mt->last_level,
+ mt->width0,
+ mt->height0,
+ mt->depth0,
+ true);
+ if (!mt->stencil_mt) {
+ intel_miptree_release(&mt);
+ return NULL;
+ }
+ }
+
return mt;
}
(base_format == GL_DEPTH_COMPONENT ||
base_format == GL_DEPTH_STENCIL_EXT))
tiling = I915_TILING_Y;
+ else if (format == MESA_FORMAT_S8)
+ tiling = I915_TILING_NONE;
else if (width0 >= 64)
tiling = I915_TILING_X;
}
intel_region_release(&((*mt)->region));
intel_region_release(&((*mt)->hiz_region));
+ intel_miptree_release(&(*mt)->stencil_mt);
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
free((*mt)->level[i].slice);
intel_region_unmap(intel, dst_mt->region);
intel_region_unmap(intel, src_mt->region);
}
+
+ if (src_mt->stencil_mt) {
+ intel_miptree_copy_slice(intel,
+ dst_mt->stencil_mt, src_mt->stencil_mt,
+ level, face, depth);
+ }
}
/**
intel_miptree_reference(&intelImage->mt, dst_mt);
}
+/**
+ * \param scatter Scatter if true. Gather if false.
+ *
+ * \see intel_miptree_s8z24_scatter()
+ * \see intel_miptree_s8z24_gather()
+ */
+static void
+intel_miptree_s8z24_scattergather(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t layer,
+ bool scatter)
+{
+ /* Check function inputs. */
+ assert(level >= mt->first_level);
+ assert(level <= mt->last_level);
+ assert(layer < mt->level[level].depth);
+
+ /* Label everything and its bit layout, just to make the code easier to
+ * read.
+ */
+ struct intel_mipmap_tree *s8_mt = mt->stencil_mt;
+ struct intel_mipmap_level *s8_level = &s8_mt->level[level];
+ struct intel_mipmap_slice *s8_slice = &s8_mt->level[level].slice[layer];
+
+ struct intel_mipmap_tree *s8z24_mt = mt;
+ struct intel_mipmap_level *s8z24_level = &s8z24_mt->level[level];
+ struct intel_mipmap_slice *s8z24_slice = &s8z24_mt->level[level].slice[layer];
+
+ /* Check that both miptree levels have the same dimensions. */
+ assert(s8_level->width == s8z24_level->width);
+ assert(s8_level->height == s8z24_level->height);
+ assert(s8_level->depth == s8z24_level->depth);
+
+ /* Map the buffers. */
+ if (drm_intel_bo_references(intel->batch.bo, s8_mt->region->bo) ||
+ drm_intel_bo_references(intel->batch.bo, s8z24_mt->region->bo)) {
+ intel_batchbuffer_flush(intel);
+ }
+ drm_intel_gem_bo_map_gtt(s8_mt->region->bo);
+ drm_intel_gem_bo_map_gtt(s8z24_mt->region->bo);
+
+ /* Define the invariant values outside the for loop, because I don't trust
+ * GCC to do it for us.
+ */
+ uint8_t *s8_map = s8_mt->region->bo->virtual
+ + s8_slice->x_offset
+ + s8_slice->y_offset;
+
+ uint8_t *s8z24_map = s8z24_mt->region->bo->virtual
+ + s8z24_slice->x_offset
+ + s8z24_slice->y_offset;
+
+ ptrdiff_t s8z24_stride = s8z24_mt->region->pitch * s8z24_mt->region->cpp;
+
+ uint32_t w = s8_level->width;
+ uint32_t h = s8_level->height;
+
+ for (uint32_t y = 0; y < h; ++y) {
+ for (uint32_t x = 0; x < w; ++x) {
+ ptrdiff_t s8_offset = intel_offset_S8(s8_mt->region->pitch, x, y);
+ ptrdiff_t s8z24_offset = y * s8z24_stride
+ + x * 4
+ + 3;
+ if (scatter) {
+ s8_map[s8_offset] = s8z24_map[s8z24_offset];
+ } else {
+ s8z24_map[s8z24_offset] = s8_map[s8_offset];
+ }
+ }
+ }
+
+ drm_intel_gem_bo_unmap_gtt(s8_mt->region->bo);
+ drm_intel_gem_bo_unmap_gtt(s8z24_mt->region->bo);
+}
+
+void
+intel_miptree_s8z24_scatter(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t layer)
+{
+ intel_miptree_s8z24_scattergather(intel, mt, level, layer, true);
+}
+
+void
+intel_miptree_s8z24_gather(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t layer)
+{
+ intel_miptree_s8z24_scattergather(intel, mt, level, layer, false);
+}
*/
struct intel_region *hiz_region;
+ /**
+ * \brief Stencil miptree for depthstencil textures.
+ *
+ * This miptree is used for depthstencil textures that require separate
+ * stencil. The stencil miptree's data is the golden copy of the
+ * parent miptree's stencil bits. When necessary, we scatter/gather the
+ * stencil bits between the parent miptree and the stencil miptree.
+ *
+ * \see intel_miptree_s8z24_scatter()
+ * \see intel_miptree_s8z24_gather()
+ */
+ struct intel_mipmap_tree *stencil_mt;
+
/* These are also refcounted:
*/
GLuint refcount;
struct intel_texture_image *intelImage,
struct intel_mipmap_tree *dst_mt);
+/**
+ * Copy the stencil data from \c mt->stencil_mt->region to \c mt->region for
+ * the given miptree slice.
+ *
+ * \see intel_mipmap_tree::stencil_mt
+ */
+void
+intel_miptree_s8z24_scatter(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t slice);
+
+/**
+ * Copy the stencil data in \c mt->stencil_mt->region to \c mt->region for the
+ * given miptree slice.
+ *
+ * \see intel_mipmap_tree::stencil_mt
+ */
+void
+intel_miptree_s8z24_gather(struct intel_context *intel,
+ struct intel_mipmap_tree *mt,
+ uint32_t level,
+ uint32_t layer);
+
/* i915_mipmap_tree.c:
*/
void i915_miptree_layout(struct intel_mipmap_tree *mt);
*/
ctx->Driver.FreeTextureImageBuffer(ctx, image);
- if (intel->must_use_separate_stencil
- && image->TexFormat == MESA_FORMAT_S8_Z24) {
- intel_tex_image_s8z24_create_renderbuffers(intel, intel_image);
- }
-
/* Allocate the swrast_texture_image::ImageOffsets array now */
switch (texobj->Target) {
case GL_TEXTURE_3D:
*/
intel_miptree_reference(&intel_texobj->mt, intel_image->mt);
- if (intel->must_use_separate_stencil
- && image->TexFormat == MESA_FORMAT_S8_Z24) {
- intel_tex_image_s8z24_create_renderbuffers(intel, intel_image);
- }
-
DBG("%s: alloc obj %p level %d %dx%dx%d using new miptree %p\n",
__FUNCTION__, texobj, image->Level,
width, height, depth, intel_image->mt);
free(intelImage->base.ImageOffsets);
intelImage->base.ImageOffsets = NULL;
}
-
- _mesa_reference_renderbuffer(&intelImage->depth_rb, NULL);
- _mesa_reference_renderbuffer(&intelImage->stencil_rb, NULL);
}
/**
assert(tex_image->TexObject->Target != GL_TEXTURE_1D_ARRAY ||
h == 1);
- if (intel_image->stencil_rb) {
- /*
- * The texture has packed depth/stencil format, but uses separate
- * stencil. The texture's embedded stencil buffer contains the real
- * stencil data, so copy that into the miptree.
+ if (mt->stencil_mt) {
+ /* The miptree has depthstencil format, but uses separate stencil. The
+ * embedded stencil miptree contains the real stencil data, so gather
+ * that into the depthstencil miptree.
+ *
+ * FIXME: Avoid the gather if the texture is mapped as write-only.
*/
- intel_tex_image_s8z24_gather(intel, intel_image);
+ intel_miptree_s8z24_gather(intel, mt, tex_image->Level, slice);
}
/* For compressed formats, the stride is the number of bytes per
{
struct intel_context *intel = intel_context(ctx);
struct intel_texture_image *intel_image = intel_texture_image(tex_image);
+ struct intel_mipmap_tree *mt = intel_image->mt;
intel_region_unmap(intel, intel_image->mt->region);
- if (intel_image->stencil_rb) {
- /*
- * The texture has packed depth/stencil format, but uses separate
- * stencil. The texture's embedded stencil buffer contains the real
- * stencil data, so copy that into the miptree.
+ if (mt->stencil_mt) {
+ /* The miptree has depthstencil format, but uses separate stencil. The
+ * embedded stencil miptree must contain the real stencil data after
+ * unmapping, so copy it from the depthstencil miptree into the stencil
+ * miptree.
+ *
+ * FIXME: Avoid the scatter if the texture was mapped as read-only.
*/
- intel_tex_image_s8z24_scatter(intel, intel_image);
+ intel_miptree_s8z24_scatter(intel, mt, tex_image->Level, slice);
}
}
return true;
}
-/**
- * \param scatter Scatter if true. Gather if false.
- *
- * \see intel_tex_image_x8z24_scatter
- * \see intel_tex_image_x8z24_gather
- */
-static void
-intel_tex_image_s8z24_scattergather(struct intel_context *intel,
- struct intel_texture_image *intel_image,
- bool scatter)
-{
- struct gl_context *ctx = &intel->ctx;
- struct gl_renderbuffer *depth_rb = intel_image->depth_rb;
- struct gl_renderbuffer *stencil_rb = intel_image->stencil_rb;
- int w, h, d;
-
- intel_miptree_get_dimensions_for_image(&intel_image->base.Base, &w, &h, &d);
- assert(d == 1); /* FINISHME */
-
- uint32_t depth_row[w];
- uint8_t stencil_row[w];
-
- intel_renderbuffer_map(intel, depth_rb);
- intel_renderbuffer_map(intel, stencil_rb);
-
- if (scatter) {
- for (int y = 0; y < h; ++y) {
- depth_rb->GetRow(ctx, depth_rb, w, 0, y, depth_row);
- for (int x = 0; x < w; ++x) {
- stencil_row[x] = depth_row[x] >> 24;
- }
- stencil_rb->PutRow(ctx, stencil_rb, w, 0, y, stencil_row, NULL);
- }
- } else { /* gather */
- for (int y = 0; y < h; ++y) {
- depth_rb->GetRow(ctx, depth_rb, w, 0, y, depth_row);
- stencil_rb->GetRow(ctx, stencil_rb, w, 0, y, stencil_row);
- for (int x = 0; x < w; ++x) {
- uint32_t s8_x24 = stencil_row[x] << 24;
- uint32_t x8_z24 = depth_row[x] & 0x00ffffff;
- depth_row[x] = s8_x24 | x8_z24;
- }
- depth_rb->PutRow(ctx, depth_rb, w, 0, y, depth_row, NULL);
- }
- }
-
- intel_renderbuffer_unmap(intel, depth_rb);
- intel_renderbuffer_unmap(intel, stencil_rb);
-}
-
-/**
- * Copy the x8 bits from intel_image->depth_rb to intel_image->stencil_rb.
- */
-void
-intel_tex_image_s8z24_scatter(struct intel_context *intel,
- struct intel_texture_image *intel_image)
-{
- intel_tex_image_s8z24_scattergather(intel, intel_image, true);
-}
-
-/**
- * Copy the data in intel_image->stencil_rb to the x8 bits in
- * intel_image->depth_rb.
- */
-void
-intel_tex_image_s8z24_gather(struct intel_context *intel,
- struct intel_texture_image *intel_image)
-{
- intel_tex_image_s8z24_scattergather(intel, intel_image, false);
-}
-
-bool
-intel_tex_image_s8z24_create_renderbuffers(struct intel_context *intel,
- struct intel_texture_image *image)
-{
- struct gl_context *ctx = &intel->ctx;
- bool ok = true;
- int width, height, depth;
- struct gl_renderbuffer *drb;
- struct gl_renderbuffer *srb;
- struct intel_renderbuffer *idrb;
- struct intel_renderbuffer *isrb;
-
- intel_miptree_get_dimensions_for_image(&image->base.Base,
- &width, &height, &depth);
- assert(depth == 1); /* FINISHME */
-
- assert(intel->has_separate_stencil);
- assert(image->base.Base.TexFormat == MESA_FORMAT_S8_Z24);
- assert(image->mt != NULL);
-
- drb = intel_create_wrapped_renderbuffer(ctx, width, height,
- MESA_FORMAT_X8_Z24);
- srb = intel_create_wrapped_renderbuffer(ctx, width, height,
- MESA_FORMAT_S8);
-
- if (!drb || !srb) {
- if (drb) {
- drb->Delete(drb);
- }
- if (srb) {
- srb->Delete(srb);
- }
- return false;
- }
-
- idrb = intel_renderbuffer(drb);
- isrb = intel_renderbuffer(srb);
-
- intel_miptree_reference(&idrb->mt, image->mt);
- ok = intel_alloc_renderbuffer_storage(ctx, srb, GL_STENCIL_INDEX8,
- width, height);
-
- if (!ok) {
- drb->Delete(drb);
- srb->Delete(srb);
- return false;
- }
-
- intel_renderbuffer_set_draw_offset(idrb);
- intel_renderbuffer_set_draw_offset(isrb);
-
- _mesa_reference_renderbuffer(&image->depth_rb, drb);
- _mesa_reference_renderbuffer(&image->stencil_rb, srb);
-
- return true;
-}
-
static void
intelTexImage(struct gl_context * ctx,
GLint dims,
*/
struct intel_mipmap_tree *mt;
bool used_as_render_target;
-
- /**
- * \name Renderbuffers for faking packed depth/stencil
- *
- * These renderbuffers are non-null only if the intel_context is using
- * separate stencil and this texture has a packed depth/stencil format. When
- * glFramebufferTexture is called on this image, the resultant renderbuffer
- * wrapper reuses these renderbuffers as its own.
- *
- * \see intel_wrap_texture
- * \see intel_tex_image_s8z24_create_renderbuffers
- * \see intel_tex_image_s8z24_scatter
- * \see intel_tex_image_s8z24_gather
- *
- * \{
- */
-
- /**
- * The depth buffer has format X8_Z24. The x8 bits are undefined unless
- * intel_tex_image_s8z24_gather has been immediately called. The depth
- * buffer reuses the image miptree's region and hiz_region as its own.
- */
- struct gl_renderbuffer *depth_rb;
-
- /**
- * The stencil buffer has format S8 and keeps its data in its own region.
- */
- struct gl_renderbuffer *stencil_rb;
-
- /** \} */
};
static INLINE struct intel_texture_object *