summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nvfx/nvfx_transfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/nvfx/nvfx_transfer.c')
-rw-r--r--src/gallium/drivers/nvfx/nvfx_transfer.c328
1 files changed, 171 insertions, 157 deletions
diff --git a/src/gallium/drivers/nvfx/nvfx_transfer.c b/src/gallium/drivers/nvfx/nvfx_transfer.c
index 9ff0a93d307..7cb47a20f64 100644
--- a/src/gallium/drivers/nvfx/nvfx_transfer.c
+++ b/src/gallium/drivers/nvfx/nvfx_transfer.c
@@ -4,204 +4,218 @@
#include "util/u_format.h"
#include "util/u_memory.h"
#include "util/u_math.h"
-#include "nouveau/nouveau_winsys.h"
+#include "util/u_staging.h"
#include "nvfx_context.h"
#include "nvfx_screen.h"
#include "nvfx_state.h"
#include "nvfx_resource.h"
#include "nvfx_transfer.h"
-struct nvfx_transfer {
- struct pipe_transfer base;
- struct pipe_surface *surface;
- boolean direct;
-};
-
-static void
-nvfx_compatible_transfer_tex(struct pipe_resource *pt, unsigned width, unsigned height,
- unsigned bind,
- struct pipe_resource *template)
-{
- memset(template, 0, sizeof(struct pipe_resource));
- template->target = pt->target;
- template->format = pt->format;
- template->width0 = width;
- template->height0 = height;
- template->depth0 = 1;
- template->last_level = 0;
- template->nr_samples = pt->nr_samples;
- template->bind = bind;
- template->usage = PIPE_USAGE_DYNAMIC;
- template->flags = NVFX_RESOURCE_FLAG_LINEAR;
-}
-
-
-static unsigned nvfx_transfer_bind_flags( unsigned transfer_usage )
+struct nvfx_staging_transfer
{
- unsigned bind = 0;
+ struct util_staging_transfer base;
-#if 0
- if (transfer_usage & PIPE_TRANSFER_WRITE)
- bind |= PIPE_BIND_BLIT_SOURCE;
-
- if (transfer_usage & PIPE_TRANSFER_READ)
- bind |= PIPE_BIND_BLIT_DESTINATION;
-#endif
-
- return bind;
-}
+ unsigned offset;
+ unsigned map_count;
+};
struct pipe_transfer *
-nvfx_miptree_transfer_new(struct pipe_context *pipe,
+nvfx_transfer_new(struct pipe_context *pipe,
struct pipe_resource *pt,
struct pipe_subresource sr,
unsigned usage,
const struct pipe_box *box)
{
- struct pipe_screen *pscreen = pipe->screen;
- struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
- struct nvfx_transfer *tx;
- struct pipe_resource tx_tex_template, *tx_tex;
- static int no_transfer = -1;
- unsigned bind = nvfx_transfer_bind_flags(usage);
- if(no_transfer < 0)
- no_transfer = debug_get_bool_option("NOUVEAU_NO_TRANSFER", FALSE);
-
-
- tx = CALLOC_STRUCT(nvfx_transfer);
- if (!tx)
- return NULL;
-
- /* Don't handle 3D transfers yet.
- */
- assert(box->depth == 1);
-
- pipe_resource_reference(&tx->base.resource, pt);
- tx->base.sr = sr;
- tx->base.usage = usage;
- tx->base.box = *box;
- tx->base.stride = mt->level[sr.level].pitch;
-
- /* Direct access to texture */
- if ((pt->usage == PIPE_USAGE_DYNAMIC ||
- no_transfer) &&
- pt->flags & NVFX_RESOURCE_FLAG_LINEAR)
+ if((usage & (PIPE_TRANSFER_UNSYNCHRONIZED | PIPE_TRANSFER_DONTBLOCK)) == PIPE_TRANSFER_DONTBLOCK)
+ {
+ struct nouveau_bo* bo = ((struct nvfx_resource*)pt)->bo;
+ if(bo && nouveau_bo_busy(bo, NOUVEAU_BO_WR))
+ return NULL;
+ }
+
+ if(pt->target == PIPE_BUFFER)
{
- tx->direct = true;
-
- /* XXX: just call the internal nvfx function.
- */
- tx->surface = pscreen->get_tex_surface(pscreen, pt,
- sr.face, sr.level,
- box->z,
- bind);
- return &tx->base;
- }
+ // it would be nice if we could avoid all this ridiculous overhead...
+ struct pipe_transfer* tx;
+ struct nvfx_buffer* buffer = nvfx_buffer(pt);
+
+ tx = CALLOC_STRUCT(pipe_transfer);
+ if (!tx)
+ return NULL;
- tx->direct = false;
+ pipe_resource_reference(&tx->resource, pt);
+ tx->sr = sr;
+ tx->usage = usage;
+ tx->box = *box;
- nvfx_compatible_transfer_tex(pt, box->width, box->height, bind, &tx_tex_template);
+ tx->slice_stride = tx->stride = util_format_get_stride(pt->format, box->width);
+ tx->data = buffer->data + util_format_get_stride(pt->format, box->x);
- tx_tex = pscreen->resource_create(pscreen, &tx_tex_template);
- if (!tx_tex)
+ return tx;
+ }
+ else
{
- FREE(tx);
- return NULL;
+ struct nvfx_staging_transfer* tx;
+ bool direct = !nvfx_resource_on_gpu(pt) && pt->flags & NVFX_RESOURCE_FLAG_LINEAR;
+
+ tx = CALLOC_STRUCT(nvfx_staging_transfer);
+ if(!tx)
+ return NULL;
+
+ util_staging_transfer_init(pipe, pt, sr, usage, box, direct, &tx->base);
+
+ if(direct)
+ {
+ tx->base.base.stride = nvfx_subresource_pitch(pt, sr.level);
+ tx->base.base.slice_stride = tx->base.base.stride * u_minify(pt->height0, sr.level);
+ tx->offset = nvfx_subresource_offset(pt, sr.face, sr.level, box->z)
+ + util_format_get_2d_size(pt->format, tx->base.base.stride, box->y)
+ + util_format_get_stride(pt->format, box->x);
+ }
+ else
+ {
+ tx->base.base.stride = nvfx_subresource_pitch(tx->base.staging_resource, 0);
+ tx->base.base.slice_stride = tx->base.base.stride * tx->base.staging_resource->height0;
+ tx->offset = 0;
+ }
+
+ assert(tx->base.base.stride);
+
+ return &tx->base.base;
}
+}
- tx->base.stride = ((struct nvfx_miptree*)tx_tex)->level[0].pitch;
-
- tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
- 0, 0, 0,
- bind);
-
- pipe_resource_reference(&tx_tex, NULL);
-
- if (!tx->surface)
+static void nvfx_buffer_dirty_interval(struct nvfx_buffer* buffer, unsigned begin, unsigned size, boolean unsynchronized)
+{
+ struct nvfx_screen* screen = nvfx_screen(buffer->base.base.screen);
+ buffer->last_update_static = buffer->bytes_to_draw_until_static < 0;
+ if(buffer->dirty_begin == buffer->dirty_end)
{
- pipe_surface_reference(&tx->surface, NULL);
- FREE(tx);
- return NULL;
+ buffer->dirty_begin = begin;
+ buffer->dirty_end = begin + size;
+ buffer->dirty_unsynchronized = unsynchronized;
+ }
+ else
+ {
+ buffer->dirty_begin = MIN2(buffer->dirty_begin, begin);
+ buffer->dirty_end = MAX2(buffer->dirty_end, begin + size);
+ buffer->dirty_unsynchronized &= unsynchronized;
}
- if (usage & PIPE_TRANSFER_READ) {
- struct nvfx_screen *nvscreen = nvfx_screen(pscreen);
- struct pipe_surface *src;
+ if(unsynchronized)
+ {
+ // TODO: revisit this, it doesn't seem quite right
+ //printf("UNSYNC UPDATE %p %u %u\n", buffer, begin, size);
+ buffer->bytes_to_draw_until_static += size * screen->static_reuse_threshold;
+ }
+ else
+ buffer->bytes_to_draw_until_static = buffer->size * screen->static_reuse_threshold;
+}
- src = pscreen->get_tex_surface(pscreen, pt,
- sr.face, sr.level, box->z,
- 0 /*PIPE_BIND_BLIT_SOURCE*/);
+static void nvfx_transfer_flush_region( struct pipe_context *pipe,
+ struct pipe_transfer *ptx,
+ const struct pipe_box *box)
+{
+ if(ptx->resource->target == PIPE_BUFFER && (ptx->usage & PIPE_TRANSFER_FLUSH_EXPLICIT))
+ {
+ struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource);
+ nvfx_buffer_dirty_interval(buffer,
+ (uint8_t*)ptx->data - buffer->data + util_format_get_stride(buffer->base.base.format, box->x),
+ util_format_get_stride(buffer->base.base.format, box->width),
+ !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED));
+ }
+}
- /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
- /* TODO: Check if SIFM can un-swizzle */
- nvscreen->eng2d->copy(nvscreen->eng2d,
- tx->surface, 0, 0,
- src,
- box->x, box->y,
- box->width, box->height);
+static void
+nvfx_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *ptx)
+{
+ if(ptx->resource->target == PIPE_BUFFER)
+ {
+ struct nvfx_buffer* buffer = nvfx_buffer(ptx->resource);
+ if((ptx->usage & (PIPE_TRANSFER_WRITE | PIPE_TRANSFER_FLUSH_EXPLICIT)) == PIPE_TRANSFER_WRITE)
+ nvfx_buffer_dirty_interval(buffer,
+ (uint8_t*)ptx->data - buffer->data,
+ ptx->stride,
+ !!(ptx->usage & PIPE_TRANSFER_UNSYNCHRONIZED));
+ pipe_resource_reference(&ptx->resource, 0);
+ FREE(ptx);
+ }
+ else
+ {
+ struct nouveau_channel* chan = nvfx_context(pipe)->screen->base.channel;
+ util_staging_transfer_destroy(pipe, ptx);
- pipe_surface_reference(&src, NULL);
+ FIRE_RING(chan);
}
+}
- return &tx->base;
+void *
+nvfx_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
+{
+ if(ptx->resource->target == PIPE_BUFFER)
+ return ptx->data;
+ else
+ {
+ struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx;
+ if(!ptx->data)
+ {
+ struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource;
+ uint8_t *map = nouveau_screen_bo_map(pipe->screen, mt->base.bo, nouveau_screen_transfer_flags(ptx->usage));
+ ptx->data = map + tx->offset;
+ }
+
+ ++tx->map_count;
+ return ptx->data;
+ }
}
void
-nvfx_miptree_transfer_del(struct pipe_context *pipe,
- struct pipe_transfer *ptx)
+nvfx_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx)
{
- struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
-
- if (!tx->direct && (ptx->usage & PIPE_TRANSFER_WRITE)) {
- struct pipe_screen *pscreen = pipe->screen;
- struct nvfx_screen *nvscreen = nvfx_screen(pscreen);
- struct pipe_surface *dst;
-
- dst = pscreen->get_tex_surface(pscreen,
- ptx->resource,
- ptx->sr.face,
- ptx->sr.level,
- ptx->box.z,
- 0 /*PIPE_BIND_BLIT_DESTINATION*/);
-
- /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
- nvscreen->eng2d->copy(nvscreen->eng2d,
- dst, ptx->box.x, ptx->box.y,
- tx->surface, 0, 0,
- ptx->box.width, ptx->box.height);
-
- pipe_surface_reference(&dst, NULL);
+ if(ptx->resource->target != PIPE_BUFFER)
+ {
+ struct nvfx_staging_transfer *tx = (struct nvfx_staging_transfer *)ptx;
+ struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->base.staging_resource;
+
+ if(!--tx->map_count)
+ {
+ nouveau_screen_bo_unmap(pipe->screen, mt->base.bo);
+ ptx->data = 0;
+ }
}
-
- pipe_surface_reference(&tx->surface, NULL);
- pipe_resource_reference(&ptx->resource, NULL);
- FREE(ptx);
}
-void *
-nvfx_miptree_transfer_map(struct pipe_context *pipe, struct pipe_transfer *ptx)
+static void nvfx_transfer_inline_write( struct pipe_context *pipe,
+ struct pipe_resource *pr,
+ struct pipe_subresource sr,
+ unsigned usage,
+ const struct pipe_box *box,
+ const void *data,
+ unsigned stride,
+ unsigned slice_stride)
{
- struct pipe_screen *pscreen = pipe->screen;
- struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
- struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
- struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
- uint8_t *map = nouveau_screen_bo_map(pscreen, mt->base.bo,
- nouveau_screen_transfer_flags(ptx->usage));
-
- if(!tx->direct)
- return map + ns->base.offset;
+ if(pr->target != PIPE_BUFFER)
+ {
+ u_default_transfer_inline_write(pipe, pr, sr, usage, box, data, stride, slice_stride);
+ }
else
- return (map + ns->base.offset +
- ptx->box.y * ns->pitch +
- ptx->box.x * util_format_get_blocksize(ptx->resource->format));
+ {
+ struct nvfx_buffer* buffer = nvfx_buffer(pr);
+ unsigned begin = util_format_get_stride(pr->format, box->x);
+ unsigned size = util_format_get_stride(pr->format, box->width);
+ memcpy(buffer->data + begin, data, size);
+ nvfx_buffer_dirty_interval(buffer, begin, size,
+ !!(pr->flags & PIPE_TRANSFER_UNSYNCHRONIZED));
+ }
}
void
-nvfx_miptree_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *ptx)
+nvfx_init_transfer_functions(struct pipe_context *pipe)
{
- struct pipe_screen *pscreen = pipe->screen;
- struct nvfx_transfer *tx = (struct nvfx_transfer *)ptx;
- struct nvfx_miptree *mt = (struct nvfx_miptree *)tx->surface->texture;
-
- nouveau_screen_bo_unmap(pscreen, mt->base.bo);
+ pipe->get_transfer = nvfx_transfer_new;
+ pipe->transfer_map = nvfx_transfer_map;
+ pipe->transfer_flush_region = nvfx_transfer_flush_region;
+ pipe->transfer_unmap = nvfx_transfer_unmap;
+ pipe->transfer_destroy = nvfx_transfer_destroy;
+ pipe->transfer_inline_write = nvfx_transfer_inline_write;
}