diff options
| -rw-r--r-- | src/gallium/drivers/r300/r300_context.c | 2 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_screen.h | 6 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_texture.c | 5 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_transfer.c | 210 | ||||
| -rw-r--r-- | src/gallium/drivers/r300/r300_transfer.h | 29 | 
5 files changed, 197 insertions, 55 deletions
| diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index ec1c586522..e43e088b36 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -159,6 +159,8 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,      if (!r300)          return NULL; +    r300screen->ctx = (struct pipe_context*)r300; +      r300->winsys = radeon_winsys;      r300->context.winsys = (struct pipe_winsys*)radeon_winsys; diff --git a/src/gallium/drivers/r300/r300_screen.h b/src/gallium/drivers/r300/r300_screen.h index 6d72fec778..484bde6a6b 100644 --- a/src/gallium/drivers/r300/r300_screen.h +++ b/src/gallium/drivers/r300/r300_screen.h @@ -28,6 +28,8 @@  #include "r300_chipset.h" +#define R300_TEXTURE_USAGE_TRANSFER PIPE_TEXTURE_USAGE_CUSTOM +  struct radeon_winsys;  struct r300_screen { @@ -36,6 +38,10 @@ struct r300_screen {      struct radeon_winsys* radeon_winsys; +    /* XXX This hack will be removed once texture transfers become part of +     * pipe_context. */ +    struct pipe_context* ctx; +      /* Chipset capabilities */      struct r300_capabilities* caps; diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index c0144f64b4..04e326eb78 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -725,9 +725,8 @@ static void r300_setup_flags(struct r300_texture* tex)  }  /* Create a new texture. */ -static struct pipe_texture* -    r300_texture_create(struct pipe_screen* screen, -                        const struct pipe_texture* template) +static struct pipe_texture* r300_texture_create(struct pipe_screen* screen, +                                         const struct pipe_texture* template)  {      struct r300_texture* tex = CALLOC_STRUCT(r300_texture);      struct r300_screen* rscreen = r300_screen(screen); diff --git a/src/gallium/drivers/r300/r300_transfer.c b/src/gallium/drivers/r300/r300_transfer.c index fa48688db2..56a6976e8b 100644 --- a/src/gallium/drivers/r300/r300_transfer.c +++ b/src/gallium/drivers/r300/r300_transfer.c @@ -29,6 +29,89 @@  #include "util/u_memory.h"  #include "util/u_format.h" +struct r300_transfer { +    /* Parent class */ +    struct pipe_transfer transfer; + +    /* Pipe context. */ +    struct pipe_context *ctx; + +    /* Parameters of get_tex_transfer. */ +    unsigned x, y, level, zslice, face; + +    /* Offset from start of buffer. */ +    unsigned offset; + +    /* Detiled texture. */ +    struct r300_texture *detiled_texture; + +    /* Transfer and format flags. */ +    unsigned buffer_usage, render_target_usage; +}; + +/* Convenience cast wrapper. */ +static INLINE struct r300_transfer* +r300_transfer(struct pipe_transfer* transfer) +{ +    return (struct r300_transfer*)transfer; +} + +/* Copy from a tiled texture to a detiled one. */ +static void r300_copy_from_tiled_texture(struct pipe_context *ctx, +                                         struct r300_transfer *r300transfer) +{ +    struct pipe_screen *screen = ctx->screen; +    struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; +    struct pipe_texture *tex = transfer->texture; +    struct pipe_surface *src, *dst; + +    src = screen->get_tex_surface(screen, tex, r300transfer->face, +                                  r300transfer->level, r300transfer->zslice, +                                  PIPE_BUFFER_USAGE_GPU_READ | +                                  PIPE_BUFFER_USAGE_PIXEL); + +    dst = screen->get_tex_surface(screen, &r300transfer->detiled_texture->tex, +                                  0, 0, 0, +                                  PIPE_BUFFER_USAGE_GPU_WRITE | +                                  PIPE_BUFFER_USAGE_PIXEL | +                                  r300transfer->buffer_usage); + +    ctx->surface_copy(ctx, dst, 0, 0, src, r300transfer->x, r300transfer->y, +                      transfer->width, transfer->height); + +    pipe_surface_reference(&src, NULL); +    pipe_surface_reference(&dst, NULL); +} + +/* Copy a detiled texture to a tiled one. */ +static void r300_copy_into_tiled_texture(struct pipe_context *ctx, +                                         struct r300_transfer *r300transfer) +{ +    struct pipe_screen *screen = ctx->screen; +    struct pipe_transfer *transfer = (struct pipe_transfer*)r300transfer; +    struct pipe_texture *tex = transfer->texture; +    struct pipe_surface *src, *dst; + +    src = screen->get_tex_surface(screen, &r300transfer->detiled_texture->tex, +                                  0, 0, 0, +                                  PIPE_BUFFER_USAGE_GPU_READ | +                                  PIPE_BUFFER_USAGE_PIXEL); + +    dst = screen->get_tex_surface(screen, tex, r300transfer->face, +                                  r300transfer->level, r300transfer->zslice, +                                  PIPE_BUFFER_USAGE_GPU_WRITE | +                                  PIPE_BUFFER_USAGE_PIXEL); + +    ctx->surface_copy(ctx, dst, r300transfer->x, r300transfer->y, src, 0, 0, +                      transfer->width, transfer->height); + +    /* XXX this flush fixes lots of regressions, not sure why */ +    ctx->flush(ctx, 0, NULL); + +    pipe_surface_reference(&src, NULL); +    pipe_surface_reference(&dst, NULL); +} +  static struct pipe_transfer*  r300_get_tex_transfer(struct pipe_screen *screen,                        struct pipe_texture *texture, @@ -38,58 +121,139 @@ r300_get_tex_transfer(struct pipe_screen *screen,  {      struct r300_texture *tex = (struct r300_texture *)texture;      struct r300_transfer *trans; -    struct r300_screen *rscreen = r300_screen(screen); -    unsigned offset; - -    offset = r300_texture_get_offset(tex, level, zslice, face);  /* in bytes */ +    struct r300_screen *r300screen = r300_screen(screen); +    struct pipe_texture template;      trans = CALLOC_STRUCT(r300_transfer);      if (trans) { +        /* Initialize the transfer object. */          pipe_texture_reference(&trans->transfer.texture, texture); -        trans->transfer.x = x; -        trans->transfer.y = y; +        trans->transfer.usage = usage;          trans->transfer.width = w;          trans->transfer.height = h; -        trans->transfer.stride = r300_texture_get_stride(rscreen, tex, level); -        trans->transfer.usage = usage; -        trans->transfer.zslice = zslice; -        trans->transfer.face = face; +        trans->ctx = r300screen->ctx; +        trans->x = x; +        trans->y = y; +        trans->level = level; +        trans->zslice = zslice; +        trans->face = face; + +        /* If the texture is tiled, we must create a temporary detiled texture +         * for this transfer. */ +        if (tex->microtile || tex->macrotile) { +            trans->buffer_usage = pipe_transfer_buffer_flags(&trans->transfer); +            trans->render_target_usage = +                util_format_is_depth_or_stencil(texture->format) ? +                PIPE_TEXTURE_USAGE_DEPTH_STENCIL : +                PIPE_TEXTURE_USAGE_RENDER_TARGET; + +            template.target = PIPE_TEXTURE_2D; +            template.format = texture->format; +            template.width0 = w; +            template.height0 = h; +            template.depth0 = 0; +            template.last_level = 0; +            template.nr_samples = 0; +            template.tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC | +                                 R300_TEXTURE_USAGE_TRANSFER; -        trans->offset = offset; +            /* For texture reading, the temporary (detiled) texture is used as +             * a render target when blitting from a tiled texture. */ +            if (usage & PIPE_TRANSFER_READ) { +                template.tex_usage |= trans->render_target_usage; +            } +            /* For texture writing, the temporary texture is used as a sampler +             * when blitting into a tiled texture. */ +            if (usage & PIPE_TRANSFER_WRITE) { +                template.tex_usage |= PIPE_TEXTURE_USAGE_SAMPLER; +            } + +            /* Create the temporary texture. */ +            trans->detiled_texture = +                (struct r300_texture*)screen->texture_create(screen, &template); +            assert(!trans->detiled_texture->microtile && +                   !trans->detiled_texture->macrotile); + +            /* Set the stride. +             * Parameters x, y, level, zslice, and face remain zero. */ +            trans->transfer.stride = +                r300_texture_get_stride(r300screen, trans->detiled_texture, 0); + +            if (usage & PIPE_TRANSFER_READ) { +                /* We cannot map a tiled texture directly because the data is +                 * in a different order, therefore we do detiling using a blit. */ +                r300_copy_from_tiled_texture(r300screen->ctx, trans); +            } +        } else { +            trans->transfer.x = x; +            trans->transfer.y = y; +            trans->transfer.stride = +                r300_texture_get_stride(r300screen, tex, level); +            trans->transfer.level = level; +            trans->transfer.zslice = zslice; +            trans->transfer.face = face; +            trans->offset = r300_texture_get_offset(tex, level, zslice, face); +        }      }      return &trans->transfer;  }  static void r300_tex_transfer_destroy(struct pipe_transfer *trans)  { -   pipe_texture_reference(&trans->texture, NULL); -   FREE(trans); +    struct r300_transfer *r300transfer = r300_transfer(trans); + +    if (r300transfer->detiled_texture) { +        if (trans->usage & PIPE_TRANSFER_WRITE) { +            r300_copy_into_tiled_texture(r300transfer->ctx, r300transfer); +        } + +        pipe_texture_reference( +            (struct pipe_texture**)&r300transfer->detiled_texture, NULL); +    } +    pipe_texture_reference(&trans->texture, NULL); +    FREE(trans);  }  static void* r300_transfer_map(struct pipe_screen *screen, -                              struct pipe_transfer *transfer) +                               struct pipe_transfer *transfer)  { +    struct r300_transfer *r300transfer = r300_transfer(transfer);      struct r300_texture *tex = (struct r300_texture*)transfer->texture;      char *map;      enum pipe_format format = tex->tex.format; -    map = pipe_buffer_map(screen, tex->buffer, -                          pipe_transfer_buffer_flags(transfer)); +    if (r300transfer->detiled_texture) { +        /* The detiled texture is of the same size as the region being mapped +         * (no offset needed). */ +        return pipe_buffer_map(screen, +                               r300transfer->detiled_texture->buffer, +                               pipe_transfer_buffer_flags(transfer)); +    } else { +        /* Tiling is disabled. */ +        map = pipe_buffer_map(screen, tex->buffer, +                              pipe_transfer_buffer_flags(transfer)); -    if (!map) { -        return NULL; -    } +        if (!map) { +            return NULL; +        } -    return map + r300_transfer(transfer)->offset + -        transfer->y / util_format_get_blockheight(format) * transfer->stride + -        transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); +        return map + r300_transfer(transfer)->offset + +            transfer->y / util_format_get_blockheight(format) * transfer->stride + +            transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); +    }  }  static void r300_transfer_unmap(struct pipe_screen *screen,                                  struct pipe_transfer *transfer)  { +    struct r300_transfer *r300transfer = r300_transfer(transfer);      struct r300_texture *tex = (struct r300_texture*)transfer->texture; -    pipe_buffer_unmap(screen, tex->buffer); + +    if (r300transfer->detiled_texture) { +        pipe_buffer_unmap(screen, r300transfer->detiled_texture->buffer); +    } else { +        pipe_buffer_unmap(screen, tex->buffer); +    }  }  void r300_init_screen_transfer_functions(struct pipe_screen *screen) diff --git a/src/gallium/drivers/r300/r300_transfer.h b/src/gallium/drivers/r300/r300_transfer.h index faf62338ef..60d1d3dc85 100644 --- a/src/gallium/drivers/r300/r300_transfer.h +++ b/src/gallium/drivers/r300/r300_transfer.h @@ -25,36 +25,7 @@  #define R300_TRANSFER  #include "pipe/p_screen.h" -#include "pipe/p_state.h" - -struct r300_texture; -struct r300_screen; - -struct r300_transfer { -    /* Parent class */ -    struct pipe_transfer transfer; - -    /* Parameters of get_tex_transfer. */ -    unsigned x, y, level, zslice, face; - -    /* Offset from start of buffer. */ -    unsigned offset; - -    /* Untiled texture. */ -    struct r300_texture *untiled_texture; - -    /* Transfer and format flags. */ -    unsigned buffer_usage, render_target_usage; -}; - -/* Convenience cast wrapper. */ -static INLINE struct r300_transfer* -r300_transfer(struct pipe_transfer* transfer) -{ -    return (struct r300_transfer*)transfer; -}  void r300_init_screen_transfer_functions(struct pipe_screen *screen);  #endif - | 
