From 98badd7f6eaa0ac3ad3d5375f084b84172bb7582 Mon Sep 17 00:00:00 2001 From: Charmaine Lee Date: Tue, 1 Aug 2017 15:58:50 -0700 Subject: [PATCH] svga: avoid emitting redundant SetShaderResources and SetVertexBuffers Minor performance improvement in avoiding binding the same shader resource or the same vertex buffer for the same slot. Tested with MTT glretrace. v2: Per Brian's suggestion, add a helper function to do vertex buffer comparision. v3: Change the helper function to vertex_buffers_equal(). Reviewed-by: Brian Paul --- src/gallium/drivers/svga/svga_draw.c | 78 ++++++++++++++++--- src/gallium/drivers/svga/svga_state_sampler.c | 56 +++++++++++-- 2 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c index 5919bd35dae..0639d5eaebe 100644 --- a/src/gallium/drivers/svga/svga_draw.c +++ b/src/gallium/drivers/svga/svga_draw.c @@ -489,6 +489,24 @@ last_command_was_draw(const struct svga_context *svga) } +/** + * A helper function to compare vertex buffers. + * They are equal if the vertex buffer attributes and the vertex buffer + * resources are identical. + */ +static boolean +vertex_buffers_equal(unsigned count, + SVGA3dVertexBuffer *pVBufAttr1, + struct pipe_resource **pVBuf1, + SVGA3dVertexBuffer *pVBufAttr2, + struct pipe_resource **pVBuf2) +{ + return (memcmp(pVBufAttr1, pVBufAttr2, + count * sizeof(*pVBufAttr1)) == 0) && + (memcmp(pVBuf1, pVBuf2, count * sizeof(*pVBuf1)) == 0); +} + + static enum pipe_error draw_vgpu10(struct svga_hwtnl *hwtnl, const SVGA3dPrimitiveRange *range, @@ -607,10 +625,11 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, */ 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]))) { + !vertex_buffers_equal(vbuf_count, + vbuffer_attrs, + vbuffers, + svga->state.hw_draw.vbuffer_attrs, + svga->state.hw_draw.vbuffers)) { unsigned num_vbuffers; @@ -631,13 +650,52 @@ draw_vgpu10(struct svga_hwtnl *hwtnl, } if (num_vbuffers > 0) { + SVGA3dVertexBuffer *pbufAttrs = vbuffer_attrs; + struct svga_winsys_surface **pbufHandles = vbuffer_handles; + unsigned numVBuf = 0; - ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, num_vbuffers, - 0, /* startBuffer */ - vbuffer_attrs, - vbuffer_handles); - if (ret != PIPE_OK) - return ret; + /* Loop through the vertex buffer lists to only emit + * those vertex buffers that are not already in the + * corresponding entries in the device's vertex buffer list. + */ + for (i = 0; i < num_vbuffers; i++) { + boolean emit; + + emit = vertex_buffers_equal(1, + &vbuffer_attrs[i], + &vbuffers[i], + &svga->state.hw_draw.vbuffer_attrs[i], + &svga->state.hw_draw.vbuffers[i]); + + if (!emit && i == num_vbuffers-1) { + /* Include the last vertex buffer in the next emit + * if it is different. + */ + emit = TRUE; + numVBuf++; + i++; + } + + if (emit) { + /* numVBuf can only be 0 if the first vertex buffer + * is the same as the one in the device's list. + * In this case, there is nothing to send yet. + */ + if (numVBuf) { + ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, + numVBuf, + i - numVBuf, + pbufAttrs, pbufHandles); + if (ret != PIPE_OK) + return ret; + } + pbufAttrs += (numVBuf + 1); + pbufHandles += (numVBuf + 1); + numVBuf = 0; + } + else + numVBuf++; + } /* save the number of vertex buffers sent to the device, not * including trailing unbound vertex buffers. diff --git a/src/gallium/drivers/svga/svga_state_sampler.c b/src/gallium/drivers/svga/svga_state_sampler.c index c361dba676a..763437d9b87 100644 --- a/src/gallium/drivers/svga/svga_state_sampler.c +++ b/src/gallium/drivers/svga/svga_state_sampler.c @@ -278,14 +278,54 @@ update_sampler_resources(struct svga_context *svga, unsigned dirty) if (count != svga->state.hw_draw.num_sampler_views[shader] || memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader], count * sizeof(sampler_views[0])) != 0) { - ret = SVGA3D_vgpu10_SetShaderResources(svga->swc, - svga_shader_type(shader), - 0, /* startView */ - nviews, - ids, - surfaces); - if (ret != PIPE_OK) - return ret; + SVGA3dShaderResourceViewId *pIds = ids; + struct svga_winsys_surface **pSurf = surfaces; + unsigned numSR = 0; + + /* Loop through the sampler view list to only emit + * the sampler views that are not already in the + * corresponding entries in the device's + * shader resource list. + */ + for (i = 0; i < nviews; i++) { + boolean emit; + + emit = sampler_views[i] == + svga->state.hw_draw.sampler_views[shader][i]; + + if (!emit && i == nviews-1) { + /* Include the last sampler view in the next emit + * if it is different. + */ + emit = TRUE; + numSR++; + i++; + } + + if (emit) { + /* numSR can only be 0 if the first entry of the list + * is the same as the one in the device list. + * In this case, * there is nothing to send yet. + */ + if (numSR) { + ret = SVGA3D_vgpu10_SetShaderResources( + svga->swc, + svga_shader_type(shader), + i - numSR, /* startView */ + numSR, + pIds, + pSurf); + + if (ret != PIPE_OK) + return ret; + } + pIds += (numSR + 1); + pSurf += (numSR + 1); + numSR = 0; + } + else + numSR++; + } /* Save referenced sampler views in the hw draw state. */ svga->state.hw_draw.num_sampler_views[shader] = count; -- 2.30.2