X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fintel%2Fintel_fbo.c;h=481080944dd786dc3a94ac51dde8d8d8e606cd55;hb=8fd62e80ae1985b1dc466ecddbbed1e48edb08f9;hp=1bd16f06a38df3dbb912f5a54f65e291487cbe08;hpb=190aec75a4362b56b9b311975a777c56e8e6c67d;p=mesa.git diff --git a/src/mesa/drivers/dri/intel/intel_fbo.c b/src/mesa/drivers/dri/intel/intel_fbo.c index 1bd16f06a38..481080944dd 100644 --- a/src/mesa/drivers/dri/intel/intel_fbo.c +++ b/src/mesa/drivers/dri/intel/intel_fbo.c @@ -36,6 +36,8 @@ #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" @@ -54,6 +56,21 @@ #define FILE_DEBUG_FLAG DEBUG_FBO +static struct gl_renderbuffer * +intel_new_renderbuffer(struct gl_context * ctx, GLuint name); + +struct intel_region* +intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex) +{ + struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex); + if (irb && irb->mt) { + if (attIndex == BUFFER_STENCIL && irb->mt->stencil_mt) + return irb->mt->stencil_mt->region; + else + return irb->mt->region; + } else + return NULL; +} /** * Create a new framebuffer object. @@ -70,299 +87,15 @@ intel_new_framebuffer(struct gl_context * ctx, GLuint name) /** Called by gl_renderbuffer::Delete() */ static void -intel_delete_renderbuffer(struct gl_renderbuffer *rb) +intel_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { struct intel_renderbuffer *irb = intel_renderbuffer(rb); ASSERT(irb); - intel_region_release(&irb->region); - intel_region_release(&irb->hiz_region); - - _mesa_reference_renderbuffer(&irb->wrapped_depth, NULL); - _mesa_reference_renderbuffer(&irb->wrapped_stencil, NULL); - - free(irb); -} - -/** - * \brief Map a renderbuffer through the GTT. - * - * \see intel_map_renderbuffer() - */ -static void -intel_map_renderbuffer_gtt(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint x, GLuint y, GLuint w, GLuint h, - GLbitfield mode, - GLubyte **out_map, - GLint *out_stride) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - GLubyte *map; - int stride, flip_stride; - - assert(irb->region); - - irb->map_mode = mode; - irb->map_x = x; - irb->map_y = y; - irb->map_w = w; - irb->map_h = h; - - stride = irb->region->pitch * irb->region->cpp; - - if (rb->Name == 0) { - y = irb->region->height - 1 - y; - flip_stride = -stride; - } else { - x += irb->draw_x; - y += irb->draw_y; - flip_stride = stride; - } - - if (drm_intel_bo_references(intel->batch.bo, irb->region->bo)) { - intel_batchbuffer_flush(intel); - } - - drm_intel_gem_bo_map_gtt(irb->region->bo); - - map = irb->region->bo->virtual; - map += x * irb->region->cpp; - map += (int)y * stride; - - *out_map = map; - *out_stride = flip_stride; - - DBG("%s: rb %d (%s) gtt mapped: (%d, %d) (%dx%d) -> %p/%d\n", - __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format), - x, y, w, h, *out_map, *out_stride); -} - -/** - * \brief Map a renderbuffer by blitting it to a temporary gem buffer. - * - * On gen6+, we have LLC sharing, which means we can get high-performance - * access to linear-mapped buffers. - * - * This function allocates a temporary gem buffer at - * intel_renderbuffer::map_bo, then blits the renderbuffer into it, and - * returns a map of that. (Note: Only X tiled buffers can be blitted). - * - * \see intel_renderbuffer::map_bo - * \see intel_map_renderbuffer() - */ -static void -intel_map_renderbuffer_blit(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint x, GLuint y, GLuint w, GLuint h, - GLbitfield mode, - GLubyte **out_map, - GLint *out_stride) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - - int src_x, src_y; - int dst_stride; - - assert(irb->region); - assert(intel->gen >= 6); - assert(!(mode & GL_MAP_WRITE_BIT)); - assert(irb->region->tiling == I915_TILING_X); - - irb->map_mode = mode; - irb->map_x = x; - irb->map_y = y; - irb->map_w = w; - irb->map_h = h; - - dst_stride = ALIGN(w * irb->region->cpp, 4); - - if (rb->Name) { - src_x = x + irb->draw_x; - src_y = y + irb->draw_y; - } else { - src_x = x; - src_y = irb->region->height - y - h; - } - - irb->map_bo = drm_intel_bo_alloc(intel->bufmgr, "MapRenderbuffer() temp", - dst_stride * h, 4096); - - /* We don't do the flip in the blit, because it's always so tricky to get - * right. - */ - if (irb->map_bo && - intelEmitCopyBlit(intel, - irb->region->cpp, - irb->region->pitch, irb->region->bo, - 0, irb->region->tiling, - dst_stride / irb->region->cpp, irb->map_bo, - 0, I915_TILING_NONE, - src_x, src_y, - 0, 0, - w, h, - GL_COPY)) { - intel_batchbuffer_flush(intel); - drm_intel_bo_map(irb->map_bo, false); - - if (rb->Name) { - *out_map = irb->map_bo->virtual; - *out_stride = dst_stride; - } else { - *out_map = irb->map_bo->virtual + (h - 1) * dst_stride; - *out_stride = -dst_stride; - } - - DBG("%s: rb %d (%s) blit mapped: (%d, %d) (%dx%d) -> %p/%d\n", - __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format), - src_x, src_y, w, h, *out_map, *out_stride); - } else { - /* Fallback to GTT mapping. */ - drm_intel_bo_unreference(irb->map_bo); - irb->map_bo = NULL; - intel_map_renderbuffer_gtt(ctx, rb, - x, y, w, h, - mode, - out_map, out_stride); - } -} - -/** - * \brief Map a stencil renderbuffer. - * - * Stencil buffers are W-tiled. Since the GTT has no W fence, we must detile - * the buffer in software. - * - * This function allocates a temporary malloc'd buffer at - * intel_renderbuffer::map_buffer, detiles the stencil buffer into it, then - * returns the temporary buffer as the map. - * - * \see intel_renderbuffer::map_buffer - * \see intel_map_renderbuffer() - * \see intel_unmap_renderbuffer_s8() - */ -static void -intel_map_renderbuffer_s8(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint x, GLuint y, GLuint w, GLuint h, - GLbitfield mode, - GLubyte **out_map, - GLint *out_stride) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - uint8_t *tiled_s8_map; - uint8_t *untiled_s8_map; - - assert(rb->Format == MESA_FORMAT_S8); - assert(irb->region); - - irb->map_mode = mode; - irb->map_x = x; - irb->map_y = y; - irb->map_w = w; - irb->map_h = h; - - /* Flip the Y axis for the default framebuffer. */ - int y_flip = (rb->Name == 0) ? -1 : 1; - int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0; - - irb->map_buffer = malloc(w * h); - untiled_s8_map = irb->map_buffer; - tiled_s8_map = intel_region_map(intel, irb->region, mode); - - for (uint32_t pix_y = 0; pix_y < h; pix_y++) { - for (uint32_t pix_x = 0; pix_x < w; pix_x++) { - uint32_t flipped_y = y_flip * (int32_t)(y + pix_y) + y_bias; - ptrdiff_t offset = intel_offset_S8(irb->region->pitch, - x + pix_x, - flipped_y); - untiled_s8_map[pix_y * w + pix_x] = tiled_s8_map[offset]; - } - } - - *out_map = untiled_s8_map; - *out_stride = w; - - DBG("%s: rb %d (%s) s8 detiled mapped: (%d, %d) (%dx%d) -> %p/%d\n", - __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format), - x, y, w, h, *out_map, *out_stride); -} - -/** - * \brief Map a depthstencil buffer with separate stencil. - * - * A depthstencil renderbuffer, if using separate stencil, consists of a depth - * renderbuffer and a hidden stencil renderbuffer. This function maps the - * depth buffer, whose format is MESA_FORMAT_X8_Z24, through the GTT and - * returns that as the mapped pointer. The caller need not be aware of the - * hidden stencil buffer and may safely assume that the mapped pointer points - * to a MESA_FORMAT_S8_Z24 buffer - * - * The consistency between the depth buffer's S8 bits and the hidden stencil - * buffer is managed within intel_map_renderbuffer() and - * intel_unmap_renderbuffer() by scattering or gathering the stencil bits - * according to the map mode. - * - * \see intel_map_renderbuffer() - * \see intel_unmap_renderbuffer_separate_s8z24() - */ -static void -intel_map_renderbuffer_separate_s8z24(struct gl_context *ctx, - struct gl_renderbuffer *rb, - GLuint x, GLuint y, GLuint w, GLuint h, - GLbitfield mode, - GLubyte **out_map, - GLint *out_stride) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - - uint8_t *s8z24_map; - int32_t s8z24_stride; - - struct intel_renderbuffer *s8_irb; - uint8_t *s8_map; - - assert(rb->Name != 0); - assert(rb->Format == MESA_FORMAT_S8_Z24); - assert(irb->wrapped_depth != NULL); - assert(irb->wrapped_stencil != NULL); - - irb->map_mode = mode; - irb->map_x = x; - irb->map_y = y; - irb->map_w = w; - irb->map_h = h; - - /* Map with write mode for the gather below. */ - intel_map_renderbuffer_gtt(ctx, irb->wrapped_depth, - x, y, w, h, mode | GL_MAP_WRITE_BIT, - &s8z24_map, &s8z24_stride); - - s8_irb = intel_renderbuffer(irb->wrapped_stencil); - s8_map = intel_region_map(intel, s8_irb->region, GL_MAP_READ_BIT); - - /* Gather the stencil buffer into the depth buffer. */ - for (uint32_t pix_y = 0; pix_y < h; ++pix_y) { - for (uint32_t pix_x = 0; pix_x < w; ++pix_x) { - ptrdiff_t s8_offset = intel_offset_S8(s8_irb->region->pitch, - x + pix_x, - y + pix_y); - ptrdiff_t s8z24_offset = pix_y * s8z24_stride - + pix_x * 4 - + 3; - s8z24_map[s8z24_offset] = s8_map[s8_offset]; - } - } - - intel_region_unmap(intel, s8_irb->region); + intel_miptree_release(&irb->mt); - *out_map = s8z24_map; - *out_stride = s8z24_stride; + _mesa_delete_renderbuffer(ctx, rb); } /** @@ -377,134 +110,49 @@ intel_map_renderbuffer(struct gl_context *ctx, GLint *out_stride) { struct intel_context *intel = intel_context(ctx); + struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb; struct intel_renderbuffer *irb = intel_renderbuffer(rb); + void *map; + int stride; + + if (srb->Buffer) { + /* this is a malloc'd renderbuffer (accum buffer), not an irb */ + GLint bpp = _mesa_get_format_bytes(rb->Format); + GLint rowStride = srb->RowStride; + *out_map = (GLubyte *) srb->Buffer + y * rowStride + x * bpp; + *out_stride = rowStride; + return; + } /* We sometimes get called with this by our intel_span.c usage. */ - if (!irb->region && !irb->wrapped_depth) { + if (!irb->mt) { *out_map = NULL; *out_stride = 0; return; } - if (rb->Format == MESA_FORMAT_S8) { - intel_map_renderbuffer_s8(ctx, rb, x, y, w, h, mode, - out_map, out_stride); - } else if (irb->wrapped_depth) { - intel_map_renderbuffer_separate_s8z24(ctx, rb, x, y, w, h, mode, - out_map, out_stride); - } else if (intel->gen >= 6 && - !(mode & GL_MAP_WRITE_BIT) && - irb->region->tiling == I915_TILING_X) { - intel_map_renderbuffer_blit(ctx, rb, x, y, w, h, mode, - out_map, out_stride); - } else { - intel_map_renderbuffer_gtt(ctx, rb, x, y, w, h, mode, - out_map, out_stride); + /* For a window-system renderbuffer, we need to flip the mapping we receive + * upside-down. So we need to ask for a rectangle on flipped vertically, and + * we then return a pointer to the bottom of it with a negative stride. + */ + if (rb->Name == 0) { + y = rb->Height - y - h; } -} -/** - * \see intel_map_renderbuffer_s8() - */ -static void -intel_unmap_renderbuffer_s8(struct gl_context *ctx, - struct gl_renderbuffer *rb) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); + intel_miptree_map(intel, irb->mt, irb->mt_level, irb->mt_layer, + x, y, w, h, mode, &map, &stride); - DBG("%s: rb %d (%s)\n", __FUNCTION__, - rb->Name, _mesa_get_format_name(rb->Format)); - - assert(rb->Format == MESA_FORMAT_S8); - - if (!irb->map_buffer) - return; - - if (irb->map_mode & GL_MAP_WRITE_BIT) { - /* The temporary buffer was written to, so we must copy its pixels into - * the real buffer. - */ - uint8_t *untiled_s8_map = irb->map_buffer; - uint8_t *tiled_s8_map = irb->region->bo->virtual; - - /* Flip the Y axis for the default framebuffer. */ - int y_flip = (rb->Name == 0) ? -1 : 1; - int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0; - - for (uint32_t pix_y = 0; pix_y < irb->map_h; pix_y++) { - for (uint32_t pix_x = 0; pix_x < irb->map_w; pix_x++) { - uint32_t flipped_y = y_flip * (int32_t)(pix_y + irb->map_y) + y_bias; - ptrdiff_t offset = intel_offset_S8(irb->region->pitch, - pix_x + irb->map_x, - flipped_y); - tiled_s8_map[offset] = - untiled_s8_map[pix_y * irb->map_w + pix_x]; - } - } + if (rb->Name == 0) { + map += (h - 1) * stride; + stride = -stride; } - intel_region_unmap(intel, irb->region); - free(irb->map_buffer); - irb->map_buffer = NULL; -} - -/** - * \brief Unmap a depthstencil renderbuffer with separate stencil. - * - * \see intel_map_renderbuffer_separate_s8z24() - * \see intel_unmap_renderbuffer() - */ -static void -intel_unmap_renderbuffer_separate_s8z24(struct gl_context *ctx, - struct gl_renderbuffer *rb) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_renderbuffer *irb = intel_renderbuffer(rb); - struct intel_renderbuffer *s8z24_irb; - - assert(rb->Name != 0); - assert(rb->Format == MESA_FORMAT_S8_Z24); - assert(irb->wrapped_depth != NULL); - assert(irb->wrapped_stencil != NULL); - - s8z24_irb = intel_renderbuffer(irb->wrapped_depth); - - if (irb->map_mode & GL_MAP_WRITE_BIT) { - /* Copy the stencil bits from the depth buffer into the stencil buffer. - */ - uint32_t map_x = irb->map_x; - uint32_t map_y = irb->map_y; - uint32_t map_w = irb->map_w; - uint32_t map_h = irb->map_h; - - struct intel_renderbuffer *s8_irb; - uint8_t *s8_map; - - s8_irb = intel_renderbuffer(irb->wrapped_stencil); - s8_map = intel_region_map(intel, s8_irb->region, GL_MAP_WRITE_BIT); - - int32_t s8z24_stride = 4 * s8z24_irb->region->pitch; - uint8_t *s8z24_map = s8z24_irb->region->bo->virtual - + map_y * s8z24_stride - + map_x * 4; - - for (uint32_t pix_y = 0; pix_y < map_h; ++pix_y) { - for (uint32_t pix_x = 0; pix_x < map_w; ++pix_x) { - ptrdiff_t s8_offset = intel_offset_S8(s8_irb->region->pitch, - map_x + pix_x, - map_y + pix_y); - ptrdiff_t s8z24_offset = pix_y * s8z24_stride - + pix_x * 4 - + 3; - s8_map[s8_offset] = s8z24_map[s8z24_offset]; - } - } - - intel_region_unmap(intel, s8_irb->region); - } + DBG("%s: rb %d (%s) mt mapped: (%d, %d) (%dx%d) -> %p/%d\n", + __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format), + x, y, w, h, map, stride); - drm_intel_gem_bo_unmap_gtt(s8z24_irb->region->bo); + *out_map = map; + *out_stride = stride; } /** @@ -514,42 +162,57 @@ static void intel_unmap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { + struct intel_context *intel = intel_context(ctx); + struct swrast_renderbuffer *srb = (struct swrast_renderbuffer *)rb; struct intel_renderbuffer *irb = intel_renderbuffer(rb); DBG("%s: rb %d (%s)\n", __FUNCTION__, rb->Name, _mesa_get_format_name(rb->Format)); - if (rb->Format == MESA_FORMAT_S8) { - intel_unmap_renderbuffer_s8(ctx, rb); - } else if (irb->wrapped_depth) { - intel_unmap_renderbuffer_separate_s8z24(ctx, rb); - } else if (irb->map_bo) { - /* Paired with intel_map_renderbuffer_blit(). */ - drm_intel_bo_unmap(irb->map_bo); - drm_intel_bo_unreference(irb->map_bo); - irb->map_bo = 0; - } else { - /* Paired with intel_map_renderbuffer_gtt(). */ - if (irb->region) { - /* The region may be null when intel_map_renderbuffer() is - * called from intel_span.c. - */ - drm_intel_gem_bo_unmap_gtt(irb->region->bo); - } + if (srb->Buffer) { + /* this is a malloc'd renderbuffer (accum buffer) */ + /* nothing to do */ + return; } + + intel_miptree_unmap(intel, irb->mt, irb->mt_level, irb->mt_layer); } + /** - * Return a pointer to a specific pixel in a renderbuffer. + * Round up the requested multisample count to the next supported sample size. */ -static void * -intel_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb, - GLint x, GLint y) -{ - /* By returning NULL we force all software rendering to go through - * the span routines. - */ - return NULL; +unsigned +intel_quantize_num_samples(struct intel_screen *intel, unsigned num_samples) +{ + switch (intel->gen) { + case 6: + /* Gen6 supports only 4x multisampling. */ + if (num_samples > 0) + return 4; + else + return 0; + case 7: + /* Gen7 supports 4x and 8x multisampling. */ + if (num_samples > 4) + return 8; + else if (num_samples > 0) + return 4; + else + return 0; + return 0; + default: + /* MSAA unsupported. However, a careful reading of + * EXT_framebuffer_multisample reveals that we need to permit + * num_samples to be 1 (since num_samples is permitted to be as high as + * GL_MAX_SAMPLES, and GL_MAX_SAMPLES must be at least 1). Since + * platforms before Gen6 don't support MSAA, this is safe, because + * multisampling won't happen anyhow. + */ + if (num_samples > 0) + return 1; + return 0; + } } @@ -557,16 +220,15 @@ intel_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb, * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ -GLboolean +static GLboolean intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); + struct intel_screen *screen = intel->intelScreen; struct intel_renderbuffer *irb = intel_renderbuffer(rb); - int cpp, tiling; - - ASSERT(rb->Name != 0); + rb->NumSamples = intel_quantize_num_samples(screen, rb->NumSamples); switch (internalFormat) { default: @@ -575,7 +237,8 @@ intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer * except they're less useful because you can't texture with * them. */ - rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, internalFormat, + rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D, + internalFormat, GL_NONE, GL_NONE); break; case GL_STENCIL_INDEX: @@ -596,117 +259,26 @@ intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); - rb->DataType = intel_mesa_format_to_rb_datatype(rb->Format); - cpp = _mesa_get_format_bytes(rb->Format); - intel_flush(ctx); - - /* free old region */ - if (irb->region) { - intel_region_release(&irb->region); - } - if (irb->hiz_region) { - intel_region_release(&irb->hiz_region); - } + intel_miptree_release(&irb->mt); DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat), _mesa_get_format_name(rb->Format), width, height); - tiling = I915_TILING_NONE; - if (intel->use_texture_tiling) { - GLenum base_format = _mesa_get_format_base_format(rb->Format); - - if (intel->gen >= 4 && (base_format == GL_DEPTH_COMPONENT || - base_format == GL_STENCIL_INDEX || - base_format == GL_DEPTH_STENCIL)) - tiling = I915_TILING_Y; - else - tiling = I915_TILING_X; - } - - if (irb->Base.Format == MESA_FORMAT_S8) { - /* - * The stencil buffer is W tiled. However, we request from the kernel a - * non-tiled buffer because the GTT is incapable of W fencing. - * - * 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. - * To accomplish this, we resort to the nasty hack of doubling the drm - * region's cpp and halving its height. - * - * If we neglect to double the pitch, then render corruption occurs. - */ - irb->region = intel_region_alloc(intel->intelScreen, - I915_TILING_NONE, - cpp * 2, - ALIGN(width, 64), - ALIGN((height + 1) / 2, 64), - true); - if (!irb->region) - return false; - - } else if (irb->Base.Format == MESA_FORMAT_S8_Z24 - && intel->must_use_separate_stencil) { - - bool ok = true; - struct gl_renderbuffer *depth_rb; - struct gl_renderbuffer *stencil_rb; - - depth_rb = intel_create_wrapped_renderbuffer(ctx, width, height, - MESA_FORMAT_X8_Z24); - stencil_rb = intel_create_wrapped_renderbuffer(ctx, width, height, - MESA_FORMAT_S8); - ok = depth_rb && stencil_rb; - ok = ok && intel_alloc_renderbuffer_storage(ctx, depth_rb, - depth_rb->InternalFormat, - width, height); - ok = ok && intel_alloc_renderbuffer_storage(ctx, stencil_rb, - stencil_rb->InternalFormat, - width, height); - - if (!ok) { - if (depth_rb) { - intel_delete_renderbuffer(depth_rb); - } - if (stencil_rb) { - intel_delete_renderbuffer(stencil_rb); - } - return false; - } - - depth_rb->Wrapped = rb; - stencil_rb->Wrapped = rb; - _mesa_reference_renderbuffer(&irb->wrapped_depth, depth_rb); - _mesa_reference_renderbuffer(&irb->wrapped_stencil, stencil_rb); - - } else { - irb->region = intel_region_alloc(intel->intelScreen, tiling, cpp, - width, height, true); - if (!irb->region) - return false; + if (width == 0 || height == 0) + return true; - if (intel->vtbl.is_hiz_depth_format(intel, rb->Format)) { - irb->hiz_region = intel_region_alloc(intel->intelScreen, - I915_TILING_Y, - irb->region->cpp, - irb->region->width, - irb->region->height, - true); - if (!irb->hiz_region) { - intel_region_release(&irb->region); - return false; - } - } - } + irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format, + width, height, + rb->NumSamples); + if (!irb->mt) + return false; return true; } -#if FEATURE_OES_EGL_image static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, @@ -735,17 +307,21 @@ intel_image_target_renderbuffer_storage(struct gl_context *ctx, } irb = intel_renderbuffer(rb); - intel_region_reference(&irb->region, image->region); + intel_miptree_release(&irb->mt); + irb->mt = intel_miptree_create_for_region(intel, + GL_TEXTURE_2D, + image->format, + image->region); + if (!irb->mt) + return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; - rb->DataType = image->data_type; rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx, image->internal_format); } -#endif /** * Called for each hardware renderbuffer when a _window_ is resized. @@ -775,7 +351,7 @@ intel_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, fb->Initialized = true; /* XXX remove someday */ - if (fb->Name != 0) { + if (_mesa_is_user_fbo(fb)) { return; } @@ -804,13 +380,16 @@ intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, /** * Create a new intel_renderbuffer which corresponds to an on-screen window, * not a user-created renderbuffer. + * + * \param num_samples must be quantized. */ struct intel_renderbuffer * -intel_create_renderbuffer(gl_format format) +intel_create_renderbuffer(gl_format format, unsigned num_samples) { - GET_CURRENT_CONTEXT(ctx); - struct intel_renderbuffer *irb; + struct gl_renderbuffer *rb; + + GET_CURRENT_CONTEXT(ctx); irb = CALLOC_STRUCT(intel_renderbuffer); if (!irb) { @@ -818,53 +397,41 @@ intel_create_renderbuffer(gl_format format) return NULL; } - _mesa_init_renderbuffer(&irb->Base, 0); - irb->Base.ClassID = INTEL_RB_CLASS; - irb->Base._BaseFormat = _mesa_get_format_base_format(format); - irb->Base.Format = format; - irb->Base.InternalFormat = irb->Base._BaseFormat; - irb->Base.DataType = intel_mesa_format_to_rb_datatype(format); + rb = &irb->Base.Base; + + _mesa_init_renderbuffer(rb, 0); + rb->ClassID = INTEL_RB_CLASS; + rb->_BaseFormat = _mesa_get_format_base_format(format); + rb->Format = format; + rb->InternalFormat = rb->_BaseFormat; + rb->NumSamples = num_samples; /* intel-specific methods */ - irb->Base.Delete = intel_delete_renderbuffer; - irb->Base.AllocStorage = intel_alloc_window_storage; - irb->Base.GetPointer = intel_get_pointer; + rb->Delete = intel_delete_renderbuffer; + rb->AllocStorage = intel_alloc_window_storage; return irb; } - -struct gl_renderbuffer* -intel_create_wrapped_renderbuffer(struct gl_context * ctx, - int width, int height, - gl_format format) +/** + * Private window-system buffers (as opposed to ones shared with the display + * server created with intel_create_renderbuffer()) are most similar in their + * handling to user-created renderbuffers, but they have a resize handler that + * may be called at intel_update_renderbuffers() time. + * + * \param num_samples must be quantized. + */ +struct intel_renderbuffer * +intel_create_private_renderbuffer(gl_format format, unsigned num_samples) { - /* - * The name here is irrelevant, as long as its nonzero, because the - * renderbuffer never gets entered into Mesa's renderbuffer hash table. - */ - GLuint name = ~0; + struct intel_renderbuffer *irb; - struct intel_renderbuffer *irb = CALLOC_STRUCT(intel_renderbuffer); - if (!irb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); - return NULL; - } + irb = intel_create_renderbuffer(format, num_samples); + irb->Base.Base.AllocStorage = intel_alloc_renderbuffer_storage; - struct gl_renderbuffer *rb = &irb->Base; - _mesa_init_renderbuffer(rb, name); - rb->ClassID = INTEL_RB_CLASS; - rb->_BaseFormat = _mesa_get_format_base_format(format); - rb->Format = format; - rb->InternalFormat = rb->_BaseFormat; - rb->DataType = intel_mesa_format_to_rb_datatype(format); - rb->Width = width; - rb->Height = height; - - return rb; + return irb; } - /** * Create a new renderbuffer object. * Typically called via glBindRenderbufferEXT(). @@ -874,6 +441,7 @@ intel_new_renderbuffer(struct gl_context * ctx, GLuint name) { /*struct intel_context *intel = intel_context(ctx); */ struct intel_renderbuffer *irb; + struct gl_renderbuffer *rb; irb = CALLOC_STRUCT(intel_renderbuffer); if (!irb) { @@ -881,16 +449,17 @@ intel_new_renderbuffer(struct gl_context * ctx, GLuint name) return NULL; } - _mesa_init_renderbuffer(&irb->Base, name); - irb->Base.ClassID = INTEL_RB_CLASS; + rb = &irb->Base.Base; + + _mesa_init_renderbuffer(rb, name); + rb->ClassID = INTEL_RB_CLASS; /* intel-specific methods */ - irb->Base.Delete = intel_delete_renderbuffer; - irb->Base.AllocStorage = intel_alloc_renderbuffer_storage; - irb->Base.GetPointer = intel_get_pointer; + rb->Delete = intel_delete_renderbuffer; + rb->AllocStorage = intel_alloc_renderbuffer_storage; /* span routines set in alloc_storage function */ - return &irb->Base; + return rb; } @@ -920,152 +489,57 @@ intel_framebuffer_renderbuffer(struct gl_context * ctx, { DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0); - intel_flush(ctx); - _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); intel_draw_buffer(ctx); } static bool -intel_update_tex_wrapper_regions(struct intel_context *intel, - struct intel_renderbuffer *irb, - struct intel_texture_image *intel_image); - -static bool -intel_update_wrapper(struct gl_context *ctx, struct intel_renderbuffer *irb, - struct gl_texture_image *texImage) +intel_renderbuffer_update_wrapper(struct intel_context *intel, + struct intel_renderbuffer *irb, + struct gl_texture_image *image, + uint32_t layer) { - struct intel_context *intel = intel_context(ctx); - struct intel_texture_image *intel_image = intel_texture_image(texImage); - int width, height, depth; - - if (!intel_span_supports_format(texImage->TexFormat)) { - DBG("Render to texture BAD FORMAT %s\n", - _mesa_get_format_name(texImage->TexFormat)); - return false; - } else { - DBG("Render to texture %s\n", _mesa_get_format_name(texImage->TexFormat)); - } + struct gl_renderbuffer *rb = &irb->Base.Base; + struct intel_texture_image *intel_image = intel_texture_image(image); + struct intel_mipmap_tree *mt = intel_image->mt; + int level = image->Level; - intel_miptree_get_dimensions_for_image(texImage, &width, &height, &depth); + rb->Format = image->TexFormat; + rb->InternalFormat = image->InternalFormat; + rb->_BaseFormat = image->_BaseFormat; + rb->Width = mt->level[level].width; + rb->Height = mt->level[level].height; - irb->Base.Format = texImage->TexFormat; - irb->Base.DataType = intel_mesa_format_to_rb_datatype(texImage->TexFormat); - irb->Base.InternalFormat = texImage->InternalFormat; - irb->Base._BaseFormat = _mesa_base_tex_format(ctx, irb->Base.InternalFormat); - irb->Base.Width = width; - irb->Base.Height = height; + rb->Delete = intel_delete_renderbuffer; + rb->AllocStorage = intel_nop_alloc_storage; - irb->Base.Delete = intel_delete_renderbuffer; - irb->Base.AllocStorage = intel_nop_alloc_storage; + intel_miptree_check_level_layer(mt, level, layer); + 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. */ + intel_miptree_reference(&irb->mt, mt); - bool ok; - struct intel_renderbuffer *depth_irb = - intel_renderbuffer(intel_image->depth_rb); + intel_renderbuffer_set_draw_offset(irb); - /* Update the hiz region if necessary. */ - ok = intel_update_tex_wrapper_regions(intel, depth_irb, intel_image); - if (!ok) { + if (mt->hiz_mt == NULL && + intel->vtbl.is_hiz_depth_format(intel, rb->Format)) { + intel_miptree_alloc_hiz(intel, mt, 0 /* num_samples */); + if (!mt->hiz_mt) return false; - } - - /* The tex image shares its embedded depth and stencil renderbuffers with - * the renderbuffer wrapper. */ - _mesa_reference_renderbuffer(&irb->wrapped_depth, - intel_image->depth_rb); - _mesa_reference_renderbuffer(&irb->wrapped_stencil, - intel_image->stencil_rb); - - return true; - } else { - return intel_update_tex_wrapper_regions(intel, irb, intel_image); - } -} - -/** - * FIXME: The handling of the hiz region is broken for mipmapped depth textures - * FIXME: because intel_finalize_mipmap_tree is unaware of it. - */ -static bool -intel_update_tex_wrapper_regions(struct intel_context *intel, - struct intel_renderbuffer *irb, - struct intel_texture_image *intel_image) -{ - struct gl_renderbuffer *rb = &irb->Base; - - /* Point the renderbuffer's region to the texture's region. */ - if (irb->region != intel_image->mt->region) { - intel_region_reference(&irb->region, intel_image->mt->region); - } - - /* Allocate the texture's hiz region if necessary. */ - if (intel->vtbl.is_hiz_depth_format(intel, rb->Format) - && !intel_image->mt->hiz_region) { - intel_image->mt->hiz_region = - intel_region_alloc(intel->intelScreen, - I915_TILING_Y, - _mesa_get_format_bytes(rb->Format), - rb->Width, - rb->Height, - true); - if (!intel_image->mt->hiz_region) - return false; - } - - /* Point the renderbuffer's hiz region to the texture's hiz region. */ - if (irb->hiz_region != intel_image->mt->hiz_region) { - intel_region_reference(&irb->hiz_region, intel_image->mt->hiz_region); } return true; } - -/** - * When glFramebufferTexture[123]D is called this function sets up the - * gl_renderbuffer wrapper around the texture image. - * This will have the region info needed for hardware rendering. - */ -static struct intel_renderbuffer * -intel_wrap_texture(struct gl_context * ctx, struct gl_texture_image *texImage) -{ - const GLuint name = ~0; /* not significant, but distinct for debugging */ - struct intel_renderbuffer *irb; - - /* make an intel_renderbuffer to wrap the texture image */ - irb = CALLOC_STRUCT(intel_renderbuffer); - if (!irb) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture"); - return NULL; - } - - _mesa_init_renderbuffer(&irb->Base, name); - irb->Base.ClassID = INTEL_RB_CLASS; - - if (!intel_update_wrapper(ctx, irb, texImage)) { - free(irb); - return NULL; - } - - return irb; -} - void -intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb, - struct intel_texture_image *intel_image, - int zoffset) +intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb) { unsigned int dst_x, dst_y; /* compute offset of the particular 2D image within the texture region */ - intel_miptree_get_image_offset(intel_image->mt, - intel_image->base.Base.Level, - intel_image->base.Base.Face, - zoffset, + intel_miptree_get_image_offset(irb->mt, + irb->mt_level, + irb->mt_layer, &dst_x, &dst_y); irb->draw_x = dst_x; @@ -1087,42 +561,16 @@ intel_renderbuffer_tile_offsets(struct intel_renderbuffer *irb, uint32_t *tile_x, uint32_t *tile_y) { - int cpp = irb->region->cpp; - uint32_t pitch = irb->region->pitch * cpp; - - if (irb->region->tiling == I915_TILING_NONE) { - *tile_x = 0; - *tile_y = 0; - return irb->draw_x * cpp + irb->draw_y * pitch; - } else if (irb->region->tiling == I915_TILING_X) { - *tile_x = irb->draw_x % (512 / cpp); - *tile_y = irb->draw_y % 8; - return ((irb->draw_y / 8) * (8 * pitch) + - (irb->draw_x - *tile_x) / (512 / cpp) * 4096); - } else { - assert(irb->region->tiling == I915_TILING_Y); - *tile_x = irb->draw_x % (128 / cpp); - *tile_y = irb->draw_y % 32; - return ((irb->draw_y / 32) * (32 * pitch) + - (irb->draw_x - *tile_x) / (128 / cpp) * 4096); - } -} + struct intel_region *region = irb->mt->region; + uint32_t mask_x, mask_y; -#ifndef I915 -static bool -need_tile_offset_workaround(struct brw_context *brw, - struct intel_renderbuffer *irb) -{ - uint32_t tile_x, tile_y; - - if (brw->has_surface_tile_offset) - return false; - - intel_renderbuffer_tile_offsets(irb, &tile_x, &tile_y); + intel_region_get_tile_masks(region, &mask_x, &mask_y, false); - return tile_x != 0 || tile_y != 0; + *tile_x = irb->draw_x & mask_x; + *tile_y = irb->draw_y & mask_y; + return intel_region_get_aligned_offset(region, irb->draw_x & ~mask_x, + irb->draw_y & ~mask_y, false); } -#endif /** * Called by glFramebufferTexture[123]DEXT() (and other places) to @@ -1135,12 +583,22 @@ intel_render_texture(struct gl_context * ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { + struct intel_context *intel = intel_context(ctx); struct gl_texture_image *image = _mesa_get_attachment_teximage(att); struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); struct intel_texture_image *intel_image = intel_texture_image(image); + struct intel_mipmap_tree *mt = intel_image->mt; + int layer; (void) fb; + if (att->CubeMapFace > 0) { + assert(att->Zoffset == 0); + layer = att->CubeMapFace; + } else { + layer = att->Zoffset; + } + if (!intel_image->mt) { /* Fallback on drawing to a texture that doesn't have a miptree * (has a border, width/height 0, etc.) @@ -1150,10 +608,13 @@ intel_render_texture(struct gl_context * ctx, return; } else if (!irb) { - irb = intel_wrap_texture(ctx, image); + intel_miptree_check_level_layer(mt, att->TextureLevel, layer); + + irb = (struct intel_renderbuffer *)intel_new_renderbuffer(ctx, ~0); + if (irb) { /* bind the wrapper to the attachment point */ - _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base); + _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base.Base); } else { /* fallback to software rendering */ @@ -1162,49 +623,19 @@ intel_render_texture(struct gl_context * ctx, } } - if (!intel_update_wrapper(ctx, irb, image)) { + if (!intel_renderbuffer_update_wrapper(intel, irb, image, layer)) { _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _swrast_render_texture(ctx, fb, att); return; } - DBG("Begin render texture tid %lx tex=%u w=%d h=%d refcount=%d\n", - _glthread_GetID(), - att->Texture->Name, image->Width, image->Height, - irb->Base.RefCount); - - intel_renderbuffer_set_draw_offset(irb, intel_image, att->Zoffset); - intel_image->used_as_render_target = true; - -#ifndef I915 - if (need_tile_offset_workaround(brw_context(ctx), irb)) { - /* Original gen4 hardware couldn't draw to a non-tile-aligned - * destination in a miptree unless you actually setup your - * renderbuffer as a miptree and used the fragile - * lod/array_index/etc. controls to select the image. So, - * instead, we just make a new single-level miptree and render - * into that. - */ - struct intel_context *intel = intel_context(ctx); - struct intel_mipmap_tree *new_mt; - int width, height, depth; - - intel_miptree_get_dimensions_for_image(image, &width, &height, &depth); - - new_mt = intel_miptree_create(intel, image->TexObject->Target, - intel_image->base.Base.TexFormat, - intel_image->base.Base.Level, - intel_image->base.Base.Level, - width, height, depth, - true); + irb->tex_image = image; - intel_miptree_copy_teximage(intel, intel_image, new_mt); - intel_renderbuffer_set_draw_offset(irb, intel_image, att->Zoffset); + DBG("Begin render %s texture tex=%u w=%d h=%d refcount=%d\n", + _mesa_get_format_name(image->TexFormat), + att->Texture->Name, image->Width, image->Height, + irb->Base.Base.RefCount); - intel_region_reference(&irb->region, intel_image->mt->region); - intel_miptree_release(&new_mt); - } -#endif /* update drawing region, etc */ intel_draw_buffer(ctx); } @@ -1221,14 +652,13 @@ intel_finish_render_texture(struct gl_context * ctx, struct gl_texture_object *tex_obj = att->Texture; struct gl_texture_image *image = tex_obj->Image[att->CubeMapFace][att->TextureLevel]; - struct intel_texture_image *intel_image = intel_texture_image(image); + struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); - DBG("Finish render texture tid %lx tex=%u\n", - _glthread_GetID(), att->Texture->Name); + DBG("Finish render %s texture tex=%u\n", + _mesa_get_format_name(image->TexFormat), att->Texture->Name); - /* Flag that this image may now be validated into the object's miptree. */ - if (intel_image) - intel_image->used_as_render_target = false; + if (irb) + irb->tex_image = NULL; /* Since we've (probably) rendered to the texture and will (likely) use * it in the texture domain later on in this batchbuffer, flush the @@ -1249,26 +679,56 @@ intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) intel_get_renderbuffer(fb, BUFFER_DEPTH); const struct intel_renderbuffer *stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); + struct intel_mipmap_tree *depth_mt = NULL, *stencil_mt = NULL; int i; - /* - * The depth and stencil renderbuffers are the same renderbuffer or wrap - * the same texture. - */ - if (depthRb && stencilRb) { - bool depth_stencil_are_same; - if (depthRb == stencilRb) - depth_stencil_are_same = true; - else if ((fb->Attachment[BUFFER_DEPTH].Type == GL_TEXTURE) && - (fb->Attachment[BUFFER_STENCIL].Type == GL_TEXTURE) && - (fb->Attachment[BUFFER_DEPTH].Texture->Name == - fb->Attachment[BUFFER_STENCIL].Texture->Name)) - depth_stencil_are_same = true; - else - depth_stencil_are_same = false; + DBG("%s() on fb %p (%s)\n", __FUNCTION__, + fb, (fb == ctx->DrawBuffer ? "drawbuffer" : + (fb == ctx->ReadBuffer ? "readbuffer" : "other buffer"))); - if (!intel->has_separate_stencil && !depth_stencil_are_same) { - fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + if (depthRb) + depth_mt = depthRb->mt; + if (stencilRb) { + stencil_mt = stencilRb->mt; + if (stencil_mt->stencil_mt) + stencil_mt = stencil_mt->stencil_mt; + } + + if (depth_mt && stencil_mt) { + if (depth_mt == stencil_mt) { + /* For true packed depth/stencil (not faked on prefers-separate-stencil + * hardware) we need to be sure they're the same level/layer, since + * we'll be emitting a single packet describing the packed setup. + */ + if (depthRb->mt_level != stencilRb->mt_level || + depthRb->mt_layer != stencilRb->mt_layer) { + DBG("depth image level/layer %d/%d != stencil image %d/%d\n", + depthRb->mt_level, + depthRb->mt_layer, + stencilRb->mt_level, + stencilRb->mt_layer); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + } + } else { + if (!intel->has_separate_stencil) { + DBG("separate stencil unsupported\n"); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + } + if (stencil_mt->format != MESA_FORMAT_S8) { + DBG("separate stencil is %s instead of S8\n", + _mesa_get_format_name(stencil_mt->format)); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + } + if (intel->gen < 7 && depth_mt->hiz_mt == NULL) { + /* Before Gen7, separate depth and stencil buffers can be used + * only if HiZ is enabled. From the Sandybridge PRM, Volume 2, + * Part 1, Bit 3DSTATE_DEPTH_BUFFER.SeparateStencilBufferEnable: + * [DevSNB]: This field must be set to the same value (enabled + * or disabled) as Hierarchical Depth Buffer Enable. + */ + DBG("separate stencil without HiZ\n"); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; + } } } @@ -1290,6 +750,17 @@ intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) continue; } + if (fb->Attachment[i].Type == GL_TEXTURE) { + const struct gl_texture_image *img = + _mesa_get_attachment_teximage_const(&fb->Attachment[i]); + + if (img->Border) { + DBG("texture with border\n"); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + continue; + } + } + irb = intel_renderbuffer(rb); if (irb == NULL) { DBG("software rendering renderbuffer\n"); @@ -1297,10 +768,9 @@ intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) continue; } - if (!intel_span_supports_format(irb->Base.Format) || - !intel->vtbl.render_target_supported(irb->Base.Format)) { - DBG("Unsupported texture/renderbuffer format attached: %s\n", - _mesa_get_format_name(irb->Base.Format)); + if (!intel->vtbl.render_target_supported(intel, rb)) { + DBG("Unsupported HW texture/renderbuffer format attached: %s\n", + _mesa_get_format_name(intel_rb_format(irb))); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; } } @@ -1323,41 +793,72 @@ intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx, GLbitfield mask, GLenum filter) { if (mask & GL_COLOR_BUFFER_BIT) { + GLint i; const struct gl_framebuffer *drawFb = ctx->DrawBuffer; const struct gl_framebuffer *readFb = ctx->ReadBuffer; - const struct gl_renderbuffer_attachment *drawAtt = - &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]]; - - /* If the source and destination are the same size with no - mirroring, the rectangles are within the size of the - texture and there is no scissor then we can use - glCopyTexSubimage2D to implement the blit. This will end - up as a fast hardware blit on some drivers */ - if (drawAtt && drawAtt->Texture && - srcX0 - srcX1 == dstX0 - dstX1 && - srcY0 - srcY1 == dstY0 - dstY1 && - srcX1 >= srcX0 && - srcY1 >= srcY0 && - srcX0 >= 0 && srcX1 <= readFb->Width && - srcY0 >= 0 && srcY1 <= readFb->Height && - dstX0 >= 0 && dstX1 <= drawFb->Width && - dstY0 >= 0 && dstY1 <= drawFb->Height && - !ctx->Scissor.Enabled) { - const struct gl_texture_object *texObj = drawAtt->Texture; - const GLuint dstLevel = drawAtt->TextureLevel; - const GLenum target = texObj->Target; - - struct gl_texture_image *texImage = - _mesa_select_tex_image(ctx, texObj, target, dstLevel); - - if (intel_copy_texsubimage(intel_context(ctx), - intel_texture_image(texImage), - dstX0, dstY0, - srcX0, srcY0, - srcX1 - srcX0, /* width */ - srcY1 - srcY0)) - mask &= ~GL_COLOR_BUFFER_BIT; + const struct gl_renderbuffer_attachment *drawAtt; + struct intel_renderbuffer *srcRb = + intel_renderbuffer(readFb->_ColorReadBuffer); + + /* If the source and destination are the same size with no mirroring, + * the rectangles are within the size of the texture and there is no + * scissor then we can use glCopyTexSubimage2D to implement the blit. + * This will end up as a fast hardware blit on some drivers. + */ + const GLboolean use_intel_copy_texsubimage = + srcX0 - srcX1 == dstX0 - dstX1 && + srcY0 - srcY1 == dstY0 - dstY1 && + srcX1 >= srcX0 && + srcY1 >= srcY0 && + srcX0 >= 0 && srcX1 <= readFb->Width && + srcY0 >= 0 && srcY1 <= readFb->Height && + dstX0 >= 0 && dstX1 <= drawFb->Width && + dstY0 >= 0 && dstY1 <= drawFb->Height && + !ctx->Scissor.Enabled; + + /* Verify that all the draw buffers can be blitted using + * intel_copy_texsubimage(). + */ + for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { + int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; + if (idx == -1) + continue; + drawAtt = &drawFb->Attachment[idx]; + + if (srcRb && drawAtt && drawAtt->Texture && + use_intel_copy_texsubimage) + continue; + else + return mask; + } + + /* Blit to all active draw buffers */ + for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { + int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; + if (idx == -1) + continue; + drawAtt = &drawFb->Attachment[idx]; + + { + const struct gl_texture_object *texObj = drawAtt->Texture; + const GLuint dstLevel = drawAtt->TextureLevel; + const GLenum target = texObj->Target; + + struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, texObj, target, dstLevel); + + if (!intel_copy_texsubimage(intel_context(ctx), + intel_texture_image(texImage), + dstX0, dstY0, + srcRb, + srcX0, srcY0, + srcX1 - srcX0, /* width */ + srcY1 - srcY0)) + return mask; + } } + + mask &= ~GL_COLOR_BUFFER_BIT; } return mask; @@ -1377,12 +878,103 @@ intel_blit_framebuffer(struct gl_context *ctx, if (mask == 0x0) return; +#ifndef I915 + mask = brw_blorp_framebuffer(intel_context(ctx), + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (mask == 0x0) + return; +#endif + _mesa_meta_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } +/** + * This is a no-op except on multisample buffers shared with DRI2. + */ +void +intel_renderbuffer_set_needs_downsample(struct intel_renderbuffer *irb) +{ + if (irb->mt && irb->mt->singlesample_mt) + irb->mt->need_downsample = true; +} + +void +intel_renderbuffer_set_needs_hiz_resolve(struct intel_renderbuffer *irb) +{ + if (irb->mt) { + intel_miptree_slice_set_needs_hiz_resolve(irb->mt, + irb->mt_level, + irb->mt_layer); + } +} + +void +intel_renderbuffer_set_needs_depth_resolve(struct intel_renderbuffer *irb) +{ + if (irb->mt) { + intel_miptree_slice_set_needs_depth_resolve(irb->mt, + irb->mt_level, + irb->mt_layer); + } +} + +bool +intel_renderbuffer_resolve_hiz(struct intel_context *intel, + struct intel_renderbuffer *irb) +{ + if (irb->mt) + return intel_miptree_slice_resolve_hiz(intel, + irb->mt, + irb->mt_level, + irb->mt_layer); + + return false; +} + +bool +intel_renderbuffer_resolve_depth(struct intel_context *intel, + struct intel_renderbuffer *irb) +{ + if (irb->mt) + return intel_miptree_slice_resolve_depth(intel, + irb->mt, + irb->mt_level, + irb->mt_layer); + + return false; +} + +void +intel_renderbuffer_move_to_temp(struct intel_context *intel, + struct intel_renderbuffer *irb) +{ + struct intel_texture_image *intel_image = + intel_texture_image(irb->tex_image); + struct intel_mipmap_tree *new_mt; + int width, height, depth; + + intel_miptree_get_dimensions_for_image(irb->tex_image, &width, &height, &depth); + + new_mt = intel_miptree_create(intel, irb->tex_image->TexObject->Target, + intel_image->base.Base.TexFormat, + intel_image->base.Base.Level, + intel_image->base.Base.Level, + width, height, depth, + true, + irb->mt->num_samples, + false /* force_y_tiling */); + + intel_miptree_copy_teximage(intel, intel_image, new_mt); + intel_miptree_reference(&irb->mt, intel_image->mt); + intel_renderbuffer_set_draw_offset(irb); + intel_miptree_release(&new_mt); +} + /** * Do one-time context initializations related to GL_EXT_framebuffer_object. * Hook in device driver functions. @@ -1401,9 +993,6 @@ intel_fbo_init(struct intel_context *intel) intel->ctx.Driver.ResizeBuffers = intel_resize_buffers; intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer; intel->ctx.Driver.BlitFramebuffer = intel_blit_framebuffer; - -#if FEATURE_OES_EGL_image intel->ctx.Driver.EGLImageTargetRenderbufferStorage = intel_image_target_renderbuffer_storage; -#endif }