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