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