• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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