+ mtx_destroy(&ctx->gmem_lock);
+
+ if (fd_mesa_debug & (FD_DBG_BSTAT | FD_DBG_MSGS)) {
+ printf("batch_total=%u, batch_sysmem=%u, batch_gmem=%u, batch_nondraw=%u, batch_restore=%u\n",
+ (uint32_t)ctx->stats.batch_total, (uint32_t)ctx->stats.batch_sysmem,
+ (uint32_t)ctx->stats.batch_gmem, (uint32_t)ctx->stats.batch_nondraw,
+ (uint32_t)ctx->stats.batch_restore);
+ }
+}
+
+static void
+fd_set_debug_callback(struct pipe_context *pctx,
+ const struct pipe_debug_callback *cb)
+{
+ struct fd_context *ctx = fd_context(pctx);
+
+ if (cb)
+ ctx->debug = *cb;
+ else
+ memset(&ctx->debug, 0, sizeof(ctx->debug));
+}
+
+static uint32_t
+fd_get_reset_count(struct fd_context *ctx, bool per_context)
+{
+ uint64_t val;
+ enum fd_param_id param =
+ per_context ? FD_CTX_FAULTS : FD_GLOBAL_FAULTS;
+ int ret = fd_pipe_get_param(ctx->pipe, param, &val);
+ debug_assert(!ret);
+ return val;
+}
+
+static enum pipe_reset_status
+fd_get_device_reset_status(struct pipe_context *pctx)
+{
+ struct fd_context *ctx = fd_context(pctx);
+ int context_faults = fd_get_reset_count(ctx, true);
+ int global_faults = fd_get_reset_count(ctx, false);
+ enum pipe_reset_status status;
+
+ if (context_faults != ctx->context_reset_count) {
+ status = PIPE_GUILTY_CONTEXT_RESET;
+ } else if (global_faults != ctx->global_reset_count) {
+ status = PIPE_INNOCENT_CONTEXT_RESET;
+ } else {
+ status = PIPE_NO_RESET;
+ }
+
+ ctx->context_reset_count = context_faults;
+ ctx->global_reset_count = global_faults;
+
+ return status;
+}
+
+/* TODO we could combine a few of these small buffers (solid_vbuf,
+ * blit_texcoord_vbuf, and vsc_size_mem, into a single buffer and
+ * save a tiny bit of memory
+ */
+
+static struct pipe_resource *
+create_solid_vertexbuf(struct pipe_context *pctx)
+{
+ static const float init_shader_const[] = {
+ -1.000000, +1.000000, +1.000000,
+ +1.000000, -1.000000, +1.000000,
+ };
+ struct pipe_resource *prsc = pipe_buffer_create(pctx->screen,
+ PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(init_shader_const));
+ pipe_buffer_write(pctx, prsc, 0,
+ sizeof(init_shader_const), init_shader_const);
+ return prsc;
+}
+
+static struct pipe_resource *
+create_blit_texcoord_vertexbuf(struct pipe_context *pctx)
+{
+ struct pipe_resource *prsc = pipe_buffer_create(pctx->screen,
+ PIPE_BIND_CUSTOM, PIPE_USAGE_DYNAMIC, 16);
+ return prsc;
+}
+
+void
+fd_context_setup_common_vbos(struct fd_context *ctx)
+{
+ struct pipe_context *pctx = &ctx->base;
+
+ ctx->solid_vbuf = create_solid_vertexbuf(pctx);
+ ctx->blit_texcoord_vbuf = create_blit_texcoord_vertexbuf(pctx);
+
+ /* setup solid_vbuf_state: */
+ ctx->solid_vbuf_state.vtx = pctx->create_vertex_elements_state(
+ pctx, 1, (struct pipe_vertex_element[]){{
+ .vertex_buffer_index = 0,
+ .src_offset = 0,
+ .src_format = PIPE_FORMAT_R32G32B32_FLOAT,
+ }});
+ ctx->solid_vbuf_state.vertexbuf.count = 1;
+ ctx->solid_vbuf_state.vertexbuf.vb[0].stride = 12;
+ ctx->solid_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->solid_vbuf;
+
+ /* setup blit_vbuf_state: */
+ ctx->blit_vbuf_state.vtx = pctx->create_vertex_elements_state(
+ pctx, 2, (struct pipe_vertex_element[]){{
+ .vertex_buffer_index = 0,
+ .src_offset = 0,
+ .src_format = PIPE_FORMAT_R32G32_FLOAT,
+ }, {
+ .vertex_buffer_index = 1,
+ .src_offset = 0,
+ .src_format = PIPE_FORMAT_R32G32B32_FLOAT,
+ }});
+ ctx->blit_vbuf_state.vertexbuf.count = 2;
+ ctx->blit_vbuf_state.vertexbuf.vb[0].stride = 8;
+ ctx->blit_vbuf_state.vertexbuf.vb[0].buffer.resource = ctx->blit_texcoord_vbuf;
+ ctx->blit_vbuf_state.vertexbuf.vb[1].stride = 12;
+ ctx->blit_vbuf_state.vertexbuf.vb[1].buffer.resource = ctx->solid_vbuf;
+}
+
+void
+fd_context_cleanup_common_vbos(struct fd_context *ctx)
+{
+ struct pipe_context *pctx = &ctx->base;
+
+ pctx->delete_vertex_elements_state(pctx, ctx->solid_vbuf_state.vtx);
+ pctx->delete_vertex_elements_state(pctx, ctx->blit_vbuf_state.vtx);
+
+ pipe_resource_reference(&ctx->solid_vbuf, NULL);
+ pipe_resource_reference(&ctx->blit_texcoord_vbuf, NULL);