Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/**********************************************************
2
 * Copyright 2009 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 "pipebuffer/pb_buffer.h"
33
#include "pipebuffer/pb_validate.h"
34
 
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"
41
 
42
#define VMW_COMMAND_SIZE (64*1024)
43
#define VMW_SURFACE_RELOCS (1024)
44
#define VMW_REGION_RELOCS (512)
45
 
46
#define VMW_MUST_FLUSH_STACK 8
47
 
48
struct vmw_region_relocation
49
{
50
   struct SVGAGuestPtr *where;
51
   struct pb_buffer *buffer;
52
   /* TODO: put offset info inside where */
53
   uint32 offset;
54
};
55
 
56
struct vmw_svga_winsys_context
57
{
58
   struct svga_winsys_context base;
59
 
60
   struct vmw_winsys_screen *vws;
61
 
62
#ifdef DEBUG
63
   boolean must_flush;
64
   struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
65
#endif
66
 
67
   struct {
68
      uint8_t buffer[VMW_COMMAND_SIZE];
69
      uint32_t size;
70
      uint32_t used;
71
      uint32_t reserved;
72
   } command;
73
 
74
   struct {
75
      struct vmw_svga_winsys_surface *handles[VMW_SURFACE_RELOCS];
76
      uint32_t size;
77
      uint32_t used;
78
      uint32_t staged;
79
      uint32_t reserved;
80
   } surface;
81
 
82
   struct {
83
      struct vmw_region_relocation relocs[VMW_REGION_RELOCS];
84
      uint32_t size;
85
      uint32_t used;
86
      uint32_t staged;
87
      uint32_t reserved;
88
   } region;
89
 
90
   struct pb_validate *validate;
91
 
92
   /**
93
    * The amount of GMR that is referred by the commands currently batched
94
    * in the context.
95
    */
96
   uint32_t seen_regions;
97
 
98
   /**
99
    * Whether this context should fail to reserve more commands, not because it
100
    * ran out of command space, but because a substantial ammount of GMR was
101
    * referred.
102
    */
103
   boolean preemptive_flush;
104
};
105
 
106
 
107
static INLINE struct vmw_svga_winsys_context *
108
vmw_svga_winsys_context(struct svga_winsys_context *swc)
109
{
110
   assert(swc);
111
   return (struct vmw_svga_winsys_context *)swc;
112
}
113
 
114
 
115
static INLINE unsigned
116
vmw_translate_to_pb_flags(unsigned flags)
117
{
118
   unsigned f = 0;
119
   if (flags & SVGA_RELOC_READ)
120
      f |= PB_USAGE_GPU_READ;
121
 
122
   if (flags & SVGA_RELOC_WRITE)
123
      f |= PB_USAGE_GPU_WRITE;
124
 
125
   return f;
126
}
127
 
128
static enum pipe_error
129
vmw_swc_flush(struct svga_winsys_context *swc,
130
              struct pipe_fence_handle **pfence)
131
{
132
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
133
   struct pipe_fence_handle *fence = NULL;
134
   unsigned i;
135
   enum pipe_error ret;
136
 
137
   ret = pb_validate_validate(vswc->validate);
138
   assert(ret == PIPE_OK);
139
   if(ret == PIPE_OK) {
140
 
141
      /* Apply relocations */
142
      for(i = 0; i < vswc->region.used; ++i) {
143
         struct vmw_region_relocation *reloc = &vswc->region.relocs[i];
144
         struct SVGAGuestPtr ptr;
145
 
146
         if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr))
147
            assert(0);
148
 
149
         ptr.offset += reloc->offset;
150
 
151
         *reloc->where = ptr;
152
      }
153
 
154
      if (vswc->command.used || pfence != NULL)
155
         vmw_ioctl_command(vswc->vws,
156
			   vswc->base.cid,
157
			   0,
158
                           vswc->command.buffer,
159
                           vswc->command.used,
160
                           &fence);
161
 
162
      pb_validate_fence(vswc->validate, fence);
163
   }
164
 
165
   vswc->command.used = 0;
166
   vswc->command.reserved = 0;
167
 
168
   for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
169
      struct vmw_svga_winsys_surface *vsurf =
170
	 vswc->surface.handles[i];
171
      p_atomic_dec(&vsurf->validated);
172
      vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
173
   }
174
 
175
   vswc->surface.used = 0;
176
   vswc->surface.reserved = 0;
177
 
178
   for(i = 0; i < vswc->region.used + vswc->region.staged; ++i) {
179
      pb_reference(&vswc->region.relocs[i].buffer, NULL);
180
   }
181
 
182
   vswc->region.used = 0;
183
   vswc->region.reserved = 0;
184
 
185
#ifdef DEBUG
186
   vswc->must_flush = FALSE;
187
#endif
188
   vswc->preemptive_flush = FALSE;
189
   vswc->seen_regions = 0;
190
 
191
   if(pfence)
192
      vmw_fence_reference(vswc->vws, pfence, fence);
193
 
194
   vmw_fence_reference(vswc->vws, &fence, NULL);
195
 
196
   return ret;
197
}
198
 
199
 
200
static void *
201
vmw_swc_reserve(struct svga_winsys_context *swc,
202
                uint32_t nr_bytes, uint32_t nr_relocs )
203
{
204
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
205
 
206
#ifdef DEBUG
207
   /* Check if somebody forgot to check the previous failure */
208
   if(vswc->must_flush) {
209
      debug_printf("Forgot to flush:\n");
210
      debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
211
      assert(!vswc->must_flush);
212
   }
213
#endif
214
 
215
   assert(nr_bytes <= vswc->command.size);
216
   if(nr_bytes > vswc->command.size)
217
      return NULL;
218
 
219
   if(vswc->preemptive_flush ||
220
      vswc->command.used + nr_bytes > vswc->command.size ||
221
      vswc->surface.used + nr_relocs > vswc->surface.size ||
222
      vswc->region.used + nr_relocs > vswc->region.size) {
223
#ifdef DEBUG
224
      vswc->must_flush = TRUE;
225
      debug_backtrace_capture(vswc->must_flush_stack, 1,
226
                              VMW_MUST_FLUSH_STACK);
227
#endif
228
      return NULL;
229
   }
230
 
231
   assert(vswc->command.used + nr_bytes <= vswc->command.size);
232
   assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
233
   assert(vswc->region.used + nr_relocs <= vswc->region.size);
234
 
235
   vswc->command.reserved = nr_bytes;
236
   vswc->surface.reserved = nr_relocs;
237
   vswc->surface.staged = 0;
238
   vswc->region.reserved = nr_relocs;
239
   vswc->region.staged = 0;
240
 
241
   return vswc->command.buffer + vswc->command.used;
242
}
243
 
244
 
245
static void
246
vmw_swc_surface_relocation(struct svga_winsys_context *swc,
247
                           uint32 *where,
248
                           struct svga_winsys_surface *surface,
249
                           unsigned flags)
250
{
251
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
252
   struct vmw_svga_winsys_surface *vsurf;
253
 
254
   if(!surface) {
255
      *where = SVGA3D_INVALID_ID;
256
      return;
257
   }
258
 
259
   assert(vswc->surface.staged < vswc->surface.reserved);
260
 
261
   vsurf = vmw_svga_winsys_surface(surface);
262
 
263
   *where = vsurf->sid;
264
 
265
   vmw_svga_winsys_surface_reference(&vswc->surface.handles[vswc->surface.used + vswc->surface.staged], vsurf);
266
   p_atomic_inc(&vsurf->validated);
267
   ++vswc->surface.staged;
268
}
269
 
270
 
271
static void
272
vmw_swc_region_relocation(struct svga_winsys_context *swc,
273
                          struct SVGAGuestPtr *where,
274
                          struct svga_winsys_buffer *buffer,
275
                          uint32 offset,
276
                          unsigned flags)
277
{
278
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
279
   struct vmw_region_relocation *reloc;
280
   unsigned translated_flags;
281
   enum pipe_error ret;
282
 
283
   assert(vswc->region.staged < vswc->region.reserved);
284
 
285
   reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
286
   reloc->where = where;
287
   pb_reference(&reloc->buffer, vmw_pb_buffer(buffer));
288
   reloc->offset = offset;
289
 
290
   ++vswc->region.staged;
291
 
292
   translated_flags = vmw_translate_to_pb_flags(flags);
293
   ret = pb_validate_add_buffer(vswc->validate, reloc->buffer, translated_flags);
294
   /* TODO: Update pipebuffer to reserve buffers and not fail here */
295
   assert(ret == PIPE_OK);
296
   (void)ret;
297
 
298
   /*
299
    * Flush preemptively the FIFO commands to keep the GMR working set within
300
    * the GMR pool size.
301
    *
302
    * This is necessary for applications like SPECviewperf that generate huge
303
    * amounts of immediate vertex data, so that we don't pile up too much of
304
    * that vertex data neither in the guest nor in the host.
305
    *
306
    * Note that in the current implementation if a region is referred twice in
307
    * a command stream, it will be accounted twice. We could detect repeated
308
    * regions and count only once, but there is no incentive to do that, since
309
    * regions are typically short-lived; always referred in a single command;
310
    * and at the worst we just flush the commands a bit sooner, which for the
311
    * SVGA virtual device it's not a performance issue since flushing commands
312
    * to the FIFO won't cause flushing in the host.
313
    */
314
   vswc->seen_regions += reloc->buffer->size;
315
   if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/3)
316
      vswc->preemptive_flush = TRUE;
317
}
318
 
319
 
320
static void
321
vmw_swc_commit(struct svga_winsys_context *swc)
322
{
323
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
324
 
325
   assert(vswc->command.reserved);
326
   assert(vswc->command.used + vswc->command.reserved <= vswc->command.size);
327
   vswc->command.used += vswc->command.reserved;
328
   vswc->command.reserved = 0;
329
 
330
   assert(vswc->surface.staged <= vswc->surface.reserved);
331
   assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size);
332
   vswc->surface.used += vswc->surface.staged;
333
   vswc->surface.staged = 0;
334
   vswc->surface.reserved = 0;
335
 
336
   assert(vswc->region.staged <= vswc->region.reserved);
337
   assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
338
   vswc->region.used += vswc->region.staged;
339
   vswc->region.staged = 0;
340
   vswc->region.reserved = 0;
341
}
342
 
343
 
344
static void
345
vmw_swc_destroy(struct svga_winsys_context *swc)
346
{
347
   struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
348
   unsigned i;
349
 
350
   for(i = 0; i < vswc->region.used; ++i) {
351
      pb_reference(&vswc->region.relocs[i].buffer, NULL);
352
   }
353
 
354
   for(i = 0; i < vswc->surface.used; ++i) {
355
      p_atomic_dec(&vswc->surface.handles[i]->validated);
356
      vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
357
   }
358
   pb_validate_destroy(vswc->validate);
359
   vmw_ioctl_context_destroy(vswc->vws, swc->cid);
360
   FREE(vswc);
361
}
362
 
363
 
364
struct svga_winsys_context *
365
vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
366
{
367
   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
368
   struct vmw_svga_winsys_context *vswc;
369
 
370
   vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
371
   if(!vswc)
372
      return NULL;
373
 
374
   vswc->base.destroy = vmw_swc_destroy;
375
   vswc->base.reserve = vmw_swc_reserve;
376
   vswc->base.surface_relocation = vmw_swc_surface_relocation;
377
   vswc->base.region_relocation = vmw_swc_region_relocation;
378
   vswc->base.commit = vmw_swc_commit;
379
   vswc->base.flush = vmw_swc_flush;
380
 
381
   vswc->base.cid = vmw_ioctl_context_create(vws);
382
 
383
   vswc->vws = vws;
384
 
385
   vswc->command.size = VMW_COMMAND_SIZE;
386
   vswc->surface.size = VMW_SURFACE_RELOCS;
387
   vswc->region.size = VMW_REGION_RELOCS;
388
 
389
   vswc->validate = pb_validate_create();
390
   if(!vswc->validate) {
391
      FREE(vswc);
392
      return NULL;
393
   }
394
 
395
   return &vswc->base;
396
}