summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/r300/r300_blit.c
diff options
context:
space:
mode:
authorMarek Olšák <maraeo@gmail.com>2011-12-29 18:18:38 +0100
committerMarek Olšák <maraeo@gmail.com>2012-01-01 11:47:05 +0100
commitce9d61fec64138ebf8d0bec2511e66593297b7d5 (patch)
tree3e60c2743b8df17392415e7d22b0e10446343624 /src/gallium/drivers/r300/r300_blit.c
parentce31970af16558ebd60cfae33c000252bc3e1cbf (diff)
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.
Diffstat (limited to 'src/gallium/drivers/r300/r300_blit.c')
-rw-r--r--src/gallium/drivers/r300/r300_blit.c172
1 files changed, 100 insertions, 72 deletions
diff --git a/src/gallium/drivers/r300/r300_blit.c b/src/gallium/drivers/r300/r300_blit.c
index 3974aea878f..c780c8dd1ad 100644
--- a/src/gallium/drivers/r300/r300_blit.c
+++ b/src/gallium/drivers/r300/r300_blit.c
@@ -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,103 +453,138 @@ 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;
}
- if (r300->zmask_in_use && !r300->locked_zbuffer) {
- if (fb->zsbuf->texture == src ||
- fb->zsbuf->texture == dst) {
- r300_decompress_zmask(r300);
- }
- }
+ /* 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 (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)) {
+ 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:
- new_dst.format = PIPE_FORMAT_I8_UNORM;
+ dst_templ.format = PIPE_FORMAT_I8_UNORM;
break;
case 2:
- new_dst.format = PIPE_FORMAT_B4G4R4A4_UNORM;
+ dst_templ.format = PIPE_FORMAT_B4G4R4A4_UNORM;
break;
case 4:
- new_dst.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ dst_templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
break;
case 8:
- new_dst.format = PIPE_FORMAT_R16G16B16A16_UNORM;
+ dst_templ.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));
+ 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));
}
- new_src.format = new_dst.format;
+ src_templ.format = dst_templ.format;
}
/* Handle compressed formats. */
- if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC ||
- desc->layout == UTIL_FORMAT_LAYOUT_RGTC) {
- switch (util_format_get_blocksize(old_dst.format)) {
+ 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:
- /* 1 pixel = 4 bits,
- * we set 1 pixel = 2 bytes ===> 4 times larger pixels. */
- new_dst.format = PIPE_FORMAT_B4G4R4A4_UNORM;
+ /* 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:
- /* 1 pixel = 8 bits,
- * we set 1 pixel = 4 bytes ===> 4 times larger pixels. */
- new_dst.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+ /* 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;
- /* 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;
+ dst_height0 = dst_height0 / 4;
+ src_height0 = src_height0 / 4;
dsty /= 4;
- box = *src_box;
box.y /= 4;
- box.height = (box.height + 3) / 4;
- src_box = &box;
+ box.height /= 4;
}
- 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);
+ /* 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;
+ }
- r300_hw_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
- src, src_level, src_box);
+ /* Decompress ZMASK. */
+ if (r300->zmask_in_use && !r300->locked_zbuffer) {
+ if (fb->zsbuf->texture == src ||
+ fb->zsbuf->texture == dst) {
+ r300_decompress_zmask(r300);
+ }
+ }
+
+ 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);
+
+ 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);
- 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)