Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / gallium / winsys / drm / vmware / core / vmw_context.c
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
45 #define VMW_MUST_FLUSH_STACK 8
46
47 struct vmw_svga_winsys_context
48 {
49 struct svga_winsys_context base;
50
51 struct vmw_winsys_screen *vws;
52
53 #ifdef DEBUG
54 boolean must_flush;
55 struct debug_stack_frame must_flush_stack[VMW_MUST_FLUSH_STACK];
56 #endif
57
58 struct {
59 uint8_t buffer[VMW_COMMAND_SIZE];
60 uint32_t size;
61 uint32_t used;
62 uint32_t reserved;
63 } command;
64
65 struct {
66 struct vmw_svga_winsys_surface *handles[VMW_SURFACE_RELOCS];
67 uint32_t size;
68 uint32_t used;
69 uint32_t staged;
70 uint32_t reserved;
71 } surface;
72
73 struct pb_validate *validate;
74
75 uint32_t last_fence;
76 };
77
78
79 static INLINE struct vmw_svga_winsys_context *
80 vmw_svga_winsys_context(struct svga_winsys_context *swc)
81 {
82 assert(swc);
83 return (struct vmw_svga_winsys_context *)swc;
84 }
85
86
87 static enum pipe_error
88 vmw_swc_flush(struct svga_winsys_context *swc,
89 struct pipe_fence_handle **pfence)
90 {
91 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
92 struct pipe_fence_handle *fence = NULL;
93 unsigned i;
94 enum pipe_error ret;
95
96 ret = pb_validate_validate(vswc->validate);
97 assert(ret == PIPE_OK);
98 if(ret == PIPE_OK) {
99
100 if (vswc->command.used)
101 vmw_ioctl_command(vswc->vws,
102 vswc->command.buffer,
103 vswc->command.used,
104 &vswc->last_fence);
105
106 fence = vmw_pipe_fence(vswc->last_fence);
107
108 pb_validate_fence(vswc->validate, fence);
109 }
110
111 vswc->command.used = 0;
112 vswc->command.reserved = 0;
113
114 for(i = 0; i < vswc->surface.used + vswc->surface.staged; ++i) {
115 struct vmw_svga_winsys_surface *vsurf =
116 vswc->surface.handles[i];
117 p_atomic_dec(&vsurf->validated);
118 vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
119 }
120
121 vswc->surface.used = 0;
122 vswc->surface.reserved = 0;
123
124 #ifdef DEBUG
125 vswc->must_flush = FALSE;
126 #endif
127
128 if(pfence)
129 *pfence = fence;
130
131 return ret;
132 }
133
134
135 static void *
136 vmw_swc_reserve(struct svga_winsys_context *swc,
137 uint32_t nr_bytes, uint32_t nr_relocs )
138 {
139 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
140
141 #ifdef DEBUG
142 /* Check if somebody forgot to check the previous failure */
143 if(vswc->must_flush) {
144 debug_printf("Forgot to flush:\n");
145 debug_backtrace_dump(vswc->must_flush_stack, VMW_MUST_FLUSH_STACK);
146 assert(!vswc->must_flush);
147 }
148 #endif
149
150 assert(nr_bytes <= vswc->command.size);
151 if(nr_bytes > vswc->command.size)
152 return NULL;
153
154 if(vswc->command.used + nr_bytes > vswc->command.size ||
155 vswc->surface.used + nr_relocs > vswc->surface.size) {
156 #ifdef DEBUG
157 vswc->must_flush = TRUE;
158 debug_backtrace_capture(vswc->must_flush_stack, 1,
159 VMW_MUST_FLUSH_STACK);
160 #endif
161 return NULL;
162 }
163
164 assert(vswc->command.used + nr_bytes <= vswc->command.size);
165 assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
166
167 vswc->command.reserved = nr_bytes;
168 vswc->surface.reserved = nr_relocs;
169 vswc->surface.staged = 0;
170
171 return vswc->command.buffer + vswc->command.used;
172 }
173
174
175 static void
176 vmw_swc_surface_relocation(struct svga_winsys_context *swc,
177 uint32 *where,
178 struct svga_winsys_surface *surface,
179 unsigned flags)
180 {
181 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
182 struct vmw_svga_winsys_surface *vsurf;
183
184 if(!surface) {
185 *where = SVGA3D_INVALID_ID;
186 return;
187 }
188
189 assert(vswc->surface.staged < vswc->surface.reserved);
190
191 vsurf = vmw_svga_winsys_surface(surface);
192
193 *where = vsurf->sid;
194
195 vmw_svga_winsys_surface_reference(&vswc->surface.handles[vswc->surface.used + vswc->surface.staged], vsurf);
196 p_atomic_inc(&vsurf->validated);
197 ++vswc->surface.staged;
198 }
199
200
201 static void
202 vmw_swc_region_relocation(struct svga_winsys_context *swc,
203 struct SVGAGuestPtr *where,
204 struct svga_winsys_buffer *buffer,
205 uint32 offset,
206 unsigned flags)
207 {
208 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
209 struct SVGAGuestPtr ptr;
210 struct pb_buffer *buf = vmw_pb_buffer(buffer);
211 enum pipe_error ret;
212
213 if(!vmw_gmr_bufmgr_region_ptr(buf, &ptr))
214 assert(0);
215
216 ptr.offset += offset;
217
218 *where = ptr;
219
220 ret = pb_validate_add_buffer(vswc->validate, buf, flags);
221 /* TODO: Update pipebuffer to reserve buffers and not fail here */
222 assert(ret == PIPE_OK);
223 }
224
225
226 static void
227 vmw_swc_commit(struct svga_winsys_context *swc)
228 {
229 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
230
231 assert(vswc->command.reserved);
232 assert(vswc->command.used + vswc->command.reserved <= vswc->command.size);
233 vswc->command.used += vswc->command.reserved;
234 vswc->command.reserved = 0;
235
236 assert(vswc->surface.staged <= vswc->surface.reserved);
237 assert(vswc->surface.used + vswc->surface.staged <= vswc->surface.size);
238 vswc->surface.used += vswc->surface.staged;
239 vswc->surface.staged = 0;
240 vswc->surface.reserved = 0;
241 }
242
243
244 static void
245 vmw_swc_destroy(struct svga_winsys_context *swc)
246 {
247 struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
248 unsigned i;
249 for(i = 0; i < vswc->surface.used; ++i) {
250 p_atomic_dec(&vswc->surface.handles[i]->validated);
251 vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
252 }
253 pb_validate_destroy(vswc->validate);
254 vmw_ioctl_context_destroy(vswc->vws, swc->cid);
255 FREE(vswc);
256 }
257
258
259 struct svga_winsys_context *
260 vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
261 {
262 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
263 struct vmw_svga_winsys_context *vswc;
264
265 vswc = CALLOC_STRUCT(vmw_svga_winsys_context);
266 if(!vswc)
267 return NULL;
268
269 vswc->base.destroy = vmw_swc_destroy;
270 vswc->base.reserve = vmw_swc_reserve;
271 vswc->base.surface_relocation = vmw_swc_surface_relocation;
272 vswc->base.region_relocation = vmw_swc_region_relocation;
273 vswc->base.commit = vmw_swc_commit;
274 vswc->base.flush = vmw_swc_flush;
275
276 vswc->base.cid = vmw_ioctl_context_create(vws);
277
278 vswc->vws = vws;
279
280 vswc->command.size = VMW_COMMAND_SIZE;
281 vswc->surface.size = VMW_SURFACE_RELOCS;
282
283 vswc->validate = pb_validate_create();
284 if(!vswc->validate) {
285 FREE(vswc);
286 return NULL;
287 }
288
289 return &vswc->base;
290 }
291
292
293 struct pipe_context *
294 vmw_svga_context_create(struct pipe_screen *screen)
295 {
296 return svga_context_create(screen);
297 }