+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 svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX];
+ struct svga_winsys_surface *ib_handle;
+ const unsigned vbuf_count = hwtnl->cmd.vbuf_count;
+ 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;
+ }
+
+ 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);
+
+ 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)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+ }
+ else {
+ vb_handle[i] = NULL;
+ }
+ }
+
+ /* Get handles for the index buffers */
+ 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)
+ return ret;
+
+ svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id;
+ }
+
+ /* setup vertex buffers */
+ {
+ SVGA3dVertexBuffer buffers[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;
+ }
+ 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 (((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,
+ 0, /* startBuffer */
+ buffers, vb_handle);
+ 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]));
+ }
+ }
+ }
+
+ /* Set primitive type (line, tri, etc) */
+ if (svga->state.hw_draw.topology != range->primType) {
+ ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType);
+ if (ret != PIPE_OK)
+ return ret;
+
+ svga->state.hw_draw.topology = range->primType;
+ }
+
+ if (ib_handle) {
+ /* indexed drawing */
+ SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth);
+
+ /* setup index buffer */
+ if (ib_handle != svga->state.hw_draw.ib ||
+ indexFormat != svga->state.hw_draw.ib_format ||
+ range->indexArray.offset != svga->state.hw_draw.ib_offset) {
+ 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;
+ svga->state.hw_draw.ib_format = indexFormat;
+ svga->state.hw_draw.ib_offset = range->indexArray.offset;
+ }
+
+ if (instance_count > 1) {
+ ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc,
+ vcount,
+ instance_count,
+ 0, /* startIndexLocation */
+ range->indexBias,
+ start_instance);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ else {
+ /* non-instanced drawing */
+ ret = SVGA3D_vgpu10_DrawIndexed(svga->swc,
+ vcount,
+ 0, /* startIndexLocation */
+ range->indexBias);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ }
+ else {
+ /* non-indexed drawing */
+ if (instance_count > 1) {
+ ret = SVGA3D_vgpu10_DrawInstanced(svga->swc,
+ vcount,
+ instance_count,
+ range->indexBias,
+ start_instance);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ else {
+ /* non-instanced */
+ ret = SVGA3D_vgpu10_Draw(svga->swc,
+ vcount,
+ range->indexBias);
+ if (ret != PIPE_OK)
+ return ret;
+ }
+ }
+
+ hwtnl->cmd.prim_count = 0;
+
+ return PIPE_OK;
+}
+
+
+
+/**
+ * Emit any pending drawing commands to the command buffer.
+ * When we receive VGPU9 drawing commands we accumulate them and don't
+ * immediately emit them into the command buffer.
+ * This function needs to be called before we change state that could
+ * effect those pending draws.
+ */
+enum pipe_error
+svga_hwtnl_flush(struct svga_hwtnl *hwtnl)
+{
+ if (!svga_have_vgpu10(hwtnl->svga) && hwtnl->cmd.prim_count) {
+ /* we only queue up primitive for VGPU9 */
+ return draw_vgpu9(hwtnl);
+ }
+ return PIPE_OK;
+}
+
+
+void
+svga_hwtnl_set_index_bias(struct svga_hwtnl *hwtnl, int index_bias)
+{
+ hwtnl->index_bias = index_bias;
+}