r300g: rework resource_copy_region, not changing pipe_resource

Changing pipe_resource was wrong, because it can be used by other contexts
at the same time. This fixes the last possible race condition in r300g
that I know of.

This also fixes blitting NPOT compressed textures. Random pixels sometimes
appeared at the right-hand edge of the texture.

Finally, this removes r300_texture_desc::stride_in_pixels. It makes little
sense with sampler views and surfaces being able to override width0, height0,
and the format entirely.
This commit is contained in:
Marek Olšák
2011-12-29 18:18:38 +01:00
parent ce31970af1
commit ce9d61fec6
9 changed files with 212 additions and 137 deletions

View File

@@ -434,21 +434,14 @@ void r300_decompress_zmask_locked(struct r300_context *r300)
pipe_surface_reference(&r300->locked_zbuffer, NULL);
}
/* Copy a block of pixels from one surface to another using HW. */
static void r300_hw_copy_region(struct pipe_context* pipe,
struct pipe_resource *dst,
unsigned dst_level,
unsigned dstx, unsigned dsty, unsigned dstz,
struct pipe_resource *src,
unsigned src_level,
const struct pipe_box *src_box)
bool r300_is_blit_supported(enum pipe_format format)
{
struct r300_context* r300 = r300_context(pipe);
const struct util_format_description *desc =
util_format_description(format);
r300_blitter_begin(r300, R300_COPY);
util_blitter_copy_texture(r300->blitter, dst, dst_level, dstx, dsty, dstz,
src, src_level, src_box, TRUE);
r300_blitter_end(r300);
return desc->layout == UTIL_FORMAT_LAYOUT_PLAIN ||
desc->layout == UTIL_FORMAT_LAYOUT_S3TC ||
desc->layout == UTIL_FORMAT_LAYOUT_RGTC;
}
/* Copy a block of pixels from one surface to another. */
@@ -460,24 +453,120 @@ static void r300_resource_copy_region(struct pipe_context *pipe,
unsigned src_level,
const struct pipe_box *src_box)
{
struct pipe_screen *screen = pipe->screen;
struct r300_context *r300 = r300_context(pipe);
struct pipe_framebuffer_state *fb =
(struct pipe_framebuffer_state*)r300->fb_state.state;
struct pipe_resource old_src = *src;
struct pipe_resource old_dst = *dst;
struct pipe_resource new_src = old_src;
struct pipe_resource new_dst = old_dst;
const struct util_format_description *desc =
util_format_description(dst->format);
unsigned src_width0 = r300_resource(src)->tex.width0;
unsigned src_height0 = r300_resource(src)->tex.height0;
unsigned dst_width0 = r300_resource(dst)->tex.width0;
unsigned dst_height0 = r300_resource(dst)->tex.height0;
unsigned layout;
struct pipe_box box;
struct pipe_sampler_view src_templ, *src_view;
struct pipe_surface dst_templ, *dst_view;
/* Fallback for buffers. */
if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
if ((dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) ||
!r300_is_blit_supported(dst->format)) {
util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
src, src_level, src_box);
return;
}
/* The code below changes the texture format so that the copy can be done
* on hardware. E.g. depth-stencil surfaces are copied as RGBA
* colorbuffers. */
util_blitter_default_dst_texture(&dst_templ, dst, dst_level, dstz, src_box);
util_blitter_default_src_texture(&src_templ, src, src_level);
layout = util_format_description(dst_templ.format)->layout;
/* Handle non-renderable plain formats. */
if (layout == UTIL_FORMAT_LAYOUT_PLAIN &&
(!screen->is_format_supported(screen, src_templ.format, src->target,
src->nr_samples,
PIPE_BIND_SAMPLER_VIEW) ||
!screen->is_format_supported(screen, dst_templ.format, dst->target,
dst->nr_samples,
PIPE_BIND_RENDER_TARGET))) {
switch (util_format_get_blocksize(dst_templ.format)) {
case 1:
dst_templ.format = PIPE_FORMAT_I8_UNORM;
break;
case 2:
dst_templ.format = PIPE_FORMAT_B4G4R4A4_UNORM;
break;
case 4:
dst_templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
break;
case 8:
dst_templ.format = PIPE_FORMAT_R16G16B16A16_UNORM;
break;
default:
debug_printf("r300: copy_region: Unhandled format: %s. Falling back to software.\n"
"r300: copy_region: Software fallback doesn't work for tiled textures.\n",
util_format_short_name(dst_templ.format));
}
src_templ.format = dst_templ.format;
}
/* Handle compressed formats. */
if (layout == UTIL_FORMAT_LAYOUT_S3TC ||
layout == UTIL_FORMAT_LAYOUT_RGTC) {
assert(src_templ.format == dst_templ.format);
box = *src_box;
src_box = &box;
dst_width0 = align(dst_width0, 4);
dst_height0 = align(dst_height0, 4);
src_width0 = align(src_width0, 4);
src_height0 = align(src_height0, 4);
box.width = align(box.width, 4);
box.height = align(box.height, 4);
switch (util_format_get_blocksize(dst_templ.format)) {
case 8:
/* one 4x4 pixel block has 8 bytes.
* we set 1 pixel = 4 bytes ===> 1 block corrensponds to 2 pixels. */
dst_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
dst_width0 = dst_width0 / 2;
src_width0 = src_width0 / 2;
dstx /= 2;
box.x /= 2;
box.width /= 2;
break;
case 16:
/* one 4x4 pixel block has 16 bytes.
* we set 1 pixel = 4 bytes ===> 1 block corresponds to 4 pixels. */
dst_templ.format = PIPE_FORMAT_R8G8B8A8_UNORM;
break;
}
src_templ.format = dst_templ.format;
dst_height0 = dst_height0 / 4;
src_height0 = src_height0 / 4;
dsty /= 4;
box.y /= 4;
box.height /= 4;
}
/* Fallback for textures. */
if (!screen->is_format_supported(screen, dst_templ.format,
dst->target, dst->nr_samples,
PIPE_BIND_RENDER_TARGET) ||
!screen->is_format_supported(screen, src_templ.format,
src->target, src->nr_samples,
PIPE_BIND_SAMPLER_VIEW)) {
assert(0 && "this shouldn't happen, update r300_is_blit_supported");
util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
src, src_level, src_box);
return;
}
/* Decompress ZMASK. */
if (r300->zmask_in_use && !r300->locked_zbuffer) {
if (fb->zsbuf->texture == src ||
fb->zsbuf->texture == dst) {
@@ -485,78 +574,17 @@ static void r300_resource_copy_region(struct pipe_context *pipe,
}
}
/* Handle non-renderable plain formats. */
if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN &&
(desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB ||
!pipe->screen->is_format_supported(pipe->screen,
src->format, src->target,
src->nr_samples,
PIPE_BIND_SAMPLER_VIEW) ||
!pipe->screen->is_format_supported(pipe->screen,
dst->format, dst->target,
dst->nr_samples,
PIPE_BIND_RENDER_TARGET))) {
switch (util_format_get_blocksize(old_dst.format)) {
case 1:
new_dst.format = PIPE_FORMAT_I8_UNORM;
break;
case 2:
new_dst.format = PIPE_FORMAT_B4G4R4A4_UNORM;
break;
case 4:
new_dst.format = PIPE_FORMAT_B8G8R8A8_UNORM;
break;
case 8:
new_dst.format = PIPE_FORMAT_R16G16B16A16_UNORM;
break;
default:
debug_printf("r300: surface_copy: Unhandled format: %s. Falling back to software.\n"
"r300: surface_copy: Software fallback doesn't work for tiled textures.\n",
util_format_short_name(dst->format));
}
new_src.format = new_dst.format;
}
dst_view = r300_create_surface_custom(pipe, dst, &dst_templ, dst_width0, dst_height0);
src_view = r300_create_sampler_view_custom(pipe, src, &src_templ, src_width0, src_height0);
/* Handle compressed formats. */
if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC ||
desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
switch (util_format_get_blocksize(old_dst.format)) {
case 8:
/* 1 pixel = 4 bits,
* we set 1 pixel = 2 bytes ===> 4 times larger pixels. */
new_dst.format = PIPE_FORMAT_B4G4R4A4_UNORM;
break;
case 16:
/* 1 pixel = 8 bits,
* we set 1 pixel = 4 bytes ===> 4 times larger pixels. */
new_dst.format = PIPE_FORMAT_B8G8R8A8_UNORM;
break;
}
r300_blitter_begin(r300, R300_COPY);
util_blitter_copy_texture_view(r300->blitter, dst_view, dstx, dsty,
src_view, src_box,
src_width0, src_height0);
r300_blitter_end(r300);
/* Since the pixels are 4 times larger, we must decrease
* the image size and the coordinates 4 times. */
new_src.format = new_dst.format;
new_dst.height0 = (new_dst.height0 + 3) / 4;
new_src.height0 = (new_src.height0 + 3) / 4;
dsty /= 4;
box = *src_box;
box.y /= 4;
box.height = (box.height + 3) / 4;
src_box = &box;
}
if (old_src.format != new_src.format)
r300_resource_set_properties(pipe->screen, src, &new_src);
if (old_dst.format != new_dst.format)
r300_resource_set_properties(pipe->screen, dst, &new_dst);
r300_hw_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
src, src_level, src_box);
if (old_src.format != new_src.format)
r300_resource_set_properties(pipe->screen, src, &old_src);
if (old_dst.format != new_dst.format)
r300_resource_set_properties(pipe->screen, dst, &old_dst);
pipe_surface_reference(&dst_view, NULL);
pipe_sampler_view_reference(&src_view, NULL);
}
void r300_init_blit_functions(struct r300_context *r300)