summaryrefslogtreecommitdiffstats
path: root/src/mesa/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers')
-rw-r--r--src/mesa/drivers/dri/i965/brw_misc_state.c96
-rw-r--r--src/mesa/drivers/dri/i965/gen6_hiz.c54
-rw-r--r--src/mesa/drivers/dri/i965/gen7_hiz.c54
-rw-r--r--src/mesa/drivers/dri/i965/gen7_misc_state.c79
-rw-r--r--src/mesa/drivers/dri/intel/intel_fbo.c27
-rw-r--r--src/mesa/drivers/dri/intel/intel_fbo.h5
-rw-r--r--src/mesa/drivers/dri/intel/intel_regions.c56
-rw-r--r--src/mesa/drivers/dri/intel/intel_regions.h8
8 files changed, 319 insertions, 60 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c
index 51ea03b6a3f..7a0f5a31ac0 100644
--- a/src/mesa/drivers/dri/i965/brw_misc_state.c
+++ b/src/mesa/drivers/dri/i965/brw_misc_state.c
@@ -266,10 +266,45 @@ static void emit_depthbuffer(struct brw_context *brw)
unsigned int len;
bool separate_stencil = false;
+ /* Amount by which drawing should be offset in order to draw to the
+ * appropriate miplevel/zoffset/cubeface. We will extract these values
+ * from depth_irb or stencil_irb once we determine which is present.
+ */
+ uint32_t draw_x = 0, draw_y = 0;
+
+ /* Masks used to determine how much of the draw_x and draw_y offsets should
+ * be performed using the fine adjustment of "depth coordinate offset X/Y"
+ * (dw5 of 3DSTATE_DEPTH_BUFFER). Any remaining coarse adjustment will be
+ * performed by changing the base addresses of the buffers.
+ *
+ * Since the HiZ, depth, and stencil buffers all use the same "depth
+ * coordinate offset X/Y" values, we need to make sure that the coarse
+ * adjustment will be possible to apply to all three buffers. Since coarse
+ * adjustment can only be applied in multiples of the tile size, we will OR
+ * together the tile masks of all the buffers to determine which offsets to
+ * perform as fine adjustments.
+ */
+ uint32_t tile_mask_x = 0, tile_mask_y = 0;
+
+ if (depth_irb) {
+ intel_region_get_tile_masks(depth_irb->mt->region,
+ &tile_mask_x, &tile_mask_y);
+ }
+
if (depth_irb &&
depth_irb->mt &&
depth_irb->mt->hiz_mt) {
hiz_region = depth_irb->mt->hiz_mt->region;
+
+ uint32_t hiz_tile_mask_x, hiz_tile_mask_y;
+ intel_region_get_tile_masks(hiz_region,
+ &hiz_tile_mask_x, &hiz_tile_mask_y);
+
+ /* Each HiZ row represents 2 rows of pixels */
+ hiz_tile_mask_y = hiz_tile_mask_y << 1 | 1;
+
+ tile_mask_x |= hiz_tile_mask_x;
+ tile_mask_y |= hiz_tile_mask_y;
}
/* 3DSTATE_DEPTH_BUFFER, 3DSTATE_STENCIL_BUFFER are both
@@ -286,8 +321,21 @@ static void emit_depthbuffer(struct brw_context *brw)
if (stencil_mt->stencil_mt)
stencil_mt = stencil_mt->stencil_mt;
- if (stencil_mt->format == MESA_FORMAT_S8)
+ if (stencil_mt->format == MESA_FORMAT_S8) {
separate_stencil = true;
+
+ /* Separate stencil buffer uses 64x64 tiles. */
+ tile_mask_x |= 63;
+ tile_mask_y |= 63;
+ } else {
+ uint32_t stencil_tile_mask_x, stencil_tile_mask_y;
+ intel_region_get_tile_masks(stencil_mt->region,
+ &stencil_tile_mask_x,
+ &stencil_tile_mask_y);
+
+ tile_mask_x |= stencil_tile_mask_x;
+ tile_mask_y |= stencil_tile_mask_y;
+ }
}
/* If there's a packed depth/stencil bound to stencil only, we need to
@@ -321,6 +369,8 @@ static void emit_depthbuffer(struct brw_context *brw)
ADVANCE_BATCH();
} else if (!depth_irb && separate_stencil) {
+ uint32_t tile_x, tile_y;
+
/*
* There exists a separate stencil buffer but no depth buffer.
*
@@ -343,6 +393,11 @@ static void emit_depthbuffer(struct brw_context *brw)
*/
assert(intel->has_separate_stencil);
+ draw_x = stencil_irb->draw_x;
+ draw_y = stencil_irb->draw_y;
+ tile_x = draw_x & tile_mask_x;
+ tile_y = draw_y & tile_mask_y;
+
BEGIN_BATCH(len);
OUT_BATCH(_3DSTATE_DEPTH_BUFFER << 16 | (len - 2));
OUT_BATCH((BRW_DEPTHFORMAT_D32_FLOAT << 18) |
@@ -352,11 +407,15 @@ static void emit_depthbuffer(struct brw_context *brw)
(1 << 27) | /* tiled surface */
(BRW_SURFACE_2D << 29));
OUT_BATCH(0);
- OUT_BATCH(((stencil_irb->Base.Base.Width - 1) << 6) |
- (stencil_irb->Base.Base.Height - 1) << 19);
- OUT_BATCH(0);
+ OUT_BATCH(((stencil_irb->Base.Base.Width + tile_x - 1) << 6) |
+ (stencil_irb->Base.Base.Height + tile_y - 1) << 19);
OUT_BATCH(0);
+ if (intel->is_g4x || intel->gen >= 5)
+ OUT_BATCH(tile_x | (tile_y << 16));
+ else
+ assert(tile_x == 0 && tile_y == 0);
+
if (intel->gen >= 6)
OUT_BATCH(0);
@@ -369,11 +428,18 @@ static void emit_depthbuffer(struct brw_context *brw)
/* If using separate stencil, hiz must be enabled. */
assert(!separate_stencil || hiz_region);
- offset = intel_renderbuffer_tile_offsets(depth_irb, &tile_x, &tile_y);
-
assert(intel->gen < 6 || region->tiling == I915_TILING_Y);
assert(!hiz_region || region->tiling == I915_TILING_Y);
+ draw_x = depth_irb->draw_x;
+ draw_y = depth_irb->draw_y;
+ tile_x = draw_x & tile_mask_x;
+ tile_y = draw_y & tile_mask_y;
+
+ offset = intel_region_get_aligned_offset(region,
+ draw_x & ~tile_mask_x,
+ draw_y & ~tile_mask_y);
+
BEGIN_BATCH(len);
OUT_BATCH(_3DSTATE_DEPTH_BUFFER << 16 | (len - 2));
OUT_BATCH(((region->pitch * region->cpp) - 1) |
@@ -413,12 +479,17 @@ static void emit_depthbuffer(struct brw_context *brw)
/* Emit hiz buffer. */
if (hiz_region) {
+ uint32_t hiz_offset =
+ intel_region_get_aligned_offset(hiz_region,
+ draw_x & ~tile_mask_x,
+ (draw_y & ~tile_mask_y) / 2);
+
BEGIN_BATCH(3);
OUT_BATCH((_3DSTATE_HIER_DEPTH_BUFFER << 16) | (3 - 2));
OUT_BATCH(hiz_region->pitch * hiz_region->cpp - 1);
OUT_RELOC(hiz_region->bo,
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
- 0);
+ hiz_offset);
ADVANCE_BATCH();
} else {
BEGIN_BATCH(3);
@@ -431,6 +502,15 @@ static void emit_depthbuffer(struct brw_context *brw)
/* Emit stencil buffer. */
if (separate_stencil) {
struct intel_region *region = stencil_mt->region;
+
+ /* Note: we can't compute the stencil offset using
+ * intel_region_get_aligned_offset(), because stencil_region claims
+ * that the region is untiled; in fact it's W tiled.
+ */
+ uint32_t stencil_offset =
+ (draw_y & ~tile_mask_y) * region->pitch +
+ (draw_x & ~tile_mask_x) * 64;
+
BEGIN_BATCH(3);
OUT_BATCH((_3DSTATE_STENCIL_BUFFER << 16) | (3 - 2));
/* The stencil buffer has quirky pitch requirements. From Vol 2a,
@@ -441,7 +521,7 @@ static void emit_depthbuffer(struct brw_context *brw)
OUT_BATCH(2 * region->pitch * region->cpp - 1);
OUT_RELOC(region->bo,
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
- 0);
+ stencil_offset);
ADVANCE_BATCH();
} else {
BEGIN_BATCH(3);
diff --git a/src/mesa/drivers/dri/i965/gen6_hiz.c b/src/mesa/drivers/dri/i965/gen6_hiz.c
index 9837b1fc54d..d9b547c3964 100644
--- a/src/mesa/drivers/dri/i965/gen6_hiz.c
+++ b/src/mesa/drivers/dri/i965/gen6_hiz.c
@@ -261,11 +261,42 @@ gen6_hiz_exec(struct intel_context *intel,
{
struct gl_context *ctx = &intel->ctx;
struct brw_context *brw = brw_context(ctx);
+ uint32_t draw_x, draw_y;
+ uint32_t tile_mask_x, tile_mask_y;
assert(op != GEN6_HIZ_OP_DEPTH_CLEAR); /* Not implemented yet. */
assert(mt->hiz_mt != NULL);
intel_miptree_check_level_layer(mt, level, layer);
+ {
+ /* Construct a dummy renderbuffer just to extract tile offsets. */
+ struct intel_renderbuffer rb;
+ rb.mt = mt;
+ rb.mt_level = level;
+ rb.mt_layer = layer;
+ intel_renderbuffer_set_draw_offset(&rb);
+ draw_x = rb.draw_x;
+ draw_y = rb.draw_y;
+ }
+
+ /* Compute masks to determine how much of draw_x and draw_y should be
+ * performed using the fine adjustment of "depth coordinate offset X/Y"
+ * (dw5 of 3DSTATE_DEPTH_BUFFER). See the emit_depthbuffer() function for
+ * details.
+ */
+ {
+ uint32_t depth_mask_x, depth_mask_y, hiz_mask_x, hiz_mask_y;
+ intel_region_get_tile_masks(mt->region, &depth_mask_x, &depth_mask_y);
+ intel_region_get_tile_masks(mt->hiz_mt->region,
+ &hiz_mask_x, &hiz_mask_y);
+
+ /* Each HiZ row represents 2 rows of pixels */
+ hiz_mask_y = hiz_mask_y << 1 | 1;
+
+ tile_mask_x = depth_mask_x | hiz_mask_x;
+ tile_mask_y = depth_mask_y | hiz_mask_y;
+ }
+
gen6_hiz_emit_batch_head(brw);
gen6_hiz_emit_vertices(brw, mt, level, layer);
@@ -450,18 +481,11 @@ gen6_hiz_exec(struct intel_context *intel,
uint32_t width = mt->level[level].width;
uint32_t height = mt->level[level].height;
- uint32_t tile_x;
- uint32_t tile_y;
- uint32_t offset;
- {
- /* Construct a dummy renderbuffer just to extract tile offsets. */
- struct intel_renderbuffer rb;
- rb.mt = mt;
- rb.mt_level = level;
- rb.mt_layer = layer;
- intel_renderbuffer_set_draw_offset(&rb);
- offset = intel_renderbuffer_tile_offsets(&rb, &tile_x, &tile_y);
- }
+ 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(mt->region,
+ draw_x & ~tile_mask_x,
+ draw_y & ~tile_mask_y);
uint32_t format;
switch (mt->format) {
@@ -499,13 +523,17 @@ gen6_hiz_exec(struct intel_context *intel,
/* 3DSTATE_HIER_DEPTH_BUFFER */
{
struct intel_region *hiz_region = 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);
BEGIN_BATCH(3);
OUT_BATCH((_3DSTATE_HIER_DEPTH_BUFFER << 16) | (3 - 2));
OUT_BATCH(hiz_region->pitch * hiz_region->cpp - 1);
OUT_RELOC(hiz_region->bo,
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
- 0);
+ hiz_offset);
ADVANCE_BATCH();
}
diff --git a/src/mesa/drivers/dri/i965/gen7_hiz.c b/src/mesa/drivers/dri/i965/gen7_hiz.c
index 18c178eb041..4538ec9f203 100644
--- a/src/mesa/drivers/dri/i965/gen7_hiz.c
+++ b/src/mesa/drivers/dri/i965/gen7_hiz.c
@@ -46,6 +46,8 @@ gen7_hiz_exec(struct intel_context *intel,
{
struct gl_context *ctx = &intel->ctx;
struct brw_context *brw = brw_context(ctx);
+ uint32_t draw_x, draw_y;
+ uint32_t tile_mask_x, tile_mask_y;
assert(op != GEN6_HIZ_OP_DEPTH_CLEAR); /* Not implemented yet. */
assert(mt->hiz_mt != NULL);
@@ -59,6 +61,35 @@ gen7_hiz_exec(struct intel_context *intel,
default: assert(0); break;
}
+ {
+ /* Construct a dummy renderbuffer just to extract tile offsets. */
+ struct intel_renderbuffer rb;
+ rb.mt = mt;
+ rb.mt_level = level;
+ rb.mt_layer = layer;
+ intel_renderbuffer_set_draw_offset(&rb);
+ draw_x = rb.draw_x;
+ draw_y = rb.draw_y;
+ }
+
+ /* Compute masks to determine how much of draw_x and draw_y should be
+ * performed using the fine adjustment of "depth coordinate offset X/Y"
+ * (dw5 of 3DSTATE_DEPTH_BUFFER). See the emit_depthbuffer() function for
+ * details.
+ */
+ {
+ uint32_t depth_mask_x, depth_mask_y, hiz_mask_x, hiz_mask_y;
+ intel_region_get_tile_masks(mt->region, &depth_mask_x, &depth_mask_y);
+ intel_region_get_tile_masks(mt->hiz_mt->region,
+ &hiz_mask_x, &hiz_mask_y);
+
+ /* Each HiZ row represents 2 rows of pixels */
+ hiz_mask_y = hiz_mask_y << 1 | 1;
+
+ tile_mask_x = depth_mask_x | hiz_mask_x;
+ tile_mask_y = depth_mask_y | hiz_mask_y;
+ }
+
gen6_hiz_emit_batch_head(brw);
gen6_hiz_emit_vertices(brw, mt, level, layer);
@@ -327,18 +358,11 @@ gen7_hiz_exec(struct intel_context *intel,
uint32_t width = mt->level[level].width;
uint32_t height = mt->level[level].height;
- uint32_t tile_x;
- uint32_t tile_y;
- uint32_t offset;
- {
- /* Construct a dummy renderbuffer just to extract tile offsets. */
- struct intel_renderbuffer rb;
- rb.mt = mt;
- rb.mt_level = level;
- rb.mt_layer = layer;
- intel_renderbuffer_set_draw_offset(&rb);
- offset = intel_renderbuffer_tile_offsets(&rb, &tile_x, &tile_y);
- }
+ 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(mt->region,
+ draw_x & ~tile_mask_x,
+ draw_y & ~tile_mask_y);
intel_emit_depth_stall_flushes(intel);
@@ -364,13 +388,17 @@ gen7_hiz_exec(struct intel_context *intel,
/* 3DSTATE_HIER_DEPTH_BUFFER */
{
struct intel_region *hiz_region = 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);
BEGIN_BATCH(3);
OUT_BATCH((GEN7_3DSTATE_HIER_DEPTH_BUFFER << 16) | (3 - 2));
OUT_BATCH(hiz_region->pitch * hiz_region->cpp - 1);
OUT_RELOC(hiz_region->bo,
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
- 0);
+ hiz_offset);
ADVANCE_BATCH();
}
diff --git a/src/mesa/drivers/dri/i965/gen7_misc_state.c b/src/mesa/drivers/dri/i965/gen7_misc_state.c
index 3a6144f2838..d9beda8f36e 100644
--- a/src/mesa/drivers/dri/i965/gen7_misc_state.c
+++ b/src/mesa/drivers/dri/i965/gen7_misc_state.c
@@ -42,18 +42,58 @@ static void emit_depthbuffer(struct brw_context *brw)
*stencil_mt = NULL,
*hiz_mt = NULL;
+ /* Amount by which drawing should be offset in order to draw to the
+ * appropriate miplevel/zoffset/cubeface. We will extract these values
+ * from depth_irb or stencil_irb once we determine which is present.
+ */
+ uint32_t draw_x = 0, draw_y = 0;
+
+ /* Masks used to determine how much of the draw_x and draw_y offsets should
+ * be performed using the fine adjustment of "depth coordinate offset X/Y"
+ * (dw5 of 3DSTATE_DEPTH_BUFFER). Any remaining coarse adjustment will be
+ * performed by changing the base addresses of the buffers.
+ *
+ * Since the HiZ, depth, and stencil buffers all use the same "depth
+ * coordinate offset X/Y" values, we need to make sure that the coarse
+ * adjustment will be possible to apply to all three buffers. Since coarse
+ * adjustment can only be applied in multiples of the tile size, we will OR
+ * together the tile masks of all the buffers to determine which offsets to
+ * perform as fine adjustments.
+ */
+ uint32_t tile_mask_x = 0, tile_mask_y = 0;
+
if (drb)
depth_mt = drb->mt;
- if (depth_mt)
+ if (depth_mt) {
hiz_mt = depth_mt->hiz_mt;
+ intel_region_get_tile_masks(depth_mt->region,
+ &tile_mask_x, &tile_mask_y);
+
+ if (hiz_mt) {
+ uint32_t hiz_tile_mask_x, hiz_tile_mask_y;
+ intel_region_get_tile_masks(hiz_mt->region,
+ &hiz_tile_mask_x, &hiz_tile_mask_y);
+
+ /* Each HiZ row represents 2 rows of pixels */
+ hiz_tile_mask_y = hiz_tile_mask_y << 1 | 1;
+
+ tile_mask_x |= hiz_tile_mask_x;
+ tile_mask_y |= hiz_tile_mask_y;
+ }
+ }
+
if (srb) {
stencil_mt = srb->mt;
if (stencil_mt->stencil_mt)
stencil_mt = stencil_mt->stencil_mt;
assert(stencil_mt->format == MESA_FORMAT_S8);
+
+ /* Stencil buffer uses 64x64 tiles. */
+ tile_mask_x |= 63;
+ tile_mask_y |= 63;
}
/* Gen7 doesn't support packed depth/stencil */
@@ -65,6 +105,7 @@ static void emit_depthbuffer(struct brw_context *brw)
if (depth_mt == NULL) {
uint32_t dw1 = BRW_DEPTHFORMAT_D32_FLOAT << 18;
uint32_t dw3 = 0;
+ uint32_t tile_x, tile_y;
if (stencil_mt == NULL) {
dw1 |= (BRW_SURFACE_NULL << 29);
@@ -72,10 +113,15 @@ static void emit_depthbuffer(struct brw_context *brw)
/* _NEW_STENCIL: enable stencil buffer writes */
dw1 |= ((ctx->Stencil.WriteMask != 0) << 27);
+ draw_x = srb->draw_x;
+ draw_y = srb->draw_y;
+ tile_x = draw_x & tile_mask_x;
+ tile_y = draw_y & tile_mask_y;
+
/* 3DSTATE_STENCIL_BUFFER inherits surface type and dimensions. */
dw1 |= (BRW_SURFACE_2D << 29);
- dw3 = ((srb->Base.Base.Width - 1) << 4) |
- ((srb->Base.Base.Height - 1) << 18);
+ dw3 = ((srb->Base.Base.Width + tile_x - 1) << 4) |
+ ((srb->Base.Base.Height + tile_y - 1) << 18);
}
BEGIN_BATCH(7);
@@ -84,14 +130,21 @@ static void emit_depthbuffer(struct brw_context *brw)
OUT_BATCH(0);
OUT_BATCH(dw3);
OUT_BATCH(0);
- OUT_BATCH(0);
+ OUT_BATCH(tile_x | (tile_y << 16));
OUT_BATCH(0);
ADVANCE_BATCH();
} else {
struct intel_region *region = depth_mt->region;
uint32_t tile_x, tile_y, offset;
- offset = intel_renderbuffer_tile_offsets(drb, &tile_x, &tile_y);
+ draw_x = drb->draw_x;
+ draw_y = drb->draw_y;
+ tile_x = draw_x & tile_mask_x;
+ tile_y = draw_y & tile_mask_y;
+
+ offset = intel_region_get_aligned_offset(region,
+ draw_x & ~tile_mask_x,
+ draw_y & ~tile_mask_y);
assert(region->tiling == I915_TILING_Y);
@@ -122,13 +175,17 @@ static void emit_depthbuffer(struct brw_context *brw)
OUT_BATCH(0);
ADVANCE_BATCH();
} else {
+ uint32_t hiz_offset =
+ intel_region_get_aligned_offset(hiz_mt->region,
+ draw_x & ~tile_mask_x,
+ (draw_y & ~tile_mask_y) / 2);
BEGIN_BATCH(3);
OUT_BATCH(GEN7_3DSTATE_HIER_DEPTH_BUFFER << 16 | (3 - 2));
OUT_BATCH(hiz_mt->region->pitch * hiz_mt->region->cpp - 1);
OUT_RELOC(hiz_mt->region->bo,
I915_GEM_DOMAIN_RENDER,
I915_GEM_DOMAIN_RENDER,
- 0);
+ hiz_offset);
ADVANCE_BATCH();
}
@@ -141,6 +198,14 @@ static void emit_depthbuffer(struct brw_context *brw)
} else {
const int enabled = intel->is_haswell ? HSW_STENCIL_ENABLED : 0;
+ /* Note: We can't compute the stencil offset using
+ * intel_region_get_aligned_offset(), because the stencil region claims
+ * that the region is untiled; in fact it's W tiled.
+ */
+ uint32_t stencil_offset =
+ (draw_y & ~tile_mask_y) * stencil_mt->region->pitch +
+ (draw_x & ~tile_mask_x) * 64;
+
BEGIN_BATCH(3);
OUT_BATCH(GEN7_3DSTATE_STENCIL_BUFFER << 16 | (3 - 2));
/* The stencil buffer has quirky pitch requirements. From the Graphics
@@ -161,7 +226,7 @@ static void emit_depthbuffer(struct brw_context *brw)
(2 * stencil_mt->region->pitch * stencil_mt->region->cpp - 1));
OUT_RELOC(stencil_mt->region->bo,
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
- 0);
+ stencil_offset);
ADVANCE_BATCH();
}
diff --git a/src/mesa/drivers/dri/intel/intel_fbo.c b/src/mesa/drivers/dri/intel/intel_fbo.c
index 5872ecec11a..2f95ad06025 100644
--- a/src/mesa/drivers/dri/intel/intel_fbo.c
+++ b/src/mesa/drivers/dri/intel/intel_fbo.c
@@ -535,25 +535,14 @@ intel_renderbuffer_tile_offsets(struct intel_renderbuffer *irb,
uint32_t *tile_y)
{
struct intel_region *region = irb->mt->region;
- int cpp = region->cpp;
- uint32_t pitch = region->pitch * cpp;
-
- if (region->tiling == I915_TILING_NONE) {
- *tile_x = 0;
- *tile_y = 0;
- return irb->draw_x * cpp + irb->draw_y * pitch;
- } else if (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(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);
- }
+ uint32_t mask_x, mask_y;
+
+ intel_region_get_tile_masks(region, &mask_x, &mask_y);
+
+ *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);
}
/**
diff --git a/src/mesa/drivers/dri/intel/intel_fbo.h b/src/mesa/drivers/dri/intel/intel_fbo.h
index 724f141535c..947944ac8e1 100644
--- a/src/mesa/drivers/dri/intel/intel_fbo.h
+++ b/src/mesa/drivers/dri/intel/intel_fbo.h
@@ -153,6 +153,11 @@ intel_flip_renderbuffers(struct gl_framebuffer *fb);
void
intel_renderbuffer_set_draw_offset(struct intel_renderbuffer *irb);
+void
+intel_renderbuffer_fine_offset_masks(struct intel_renderbuffer *irb,
+ uint32_t *fine_offset_mask_x,
+ uint32_t *fine_offset_mask_y);
+
uint32_t
intel_renderbuffer_tile_offsets(struct intel_renderbuffer *irb,
uint32_t *tile_x,
diff --git a/src/mesa/drivers/dri/intel/intel_regions.c b/src/mesa/drivers/dri/intel/intel_regions.c
index abea2bd0f71..1ef1ac663c5 100644
--- a/src/mesa/drivers/dri/intel/intel_regions.c
+++ b/src/mesa/drivers/dri/intel/intel_regions.c
@@ -390,3 +390,59 @@ intel_region_copy(struct intel_context *intel,
srcx, srcy, dstx, dsty, width, height,
logicop);
}
+
+/**
+ * This function computes masks that may be used to select the bits of the X
+ * and Y coordinates that indicate the offset within a tile. If the region is
+ * untiled, the masks are set to 0.
+ */
+void
+intel_region_get_tile_masks(struct intel_region *region,
+ uint32_t *mask_x, uint32_t *mask_y)
+{
+ int cpp = region->cpp;
+
+ switch (region->tiling) {
+ default:
+ assert(false);
+ case I915_TILING_NONE:
+ *mask_x = *mask_y = 0;
+ break;
+ case I915_TILING_X:
+ *mask_x = 512 / cpp - 1;
+ *mask_y = 7;
+ break;
+ case I915_TILING_Y:
+ *mask_x = 128 / cpp - 1;
+ *mask_y = 31;
+ break;
+ }
+}
+
+/**
+ * Compute the offset (in bytes) from the start of the region to the given x
+ * and y coordinate. For tiled regions, caller must ensure that x and y are
+ * multiples of the tile size.
+ */
+uint32_t
+intel_region_get_aligned_offset(struct intel_region *region, uint32_t x,
+ uint32_t y)
+{
+ int cpp = region->cpp;
+ uint32_t pitch = region->pitch * cpp;
+
+ switch (region->tiling) {
+ default:
+ assert(false);
+ case I915_TILING_NONE:
+ return y * pitch + x * cpp;
+ case I915_TILING_X:
+ assert((x % (512 / cpp)) == 0);
+ assert((y % 8) == 0);
+ return y * pitch + x / (512 / cpp) * 4096;
+ case I915_TILING_Y:
+ assert((x % (128 / cpp)) == 0);
+ assert((y % 32) == 0);
+ return y * pitch + x / (128 / cpp) * 4096;
+ }
+}
diff --git a/src/mesa/drivers/dri/intel/intel_regions.h b/src/mesa/drivers/dri/intel/intel_regions.h
index af3a059560a..0a05d79882a 100644
--- a/src/mesa/drivers/dri/intel/intel_regions.h
+++ b/src/mesa/drivers/dri/intel/intel_regions.h
@@ -129,6 +129,14 @@ void _mesa_copy_rect(GLubyte * dst,
const GLubyte * src,
GLuint src_pitch, GLuint src_x, GLuint src_y);
+void
+intel_region_get_tile_masks(struct intel_region *region,
+ uint32_t *mask_x, uint32_t *mask_y);
+
+uint32_t
+intel_region_get_aligned_offset(struct intel_region *region, uint32_t x,
+ uint32_t y);
+
struct __DRIimageRec {
struct intel_region *region;
GLenum internal_format;