r300g: accelerate blitting for all formats by faking the texture format
authorMarek Olšák <maraeo@gmail.com>
Sun, 14 Feb 2010 03:57:03 +0000 (04:57 +0100)
committerMarek Olšák <maraeo@gmail.com>
Sun, 14 Feb 2010 17:15:13 +0000 (18:15 +0100)
src/gallium/drivers/r300/r300_blit.c
src/gallium/drivers/r300/r300_texture.c
src/gallium/drivers/r300/r300_texture.h

index faaf9523cb22c57719476feea95344e1eca7ea56..eb9b0beeb5a9589b803b1fb2796e3f2a90f1fa83 100644 (file)
@@ -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,
index f228220bb54f96a26612dcdfaa8bb6e68d55b7a4..f3325be87aea5a77f812d294cfd3df5359554b8a 100644 (file)
@@ -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)
 {
index 1d2382da06d54849129d0984aec1c30b0c2cdd96..b9c3ab80932d5384ef637ee17fa9eec27ce9be76 100644 (file)
@@ -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.