Merge branch 'gallium-tex-surface' into gallium-0.1
[mesa.git] / src / gallium / winsys / xlib / xm_winsys_aub.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell
32 * Brian Paul
33 */
34
35
36 #include "glxheader.h"
37 #include "xmesaP.h"
38
39 #include "pipe/p_winsys.h"
40 #include "pipe/p_util.h"
41 #include "pipe/p_inlines.h"
42 #include "i965simple/brw_winsys.h"
43 #include "i965simple/brw_screen.h"
44 #include "brw_aub.h"
45 #include "xm_winsys_aub.h"
46
47
48
49 struct aub_buffer {
50 char *data;
51 unsigned offset;
52 unsigned size;
53 unsigned refcount;
54 unsigned map_count;
55 boolean dump_on_unmap;
56 };
57
58
59
60 struct aub_pipe_winsys {
61 struct pipe_winsys winsys;
62
63 struct brw_aubfile *aubfile;
64
65 /* This is simple, isn't it:
66 */
67 char *pool;
68 unsigned size;
69 unsigned used;
70 };
71
72
73 /* Turn a pipe winsys into an aub/pipe winsys:
74 */
75 static inline struct aub_pipe_winsys *
76 aub_pipe_winsys( struct pipe_winsys *winsys )
77 {
78 return (struct aub_pipe_winsys *)winsys;
79 }
80
81
82
83 static INLINE struct aub_buffer *
84 aub_bo( struct pipe_buffer *bo )
85 {
86 return (struct aub_buffer *)bo;
87 }
88
89 static INLINE struct pipe_buffer *
90 pipe_bo( struct aub_buffer *bo )
91 {
92 return (struct pipe_buffer *)bo;
93 }
94
95
96
97
98 static void *aub_buffer_map(struct pipe_winsys *winsys,
99 struct pipe_buffer *buf,
100 unsigned flags )
101 {
102 struct aub_buffer *sbo = aub_bo(buf);
103
104 assert(sbo->data);
105
106 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
107 sbo->dump_on_unmap = 1;
108
109 sbo->map_count++;
110 return sbo->data;
111 }
112
113 static void aub_buffer_unmap(struct pipe_winsys *winsys,
114 struct pipe_buffer *buf)
115 {
116 struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
117 struct aub_buffer *sbo = aub_bo(buf);
118
119 sbo->map_count--;
120
121 if (sbo->map_count == 0 &&
122 sbo->dump_on_unmap) {
123
124 sbo->dump_on_unmap = 0;
125
126 brw_aub_gtt_data( iws->aubfile,
127 sbo->offset,
128 sbo->data,
129 sbo->size,
130 0,
131 0);
132 }
133 }
134
135
136 static void
137 aub_buffer_destroy(struct pipe_winsys *winsys,
138 struct pipe_buffer *buf)
139 {
140 free(buf);
141 }
142
143
144 void xmesa_buffer_subdata_aub(struct pipe_winsys *winsys,
145 struct pipe_buffer *buf,
146 unsigned long offset,
147 unsigned long size,
148 const void *data,
149 unsigned aub_type,
150 unsigned aub_sub_type)
151 {
152 struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
153 struct aub_buffer *sbo = aub_bo(buf);
154
155 assert(sbo->size > offset + size);
156 memcpy(sbo->data + offset, data, size);
157
158 brw_aub_gtt_data( iws->aubfile,
159 sbo->offset + offset,
160 sbo->data + offset,
161 size,
162 aub_type,
163 aub_sub_type );
164 }
165
166 void xmesa_commands_aub(struct pipe_winsys *winsys,
167 unsigned *cmds,
168 unsigned nr_dwords)
169 {
170 struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
171 unsigned size = nr_dwords * 4;
172
173 assert(iws->used + size < iws->size);
174
175 brw_aub_gtt_cmds( iws->aubfile,
176 AUB_BUF_START + iws->used,
177 cmds,
178 nr_dwords * sizeof(int) );
179
180 iws->used += align(size, 4096);
181 }
182
183
184 static struct aub_pipe_winsys *global_winsys = NULL;
185
186 void xmesa_display_aub( /* struct pipe_winsys *winsys, */
187 struct pipe_surface *surface )
188 {
189 // struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
190 brw_aub_dump_bmp( global_winsys->aubfile,
191 surface,
192 aub_bo(surface->buffer)->offset );
193 }
194
195
196
197 /* Pipe has no concept of pools. We choose the tex/region pool
198 * for all buffers.
199 */
200 static struct pipe_buffer *
201 aub_buffer_create(struct pipe_winsys *winsys,
202 unsigned alignment,
203 unsigned usage,
204 unsigned size)
205 {
206 struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
207 struct aub_buffer *sbo = CALLOC_STRUCT(aub_buffer);
208
209 sbo->refcount = 1;
210
211 /* Could reuse buffers that are not referenced in current
212 * batchbuffer. Can't do that atm, so always reallocate:
213 */
214 assert(iws->used + size < iws->size);
215 sbo->data = iws->pool + iws->used;
216 sbo->offset = AUB_BUF_START + iws->used;
217 iws->used += align(size, 4096);
218
219 sbo->size = size;
220
221 return pipe_bo(sbo);
222 }
223
224
225 static struct pipe_buffer *
226 aub_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes)
227 {
228 struct aub_buffer *sbo;
229
230 /* Lets hope this is meant for upload, not as a result!
231 */
232 sbo = aub_bo(aub_buffer_create( winsys, 0, 0, 0 ));
233
234 sbo->data = ptr;
235 sbo->size = bytes;
236
237 return pipe_bo(sbo);
238 }
239
240
241 /* The state tracker (should!) keep track of whether the fake
242 * frontbuffer has been touched by any rendering since the last time
243 * we copied its contents to the real frontbuffer. Our task is easy:
244 */
245 static void
246 aub_flush_frontbuffer( struct pipe_winsys *winsys,
247 struct pipe_surface *surf,
248 void *context_private)
249 {
250 xmesa_display_aub( surf );
251 }
252
253 static struct pipe_surface *
254 aub_i915_surface_alloc(struct pipe_winsys *winsys)
255 {
256 struct pipe_surface *surf = CALLOC_STRUCT(pipe_surface);
257 if (surf) {
258 surf->refcount = 1;
259 surf->winsys = winsys;
260 }
261 return surf;
262 }
263
264
265 /**
266 * Round n up to next multiple.
267 */
268 static INLINE unsigned
269 round_up(unsigned n, unsigned multiple)
270 {
271 return (n + multiple - 1) & ~(multiple - 1);
272 }
273
274 static int
275 aub_i915_surface_alloc_storage(struct pipe_winsys *winsys,
276 struct pipe_surface *surf,
277 unsigned width, unsigned height,
278 enum pipe_format format,
279 unsigned flags,
280 unsigned tex_usage)
281 {
282 const unsigned alignment = 64;
283
284 surf->width = width;
285 surf->height = height;
286 surf->format = format;
287 surf->cpp = pf_get_size(format);
288 surf->pitch = round_up(width, alignment / surf->cpp);
289
290 assert(!surf->buffer);
291 surf->buffer = winsys->buffer_create(winsys, alignment,
292 PIPE_BUFFER_USAGE_PIXEL,
293 surf->pitch * surf->cpp * height);
294 if(!surf->buffer)
295 return -1;
296
297 return 0;
298 }
299
300 static void
301 aub_i915_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
302 {
303 struct pipe_surface *surf = *s;
304 surf->refcount--;
305 if (surf->refcount == 0) {
306 if (surf->buffer)
307 pipe_buffer_reference(winsys, &surf->buffer, NULL);
308 free(surf);
309 }
310 *s = NULL;
311 }
312
313
314
315 static const char *
316 aub_get_name( struct pipe_winsys *winsys )
317 {
318 return "Aub/xlib";
319 }
320
321 struct pipe_winsys *
322 xmesa_create_pipe_winsys_aub( void )
323 {
324 struct aub_pipe_winsys *iws = CALLOC_STRUCT( aub_pipe_winsys );
325
326 /* Fill in this struct with callbacks that pipe will need to
327 * communicate with the window system, buffer manager, etc.
328 *
329 * Pipe would be happy with a malloc based memory manager, but
330 * the SwapBuffers implementation in this winsys driver requires
331 * that rendering be done to an appropriate _DriBufferObject.
332 */
333 iws->winsys.buffer_create = aub_buffer_create;
334 iws->winsys.user_buffer_create = aub_user_buffer_create;
335 iws->winsys.buffer_map = aub_buffer_map;
336 iws->winsys.buffer_unmap = aub_buffer_unmap;
337 iws->winsys.buffer_destroy = aub_buffer_destroy;
338 iws->winsys.flush_frontbuffer = aub_flush_frontbuffer;
339 iws->winsys.get_name = aub_get_name;
340
341 iws->winsys.surface_alloc = aub_i915_surface_alloc;
342 iws->winsys.surface_alloc_storage = aub_i915_surface_alloc_storage;
343 iws->winsys.surface_release = aub_i915_surface_release;
344
345 iws->aubfile = brw_aubfile_create();
346 iws->size = AUB_BUF_SIZE;
347 iws->pool = malloc(AUB_BUF_SIZE);
348
349 /* HACK: static copy of this pointer:
350 */
351 assert(global_winsys == NULL);
352 global_winsys = iws;
353
354 return &iws->winsys;
355 }
356
357
358 void
359 xmesa_destroy_pipe_winsys_aub( struct pipe_winsys *winsys )
360
361 {
362 struct aub_pipe_winsys *iws = aub_pipe_winsys(winsys);
363 brw_aub_destroy(iws->aubfile);
364 free(iws->pool);
365 free(iws);
366 }
367
368
369
370
371
372
373
374 #define IWS_BATCHBUFFER_SIZE 1024
375
376 struct aub_brw_winsys {
377 struct brw_winsys winsys; /**< batch buffer funcs */
378 struct aub_context *aub;
379
380 struct pipe_winsys *pipe_winsys;
381
382 unsigned batch_data[IWS_BATCHBUFFER_SIZE];
383 unsigned batch_nr;
384 unsigned batch_size;
385 unsigned batch_alloc;
386 };
387
388
389 /* Turn a i965simple winsys into an aub/i965simple winsys:
390 */
391 static inline struct aub_brw_winsys *
392 aub_brw_winsys( struct brw_winsys *sws )
393 {
394 return (struct aub_brw_winsys *)sws;
395 }
396
397
398 /* Simple batchbuffer interface:
399 */
400
401 static unsigned *aub_i965_batch_start( struct brw_winsys *sws,
402 unsigned dwords,
403 unsigned relocs )
404 {
405 struct aub_brw_winsys *iws = aub_brw_winsys(sws);
406
407 if (iws->batch_size < iws->batch_nr + dwords)
408 return NULL;
409
410 iws->batch_alloc = iws->batch_nr + dwords;
411 return (void *)1; /* not a valid pointer! */
412 }
413
414 static void aub_i965_batch_dword( struct brw_winsys *sws,
415 unsigned dword )
416 {
417 struct aub_brw_winsys *iws = aub_brw_winsys(sws);
418
419 assert(iws->batch_nr < iws->batch_alloc);
420 iws->batch_data[iws->batch_nr++] = dword;
421 }
422
423 static void aub_i965_batch_reloc( struct brw_winsys *sws,
424 struct pipe_buffer *buf,
425 unsigned access_flags,
426 unsigned delta )
427 {
428 struct aub_brw_winsys *iws = aub_brw_winsys(sws);
429
430 assert(iws->batch_nr < iws->batch_alloc);
431 iws->batch_data[iws->batch_nr++] = aub_bo(buf)->offset + delta;
432 }
433
434 static unsigned aub_i965_get_buffer_offset( struct brw_winsys *sws,
435 struct pipe_buffer *buf,
436 unsigned access_flags )
437 {
438 return aub_bo(buf)->offset;
439 }
440
441 static void aub_i965_batch_end( struct brw_winsys *sws )
442 {
443 struct aub_brw_winsys *iws = aub_brw_winsys(sws);
444
445 assert(iws->batch_nr <= iws->batch_alloc);
446 iws->batch_alloc = 0;
447 }
448
449 static void aub_i965_batch_flush( struct brw_winsys *sws,
450 struct pipe_fence_handle **fence )
451 {
452 struct aub_brw_winsys *iws = aub_brw_winsys(sws);
453 assert(iws->batch_nr <= iws->batch_size);
454
455 if (iws->batch_nr) {
456 xmesa_commands_aub( iws->pipe_winsys,
457 iws->batch_data,
458 iws->batch_nr );
459 }
460
461 iws->batch_nr = 0;
462 }
463
464
465
466 static void aub_i965_buffer_subdata_typed(struct brw_winsys *winsys,
467 struct pipe_buffer *buf,
468 unsigned long offset,
469 unsigned long size,
470 const void *data,
471 unsigned data_type)
472 {
473 struct aub_brw_winsys *iws = aub_brw_winsys(winsys);
474 unsigned aub_type = DW_GENERAL_STATE;
475 unsigned aub_sub_type;
476
477 switch (data_type) {
478 case BRW_CC_VP:
479 aub_sub_type = DWGS_COLOR_CALC_VIEWPORT_STATE;
480 break;
481 case BRW_CC_UNIT:
482 aub_sub_type = DWGS_COLOR_CALC_STATE;
483 break;
484 case BRW_WM_PROG:
485 aub_sub_type = DWGS_KERNEL_INSTRUCTIONS;
486 break;
487 case BRW_SAMPLER_DEFAULT_COLOR:
488 aub_sub_type = DWGS_SAMPLER_DEFAULT_COLOR;
489 break;
490 case BRW_SAMPLER:
491 aub_sub_type = DWGS_SAMPLER_STATE;
492 break;
493 case BRW_WM_UNIT:
494 aub_sub_type = DWGS_WINDOWER_IZ_STATE;
495 break;
496 case BRW_SF_PROG:
497 aub_sub_type = DWGS_KERNEL_INSTRUCTIONS;
498 break;
499 case BRW_SF_VP:
500 aub_sub_type = DWGS_STRIPS_FANS_VIEWPORT_STATE;
501 break;
502 case BRW_SF_UNIT:
503 aub_sub_type = DWGS_STRIPS_FANS_STATE;
504 break;
505 case BRW_VS_UNIT:
506 aub_sub_type = DWGS_VERTEX_SHADER_STATE;
507 break;
508 case BRW_VS_PROG:
509 aub_sub_type = DWGS_KERNEL_INSTRUCTIONS;
510 break;
511 case BRW_GS_UNIT:
512 aub_sub_type = DWGS_GEOMETRY_SHADER_STATE;
513 break;
514 case BRW_GS_PROG:
515 aub_sub_type = DWGS_KERNEL_INSTRUCTIONS;
516 break;
517 case BRW_CLIP_VP:
518 aub_sub_type = DWGS_CLIPPER_VIEWPORT_STATE;
519 break;
520 case BRW_CLIP_UNIT:
521 aub_sub_type = DWGS_CLIPPER_STATE;
522 break;
523 case BRW_CLIP_PROG:
524 aub_sub_type = DWGS_KERNEL_INSTRUCTIONS;
525 break;
526 case BRW_SS_SURFACE:
527 aub_type = DW_SURFACE_STATE;
528 aub_sub_type = DWSS_SURFACE_STATE;
529 break;
530 case BRW_SS_SURF_BIND:
531 aub_type = DW_SURFACE_STATE;
532 aub_sub_type = DWSS_BINDING_TABLE_STATE;
533 break;
534 case BRW_CONSTANT_BUFFER:
535 aub_type = DW_CONSTANT_URB_ENTRY;
536 aub_sub_type = 0;
537 break;
538
539 default:
540 assert(0);
541 break;
542 }
543
544 xmesa_buffer_subdata_aub( iws->pipe_winsys,
545 buf,
546 offset,
547 size,
548 data,
549 aub_type,
550 aub_sub_type );
551 }
552
553 /**
554 * Create i965 hardware rendering context.
555 */
556 struct pipe_context *
557 xmesa_create_i965simple( struct pipe_winsys *winsys )
558 {
559 struct aub_brw_winsys *iws = CALLOC_STRUCT( aub_brw_winsys );
560 struct pipe_screen *screen = brw_create_screen(winsys, 0/* XXX pci_id */);
561
562 /* Fill in this struct with callbacks that i965simple will need to
563 * communicate with the window system, buffer manager, etc.
564 */
565 iws->winsys.batch_start = aub_i965_batch_start;
566 iws->winsys.batch_dword = aub_i965_batch_dword;
567 iws->winsys.batch_reloc = aub_i965_batch_reloc;
568 iws->winsys.batch_end = aub_i965_batch_end;
569 iws->winsys.batch_flush = aub_i965_batch_flush;
570 iws->winsys.buffer_subdata_typed = aub_i965_buffer_subdata_typed;
571 iws->winsys.get_buffer_offset = aub_i965_get_buffer_offset;
572
573 iws->pipe_winsys = winsys;
574
575 iws->batch_size = IWS_BATCHBUFFER_SIZE;
576
577 /* Create the i965simple context:
578 */
579 return brw_create( screen,
580 &iws->winsys,
581 0 );
582 }