1 /*
2 * Copyright (c) 2009-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8
9 #include "svga_cmd.h"
10
11 #include "util/u_debug.h"
12 #include "util/u_memory.h"
13 #include "util/u_debug_stack.h"
14 #include "util/u_debug_flush.h"
15 #include "util/u_hash_table.h"
16 #include "util/u_bitmask.h"
17 #include "util/u_atomic.h"
18 #include "pipebuffer/pb_buffer.h"
19 #include "pipebuffer/pb_validate.h"
20
21 #include "svga_winsys.h"
22 #include "vmw_context.h"
23 #include "vmw_screen.h"
24 #include "vmw_buffer.h"
25 #include "vmw_surface.h"
26 #include "vmw_fence.h"
27 #include "vmw_shader.h"
28 #include "vmw_query.h"
29
30 #define VMW_COMMAND_SIZE (64*1024)
31 #define VMW_SURFACE_RELOCS (1024)
32 #define VMW_SHADER_RELOCS (1024)
33 #define VMW_REGION_RELOCS (512)
34
35 #define VMW_MUST_FLUSH_STACK 8
36
37 /*
38 * A factor applied to the maximum mob memory size to determine
39 * the optimial time to preemptively flush the command buffer.
40 * The constant is based on some performance trials with SpecViewperf.
41 */
42 #define VMW_MAX_MOB_MEM_FACTOR 2
43
44 /*
45 * A factor applied to the maximum surface memory size to determine
46 * the optimial time to preemptively flush the command buffer.
47 * The constant is based on some performance trials with SpecViewperf.
48 */
49 #define VMW_MAX_SURF_MEM_FACTOR 2
50
51
52
53 struct vmw_buffer_relocation
54 {
55 struct pb_buffer *buffer;
56 bool is_mob;
57 uint32 offset;
58
59 union {
60 struct {
61 struct SVGAGuestPtr *where;
62 } region;
63 struct {
64 SVGAMobId *id;
65 uint32 *offset_into_mob;
66 } mob;
67 };
68 };
69
70 struct vmw_ctx_validate_item {
71 union {
72 struct vmw_svga_winsys_surface *vsurf;
73 struct vmw_svga_winsys_shader *vshader;
74 };
75 bool referenced;
76 };
77
78 struct vmw_svga_winsys_context
79 {
80 struct svga_winsys_context base;
81
82 struct vmw_winsys_screen *vws;
83 struct hash_table *hash;
84
85 #if MESA_DEBUG
86 bool must_flush;
87 struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
88 struct debug_flush_ctx *fctx;
89 #endif
90
91 struct {
92 uint8_t buffer[VMW_COMMAND_SIZE];
93 uint32_t size;
94 uint32_t used;
95 uint32_t reserved;
96 } command;
97
98 struct {
99 struct vmw_ctx_validate_item items[VMW_SURFACE_RELOCS];
100 uint32_t size;
101 uint32_t used;
102 uint32_t staged;
103 uint32_t reserved;
104 } surface;
105
106 struct {
107 struct vmw_buffer_relocation relocs[VMW_REGION_RELOCS];
108 uint32_t size;
109 uint32_t used;
110 uint32_t staged;
111 uint32_t reserved;
112 } region;
113
114 struct {
115 struct vmw_ctx_validate_item items[VMW_SHADER_RELOCS];
116 uint32_t size;
117 uint32_t used;
118 uint32_t staged;
119 uint32_t reserved;
120 } shader;
121
122 struct pb_validate *validate;
123
124 /**
125 * The amount of surface, GMR or MOB memory that is referred by the commands
126 * currently batched in the context command buffer.
127 */
128 uint64_t seen_surfaces;
129 uint64_t seen_regions;
130 uint64_t seen_mobs;
131
132 int32_t refcount;
133
134 /* Bitmask of userspace managed surfaces */
135 struct util_bitmask *surface_id_bm;
136
137 /**
138 * Whether this context should fail to reserve more commands, not because it
139 * ran out of command space, but because a substantial ammount of GMR was
140 * referred.
141 */
142 bool preemptive_flush;
143 };
144
145
146 static inline struct vmw_svga_winsys_context *
vmw_svga_winsys_context(struct svga_winsys_context * swc)147 vmw_svga_winsys_context(struct svga_winsys_context *swc)
148 {
149 assert(swc);
150 return (struct vmw_svga_winsys_context *)swc;
151 }
152
153
154 static inline enum pb_usage_flags
vmw_translate_to_pb_flags(unsigned flags)155 vmw_translate_to_pb_flags(unsigned flags)
156 {
157 enum pb_usage_flags f = 0;
158 if (flags & SVGA_RELOC_READ)
159 f |= PB_USAGE_GPU_READ;
160
161 if (flags & SVGA_RELOC_WRITE)
162 f |= PB_USAGE_GPU_WRITE;
163
164 return f;
165 }
166
167 static enum pipe_error
vmw_swc_flush(struct svga_winsys_context * swc,struct pipe_fence_handle ** pfence)168 vmw_swc_flush(struct svga_winsys_context *swc,
169 struct pipe_fence_handle **pfence)
170 {
171 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
172 struct vmw_winsys_screen *vws = vswc->vws;
173 struct pipe_fence_handle *fence = NULL;
174 unsigned i;
175 enum pipe_error ret;
176
177 /*
178 * If we hit a retry, lock the mutex and retry immediately.
179 * If we then still hit a retry, sleep until another thread
180 * wakes us up after it has released its buffers from the
181 * validate list.
182 *
183 * If we hit another error condition, we still need to broadcast since
184 * pb_validate_validate releases validated buffers in its error path.
185 */
186
187 ret = pb_validate_validate(vswc->validate);
188 if (ret != PIPE_OK) {
189 mtx_lock(&vws->cs_mutex);
190 while (ret == PIPE_ERROR_RETRY) {
191 ret = pb_validate_validate(vswc->validate);
192 if (ret == PIPE_ERROR_RETRY) {
193 cnd_wait(&vws->cs_cond, &vws->cs_mutex);
194 }
195 }
196 if (ret != PIPE_OK) {
197 cnd_broadcast(&vws->cs_cond);
198 }
199 mtx_unlock(&vws->cs_mutex);
200 }
201
202 assert(ret == PIPE_OK);
203 if(ret == PIPE_OK) {
204
205 /* Apply relocations */
206 for(i = 0; i < vswc->region.used; ++i) {
207 struct vmw_buffer_relocation *reloc = &vswc->region.relocs[i];
208 struct SVGAGuestPtr ptr;
209
210 if(!vmw_dma_bufmgr_region_ptr(reloc->buffer, &ptr))
211 assert(0);
212
213 ptr.offset += reloc->offset;
214
215 if (reloc->is_mob) {
216 if (reloc->mob.id)
217 *reloc->mob.id = ptr.gmrId;
218 if (reloc->mob.offset_into_mob)
219 *reloc->mob.offset_into_mob = ptr.offset;
220 else {
221 assert(ptr.offset == 0);
222 }
223 } else
224 *reloc->region.where = ptr;
225 }
226
227 if (vswc->command.used || pfence != NULL)
228 vmw_ioctl_command(vws,
229 vswc->base.cid,
230 0,
231 vswc->command.buffer,
232 vswc->command.used,
233 &fence,
234 vswc->base.imported_fence_fd,
235 vswc->base.hints);
236
237 pb_validate_fence(vswc->validate, fence);
238 mtx_lock(&vws->cs_mutex);
239 cnd_broadcast(&vws->cs_cond);
240 mtx_unlock(&vws->cs_mutex);
241 }
242
243 vswc->command.used = 0;
244 vswc->command.reserved = 0;
245
246 for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
247 struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
248 if (isurf->referenced)
249 p_atomic_dec(&isurf->vsurf->validated);
250 vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
251 }
252
253 _mesa_hash_table_clear(vswc->hash, NULL);
254 vswc->surface.used = 0;
255 vswc->surface.reserved = 0;
256
257 for(i = 0; i < vswc->shader.used + vswc->shader.staged; ++i) {
258 struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
259 if (ishader->referenced)
260 p_atomic_dec(&ishader->vshader->validated);
261 vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
262 }
263
264 vswc->shader.used = 0;
265 vswc->shader.reserved = 0;
266
267 vswc->region.used = 0;
268 vswc->region.reserved = 0;
269
270 #if MESA_DEBUG
271 vswc->must_flush = false;
272 debug_flush_flush(vswc->fctx);
273 #endif
274 swc->hints &= ~SVGA_HINT_FLAG_CAN_PRE_FLUSH;
275 swc->hints &= ~SVGA_HINT_FLAG_EXPORT_FENCE_FD;
276 vswc->preemptive_flush = false;
277 vswc->seen_surfaces = 0;
278 vswc->seen_regions = 0;
279 vswc->seen_mobs = 0;
280
281 if (vswc->base.imported_fence_fd != -1) {
282 close(vswc->base.imported_fence_fd);
283 vswc->base.imported_fence_fd = -1;
284 }
285
286 if(pfence)
287 vmw_fence_reference(vswc->vws, pfence, fence);
288
289 vmw_fence_reference(vswc->vws, &fence, NULL);
290
291 return ret;
292 }
293
294
295 static void *
vmw_swc_reserve(struct svga_winsys_context * swc,uint32_t nr_bytes,uint32_t nr_relocs)296 vmw_swc_reserve(struct svga_winsys_context *swc,
297 uint32_t nr_bytes, uint32_t nr_relocs )
298 {
299 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
300
301 #if MESA_DEBUG
302 /* Check if somebody forgot to check the previous failure */
303 if(vswc->must_flush) {
304 debug_printf("Forgot to flush:\n");
305 debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
306 assert(!vswc->must_flush);
307 }
308 debug_flush_might_flush(vswc->fctx);
309 #endif
310
311 assert(nr_bytes <= vswc->command.size);
312 if(nr_bytes > vswc->command.size)
313 return NULL;
314
315 if(vswc->preemptive_flush ||
316 vswc->command.used + nr_bytes > vswc->command.size ||
317 vswc->surface.used + nr_relocs > vswc->surface.size ||
318 vswc->shader.used + nr_relocs > vswc->shader.size ||
319 vswc->region.used + nr_relocs > vswc->region.size) {
320 #if MESA_DEBUG
321 vswc->must_flush = true;
322 debug_backtrace_capture(vswc->must_flush_stack, 1,
323 VMW_MUST_FLUSH_STACK);
324 #endif
325 return NULL;
326 }
327
328 assert(vswc->command.used + nr_bytes <= vswc->command.size);
329 assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
330 assert(vswc->shader.used + nr_relocs <= vswc->shader.size);
331 assert(vswc->region.used + nr_relocs <= vswc->region.size);
332
333 vswc->command.reserved = nr_bytes;
334 vswc->surface.reserved = nr_relocs;
335 vswc->surface.staged = 0;
336 vswc->shader.reserved = nr_relocs;
337 vswc->shader.staged = 0;
338 vswc->region.reserved = nr_relocs;
339 vswc->region.staged = 0;
340
341 return vswc->command.buffer + vswc->command.used;
342 }
343
344 static unsigned
vmw_swc_get_command_buffer_size(struct svga_winsys_context * swc)345 vmw_swc_get_command_buffer_size(struct svga_winsys_context *swc)
346 {
347 const struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
348 return vswc->command.used;
349 }
350
351 static void
vmw_swc_context_relocation(struct svga_winsys_context * swc,uint32 * cid)352 vmw_swc_context_relocation(struct svga_winsys_context *swc,
353 uint32 *cid)
354 {
355 *cid = swc->cid;
356 }
357
358 static bool
vmw_swc_add_validate_buffer(struct vmw_svga_winsys_context * vswc,struct pb_buffer * pb_buf,unsigned flags)359 vmw_swc_add_validate_buffer(struct vmw_svga_winsys_context *vswc,
360 struct pb_buffer *pb_buf,
361 unsigned flags)
362 {
363 ASSERTED enum pipe_error ret;
364 unsigned translated_flags;
365 bool already_present;
366
367 translated_flags = vmw_translate_to_pb_flags(flags);
368 ret = pb_validate_add_buffer(vswc->validate, pb_buf, translated_flags,
369 vswc->hash, &already_present);
370 assert(ret == PIPE_OK);
371 return !already_present;
372 }
373
374 static void
vmw_swc_region_relocation(struct svga_winsys_context * swc,struct SVGAGuestPtr * where,struct svga_winsys_buffer * buffer,uint32 offset,unsigned flags)375 vmw_swc_region_relocation(struct svga_winsys_context *swc,
376 struct SVGAGuestPtr *where,
377 struct svga_winsys_buffer *buffer,
378 uint32 offset,
379 unsigned flags)
380 {
381 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
382 struct vmw_buffer_relocation *reloc;
383
384 assert(vswc->region.staged < vswc->region.reserved);
385
386 reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
387 reloc->region.where = where;
388
389 /*
390 * pb_validate holds a refcount to the buffer, so no need to
391 * refcount it again in the relocation.
392 */
393 reloc->buffer = vmw_pb_buffer(buffer);
394 reloc->offset = offset;
395 reloc->is_mob = false;
396 ++vswc->region.staged;
397
398 if (vmw_swc_add_validate_buffer(vswc, reloc->buffer, flags)) {
399 vswc->seen_regions += reloc->buffer->base.size;
400 if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
401 vswc->seen_regions >= VMW_GMR_POOL_SIZE/5)
402 vswc->preemptive_flush = true;
403 }
404
405 #if MESA_DEBUG
406 if (!(flags & SVGA_RELOC_INTERNAL))
407 debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
408 #endif
409 }
410
411 static void
vmw_swc_mob_relocation(struct svga_winsys_context * swc,SVGAMobId * id,uint32 * offset_into_mob,struct svga_winsys_buffer * buffer,uint32 offset,unsigned flags)412 vmw_swc_mob_relocation(struct svga_winsys_context *swc,
413 SVGAMobId *id,
414 uint32 *offset_into_mob,
415 struct svga_winsys_buffer *buffer,
416 uint32 offset,
417 unsigned flags)
418 {
419 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
420 struct vmw_buffer_relocation *reloc;
421 struct pb_buffer *pb_buffer = vmw_pb_buffer(buffer);
422
423 if (id) {
424 assert(vswc->region.staged < vswc->region.reserved);
425
426 reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
427 reloc->mob.id = id;
428 reloc->mob.offset_into_mob = offset_into_mob;
429
430 /*
431 * pb_validate holds a refcount to the buffer, so no need to
432 * refcount it again in the relocation.
433 */
434 reloc->buffer = pb_buffer;
435 reloc->offset = offset;
436 reloc->is_mob = true;
437 ++vswc->region.staged;
438 }
439
440 if (vmw_swc_add_validate_buffer(vswc, pb_buffer, flags)) {
441 vswc->seen_mobs += pb_buffer->base.size;
442
443 if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
444 vswc->seen_mobs >=
445 vswc->vws->ioctl.max_mob_memory / VMW_MAX_MOB_MEM_FACTOR)
446 vswc->preemptive_flush = true;
447 }
448
449 #if MESA_DEBUG
450 if (!(flags & SVGA_RELOC_INTERNAL))
451 debug_flush_cb_reference(vswc->fctx, vmw_debug_flush_buf(buffer));
452 #endif
453 }
454
455
456 /**
457 * vmw_swc_surface_clear_reference - Clear referenced info for a surface
458 *
459 * @swc: Pointer to an svga_winsys_context
460 * @vsurf: Pointer to a vmw_svga_winsys_surface, the referenced info of which
461 * we want to clear
462 *
463 * This is primarily used by a discard surface map to indicate that the
464 * surface data is no longer referenced by a draw call, and mapping it
465 * should therefore no longer cause a flush.
466 */
467 void
vmw_swc_surface_clear_reference(struct svga_winsys_context * swc,struct vmw_svga_winsys_surface * vsurf)468 vmw_swc_surface_clear_reference(struct svga_winsys_context *swc,
469 struct vmw_svga_winsys_surface *vsurf)
470 {
471 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
472 struct vmw_ctx_validate_item *isrf =
473 util_hash_table_get(vswc->hash, vsurf);
474
475 if (isrf && isrf->referenced) {
476 isrf->referenced = false;
477 p_atomic_dec(&vsurf->validated);
478 }
479 }
480
481 static void
vmw_swc_surface_only_relocation(struct svga_winsys_context * swc,uint32 * where,struct vmw_svga_winsys_surface * vsurf,unsigned flags)482 vmw_swc_surface_only_relocation(struct svga_winsys_context *swc,
483 uint32 *where,
484 struct vmw_svga_winsys_surface *vsurf,
485 unsigned flags)
486 {
487 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
488 struct vmw_ctx_validate_item *isrf;
489
490 assert(vswc->surface.staged < vswc->surface.reserved);
491 isrf = util_hash_table_get(vswc->hash, vsurf);
492
493 if (isrf == NULL) {
494 isrf = &vswc->surface.items[vswc->surface.used + vswc->surface.staged];
495 vmw_svga_winsys_surface_reference(&isrf->vsurf, vsurf);
496 isrf->referenced = false;
497
498 _mesa_hash_table_insert(vswc->hash, vsurf, isrf);
499 ++vswc->surface.staged;
500
501 vswc->seen_surfaces += vsurf->size;
502 if ((swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) &&
503 vswc->seen_surfaces >=
504 vswc->vws->ioctl.max_surface_memory / VMW_MAX_SURF_MEM_FACTOR)
505 vswc->preemptive_flush = true;
506 }
507
508 if (!(flags & SVGA_RELOC_INTERNAL) && !isrf->referenced) {
509 isrf->referenced = true;
510 p_atomic_inc(&vsurf->validated);
511 }
512
513 if (where)
514 *where = vsurf->sid;
515 }
516
517 static void
vmw_swc_surface_relocation(struct svga_winsys_context * swc,uint32 * where,uint32 * mobid,struct svga_winsys_surface * surface,unsigned flags)518 vmw_swc_surface_relocation(struct svga_winsys_context *swc,
519 uint32 *where,
520 uint32 *mobid,
521 struct svga_winsys_surface *surface,
522 unsigned flags)
523 {
524 struct vmw_svga_winsys_surface *vsurf;
525
526 assert(swc->have_gb_objects || mobid == NULL);
527
528 if (!surface) {
529 *where = SVGA3D_INVALID_ID;
530 if (mobid)
531 *mobid = SVGA3D_INVALID_ID;
532 return;
533 }
534
535 vsurf = vmw_svga_winsys_surface(surface);
536 vmw_swc_surface_only_relocation(swc, where, vsurf, flags);
537
538 if (swc->have_gb_objects && vsurf->buf != NULL) {
539
540 /*
541 * Make sure backup buffer ends up fenced.
542 */
543
544 mtx_lock(&vsurf->mutex);
545 assert(vsurf->buf != NULL);
546
547 /*
548 * An internal reloc means that the surface transfer direction
549 * is opposite to the MOB transfer direction...
550 */
551 if ((flags & SVGA_RELOC_INTERNAL) &&
552 (flags & (SVGA_RELOC_READ | SVGA_RELOC_WRITE)) !=
553 (SVGA_RELOC_READ | SVGA_RELOC_WRITE))
554 flags ^= (SVGA_RELOC_READ | SVGA_RELOC_WRITE);
555 vmw_swc_mob_relocation(swc, mobid, NULL, (struct svga_winsys_buffer *)
556 vsurf->buf, 0, flags);
557 mtx_unlock(&vsurf->mutex);
558 }
559 }
560
561 static void
vmw_swc_shader_relocation(struct svga_winsys_context * swc,uint32 * shid,uint32 * mobid,uint32 * offset,struct svga_winsys_gb_shader * shader,unsigned flags)562 vmw_swc_shader_relocation(struct svga_winsys_context *swc,
563 uint32 *shid,
564 uint32 *mobid,
565 uint32 *offset,
566 struct svga_winsys_gb_shader *shader,
567 unsigned flags)
568 {
569 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
570 struct vmw_winsys_screen *vws = vswc->vws;
571 struct vmw_svga_winsys_shader *vshader;
572 struct vmw_ctx_validate_item *ishader;
573
574 if(!shader) {
575 *shid = SVGA3D_INVALID_ID;
576 return;
577 }
578
579 vshader = vmw_svga_winsys_shader(shader);
580
581 if (!vws->base.have_vgpu10) {
582 assert(vswc->shader.staged < vswc->shader.reserved);
583 ishader = util_hash_table_get(vswc->hash, vshader);
584
585 if (ishader == NULL) {
586 ishader = &vswc->shader.items[vswc->shader.used + vswc->shader.staged];
587 vmw_svga_winsys_shader_reference(&ishader->vshader, vshader);
588 ishader->referenced = false;
589
590 _mesa_hash_table_insert(vswc->hash, vshader, ishader);
591 ++vswc->shader.staged;
592 }
593
594 if (!ishader->referenced) {
595 ishader->referenced = true;
596 p_atomic_inc(&vshader->validated);
597 }
598 }
599
600 if (shid)
601 *shid = vshader->shid;
602
603 if (vshader->buf)
604 vmw_swc_mob_relocation(swc, mobid, offset, vshader->buf,
605 0, SVGA_RELOC_READ);
606 }
607
608 static void
vmw_swc_query_relocation(struct svga_winsys_context * swc,SVGAMobId * id,struct svga_winsys_gb_query * query)609 vmw_swc_query_relocation(struct svga_winsys_context *swc,
610 SVGAMobId *id,
611 struct svga_winsys_gb_query *query)
612 {
613 /* Queries are backed by one big MOB */
614 vmw_swc_mob_relocation(swc, id, NULL, query->buf, 0,
615 SVGA_RELOC_READ | SVGA_RELOC_WRITE);
616 }
617
618 static void
vmw_swc_commit(struct svga_winsys_context * swc)619 vmw_swc_commit(struct svga_winsys_context *swc)
620 {
621 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
622
623 assert(vswc->command.used + vswc->command.reserved <= vswc->command.size);
624 vswc->command.used += vswc->command.reserved;
625 vswc->command.reserved = 0;
626
627 assert(vswc->surface.staged <= vswc->surface.reserved);
628 assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size);
629 vswc->surface.used += vswc->surface.staged;
630 vswc->surface.staged = 0;
631 vswc->surface.reserved = 0;
632
633 assert(vswc->shader.staged <= vswc->shader.reserved);
634 assert(vswc->shader.used + vswc->shader.staged <= vswc->shader.size);
635 vswc->shader.used += vswc->shader.staged;
636 vswc->shader.staged = 0;
637 vswc->shader.reserved = 0;
638
639 assert(vswc->region.staged <= vswc->region.reserved);
640 assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
641 vswc->region.used += vswc->region.staged;
642 vswc->region.staged = 0;
643 vswc->region.reserved = 0;
644 }
645
646
647 static void
vmw_swc_destroy(struct svga_winsys_context * swc)648 vmw_swc_destroy(struct svga_winsys_context *swc)
649 {
650 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
651 unsigned i;
652
653 for(i = 0; i < vswc->surface.used; ++i) {
654 struct vmw_ctx_validate_item *isurf = &vswc->surface.items[i];
655 if (isurf->referenced)
656 p_atomic_dec(&isurf->vsurf->validated);
657 vmw_svga_winsys_surface_reference(&isurf->vsurf, NULL);
658 }
659
660 for(i = 0; i < vswc->shader.used; ++i) {
661 struct vmw_ctx_validate_item *ishader = &vswc->shader.items[i];
662 if (ishader->referenced)
663 p_atomic_dec(&ishader->vshader->validated);
664 vmw_svga_winsys_shader_reference(&ishader->vshader, NULL);
665 }
666
667 if (vmw_has_userspace_surface(vswc->vws))
668 util_bitmask_destroy(vswc->surface_id_bm);
669 _mesa_hash_table_destroy(vswc->hash, NULL);
670 pb_validate_destroy(vswc->validate);
671 vmw_ioctl_context_destroy(vswc->vws, swc->cid);
672 if (vswc->vws->swc == swc)
673 vswc->vws->swc = NULL;
674 #if MESA_DEBUG
675 debug_flush_ctx_destroy(vswc->fctx);
676 #endif
677 FREE(vswc);
678 }
679
680 void
vmw_swc_unref(struct svga_winsys_context * swc)681 vmw_swc_unref(struct svga_winsys_context *swc)
682 {
683 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
684 if (p_atomic_dec_zero(&vswc->refcount)) {
685 vmw_swc_destroy(swc);
686 }
687 }
688
689 /**
690 * vmw_svga_winsys_vgpu10_shader_screate - The winsys shader_crate callback
691 *
692 * @swc: The winsys context.
693 * @shaderId: Previously allocated shader id.
694 * @shaderType: The shader type.
695 * @bytecode: The shader bytecode
696 * @bytecodelen: The length of the bytecode.
697 *
698 * Creates an svga_winsys_gb_shader structure and allocates a buffer for the
699 * shader code and copies the shader code into the buffer. Shader
700 * resource creation is not done.
701 */
702 static struct svga_winsys_gb_shader *
vmw_svga_winsys_vgpu10_shader_create(struct svga_winsys_context * swc,uint32 shaderId,SVGA3dShaderType shaderType,const uint32 * bytecode,uint32 bytecodeLen,const SVGA3dDXShaderSignatureHeader * sgnInfo,uint32 sgnLen)703 vmw_svga_winsys_vgpu10_shader_create(struct svga_winsys_context *swc,
704 uint32 shaderId,
705 SVGA3dShaderType shaderType,
706 const uint32 *bytecode,
707 uint32 bytecodeLen,
708 const SVGA3dDXShaderSignatureHeader *sgnInfo,
709 uint32 sgnLen)
710 {
711 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
712 struct vmw_svga_winsys_shader *shader;
713 shader = vmw_svga_shader_create(&vswc->vws->base, shaderType, bytecode,
714 bytecodeLen, sgnInfo, sgnLen);
715 if (!shader)
716 return NULL;
717
718 shader->shid = shaderId;
719 return svga_winsys_shader(shader);
720 }
721
722 /**
723 * vmw_svga_winsys_vgpu10_shader_destroy - The winsys shader_destroy callback.
724 *
725 * @swc: The winsys context.
726 * @shader: A shader structure previously allocated by shader_create.
727 *
728 * Frees the shader structure and the buffer holding the shader code.
729 */
730 static void
vmw_svga_winsys_vgpu10_shader_destroy(struct svga_winsys_context * swc,struct svga_winsys_gb_shader * shader)731 vmw_svga_winsys_vgpu10_shader_destroy(struct svga_winsys_context *swc,
732 struct svga_winsys_gb_shader *shader)
733 {
734 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
735
736 vmw_svga_winsys_shader_destroy(&vswc->vws->base, shader);
737 }
738
739 /**
740 * vmw_svga_winsys_resource_rebind - The winsys resource_rebind callback
741 *
742 * @swc: The winsys context.
743 * @surface: The surface to be referenced.
744 * @shader: The shader to be referenced.
745 * @flags: Relocation flags.
746 *
747 * This callback is needed because shader backing buffers are sub-allocated, and
748 * hence the kernel fencing is not sufficient. The buffers need to be put on
749 * the context's validation list and fenced after command submission to avoid
750 * reuse of busy shader buffers. In addition, surfaces need to be put on the
751 * validation list in order for the driver to regard them as referenced
752 * by the command stream.
753 */
754 static enum pipe_error
vmw_svga_winsys_resource_rebind(struct svga_winsys_context * swc,struct svga_winsys_surface * surface,struct svga_winsys_gb_shader * shader,unsigned flags)755 vmw_svga_winsys_resource_rebind(struct svga_winsys_context *swc,
756 struct svga_winsys_surface *surface,
757 struct svga_winsys_gb_shader *shader,
758 unsigned flags)
759 {
760 /**
761 * Need to reserve one validation item for either the surface or
762 * the shader.
763 */
764 if (!vmw_swc_reserve(swc, 0, 1))
765 return PIPE_ERROR_OUT_OF_MEMORY;
766
767 if (surface)
768 vmw_swc_surface_relocation(swc, NULL, NULL, surface, flags);
769 else if (shader)
770 vmw_swc_shader_relocation(swc, NULL, NULL, NULL, shader, flags);
771
772 vmw_swc_commit(swc);
773
774 return PIPE_OK;
775 }
776
777 struct svga_winsys_context *
vmw_svga_winsys_context_create(struct svga_winsys_screen * sws)778 vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
779 {
780 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
781 struct vmw_svga_winsys_context *vswc;
782
783 vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
784 if(!vswc)
785 return NULL;
786
787 vswc->base.destroy = vmw_swc_unref;
788 vswc->base.reserve = vmw_swc_reserve;
789 vswc->base.get_command_buffer_size = vmw_swc_get_command_buffer_size;
790 vswc->base.surface_relocation = vmw_swc_surface_relocation;
791 vswc->base.region_relocation = vmw_swc_region_relocation;
792 vswc->base.mob_relocation = vmw_swc_mob_relocation;
793 vswc->base.query_relocation = vmw_swc_query_relocation;
794 vswc->base.query_bind = vmw_swc_query_bind;
795 vswc->base.context_relocation = vmw_swc_context_relocation;
796 vswc->base.shader_relocation = vmw_swc_shader_relocation;
797 vswc->base.commit = vmw_swc_commit;
798 vswc->base.flush = vmw_swc_flush;
799 vswc->base.surface_map = vmw_svga_winsys_surface_map;
800 vswc->base.surface_unmap = vmw_svga_winsys_surface_unmap;
801
802 vswc->base.shader_create = vmw_svga_winsys_vgpu10_shader_create;
803 vswc->base.shader_destroy = vmw_svga_winsys_vgpu10_shader_destroy;
804
805 vswc->base.resource_rebind = vmw_svga_winsys_resource_rebind;
806
807 if (sws->have_vgpu10)
808 vswc->base.cid = vmw_ioctl_extended_context_create(vws, sws->have_vgpu10);
809 else
810 vswc->base.cid = vmw_ioctl_context_create(vws);
811
812 if (vswc->base.cid == -1)
813 goto out_no_context;
814
815 vswc->base.imported_fence_fd = -1;
816
817 vswc->base.have_gb_objects = sws->have_gb_objects;
818
819 vswc->vws = vws;
820
821 vswc->command.size = VMW_COMMAND_SIZE;
822 vswc->surface.size = VMW_SURFACE_RELOCS;
823 vswc->shader.size = VMW_SHADER_RELOCS;
824 vswc->region.size = VMW_REGION_RELOCS;
825
826 vswc->validate = pb_validate_create();
827 if(!vswc->validate)
828 goto out_no_validate;
829
830 vswc->hash = util_hash_table_create_ptr_keys();
831 if (!vswc->hash)
832 goto out_no_hash;
833
834 if (vmw_has_userspace_surface(vws)) {
835 if(!(vswc->surface_id_bm = util_bitmask_create()))
836 goto out_no_user_srf;
837 /**
838 * First id assigned is 0 which is invalid for surface id. Consume the
839 * first id.
840 */
841 vmw_swc_surface_add_userspace_id(&vswc->base);
842 }
843
844 /**
845 * The context refcount is initialized to 2, one reference is for the context
846 * itself and the other is for vws screen. One unref is done when context
847 * destroy is called and the other when the either vws screen is destroyed
848 * or it initializes another context.
849 * This ensures that a screen always has access to its last created context.
850 * The vws screen needs this context to submit surface commands for userspace
851 * managed surfaces.
852 */
853 p_atomic_set(&vswc->refcount, 1);
854 if (vws->swc)
855 vmw_swc_unref(vws->swc);
856 vws->swc = &vswc->base;
857 p_atomic_inc(&vswc->refcount);
858
859 #if MESA_DEBUG
860 vswc->fctx = debug_flush_ctx_create(true, VMW_DEBUG_FLUSH_STACK);
861 #endif
862
863 vswc->base.force_coherent = vws->force_coherent;
864 return &vswc->base;
865
866 out_no_user_srf:
867 _mesa_hash_table_destroy(vswc->hash, NULL);
868 out_no_hash:
869 pb_validate_destroy(vswc->validate);
870 out_no_validate:
871 vmw_ioctl_context_destroy(vws, vswc->base.cid);
872 out_no_context:
873 FREE(vswc);
874 return NULL;
875 }
876
877 void
vmw_swc_surface_clear_userspace_id(struct svga_winsys_context * swc,uint32 sid)878 vmw_swc_surface_clear_userspace_id(struct svga_winsys_context *swc,
879 uint32 sid)
880 {
881 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
882 util_bitmask_clear(vswc->surface_id_bm, sid);
883 }
884
885 uint32_t
vmw_swc_surface_add_userspace_id(struct svga_winsys_context * swc)886 vmw_swc_surface_add_userspace_id(struct svga_winsys_context *swc)
887 {
888 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
889 return util_bitmask_add(vswc->surface_id_bm);
890 }
891