}
+/**
+ * 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,
*/
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;
}
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.
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;