1 /**********************************************************
2 * Copyright 2009 VMware, Inc. All rights reserved.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 **********************************************************/
29 #include "util/u_debug.h"
30 #include "util/u_memory.h"
31 #include "util/u_debug_stack.h"
32 #include "pipebuffer/pb_buffer.h"
33 #include "pipebuffer/pb_validate.h"
35 #include "svga_winsys.h"
36 #include "vmw_context.h"
37 #include "vmw_screen.h"
38 #include "vmw_buffer.h"
39 #include "vmw_surface.h"
40 #include "vmw_fence.h"
42 #define VMW_COMMAND_SIZE (64*1024)
43 #define VMW_SURFACE_RELOCS (1024)
44 #define VMW_REGION_RELOCS (512)
46 #define VMW_MUST_FLUSH_STACK 8
48 struct vmw_region_relocation
50 struct SVGAGuestPtr
*where
;
51 struct pb_buffer
*buffer
;
52 /* TODO: put offset info inside where */
56 struct vmw_svga_winsys_context
58 struct svga_winsys_context base
;
60 struct vmw_winsys_screen
*vws
;
64 struct debug_stack_frame must_flush_stack
[VMW_MUST_FLUSH_STACK
];
68 uint8_t buffer
[VMW_COMMAND_SIZE
];
75 struct vmw_svga_winsys_surface
*handles
[VMW_SURFACE_RELOCS
];
83 struct vmw_region_relocation relocs
[VMW_REGION_RELOCS
];
90 struct pb_validate
*validate
;
95 * The amount of GMR that is referred by the commands currently batched
98 uint32_t seen_regions
;
101 * Whether this context should fail to reserve more commands, not because it
102 * ran out of command space, but because a substantial ammount of GMR was
105 boolean preemptive_flush
;
107 boolean throttle_set
;
108 uint32_t throttle_us
;
112 static INLINE
struct vmw_svga_winsys_context
*
113 vmw_svga_winsys_context(struct svga_winsys_context
*swc
)
116 return (struct vmw_svga_winsys_context
*)swc
;
120 static INLINE
unsigned
121 vmw_translate_to_pb_flags(unsigned flags
)
124 if (flags
& SVGA_RELOC_READ
)
125 f
|= PB_USAGE_GPU_READ
;
127 if (flags
& SVGA_RELOC_WRITE
)
128 f
|= PB_USAGE_GPU_WRITE
;
133 static enum pipe_error
134 vmw_swc_flush(struct svga_winsys_context
*swc
,
135 struct pipe_fence_handle
**pfence
)
137 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
138 struct pipe_fence_handle
*fence
= NULL
;
141 uint32_t throttle_us
;
143 ret
= pb_validate_validate(vswc
->validate
);
144 assert(ret
== PIPE_OK
);
147 /* Apply relocations */
148 for(i
= 0; i
< vswc
->region
.used
; ++i
) {
149 struct vmw_region_relocation
*reloc
= &vswc
->region
.relocs
[i
];
150 struct SVGAGuestPtr ptr
;
152 if(!vmw_gmr_bufmgr_region_ptr(reloc
->buffer
, &ptr
))
155 ptr
.offset
+= reloc
->offset
;
160 throttle_us
= vswc
->throttle_set
?
161 vswc
->throttle_us
: vswc
->vws
->default_throttle_us
;
163 if (vswc
->command
.used
)
164 vmw_ioctl_command(vswc
->vws
,
167 vswc
->command
.buffer
,
171 fence
= vmw_pipe_fence(vswc
->last_fence
);
173 pb_validate_fence(vswc
->validate
, fence
);
176 vswc
->command
.used
= 0;
177 vswc
->command
.reserved
= 0;
179 for(i
= 0; i
< vswc
->surface
.used
+ vswc
->surface
.staged
; ++i
) {
180 struct vmw_svga_winsys_surface
*vsurf
=
181 vswc
->surface
.handles
[i
];
182 p_atomic_dec(&vsurf
->validated
);
183 vmw_svga_winsys_surface_reference(&vswc
->surface
.handles
[i
], NULL
);
186 vswc
->surface
.used
= 0;
187 vswc
->surface
.reserved
= 0;
189 for(i
= 0; i
< vswc
->region
.used
+ vswc
->region
.staged
; ++i
) {
190 pb_reference(&vswc
->region
.relocs
[i
].buffer
, NULL
);
193 vswc
->region
.used
= 0;
194 vswc
->region
.reserved
= 0;
197 vswc
->must_flush
= FALSE
;
199 vswc
->preemptive_flush
= FALSE
;
200 vswc
->seen_regions
= 0;
210 vmw_swc_reserve(struct svga_winsys_context
*swc
,
211 uint32_t nr_bytes
, uint32_t nr_relocs
)
213 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
216 /* Check if somebody forgot to check the previous failure */
217 if(vswc
->must_flush
) {
218 debug_printf("Forgot to flush:\n");
219 debug_backtrace_dump(vswc
->must_flush_stack
, VMW_MUST_FLUSH_STACK
);
220 assert(!vswc
->must_flush
);
224 assert(nr_bytes
<= vswc
->command
.size
);
225 if(nr_bytes
> vswc
->command
.size
)
228 if(vswc
->preemptive_flush
||
229 vswc
->command
.used
+ nr_bytes
> vswc
->command
.size
||
230 vswc
->surface
.used
+ nr_relocs
> vswc
->surface
.size
||
231 vswc
->region
.used
+ nr_relocs
> vswc
->region
.size
) {
233 vswc
->must_flush
= TRUE
;
234 debug_backtrace_capture(vswc
->must_flush_stack
, 1,
235 VMW_MUST_FLUSH_STACK
);
240 assert(vswc
->command
.used
+ nr_bytes
<= vswc
->command
.size
);
241 assert(vswc
->surface
.used
+ nr_relocs
<= vswc
->surface
.size
);
242 assert(vswc
->region
.used
+ nr_relocs
<= vswc
->region
.size
);
244 vswc
->command
.reserved
= nr_bytes
;
245 vswc
->surface
.reserved
= nr_relocs
;
246 vswc
->surface
.staged
= 0;
247 vswc
->region
.reserved
= nr_relocs
;
248 vswc
->region
.staged
= 0;
250 return vswc
->command
.buffer
+ vswc
->command
.used
;
255 vmw_swc_surface_relocation(struct svga_winsys_context
*swc
,
257 struct svga_winsys_surface
*surface
,
260 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
261 struct vmw_svga_winsys_surface
*vsurf
;
264 *where
= SVGA3D_INVALID_ID
;
268 assert(vswc
->surface
.staged
< vswc
->surface
.reserved
);
270 vsurf
= vmw_svga_winsys_surface(surface
);
274 vmw_svga_winsys_surface_reference(&vswc
->surface
.handles
[vswc
->surface
.used
+ vswc
->surface
.staged
], vsurf
);
275 p_atomic_inc(&vsurf
->validated
);
276 ++vswc
->surface
.staged
;
281 vmw_swc_region_relocation(struct svga_winsys_context
*swc
,
282 struct SVGAGuestPtr
*where
,
283 struct svga_winsys_buffer
*buffer
,
287 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
288 struct vmw_region_relocation
*reloc
;
289 unsigned translated_flags
;
292 assert(vswc
->region
.staged
< vswc
->region
.reserved
);
294 reloc
= &vswc
->region
.relocs
[vswc
->region
.used
+ vswc
->region
.staged
];
295 reloc
->where
= where
;
296 pb_reference(&reloc
->buffer
, vmw_pb_buffer(buffer
));
297 reloc
->offset
= offset
;
299 ++vswc
->region
.staged
;
301 translated_flags
= vmw_translate_to_pb_flags(flags
);
302 ret
= pb_validate_add_buffer(vswc
->validate
, reloc
->buffer
, translated_flags
);
303 /* TODO: Update pipebuffer to reserve buffers and not fail here */
304 assert(ret
== PIPE_OK
);
307 * Flush preemptively the FIFO commands to keep the GMR working set within
310 * This is necessary for applications like SPECviewperf that generate huge
311 * amounts of immediate vertex data, so that we don't pile up too much of
312 * that vertex data neither in the guest nor in the host.
314 * Note that in the current implementation if a region is referred twice in
315 * a command stream, it will be accounted twice. We could detect repeated
316 * regions and count only once, but there is no incentive to do that, since
317 * regions are typically short-lived; always referred in a single command;
318 * and at the worst we just flush the commands a bit sooner, which for the
319 * SVGA virtual device it's not a performance issue since flushing commands
320 * to the FIFO won't cause flushing in the host.
322 vswc
->seen_regions
+= reloc
->buffer
->base
.size
;
323 if(vswc
->seen_regions
>= VMW_GMR_POOL_SIZE
/3)
324 vswc
->preemptive_flush
= TRUE
;
329 vmw_swc_commit(struct svga_winsys_context
*swc
)
331 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
333 assert(vswc
->command
.reserved
);
334 assert(vswc
->command
.used
+ vswc
->command
.reserved
<= vswc
->command
.size
);
335 vswc
->command
.used
+= vswc
->command
.reserved
;
336 vswc
->command
.reserved
= 0;
338 assert(vswc
->surface
.staged
<= vswc
->surface
.reserved
);
339 assert(vswc
->surface
.used
+ vswc
->surface
.staged
<= vswc
->surface
.size
);
340 vswc
->surface
.used
+= vswc
->surface
.staged
;
341 vswc
->surface
.staged
= 0;
342 vswc
->surface
.reserved
= 0;
344 assert(vswc
->region
.staged
<= vswc
->region
.reserved
);
345 assert(vswc
->region
.used
+ vswc
->region
.staged
<= vswc
->region
.size
);
346 vswc
->region
.used
+= vswc
->region
.staged
;
347 vswc
->region
.staged
= 0;
348 vswc
->region
.reserved
= 0;
353 vmw_swc_destroy(struct svga_winsys_context
*swc
)
355 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
358 for(i
= 0; i
< vswc
->region
.used
; ++i
) {
359 pb_reference(&vswc
->region
.relocs
[i
].buffer
, NULL
);
362 for(i
= 0; i
< vswc
->surface
.used
; ++i
) {
363 p_atomic_dec(&vswc
->surface
.handles
[i
]->validated
);
364 vmw_svga_winsys_surface_reference(&vswc
->surface
.handles
[i
], NULL
);
366 pb_validate_destroy(vswc
->validate
);
367 vmw_ioctl_context_destroy(vswc
->vws
, swc
->cid
);
372 struct svga_winsys_context
*
373 vmw_svga_winsys_context_create(struct svga_winsys_screen
*sws
)
375 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
376 struct vmw_svga_winsys_context
*vswc
;
378 vswc
= CALLOC_STRUCT(vmw_svga_winsys_context
);
382 vswc
->base
.destroy
= vmw_swc_destroy
;
383 vswc
->base
.reserve
= vmw_swc_reserve
;
384 vswc
->base
.surface_relocation
= vmw_swc_surface_relocation
;
385 vswc
->base
.region_relocation
= vmw_swc_region_relocation
;
386 vswc
->base
.commit
= vmw_swc_commit
;
387 vswc
->base
.flush
= vmw_swc_flush
;
389 vswc
->base
.cid
= vmw_ioctl_context_create(vws
);
393 vswc
->command
.size
= VMW_COMMAND_SIZE
;
394 vswc
->surface
.size
= VMW_SURFACE_RELOCS
;
395 vswc
->region
.size
= VMW_REGION_RELOCS
;
397 vswc
->validate
= pb_validate_create();
398 if(!vswc
->validate
) {
408 vmw_svga_context_set_throttling(struct pipe_context
*pipe
,
409 uint32_t throttle_us
)
411 struct svga_winsys_context
*swc
= svga_winsys_context(pipe
);
412 struct vmw_svga_winsys_context
*vswc
= vmw_svga_winsys_context(swc
);
414 vswc
->throttle_us
= throttle_us
;
415 vswc
->throttle_set
= TRUE
;