summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharmaine Lee <[email protected]>2017-08-01 15:58:50 -0700
committerBrian Paul <[email protected]>2017-09-05 10:31:18 -0600
commit98badd7f6eaa0ac3ad3d5375f084b84172bb7582 (patch)
tree257747cde945988df07ab8d27aef1d1a4c6d577c
parente439908af9665b50443f1196cb55388c69d0c7d7 (diff)
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 <[email protected]>
-rw-r--r--src/gallium/drivers/svga/svga_draw.c78
-rw-r--r--src/gallium/drivers/svga/svga_state_sampler.c56
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;