lp_setup.c revision 1928c965b1fb76987cbc834111bd1d1e1f2cda51
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/**
29 * Tiling engine.
30 *
31 * Builds per-tile display lists and executes them on calls to
32 * lp_setup_flush().
33 */
34
35#include "pipe/p_defines.h"
36#include "pipe/p_inlines.h"
37#include "util/u_math.h"
38#include "util/u_memory.h"
39#include "util/u_pack_color.h"
40#include "lp_state.h"
41#include "lp_buffer.h"
42#include "lp_texture.h"
43#include "lp_setup_context.h"
44
45static void set_state( struct setup_context *, unsigned );
46
47void lp_setup_new_cmd_block( struct cmd_block_list *list )
48{
49   struct cmd_block *block = MALLOC_STRUCT(cmd_block);
50   list->tail->next = block;
51   list->tail = block;
52   block->next = NULL;
53   block->count = 0;
54}
55
56void lp_setup_new_data_block( struct data_block_list *list )
57{
58   struct data_block *block = MALLOC_STRUCT(data_block);
59   list->tail->next = block;
60   list->tail = block;
61   block->next = NULL;
62   block->used = 0;
63}
64
65
66static void
67first_triangle( struct setup_context *setup,
68                const float (*v0)[4],
69                const float (*v1)[4],
70                const float (*v2)[4])
71{
72   set_state( setup, SETUP_ACTIVE );
73   lp_setup_choose_triangle( setup );
74   setup->triangle( setup, v0, v1, v2 );
75}
76
77static void
78first_line( struct setup_context *setup,
79	    const float (*v0)[4],
80	    const float (*v1)[4])
81{
82   set_state( setup, SETUP_ACTIVE );
83   lp_setup_choose_line( setup );
84   setup->line( setup, v0, v1 );
85}
86
87static void
88first_point( struct setup_context *setup,
89	     const float (*v0)[4])
90{
91   set_state( setup, SETUP_ACTIVE );
92   lp_setup_choose_point( setup );
93   setup->point( setup, v0 );
94}
95
96static void reset_context( struct setup_context *setup )
97{
98   unsigned i, j;
99
100   /* Free binner command lists:
101    */
102   for (i = 0; i < setup->tiles_x; i++) {
103      for (j = 0; j < setup->tiles_y; j++) {
104         struct cmd_block_list *list = &setup->tile[i][j];
105         struct cmd_block *block;
106         struct cmd_block *tmp;
107
108         for (block = list->head; block != list->tail; block = tmp) {
109            tmp = block->next;
110            FREE(block);
111         }
112
113         list->head = list->tail;
114      }
115   }
116
117   /* Free binned data:
118    */
119   {
120      struct data_block_list *list = &setup->data;
121      struct data_block *block, *tmp;
122
123      for (block = list->head; block != list->tail; block = tmp) {
124         tmp = block->next;
125         FREE(block);
126      }
127
128      list->head = list->tail;
129   }
130
131   /* Reset some state:
132    */
133   setup->clear.flags = 0;
134
135   /* Have an explicit "start-binning" call and get rid of this
136    * pointer twiddling?
137    */
138   setup->line = first_line;
139   setup->point = first_point;
140   setup->triangle = first_triangle;
141}
142
143
144
145
146/* Add a command to all active bins.
147 */
148static void bin_everywhere( struct setup_context *setup,
149                            lp_rast_cmd cmd,
150                            const union lp_rast_cmd_arg arg )
151{
152   unsigned i, j;
153   for (i = 0; i < setup->tiles_x; i++)
154      for (j = 0; j < setup->tiles_y; j++)
155         bin_command( &setup->tile[i][j], cmd, arg );
156}
157
158
159static void
160rasterize_bins( struct setup_context *setup,
161                boolean write_depth )
162{
163   struct lp_rasterizer *rast = setup->rast;
164   struct cmd_block *block;
165   unsigned i,j,k;
166
167   if (setup->state != SETUP_ACTIVE) {
168      /* this can happen, not a big deal */
169      debug_printf("%s called when not binning\n", __FUNCTION__);
170      return;
171   }
172
173   lp_rast_begin( rast,
174                  setup->fb.width,
175                  setup->fb.height );
176
177   lp_rast_bind_color( rast,
178                       setup->fb.cbuf,
179                       setup->fb.cbuf != NULL );
180
181   lp_rast_bind_zstencil( rast,
182                          setup->fb.zsbuf,
183                          setup->fb.zsbuf != NULL && write_depth );
184
185   for (i = 0; i < setup->tiles_x; i++) {
186      for (j = 0; j < setup->tiles_y; j++) {
187
188         lp_rast_start_tile( rast,
189                             i * TILESIZE,
190                             j * TILESIZE );
191
192         for (block = setup->tile[i][j].head; block; block = block->next) {
193            for (k = 0; k < block->count; k++) {
194               block->cmd[k]( rast, block->arg[k] );
195            }
196         }
197
198         lp_rast_end_tile( rast );
199      }
200   }
201
202   reset_context( setup );
203}
204
205
206
207static void
208begin_binning( struct setup_context *setup )
209{
210   if (!setup->fb.cbuf && !setup->fb.zsbuf) {
211      setup->fb.width = 0;
212      setup->fb.height = 0;
213   }
214   else if (!setup->fb.zsbuf) {
215      setup->fb.width = setup->fb.cbuf->width;
216      setup->fb.height = setup->fb.cbuf->height;
217   }
218   else if (!setup->fb.cbuf) {
219      setup->fb.width = setup->fb.zsbuf->width;
220      setup->fb.height = setup->fb.zsbuf->height;
221   }
222   else {
223      /* XXX: not sure what we're really supposed to do for
224       * mis-matched color & depth buffer sizes.
225       */
226      setup->fb.width = MIN2(setup->fb.cbuf->width,
227                             setup->fb.zsbuf->width);
228      setup->fb.height = MIN2(setup->fb.cbuf->height,
229                              setup->fb.zsbuf->height);
230   }
231
232   setup->tiles_x = align(setup->fb.width, TILESIZE);
233   setup->tiles_y = align(setup->fb.height, TILESIZE);
234
235   if (setup->fb.cbuf) {
236      if (setup->clear.flags & PIPE_CLEAR_COLOR)
237         bin_everywhere( setup,
238                         lp_rast_clear_color,
239                         setup->clear.color );
240      else
241         bin_everywhere( setup, lp_rast_load_color, lp_rast_arg_null() );
242   }
243
244   if (setup->fb.zsbuf) {
245      if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
246         bin_everywhere( setup,
247                         lp_rast_clear_zstencil,
248                         setup->clear.zstencil );
249      else
250         bin_everywhere( setup, lp_rast_load_zstencil, lp_rast_arg_null() );
251   }
252}
253
254
255/* This basically bins and then flushes any outstanding full-screen
256 * clears.
257 *
258 * TODO: fast path for fullscreen clears and no triangles.
259 */
260static void
261execute_clears( struct setup_context *setup )
262{
263   begin_binning( setup );
264   rasterize_bins( setup, TRUE );
265}
266
267
268static void
269set_state( struct setup_context *setup,
270           unsigned new_state )
271{
272   unsigned old_state = setup->state;
273
274   if (old_state == new_state)
275      return;
276
277   switch (new_state) {
278   case SETUP_ACTIVE:
279      if (old_state == SETUP_FLUSHED)
280         begin_binning( setup );
281      break;
282
283   case SETUP_CLEARED:
284      if (old_state == SETUP_ACTIVE) {
285         assert(0);
286         return;
287      }
288      break;
289
290   case SETUP_FLUSHED:
291      if (old_state == SETUP_CLEARED)
292         execute_clears( setup );
293      else
294         rasterize_bins( setup, TRUE );
295      break;
296   }
297
298   setup->state = new_state;
299}
300
301
302void
303lp_setup_flush( struct setup_context *setup,
304                unsigned flags )
305{
306   set_state( setup, SETUP_FLUSHED );
307}
308
309
310void
311lp_setup_bind_framebuffer( struct setup_context *setup,
312                           struct pipe_surface *color,
313                           struct pipe_surface *zstencil )
314{
315   unsigned width, height;
316
317   set_state( setup, SETUP_FLUSHED );
318
319   pipe_surface_reference( &setup->fb.cbuf, color );
320   pipe_surface_reference( &setup->fb.zsbuf, zstencil );
321
322   width = MAX2( color->width, zstencil->width );
323   height = MAX2( color->height, zstencil->height );
324
325   setup->tiles_x = align( width, TILESIZE ) / TILESIZE;
326   setup->tiles_y = align( height, TILESIZE ) / TILESIZE;
327}
328
329void
330lp_setup_clear( struct setup_context *setup,
331                const float *color,
332                double depth,
333                unsigned stencil,
334                unsigned flags )
335{
336   if (flags & PIPE_CLEAR_COLOR) {
337      util_pack_color(color,
338                      setup->fb.cbuf->format,
339                      &setup->clear.color.clear_color );
340   }
341
342   if (flags & PIPE_CLEAR_DEPTHSTENCIL) {
343      setup->clear.zstencil.clear_zstencil =
344         util_pack_z_stencil(setup->fb.zsbuf->format,
345                             depth,
346                             stencil);
347   }
348
349   if (setup->state == SETUP_ACTIVE) {
350      /* Add the clear to existing bins.  In the unusual case where
351       * both color and depth-stencilare being cleared, we could
352       * discard the currently binned scene and start again, but I
353       * don't see that as being a common usage.
354       */
355      if (flags & PIPE_CLEAR_COLOR)
356         bin_everywhere( setup,
357                         lp_rast_clear_color,
358                         setup->clear.color );
359
360      if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL)
361         bin_everywhere( setup,
362                         lp_rast_clear_zstencil,
363                         setup->clear.zstencil );
364   }
365   else {
366      /* Put ourselves into the 'pre-clear' state, specifically to try
367       * and accumulate multiple clears to color and depth_stencil
368       * buffers which the app or state-tracker might issue
369       * separately.
370       */
371      set_state( setup, SETUP_CLEARED );
372
373      setup->clear.flags |= flags;
374   }
375}
376
377
378
379void
380lp_setup_set_triangle_state( struct setup_context *setup,
381                             unsigned cull_mode,
382                             boolean ccw_is_frontface)
383{
384   setup->ccw_is_frontface = ccw_is_frontface;
385   setup->cullmode = cull_mode;
386   setup->triangle = first_triangle;
387}
388
389
390
391void
392lp_setup_set_fs_inputs( struct setup_context *setup,
393                        const struct lp_shader_input *input,
394                        unsigned nr )
395{
396   memcpy( setup->fs.input, input, nr * sizeof input[0] );
397   setup->fs.nr_inputs = nr;
398}
399
400void
401lp_setup_set_fs( struct setup_context *setup,
402                 struct lp_fragment_shader *fs )
403{
404   /* FIXME: reference count */
405
406   setup->fs.jit_function = fs->current->jit_function;
407}
408
409void
410lp_setup_set_fs_constants(struct setup_context *setup,
411                          struct pipe_buffer *buffer)
412{
413   const void *data = buffer ? llvmpipe_buffer(buffer)->data : NULL;
414   struct pipe_buffer *dummy;
415
416   /* FIXME: hold on to the reference */
417   dummy = NULL;
418   pipe_buffer_reference(&dummy, buffer);
419
420   setup->fs.jit_context.constants = data;
421
422   setup->fs.jit_context_dirty = TRUE;
423}
424
425
426void
427lp_setup_set_alpha_ref_value( struct setup_context *setup,
428                              float alpha_ref_value )
429{
430   if(setup->fs.jit_context.alpha_ref_value != alpha_ref_value) {
431      setup->fs.jit_context.alpha_ref_value = alpha_ref_value;
432      setup->fs.jit_context_dirty = TRUE;
433   }
434}
435
436void
437lp_setup_set_blend_color( struct setup_context *setup,
438                          const struct pipe_blend_color *blend_color )
439{
440   unsigned i, j;
441
442   if(!setup->fs.jit_context.blend_color)
443      setup->fs.jit_context.blend_color = align_malloc(4 * 16, 16);
444
445   for (i = 0; i < 4; ++i) {
446      uint8_t c = float_to_ubyte(blend_color->color[i]);
447      for (j = 0; j < 16; ++j)
448         setup->fs.jit_context.blend_color[i*4 + j] = c;
449   }
450
451   setup->fs.jit_context_dirty = TRUE;
452}
453
454void
455lp_setup_set_sampler_textures( struct setup_context *setup,
456                               unsigned num, struct pipe_texture **texture)
457{
458   struct pipe_texture *dummy;
459   unsigned i;
460
461   assert(num <= PIPE_MAX_SAMPLERS);
462
463   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
464      struct pipe_texture *tex = i < num ? texture[i] : NULL;
465
466      /* FIXME: hold on to the reference */
467      dummy = NULL;
468      pipe_texture_reference(&dummy, tex);
469
470      if(tex) {
471         struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
472         struct lp_jit_texture *jit_tex = &setup->fs.jit_context.textures[i];
473         jit_tex->width = tex->width[0];
474         jit_tex->height = tex->height[0];
475         jit_tex->stride = lp_tex->stride[0];
476         if(!lp_tex->dt)
477            jit_tex->data = lp_tex->data;
478         else
479            /* FIXME: map the rendertarget */
480            assert(0);
481      }
482   }
483
484   setup->fs.jit_context_dirty = TRUE;
485}
486
487boolean
488lp_setup_is_texture_referenced( struct setup_context *setup,
489                                const struct pipe_texture *texture )
490{
491   /* FIXME */
492   return PIPE_UNREFERENCED;
493}
494
495
496/* Stubs for lines & points for now:
497 */
498void
499lp_setup_point(struct setup_context *setup,
500		     const float (*v0)[4])
501{
502   setup->point( setup, v0 );
503}
504
505void
506lp_setup_line(struct setup_context *setup,
507		    const float (*v0)[4],
508		    const float (*v1)[4])
509{
510   setup->line( setup, v0, v1 );
511}
512
513void
514lp_setup_tri(struct setup_context *setup,
515             const float (*v0)[4],
516             const float (*v1)[4],
517             const float (*v2)[4])
518{
519   setup->triangle( setup, v0, v1, v2 );
520}
521
522
523void
524lp_setup_destroy( struct setup_context *setup )
525{
526   unsigned i, j;
527
528   reset_context( setup );
529
530   for (i = 0; i < TILES_X; i++)
531      for (j = 0; j < TILES_Y; j++)
532         FREE(setup->tile[i][j].head);
533
534   lp_rast_destroy( setup->rast );
535   FREE( setup );
536}
537
538
539/**
540 * Create a new primitive tiling engine.  Currently also creates a
541 * rasterizer to use with it.
542 */
543struct setup_context *
544lp_setup_create( void )
545{
546   struct setup_context *setup = CALLOC_STRUCT(setup_context);
547   unsigned i, j;
548
549   setup->rast = lp_rast_create();
550   if (!setup->rast)
551      goto fail;
552
553   for (i = 0; i < TILES_X; i++)
554      for (j = 0; j < TILES_Y; j++)
555         setup->tile[i][j].head =
556            setup->tile[i][j].tail = CALLOC_STRUCT(cmd_block);
557
558   return setup;
559
560fail:
561   FREE(setup);
562   return NULL;
563}
564
565