1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
31 * Builds per-tile display lists and executes them on calls to
35 #include "pipe/p_defines.h"
36 #include "util/u_inlines.h"
37 #include "util/u_memory.h"
38 #include "util/u_pack_color.h"
39 #include "util/u_surface.h"
41 #include "lp_scene_queue.h"
42 #include "lp_texture.h"
46 #include "lp_setup_context.h"
47 #include "lp_screen.h"
48 #include "state_tracker/sw_winsys.h"
50 #include "draw/draw_context.h"
51 #include "draw/draw_vbuf.h"
54 static void set_scene_state( struct lp_setup_context
*, enum setup_state
);
58 lp_setup_get_current_scene(struct lp_setup_context
*setup
)
62 /* wait for a free/empty scene
64 setup
->scene
= lp_scene_dequeue(setup
->empty_scenes
, TRUE
);
66 assert(lp_scene_is_empty(setup
->scene
));
68 lp_scene_begin_binning(setup
->scene
,
76 first_triangle( struct lp_setup_context
*setup
,
81 set_scene_state( setup
, SETUP_ACTIVE
);
82 lp_setup_choose_triangle( setup
);
83 setup
->triangle( setup
, v0
, v1
, v2
);
87 first_line( struct lp_setup_context
*setup
,
91 set_scene_state( setup
, SETUP_ACTIVE
);
92 lp_setup_choose_line( setup
);
93 setup
->line( setup
, v0
, v1
);
97 first_point( struct lp_setup_context
*setup
,
100 set_scene_state( setup
, SETUP_ACTIVE
);
101 lp_setup_choose_point( setup
);
102 setup
->point( setup
, v0
);
105 static void reset_context( struct lp_setup_context
*setup
)
107 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
109 /* Reset derived state */
110 setup
->constants
.stored_size
= 0;
111 setup
->constants
.stored_data
= NULL
;
112 setup
->fs
.stored
= NULL
;
120 setup
->clear
.flags
= 0;
122 /* Have an explicit "start-binning" call and get rid of this
125 setup
->line
= first_line
;
126 setup
->point
= first_point
;
127 setup
->triangle
= first_triangle
;
131 /** Rasterize all scene's bins */
133 lp_setup_rasterize_scene( struct lp_setup_context
*setup
,
134 boolean write_depth
)
136 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
138 lp_scene_rasterize(scene
,
142 reset_context( setup
);
144 LP_DBG(DEBUG_SETUP
, "%s done \n", __FUNCTION__
);
150 begin_binning( struct lp_setup_context
*setup
)
152 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
154 LP_DBG(DEBUG_SETUP
, "%s color: %s depth: %s\n", __FUNCTION__
,
155 (setup
->clear
.flags
& PIPE_CLEAR_COLOR
) ? "clear": "load",
156 (setup
->clear
.flags
& PIPE_CLEAR_DEPTHSTENCIL
) ? "clear": "load");
158 if (setup
->fb
.nr_cbufs
) {
159 if (setup
->clear
.flags
& PIPE_CLEAR_COLOR
) {
160 lp_scene_bin_everywhere( scene
,
162 setup
->clear
.color
);
163 scene
->has_color_clear
= TRUE
;
167 if (setup
->fb
.zsbuf
) {
168 if (setup
->clear
.flags
& PIPE_CLEAR_DEPTHSTENCIL
) {
169 lp_scene_bin_everywhere( scene
,
170 lp_rast_clear_zstencil
,
171 setup
->clear
.zstencil
);
172 scene
->has_depth_clear
= TRUE
;
176 LP_DBG(DEBUG_SETUP
, "%s done\n", __FUNCTION__
);
180 /* This basically bins and then flushes any outstanding full-screen
183 * TODO: fast path for fullscreen clears and no triangles.
186 execute_clears( struct lp_setup_context
*setup
)
188 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
190 begin_binning( setup
);
191 lp_setup_rasterize_scene( setup
, TRUE
);
196 set_scene_state( struct lp_setup_context
*setup
,
197 enum setup_state new_state
)
199 unsigned old_state
= setup
->state
;
201 if (old_state
== new_state
)
204 LP_DBG(DEBUG_SETUP
, "%s old %d new %d\n", __FUNCTION__
, old_state
, new_state
);
208 begin_binning( setup
);
212 if (old_state
== SETUP_ACTIVE
) {
219 if (old_state
== SETUP_CLEARED
)
220 execute_clears( setup
);
222 lp_setup_rasterize_scene( setup
, TRUE
);
226 assert(0 && "invalid setup state mode");
229 setup
->state
= new_state
;
234 * \param flags bitmask of PIPE_FLUSH_x flags
237 lp_setup_flush( struct lp_setup_context
*setup
,
240 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
243 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
244 union lp_rast_cmd_arg dummy
;
246 if (flags
& (PIPE_FLUSH_SWAPBUFFERS
|
248 /* Store colors in the linear color buffer(s).
249 * If we don't do this here, we'll end up converting the tiled
250 * data to linear in the texture_unmap() function, which will
251 * not be a parallel/threaded operation as here.
253 lp_scene_bin_everywhere(scene
, lp_rast_store_color
, dummy
);
257 set_scene_state( setup
, SETUP_FLUSHED
);
262 lp_setup_bind_framebuffer( struct lp_setup_context
*setup
,
263 const struct pipe_framebuffer_state
*fb
)
265 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
267 /* Flush any old scene.
269 set_scene_state( setup
, SETUP_FLUSHED
);
271 /* Set new state. This will be picked up later when we next need a
274 util_copy_framebuffer_state(&setup
->fb
, fb
);
279 lp_setup_clear( struct lp_setup_context
*setup
,
285 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
288 LP_DBG(DEBUG_SETUP
, "%s state %d\n", __FUNCTION__
, setup
->state
);
291 if (flags
& PIPE_CLEAR_COLOR
) {
292 for (i
= 0; i
< 4; ++i
)
293 setup
->clear
.color
.clear_color
[i
] = float_to_ubyte(color
[i
]);
296 if (flags
& PIPE_CLEAR_DEPTHSTENCIL
) {
297 setup
->clear
.zstencil
.clear_zstencil
=
298 util_pack_z_stencil(setup
->fb
.zsbuf
->format
,
303 if (setup
->state
== SETUP_ACTIVE
) {
304 /* Add the clear to existing scene. In the unusual case where
305 * both color and depth-stencil are being cleared when there's
306 * already been some rendering, we could discard the currently
307 * binned scene and start again, but I don't see that as being
310 if (flags
& PIPE_CLEAR_COLOR
) {
311 lp_scene_bin_everywhere( scene
,
313 setup
->clear
.color
);
314 scene
->has_color_clear
= TRUE
;
317 if (setup
->clear
.flags
& PIPE_CLEAR_DEPTHSTENCIL
) {
318 lp_scene_bin_everywhere( scene
,
319 lp_rast_clear_zstencil
,
320 setup
->clear
.zstencil
);
321 scene
->has_depth_clear
= TRUE
;
326 /* Put ourselves into the 'pre-clear' state, specifically to try
327 * and accumulate multiple clears to color and depth_stencil
328 * buffers which the app or state-tracker might issue
331 set_scene_state( setup
, SETUP_CLEARED
);
333 setup
->clear
.flags
|= flags
;
341 struct pipe_fence_handle
*
342 lp_setup_fence( struct lp_setup_context
*setup
)
344 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
345 const unsigned rank
= lp_scene_get_num_bins( scene
); /* xxx */
346 struct lp_fence
*fence
= lp_fence_create(rank
);
348 LP_DBG(DEBUG_SETUP
, "%s rank %u\n", __FUNCTION__
, rank
);
350 set_scene_state( setup
, SETUP_ACTIVE
);
352 /* insert the fence into all command bins */
353 lp_scene_bin_everywhere( scene
,
355 lp_rast_arg_fence(fence
) );
357 return (struct pipe_fence_handle
*) fence
;
362 lp_setup_set_triangle_state( struct lp_setup_context
*setup
,
364 boolean ccw_is_frontface
,
366 boolean gl_rasterization_rules
)
368 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
370 setup
->ccw_is_frontface
= ccw_is_frontface
;
371 setup
->cullmode
= cull_mode
;
372 setup
->triangle
= first_triangle
;
373 setup
->scissor_test
= scissor
;
374 setup
->pixel_offset
= gl_rasterization_rules
? 0.5f
: 0.0f
;
380 lp_setup_set_fs_inputs( struct lp_setup_context
*setup
,
381 const struct lp_shader_input
*input
,
384 LP_DBG(DEBUG_SETUP
, "%s %p %u\n", __FUNCTION__
, (void *) input
, nr
);
386 memcpy( setup
->fs
.input
, input
, nr
* sizeof input
[0] );
387 setup
->fs
.nr_inputs
= nr
;
391 lp_setup_set_fs_functions( struct lp_setup_context
*setup
,
392 lp_jit_frag_func jit_function0
,
393 lp_jit_frag_func jit_function1
,
396 LP_DBG(DEBUG_SETUP
, "%s %p\n", __FUNCTION__
, (void *) jit_function0
);
397 /* FIXME: reference count */
399 setup
->fs
.current
.jit_function
[0] = jit_function0
;
400 setup
->fs
.current
.jit_function
[1] = jit_function1
;
401 setup
->fs
.current
.opaque
= opaque
;
402 setup
->dirty
|= LP_SETUP_NEW_FS
;
406 lp_setup_set_fs_constants(struct lp_setup_context
*setup
,
407 struct pipe_resource
*buffer
)
409 LP_DBG(DEBUG_SETUP
, "%s %p\n", __FUNCTION__
, (void *) buffer
);
411 pipe_resource_reference(&setup
->constants
.current
, buffer
);
413 setup
->dirty
|= LP_SETUP_NEW_CONSTANTS
;
418 lp_setup_set_alpha_ref_value( struct lp_setup_context
*setup
,
419 float alpha_ref_value
)
421 LP_DBG(DEBUG_SETUP
, "%s %f\n", __FUNCTION__
, alpha_ref_value
);
423 if(setup
->fs
.current
.jit_context
.alpha_ref_value
!= alpha_ref_value
) {
424 setup
->fs
.current
.jit_context
.alpha_ref_value
= alpha_ref_value
;
425 setup
->dirty
|= LP_SETUP_NEW_FS
;
430 lp_setup_set_stencil_ref_values( struct lp_setup_context
*setup
,
431 const ubyte refs
[2] )
433 LP_DBG(DEBUG_SETUP
, "%s %d %d\n", __FUNCTION__
, refs
[0], refs
[1]);
435 if (setup
->fs
.current
.jit_context
.stencil_ref_front
!= refs
[0] ||
436 setup
->fs
.current
.jit_context
.stencil_ref_back
!= refs
[1]) {
437 setup
->fs
.current
.jit_context
.stencil_ref_front
= refs
[0];
438 setup
->fs
.current
.jit_context
.stencil_ref_back
= refs
[1];
439 setup
->dirty
|= LP_SETUP_NEW_FS
;
444 lp_setup_set_blend_color( struct lp_setup_context
*setup
,
445 const struct pipe_blend_color
*blend_color
)
447 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
451 if(memcmp(&setup
->blend_color
.current
, blend_color
, sizeof *blend_color
) != 0) {
452 memcpy(&setup
->blend_color
.current
, blend_color
, sizeof *blend_color
);
453 setup
->dirty
|= LP_SETUP_NEW_BLEND_COLOR
;
459 lp_setup_set_scissor( struct lp_setup_context
*setup
,
460 const struct pipe_scissor_state
*scissor
)
462 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
466 if (memcmp(&setup
->scissor
.current
, scissor
, sizeof(*scissor
)) != 0) {
467 setup
->scissor
.current
= *scissor
; /* struct copy */
468 setup
->dirty
|= LP_SETUP_NEW_SCISSOR
;
474 lp_setup_set_flatshade_first( struct lp_setup_context
*setup
,
475 boolean flatshade_first
)
477 setup
->flatshade_first
= flatshade_first
;
482 lp_setup_set_vertex_info( struct lp_setup_context
*setup
,
483 struct vertex_info
*vertex_info
)
485 /* XXX: just silently holding onto the pointer:
487 setup
->vertex_info
= vertex_info
;
492 * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
495 lp_setup_set_fragment_sampler_views(struct lp_setup_context
*setup
,
497 struct pipe_sampler_view
**views
)
501 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
503 assert(num
<= PIPE_MAX_SAMPLERS
);
505 for (i
= 0; i
< PIPE_MAX_SAMPLERS
; i
++) {
506 struct pipe_sampler_view
*view
= i
< num
? views
[i
] : NULL
;
509 struct pipe_resource
*tex
= view
->texture
;
510 struct llvmpipe_resource
*lp_tex
= llvmpipe_resource(tex
);
511 struct lp_jit_texture
*jit_tex
;
512 jit_tex
= &setup
->fs
.current
.jit_context
.textures
[i
];
513 jit_tex
->width
= tex
->width0
;
514 jit_tex
->height
= tex
->height0
;
515 jit_tex
->depth
= tex
->depth0
;
516 jit_tex
->last_level
= tex
->last_level
;
518 /* We're referencing the texture's internal data, so save a
521 pipe_resource_reference(&setup
->fs
.current_tex
[i
], tex
);
524 /* regular texture - setup array of mipmap level pointers */
526 for (j
= 0; j
<= tex
->last_level
; j
++) {
529 (ubyte
*) lp_tex
->data
+ lp_tex
->level_offset
[j
];
532 llvmpipe_get_texture_image(lp_tex
, 0, j
, LP_TEX_USAGE_READ
,
533 LP_TEX_LAYOUT_LINEAR
);
535 jit_tex
->row_stride
[j
] = lp_tex
->stride
[j
];
539 /* display target texture/surface */
541 * XXX: Where should this be unmapped?
544 struct llvmpipe_screen
*screen
= llvmpipe_screen(tex
->screen
);
545 struct sw_winsys
*winsys
= screen
->winsys
;
546 jit_tex
->data
[0] = winsys
->displaytarget_map(winsys
, lp_tex
->dt
,
548 jit_tex
->row_stride
[0] = lp_tex
->stride
[0];
549 assert(jit_tex
->data
[0]);
554 setup
->dirty
|= LP_SETUP_NEW_FS
;
559 * Is the given texture referenced by any scene?
560 * Note: we have to check all scenes including any scenes currently
561 * being rendered and the current scene being built.
564 lp_setup_is_resource_referenced( const struct lp_setup_context
*setup
,
565 const struct pipe_resource
*texture
)
569 /* check the render targets */
570 for (i
= 0; i
< setup
->fb
.nr_cbufs
; i
++) {
571 if (setup
->fb
.cbufs
[i
]->texture
== texture
)
572 return PIPE_REFERENCED_FOR_READ
| PIPE_REFERENCED_FOR_WRITE
;
574 if (setup
->fb
.zsbuf
&& setup
->fb
.zsbuf
->texture
== texture
) {
575 return PIPE_REFERENCED_FOR_READ
| PIPE_REFERENCED_FOR_WRITE
;
578 /* check textures referenced by the scene */
579 for (i
= 0; i
< Elements(setup
->scenes
); i
++) {
580 if (lp_scene_is_resource_referenced(setup
->scenes
[i
], texture
)) {
581 return PIPE_REFERENCED_FOR_READ
;
585 return PIPE_UNREFERENCED
;
590 * Called by vbuf code when we're about to draw something.
593 lp_setup_update_state( struct lp_setup_context
*setup
)
595 struct lp_scene
*scene
= lp_setup_get_current_scene(setup
);
597 LP_DBG(DEBUG_SETUP
, "%s\n", __FUNCTION__
);
599 assert(setup
->fs
.current
.jit_function
);
601 if(setup
->dirty
& LP_SETUP_NEW_BLEND_COLOR
) {
605 stored
= lp_scene_alloc_aligned(scene
, 4 * 16, 16);
607 /* smear each blend color component across 16 ubyte elements */
608 for (i
= 0; i
< 4; ++i
) {
609 uint8_t c
= float_to_ubyte(setup
->blend_color
.current
.color
[i
]);
610 for (j
= 0; j
< 16; ++j
)
611 stored
[i
*16 + j
] = c
;
614 setup
->blend_color
.stored
= stored
;
616 setup
->fs
.current
.jit_context
.blend_color
= setup
->blend_color
.stored
;
617 setup
->dirty
|= LP_SETUP_NEW_FS
;
620 if (setup
->dirty
& LP_SETUP_NEW_SCISSOR
) {
623 stored
= lp_scene_alloc_aligned(scene
, 4 * sizeof(int32_t), 16);
625 stored
[0] = (float) setup
->scissor
.current
.minx
;
626 stored
[1] = (float) setup
->scissor
.current
.miny
;
627 stored
[2] = (float) setup
->scissor
.current
.maxx
;
628 stored
[3] = (float) setup
->scissor
.current
.maxy
;
630 setup
->scissor
.stored
= stored
;
632 setup
->fs
.current
.jit_context
.scissor_xmin
= stored
[0];
633 setup
->fs
.current
.jit_context
.scissor_ymin
= stored
[1];
634 setup
->fs
.current
.jit_context
.scissor_xmax
= stored
[2];
635 setup
->fs
.current
.jit_context
.scissor_ymax
= stored
[3];
637 setup
->dirty
|= LP_SETUP_NEW_FS
;
640 if(setup
->dirty
& LP_SETUP_NEW_CONSTANTS
) {
641 struct pipe_resource
*buffer
= setup
->constants
.current
;
644 unsigned current_size
= buffer
->width0
;
645 const void *current_data
= llvmpipe_resource_data(buffer
);
647 /* TODO: copy only the actually used constants? */
649 if(setup
->constants
.stored_size
!= current_size
||
650 !setup
->constants
.stored_data
||
651 memcmp(setup
->constants
.stored_data
,
653 current_size
) != 0) {
656 stored
= lp_scene_alloc(scene
, current_size
);
661 setup
->constants
.stored_size
= current_size
;
662 setup
->constants
.stored_data
= stored
;
667 setup
->constants
.stored_size
= 0;
668 setup
->constants
.stored_data
= NULL
;
671 setup
->fs
.current
.jit_context
.constants
= setup
->constants
.stored_data
;
672 setup
->dirty
|= LP_SETUP_NEW_FS
;
676 if(setup
->dirty
& LP_SETUP_NEW_FS
) {
677 if(!setup
->fs
.stored
||
678 memcmp(setup
->fs
.stored
,
680 sizeof setup
->fs
.current
) != 0) {
681 /* The fs state that's been stored in the scene is different from
682 * the new, current state. So allocate a new lp_rast_state object
683 * and append it to the bin's setup data buffer.
686 struct lp_rast_state
*stored
=
687 (struct lp_rast_state
*) lp_scene_alloc(scene
, sizeof *stored
);
691 sizeof setup
->fs
.current
);
692 setup
->fs
.stored
= stored
;
694 /* put the state-set command into all bins */
695 lp_scene_bin_state_command( scene
,
697 lp_rast_arg_state(setup
->fs
.stored
) );
700 /* The scene now references the textures in the rasterization
701 * state record. Note that now.
703 for (i
= 0; i
< Elements(setup
->fs
.current_tex
); i
++) {
704 if (setup
->fs
.current_tex
[i
])
705 lp_scene_texture_reference(scene
, setup
->fs
.current_tex
[i
]);
712 assert(setup
->fs
.stored
);
717 /* Only caller is lp_setup_vbuf_destroy()
720 lp_setup_destroy( struct lp_setup_context
*setup
)
724 reset_context( setup
);
726 for (i
= 0; i
< Elements(setup
->fs
.current_tex
); i
++) {
727 pipe_resource_reference(&setup
->fs
.current_tex
[i
], NULL
);
730 pipe_resource_reference(&setup
->constants
.current
, NULL
);
732 /* free the scenes in the 'empty' queue */
734 struct lp_scene
*scene
= lp_scene_dequeue(setup
->empty_scenes
, FALSE
);
737 lp_scene_destroy(scene
);
740 lp_rast_destroy( setup
->rast
);
747 * Create a new primitive tiling engine. Plug it into the backend of
748 * the draw module. Currently also creates a rasterizer to use with
751 struct lp_setup_context
*
752 lp_setup_create( struct pipe_context
*pipe
,
753 struct draw_context
*draw
)
756 struct lp_setup_context
*setup
= CALLOC_STRUCT(lp_setup_context
);
761 lp_setup_init_vbuf(setup
);
763 setup
->empty_scenes
= lp_scene_queue_create();
764 if (!setup
->empty_scenes
)
767 /* XXX: move this to the screen and share between contexts:
769 setup
->rast
= lp_rast_create();
773 setup
->vbuf
= draw_vbuf_stage(draw
, &setup
->base
);
777 draw_set_rasterize_stage(draw
, setup
->vbuf
);
778 draw_set_render(draw
, &setup
->base
);
780 /* create some empty scenes */
781 for (i
= 0; i
< MAX_SCENES
; i
++) {
782 setup
->scenes
[i
] = lp_scene_create( pipe
, setup
->empty_scenes
);
784 lp_scene_enqueue(setup
->empty_scenes
, setup
->scenes
[i
]);
787 setup
->triangle
= first_triangle
;
788 setup
->line
= first_line
;
789 setup
->point
= first_point
;
797 lp_rast_destroy( setup
->rast
);
802 if (setup
->empty_scenes
)
803 lp_scene_queue_destroy(setup
->empty_scenes
);