intel: fix meta for compressed array images
The uncompressed format that we cast to has a different layout when array size
is greater than 1. We have to treat the array size as 1, and set up Surface
Base Address and X/Y offsets to point to the destination layer manually.
v2: Divide X/Y offsets by block width/height. There should still be corner
cases and we need more testcases.
diff --git a/icd/intel/cmd_meta.c b/icd/intel/cmd_meta.c
index d21756e..ad037fc 100644
--- a/icd/intel/cmd_meta.c
+++ b/icd/intel/cmd_meta.c
@@ -152,31 +152,62 @@
const struct intel_img *img,
struct intel_cmd_meta *meta)
{
- XGL_INT w, h;
+ XGL_INT w, h, layer;
+ unsigned x_offset, y_offset;
if (cmd_gen(cmd) >= INTEL_GEN(7)) {
w = GEN_EXTRACT(meta->dst.surface[2], GEN7_SURFACE_DW2_WIDTH);
h = GEN_EXTRACT(meta->dst.surface[2], GEN7_SURFACE_DW2_HEIGHT);
- meta->dst.surface[2] &= ~(GEN7_SURFACE_DW2_WIDTH__MASK |
- GEN7_SURFACE_DW2_HEIGHT__MASK);
+ layer = GEN_EXTRACT(meta->dst.surface[4],
+ GEN7_SURFACE_DW4_MIN_ARRAY_ELEMENT);
} else {
w = GEN_EXTRACT(meta->dst.surface[2], GEN6_SURFACE_DW2_WIDTH);
h = GEN_EXTRACT(meta->dst.surface[2], GEN6_SURFACE_DW2_HEIGHT);
- meta->dst.surface[2] &= ~(GEN6_SURFACE_DW2_WIDTH__MASK |
- GEN6_SURFACE_DW2_HEIGHT__MASK);
+ layer = GEN_EXTRACT(meta->dst.surface[4],
+ GEN6_SURFACE_DW4_MIN_ARRAY_ELEMENT);
}
/* note that the width/height fields have the real values minus 1 */
w = (w + img->layout.block_width) / img->layout.block_width - 1;
h = (h + img->layout.block_height) / img->layout.block_height - 1;
+ /* adjust width and height */
if (cmd_gen(cmd) >= INTEL_GEN(7)) {
+ meta->dst.surface[2] &= ~(GEN7_SURFACE_DW2_WIDTH__MASK |
+ GEN7_SURFACE_DW2_HEIGHT__MASK);
meta->dst.surface[2] |= GEN_SHIFT32(w, GEN7_SURFACE_DW2_WIDTH) |
GEN_SHIFT32(h, GEN7_SURFACE_DW2_HEIGHT);
} else {
+ meta->dst.surface[2] &= ~(GEN6_SURFACE_DW2_WIDTH__MASK |
+ GEN6_SURFACE_DW2_HEIGHT__MASK);
meta->dst.surface[2] |= GEN_SHIFT32(w, GEN6_SURFACE_DW2_WIDTH) |
GEN_SHIFT32(h, GEN6_SURFACE_DW2_HEIGHT);
}
+
+ if (!layer)
+ return;
+
+ meta->dst.reloc_offset = intel_layout_get_slice_tile_offset(&img->layout,
+ 0, layer, &x_offset, &y_offset);
+
+ /*
+ * The lower 2 bits (or 1 bit for Y) are missing. This may be a problem
+ * for small images (16x16 or smaller). We will need to adjust the
+ * drawing rectangle instead.
+ */
+ x_offset = (x_offset / img->layout.block_width) >> 2;
+ y_offset = (y_offset / img->layout.block_height) >> 1;
+
+ /* adjust min array element and X/Y offsets */
+ if (cmd_gen(cmd) >= INTEL_GEN(7)) {
+ meta->dst.surface[4] &= ~GEN7_SURFACE_DW4_MIN_ARRAY_ELEMENT__MASK;
+ meta->dst.surface[5] |= GEN_SHIFT32(x_offset, GEN7_SURFACE_DW5_X_OFFSET) |
+ GEN_SHIFT32(y_offset, GEN7_SURFACE_DW5_Y_OFFSET);
+ } else {
+ meta->dst.surface[4] &= ~GEN6_SURFACE_DW4_MIN_ARRAY_ELEMENT__MASK;
+ meta->dst.surface[5] |= GEN_SHIFT32(x_offset, GEN6_SURFACE_DW5_X_OFFSET) |
+ GEN_SHIFT32(y_offset, GEN6_SURFACE_DW5_Y_OFFSET);
+ }
}
static void cmd_meta_set_dst_for_img(struct intel_cmd *cmd,