By just using offsets, we confused the hardware's tiling calculations, resulting in failures in miptree validation and blit clears. Fixes piglit fbo-clearmipmap. Bug #23552. (automatic mipmap generation)tags/mesa_7_6_1_rc1
@@ -86,10 +86,10 @@ GLboolean brw_miptree_layout(struct intel_context *intel, | |||
mt->pitch = intel_miptree_pitch_align(intel, mt, tiling, mt->pitch); | |||
if (mt->compressed) { | |||
qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4 * mt->pitch * mt->cpp; | |||
qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4; | |||
mt->total_height = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) / 4 * 6; | |||
} else { | |||
qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) * mt->pitch * mt->cpp; | |||
qpitch = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h); | |||
mt->total_height = (y_pitch + ALIGN(minify(y_pitch), align_h) + 11 * align_h) * 6; | |||
} | |||
@@ -102,7 +102,8 @@ GLboolean brw_miptree_layout(struct intel_context *intel, | |||
height, 1); | |||
for (q = 0; q < nr_images; q++) | |||
intel_miptree_set_image_offset_ex(mt, level, q, x, y, q * qpitch); | |||
intel_miptree_set_image_offset(mt, level, q, | |||
x, y + q * qpitch); | |||
if (mt->compressed) | |||
img_height = MAX2(1, height/4); |
@@ -441,6 +441,10 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask) | |||
intel_region_buffer(intel, irb->region, | |||
all ? INTEL_WRITE_FULL : | |||
INTEL_WRITE_PART); | |||
int x1 = b.x1 + irb->region->draw_x; | |||
int y1 = b.y1 + irb->region->draw_y; | |||
int x2 = b.x2 + irb->region->draw_x; | |||
int y2 = b.y2 + irb->region->draw_y; | |||
GLuint clearVal; | |||
GLint pitch, cpp; | |||
@@ -449,11 +453,10 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask) | |||
pitch = irb->region->pitch; | |||
cpp = irb->region->cpp; | |||
DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", | |||
DBG("%s dst:buf(%p)/%d %d,%d sz:%dx%d\n", | |||
__FUNCTION__, | |||
irb->region->buffer, (pitch * cpp), | |||
irb->region->draw_offset, | |||
b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1); | |||
x1, y1, x2 - x1, y2 - y1); | |||
BR13 = 0xf0 << 16; | |||
CMD = XY_COLOR_BLT_CMD; | |||
@@ -526,17 +529,17 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask) | |||
buf, irb->Base.Name); | |||
*/ | |||
assert(b.x1 < b.x2); | |||
assert(b.y1 < b.y2); | |||
assert(x1 < x2); | |||
assert(y1 < y2); | |||
BEGIN_BATCH(6, REFERENCES_CLIPRECTS); | |||
OUT_BATCH(CMD); | |||
OUT_BATCH(BR13); | |||
OUT_BATCH((b.y1 << 16) | b.x1); | |||
OUT_BATCH((b.y2 << 16) | b.x2); | |||
OUT_BATCH((y1 << 16) | x1); | |||
OUT_BATCH((y2 << 16) | x2); | |||
OUT_RELOC(write_buffer, | |||
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, | |||
irb->region->draw_offset); | |||
0); | |||
OUT_BATCH(clearVal); | |||
ADVANCE_BATCH(); | |||
clearMask &= ~bufBit; /* turn off bit, for faster loop exit */ |
@@ -571,7 +571,7 @@ intel_render_texture(GLcontext * ctx, | |||
= att->Texture->Image[att->CubeMapFace][att->TextureLevel]; | |||
struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); | |||
struct intel_texture_image *intel_image; | |||
GLuint imageOffset; | |||
GLuint dst_x, dst_y; | |||
(void) fb; | |||
@@ -618,18 +618,16 @@ intel_render_texture(GLcontext * ctx, | |||
} | |||
/* compute offset of the particular 2D image within the texture region */ | |||
imageOffset = intel_miptree_image_offset(intel_image->mt, | |||
att->CubeMapFace, | |||
att->TextureLevel); | |||
if (att->Texture->Target == GL_TEXTURE_3D) { | |||
const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt, | |||
att->TextureLevel); | |||
imageOffset += offsets[att->Zoffset]; | |||
} | |||
/* store that offset in the region */ | |||
intel_image->mt->region->draw_offset = imageOffset; | |||
intel_miptree_get_image_offset(intel_image->mt, | |||
att->TextureLevel, | |||
att->CubeMapFace, | |||
att->Zoffset, | |||
&dst_x, &dst_y); | |||
intel_image->mt->region->draw_offset = (dst_y * intel_image->mt->pitch + | |||
dst_x) * intel_image->mt->cpp; | |||
intel_image->mt->region->draw_x = dst_x; | |||
intel_image->mt->region->draw_y = dst_y; | |||
/* update drawing region, etc */ | |||
intel_draw_buffer(ctx, fb); |
@@ -287,9 +287,10 @@ intel_miptree_release(struct intel_context *intel, | |||
intel_region_release(&((*mt)->region)); | |||
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) | |||
if ((*mt)->level[i].image_offset) | |||
free((*mt)->level[i].image_offset); | |||
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { | |||
free((*mt)->level[i].x_offset); | |||
free((*mt)->level[i].y_offset); | |||
} | |||
free(*mt); | |||
} | |||
@@ -350,82 +351,58 @@ intel_miptree_set_level_info(struct intel_mipmap_tree *mt, | |||
mt->level[level].height = h; | |||
mt->level[level].depth = d; | |||
mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp; | |||
mt->level[level].level_x = x; | |||
mt->level[level].level_y = y; | |||
mt->level[level].nr_images = nr_images; | |||
DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, | |||
level, w, h, d, x, y, mt->level[level].level_offset); | |||
/* Not sure when this would happen, but anyway: | |||
*/ | |||
if (mt->level[level].image_offset) { | |||
free(mt->level[level].image_offset); | |||
mt->level[level].image_offset = NULL; | |||
} | |||
assert(nr_images); | |||
assert(!mt->level[level].x_offset); | |||
mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint)); | |||
mt->level[level].image_offset[0] = 0; | |||
mt->level[level].x_offset = malloc(nr_images * sizeof(GLuint)); | |||
mt->level[level].x_offset[0] = mt->level[level].level_x; | |||
mt->level[level].y_offset = malloc(nr_images * sizeof(GLuint)); | |||
mt->level[level].y_offset[0] = mt->level[level].level_y; | |||
} | |||
void | |||
intel_miptree_set_image_offset_ex(struct intel_mipmap_tree *mt, | |||
GLuint level, GLuint img, | |||
GLuint x, GLuint y, | |||
GLuint offset) | |||
intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint level, GLuint img, | |||
GLuint x, GLuint y) | |||
{ | |||
if (img == 0 && level == 0) | |||
assert(x == 0 && y == 0); | |||
assert(img < mt->level[level].nr_images); | |||
mt->level[level].image_offset[img] = (x + y * mt->pitch) * mt->cpp + offset; | |||
mt->level[level].x_offset[img] = mt->level[level].level_x + x; | |||
mt->level[level].y_offset[img] = mt->level[level].level_y + y; | |||
DBG("%s level %d img %d pos %d,%d image_offset %x\n", | |||
__FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]); | |||
DBG("%s level %d img %d pos %d,%d\n", | |||
__FUNCTION__, level, img, | |||
mt->level[level].x_offset[img], mt->level[level].y_offset[img]); | |||
} | |||
void | |||
intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint level, GLuint img, | |||
GLuint x, GLuint y) | |||
{ | |||
intel_miptree_set_image_offset_ex(mt, level, img, x, y, 0); | |||
} | |||
/* Although we use the image_offset[] array to store relative offsets | |||
* to cube faces, Mesa doesn't know anything about this and expects | |||
* each cube face to be treated as a separate image. | |||
* | |||
* These functions present that view to mesa: | |||
*/ | |||
const GLuint * | |||
intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level) | |||
{ | |||
static const GLuint zero = 0; | |||
if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1) | |||
return &zero; | |||
else | |||
return mt->level[level].image_offset; | |||
} | |||
GLuint | |||
intel_miptree_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint face, GLuint level) | |||
intel_miptree_get_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint level, GLuint face, GLuint depth, | |||
GLuint *x, GLuint *y) | |||
{ | |||
if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) | |||
return (mt->level[level].level_offset + | |||
mt->level[level].image_offset[face]); | |||
else | |||
return mt->level[level].level_offset; | |||
if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) { | |||
*x = mt->level[level].x_offset[face]; | |||
*y = mt->level[level].y_offset[face]; | |||
} else if (mt->target == GL_TEXTURE_3D) { | |||
*x = mt->level[level].x_offset[depth]; | |||
*y = mt->level[level].y_offset[depth]; | |||
} else { | |||
*x = mt->level[level].x_offset[0]; | |||
*y = mt->level[level].y_offset[0]; | |||
} | |||
} | |||
/** | |||
* Map a teximage in a mipmap tree. | |||
* \param row_stride returns row stride in bytes | |||
@@ -441,6 +418,7 @@ intel_miptree_image_map(struct intel_context * intel, | |||
GLuint level, | |||
GLuint * row_stride, GLuint * image_offsets) | |||
{ | |||
GLuint x, y; | |||
DBG("%s \n", __FUNCTION__); | |||
if (row_stride) | |||
@@ -449,17 +427,23 @@ intel_miptree_image_map(struct intel_context * intel, | |||
if (mt->target == GL_TEXTURE_3D) { | |||
int i; | |||
for (i = 0; i < mt->level[level].depth; i++) | |||
image_offsets[i] = mt->level[level].image_offset[i] / mt->cpp; | |||
for (i = 0; i < mt->level[level].depth; i++) { | |||
intel_miptree_get_image_offset(mt, level, face, i, | |||
&x, &y); | |||
image_offsets[i] = x + y * mt->pitch; | |||
} | |||
return intel_region_map(intel, mt->region); | |||
} else { | |||
assert(mt->level[level].depth == 1); | |||
assert(mt->target == GL_TEXTURE_CUBE_MAP || | |||
mt->level[level].image_offset[0] == 0); | |||
intel_miptree_get_image_offset(mt, level, face, 0, | |||
&x, &y); | |||
image_offsets[0] = 0; | |||
} | |||
return (intel_region_map(intel, mt->region) + | |||
intel_miptree_image_offset(mt, face, level)); | |||
return intel_region_map(intel, mt->region) + | |||
(x + y * mt->pitch) * mt->cpp; | |||
} | |||
} | |||
void | |||
@@ -484,20 +468,19 @@ intel_miptree_image_data(struct intel_context *intel, | |||
GLuint src_image_pitch) | |||
{ | |||
GLuint depth = dst->level[level].depth; | |||
GLuint dst_offset = intel_miptree_image_offset(dst, face, level); | |||
const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); | |||
GLuint i; | |||
GLuint height = 0; | |||
DBG("%s: %d/%d\n", __FUNCTION__, face, level); | |||
for (i = 0; i < depth; i++) { | |||
GLuint dst_x, dst_y, height; | |||
intel_miptree_get_image_offset(dst, level, face, i, &dst_x, &dst_y); | |||
height = dst->level[level].height; | |||
if(dst->compressed) | |||
height = (height + 3) / 4; | |||
intel_region_data(intel, | |||
dst->region, | |||
dst_offset + dst_depth_offset[i], /* dst_offset */ | |||
0, 0, /* dstx, dsty */ | |||
dst->region, 0, dst_x, dst_y, | |||
src, | |||
src_row_pitch, | |||
0, 0, /* source x, y */ | |||
@@ -519,10 +502,7 @@ intel_miptree_image_copy(struct intel_context *intel, | |||
GLuint width = src->level[level].width; | |||
GLuint height = src->level[level].height; | |||
GLuint depth = src->level[level].depth; | |||
GLuint dst_offset = intel_miptree_image_offset(dst, face, level); | |||
GLuint src_offset = intel_miptree_image_offset(src, face, level); | |||
const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); | |||
const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); | |||
GLuint src_x, src_y, dst_x, dst_y; | |||
GLuint i; | |||
GLboolean success; | |||
@@ -535,22 +515,23 @@ intel_miptree_image_copy(struct intel_context *intel, | |||
} | |||
for (i = 0; i < depth; i++) { | |||
intel_miptree_get_image_offset(src, level, face, i, &src_x, &src_y); | |||
intel_miptree_get_image_offset(dst, level, face, i, &dst_x, &dst_y); | |||
success = intel_region_copy(intel, | |||
dst->region, dst_offset + dst_depth_offset[i], | |||
0, 0, | |||
src->region, src_offset + src_depth_offset[i], | |||
0, 0, width, height, GL_COPY); | |||
dst->region, 0, dst_x, dst_y, | |||
src->region, 0, src_x, src_y, width, height, | |||
GL_COPY); | |||
if (!success) { | |||
GLubyte *src_ptr, *dst_ptr; | |||
src_ptr = intel_region_map(intel, src->region); | |||
dst_ptr = intel_region_map(intel, dst->region); | |||
_mesa_copy_rect(dst_ptr + dst_offset + dst_depth_offset[i], | |||
_mesa_copy_rect(dst_ptr + dst->cpp * (dst_x + dst_y * dst->pitch), | |||
dst->cpp, | |||
dst->pitch, | |||
0, 0, width, height, | |||
src_ptr + src_offset + src_depth_offset[i], | |||
src_ptr + src->cpp * (src_x + src_y * src->pitch), | |||
src->pitch, | |||
0, 0); | |||
intel_region_unmap(intel, src->region); |
@@ -70,6 +70,10 @@ struct intel_mipmap_level | |||
* always zero in that case. | |||
*/ | |||
GLuint level_offset; | |||
/** Offset to this miptree level, used in computing x_offset. */ | |||
GLuint level_x; | |||
/** Offset to this miptree level, used in computing y_offset. */ | |||
GLuint level_y; | |||
GLuint width; | |||
GLuint height; | |||
/** Depth of the mipmap at this level: 1 for 1D/2D/CUBE, n for 3D. */ | |||
@@ -86,7 +90,7 @@ struct intel_mipmap_level | |||
* compute the offsets of depth/cube images within a mipmap level, | |||
* so have to store them as a lookup table. | |||
*/ | |||
GLuint *image_offset; | |||
GLuint *x_offset, *y_offset; | |||
}; | |||
struct intel_mipmap_tree | |||
@@ -176,19 +180,10 @@ GLubyte *intel_miptree_image_map(struct intel_context *intel, | |||
void intel_miptree_image_unmap(struct intel_context *intel, | |||
struct intel_mipmap_tree *mt); | |||
/* Return the linear offset of an image relative to the start of the | |||
* tree: | |||
*/ | |||
GLuint intel_miptree_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint face, GLuint level); | |||
/* Return pointers to each 2d slice within an image. Indexed by depth | |||
* value. | |||
*/ | |||
const GLuint *intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, | |||
GLuint level); | |||
void | |||
intel_miptree_get_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint level, GLuint face, GLuint depth, | |||
GLuint *x, GLuint *y); | |||
void intel_miptree_set_level_info(struct intel_mipmap_tree *mt, | |||
GLuint level, | |||
@@ -196,16 +191,10 @@ void intel_miptree_set_level_info(struct intel_mipmap_tree *mt, | |||
GLuint x, GLuint y, | |||
GLuint w, GLuint h, GLuint d); | |||
void intel_miptree_set_image_offset_ex(struct intel_mipmap_tree *mt, | |||
GLuint level, | |||
GLuint img, GLuint x, GLuint y, | |||
GLuint offset); | |||
void intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, | |||
GLuint level, | |||
GLuint img, GLuint x, GLuint y); | |||
/* Upload an image into a tree | |||
*/ | |||
void intel_miptree_image_data(struct intel_context *intel, |
@@ -62,6 +62,8 @@ struct intel_region | |||
GLuint map_refcount; /**< Reference count for mapping */ | |||
GLuint draw_offset; /**< Offset of drawing address within the region */ | |||
GLuint draw_x, draw_y; /**< Offset of drawing within the region */ | |||
uint32_t tiling; /**< Which tiling mode the region is in */ | |||
uint32_t bit_6_swizzle; /**< GEM flag for address swizzling requirement */ | |||
drmAddress classic_map; /**< drmMap of the region when not in GEM mode */ |
@@ -115,20 +115,22 @@ do_copy_texsubimage(struct intel_context *intel, | |||
drm_intel_bo *dst_bo = intel_region_buffer(intel, | |||
intelImage->mt->region, | |||
INTEL_WRITE_PART); | |||
GLuint image_offset = intel_miptree_image_offset(intelImage->mt, | |||
intelImage->face, | |||
intelImage->level); | |||
const GLint orig_x = x; | |||
const GLint orig_y = y; | |||
GLuint image_x, image_y; | |||
GLshort src_pitch; | |||
intel_miptree_get_image_offset(intelImage->mt, | |||
intelImage->level, | |||
intelImage->face, | |||
0, | |||
&image_x, &image_y); | |||
/* Update dst for clipped src. Need to also clip the source rect. */ | |||
dstx += x - orig_x; | |||
dsty += y - orig_y; | |||
/* Can't blit to tiled buffers with non-tile-aligned offset. */ | |||
if (intelImage->mt->region->tiling != I915_TILING_NONE && | |||
(image_offset & 4095) != 0) { | |||
if (intelImage->mt->region->tiling == I915_TILING_Y) { | |||
UNLOCK_HARDWARE(intel); | |||
return GL_FALSE; | |||
} | |||
@@ -160,9 +162,10 @@ do_copy_texsubimage(struct intel_context *intel, | |||
src->tiling, | |||
intelImage->mt->pitch, | |||
dst_bo, | |||
image_offset, | |||
0, | |||
intelImage->mt->region->tiling, | |||
x, y, dstx, dsty, width, height, | |||
x, y, image_x + dstx, image_y + dsty, | |||
width, height, | |||
GL_COPY)) { | |||
UNLOCK_HARDWARE(intel); | |||
return GL_FALSE; |
@@ -204,7 +204,7 @@ try_pbo_upload(struct intel_context *intel, | |||
{ | |||
struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); | |||
GLuint src_offset, src_stride; | |||
GLuint dst_offset, dst_stride; | |||
GLuint dst_x, dst_y, dst_stride; | |||
if (unpack->BufferObj->Name == 0 || | |||
intel->ctx._ImageTransferState || | |||
@@ -221,9 +221,9 @@ try_pbo_upload(struct intel_context *intel, | |||
else | |||
src_stride = width; | |||
dst_offset = intel_miptree_image_offset(intelImage->mt, | |||
intelImage->face, | |||
intelImage->level); | |||
intel_miptree_get_image_offset(intelImage->mt, intelImage->level, | |||
intelImage->face, 0, | |||
&dst_x, &dst_y); | |||
dst_stride = intelImage->mt->pitch; | |||
@@ -239,8 +239,8 @@ try_pbo_upload(struct intel_context *intel, | |||
if (!intelEmitCopyBlit(intel, | |||
intelImage->mt->cpp, | |||
src_stride, src_buffer, src_offset, GL_FALSE, | |||
dst_stride, dst_buffer, dst_offset, GL_FALSE, | |||
0, 0, 0, 0, width, height, | |||
dst_stride, dst_buffer, 0, GL_FALSE, | |||
0, 0, dst_x, dst_y, width, height, | |||
GL_COPY)) { | |||
UNLOCK_HARDWARE(intel); | |||
return GL_FALSE; | |||
@@ -262,7 +262,7 @@ try_pbo_zcopy(struct intel_context *intel, | |||
{ | |||
struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); | |||
GLuint src_offset, src_stride; | |||
GLuint dst_offset, dst_stride; | |||
GLuint dst_x, dst_y, dst_stride; | |||
if (unpack->BufferObj->Name == 0 || | |||
intel->ctx._ImageTransferState || | |||
@@ -279,13 +279,14 @@ try_pbo_zcopy(struct intel_context *intel, | |||
else | |||
src_stride = width; | |||
dst_offset = intel_miptree_image_offset(intelImage->mt, | |||
intelImage->face, | |||
intelImage->level); | |||
intel_miptree_get_image_offset(intelImage->mt, intelImage->level, | |||
intelImage->face, 0, | |||
&dst_x, &dst_y); | |||
dst_stride = intelImage->mt->pitch; | |||
if (src_stride != dst_stride || dst_offset != 0 || src_offset != 0) { | |||
if (src_stride != dst_stride || dst_x != 0 || dst_y != 0 || | |||
src_offset != 0) { | |||
DBG("%s: failure 2\n", __FUNCTION__); | |||
return GL_FALSE; | |||
} |