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