diff options
author | Ilia Mirkin <[email protected]> | 2014-03-25 17:03:29 -0400 |
---|---|---|
committer | Ilia Mirkin <[email protected]> | 2014-03-31 21:55:03 -0400 |
commit | 010171b562b0580595996e979c06a989f0b40a3c (patch) | |
tree | 60e9cdbd4f461174ed6f2f3b61153948fdc00bf2 /src/gallium/drivers/nouveau/nv50/nv50_surface.c | |
parent | f5ba1a1f7f6c50c2c1f3544555f419a0e7216a94 (diff) |
nv50: implement clear_buffer to accelerate ARB_clear_buffer_object
Signed-off-by: Ilia Mirkin <[email protected]>
Diffstat (limited to 'src/gallium/drivers/nouveau/nv50/nv50_surface.c')
-rw-r--r-- | src/gallium/drivers/nouveau/nv50/nv50_surface.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/gallium/drivers/nouveau/nv50/nv50_surface.c b/src/gallium/drivers/nouveau/nv50/nv50_surface.c index 612649bc27d..9da88c1db85 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_surface.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_surface.c @@ -476,6 +476,120 @@ nv50_clear(struct pipe_context *pipe, unsigned buffers, PUSH_DATA (push, nv50->rt_array_mode); } +static void +nv50_clear_buffer(struct pipe_context *pipe, + struct pipe_resource *res, + unsigned offset, unsigned size, + const void *data, int data_size) +{ + struct nv50_context *nv50 = nv50_context(pipe); + struct nouveau_pushbuf *push = nv50->base.pushbuf; + struct nv04_resource *buf = (struct 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 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); + + elements = size / data_size; + height = (elements + 8191) / 8192; + width = elements / height; + + BEGIN_NV04(push, NV50_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]); + + if (nouveau_pushbuf_space(push, 32, 1, 0)) + return; + + PUSH_REFN(push, buf->bo, buf->domain | NOUVEAU_BO_WR); + + BEGIN_NV04(push, NV50_3D(SCREEN_SCISSOR_HORIZ), 2); + PUSH_DATA (push, width << 16); + PUSH_DATA (push, height << 16); + BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2); + PUSH_DATA (push, 8192 << 16); + PUSH_DATA (push, 8192 << 16); + nv50->scissors_dirty |= 1; + + BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1); + PUSH_DATA (push, 1); + BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(0)), 5); + PUSH_DATAh(push, buf->bo->offset + buf->offset + offset); + PUSH_DATA (push, buf->bo->offset + buf->offset + offset); + PUSH_DATA (push, nv50_format_table[dst_fmt].rt); + PUSH_DATA (push, 0); + PUSH_DATA (push, 0); + BEGIN_NV04(push, NV50_3D(RT_HORIZ(0)), 2); + PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | (width * data_size)); + PUSH_DATA (push, height); + BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1); + PUSH_DATA (push, 0); + + /* NOTE: only works with D3D clear flag (5097/0x143c bit 4) */ + + BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2); + PUSH_DATA (push, (width << 16)); + PUSH_DATA (push, (height << 16)); + + BEGIN_NI04(push, NV50_3D(CLEAR_BUFFERS), 1); + PUSH_DATA (push, 0x3c); + + if (width * height != elements) { + offset += width * height * data_size; + width = elements - width * height; + height = 1; + BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(0)), 2); + PUSH_DATAh(push, buf->bo->offset + buf->offset + offset); + PUSH_DATA (push, buf->bo->offset + buf->offset + offset); + BEGIN_NV04(push, NV50_3D(RT_HORIZ(0)), 2); + PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | (width * data_size)); + PUSH_DATA (push, height); + BEGIN_NI04(push, NV50_3D(CLEAR_BUFFERS), 1); + PUSH_DATA (push, 0x3c); + } + + nouveau_fence_ref(nv50->screen->base.fence.current, &buf->fence); + nouveau_fence_ref(nv50->screen->base.fence.current, &buf->fence_wr); + + nv50->dirty |= NV50_NEW_FRAMEBUFFER | NV50_NEW_SCISSOR; +} /* =============================== BLIT CODE =================================== */ @@ -1403,4 +1517,5 @@ nv50_init_surface_functions(struct nv50_context *nv50) pipe->flush_resource = nv50_flush_resource; pipe->clear_render_target = nv50_clear_render_target; pipe->clear_depth_stencil = nv50_clear_depth_stencil; + pipe->clear_buffer = nv50_clear_buffer; } |