summaryrefslogtreecommitdiffstats
path: root/src/gallium
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium')
-rw-r--r--src/gallium/drivers/r300/r300_blit.c74
-rw-r--r--src/gallium/drivers/r300/r300_texture.c14
-rw-r--r--src/gallium/drivers/r300/r300_texture.h4
3 files changed, 85 insertions, 7 deletions
diff --git a/src/gallium/drivers/r300/r300_blit.c b/src/gallium/drivers/r300/r300_blit.c
index faaf9523cb2..eb9b0beeb5a 100644
--- a/src/gallium/drivers/r300/r300_blit.c
+++ b/src/gallium/drivers/r300/r300_blit.c
@@ -22,6 +22,9 @@
#include "r300_blit.h"
#include "r300_context.h"
+#include "r300_texture.h"
+
+#include "util/u_format.h"
static void r300_blitter_save_states(struct r300_context* r300)
{
@@ -86,13 +89,13 @@ void r300_clear(struct pipe_context* pipe,
buffers, rgba, depth, stencil);
}
-/* Copy a block of pixels from one surface to another. */
-void r300_surface_copy(struct pipe_context* pipe,
- struct pipe_surface* dst,
- unsigned dstx, unsigned dsty,
- struct pipe_surface* src,
- unsigned srcx, unsigned srcy,
- unsigned width, unsigned height)
+/* Copy a block of pixels from one surface to another using HW. */
+static void r300_hw_copy(struct pipe_context* pipe,
+ struct pipe_surface* dst,
+ unsigned dstx, unsigned dsty,
+ struct pipe_surface* src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
{
struct r300_context* r300 = r300_context(pipe);
@@ -114,6 +117,63 @@ void r300_surface_copy(struct pipe_context* pipe,
dst, dstx, dsty, src, srcx, srcy, width, height, TRUE);
}
+/* Copy a block of pixels from one surface to another. */
+void r300_surface_copy(struct pipe_context* pipe,
+ struct pipe_surface* dst,
+ unsigned dstx, unsigned dsty,
+ struct pipe_surface* src,
+ unsigned srcx, unsigned srcy,
+ unsigned width, unsigned height)
+{
+ enum pipe_format old_format = dst->texture->format;
+ enum pipe_format new_format = old_format;
+
+ assert(dst->texture->format == src->texture->format);
+
+ if (!pipe->screen->is_format_supported(pipe->screen,
+ old_format, src->texture->target,
+ PIPE_TEXTURE_USAGE_RENDER_TARGET |
+ PIPE_TEXTURE_USAGE_SAMPLER, 0)) {
+ switch (util_format_get_blocksize(old_format)) {
+ case 1:
+ new_format = PIPE_FORMAT_I8_UNORM;
+ break;
+ case 2:
+ new_format = PIPE_FORMAT_A4R4G4B4_UNORM;
+ break;
+ case 4:
+ new_format = PIPE_FORMAT_A8R8G8B8_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_name(old_format));
+ }
+ }
+
+ if (old_format != new_format) {
+ dst->format = new_format;
+ src->format = new_format;
+
+ r300_texture_reinterpret_format(pipe->screen,
+ dst->texture, new_format);
+ r300_texture_reinterpret_format(pipe->screen,
+ src->texture, new_format);
+ }
+
+ r300_hw_copy(pipe, dst, dstx, dsty, src, srcx, srcy, width, height);
+
+ if (old_format != new_format) {
+ dst->format = old_format;
+ src->format = old_format;
+
+ r300_texture_reinterpret_format(pipe->screen,
+ dst->texture, old_format);
+ r300_texture_reinterpret_format(pipe->screen,
+ src->texture, old_format);
+ }
+}
+
/* Fill a region of a surface with a constant value. */
void r300_surface_fill(struct pipe_context* pipe,
struct pipe_surface* dst,
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c
index f228220bb54..f3325be87ae 100644
--- a/src/gallium/drivers/r300/r300_texture.c
+++ b/src/gallium/drivers/r300/r300_texture.c
@@ -85,6 +85,20 @@ static void r300_setup_texture_state(struct r300_screen* screen, struct r300_tex
pt->width0, pt->height0, pt->last_level);
}
+void r300_texture_reinterpret_format(struct pipe_screen *screen,
+ struct pipe_texture *tex,
+ enum pipe_format new_format)
+{
+ struct r300_screen *r300screen = r300_screen(screen);
+
+ SCREEN_DBG(r300screen, DBG_TEX, "r300: Reinterpreting format: %s -> %s\n",
+ util_format_name(tex->format), util_format_name(new_format));
+
+ tex->format = new_format;
+
+ r300_setup_texture_state(r300_screen(screen), (struct r300_texture*)tex);
+}
+
unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level,
unsigned zslice, unsigned face)
{
diff --git a/src/gallium/drivers/r300/r300_texture.h b/src/gallium/drivers/r300/r300_texture.h
index 1d2382da06d..b9c3ab80932 100644
--- a/src/gallium/drivers/r300/r300_texture.h
+++ b/src/gallium/drivers/r300/r300_texture.h
@@ -38,6 +38,10 @@ unsigned r300_texture_get_stride(struct r300_screen* screen,
unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level,
unsigned zslice, unsigned face);
+void r300_texture_reinterpret_format(struct pipe_screen *screen,
+ struct pipe_texture *tex,
+ enum pipe_format new_format);
+
/* Translate a pipe_format into a useful texture format for sampling.
*
* R300_EASY_TX_FORMAT swizzles the texture.