nvc0: implement clear_buffer
Provide an accelerated path for ARB_clear_buffer_object Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann@mni.thm.de> Reviewed-by: Ilia Mirkin <imirkin@alum.mit.edu>
This commit is contained in:

committed by
Ilia Mirkin

parent
4c7bf8a704
commit
a26e2bc2e3
@@ -344,6 +344,146 @@ nvc0_clear_render_target(struct pipe_context *pipe,
|
||||
nvc0->dirty |= NVC0_NEW_FRAMEBUFFER;
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_clear_buffer_cpu(struct pipe_context *pipe,
|
||||
struct pipe_resource *res,
|
||||
unsigned offset, unsigned size,
|
||||
const void *data, int data_size)
|
||||
{
|
||||
struct nv04_resource *buf = nv04_resource(res);
|
||||
struct pipe_transfer *pt;
|
||||
struct pipe_box box;
|
||||
unsigned elements, i;
|
||||
|
||||
elements = size / data_size;
|
||||
|
||||
u_box_1d(offset, size, &box);
|
||||
|
||||
uint8_t *map = buf->vtbl->transfer_map(pipe, res, 0, PIPE_TRANSFER_WRITE,
|
||||
&box, &pt);
|
||||
|
||||
for (i = 0; i < elements; ++i)
|
||||
memcpy(&map[i*data_size], data, data_size);
|
||||
|
||||
buf->vtbl->transfer_unmap(pipe, pt);
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_clear_buffer(struct pipe_context *pipe,
|
||||
struct pipe_resource *res,
|
||||
unsigned offset, unsigned size,
|
||||
const void *data, int data_size)
|
||||
{
|
||||
struct nvc0_context *nvc0 = nvc0_context(pipe);
|
||||
struct nouveau_pushbuf *push = nvc0->base.pushbuf;
|
||||
struct nv04_resource *buf = nv04_resource(res);
|
||||
union pipe_color_union color;
|
||||
enum pipe_format dst_fmt;
|
||||
unsigned width, height, elements;
|
||||
|
||||
assert(res->target == PIPE_BUFFER);
|
||||
assert(nouveau_bo_memtype(buf->bo) == 0);
|
||||
|
||||
switch (data_size) {
|
||||
case 16:
|
||||
dst_fmt = PIPE_FORMAT_R32G32B32A32_UINT;
|
||||
memcpy(&color.ui, data, 16);
|
||||
break;
|
||||
case 12:
|
||||
/* This doesn't work, RGB32 is not a valid RT format.
|
||||
* dst_fmt = PIPE_FORMAT_R32G32B32_UINT;
|
||||
* memcpy(&color.ui, data, 12);
|
||||
* memset(&color.ui[3], 0, 4);
|
||||
*/
|
||||
break;
|
||||
case 8:
|
||||
dst_fmt = PIPE_FORMAT_R32G32_UINT;
|
||||
memcpy(&color.ui, data, 8);
|
||||
memset(&color.ui[2], 0, 8);
|
||||
break;
|
||||
case 4:
|
||||
dst_fmt = PIPE_FORMAT_R32_UINT;
|
||||
memcpy(&color.ui, data, 4);
|
||||
memset(&color.ui[1], 0, 12);
|
||||
break;
|
||||
case 2:
|
||||
dst_fmt = PIPE_FORMAT_R16_UINT;
|
||||
color.ui[0] = util_cpu_to_le32(
|
||||
util_le16_to_cpu(*(unsigned short *)data));
|
||||
memset(&color.ui[1], 0, 12);
|
||||
break;
|
||||
case 1:
|
||||
dst_fmt = PIPE_FORMAT_R8_UINT;
|
||||
color.ui[0] = util_cpu_to_le32(*(unsigned char *)data);
|
||||
memset(&color.ui[1], 0, 12);
|
||||
break;
|
||||
default:
|
||||
assert(!"Unsupported element size");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(size % data_size == 0);
|
||||
|
||||
if (data_size == 12) {
|
||||
/* TODO: Find a way to do this with the GPU! */
|
||||
nvc0_clear_buffer_cpu(pipe, res, offset, size, data, data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
elements = size / data_size;
|
||||
height = (elements + 16383) / 16384;
|
||||
width = elements / height;
|
||||
|
||||
if (!PUSH_SPACE(push, 40))
|
||||
return;
|
||||
|
||||
PUSH_REFN (push, buf->bo, buf->domain | NOUVEAU_BO_WR);
|
||||
|
||||
BEGIN_NVC0(push, NVC0_3D(CLEAR_COLOR(0)), 4);
|
||||
PUSH_DATAf(push, color.f[0]);
|
||||
PUSH_DATAf(push, color.f[1]);
|
||||
PUSH_DATAf(push, color.f[2]);
|
||||
PUSH_DATAf(push, color.f[3]);
|
||||
BEGIN_NVC0(push, NVC0_3D(SCREEN_SCISSOR_HORIZ), 2);
|
||||
PUSH_DATA (push, width << 16);
|
||||
PUSH_DATA (push, height << 16);
|
||||
|
||||
IMMED_NVC0(push, NVC0_3D(RT_CONTROL), 1);
|
||||
|
||||
BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(0)), 9);
|
||||
PUSH_DATAh(push, buf->address + offset);
|
||||
PUSH_DATA (push, buf->address + offset);
|
||||
PUSH_DATA (push, width * data_size);
|
||||
PUSH_DATA (push, height);
|
||||
PUSH_DATA (push, nvc0_format_table[dst_fmt].rt);
|
||||
PUSH_DATA (push, NVC0_3D_RT_TILE_MODE_LINEAR);
|
||||
PUSH_DATA (push, 1);
|
||||
PUSH_DATA (push, 0);
|
||||
PUSH_DATA (push, 0);
|
||||
|
||||
IMMED_NVC0(push, NVC0_3D(ZETA_ENABLE), 0);
|
||||
|
||||
IMMED_NVC0(push, NVC0_3D(CLEAR_BUFFERS), 0x3c);
|
||||
|
||||
if (width * height != elements) {
|
||||
offset += width * height * data_size;
|
||||
width = elements - width * height;
|
||||
height = 1;
|
||||
|
||||
BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(0)), 4);
|
||||
PUSH_DATAh(push, buf->address + offset);
|
||||
PUSH_DATA (push, buf->address + offset);
|
||||
PUSH_DATA (push, width * data_size);
|
||||
PUSH_DATA (push, height);
|
||||
|
||||
IMMED_NVC0(push, NVC0_3D(CLEAR_BUFFERS), 0x3c);
|
||||
}
|
||||
|
||||
nouveau_fence_ref(nvc0->screen->base.fence.current, &buf->fence);
|
||||
nouveau_fence_ref(nvc0->screen->base.fence.current, &buf->fence_wr);
|
||||
nvc0->dirty |= NVC0_NEW_FRAMEBUFFER;
|
||||
}
|
||||
|
||||
static void
|
||||
nvc0_clear_depth_stencil(struct pipe_context *pipe,
|
||||
struct pipe_surface *dst,
|
||||
@@ -1363,4 +1503,5 @@ nvc0_init_surface_functions(struct nvc0_context *nvc0)
|
||||
pipe->flush_resource = nvc0_flush_resource;
|
||||
pipe->clear_render_target = nvc0_clear_render_target;
|
||||
pipe->clear_depth_stencil = nvc0_clear_depth_stencil;
|
||||
pipe->clear_buffer = nvc0_clear_buffer;
|
||||
}
|
||||
|
Reference in New Issue
Block a user