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; }
/** * \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT */ static void intel_tex_map_image_for_swrast(struct intel_context *intel, struct intel_texture_image *intel_image, GLbitfield mode) { int level; int face; struct intel_mipmap_tree *mt; unsigned int x, y; if (!intel_image || !intel_image->mt) return; level = intel_image->base.Base.Level; face = intel_image->base.Base.Face; mt = intel_image->mt; for (int i = 0; i < mt->level[level].depth; i++) intel_miptree_slice_resolve_depth(intel, mt, level, i); if (mt->target == GL_TEXTURE_3D || mt->target == GL_TEXTURE_2D_ARRAY || mt->target == GL_TEXTURE_1D_ARRAY) { int i; /* ImageOffsets[] is only used for swrast's fetch_texel_3d, so we can't * share code with the normal path. */ for (i = 0; i < mt->level[level].depth; i++) { intel_miptree_get_image_offset(mt, level, i, &x, &y); intel_image->base.ImageOffsets[i] = x + y * (mt->region->pitch / mt->region->cpp); } DBG("%s \n", __FUNCTION__); intel_image->base.Map = intel_miptree_map_raw(intel, mt); } else { assert(intel_image->base.Base.Depth == 1); intel_miptree_get_image_offset(mt, level, face, &x, &y); DBG("%s: (%d,%d) -> (%d, %d)/%d\n", __FUNCTION__, face, level, x, y, mt->region->pitch); intel_image->base.Map = intel_miptree_map_raw(intel, mt) + x * mt->cpp + y * mt->region->pitch; } assert(mt->region->pitch % mt->region->cpp == 0); intel_image->base.RowStride = mt->region->pitch / mt->region->cpp; }
/** * Implements a rectangular block transfer (blit) of pixels between two * miptrees. * * Our blitter can operate on 1, 2, or 4-byte-per-pixel data, with generous, * but limited, pitches and sizes allowed. * * The src/dst coordinates are relative to the given level/slice of the * miptree. * * If @src_flip or @dst_flip is set, then the rectangle within that miptree * will be inverted (including scanline order) when copying. This is common * in GL when copying between window system and user-created * renderbuffers/textures. */ bool intel_miptree_blit(struct brw_context *brw, struct intel_mipmap_tree *src_mt, int src_level, int src_slice, uint32_t src_x, uint32_t src_y, bool src_flip, struct intel_mipmap_tree *dst_mt, int dst_level, int dst_slice, uint32_t dst_x, uint32_t dst_y, bool dst_flip, uint32_t width, uint32_t height, GLenum logicop) { /* No sRGB decode or encode is done by the hardware blitter, which is * consistent with what we want in the callers (glCopyTexSubImage(), * glBlitFramebuffer(), texture validation, etc.). */ gl_format src_format = _mesa_get_srgb_format_linear(src_mt->format); gl_format dst_format = _mesa_get_srgb_format_linear(dst_mt->format); /* The blitter doesn't support doing any format conversions. We do also * support blitting ARGB8888 to XRGB8888 (trivial, the values dropped into * the X channel don't matter), and XRGB8888 to ARGB8888 by setting the A * channel to 1.0 at the end. */ if (src_format != dst_format && ((src_format != MESA_FORMAT_ARGB8888 && src_format != MESA_FORMAT_XRGB8888) || (dst_format != MESA_FORMAT_ARGB8888 && dst_format != MESA_FORMAT_XRGB8888))) { perf_debug("%s: Can't use hardware blitter from %s to %s, " "falling back.\n", __FUNCTION__, _mesa_get_format_name(src_format), _mesa_get_format_name(dst_format)); return false; } /* According to the Ivy Bridge PRM, Vol1 Part4, section 1.2.1.2 (Graphics * Data Size Limitations): * * The BLT engine is capable of transferring very large quantities of * graphics data. Any graphics data read from and written to the * destination is permitted to represent a number of pixels that * occupies up to 65,536 scan lines and up to 32,768 bytes per scan line * at the destination. The maximum number of pixels that may be * represented per scan line’s worth of graphics data depends on the * color depth. * * Furthermore, intelEmitCopyBlit (which is called below) uses a signed * 16-bit integer to represent buffer pitch, so it can only handle buffer * pitches < 32k. * * As a result of these two limitations, we can only use the blitter to do * this copy when the region's pitch is less than 32k. */ if (src_mt->region->pitch > 32768 || dst_mt->region->pitch > 32768) { perf_debug("Falling back due to >32k pitch\n"); return false; } /* The blitter has no idea about HiZ or fast color clears, so we need to * resolve the miptrees before we do anything. */ intel_miptree_slice_resolve_depth(brw, src_mt, src_level, src_slice); intel_miptree_slice_resolve_depth(brw, dst_mt, dst_level, dst_slice); intel_miptree_resolve_color(brw, src_mt); intel_miptree_resolve_color(brw, dst_mt); if (src_flip) src_y = src_mt->level[src_level].height - src_y - height; if (dst_flip) dst_y = dst_mt->level[dst_level].height - dst_y - height; int src_pitch = src_mt->region->pitch; if (src_flip != dst_flip) src_pitch = -src_pitch; uint32_t src_image_x, src_image_y; intel_miptree_get_image_offset(src_mt, src_level, src_slice, &src_image_x, &src_image_y); src_x += src_image_x; src_y += src_image_y; uint32_t dst_image_x, dst_image_y; intel_miptree_get_image_offset(dst_mt, dst_level, dst_slice, &dst_image_x, &dst_image_y); dst_x += dst_image_x; dst_y += dst_image_y; if (!intelEmitCopyBlit(brw, src_mt->cpp, src_pitch, src_mt->region->bo, src_mt->offset, src_mt->region->tiling, dst_mt->region->pitch, dst_mt->region->bo, dst_mt->offset, dst_mt->region->tiling, src_x, src_y, dst_x, dst_y, width, height, logicop)) { return false; } if (src_mt->format == MESA_FORMAT_XRGB8888 && dst_mt->format == MESA_FORMAT_ARGB8888) { intel_miptree_set_alpha_to_one(brw, dst_mt, dst_x, dst_y, width, height); } return true; }
static void blorp_surf_for_miptree(struct brw_context *brw, struct blorp_surf *surf, struct intel_mipmap_tree *mt, bool is_render_target, uint32_t safe_aux_usage, unsigned *level, unsigned start_layer, unsigned num_layers, struct isl_surf tmp_surfs[2]) { if (mt->msaa_layout == INTEL_MSAA_LAYOUT_UMS || mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) { const unsigned num_samples = MAX2(1, mt->num_samples); for (unsigned i = 0; i < num_layers; i++) { for (unsigned s = 0; s < num_samples; s++) { const unsigned phys_layer = (start_layer + i) * num_samples + s; intel_miptree_check_level_layer(mt, *level, phys_layer); } } } else { for (unsigned i = 0; i < num_layers; i++) intel_miptree_check_level_layer(mt, *level, start_layer + i); } intel_miptree_get_isl_surf(brw, mt, &tmp_surfs[0]); surf->surf = &tmp_surfs[0]; surf->addr = (struct blorp_address) { .buffer = mt->bo, .offset = mt->offset, .read_domains = is_render_target ? I915_GEM_DOMAIN_RENDER : I915_GEM_DOMAIN_SAMPLER, .write_domain = is_render_target ? I915_GEM_DOMAIN_RENDER : 0, }; if (brw->gen == 6 && mt->format == MESA_FORMAT_S_UINT8 && mt->array_layout == ALL_SLICES_AT_EACH_LOD) { /* Sandy bridge stencil and HiZ use this ALL_SLICES_AT_EACH_LOD hack in * order to allow for layered rendering. The hack makes each LOD of the * stencil or HiZ buffer a single tightly packed array surface at some * offset into the surface. Since ISL doesn't know how to deal with the * crazy ALL_SLICES_AT_EACH_LOD layout and since we have to do a manual * offset of it anyway, we might as well do the offset here and keep the * hacks inside the i965 driver. * * See also gen6_depth_stencil_state.c */ uint32_t offset; apply_gen6_stencil_hiz_offset(&tmp_surfs[0], mt, *level, &offset); surf->addr.offset += offset; *level = 0; } struct isl_surf *aux_surf = &tmp_surfs[1]; intel_miptree_get_aux_isl_surf(brw, mt, aux_surf, &surf->aux_usage); if (surf->aux_usage != ISL_AUX_USAGE_NONE) { if (surf->aux_usage == ISL_AUX_USAGE_HIZ) { /* If we're not going to use it as a depth buffer, resolve HiZ */ if (!(safe_aux_usage & (1 << ISL_AUX_USAGE_HIZ))) { for (unsigned i = 0; i < num_layers; i++) { intel_miptree_slice_resolve_depth(brw, mt, *level, start_layer + i); /* If we're rendering to it then we'll need a HiZ resolve once * we're done before we can use it with HiZ again. */ if (is_render_target) intel_miptree_slice_set_needs_hiz_resolve(mt, *level, start_layer + i); } surf->aux_usage = ISL_AUX_USAGE_NONE; } } else if (!(safe_aux_usage & (1 << surf->aux_usage))) { uint32_t flags = 0; if (safe_aux_usage & (1 << ISL_AUX_USAGE_CCS_E)) flags |= INTEL_MIPTREE_IGNORE_CCS_E; intel_miptree_resolve_color(brw, mt, *level, start_layer, num_layers, flags); assert(!intel_miptree_has_color_unresolved(mt, *level, 1, start_layer, num_layers)); surf->aux_usage = ISL_AUX_USAGE_NONE; } } if (is_render_target) intel_miptree_used_for_rendering(brw, mt, *level, start_layer, num_layers); if (surf->aux_usage != ISL_AUX_USAGE_NONE) { /* We only really need a clear color if we also have an auxiliary * surface. Without one, it does nothing. */ surf->clear_color = intel_miptree_get_isl_clear_color(brw, mt); surf->aux_surf = aux_surf; surf->aux_addr = (struct blorp_address) { .read_domains = is_render_target ? I915_GEM_DOMAIN_RENDER : I915_GEM_DOMAIN_SAMPLER, .write_domain = is_render_target ? I915_GEM_DOMAIN_RENDER : 0, }; if (mt->mcs_buf) { surf->aux_addr.buffer = mt->mcs_buf->bo; surf->aux_addr.offset = mt->mcs_buf->offset; } else { assert(surf->aux_usage == ISL_AUX_USAGE_HIZ); struct intel_mipmap_tree *hiz_mt = mt->hiz_buf->mt; if (hiz_mt) { surf->aux_addr.buffer = hiz_mt->bo; if (brw->gen == 6 && hiz_mt->array_layout == ALL_SLICES_AT_EACH_LOD) { /* gen6 requires the HiZ buffer to be manually offset to the * right location. We could fixup the surf but it doesn't * matter since most of those fields don't matter. */ apply_gen6_stencil_hiz_offset(aux_surf, hiz_mt, *level, &surf->aux_addr.offset); } else { surf->aux_addr.offset = 0; } assert(hiz_mt->pitch == aux_surf->row_pitch); } else { surf->aux_addr.buffer = mt->hiz_buf->aux_base.bo; surf->aux_addr.offset = mt->hiz_buf->aux_base.offset; } } } else { surf->aux_addr = (struct blorp_address) { .buffer = NULL, }; memset(&surf->clear_color, 0, sizeof(surf->clear_color)); } assert((surf->aux_usage == ISL_AUX_USAGE_NONE) == (surf->aux_addr.buffer == NULL)); }