X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fsvga%2Fsvga_draw.c;h=6de233888f6f32e16e9f735c2fec9cf4c7885580;hb=28feb63580e94085dd47d5391f9f6f20d69eea6c;hp=0b9ea889afabe0fa99f222734f9bed7e7e249ff5;hpb=2c3f95d6aaab38cd66dd3dee1b089d5c91928eea;p=mesa.git diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c index 0b9ea889afa..6de233888f6 100644 --- a/src/gallium/drivers/svga/svga_draw.c +++ b/src/gallium/drivers/svga/svga_draw.c @@ -134,8 +134,25 @@ void svga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl, unsigned count, struct pipe_vertex_buffer *buffers) { - util_set_vertex_buffers_count(hwtnl->cmd.vbufs, - &hwtnl->cmd.vbuf_count, buffers, 0, count); + struct pipe_vertex_buffer *dst = hwtnl->cmd.vbufs; + const struct pipe_vertex_buffer *src = buffers; + unsigned i; + + for (i = 0; i < count; i++) { + pipe_resource_reference(&dst[i].buffer, src[i].buffer); + dst[i].user_buffer = src[i].user_buffer; + dst[i].stride = src[i].stride; + dst[i].buffer_offset = src[i].buffer_offset; + } + + /* release old buffer references */ + for ( ; i < hwtnl->cmd.vbuf_count; i++) { + pipe_resource_reference(&dst[i].buffer, NULL); + dst[i].user_buffer = NULL; /* just to be safe */ + /* don't bother zeroing stride/offset fields */ + } + + hwtnl->cmd.vbuf_count = count; } @@ -311,7 +328,7 @@ xlate_index_format(unsigned indexWidth) static enum pipe_error validate_sampler_resources(struct svga_context *svga) { - unsigned shader; + enum pipe_shader_type shader; assert(svga_have_vgpu10(svga)); @@ -376,7 +393,7 @@ validate_sampler_resources(struct svga_context *svga) static enum pipe_error validate_constant_buffers(struct svga_context *svga) { - unsigned shader; + enum pipe_shader_type shader; assert(svga_have_vgpu10(svga)); @@ -427,6 +444,32 @@ validate_constant_buffers(struct svga_context *svga) } +/** + * Was the last command put into the command buffer a drawing command? + * We use this to determine if we can skip emitting buffer re-bind + * commands when we have a sequence of drawing commands that use the + * same vertex/index buffers with no intervening commands. + * + * The first drawing command will bind the vertex/index buffers. If + * the immediately following command is also a drawing command using the + * same buffers, we shouldn't have to rebind them. + */ +static bool +last_command_was_draw(const struct svga_context *svga) +{ + switch (SVGA3D_GetLastCommand(svga->swc)) { + case SVGA_3D_CMD_DX_DRAW: + case SVGA_3D_CMD_DX_DRAW_INDEXED: + case SVGA_3D_CMD_DX_DRAW_INSTANCED: + case SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED: + case SVGA_3D_CMD_DX_DRAW_AUTO: + return true; + default: + return false; + } +} + + static enum pipe_error draw_vgpu10(struct svga_hwtnl *hwtnl, const SVGA3dPrimitiveRange *range, @@ -436,9 +479,11 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, unsigned start_instance, unsigned instance_count) { struct svga_context *svga = hwtnl->svga; - struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; + struct pipe_resource *vbuffers[SVGA3D_INPUTREG_MAX]; + struct svga_winsys_surface *vbuffer_handles[SVGA3D_INPUTREG_MAX]; struct svga_winsys_surface *ib_handle; const unsigned vbuf_count = hwtnl->cmd.vbuf_count; + int last_vbuf = -1; enum pipe_error ret; unsigned i; @@ -464,8 +509,11 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, if (ret != PIPE_OK) return ret; - /* Force rebinding the index buffer when needed */ - svga->state.hw_draw.ib = NULL; + /* No need to explicitly rebind index buffer and vertex buffers here. + * Even if the same index buffer or vertex buffers are referenced for this + * draw and we skip emitting the redundant set command, we will still + * reference the associated resources. + */ } ret = validate_sampler_resources(svga); @@ -482,16 +530,24 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, if (sbuf) { assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER); - vb_handle[i] = svga_buffer_handle(svga, &sbuf->b.b); - if (vb_handle[i] == NULL) + vbuffer_handles[i] = svga_buffer_handle(svga, &sbuf->b.b); + if (vbuffer_handles[i] == NULL) return PIPE_ERROR_OUT_OF_MEMORY; + vbuffers[i] = &sbuf->b.b; + last_vbuf = i; } else { - vb_handle[i] = NULL; + vbuffers[i] = NULL; + vbuffer_handles[i] = NULL; } } - /* Get handles for the index buffers */ + for (; i < svga->state.hw_draw.num_vbuffers; i++) { + vbuffers[i] = NULL; + vbuffer_handles[i] = NULL; + } + + /* Get handle for the index buffer */ if (ib) { struct svga_buffer *sbuf = svga_buffer(ib); @@ -518,33 +574,74 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, /* setup vertex buffers */ { - SVGA3dVertexBuffer buffers[PIPE_MAX_ATTRIBS]; + SVGA3dVertexBuffer vbuffer_attrs[PIPE_MAX_ATTRIBS]; for (i = 0; i < vbuf_count; i++) { - buffers[i].stride = hwtnl->cmd.vbufs[i].stride; - buffers[i].offset = hwtnl->cmd.vbufs[i].buffer_offset; + vbuffer_attrs[i].stride = hwtnl->cmd.vbufs[i].stride; + vbuffer_attrs[i].offset = hwtnl->cmd.vbufs[i].buffer_offset; + vbuffer_attrs[i].sid = 0; } - if (vbuf_count > 0) { - /* If we haven't yet emitted a drawing command or if any - * vertex buffer state is changing, issue that state now. + + /* If we haven't yet emitted a drawing command or if any + * vertex buffer state is changing, issue that state now. + */ + if (((hwtnl->cmd.swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) == 0) || + vbuf_count != svga->state.hw_draw.num_vbuffers || + memcmp(vbuffer_attrs, svga->state.hw_draw.vbuffer_attrs, + vbuf_count * sizeof(vbuffer_attrs[0])) || + memcmp(vbuffers, svga->state.hw_draw.vbuffers, + vbuf_count * sizeof(vbuffers[0]))) { + + unsigned num_vbuffers; + + /* get the max of the current bound vertex buffers count and + * the to-be-bound vertex buffers count, so as to unbind + * the unused vertex buffers. */ - if (((hwtnl->cmd.swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) == 0) || - vbuf_count != svga->state.hw_draw.num_vbuffers || - memcmp(buffers, svga->state.hw_draw.vbuffers, - vbuf_count * sizeof(buffers[0])) || - memcmp(vb_handle, svga->state.hw_draw.vbuffer_handles, - vbuf_count * sizeof(vb_handle[0]))) { - ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, vbuf_count, + num_vbuffers = MAX2(vbuf_count, svga->state.hw_draw.num_vbuffers); + + /* Zero-out the old buffers we want to unbind (the number of loop + * iterations here is typically very small, and often zero.) + */ + for (i = vbuf_count; i < num_vbuffers; i++) { + vbuffer_attrs[i].sid = 0; + vbuffer_attrs[i].stride = 0; + vbuffer_attrs[i].offset = 0; + vbuffer_handles[i] = NULL; + } + + if (num_vbuffers > 0) { + + ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, num_vbuffers, 0, /* startBuffer */ - buffers, vb_handle); + vbuffer_attrs, + vbuffer_handles); if (ret != PIPE_OK) return ret; - svga->state.hw_draw.num_vbuffers = vbuf_count; - memcpy(svga->state.hw_draw.vbuffers, buffers, - vbuf_count * sizeof(buffers[0])); - memcpy(svga->state.hw_draw.vbuffer_handles, vb_handle, - vbuf_count * sizeof(vb_handle[0])); + /* save the number of vertex buffers sent to the device, not + * including trailing unbound vertex buffers. + */ + svga->state.hw_draw.num_vbuffers = last_vbuf + 1; + memcpy(svga->state.hw_draw.vbuffer_attrs, vbuffer_attrs, + num_vbuffers * sizeof(vbuffer_attrs[0])); + for (i = 0; i < num_vbuffers; i++) { + pipe_resource_reference(&svga->state.hw_draw.vbuffers[i], + vbuffers[i]); + } + } + } + else { + /* Even though we can avoid emitting the redundant SetVertexBuffers + * command, we still need to reference the vertex buffers surfaces. + */ + for (i = 0; i < vbuf_count; i++) { + if (vbuffer_handles[i] && !last_command_was_draw(svga)) { + ret = svga->swc->resource_rebind(svga->swc, vbuffer_handles[i], + NULL, SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } } } } @@ -563,18 +660,32 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth); /* setup index buffer */ - if (ib_handle != svga->state.hw_draw.ib || + if (ib != svga->state.hw_draw.ib || indexFormat != svga->state.hw_draw.ib_format || range->indexArray.offset != svga->state.hw_draw.ib_offset) { + + assert(indexFormat != SVGA3D_FORMAT_INVALID); ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle, indexFormat, range->indexArray.offset); if (ret != PIPE_OK) return ret; - svga->state.hw_draw.ib = ib_handle; + + pipe_resource_reference(&svga->state.hw_draw.ib, ib); svga->state.hw_draw.ib_format = indexFormat; svga->state.hw_draw.ib_offset = range->indexArray.offset; } + else { + /* Even though we can avoid emitting the redundant SetIndexBuffer + * command, we still need to reference the index buffer surface. + */ + if (!last_command_was_draw(svga)) { + ret = svga->swc->resource_rebind(svga->swc, ib_handle, + NULL, SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } + } if (instance_count > 1) { ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc, @@ -598,16 +709,19 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, } else { /* non-indexed drawing */ - if (svga->state.hw_draw.ib_format != SVGA3D_FORMAT_INVALID) { + if (svga->state.hw_draw.ib_format != SVGA3D_FORMAT_INVALID || + svga->state.hw_draw.ib != NULL) { /* Unbind previously bound index buffer */ ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, NULL, SVGA3D_FORMAT_INVALID, 0); if (ret != PIPE_OK) return ret; + pipe_resource_reference(&svga->state.hw_draw.ib, NULL); svga->state.hw_draw.ib_format = SVGA3D_FORMAT_INVALID; - svga->state.hw_draw.ib = NULL; } + assert(svga->state.hw_draw.ib == NULL); + if (instance_count > 1) { ret = SVGA3D_vgpu10_DrawInstanced(svga->swc, vcount, @@ -644,11 +758,17 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, enum pipe_error svga_hwtnl_flush(struct svga_hwtnl *hwtnl) { + enum pipe_error ret = PIPE_OK; + + SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLFLUSH); + if (!svga_have_vgpu10(hwtnl->svga) && hwtnl->cmd.prim_count) { /* we only queue up primitive for VGPU9 */ - return draw_vgpu9(hwtnl); + ret = draw_vgpu9(hwtnl); } - return PIPE_OK; + + SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws); + return ret; } @@ -769,17 +889,14 @@ check_draw_params(struct svga_hwtnl *hwtnl, assert(range->indexWidth == range->indexArray.stride); if (ib) { - unsigned size = ib->width0; - unsigned offset = range->indexArray.offset; - unsigned stride = range->indexArray.stride; - unsigned count; + MAYBE_UNUSED unsigned size = ib->width0; + MAYBE_UNUSED unsigned offset = range->indexArray.offset; + MAYBE_UNUSED unsigned stride = range->indexArray.stride; + MAYBE_UNUSED unsigned count; assert(size); assert(offset < size); assert(stride); - (void) size; - (void) offset; - (void) stride; switch (range->primType) { case SVGA3D_PRIMITIVE_POINTLIST: @@ -825,6 +942,8 @@ svga_hwtnl_prim(struct svga_hwtnl *hwtnl, { enum pipe_error ret = PIPE_OK; + SVGA_STATS_TIME_PUSH(svga_sws(hwtnl->svga), SVGA_STATS_TIME_HWTNLPRIM); + if (svga_have_vgpu10(hwtnl->svga)) { /* draw immediately */ ret = draw_vgpu10(hwtnl, range, vcount, min_index, max_index, ib, @@ -849,7 +968,7 @@ svga_hwtnl_prim(struct svga_hwtnl *hwtnl, if (hwtnl->cmd.prim_count + 1 >= QSZ) { ret = svga_hwtnl_flush(hwtnl); if (ret != PIPE_OK) - return ret; + goto done; } /* min/max indices are relative to bias */ @@ -863,5 +982,7 @@ svga_hwtnl_prim(struct svga_hwtnl *hwtnl, hwtnl->cmd.prim_count++; } +done: + SVGA_STATS_TIME_POP(svga_screen(hwtnl->svga->pipe.screen)->sws); return ret; }