void brw_workaround_depthstencil_alignment(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; bool rebase_depth = false; bool rebase_stencil = false; struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL; struct intel_mipmap_tree *stencil_mt = get_stencil_miptree(stencil_irb); uint32_t tile_x = 0, tile_y = 0, stencil_tile_x = 0, stencil_tile_y = 0; uint32_t stencil_draw_x = 0, stencil_draw_y = 0; if (depth_irb) depth_mt = depth_irb->mt; uint32_t tile_mask_x, tile_mask_y; brw_get_depthstencil_tile_masks(depth_mt, stencil_mt, &tile_mask_x, &tile_mask_y); if (depth_irb) { tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; /* According to the Sandy Bridge PRM, volume 2 part 1, pp326-327 * (3DSTATE_DEPTH_BUFFER dw5), in the documentation for "Depth * Coordinate Offset X/Y": * * "The 3 LSBs of both offsets must be zero to ensure correct * alignment" */ if (tile_x & 7 || tile_y & 7) rebase_depth = true; /* We didn't even have intra-tile offsets before g45. */ if (intel->gen == 4 && !intel->is_g4x) { if (tile_x || tile_y) rebase_depth = true; } if (rebase_depth) { perf_debug("HW workaround: blitting depth level %d to a temporary " "to fix alignment (depth tile offset %d,%d)\n", depth_irb->mt_level, tile_x, tile_y); intel_renderbuffer_move_to_temp(intel, depth_irb); /* In the case of stencil_irb being the same packed depth/stencil * texture but not the same rb, make it point at our rebased mt, too. */ if (stencil_irb && stencil_irb != depth_irb && stencil_irb->mt == depth_mt) { intel_miptree_reference(&stencil_irb->mt, depth_irb->mt); intel_renderbuffer_set_draw_offset(stencil_irb); } stencil_mt = get_stencil_miptree(stencil_irb); tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; } if (stencil_irb) { stencil_mt = get_stencil_miptree(stencil_irb); intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); int stencil_tile_x = stencil_draw_x & tile_mask_x; int stencil_tile_y = stencil_draw_y & tile_mask_y; /* If stencil doesn't match depth, then we'll need to rebase stencil * as well. (if we hadn't decided to rebase stencil before, the * post-stencil depth test will also rebase depth to try to match it * up). */ if (tile_x != stencil_tile_x || tile_y != stencil_tile_y) { rebase_stencil = true; } } } /* If we have (just) stencil, check it for ignored low bits as well */ if (stencil_irb) { intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); stencil_tile_x = stencil_draw_x & tile_mask_x; stencil_tile_y = stencil_draw_y & tile_mask_y; if (stencil_tile_x & 7 || stencil_tile_y & 7) rebase_stencil = true; if (intel->gen == 4 && !intel->is_g4x) { if (stencil_tile_x || stencil_tile_y) rebase_stencil = true; } } if (rebase_stencil) { perf_debug("HW workaround: blitting stencil level %d to a temporary " "to fix alignment (stencil tile offset %d,%d)\n", stencil_irb->mt_level, stencil_tile_x, stencil_tile_y); intel_renderbuffer_move_to_temp(intel, stencil_irb); stencil_mt = get_stencil_miptree(stencil_irb); intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); stencil_tile_x = stencil_draw_x & tile_mask_x; stencil_tile_y = stencil_draw_y & tile_mask_y; if (depth_irb && depth_irb->mt == stencil_irb->mt) { intel_miptree_reference(&depth_irb->mt, stencil_irb->mt); intel_renderbuffer_set_draw_offset(depth_irb); } else if (depth_irb && !rebase_depth) { if (tile_x != stencil_tile_x || tile_y != stencil_tile_y) { perf_debug("HW workaround: blitting depth level %d to a temporary " "to match stencil level %d alignment (depth tile offset " "%d,%d, stencil offset %d,%d)\n", depth_irb->mt_level, stencil_irb->mt_level, tile_x, tile_y, stencil_tile_x, stencil_tile_y); intel_renderbuffer_move_to_temp(intel, depth_irb); tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; if (stencil_irb && stencil_irb->mt == depth_mt) { intel_miptree_reference(&stencil_irb->mt, depth_irb->mt); intel_renderbuffer_set_draw_offset(stencil_irb); } WARN_ONCE(stencil_tile_x != tile_x || stencil_tile_y != tile_y, "Rebased stencil tile offset (%d,%d) doesn't match depth " "tile offset (%d,%d).\n", stencil_tile_x, stencil_tile_y, tile_x, tile_y); } } } if (!depth_irb) { tile_x = stencil_tile_x; tile_y = stencil_tile_y; } /* While we just tried to get everything aligned, we may have failed to do * so in the case of rendering to array or 3D textures, where nonzero faces * will still have an offset post-rebase. At least give an informative * warning. */ WARN_ONCE((tile_x & 7) || (tile_y & 7), "Depth/stencil buffer needs alignment to 8-pixel boundaries.\n" "Truncating offset, bad rendering may occur.\n"); tile_x &= ~7; tile_y &= ~7; /* Now, after rebasing, save off the new dephtstencil state so the hardware * packets can just dereference that without re-calculating tile offsets. */ brw->depthstencil.tile_x = tile_x; brw->depthstencil.tile_y = tile_y; brw->depthstencil.depth_offset = 0; brw->depthstencil.stencil_offset = 0; brw->depthstencil.hiz_offset = 0; brw->depthstencil.depth_mt = NULL; brw->depthstencil.stencil_mt = NULL; brw->depthstencil.hiz_mt = NULL; if (depth_irb) { depth_mt = depth_irb->mt; brw->depthstencil.depth_mt = depth_mt; brw->depthstencil.depth_offset = intel_region_get_aligned_offset(depth_mt->region, depth_irb->draw_x & ~tile_mask_x, depth_irb->draw_y & ~tile_mask_y, false); if (depth_mt->hiz_mt) { brw->depthstencil.hiz_mt = depth_mt->hiz_mt; brw->depthstencil.hiz_offset = intel_region_get_aligned_offset(depth_mt->region, depth_irb->draw_x & ~tile_mask_x, (depth_irb->draw_y & ~tile_mask_y) / 2, false); } } if (stencil_irb) { stencil_mt = get_stencil_miptree(stencil_irb); brw->depthstencil.stencil_mt = stencil_mt; if (stencil_mt->format == MESA_FORMAT_S8) { /* Note: we can't compute the stencil offset using * intel_region_get_aligned_offset(), because stencil_region claims * that the region is untiled even though it's W tiled. */ brw->depthstencil.stencil_offset = (stencil_draw_y & ~tile_mask_y) * stencil_mt->region->pitch + (stencil_draw_x & ~tile_mask_x) * 64; } } }
static void gen6_blorp_emit_depth_stencil_config(struct brw_context *brw, const brw_blorp_params *params) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; uint32_t draw_x = params->depth.x_offset; uint32_t draw_y = params->depth.y_offset; uint32_t tile_mask_x, tile_mask_y; brw_get_depthstencil_tile_masks(params->depth.mt, params->depth.level, params->depth.layer, NULL, &tile_mask_x, &tile_mask_y); /* 3DSTATE_DEPTH_BUFFER */ { uint32_t tile_x = draw_x & tile_mask_x; uint32_t tile_y = draw_y & tile_mask_y; uint32_t offset = intel_region_get_aligned_offset(params->depth.mt->region, draw_x & ~tile_mask_x, draw_y & ~tile_mask_y, false); /* According to the Sandy Bridge PRM, volume 2 part 1, pp326-327 * (3DSTATE_DEPTH_BUFFER dw5), in the documentation for "Depth * Coordinate Offset X/Y": * * "The 3 LSBs of both offsets must be zero to ensure correct * alignment" * * We have no guarantee that tile_x and tile_y are correctly aligned, * since they are determined by the mipmap layout, which is only aligned * to multiples of 4. * * So, to avoid hanging the GPU, just smash the low order 3 bits of * tile_x and tile_y to 0. This is a temporary workaround until we come * up with a better solution. */ WARN_ONCE((tile_x & 7) || (tile_y & 7), "Depth/stencil buffer needs alignment to 8-pixel boundaries.\n" "Truncating offset, bad rendering may occur.\n"); tile_x &= ~7; tile_y &= ~7; intel_emit_post_sync_nonzero_flush(intel); intel_emit_depth_stall_flushes(intel); BEGIN_BATCH(7); OUT_BATCH(_3DSTATE_DEPTH_BUFFER << 16 | (7 - 2)); OUT_BATCH((params->depth.mt->region->pitch - 1) | params->depth_format << 18 | 1 << 21 | /* separate stencil enable */ 1 << 22 | /* hiz enable */ BRW_TILEWALK_YMAJOR << 26 | 1 << 27 | /* y-tiled */ BRW_SURFACE_2D << 29); OUT_RELOC(params->depth.mt->region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, offset); OUT_BATCH(BRW_SURFACE_MIPMAPLAYOUT_BELOW << 1 | (params->depth.width + tile_x - 1) << 6 | (params->depth.height + tile_y - 1) << 19); OUT_BATCH(0); OUT_BATCH(tile_x | tile_y << 16); OUT_BATCH(0); ADVANCE_BATCH(); } /* 3DSTATE_HIER_DEPTH_BUFFER */ { struct intel_region *hiz_region = params->depth.mt->hiz_mt->region; uint32_t hiz_offset = intel_region_get_aligned_offset(hiz_region, draw_x & ~tile_mask_x, (draw_y & ~tile_mask_y) / 2, false); BEGIN_BATCH(3); OUT_BATCH((_3DSTATE_HIER_DEPTH_BUFFER << 16) | (3 - 2)); OUT_BATCH(hiz_region->pitch - 1); OUT_RELOC(hiz_region->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, hiz_offset); ADVANCE_BATCH(); } /* 3DSTATE_STENCIL_BUFFER */ { BEGIN_BATCH(3); OUT_BATCH((_3DSTATE_STENCIL_BUFFER << 16) | (3 - 2)); OUT_BATCH(0); OUT_BATCH(0); ADVANCE_BATCH(); } }
void brw_workaround_depthstencil_alignment(struct brw_context *brw, GLbitfield clear_mask) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *fb = ctx->DrawBuffer; bool rebase_depth = false; bool rebase_stencil = false; struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_renderbuffer *stencil_irb = intel_get_renderbuffer(fb, BUFFER_STENCIL); struct intel_mipmap_tree *depth_mt = NULL; struct intel_mipmap_tree *stencil_mt = get_stencil_miptree(stencil_irb); uint32_t tile_x = 0, tile_y = 0, stencil_tile_x = 0, stencil_tile_y = 0; uint32_t stencil_draw_x = 0, stencil_draw_y = 0; bool invalidate_depth = clear_mask & BUFFER_BIT_DEPTH; bool invalidate_stencil = clear_mask & BUFFER_BIT_STENCIL; if (depth_irb) depth_mt = depth_irb->mt; /* Initialize brw->depthstencil to 'nop' workaround state. */ brw->depthstencil.tile_x = 0; brw->depthstencil.tile_y = 0; brw->depthstencil.depth_offset = 0; brw->depthstencil.stencil_offset = 0; brw->depthstencil.hiz_offset = 0; brw->depthstencil.depth_mt = NULL; brw->depthstencil.stencil_mt = NULL; if (depth_irb) brw->depthstencil.depth_mt = depth_mt; if (stencil_irb) brw->depthstencil.stencil_mt = get_stencil_miptree(stencil_irb); /* Gen7+ doesn't require the workarounds, since we always program the * surface state at the start of the whole surface. */ if (brw->gen >= 7) return; /* Check if depth buffer is in depth/stencil format. If so, then it's only * safe to invalidate it if we're also clearing stencil, and both depth_irb * and stencil_irb point to the same miptree. * * Note: it's not sufficient to check for the case where * _mesa_get_format_base_format(depth_mt->format) == GL_DEPTH_STENCIL, * because this fails to catch depth/stencil buffers on hardware that uses * separate stencil. To catch that case, we check whether * depth_mt->stencil_mt is non-NULL. */ if (depth_irb && invalidate_depth && (_mesa_get_format_base_format(depth_mt->format) == GL_DEPTH_STENCIL || depth_mt->stencil_mt)) { invalidate_depth = invalidate_stencil && depth_irb && stencil_irb && depth_irb->mt == stencil_irb->mt; } uint32_t tile_mask_x, tile_mask_y; brw_get_depthstencil_tile_masks(depth_mt, depth_mt ? depth_irb->mt_level : 0, depth_mt ? depth_irb->mt_layer : 0, stencil_mt, &tile_mask_x, &tile_mask_y); if (depth_irb) { tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; /* According to the Sandy Bridge PRM, volume 2 part 1, pp326-327 * (3DSTATE_DEPTH_BUFFER dw5), in the documentation for "Depth * Coordinate Offset X/Y": * * "The 3 LSBs of both offsets must be zero to ensure correct * alignment" */ if (tile_x & 7 || tile_y & 7) rebase_depth = true; /* We didn't even have intra-tile offsets before g45. */ if (!brw->has_surface_tile_offset) { if (tile_x || tile_y) rebase_depth = true; } if (rebase_depth) { perf_debug("HW workaround: blitting depth level %d to a temporary " "to fix alignment (depth tile offset %d,%d)\n", depth_irb->mt_level, tile_x, tile_y); intel_renderbuffer_move_to_temp(brw, depth_irb, invalidate_depth); /* In the case of stencil_irb being the same packed depth/stencil * texture but not the same rb, make it point at our rebased mt, too. */ if (stencil_irb && stencil_irb != depth_irb && stencil_irb->mt == depth_mt) { intel_miptree_reference(&stencil_irb->mt, depth_irb->mt); intel_renderbuffer_set_draw_offset(stencil_irb); } stencil_mt = get_stencil_miptree(stencil_irb); tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; } if (stencil_irb) { stencil_mt = get_stencil_miptree(stencil_irb); intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); int stencil_tile_x = stencil_draw_x & tile_mask_x; int stencil_tile_y = stencil_draw_y & tile_mask_y; /* If stencil doesn't match depth, then we'll need to rebase stencil * as well. (if we hadn't decided to rebase stencil before, the * post-stencil depth test will also rebase depth to try to match it * up). */ if (tile_x != stencil_tile_x || tile_y != stencil_tile_y) { rebase_stencil = true; } } } /* If we have (just) stencil, check it for ignored low bits as well */ if (stencil_irb) { intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); stencil_tile_x = stencil_draw_x & tile_mask_x; stencil_tile_y = stencil_draw_y & tile_mask_y; if (stencil_tile_x & 7 || stencil_tile_y & 7) rebase_stencil = true; if (!brw->has_surface_tile_offset) { if (stencil_tile_x || stencil_tile_y) rebase_stencil = true; } } if (rebase_stencil) { perf_debug("HW workaround: blitting stencil level %d to a temporary " "to fix alignment (stencil tile offset %d,%d)\n", stencil_irb->mt_level, stencil_tile_x, stencil_tile_y); intel_renderbuffer_move_to_temp(brw, stencil_irb, invalidate_stencil); stencil_mt = get_stencil_miptree(stencil_irb); intel_miptree_get_image_offset(stencil_mt, stencil_irb->mt_level, stencil_irb->mt_layer, &stencil_draw_x, &stencil_draw_y); stencil_tile_x = stencil_draw_x & tile_mask_x; stencil_tile_y = stencil_draw_y & tile_mask_y; if (depth_irb && depth_irb->mt == stencil_irb->mt) { intel_miptree_reference(&depth_irb->mt, stencil_irb->mt); intel_renderbuffer_set_draw_offset(depth_irb); } else if (depth_irb && !rebase_depth) { if (tile_x != stencil_tile_x || tile_y != stencil_tile_y) { perf_debug("HW workaround: blitting depth level %d to a temporary " "to match stencil level %d alignment (depth tile offset " "%d,%d, stencil offset %d,%d)\n", depth_irb->mt_level, stencil_irb->mt_level, tile_x, tile_y, stencil_tile_x, stencil_tile_y); intel_renderbuffer_move_to_temp(brw, depth_irb, invalidate_depth); tile_x = depth_irb->draw_x & tile_mask_x; tile_y = depth_irb->draw_y & tile_mask_y; if (stencil_irb && stencil_irb->mt == depth_mt) { intel_miptree_reference(&stencil_irb->mt, depth_irb->mt); intel_renderbuffer_set_draw_offset(stencil_irb); } WARN_ONCE(stencil_tile_x != tile_x || stencil_tile_y != tile_y, "Rebased stencil tile offset (%d,%d) doesn't match depth " "tile offset (%d,%d).\n", stencil_tile_x, stencil_tile_y, tile_x, tile_y); } } } if (!depth_irb) { tile_x = stencil_tile_x; tile_y = stencil_tile_y; } /* While we just tried to get everything aligned, we may have failed to do * so in the case of rendering to array or 3D textures, where nonzero faces * will still have an offset post-rebase. At least give an informative * warning. */ WARN_ONCE((tile_x & 7) || (tile_y & 7), "Depth/stencil buffer needs alignment to 8-pixel boundaries.\n" "Truncating offset, bad rendering may occur.\n"); tile_x &= ~7; tile_y &= ~7; /* Now, after rebasing, save off the new dephtstencil state so the hardware * packets can just dereference that without re-calculating tile offsets. */ brw->depthstencil.tile_x = tile_x; brw->depthstencil.tile_y = tile_y; if (depth_irb) { depth_mt = depth_irb->mt; brw->depthstencil.depth_mt = depth_mt; brw->depthstencil.depth_offset = intel_region_get_aligned_offset(depth_mt->region, depth_irb->draw_x & ~tile_mask_x, depth_irb->draw_y & ~tile_mask_y, false); if (intel_renderbuffer_has_hiz(depth_irb)) { brw->depthstencil.hiz_offset = intel_region_get_aligned_offset(depth_mt->region, depth_irb->draw_x & ~tile_mask_x, (depth_irb->draw_y & ~tile_mask_y) / 2, false); } } if (stencil_irb) { stencil_mt = get_stencil_miptree(stencil_irb); brw->depthstencil.stencil_mt = stencil_mt; if (stencil_mt->format == MESA_FORMAT_S_UINT8) { /* Note: we can't compute the stencil offset using * intel_region_get_aligned_offset(), because stencil_region claims * that the region is untiled even though it's W tiled. */ brw->depthstencil.stencil_offset = (stencil_draw_y & ~tile_mask_y) * stencil_mt->region->pitch + (stencil_draw_x & ~tile_mask_x) * 64; } } }