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