X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fintel%2Fintel_fbo.c;h=ca9aa03136b00ee26c51cbf82c58a8f57625bba0;hb=f88393afbe93898b167b3f218bbf33cffc70ef38;hp=e48d6ef9cbd5c6abfec2537045869c1a8eff56ca;hpb=f73caddd3339d284556036d031ab30ce8057a510;p=android-x86%2Fexternal-mesa.git diff --git a/src/mesa/drivers/dri/intel/intel_fbo.c b/src/mesa/drivers/dri/intel/intel_fbo.c index e48d6ef9cbd..ca9aa03136b 100644 --- a/src/mesa/drivers/dri/intel/intel_fbo.c +++ b/src/mesa/drivers/dri/intel/intel_fbo.c @@ -26,6 +26,7 @@ **************************************************************************/ +#include "main/enums.h" #include "main/imports.h" #include "main/macros.h" #include "main/mfeatures.h" @@ -35,12 +36,15 @@ #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" #include "intel_context.h" #include "intel_batchbuffer.h" #include "intel_buffers.h" +#include "intel_blit.h" #include "intel_fbo.h" #include "intel_mipmap_tree.h" #include "intel_regions.h" @@ -52,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. @@ -74,27 +93,126 @@ intel_delete_renderbuffer(struct gl_renderbuffer *rb) ASSERT(irb); - intel_region_release(&irb->region); - intel_region_release(&irb->hiz_region); + intel_miptree_release(&irb->mt); + + _mesa_delete_renderbuffer(rb); +} + +/** + * \see dd_function_table::MapRenderbuffer + */ +static void +intel_map_renderbuffer(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 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->mt) { + *out_map = NULL; + *out_stride = 0; + return; + } + + /* 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; + } + + intel_miptree_map(intel, irb->mt, irb->mt_level, irb->mt_layer, + x, y, w, h, mode, &map, &stride); + + if (rb->Name == 0) { + map += (h - 1) * stride; + stride = -stride; + } + + 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); + + *out_map = map; + *out_stride = stride; +} + +/** + * \see dd_function_table::UnmapRenderbuffer + */ +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); - _mesa_reference_renderbuffer(&irb->wrapped_depth, NULL); - _mesa_reference_renderbuffer(&irb->wrapped_stencil, NULL); + DBG("%s: rb %d (%s)\n", __FUNCTION__, + rb->Name, _mesa_get_format_name(rb->Format)); - free(irb); + 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) +unsigned +intel_quantize_num_samples(struct intel_screen *intel, unsigned num_samples) { - /* By returning NULL we force all software rendering to go through - * the span routines. - */ - return NULL; + 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; + } } @@ -108,10 +226,9 @@ intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer 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: @@ -120,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: @@ -141,118 +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); - } - /* allocate new memory region/renderbuffer */ - - /* alloc hardware renderbuffer */ - DBG("Allocating %d x %d Intel RBO\n", 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), - GL_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; - } + intel_miptree_release(&irb->mt); - depth_rb->Wrapped = rb; - stencil_rb->Wrapped = rb; - _mesa_reference_renderbuffer(&irb->wrapped_depth, depth_rb); - _mesa_reference_renderbuffer(&irb->wrapped_stencil, stencil_rb); + DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(internalFormat), + _mesa_get_format_name(rb->Format), width, height); - } else { - irb->region = intel_region_alloc(intel->intelScreen, tiling, cpp, - width, height, GL_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, - GL_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 GL_TRUE; + return true; } -#if FEATURE_OES_EGL_image static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, @@ -269,18 +295,33 @@ intel_image_target_renderbuffer_storage(struct gl_context *ctx, if (image == NULL) return; + /* __DRIimage is opaque to the core so it has to be checked here */ + switch (image->format) { + case MESA_FORMAT_RGBA8888_REV: + _mesa_error(&intel->ctx, GL_INVALID_OPERATION, + "glEGLImageTargetRenderbufferStorage(unsupported image format"); + return; + break; + default: + break; + } + 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. @@ -296,7 +337,7 @@ intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, rb->Height = height; rb->InternalFormat = internalFormat; - return GL_TRUE; + return true; } @@ -308,9 +349,9 @@ intel_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, _mesa_resize_framebuffer(ctx, fb, width, height); - fb->Initialized = GL_TRUE; /* XXX remove someday */ + fb->Initialized = true; /* XXX remove someday */ - if (fb->Name != 0) { + if (_mesa_is_user_fbo(fb)) { return; } @@ -333,19 +374,22 @@ intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { _mesa_problem(ctx, "intel_op_alloc_storage should never be called."); - return GL_FALSE; + return false; } /** * 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) { @@ -353,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(). @@ -409,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) { @@ -416,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; } @@ -437,7 +471,7 @@ intel_bind_framebuffer(struct gl_context * ctx, GLenum target, struct gl_framebuffer *fb, struct gl_framebuffer *fbread) { if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) { - intel_draw_buffer(ctx, fb); + intel_draw_buffer(ctx); } else { /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */ @@ -455,155 +489,72 @@ 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, fb); -} - -static bool -intel_update_tex_wrapper_regions(struct intel_context *intel, - struct intel_renderbuffer *irb, - struct intel_texture_image *intel_image); - -static GLboolean -intel_update_wrapper(struct gl_context *ctx, struct intel_renderbuffer *irb, - struct gl_texture_image *texImage) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_texture_image *intel_image = intel_texture_image(texImage); - - if (!intel_span_supports_format(texImage->TexFormat)) { - DBG("Render to texture BAD FORMAT %s\n", - _mesa_get_format_name(texImage->TexFormat)); - return GL_FALSE; - } else { - DBG("Render to texture %s\n", _mesa_get_format_name(texImage->TexFormat)); - } - - 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 = texImage->Width; - irb->Base.Height = texImage->Height; - - irb->Base.Delete = intel_delete_renderbuffer; - irb->Base.AllocStorage = intel_nop_alloc_storage; - - if (intel_image->stencil_rb) { - /* The tex image has packed depth/stencil format, but is using separate - * stencil. */ - - bool ok; - struct intel_renderbuffer *depth_irb = - intel_renderbuffer(intel_image->depth_rb); - - /* Update the hiz region if necessary. */ - ok = intel_update_tex_wrapper_regions(intel, depth_irb, intel_image); - if (!ok) { - return false; - } - - /* The tex image shares its embedded depth and stencil renderbuffers with - * the renderbuffer wrapper. */ - if (irb->wrapped_depth != intel_image->depth_rb) { - _mesa_reference_renderbuffer(&irb->wrapped_depth, - intel_image->depth_rb); - } - if (irb->wrapped_stencil != intel_image->stencil_rb) { - _mesa_reference_renderbuffer(&irb->wrapped_stencil, - intel_image->stencil_rb); - } - - return true; - - } else { - return intel_update_tex_wrapper_regions(intel, irb, intel_image); - } + intel_draw_buffer(ctx); } /** - * FIXME: The handling of the hiz region is broken for mipmapped depth textures - * FIXME: because intel_finalize_mipmap_tree is unaware of it. + * \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_update_tex_wrapper_regions(struct intel_context *intel, - struct intel_renderbuffer *irb, - struct intel_texture_image *intel_image) +intel_renderbuffer_update_wrapper(struct intel_context *intel, + struct intel_renderbuffer *irb, + struct gl_texture_image *image, + uint32_t layer) { - 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, - GL_TRUE); - if (!intel_image->mt->hiz_region) - return GL_FALSE; - } + 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; - /* 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); - } + rb->Format = image->TexFormat; + rb->InternalFormat = image->InternalFormat; + rb->_BaseFormat = image->_BaseFormat; + rb->Width = mt->level[level].width; + rb->Height = mt->level[level].height; - return GL_TRUE; -} + rb->Delete = intel_delete_renderbuffer; + rb->AllocStorage = intel_nop_alloc_storage; + intel_miptree_check_level_layer(mt, level, layer); + irb->mt_level = level; + irb->mt_layer = layer; -/** - * 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; + intel_miptree_reference(&irb->mt, mt); - /* 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; + intel_renderbuffer_set_draw_offset(irb); - if (!intel_update_wrapper(ctx, irb, texImage)) { - free(irb); - return NULL; + 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; } - return irb; + return true; } 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) { - struct intel_mipmap_tree *mt = intel_image->mt; 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->level, - intel_image->face, - zoffset, + intel_miptree_get_image_offset(irb->mt, + irb->mt_level, + 0, /* face, which we ignore */ + irb->mt_layer, &dst_x, &dst_y); irb->draw_x = dst_x; @@ -625,42 +576,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); - } -} - -#ifndef I915 -static bool -need_tile_offset_workaround(struct brw_context *brw, - struct intel_renderbuffer *irb) -{ - uint32_t tile_x, tile_y; + struct intel_region *region = irb->mt->region; + uint32_t mask_x, mask_y; - if (brw->has_surface_tile_offset) - return false; + intel_region_get_tile_masks(region, &mask_x, &mask_y, false); - intel_renderbuffer_tile_offsets(irb, &tile_x, &tile_y); - - 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 @@ -673,12 +598,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.) @@ -688,10 +623,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 */ @@ -700,57 +638,21 @@ 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); + irb->tex_image = image; - intel_renderbuffer_set_draw_offset(irb, intel_image, att->Zoffset); - intel_image->used_as_render_target = GL_TRUE; + 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); -#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 *old_mt = intel_image->mt; - struct intel_mipmap_tree *new_mt; - - new_mt = intel_miptree_create(intel, image->TexObject->Target, - intel_image->base.TexFormat, - intel_image->level, - intel_image->level, - intel_image->base.Width, - intel_image->base.Height, - intel_image->base.Depth, - GL_TRUE); - - intel_miptree_image_copy(intel, - new_mt, - intel_image->face, - intel_image->level, - old_mt); - - intel_miptree_release(intel, &intel_image->mt); - intel_image->mt = new_mt; - intel_renderbuffer_set_draw_offset(irb, intel_image, att->Zoffset); - - intel_region_reference(&irb->region, intel_image->mt->region); - } -#endif /* update drawing region, etc */ - intel_draw_buffer(ctx, fb); + intel_draw_buffer(ctx); } @@ -765,14 +667,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 = GL_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 @@ -793,26 +694,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; + } } } @@ -834,6 +765,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"); @@ -841,10 +783,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; } } @@ -871,13 +812,15 @@ intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx, const struct gl_framebuffer *readFb = ctx->ReadBuffer; const struct gl_renderbuffer_attachment *drawAtt = &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]]; + 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 */ - if (drawAtt && drawAtt->Texture && + if (srcRb && drawAtt && drawAtt->Texture && srcX0 - srcX1 == dstX0 - dstX1 && srcY0 - srcY1 == dstY0 - dstY1 && srcX1 >= srcX0 && @@ -893,12 +836,11 @@ intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx, struct gl_texture_image *texImage = _mesa_select_tex_image(ctx, texObj, target, dstLevel); - GLenum internalFormat = texImage->InternalFormat; - if (intel_copy_texsubimage(intel_context(ctx), target, + if (intel_copy_texsubimage(intel_context(ctx), intel_texture_image(texImage), - internalFormat, dstX0, dstY0, + srcRb, srcX0, srcY0, srcX1 - srcX0, /* width */ srcY1 - srcY0)) @@ -923,6 +865,15 @@ 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, @@ -930,6 +881,62 @@ intel_blit_framebuffer(struct gl_context *ctx, } /** + * 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; +} + +/** * Do one-time context initializations related to GL_EXT_framebuffer_object. * Hook in device driver functions. */ @@ -938,6 +945,8 @@ intel_fbo_init(struct intel_context *intel) { intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer; intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer; + intel->ctx.Driver.MapRenderbuffer = intel_map_renderbuffer; + intel->ctx.Driver.UnmapRenderbuffer = intel_unmap_renderbuffer; intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer; intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer; intel->ctx.Driver.RenderTexture = intel_render_texture; @@ -945,9 +954,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 }