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/2)
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;