diff options
Diffstat (limited to 'src/gallium/drivers/nouveau/nvc0')
-rw-r--r-- | src/gallium/drivers/nouveau/nvc0/nvc0_surface.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c index 6b7c30ce496..ef40f876e1e 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c @@ -345,6 +345,146 @@ nvc0_clear_render_target(struct pipe_context *pipe, } 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, unsigned clear_flags, @@ -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; } |