+
+static enum pipe_error
+validate_constant_buffers(struct svga_context *svga)
+{
+ enum pipe_shader_type shader;
+
+ assert(svga_have_vgpu10(svga));
+
+ for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) {
+ enum pipe_error ret;
+ struct svga_buffer *buffer;
+ struct svga_winsys_surface *handle;
+ unsigned enabled_constbufs;
+
+ /* Rebind the default constant buffer if needed */
+ if (svga->rebind.flags.constbufs) {
+ buffer = svga_buffer(svga->state.hw_draw.constbuf[shader]);
+ if (buffer) {
+ ret = svga->swc->resource_rebind(svga->swc,
+ buffer->handle,
+ NULL,
+ SVGA_RELOC_READ);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ }
+
+ /*
+ * Reference other bound constant buffers to ensure pending updates are
+ * noticed by the device.
+ */
+ enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] & ~1u;
+ while (enabled_constbufs) {
+ unsigned i = u_bit_scan(&enabled_constbufs);
+ buffer = svga_buffer(svga->curr.constbufs[shader][i].buffer);
+ if (buffer) {
+ handle = svga_buffer_handle(svga, &buffer->b.b);
+
+ if (svga->rebind.flags.constbufs) {
+ ret = svga->swc->resource_rebind(svga->swc,
+ handle,
+ NULL,
+ SVGA_RELOC_READ);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ }
+ }
+ }
+ svga->rebind.flags.constbufs = FALSE;
+
+ return PIPE_OK;
+}
+
+
+/**
+ * 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,
+ unsigned vcount,
+ unsigned min_index,
+ unsigned max_index, struct pipe_resource *ib,
+ unsigned start_instance, unsigned instance_count)
+{
+ struct svga_context *svga = hwtnl->svga;
+ 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;
+
+ assert(svga_have_vgpu10(svga));
+ assert(hwtnl->cmd.prim_count == 0);
+
+ /* We need to reemit all the current resource bindings along with the Draw
+ * command to be sure that the referenced resources are available for the
+ * Draw command, just in case the surfaces associated with the resources
+ * are paged out.
+ */
+ if (svga->rebind.val) {
+ ret = svga_rebind_framebuffer_bindings(svga);
+ if (ret != PIPE_OK)
+ return ret;
+
+ ret = svga_rebind_shaders(svga);
+ if (ret != PIPE_OK)
+ return ret;
+
+ /* Rebind stream output targets */
+ ret = svga_rebind_stream_output_targets(svga);
+ if (ret != PIPE_OK)
+ return ret;
+
+ /* 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);
+ if (ret != PIPE_OK)
+ return ret;
+
+ ret = validate_constant_buffers(svga);
+ if (ret != PIPE_OK)
+ return ret;
+
+ /* Get handle for each referenced vertex buffer */
+ for (i = 0; i < vbuf_count; i++) {
+ struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer.resource);
+
+ if (sbuf) {
+ assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER);
+ 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 {
+ vbuffers[i] = NULL;
+ vbuffer_handles[i] = NULL;
+ }
+ }
+
+ 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);
+
+ assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER);
+ (void) sbuf; /* silence unused var warning */
+
+ ib_handle = svga_buffer_handle(svga, ib);
+ if (!ib_handle)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+ }
+ else {
+ ib_handle = NULL;
+ }
+
+ /* setup vertex attribute input layout */
+ if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) {
+ ret = SVGA3D_vgpu10_SetInputLayout(svga->swc,
+ hwtnl->cmd.vdecl_layout_id);
+ if (ret != PIPE_OK)