summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nvfx/nvfx_surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/nvfx/nvfx_surface.c')
-rw-r--r--src/gallium/drivers/nvfx/nvfx_surface.c121
1 files changed, 109 insertions, 12 deletions
diff --git a/src/gallium/drivers/nvfx/nvfx_surface.c b/src/gallium/drivers/nvfx/nvfx_surface.c
index a97f342c646..8208c67f2a2 100644
--- a/src/gallium/drivers/nvfx/nvfx_surface.c
+++ b/src/gallium/drivers/nvfx/nvfx_surface.c
@@ -94,23 +94,44 @@ nvfx_region_fixup_swizzled(struct nv04_region* rgn, unsigned zslice, unsigned wi
}
static INLINE void
-nvfx_region_init_for_surface(struct nv04_region* rgn, struct nvfx_surface* surf, unsigned x, unsigned y)
+nvfx_region_init_for_surface(struct nv04_region* rgn, struct nvfx_surface* surf, unsigned x, unsigned y, bool for_write)
{
- rgn->bo = ((struct nvfx_resource*)surf->base.texture)->bo;
- rgn->offset = surf->base.offset;
- rgn->pitch = surf->pitch;
rgn->x = x;
rgn->y = y;
rgn->z = 0;
+ nvfx_region_set_format(rgn, surf->base.base.format);
- nvfx_region_set_format(rgn, surf->base.format);
- if(!(surf->base.texture->flags & NVFX_RESOURCE_FLAG_LINEAR))
- nvfx_region_fixup_swizzled(rgn, surf->base.zslice, surf->base.width, surf->base.height, u_minify(surf->base.texture->depth0, surf->base.level));
+ if(surf->temp)
+ {
+ rgn->bo = surf->temp->base.bo;
+ rgn->offset = 0;
+ rgn->pitch = surf->temp->linear_pitch;
+
+ if(for_write)
+ util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(&surf->base.base), &surf->base);
+ } else {
+ rgn->bo = ((struct nvfx_resource*)surf->base.base.texture)->bo;
+ rgn->offset = surf->base.base.offset;
+ rgn->pitch = surf->pitch;
+
+ if(!(surf->base.base.texture->flags & NVFX_RESOURCE_FLAG_LINEAR))
+ nvfx_region_fixup_swizzled(rgn, surf->base.base.zslice, surf->base.base.width, surf->base.base.height, u_minify(surf->base.base.texture->depth0, surf->base.base.level));
+ }
}
static INLINE void
-nvfx_region_init_for_subresource(struct nv04_region* rgn, struct pipe_resource* pt, struct pipe_subresource sub, unsigned x, unsigned y, unsigned z)
+nvfx_region_init_for_subresource(struct nv04_region* rgn, struct pipe_resource* pt, struct pipe_subresource sub, unsigned x, unsigned y, unsigned z, bool for_write)
{
+ if(pt->target != PIPE_BUFFER)
+ {
+ struct nvfx_surface* ns = (struct nvfx_surface*)util_surfaces_peek(&((struct nvfx_miptree*)pt)->surfaces, pt, sub.face, sub.level, z);
+ if(ns && util_dirty_surface_is_dirty(&ns->base))
+ {
+ nvfx_region_init_for_surface(rgn, ns, x, y, for_write);
+ return;
+ }
+ }
+
rgn->bo = ((struct nvfx_resource*)pt)->bo;
rgn->offset = nvfx_subresource_offset(pt, sub.face, sub.level, z);
rgn->pitch = nvfx_subresource_pitch(pt, sub.level);
@@ -165,6 +186,7 @@ nv04_scaled_image_format(enum pipe_format format)
}
}
+// XXX: must save index buffer too!
static struct blitter_context*
nvfx_get_blitter(struct pipe_context* pipe, int copy)
{
@@ -237,8 +259,8 @@ nvfx_resource_copy_region(struct pipe_context *pipe,
int dst_to_gpu = dstr->usage != PIPE_USAGE_DYNAMIC && dstr->usage != PIPE_USAGE_STAGING;
int src_on_gpu = nvfx_resource_on_gpu(srcr);
- nvfx_region_init_for_subresource(&dst, dstr, subdst, dstx, dsty, dstz);
- nvfx_region_init_for_subresource(&src, srcr, subsrc, srcx, srcy, srcz);
+ nvfx_region_init_for_subresource(&dst, dstr, subdst, dstx, dsty, dstz, TRUE);
+ nvfx_region_init_for_subresource(&src, srcr, subsrc, srcx, srcy, srcz, FALSE);
w = util_format_get_stride(dstr->format, w) >> dst.bpps;
h = util_format_get_nblocksy(dstr->format, h);
@@ -293,10 +315,11 @@ nvfx_surface_fill(struct pipe_context* pipe, struct pipe_surface *dsts,
struct nv04_2d_context *ctx = nvfx_screen(pipe->screen)->eng2d;
struct nv04_region dst;
/* Always try to use the GPU right now, if possible
- * If the user wanted the surface data on the CPU, he would have cleared with memset */
+ * If the user wanted the surface data on the CPU, he would have cleared with memset (hopefully) */
// we don't care about interior pixel order since we set all them to the same value
- nvfx_region_init_for_surface(&dst, (struct nvfx_surface*)dsts, dx, dy);
+ nvfx_region_init_for_surface(&dst, (struct nvfx_surface*)dsts, dx, dy, TRUE);
+
w = util_format_get_stride(dsts->format, w) >> dst.bpps;
h = util_format_get_nblocksy(dsts->format, h);
@@ -342,6 +365,80 @@ nvfx_screen_surface_init(struct pipe_screen *pscreen)
}
static void
+nvfx_surface_copy_temp(struct pipe_context* pipe, struct pipe_surface* surf, int to_temp)
+{
+ struct nvfx_surface* ns = (struct nvfx_surface*)surf;
+ struct pipe_subresource tempsr, surfsr;
+ struct pipe_resource *idxbuf_buffer;
+ unsigned idxbuf_format;
+
+ tempsr.face = 0;
+ tempsr.level = 0;
+ surfsr.face = surf->face;
+ surfsr.level = surf->level;
+
+ // TODO: do this properly, in blitter save
+ idxbuf_buffer = ((struct nvfx_context*)pipe)->idxbuf_buffer;
+ idxbuf_format = ((struct nvfx_context*)pipe)->idxbuf_format;
+
+ if(to_temp)
+ nvfx_resource_copy_region(pipe, &ns->temp->base.base, tempsr, 0, 0, 0, surf->texture, surfsr, 0, 0, surf->zslice, surf->width, surf->height);
+ else
+ nvfx_resource_copy_region(pipe, surf->texture, surfsr, 0, 0, surf->zslice, &ns->temp->base.base, tempsr, 0, 0, 0, surf->width, surf->height);
+
+ ((struct nvfx_context*)pipe)->idxbuf_buffer = idxbuf_buffer;
+ ((struct nvfx_context*)pipe)->idxbuf_format = idxbuf_format;
+}
+
+void
+nvfx_surface_create_temp(struct pipe_context* pipe, struct pipe_surface* surf)
+{
+ struct nvfx_surface* ns = (struct nvfx_surface*)surf;
+ struct pipe_resource template;
+ memset(&template, 0, sizeof(struct pipe_resource));
+ template.target = PIPE_TEXTURE_2D;
+ template.format = surf->format;
+ template.width0 = surf->width;
+ template.height0 = surf->height;
+ template.depth0 = 1;
+ template.nr_samples = surf->texture->nr_samples;
+ template.flags = NVFX_RESOURCE_FLAG_LINEAR;
+
+ ns->temp = (struct nvfx_miptree*)nvfx_miptree_create(pipe->screen, &template);
+ nvfx_surface_copy_temp(pipe, surf, 1);
+}
+
+void
+nvfx_surface_flush(struct pipe_context* pipe, struct pipe_surface* surf)
+{
+ struct nvfx_context* nvfx = (struct nvfx_context*)pipe;
+ struct nvfx_surface* ns = (struct nvfx_surface*)surf;
+ boolean bound = FALSE;
+
+ /* must be done before the copy, otherwise the copy will use the temp as destination */
+ util_dirty_surface_set_clean(nvfx_surface_get_dirty_surfaces(surf), &ns->base);
+
+ nvfx_surface_copy_temp(pipe, surf, 0);
+
+ if(nvfx->framebuffer.zsbuf == surf)
+ bound = TRUE;
+ else
+ {
+ for(unsigned i = 0; i < nvfx->framebuffer.nr_cbufs; ++i)
+ {
+ if(nvfx->framebuffer.cbufs[i] == surf)
+ {
+ bound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if(!bound)
+ pipe_resource_reference((struct pipe_resource**)&ns->temp, 0);
+}
+
+static void
nvfx_clear_render_target(struct pipe_context *pipe,
struct pipe_surface *dst,
const float *rgba,