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