Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | serge | 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 |
||
36 | |||
37 | #include "pipe/p_defines.h" |
||
38 | #include "util/u_framebuffer.h" |
||
39 | #include "util/u_inlines.h" |
||
40 | #include "util/u_memory.h" |
||
41 | #include "util/u_pack_color.h" |
||
42 | #include "draw/draw_pipe.h" |
||
43 | #include "os/os_time.h" |
||
44 | #include "lp_context.h" |
||
45 | #include "lp_memory.h" |
||
46 | #include "lp_scene.h" |
||
47 | #include "lp_texture.h" |
||
48 | #include "lp_debug.h" |
||
49 | #include "lp_fence.h" |
||
50 | #include "lp_query.h" |
||
51 | #include "lp_rast.h" |
||
52 | #include "lp_setup_context.h" |
||
53 | #include "lp_screen.h" |
||
54 | #include "lp_state.h" |
||
55 | #include "state_tracker/sw_winsys.h" |
||
56 | |||
57 | #include "draw/draw_context.h" |
||
58 | #include "draw/draw_vbuf.h" |
||
59 | |||
60 | |||
61 | static boolean set_scene_state( struct lp_setup_context *, enum setup_state, |
||
62 | const char *reason); |
||
63 | static boolean try_update_scene_state( struct lp_setup_context *setup ); |
||
64 | |||
65 | |||
66 | static void |
||
67 | lp_setup_get_empty_scene(struct lp_setup_context *setup) |
||
68 | { |
||
69 | struct llvmpipe_context *lp = llvmpipe_context(setup->pipe); |
||
70 | boolean discard = lp->rasterizer ? lp->rasterizer->rasterizer_discard : FALSE; |
||
71 | |||
72 | assert(setup->scene == NULL); |
||
73 | |||
74 | setup->scene_idx++; |
||
75 | setup->scene_idx %= Elements(setup->scenes); |
||
76 | |||
77 | setup->scene = setup->scenes[setup->scene_idx]; |
||
78 | |||
79 | if (setup->scene->fence) { |
||
80 | if (LP_DEBUG & DEBUG_SETUP) |
||
81 | debug_printf("%s: wait for scene %d\n", |
||
82 | __FUNCTION__, setup->scene->fence->id); |
||
83 | |||
84 | lp_fence_wait(setup->scene->fence); |
||
85 | } |
||
86 | |||
87 | lp_scene_begin_binning(setup->scene, &setup->fb, discard); |
||
88 | |||
89 | } |
||
90 | |||
91 | |||
92 | static void |
||
93 | first_triangle( struct lp_setup_context *setup, |
||
94 | const float (*v0)[4], |
||
95 | const float (*v1)[4], |
||
96 | const float (*v2)[4]) |
||
97 | { |
||
98 | assert(setup->state == SETUP_ACTIVE); |
||
99 | lp_setup_choose_triangle( setup ); |
||
100 | setup->triangle( setup, v0, v1, v2 ); |
||
101 | } |
||
102 | |||
103 | static void |
||
104 | first_line( struct lp_setup_context *setup, |
||
105 | const float (*v0)[4], |
||
106 | const float (*v1)[4]) |
||
107 | { |
||
108 | assert(setup->state == SETUP_ACTIVE); |
||
109 | lp_setup_choose_line( setup ); |
||
110 | setup->line( setup, v0, v1 ); |
||
111 | } |
||
112 | |||
113 | static void |
||
114 | first_point( struct lp_setup_context *setup, |
||
115 | const float (*v0)[4]) |
||
116 | { |
||
117 | assert(setup->state == SETUP_ACTIVE); |
||
118 | lp_setup_choose_point( setup ); |
||
119 | setup->point( setup, v0 ); |
||
120 | } |
||
121 | |||
122 | void lp_setup_reset( struct lp_setup_context *setup ) |
||
123 | { |
||
124 | unsigned i; |
||
125 | |||
126 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
127 | |||
128 | /* Reset derived state */ |
||
129 | for (i = 0; i < Elements(setup->constants); ++i) { |
||
130 | setup->constants[i].stored_size = 0; |
||
131 | setup->constants[i].stored_data = NULL; |
||
132 | } |
||
133 | setup->fs.stored = NULL; |
||
134 | setup->dirty = ~0; |
||
135 | |||
136 | /* no current bin */ |
||
137 | setup->scene = NULL; |
||
138 | |||
139 | /* Reset some state: |
||
140 | */ |
||
141 | memset(&setup->clear, 0, sizeof setup->clear); |
||
142 | |||
143 | /* Have an explicit "start-binning" call and get rid of this |
||
144 | * pointer twiddling? |
||
145 | */ |
||
146 | setup->line = first_line; |
||
147 | setup->point = first_point; |
||
148 | setup->triangle = first_triangle; |
||
149 | } |
||
150 | |||
151 | |||
152 | /** Rasterize all scene's bins */ |
||
153 | static void |
||
154 | lp_setup_rasterize_scene( struct lp_setup_context *setup ) |
||
155 | { |
||
156 | struct lp_scene *scene = setup->scene; |
||
157 | struct llvmpipe_screen *screen = llvmpipe_screen(scene->pipe->screen); |
||
158 | |||
159 | scene->num_active_queries = setup->active_binned_queries; |
||
160 | memcpy(scene->active_queries, setup->active_queries, |
||
161 | scene->num_active_queries * sizeof(scene->active_queries[0])); |
||
162 | |||
163 | lp_scene_end_binning(scene); |
||
164 | |||
165 | lp_fence_reference(&setup->last_fence, scene->fence); |
||
166 | |||
167 | if (setup->last_fence) |
||
168 | setup->last_fence->issued = TRUE; |
||
169 | |||
170 | pipe_mutex_lock(screen->rast_mutex); |
||
171 | lp_rast_queue_scene(screen->rast, scene); |
||
172 | lp_rast_finish(screen->rast); |
||
173 | pipe_mutex_unlock(screen->rast_mutex); |
||
174 | |||
175 | lp_scene_end_rasterization(setup->scene); |
||
176 | lp_setup_reset( setup ); |
||
177 | |||
178 | LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__); |
||
179 | } |
||
180 | |||
181 | |||
182 | |||
183 | static boolean |
||
184 | begin_binning( struct lp_setup_context *setup ) |
||
185 | { |
||
186 | struct lp_scene *scene = setup->scene; |
||
187 | boolean need_zsload = FALSE; |
||
188 | boolean ok; |
||
189 | |||
190 | assert(scene); |
||
191 | assert(scene->fence == NULL); |
||
192 | |||
193 | /* Always create a fence: |
||
194 | */ |
||
195 | scene->fence = lp_fence_create(MAX2(1, setup->num_threads)); |
||
196 | if (!scene->fence) |
||
197 | return FALSE; |
||
198 | |||
199 | ok = try_update_scene_state(setup); |
||
200 | if (!ok) |
||
201 | return FALSE; |
||
202 | |||
203 | if (setup->fb.zsbuf && |
||
204 | ((setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && |
||
205 | util_format_is_depth_and_stencil(setup->fb.zsbuf->format)) |
||
206 | need_zsload = TRUE; |
||
207 | |||
208 | LP_DBG(DEBUG_SETUP, "%s color: %s depth: %s\n", __FUNCTION__, |
||
209 | (setup->clear.flags & PIPE_CLEAR_COLOR) ? "clear": "load", |
||
210 | need_zsload ? "clear": "load"); |
||
211 | |||
212 | if (setup->fb.nr_cbufs) { |
||
213 | if (setup->clear.flags & PIPE_CLEAR_COLOR) { |
||
214 | ok = lp_scene_bin_everywhere( scene, |
||
215 | LP_RAST_OP_CLEAR_COLOR, |
||
216 | setup->clear.color ); |
||
217 | if (!ok) |
||
218 | return FALSE; |
||
219 | } |
||
220 | } |
||
221 | |||
222 | if (setup->fb.zsbuf) { |
||
223 | if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) { |
||
224 | if (!need_zsload) |
||
225 | scene->has_depthstencil_clear = TRUE; |
||
226 | |||
227 | ok = lp_scene_bin_everywhere( scene, |
||
228 | LP_RAST_OP_CLEAR_ZSTENCIL, |
||
229 | lp_rast_arg_clearzs( |
||
230 | setup->clear.zsvalue, |
||
231 | setup->clear.zsmask)); |
||
232 | if (!ok) |
||
233 | return FALSE; |
||
234 | } |
||
235 | } |
||
236 | |||
237 | setup->clear.flags = 0; |
||
238 | setup->clear.zsmask = 0; |
||
239 | setup->clear.zsvalue = 0; |
||
240 | |||
241 | scene->had_queries = !!setup->active_binned_queries; |
||
242 | |||
243 | LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__); |
||
244 | return TRUE; |
||
245 | } |
||
246 | |||
247 | |||
248 | /* This basically bins and then flushes any outstanding full-screen |
||
249 | * clears. |
||
250 | * |
||
251 | * TODO: fast path for fullscreen clears and no triangles. |
||
252 | */ |
||
253 | static boolean |
||
254 | execute_clears( struct lp_setup_context *setup ) |
||
255 | { |
||
256 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
257 | |||
258 | return begin_binning( setup ); |
||
259 | } |
||
260 | |||
261 | const char *states[] = { |
||
262 | "FLUSHED", |
||
263 | "CLEARED", |
||
264 | "ACTIVE " |
||
265 | }; |
||
266 | |||
267 | |||
268 | static boolean |
||
269 | set_scene_state( struct lp_setup_context *setup, |
||
270 | enum setup_state new_state, |
||
271 | const char *reason) |
||
272 | { |
||
273 | unsigned old_state = setup->state; |
||
274 | |||
275 | if (old_state == new_state) |
||
276 | return TRUE; |
||
277 | |||
278 | if (LP_DEBUG & DEBUG_SCENE) { |
||
279 | debug_printf("%s old %s new %s%s%s\n", |
||
280 | __FUNCTION__, |
||
281 | states[old_state], |
||
282 | states[new_state], |
||
283 | (new_state == SETUP_FLUSHED) ? ": " : "", |
||
284 | (new_state == SETUP_FLUSHED) ? reason : ""); |
||
285 | |||
286 | if (new_state == SETUP_FLUSHED && setup->scene) |
||
287 | lp_debug_draw_bins_by_cmd_length(setup->scene); |
||
288 | } |
||
289 | |||
290 | /* wait for a free/empty scene |
||
291 | */ |
||
292 | if (old_state == SETUP_FLUSHED) |
||
293 | lp_setup_get_empty_scene(setup); |
||
294 | |||
295 | switch (new_state) { |
||
296 | case SETUP_CLEARED: |
||
297 | break; |
||
298 | |||
299 | case SETUP_ACTIVE: |
||
300 | if (!begin_binning( setup )) |
||
301 | goto fail; |
||
302 | break; |
||
303 | |||
304 | case SETUP_FLUSHED: |
||
305 | if (old_state == SETUP_CLEARED) |
||
306 | if (!execute_clears( setup )) |
||
307 | goto fail; |
||
308 | |||
309 | lp_setup_rasterize_scene( setup ); |
||
310 | assert(setup->scene == NULL); |
||
311 | break; |
||
312 | |||
313 | default: |
||
314 | assert(0 && "invalid setup state mode"); |
||
315 | goto fail; |
||
316 | } |
||
317 | |||
318 | setup->state = new_state; |
||
319 | return TRUE; |
||
320 | |||
321 | fail: |
||
322 | if (setup->scene) { |
||
323 | lp_scene_end_rasterization(setup->scene); |
||
324 | setup->scene = NULL; |
||
325 | } |
||
326 | |||
327 | setup->state = SETUP_FLUSHED; |
||
328 | lp_setup_reset( setup ); |
||
329 | return FALSE; |
||
330 | } |
||
331 | |||
332 | |||
333 | void |
||
334 | lp_setup_flush( struct lp_setup_context *setup, |
||
335 | struct pipe_fence_handle **fence, |
||
336 | const char *reason) |
||
337 | { |
||
338 | set_scene_state( setup, SETUP_FLUSHED, reason ); |
||
339 | |||
340 | if (fence) { |
||
341 | lp_fence_reference((struct lp_fence **)fence, setup->last_fence); |
||
342 | } |
||
343 | } |
||
344 | |||
345 | |||
346 | void |
||
347 | lp_setup_bind_framebuffer( struct lp_setup_context *setup, |
||
348 | const struct pipe_framebuffer_state *fb ) |
||
349 | { |
||
350 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
351 | |||
352 | /* Flush any old scene. |
||
353 | */ |
||
354 | set_scene_state( setup, SETUP_FLUSHED, __FUNCTION__ ); |
||
355 | |||
356 | /* |
||
357 | * Ensure the old scene is not reused. |
||
358 | */ |
||
359 | assert(!setup->scene); |
||
360 | |||
361 | /* Set new state. This will be picked up later when we next need a |
||
362 | * scene. |
||
363 | */ |
||
364 | util_copy_framebuffer_state(&setup->fb, fb); |
||
365 | setup->framebuffer.x0 = 0; |
||
366 | setup->framebuffer.y0 = 0; |
||
367 | setup->framebuffer.x1 = fb->width-1; |
||
368 | setup->framebuffer.y1 = fb->height-1; |
||
369 | setup->dirty |= LP_SETUP_NEW_SCISSOR; |
||
370 | } |
||
371 | |||
372 | |||
373 | static boolean |
||
374 | lp_setup_try_clear( struct lp_setup_context *setup, |
||
375 | const union pipe_color_union *color, |
||
376 | double depth, |
||
377 | unsigned stencil, |
||
378 | unsigned flags ) |
||
379 | { |
||
380 | uint64_t zsmask = 0; |
||
381 | uint64_t zsvalue = 0; |
||
382 | union lp_rast_cmd_arg color_arg; |
||
383 | unsigned i; |
||
384 | |||
385 | LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); |
||
386 | |||
387 | if (flags & PIPE_CLEAR_COLOR) { |
||
388 | for (i = 0; i < 4; i++) |
||
389 | color_arg.clear_color.i[i] = color->i[i]; |
||
390 | } |
||
391 | |||
392 | if (flags & PIPE_CLEAR_DEPTHSTENCIL) { |
||
393 | uint32_t zmask = (flags & PIPE_CLEAR_DEPTH) ? ~0 : 0; |
||
394 | uint8_t smask = (flags & PIPE_CLEAR_STENCIL) ? ~0 : 0; |
||
395 | |||
396 | zsvalue = util_pack64_z_stencil(setup->fb.zsbuf->format, |
||
397 | depth, |
||
398 | stencil); |
||
399 | |||
400 | |||
401 | zsmask = util_pack64_mask_z_stencil(setup->fb.zsbuf->format, |
||
402 | zmask, |
||
403 | smask); |
||
404 | |||
405 | zsvalue &= zsmask; |
||
406 | } |
||
407 | |||
408 | if (setup->state == SETUP_ACTIVE) { |
||
409 | struct lp_scene *scene = setup->scene; |
||
410 | |||
411 | /* Add the clear to existing scene. In the unusual case where |
||
412 | * both color and depth-stencil are being cleared when there's |
||
413 | * already been some rendering, we could discard the currently |
||
414 | * binned scene and start again, but I don't see that as being |
||
415 | * a common usage. |
||
416 | */ |
||
417 | if (flags & PIPE_CLEAR_COLOR) { |
||
418 | if (!lp_scene_bin_everywhere( scene, |
||
419 | LP_RAST_OP_CLEAR_COLOR, |
||
420 | color_arg )) |
||
421 | return FALSE; |
||
422 | } |
||
423 | |||
424 | if (flags & PIPE_CLEAR_DEPTHSTENCIL) { |
||
425 | if (!lp_scene_bin_everywhere( scene, |
||
426 | LP_RAST_OP_CLEAR_ZSTENCIL, |
||
427 | lp_rast_arg_clearzs(zsvalue, zsmask) )) |
||
428 | return FALSE; |
||
429 | } |
||
430 | } |
||
431 | else { |
||
432 | /* Put ourselves into the 'pre-clear' state, specifically to try |
||
433 | * and accumulate multiple clears to color and depth_stencil |
||
434 | * buffers which the app or state-tracker might issue |
||
435 | * separately. |
||
436 | */ |
||
437 | set_scene_state( setup, SETUP_CLEARED, __FUNCTION__ ); |
||
438 | |||
439 | setup->clear.flags |= flags; |
||
440 | |||
441 | if (flags & PIPE_CLEAR_DEPTHSTENCIL) { |
||
442 | setup->clear.zsmask |= zsmask; |
||
443 | setup->clear.zsvalue = |
||
444 | (setup->clear.zsvalue & ~zsmask) | (zsvalue & zsmask); |
||
445 | } |
||
446 | |||
447 | if (flags & PIPE_CLEAR_COLOR) { |
||
448 | memcpy(&setup->clear.color.clear_color, |
||
449 | &color_arg, |
||
450 | sizeof setup->clear.color.clear_color); |
||
451 | } |
||
452 | } |
||
453 | |||
454 | return TRUE; |
||
455 | } |
||
456 | |||
457 | void |
||
458 | lp_setup_clear( struct lp_setup_context *setup, |
||
459 | const union pipe_color_union *color, |
||
460 | double depth, |
||
461 | unsigned stencil, |
||
462 | unsigned flags ) |
||
463 | { |
||
464 | if (!lp_setup_try_clear( setup, color, depth, stencil, flags )) { |
||
465 | lp_setup_flush(setup, NULL, __FUNCTION__); |
||
466 | |||
467 | if (!lp_setup_try_clear( setup, color, depth, stencil, flags )) |
||
468 | assert(0); |
||
469 | } |
||
470 | } |
||
471 | |||
472 | |||
473 | |||
474 | |||
475 | |||
476 | void |
||
477 | lp_setup_set_triangle_state( struct lp_setup_context *setup, |
||
478 | unsigned cull_mode, |
||
479 | boolean ccw_is_frontface, |
||
480 | boolean scissor, |
||
481 | boolean half_pixel_center, |
||
482 | boolean bottom_edge_rule) |
||
483 | { |
||
484 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
485 | |||
486 | setup->ccw_is_frontface = ccw_is_frontface; |
||
487 | setup->cullmode = cull_mode; |
||
488 | setup->triangle = first_triangle; |
||
489 | setup->pixel_offset = half_pixel_center ? 0.5f : 0.0f; |
||
490 | setup->bottom_edge_rule = bottom_edge_rule; |
||
491 | |||
492 | if (setup->scissor_test != scissor) { |
||
493 | setup->dirty |= LP_SETUP_NEW_SCISSOR; |
||
494 | setup->scissor_test = scissor; |
||
495 | } |
||
496 | } |
||
497 | |||
498 | void |
||
499 | lp_setup_set_line_state( struct lp_setup_context *setup, |
||
500 | float line_width) |
||
501 | { |
||
502 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
503 | |||
504 | setup->line_width = line_width; |
||
505 | } |
||
506 | |||
507 | void |
||
508 | lp_setup_set_point_state( struct lp_setup_context *setup, |
||
509 | float point_size, |
||
510 | boolean point_size_per_vertex, |
||
511 | uint sprite_coord_enable, |
||
512 | uint sprite_coord_origin) |
||
513 | { |
||
514 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
515 | |||
516 | setup->point_size = point_size; |
||
517 | setup->sprite_coord_enable = sprite_coord_enable; |
||
518 | setup->sprite_coord_origin = sprite_coord_origin; |
||
519 | setup->point_size_per_vertex = point_size_per_vertex; |
||
520 | } |
||
521 | |||
522 | void |
||
523 | lp_setup_set_setup_variant( struct lp_setup_context *setup, |
||
524 | const struct lp_setup_variant *variant) |
||
525 | { |
||
526 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
527 | |||
528 | setup->setup.variant = variant; |
||
529 | } |
||
530 | |||
531 | void |
||
532 | lp_setup_set_fs_variant( struct lp_setup_context *setup, |
||
533 | struct lp_fragment_shader_variant *variant) |
||
534 | { |
||
535 | LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, |
||
536 | variant); |
||
537 | /* FIXME: reference count */ |
||
538 | |||
539 | setup->fs.current.variant = variant; |
||
540 | setup->dirty |= LP_SETUP_NEW_FS; |
||
541 | } |
||
542 | |||
543 | void |
||
544 | lp_setup_set_fs_constants(struct lp_setup_context *setup, |
||
545 | unsigned num, |
||
546 | struct pipe_constant_buffer *buffers) |
||
547 | { |
||
548 | unsigned i; |
||
549 | |||
550 | LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffers); |
||
551 | |||
552 | assert(num <= Elements(setup->constants)); |
||
553 | |||
554 | for (i = 0; i < num; ++i) { |
||
555 | util_copy_constant_buffer(&setup->constants[i].current, &buffers[i]); |
||
556 | } |
||
557 | for (; i < Elements(setup->constants); i++) { |
||
558 | util_copy_constant_buffer(&setup->constants[i].current, NULL); |
||
559 | } |
||
560 | setup->dirty |= LP_SETUP_NEW_CONSTANTS; |
||
561 | } |
||
562 | |||
563 | |||
564 | void |
||
565 | lp_setup_set_alpha_ref_value( struct lp_setup_context *setup, |
||
566 | float alpha_ref_value ) |
||
567 | { |
||
568 | LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value); |
||
569 | |||
570 | if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) { |
||
571 | setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value; |
||
572 | setup->dirty |= LP_SETUP_NEW_FS; |
||
573 | } |
||
574 | } |
||
575 | |||
576 | void |
||
577 | lp_setup_set_stencil_ref_values( struct lp_setup_context *setup, |
||
578 | const ubyte refs[2] ) |
||
579 | { |
||
580 | LP_DBG(DEBUG_SETUP, "%s %d %d\n", __FUNCTION__, refs[0], refs[1]); |
||
581 | |||
582 | if (setup->fs.current.jit_context.stencil_ref_front != refs[0] || |
||
583 | setup->fs.current.jit_context.stencil_ref_back != refs[1]) { |
||
584 | setup->fs.current.jit_context.stencil_ref_front = refs[0]; |
||
585 | setup->fs.current.jit_context.stencil_ref_back = refs[1]; |
||
586 | setup->dirty |= LP_SETUP_NEW_FS; |
||
587 | } |
||
588 | } |
||
589 | |||
590 | void |
||
591 | lp_setup_set_blend_color( struct lp_setup_context *setup, |
||
592 | const struct pipe_blend_color *blend_color ) |
||
593 | { |
||
594 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
595 | |||
596 | assert(blend_color); |
||
597 | |||
598 | if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) { |
||
599 | memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color); |
||
600 | setup->dirty |= LP_SETUP_NEW_BLEND_COLOR; |
||
601 | } |
||
602 | } |
||
603 | |||
604 | |||
605 | void |
||
606 | lp_setup_set_scissors( struct lp_setup_context *setup, |
||
607 | const struct pipe_scissor_state *scissors ) |
||
608 | { |
||
609 | unsigned i; |
||
610 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
611 | |||
612 | assert(scissors); |
||
613 | |||
614 | for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) { |
||
615 | setup->scissors[i].x0 = scissors[i].minx; |
||
616 | setup->scissors[i].x1 = scissors[i].maxx-1; |
||
617 | setup->scissors[i].y0 = scissors[i].miny; |
||
618 | setup->scissors[i].y1 = scissors[i].maxy-1; |
||
619 | } |
||
620 | setup->dirty |= LP_SETUP_NEW_SCISSOR; |
||
621 | } |
||
622 | |||
623 | |||
624 | void |
||
625 | lp_setup_set_flatshade_first( struct lp_setup_context *setup, |
||
626 | boolean flatshade_first ) |
||
627 | { |
||
628 | setup->flatshade_first = flatshade_first; |
||
629 | } |
||
630 | |||
631 | void |
||
632 | lp_setup_set_rasterizer_discard( struct lp_setup_context *setup, |
||
633 | boolean rasterizer_discard ) |
||
634 | { |
||
635 | if (setup->rasterizer_discard != rasterizer_discard) { |
||
636 | setup->rasterizer_discard = rasterizer_discard; |
||
637 | set_scene_state( setup, SETUP_FLUSHED, __FUNCTION__ ); |
||
638 | } |
||
639 | } |
||
640 | |||
641 | void |
||
642 | lp_setup_set_vertex_info( struct lp_setup_context *setup, |
||
643 | struct vertex_info *vertex_info ) |
||
644 | { |
||
645 | /* XXX: just silently holding onto the pointer: |
||
646 | */ |
||
647 | setup->vertex_info = vertex_info; |
||
648 | } |
||
649 | |||
650 | |||
651 | /** |
||
652 | * Called during state validation when LP_NEW_SAMPLER_VIEW is set. |
||
653 | */ |
||
654 | void |
||
655 | lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup, |
||
656 | unsigned num, |
||
657 | struct pipe_sampler_view **views) |
||
658 | { |
||
659 | unsigned i; |
||
660 | |||
661 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
662 | |||
663 | assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); |
||
664 | |||
665 | for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) { |
||
666 | struct pipe_sampler_view *view = i < num ? views[i] : NULL; |
||
667 | |||
668 | if (view) { |
||
669 | struct pipe_resource *res = view->texture; |
||
670 | struct llvmpipe_resource *lp_tex = llvmpipe_resource(res); |
||
671 | struct lp_jit_texture *jit_tex; |
||
672 | jit_tex = &setup->fs.current.jit_context.textures[i]; |
||
673 | |||
674 | /* We're referencing the texture's internal data, so save a |
||
675 | * reference to it. |
||
676 | */ |
||
677 | pipe_resource_reference(&setup->fs.current_tex[i], res); |
||
678 | |||
679 | if (!lp_tex->dt) { |
||
680 | /* regular texture - setup array of mipmap level offsets */ |
||
681 | void *mip_ptr; |
||
682 | int j; |
||
683 | unsigned first_level = 0; |
||
684 | unsigned last_level = 0; |
||
685 | |||
686 | if (llvmpipe_resource_is_texture(res)) { |
||
687 | first_level = view->u.tex.first_level; |
||
688 | last_level = view->u.tex.last_level; |
||
689 | assert(first_level <= last_level); |
||
690 | assert(last_level <= res->last_level); |
||
691 | |||
692 | /* |
||
693 | * The complexity here should no longer be necessary. |
||
694 | */ |
||
695 | mip_ptr = llvmpipe_get_texture_image_all(lp_tex, first_level, |
||
696 | LP_TEX_USAGE_READ); |
||
697 | jit_tex->base = lp_tex->linear_img.data; |
||
698 | } |
||
699 | else { |
||
700 | mip_ptr = lp_tex->data; |
||
701 | jit_tex->base = mip_ptr; |
||
702 | } |
||
703 | |||
704 | if ((LP_PERF & PERF_TEX_MEM) || !mip_ptr) { |
||
705 | /* out of memory - use dummy tile memory */ |
||
706 | /* Note if using PERF_TEX_MEM will also skip tile conversion */ |
||
707 | jit_tex->base = lp_dummy_tile; |
||
708 | jit_tex->width = TILE_SIZE/8; |
||
709 | jit_tex->height = TILE_SIZE/8; |
||
710 | jit_tex->depth = 1; |
||
711 | jit_tex->first_level = 0; |
||
712 | jit_tex->last_level = 0; |
||
713 | jit_tex->mip_offsets[0] = 0; |
||
714 | jit_tex->row_stride[0] = 0; |
||
715 | jit_tex->img_stride[0] = 0; |
||
716 | } |
||
717 | else { |
||
718 | jit_tex->width = res->width0; |
||
719 | jit_tex->height = res->height0; |
||
720 | jit_tex->depth = res->depth0; |
||
721 | jit_tex->first_level = first_level; |
||
722 | jit_tex->last_level = last_level; |
||
723 | |||
724 | if (llvmpipe_resource_is_texture(res)) { |
||
725 | for (j = first_level; j <= last_level; j++) { |
||
726 | mip_ptr = llvmpipe_get_texture_image_all(lp_tex, j, |
||
727 | LP_TEX_USAGE_READ); |
||
728 | jit_tex->mip_offsets[j] = (uint8_t *)mip_ptr - (uint8_t *)jit_tex->base; |
||
729 | /* |
||
730 | * could get mip offset directly but need call above to |
||
731 | * invoke tiled->linear conversion. |
||
732 | */ |
||
733 | assert(lp_tex->linear_mip_offsets[j] == jit_tex->mip_offsets[j]); |
||
734 | jit_tex->row_stride[j] = lp_tex->row_stride[j]; |
||
735 | jit_tex->img_stride[j] = lp_tex->img_stride[j]; |
||
736 | } |
||
737 | |||
738 | if (res->target == PIPE_TEXTURE_1D_ARRAY || |
||
739 | res->target == PIPE_TEXTURE_2D_ARRAY) { |
||
740 | /* |
||
741 | * For array textures, we don't have first_layer, instead |
||
742 | * adjust last_layer (stored as depth) plus the mip level offsets |
||
743 | * (as we have mip-first layout can't just adjust base ptr). |
||
744 | * XXX For mip levels, could do something similar. |
||
745 | */ |
||
746 | jit_tex->depth = view->u.tex.last_layer - view->u.tex.first_layer + 1; |
||
747 | for (j = first_level; j <= last_level; j++) { |
||
748 | jit_tex->mip_offsets[j] += view->u.tex.first_layer * |
||
749 | lp_tex->img_stride[j]; |
||
750 | } |
||
751 | assert(view->u.tex.first_layer <= view->u.tex.last_layer); |
||
752 | assert(view->u.tex.last_layer < res->array_size); |
||
753 | } |
||
754 | } |
||
755 | else { |
||
756 | /* |
||
757 | * For buffers, we don't have first_element, instead adjust |
||
758 | * last_element (stored as width) plus the base pointer. |
||
759 | */ |
||
760 | unsigned view_blocksize = util_format_get_blocksize(view->format); |
||
761 | /* probably don't really need to fill that out */ |
||
762 | jit_tex->mip_offsets[0] = 0; |
||
763 | jit_tex->row_stride[0] = 0; |
||
764 | jit_tex->row_stride[0] = 0; |
||
765 | |||
766 | /* everything specified in number of elements here. */ |
||
767 | jit_tex->width = view->u.buf.last_element - view->u.buf.first_element + 1; |
||
768 | jit_tex->base = (uint8_t *)jit_tex->base + view->u.buf.first_element * |
||
769 | view_blocksize; |
||
770 | /* XXX Unsure if we need to sanitize parameters? */ |
||
771 | assert(view->u.buf.first_element <= view->u.buf.last_element); |
||
772 | assert(view->u.buf.last_element * view_blocksize < res->width0); |
||
773 | } |
||
774 | } |
||
775 | } |
||
776 | else { |
||
777 | /* display target texture/surface */ |
||
778 | /* |
||
779 | * XXX: Where should this be unmapped? |
||
780 | */ |
||
781 | struct llvmpipe_screen *screen = llvmpipe_screen(res->screen); |
||
782 | struct sw_winsys *winsys = screen->winsys; |
||
783 | jit_tex->base = winsys->displaytarget_map(winsys, lp_tex->dt, |
||
784 | PIPE_TRANSFER_READ); |
||
785 | jit_tex->row_stride[0] = lp_tex->row_stride[0]; |
||
786 | jit_tex->img_stride[0] = lp_tex->img_stride[0]; |
||
787 | jit_tex->mip_offsets[0] = 0; |
||
788 | jit_tex->width = res->width0; |
||
789 | jit_tex->height = res->height0; |
||
790 | jit_tex->depth = res->depth0; |
||
791 | jit_tex->first_level = jit_tex->last_level = 0; |
||
792 | assert(jit_tex->base); |
||
793 | } |
||
794 | } |
||
795 | } |
||
796 | |||
797 | setup->dirty |= LP_SETUP_NEW_FS; |
||
798 | } |
||
799 | |||
800 | |||
801 | /** |
||
802 | * Called during state validation when LP_NEW_SAMPLER is set. |
||
803 | */ |
||
804 | void |
||
805 | lp_setup_set_fragment_sampler_state(struct lp_setup_context *setup, |
||
806 | unsigned num, |
||
807 | struct pipe_sampler_state **samplers) |
||
808 | { |
||
809 | unsigned i; |
||
810 | |||
811 | LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); |
||
812 | |||
813 | assert(num <= PIPE_MAX_SAMPLERS); |
||
814 | |||
815 | for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { |
||
816 | const struct pipe_sampler_state *sampler = i < num ? samplers[i] : NULL; |
||
817 | |||
818 | if (sampler) { |
||
819 | struct lp_jit_sampler *jit_sam; |
||
820 | jit_sam = &setup->fs.current.jit_context.samplers[i]; |
||
821 | |||
822 | jit_sam->min_lod = sampler->min_lod; |
||
823 | jit_sam->max_lod = sampler->max_lod; |
||
824 | jit_sam->lod_bias = sampler->lod_bias; |
||
825 | COPY_4V(jit_sam->border_color, sampler->border_color.f); |
||
826 | } |
||
827 | } |
||
828 | |||
829 | setup->dirty |= LP_SETUP_NEW_FS; |
||
830 | } |
||
831 | |||
832 | |||
833 | /** |
||
834 | * Is the given texture referenced by any scene? |
||
835 | * Note: we have to check all scenes including any scenes currently |
||
836 | * being rendered and the current scene being built. |
||
837 | */ |
||
838 | unsigned |
||
839 | lp_setup_is_resource_referenced( const struct lp_setup_context *setup, |
||
840 | const struct pipe_resource *texture ) |
||
841 | { |
||
842 | unsigned i; |
||
843 | |||
844 | /* check the render targets */ |
||
845 | for (i = 0; i < setup->fb.nr_cbufs; i++) { |
||
846 | if (setup->fb.cbufs[i]->texture == texture) |
||
847 | return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE; |
||
848 | } |
||
849 | if (setup->fb.zsbuf && setup->fb.zsbuf->texture == texture) { |
||
850 | return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE; |
||
851 | } |
||
852 | |||
853 | /* check textures referenced by the scene */ |
||
854 | for (i = 0; i < Elements(setup->scenes); i++) { |
||
855 | if (lp_scene_is_resource_referenced(setup->scenes[i], texture)) { |
||
856 | return LP_REFERENCED_FOR_READ; |
||
857 | } |
||
858 | } |
||
859 | |||
860 | return LP_UNREFERENCED; |
||
861 | } |
||
862 | |||
863 | |||
864 | /** |
||
865 | * Called by vbuf code when we're about to draw something. |
||
866 | */ |
||
867 | static boolean |
||
868 | try_update_scene_state( struct lp_setup_context *setup ) |
||
869 | { |
||
870 | boolean new_scene = (setup->fs.stored == NULL); |
||
871 | struct lp_scene *scene = setup->scene; |
||
872 | unsigned i; |
||
873 | |||
874 | assert(scene); |
||
875 | |||
876 | if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { |
||
877 | uint8_t *stored; |
||
878 | float* fstored; |
||
879 | unsigned i, j; |
||
880 | unsigned size; |
||
881 | |||
882 | /* Alloc u8_blend_color (16 x i8) and f_blend_color (4 or 8 x f32) */ |
||
883 | size = 4 * 16 * sizeof(uint8_t); |
||
884 | size += (LP_MAX_VECTOR_LENGTH / 4) * sizeof(float); |
||
885 | stored = lp_scene_alloc_aligned(scene, size, LP_MAX_VECTOR_LENGTH); |
||
886 | |||
887 | if (!stored) { |
||
888 | assert(!new_scene); |
||
889 | return FALSE; |
||
890 | } |
||
891 | |||
892 | /* Store floating point colour */ |
||
893 | fstored = (float*)(stored + 4*16); |
||
894 | for (i = 0; i < (LP_MAX_VECTOR_LENGTH / 4); ++i) { |
||
895 | fstored[i] = setup->blend_color.current.color[i % 4]; |
||
896 | } |
||
897 | |||
898 | /* smear each blend color component across 16 ubyte elements */ |
||
899 | for (i = 0; i < 4; ++i) { |
||
900 | uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); |
||
901 | for (j = 0; j < 16; ++j) |
||
902 | stored[i*16 + j] = c; |
||
903 | } |
||
904 | |||
905 | setup->blend_color.stored = stored; |
||
906 | setup->fs.current.jit_context.u8_blend_color = stored; |
||
907 | setup->fs.current.jit_context.f_blend_color = fstored; |
||
908 | setup->dirty |= LP_SETUP_NEW_FS; |
||
909 | } |
||
910 | |||
911 | if (setup->dirty & LP_SETUP_NEW_CONSTANTS) { |
||
912 | for (i = 0; i < Elements(setup->constants); ++i) { |
||
913 | struct pipe_resource *buffer = setup->constants[i].current.buffer; |
||
914 | const unsigned current_size = setup->constants[i].current.buffer_size; |
||
915 | const ubyte *current_data = NULL; |
||
916 | |||
917 | if (buffer) { |
||
918 | /* resource buffer */ |
||
919 | current_data = (ubyte *) llvmpipe_resource_data(buffer); |
||
920 | } |
||
921 | else if (setup->constants[i].current.user_buffer) { |
||
922 | /* user-space buffer */ |
||
923 | current_data = (ubyte *) setup->constants[i].current.user_buffer; |
||
924 | } |
||
925 | |||
926 | if (current_data) { |
||
927 | current_data += setup->constants[i].current.buffer_offset; |
||
928 | |||
929 | /* TODO: copy only the actually used constants? */ |
||
930 | |||
931 | if (setup->constants[i].stored_size != current_size || |
||
932 | !setup->constants[i].stored_data || |
||
933 | memcmp(setup->constants[i].stored_data, |
||
934 | current_data, |
||
935 | current_size) != 0) { |
||
936 | void *stored; |
||
937 | |||
938 | stored = lp_scene_alloc(scene, current_size); |
||
939 | if (!stored) { |
||
940 | assert(!new_scene); |
||
941 | return FALSE; |
||
942 | } |
||
943 | |||
944 | memcpy(stored, |
||
945 | current_data, |
||
946 | current_size); |
||
947 | setup->constants[i].stored_size = current_size; |
||
948 | setup->constants[i].stored_data = stored; |
||
949 | } |
||
950 | } |
||
951 | else { |
||
952 | setup->constants[i].stored_size = 0; |
||
953 | setup->constants[i].stored_data = NULL; |
||
954 | } |
||
955 | |||
956 | setup->fs.current.jit_context.constants[i] = setup->constants[i].stored_data; |
||
957 | setup->dirty |= LP_SETUP_NEW_FS; |
||
958 | } |
||
959 | } |
||
960 | |||
961 | |||
962 | if (setup->dirty & LP_SETUP_NEW_FS) { |
||
963 | if (!setup->fs.stored || |
||
964 | memcmp(setup->fs.stored, |
||
965 | &setup->fs.current, |
||
966 | sizeof setup->fs.current) != 0) |
||
967 | { |
||
968 | struct lp_rast_state *stored; |
||
969 | |||
970 | /* The fs state that's been stored in the scene is different from |
||
971 | * the new, current state. So allocate a new lp_rast_state object |
||
972 | * and append it to the bin's setup data buffer. |
||
973 | */ |
||
974 | stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); |
||
975 | if (!stored) { |
||
976 | assert(!new_scene); |
||
977 | return FALSE; |
||
978 | } |
||
979 | |||
980 | memcpy(stored, |
||
981 | &setup->fs.current, |
||
982 | sizeof setup->fs.current); |
||
983 | setup->fs.stored = stored; |
||
984 | |||
985 | /* The scene now references the textures in the rasterization |
||
986 | * state record. Note that now. |
||
987 | */ |
||
988 | for (i = 0; i < Elements(setup->fs.current_tex); i++) { |
||
989 | if (setup->fs.current_tex[i]) { |
||
990 | if (!lp_scene_add_resource_reference(scene, |
||
991 | setup->fs.current_tex[i], |
||
992 | new_scene)) { |
||
993 | assert(!new_scene); |
||
994 | return FALSE; |
||
995 | } |
||
996 | } |
||
997 | } |
||
998 | } |
||
999 | } |
||
1000 | |||
1001 | if (setup->dirty & LP_SETUP_NEW_SCISSOR) { |
||
1002 | unsigned i; |
||
1003 | for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) { |
||
1004 | setup->draw_regions[i] = setup->framebuffer; |
||
1005 | if (setup->scissor_test) { |
||
1006 | u_rect_possible_intersection(&setup->scissors[i], |
||
1007 | &setup->draw_regions[i]); |
||
1008 | } |
||
1009 | } |
||
1010 | /* If the framebuffer is large we have to think about fixed-point |
||
1011 | * integer overflow. For 2K by 2K images, coordinates need 15 bits |
||
1012 | * (2^11 + 4 subpixel bits). The product of two such numbers would |
||
1013 | * use 30 bits. Any larger and we could overflow a 32-bit int. |
||
1014 | * |
||
1015 | * To cope with this problem we check if triangles are large and |
||
1016 | * subdivide them if needed. |
||
1017 | */ |
||
1018 | setup->subdivide_large_triangles = (setup->fb.width > 2048 && |
||
1019 | setup->fb.height > 2048); |
||
1020 | } |
||
1021 | |||
1022 | setup->dirty = 0; |
||
1023 | |||
1024 | assert(setup->fs.stored); |
||
1025 | return TRUE; |
||
1026 | } |
||
1027 | |||
1028 | boolean |
||
1029 | lp_setup_update_state( struct lp_setup_context *setup, |
||
1030 | boolean update_scene ) |
||
1031 | { |
||
1032 | /* Some of the 'draw' pipeline stages may have changed some driver state. |
||
1033 | * Make sure we've processed those state changes before anything else. |
||
1034 | * |
||
1035 | * XXX this is the only place where llvmpipe_context is used in the |
||
1036 | * setup code. This may get refactored/changed... |
||
1037 | */ |
||
1038 | { |
||
1039 | struct llvmpipe_context *lp = llvmpipe_context(setup->pipe); |
||
1040 | if (lp->dirty) { |
||
1041 | llvmpipe_update_derived(lp); |
||
1042 | } |
||
1043 | |||
1044 | if (lp->setup->dirty) { |
||
1045 | llvmpipe_update_setup(lp); |
||
1046 | } |
||
1047 | |||
1048 | assert(setup->setup.variant); |
||
1049 | |||
1050 | /* Will probably need to move this somewhere else, just need |
||
1051 | * to know about vertex shader point size attribute. |
||
1052 | */ |
||
1053 | setup->psize = lp->psize_slot; |
||
1054 | setup->viewport_index_slot = lp->viewport_index_slot; |
||
1055 | setup->layer_slot = lp->layer_slot; |
||
1056 | |||
1057 | assert(lp->dirty == 0); |
||
1058 | |||
1059 | assert(lp->setup_variant.key.size == |
||
1060 | setup->setup.variant->key.size); |
||
1061 | |||
1062 | assert(memcmp(&lp->setup_variant.key, |
||
1063 | &setup->setup.variant->key, |
||
1064 | setup->setup.variant->key.size) == 0); |
||
1065 | } |
||
1066 | |||
1067 | if (update_scene && setup->state != SETUP_ACTIVE) { |
||
1068 | if (!set_scene_state( setup, SETUP_ACTIVE, __FUNCTION__ )) |
||
1069 | return FALSE; |
||
1070 | } |
||
1071 | |||
1072 | /* Only call into update_scene_state() if we already have a |
||
1073 | * scene: |
||
1074 | */ |
||
1075 | if (update_scene && setup->scene) { |
||
1076 | assert(setup->state == SETUP_ACTIVE); |
||
1077 | |||
1078 | if (try_update_scene_state(setup)) |
||
1079 | return TRUE; |
||
1080 | |||
1081 | /* Update failed, try to restart the scene. |
||
1082 | * |
||
1083 | * Cannot call lp_setup_flush_and_restart() directly here |
||
1084 | * because of potential recursion. |
||
1085 | */ |
||
1086 | if (!set_scene_state(setup, SETUP_FLUSHED, __FUNCTION__)) |
||
1087 | return FALSE; |
||
1088 | |||
1089 | if (!set_scene_state(setup, SETUP_ACTIVE, __FUNCTION__)) |
||
1090 | return FALSE; |
||
1091 | |||
1092 | if (!setup->scene) |
||
1093 | return FALSE; |
||
1094 | |||
1095 | return try_update_scene_state(setup); |
||
1096 | } |
||
1097 | |||
1098 | return TRUE; |
||
1099 | } |
||
1100 | |||
1101 | |||
1102 | |||
1103 | /* Only caller is lp_setup_vbuf_destroy() |
||
1104 | */ |
||
1105 | void |
||
1106 | lp_setup_destroy( struct lp_setup_context *setup ) |
||
1107 | { |
||
1108 | uint i; |
||
1109 | |||
1110 | lp_setup_reset( setup ); |
||
1111 | |||
1112 | util_unreference_framebuffer_state(&setup->fb); |
||
1113 | |||
1114 | for (i = 0; i < Elements(setup->fs.current_tex); i++) { |
||
1115 | pipe_resource_reference(&setup->fs.current_tex[i], NULL); |
||
1116 | } |
||
1117 | |||
1118 | for (i = 0; i < Elements(setup->constants); i++) { |
||
1119 | pipe_resource_reference(&setup->constants[i].current.buffer, NULL); |
||
1120 | } |
||
1121 | |||
1122 | /* free the scenes in the 'empty' queue */ |
||
1123 | for (i = 0; i < Elements(setup->scenes); i++) { |
||
1124 | struct lp_scene *scene = setup->scenes[i]; |
||
1125 | |||
1126 | if (scene->fence) |
||
1127 | lp_fence_wait(scene->fence); |
||
1128 | |||
1129 | lp_scene_destroy(scene); |
||
1130 | } |
||
1131 | |||
1132 | lp_fence_reference(&setup->last_fence, NULL); |
||
1133 | |||
1134 | FREE( setup ); |
||
1135 | } |
||
1136 | |||
1137 | |||
1138 | /** |
||
1139 | * Create a new primitive tiling engine. Plug it into the backend of |
||
1140 | * the draw module. Currently also creates a rasterizer to use with |
||
1141 | * it. |
||
1142 | */ |
||
1143 | struct lp_setup_context * |
||
1144 | lp_setup_create( struct pipe_context *pipe, |
||
1145 | struct draw_context *draw ) |
||
1146 | { |
||
1147 | struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); |
||
1148 | struct lp_setup_context *setup; |
||
1149 | unsigned i; |
||
1150 | |||
1151 | setup = CALLOC_STRUCT(lp_setup_context); |
||
1152 | if (!setup) { |
||
1153 | goto no_setup; |
||
1154 | } |
||
1155 | |||
1156 | lp_setup_init_vbuf(setup); |
||
1157 | |||
1158 | /* Used only in update_state(): |
||
1159 | */ |
||
1160 | setup->pipe = pipe; |
||
1161 | |||
1162 | |||
1163 | setup->num_threads = screen->num_threads; |
||
1164 | setup->vbuf = draw_vbuf_stage(draw, &setup->base); |
||
1165 | if (!setup->vbuf) { |
||
1166 | goto no_vbuf; |
||
1167 | } |
||
1168 | |||
1169 | draw_set_rasterize_stage(draw, setup->vbuf); |
||
1170 | draw_set_render(draw, &setup->base); |
||
1171 | |||
1172 | /* create some empty scenes */ |
||
1173 | for (i = 0; i < MAX_SCENES; i++) { |
||
1174 | setup->scenes[i] = lp_scene_create( pipe ); |
||
1175 | if (!setup->scenes[i]) { |
||
1176 | goto no_scenes; |
||
1177 | } |
||
1178 | } |
||
1179 | |||
1180 | setup->triangle = first_triangle; |
||
1181 | setup->line = first_line; |
||
1182 | setup->point = first_point; |
||
1183 | |||
1184 | setup->dirty = ~0; |
||
1185 | |||
1186 | return setup; |
||
1187 | |||
1188 | no_scenes: |
||
1189 | for (i = 0; i < MAX_SCENES; i++) { |
||
1190 | if (setup->scenes[i]) { |
||
1191 | lp_scene_destroy(setup->scenes[i]); |
||
1192 | } |
||
1193 | } |
||
1194 | |||
1195 | setup->vbuf->destroy(setup->vbuf); |
||
1196 | no_vbuf: |
||
1197 | FREE(setup); |
||
1198 | no_setup: |
||
1199 | return NULL; |
||
1200 | } |
||
1201 | |||
1202 | |||
1203 | /** |
||
1204 | * Put a BeginQuery command into all bins. |
||
1205 | */ |
||
1206 | void |
||
1207 | lp_setup_begin_query(struct lp_setup_context *setup, |
||
1208 | struct llvmpipe_query *pq) |
||
1209 | { |
||
1210 | |||
1211 | set_scene_state(setup, SETUP_ACTIVE, "begin_query"); |
||
1212 | |||
1213 | if (!(pq->type == PIPE_QUERY_OCCLUSION_COUNTER || |
||
1214 | pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || |
||
1215 | pq->type == PIPE_QUERY_PIPELINE_STATISTICS)) |
||
1216 | return; |
||
1217 | |||
1218 | /* init the query to its beginning state */ |
||
1219 | assert(setup->active_binned_queries < LP_MAX_ACTIVE_BINNED_QUERIES); |
||
1220 | /* exceeding list size so just ignore the query */ |
||
1221 | if (setup->active_binned_queries >= LP_MAX_ACTIVE_BINNED_QUERIES) { |
||
1222 | return; |
||
1223 | } |
||
1224 | assert(setup->active_queries[setup->active_binned_queries] == NULL); |
||
1225 | setup->active_queries[setup->active_binned_queries] = pq; |
||
1226 | setup->active_binned_queries++; |
||
1227 | |||
1228 | assert(setup->scene); |
||
1229 | if (setup->scene) { |
||
1230 | if (!lp_scene_bin_everywhere(setup->scene, |
||
1231 | LP_RAST_OP_BEGIN_QUERY, |
||
1232 | lp_rast_arg_query(pq))) { |
||
1233 | |||
1234 | if (!lp_setup_flush_and_restart(setup)) |
||
1235 | return; |
||
1236 | |||
1237 | if (!lp_scene_bin_everywhere(setup->scene, |
||
1238 | LP_RAST_OP_BEGIN_QUERY, |
||
1239 | lp_rast_arg_query(pq))) { |
||
1240 | return; |
||
1241 | } |
||
1242 | } |
||
1243 | setup->scene->had_queries |= TRUE; |
||
1244 | } |
||
1245 | } |
||
1246 | |||
1247 | |||
1248 | /** |
||
1249 | * Put an EndQuery command into all bins. |
||
1250 | */ |
||
1251 | void |
||
1252 | lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) |
||
1253 | { |
||
1254 | set_scene_state(setup, SETUP_ACTIVE, "end_query"); |
||
1255 | |||
1256 | assert(setup->scene); |
||
1257 | if (setup->scene) { |
||
1258 | /* pq->fence should be the fence of the *last* scene which |
||
1259 | * contributed to the query result. |
||
1260 | */ |
||
1261 | lp_fence_reference(&pq->fence, setup->scene->fence); |
||
1262 | |||
1263 | if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER || |
||
1264 | pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || |
||
1265 | pq->type == PIPE_QUERY_PIPELINE_STATISTICS || |
||
1266 | pq->type == PIPE_QUERY_TIMESTAMP) { |
||
1267 | if (pq->type == PIPE_QUERY_TIMESTAMP && |
||
1268 | !(setup->scene->tiles_x | setup->scene->tiles_y)) { |
||
1269 | /* |
||
1270 | * If there's a zero width/height framebuffer, there's no bins and |
||
1271 | * hence no rast task is ever run. So fill in something here instead. |
||
1272 | */ |
||
1273 | pq->end[0] = os_time_get_nano(); |
||
1274 | } |
||
1275 | |||
1276 | if (!lp_scene_bin_everywhere(setup->scene, |
||
1277 | LP_RAST_OP_END_QUERY, |
||
1278 | lp_rast_arg_query(pq))) { |
||
1279 | if (!lp_setup_flush_and_restart(setup)) |
||
1280 | goto fail; |
||
1281 | |||
1282 | if (!lp_scene_bin_everywhere(setup->scene, |
||
1283 | LP_RAST_OP_END_QUERY, |
||
1284 | lp_rast_arg_query(pq))) { |
||
1285 | goto fail; |
||
1286 | } |
||
1287 | } |
||
1288 | setup->scene->had_queries |= TRUE; |
||
1289 | } |
||
1290 | } |
||
1291 | else { |
||
1292 | lp_fence_reference(&pq->fence, setup->last_fence); |
||
1293 | } |
||
1294 | |||
1295 | fail: |
||
1296 | /* Need to do this now not earlier since it still needs to be marked as |
||
1297 | * active when binning it would cause a flush. |
||
1298 | */ |
||
1299 | if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER || |
||
1300 | pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || |
||
1301 | pq->type == PIPE_QUERY_PIPELINE_STATISTICS) { |
||
1302 | unsigned i; |
||
1303 | |||
1304 | /* remove from active binned query list */ |
||
1305 | for (i = 0; i < setup->active_binned_queries; i++) { |
||
1306 | if (setup->active_queries[i] == pq) |
||
1307 | break; |
||
1308 | } |
||
1309 | assert(i < setup->active_binned_queries); |
||
1310 | if (i == setup->active_binned_queries) |
||
1311 | return; |
||
1312 | setup->active_binned_queries--; |
||
1313 | setup->active_queries[i] = setup->active_queries[setup->active_binned_queries]; |
||
1314 | setup->active_queries[setup->active_binned_queries] = NULL; |
||
1315 | } |
||
1316 | } |
||
1317 | |||
1318 | |||
1319 | boolean |
||
1320 | lp_setup_flush_and_restart(struct lp_setup_context *setup) |
||
1321 | { |
||
1322 | if (0) debug_printf("%s\n", __FUNCTION__); |
||
1323 | |||
1324 | assert(setup->state == SETUP_ACTIVE); |
||
1325 | |||
1326 | if (!set_scene_state(setup, SETUP_FLUSHED, __FUNCTION__)) |
||
1327 | return FALSE; |
||
1328 | |||
1329 | if (!lp_setup_update_state(setup, TRUE)) |
||
1330 | return FALSE; |
||
1331 | |||
1332 | return TRUE; |
||
1333 | }>>>>>>>>>>>>>>>>>>=>>=>>=>=>=>=>=>>>=>>>>=>>> |
||
1334 |