summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/nv20
diff options
context:
space:
mode:
authorYounes Manton <younes.m@gmail.com>2009-02-25 12:55:26 -0500
committerYounes Manton <younes.m@gmail.com>2009-02-25 12:56:00 -0500
commita0dc286b5fecec1ede014cb5702368a60cbb22bc (patch)
tree7def0bcb025d1495cf41ea7aa54fca763ae60e10 /src/gallium/drivers/nv20
parent5726a5afa56e18b1662a8b03cf36c77e2d8b3114 (diff)
nouveau: nv04-nv40 texture transfer.
Diffstat (limited to 'src/gallium/drivers/nv20')
-rw-r--r--src/gallium/drivers/nv20/Makefile1
-rw-r--r--src/gallium/drivers/nv20/nv20_miptree.c69
-rw-r--r--src/gallium/drivers/nv20/nv20_screen.c28
-rw-r--r--src/gallium/drivers/nv20/nv20_screen.h4
-rw-r--r--src/gallium/drivers/nv20/nv20_state_emit.c14
-rw-r--r--src/gallium/drivers/nv20/nv20_transfer.c201
6 files changed, 256 insertions, 61 deletions
diff --git a/src/gallium/drivers/nv20/Makefile b/src/gallium/drivers/nv20/Makefile
index 93e34f8e92..1305f26c59 100644
--- a/src/gallium/drivers/nv20/Makefile
+++ b/src/gallium/drivers/nv20/Makefile
@@ -14,6 +14,7 @@ C_SOURCES = \
nv20_state.c \
nv20_state_emit.c \
nv20_surface.c \
+ nv20_transfer.c \
nv20_vbo.c
# nv20_vertprog.c
diff --git a/src/gallium/drivers/nv20/nv20_miptree.c b/src/gallium/drivers/nv20/nv20_miptree.c
index ef7e9c5428..2946240897 100644
--- a/src/gallium/drivers/nv20/nv20_miptree.c
+++ b/src/gallium/drivers/nv20/nv20_miptree.c
@@ -9,10 +9,14 @@ static void
nv20_miptree_layout(struct nv20_miptree *nv20mt)
{
struct pipe_texture *pt = &nv20mt->base;
- boolean swizzled = FALSE;
uint width = pt->width[0], height = pt->height[0];
uint offset = 0;
int nr_faces, l, f;
+ uint wide_pitch = pt->tex_usage & (PIPE_TEXTURE_USAGE_SAMPLER |
+ PIPE_TEXTURE_USAGE_DEPTH_STENCIL |
+ PIPE_TEXTURE_USAGE_RENDER_TARGET |
+ PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
+ PIPE_TEXTURE_USAGE_PRIMARY);
if (pt->target == PIPE_TEXTURE_CUBE) {
nr_faces = 6;
@@ -26,25 +30,31 @@ nv20_miptree_layout(struct nv20_miptree *nv20mt)
pt->nblocksx[l] = pf_get_nblocksx(&pt->block, width);
pt->nblocksy[l] = pf_get_nblocksy(&pt->block, height);
- if (swizzled)
- nv20mt->level[l].pitch = pt->nblocksx[l] * pt->block.size;
+ if (wide_pitch && (pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR))
+ nv20mt->level[l].pitch = align(pt->width[0] * pt->block.size, 64);
else
- nv20mt->level[l].pitch = pt->nblocksx[0] * pt->block.size;
- nv20mt->level[l].pitch = (nv20mt->level[l].pitch + 63) & ~63;
+ nv20mt->level[l].pitch = pt->width[l] * pt->block.size;
nv20mt->level[l].image_offset =
CALLOC(nr_faces, sizeof(unsigned));
width = MAX2(1, width >> 1);
height = MAX2(1, height >> 1);
-
}
for (f = 0; f < nr_faces; f++) {
- for (l = 0; l <= pt->last_level; l++) {
+ for (l = 0; l < pt->last_level; l++) {
nv20mt->level[l].image_offset[f] = offset;
- offset += nv20mt->level[l].pitch * pt->height[l];
+
+ if (!(pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR) &&
+ pt->width[l + 1] > 1 && pt->height[l + 1] > 1)
+ offset += align(nv20mt->level[l].pitch * pt->height[l], 64);
+ else
+ offset += nv20mt->level[l].pitch * pt->height[l];
}
+
+ nv20mt->level[l].image_offset[f] = offset;
+ offset += nv20mt->level[l].pitch * pt->height[l];
}
nv20mt->total_size = offset;
@@ -96,7 +106,8 @@ nv20_miptree_create(struct pipe_screen *screen, const struct pipe_texture *pt)
mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
else
if (pt->tex_usage & (PIPE_TEXTURE_USAGE_PRIMARY |
- PIPE_TEXTURE_USAGE_DISPLAY_TARGET))
+ PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
+ PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
else
if (pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC)
@@ -107,7 +118,11 @@ nv20_miptree_create(struct pipe_screen *screen, const struct pipe_texture *pt)
case PIPE_FORMAT_A8R8G8B8_UNORM:
case PIPE_FORMAT_X8R8G8B8_UNORM:
case PIPE_FORMAT_R16_SNORM:
+ {
+ if (debug_get_bool_option("NOUVEAU_NO_SWIZZLE", FALSE))
+ mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
break;
+ }
default:
mt->base.tex_usage |= NOUVEAU_TEXTURE_USAGE_LINEAR;
}
@@ -152,33 +167,33 @@ nv20_miptree_surface_get(struct pipe_screen *screen, struct pipe_texture *pt,
unsigned flags)
{
struct nv20_miptree *nv20mt = (struct nv20_miptree *)pt;
- struct pipe_surface *ps;
+ struct nv04_surface *ns;
- ps = CALLOC_STRUCT(pipe_surface);
- if (!ps)
+ ns = CALLOC_STRUCT(nv04_surface);
+ if (!ns)
return NULL;
- pipe_texture_reference(&ps->texture, pt);
- ps->format = pt->format;
- ps->width = pt->width[level];
- ps->height = pt->height[level];
- ps->block = pt->block;
- ps->nblocksx = pt->nblocksx[level];
- ps->nblocksy = pt->nblocksy[level];
- ps->stride = nv20mt->level[level].pitch;
- ps->usage = flags;
- ps->status = PIPE_SURFACE_STATUS_DEFINED;
- ps->refcount = 1;
+ pipe_texture_reference(&ns->base.texture, pt);
+ ns->base.format = pt->format;
+ ns->base.width = pt->width[level];
+ ns->base.height = pt->height[level];
+ ns->base.usage = flags;
+ ns->base.status = PIPE_SURFACE_STATUS_DEFINED;
+ ns->base.refcount = 1;
+ ns->base.face = face;
+ ns->base.level = level;
+ ns->base.zslice = zslice;
+ ns->pitch = nv20mt->level[level].pitch;
if (pt->target == PIPE_TEXTURE_CUBE) {
- ps->offset = nv20mt->level[level].image_offset[face];
+ ns->base.offset = nv20mt->level[level].image_offset[face];
} else
if (pt->target == PIPE_TEXTURE_3D) {
- ps->offset = nv20mt->level[level].image_offset[zslice];
+ ns->base.offset = nv20mt->level[level].image_offset[zslice];
} else {
- ps->offset = nv20mt->level[level].image_offset[0];
+ ns->base.offset = nv20mt->level[level].image_offset[0];
}
- return ps;
+ return &ns->base;
}
static void
diff --git a/src/gallium/drivers/nv20/nv20_screen.c b/src/gallium/drivers/nv20/nv20_screen.c
index 5f2b7b4f71..7760ae27c0 100644
--- a/src/gallium/drivers/nv20/nv20_screen.c
+++ b/src/gallium/drivers/nv20/nv20_screen.c
@@ -116,30 +116,6 @@ nv20_screen_is_format_supported(struct pipe_screen *screen,
return FALSE;
}
-static void *
-nv20_surface_map(struct pipe_screen *screen, struct pipe_surface *surface,
- unsigned flags )
-{
- struct pipe_winsys *ws = screen->winsys;
- void *map;
- struct nv20_miptree *nv20mt = (struct nv20_miptree *)surface->texture;
-
- map = ws->buffer_map(ws, nv20mt->buffer, flags);
- if (!map)
- return NULL;
-
- return map + surface->offset;
-}
-
-static void
-nv20_surface_unmap(struct pipe_screen *screen, struct pipe_surface *surface)
-{
- struct pipe_winsys *ws = screen->winsys;
- struct nv20_miptree *nv20mt = (struct nv20_miptree *)surface->texture;
-
- ws->buffer_unmap(ws, nv20mt->buffer);
-}
-
static void
nv20_screen_destroy(struct pipe_screen *pscreen)
{
@@ -211,10 +187,8 @@ nv20_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws)
screen->pipe.is_format_supported = nv20_screen_is_format_supported;
- screen->pipe.surface_map = nv20_surface_map;
- screen->pipe.surface_unmap = nv20_surface_unmap;
-
nv20_screen_init_miptree_functions(&screen->pipe);
+ nv20_screen_init_transfer_functions(&screen->pipe);
u_simple_screen_init(&screen->pipe);
return &screen->pipe;
diff --git a/src/gallium/drivers/nv20/nv20_screen.h b/src/gallium/drivers/nv20/nv20_screen.h
index bf2f2c0d9f..d9fce2bced 100644
--- a/src/gallium/drivers/nv20/nv20_screen.h
+++ b/src/gallium/drivers/nv20/nv20_screen.h
@@ -21,4 +21,8 @@ nv20_screen(struct pipe_screen *screen)
return (struct nv20_screen *)screen;
}
+
+void
+nv20_screen_init_transfer_functions(struct pipe_screen *pscreen);
+
#endif
diff --git a/src/gallium/drivers/nv20/nv20_state_emit.c b/src/gallium/drivers/nv20/nv20_state_emit.c
index 0f4df9ca31..4042f46d05 100644
--- a/src/gallium/drivers/nv20/nv20_state_emit.c
+++ b/src/gallium/drivers/nv20/nv20_state_emit.c
@@ -109,7 +109,7 @@ static void nv20_state_emit_scissor(struct nv20_context* nv20)
static void nv20_state_emit_framebuffer(struct nv20_context* nv20)
{
struct pipe_framebuffer_state* fb = nv20->framebuffer;
- struct pipe_surface *rt, *zeta = NULL;
+ struct nv04_surface *rt, *zeta = NULL;
uint32_t rt_format, w, h;
int colour_format = 0, zeta_format = 0;
struct nv20_miptree *nv20mt = 0;
@@ -117,7 +117,7 @@ static void nv20_state_emit_framebuffer(struct nv20_context* nv20)
w = fb->cbufs[0]->width;
h = fb->cbufs[0]->height;
colour_format = fb->cbufs[0]->format;
- rt = fb->cbufs[0];
+ rt = (struct nv04_surface *)fb->cbufs[0];
if (fb->zsbuf) {
if (colour_format) {
@@ -129,7 +129,7 @@ static void nv20_state_emit_framebuffer(struct nv20_context* nv20)
}
zeta_format = fb->zsbuf->format;
- zeta = fb->zsbuf;
+ zeta = (struct nv04_surface *)fb->zsbuf;
}
rt_format = NV20TCL_RT_FORMAT_TYPE_LINEAR | 0x20;
@@ -148,18 +148,18 @@ static void nv20_state_emit_framebuffer(struct nv20_context* nv20)
if (zeta) {
BEGIN_RING(kelvin, NV20TCL_RT_PITCH, 1);
- OUT_RING (rt->stride | (zeta->stride << 16));
+ OUT_RING (rt->pitch | (zeta->pitch << 16));
} else {
BEGIN_RING(kelvin, NV20TCL_RT_PITCH, 1);
- OUT_RING (rt->stride | (rt->stride << 16));
+ OUT_RING (rt->pitch | (rt->pitch << 16));
}
- nv20mt = (struct nv20_miptree *)rt->texture;
+ nv20mt = (struct nv20_miptree *)rt->base.texture;
nv20->rt[0] = nv20mt->buffer;
if (zeta_format)
{
- nv20mt = (struct nv20_miptree *)zeta->texture;
+ nv20mt = (struct nv20_miptree *)zeta->base.texture;
nv20->zeta = nv20mt->buffer;
}
diff --git a/src/gallium/drivers/nv20/nv20_transfer.c b/src/gallium/drivers/nv20/nv20_transfer.c
new file mode 100644
index 0000000000..19de09486d
--- /dev/null
+++ b/src/gallium/drivers/nv20/nv20_transfer.c
@@ -0,0 +1,201 @@
+#include <pipe/p_state.h>
+#include <pipe/p_defines.h>
+#include <pipe/p_inlines.h>
+#include <util/u_memory.h>
+#include <nouveau/nouveau_winsys.h>
+#include "nv20_context.h"
+#include "nv20_screen.h"
+#include "nv20_state.h"
+
+struct nv20_transfer {
+ struct pipe_transfer base;
+ struct pipe_surface *surface;
+ bool direct;
+};
+
+static unsigned nv20_usage_tx_to_buf(unsigned tx_usage)
+{
+ switch (tx_usage) {
+ case PIPE_TRANSFER_READ:
+ return PIPE_BUFFER_USAGE_CPU_READ;
+ case PIPE_TRANSFER_WRITE:
+ return PIPE_BUFFER_USAGE_CPU_WRITE;
+ case PIPE_TRANSFER_READ_WRITE:
+ return PIPE_BUFFER_USAGE_CPU_READ_WRITE;
+ default:
+ assert(0);
+ }
+
+ return -1;
+}
+
+static void
+nv20_compatible_transfer_tex(struct pipe_texture *pt, unsigned level,
+ struct pipe_texture *template)
+{
+ memset(template, 0, sizeof(struct pipe_texture));
+ template->target = pt->target;
+ template->format = pt->format;
+ template->width[0] = pt->width[level];
+ template->height[0] = pt->height[level];
+ template->depth[0] = 1;
+ template->block = pt->block;
+ template->nblocksx[0] = pt->nblocksx[level];
+ template->nblocksy[0] = pt->nblocksx[level];
+ template->last_level = 0;
+ template->compressed = pt->compressed;
+ template->nr_samples = pt->nr_samples;
+
+ template->tex_usage = PIPE_TEXTURE_USAGE_DYNAMIC |
+ NOUVEAU_TEXTURE_USAGE_LINEAR;
+}
+
+static struct pipe_transfer *
+nv20_transfer_new(struct pipe_screen *pscreen, struct pipe_texture *pt,
+ unsigned face, unsigned level, unsigned zslice,
+ enum pipe_transfer_usage usage,
+ unsigned x, unsigned y, unsigned w, unsigned h)
+{
+ struct nv20_miptree *mt = (struct nv20_miptree *)pt;
+ struct nv20_transfer *tx;
+ struct pipe_texture tx_tex_template, *tx_tex;
+
+ tx = CALLOC_STRUCT(nv20_transfer);
+ if (!tx)
+ return NULL;
+
+ tx->base.refcount = 1;
+ pipe_texture_reference(&tx->base.texture, pt);
+ tx->base.format = pt->format;
+ tx->base.x = x;
+ tx->base.y = y;
+ tx->base.width = w;
+ tx->base.height = h;
+ tx->base.block = pt->block;
+ tx->base.nblocksx = pt->nblocksx[level];
+ tx->base.nblocksy = pt->nblocksy[level];
+ tx->base.stride = mt->level[level].pitch;
+ tx->base.usage = usage;
+ tx->base.face = face;
+ tx->base.level = level;
+ tx->base.zslice = zslice;
+
+ /* Direct access to texture */
+ if ((pt->tex_usage & PIPE_TEXTURE_USAGE_DYNAMIC ||
+ debug_get_bool_option("NOUVEAU_NO_TRANSFER", TRUE/*XXX:FALSE*/)) &&
+ pt->tex_usage & NOUVEAU_TEXTURE_USAGE_LINEAR)
+ {
+ tx->direct = true;
+ tx->surface = pscreen->get_tex_surface(pscreen, pt,
+ face, level, zslice,
+ nv20_usage_tx_to_buf(usage));
+ return &tx->base;
+ }
+
+ tx->direct = false;
+
+ nv20_compatible_transfer_tex(pt, level, &tx_tex_template);
+
+ tx_tex = pscreen->texture_create(pscreen, &tx_tex_template);
+ if (!tx_tex)
+ {
+ FREE(tx);
+ return NULL;
+ }
+
+ tx->surface = pscreen->get_tex_surface(pscreen, tx_tex,
+ face, level, zslice,
+ nv20_usage_tx_to_buf(usage));
+
+ pipe_texture_reference(&tx_tex, NULL);
+
+ if (!tx->surface)
+ {
+ pipe_surface_reference(&tx->surface, NULL);
+ FREE(tx);
+ return NULL;
+ }
+
+ if (usage != PIPE_TRANSFER_WRITE) {
+ struct nv20_screen *nvscreen = nv20_screen(pscreen);
+ struct pipe_surface *src;
+
+ src = pscreen->get_tex_surface(pscreen, pt,
+ face, level, zslice,
+ PIPE_BUFFER_USAGE_GPU_READ);
+
+ /* 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, 0, 0,
+ src->width, src->height);
+
+ pipe_surface_reference(&src, NULL);
+ }
+
+ return &tx->base;
+}
+
+static void
+nv20_transfer_del(struct pipe_screen *pscreen, struct pipe_transfer **pptx)
+{
+ struct pipe_transfer *ptx = *pptx;
+ struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
+
+ if (!tx->direct && ptx->usage != PIPE_TRANSFER_READ) {
+ struct nv20_screen *nvscreen = nv20_screen(pscreen);
+ struct pipe_surface *dst;
+
+ dst = pscreen->get_tex_surface(pscreen, ptx->texture,
+ ptx->face, ptx->level, ptx->zslice,
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ /* TODO: Check if SIFM can deal with x,y,w,h when swizzling */
+ nvscreen->eng2d->copy(nvscreen->eng2d,
+ dst, 0, 0,
+ tx->surface, 0, 0,
+ dst->width, dst->height);
+
+ pipe_surface_reference(&dst, NULL);
+ }
+
+ *pptx = NULL;
+ if (--ptx->refcount)
+ return;
+
+ pipe_surface_reference(&tx->surface, NULL);
+ pipe_texture_reference(&ptx->texture, NULL);
+ FREE(ptx);
+}
+
+static void *
+nv20_transfer_map(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
+{
+ struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
+ struct nv04_surface *ns = (struct nv04_surface *)tx->surface;
+ struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
+ void *map = pipe_buffer_map(pscreen, mt->buffer,
+ nv20_usage_tx_to_buf(ptx->usage));
+
+ return map + ns->base.offset +
+ ptx->y * ns->pitch + ptx->x * ptx->block.size;
+}
+
+static void
+nv20_transfer_unmap(struct pipe_screen *pscreen, struct pipe_transfer *ptx)
+{
+ struct nv20_transfer *tx = (struct nv20_transfer *)ptx;
+ struct nv20_miptree *mt = (struct nv20_miptree *)tx->surface->texture;
+
+ pipe_buffer_unmap(pscreen, mt->buffer);
+}
+
+void
+nv20_screen_init_transfer_functions(struct pipe_screen *pscreen)
+{
+ pscreen->get_tex_transfer = nv20_transfer_new;
+ pscreen->tex_transfer_release = nv20_transfer_del;
+ pscreen->transfer_map = nv20_transfer_map;
+ pscreen->transfer_unmap = nv20_transfer_unmap;
+}