/** * Put an EndQuery command into all bins. */ void lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) { union lp_rast_cmd_arg dummy = { 0 }; set_scene_state(setup, SETUP_ACTIVE, "end_query"); assert(setup->active_query == pq); setup->active_query = NULL; /* Setup will automatically re-issue any query which carried over a * scene boundary, and the rasterizer automatically "ends" queries * which are active at the end of a scene, so there is no need to * retry this commands on failure. */ if (setup->scene) { /* pq->fence should be the fence of the *last* scene which * contributed to the query result. */ lp_fence_reference(&pq->fence, setup->scene->fence); if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_END_QUERY, dummy)) { lp_setup_flush(setup, NULL, __FUNCTION__); } } else { lp_fence_reference(&pq->fence, setup->last_fence); } }
void lp_setup_bind_framebuffer( struct lp_setup_context *setup, const struct pipe_framebuffer_state *fb ) { LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); /* Flush any old scene. */ set_scene_state( setup, SETUP_FLUSHED, __FUNCTION__ ); /* * Ensure the old scene is not reused. */ assert(!setup->scene); /* Set new state. This will be picked up later when we next need a * scene. */ util_copy_framebuffer_state(&setup->fb, fb); setup->framebuffer.x0 = 0; setup->framebuffer.y0 = 0; setup->framebuffer.x1 = fb->width-1; setup->framebuffer.y1 = fb->height-1; setup->dirty |= LP_SETUP_NEW_SCISSOR; }
/** * Put a BeginQuery command into all bins. */ void lp_setup_begin_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) { /* init the query to its beginning state */ assert(setup->active_query == NULL); set_scene_state(setup, SETUP_ACTIVE, "begin_query"); setup->active_query = pq; if (setup->scene) { if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { if (!lp_setup_flush_and_restart(setup)) return; if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { return; } } } }
/** * Put a BeginQuery command into all bins. */ void lp_setup_begin_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) { /* init the query to its beginning state */ assert(setup->active_query[pq->type] == NULL); set_scene_state(setup, SETUP_ACTIVE, "begin_query"); setup->active_query[pq->type] = pq; /* XXX: It is possible that a query is created before the scene * has been created. This means that setup->scene == NULL resulting * in the query not being binned and thus is ignored. */ if (setup->scene) { if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { if (!lp_setup_flush_and_restart(setup)) return; if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { return; } } } }
void lp_setup_set_rasterizer_discard( struct lp_setup_context *setup, boolean rasterizer_discard ) { if (setup->rasterizer_discard != rasterizer_discard) { setup->rasterizer_discard = rasterizer_discard; set_scene_state( setup, SETUP_FLUSHED, __FUNCTION__ ); } }
void lp_setup_flush_and_restart(struct lp_setup_context *setup) { if (0) debug_printf("%s\n", __FUNCTION__); assert(setup->state == SETUP_ACTIVE); set_scene_state(setup, SETUP_FLUSHED, __FUNCTION__); lp_setup_update_state(setup, TRUE); }
static boolean lp_setup_try_clear_zs(struct lp_setup_context *setup, double depth, unsigned stencil, unsigned flags) { uint64_t zsmask = 0; uint64_t zsvalue = 0; uint32_t zmask32; uint8_t smask8; LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); zmask32 = (flags & PIPE_CLEAR_DEPTH) ? ~0 : 0; smask8 = (flags & PIPE_CLEAR_STENCIL) ? ~0 : 0; zsvalue = util_pack64_z_stencil(setup->fb.zsbuf->format, depth, stencil); zsmask = util_pack64_mask_z_stencil(setup->fb.zsbuf->format, zmask32, smask8); zsvalue &= zsmask; if (setup->state == SETUP_ACTIVE) { struct lp_scene *scene = setup->scene; /* Add the clear to existing scene. In the unusual case where * both color and depth-stencil are being cleared when there's * already been some rendering, we could discard the currently * binned scene and start again, but I don't see that as being * a common usage. */ if (!lp_scene_bin_everywhere(scene, LP_RAST_OP_CLEAR_ZSTENCIL, lp_rast_arg_clearzs(zsvalue, zsmask))) return FALSE; } else { /* Put ourselves into the 'pre-clear' state, specifically to try * and accumulate multiple clears to color and depth_stencil * buffers which the app or state-tracker might issue * separately. */ set_scene_state( setup, SETUP_CLEARED, __FUNCTION__ ); setup->clear.flags |= flags; setup->clear.zsmask |= zsmask; setup->clear.zsvalue = (setup->clear.zsvalue & ~zsmask) | (zsvalue & zsmask); } return TRUE; }
void lp_setup_flush( struct lp_setup_context *setup, struct pipe_fence_handle **fence, const char *reason) { set_scene_state( setup, SETUP_FLUSHED, reason ); if (fence) { lp_fence_reference((struct lp_fence **)fence, setup->last_fence); } }
boolean lp_setup_flush_and_restart(struct lp_setup_context *setup) { if (0) debug_printf("%s\n", __FUNCTION__); assert(setup->state == SETUP_ACTIVE); if (!set_scene_state(setup, SETUP_FLUSHED, __FUNCTION__)) return FALSE; if (!lp_setup_update_state(setup, TRUE)) return FALSE; return TRUE; }
/** * Put a BeginQuery command into all bins. */ void lp_setup_begin_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) { set_scene_state(setup, SETUP_ACTIVE, "begin_query"); if (!(pq->type == PIPE_QUERY_OCCLUSION_COUNTER || pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || pq->type == PIPE_QUERY_PIPELINE_STATISTICS)) return; /* init the query to its beginning state */ assert(setup->active_binned_queries < LP_MAX_ACTIVE_BINNED_QUERIES); /* exceeding list size so just ignore the query */ if (setup->active_binned_queries >= LP_MAX_ACTIVE_BINNED_QUERIES) { return; } assert(setup->active_queries[setup->active_binned_queries] == NULL); setup->active_queries[setup->active_binned_queries] = pq; setup->active_binned_queries++; assert(setup->scene); if (setup->scene) { if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { if (!lp_setup_flush_and_restart(setup)) return; if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_BEGIN_QUERY, lp_rast_arg_query(pq))) { return; } } setup->scene->had_queries |= TRUE; } }
void lp_setup_update_state( struct lp_setup_context *setup, boolean update_scene ) { /* Some of the 'draw' pipeline stages may have changed some driver state. * Make sure we've processed those state changes before anything else. * * XXX this is the only place where llvmpipe_context is used in the * setup code. This may get refactored/changed... */ { struct llvmpipe_context *lp = llvmpipe_context(setup->pipe); if (lp->dirty) { llvmpipe_update_derived(lp); } /* Will probably need to move this somewhere else, just need * to know about vertex shader point size attribute. */ setup->psize = lp->psize_slot; assert(lp->dirty == 0); } if (update_scene) set_scene_state( setup, SETUP_ACTIVE, __FUNCTION__ ); /* Only call into update_scene_state() if we already have a * scene: */ if (update_scene && setup->scene) { assert(setup->state == SETUP_ACTIVE); if (!try_update_scene_state(setup)) { lp_setup_flush_and_restart(setup); if (!try_update_scene_state(setup)) assert(0); } } }
/* * Try to clear one color buffer of the attached fb, either by binning a clear * command or queuing up the clear for later (when binning is started). */ static boolean lp_setup_try_clear_color_buffer(struct lp_setup_context *setup, const union pipe_color_union *color, unsigned cbuf) { union lp_rast_cmd_arg clearrb_arg; union util_color uc; enum pipe_format format = setup->fb.cbufs[cbuf]->format; LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); if (util_format_is_pure_integer(format)) { /* * We expect int/uint clear values here, though some APIs * might disagree (but in any case util_pack_color() * couldn't handle it)... */ if (util_format_is_pure_sint(format)) { util_format_write_4i(format, color->i, 0, &uc, 0, 0, 0, 1, 1); } else { assert(util_format_is_pure_uint(format)); util_format_write_4ui(format, color->ui, 0, &uc, 0, 0, 0, 1, 1); } } else { util_pack_color(color->f, format, &uc); } if (setup->state == SETUP_ACTIVE) { struct lp_scene *scene = setup->scene; /* Add the clear to existing scene. In the unusual case where * both color and depth-stencil are being cleared when there's * already been some rendering, we could discard the currently * binned scene and start again, but I don't see that as being * a common usage. */ struct lp_rast_clear_rb *cc_scene = (struct lp_rast_clear_rb *) lp_scene_alloc_aligned(scene, sizeof(struct lp_rast_clear_rb), 8); if (!cc_scene) { return FALSE; } cc_scene->cbuf = cbuf; cc_scene->color_val = uc; clearrb_arg.clear_rb = cc_scene; if (!lp_scene_bin_everywhere(scene, LP_RAST_OP_CLEAR_COLOR, clearrb_arg)) return FALSE; } else { /* Put ourselves into the 'pre-clear' state, specifically to try * and accumulate multiple clears to color and depth_stencil * buffers which the app or state-tracker might issue * separately. */ set_scene_state( setup, SETUP_CLEARED, __FUNCTION__ ); assert(PIPE_CLEAR_COLOR0 == (1 << 2)); setup->clear.flags |= 1 << (cbuf + 2); setup->clear.color_val[cbuf] = uc; } return TRUE; }
/** * Put an EndQuery command into all bins. */ void lp_setup_end_query(struct lp_setup_context *setup, struct llvmpipe_query *pq) { set_scene_state(setup, SETUP_ACTIVE, "end_query"); assert(setup->scene); if (setup->scene) { /* pq->fence should be the fence of the *last* scene which * contributed to the query result. */ lp_fence_reference(&pq->fence, setup->scene->fence); if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER || pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || pq->type == PIPE_QUERY_PIPELINE_STATISTICS || pq->type == PIPE_QUERY_TIMESTAMP) { if (pq->type == PIPE_QUERY_TIMESTAMP && !(setup->scene->tiles_x | setup->scene->tiles_y)) { /* * If there's a zero width/height framebuffer, there's no bins and * hence no rast task is ever run. So fill in something here instead. */ pq->end[0] = os_time_get_nano(); } if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_END_QUERY, lp_rast_arg_query(pq))) { if (!lp_setup_flush_and_restart(setup)) goto fail; if (!lp_scene_bin_everywhere(setup->scene, LP_RAST_OP_END_QUERY, lp_rast_arg_query(pq))) { goto fail; } } setup->scene->had_queries |= TRUE; } } else { lp_fence_reference(&pq->fence, setup->last_fence); } fail: /* Need to do this now not earlier since it still needs to be marked as * active when binning it would cause a flush. */ if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER || pq->type == PIPE_QUERY_OCCLUSION_PREDICATE || pq->type == PIPE_QUERY_PIPELINE_STATISTICS) { unsigned i; /* remove from active binned query list */ for (i = 0; i < setup->active_binned_queries; i++) { if (setup->active_queries[i] == pq) break; } assert(i < setup->active_binned_queries); if (i == setup->active_binned_queries) return; setup->active_binned_queries--; setup->active_queries[i] = setup->active_queries[setup->active_binned_queries]; setup->active_queries[setup->active_binned_queries] = NULL; } }
boolean lp_setup_update_state( struct lp_setup_context *setup, boolean update_scene ) { /* Some of the 'draw' pipeline stages may have changed some driver state. * Make sure we've processed those state changes before anything else. * * XXX this is the only place where llvmpipe_context is used in the * setup code. This may get refactored/changed... */ { struct llvmpipe_context *lp = llvmpipe_context(setup->pipe); if (lp->dirty) { llvmpipe_update_derived(lp); } if (lp->setup->dirty) { llvmpipe_update_setup(lp); } assert(setup->setup.variant); /* Will probably need to move this somewhere else, just need * to know about vertex shader point size attribute. */ setup->psize_slot = lp->psize_slot; setup->viewport_index_slot = lp->viewport_index_slot; setup->layer_slot = lp->layer_slot; setup->face_slot = lp->face_slot; assert(lp->dirty == 0); assert(lp->setup_variant.key.size == setup->setup.variant->key.size); assert(memcmp(&lp->setup_variant.key, &setup->setup.variant->key, setup->setup.variant->key.size) == 0); } if (update_scene && setup->state != SETUP_ACTIVE) { if (!set_scene_state( setup, SETUP_ACTIVE, __FUNCTION__ )) return FALSE; } /* Only call into update_scene_state() if we already have a * scene: */ if (update_scene && setup->scene) { assert(setup->state == SETUP_ACTIVE); if (try_update_scene_state(setup)) return TRUE; /* Update failed, try to restart the scene. * * Cannot call lp_setup_flush_and_restart() directly here * because of potential recursion. */ if (!set_scene_state(setup, SETUP_FLUSHED, __FUNCTION__)) return FALSE; if (!set_scene_state(setup, SETUP_ACTIVE, __FUNCTION__)) return FALSE; if (!setup->scene) return FALSE; return try_update_scene_state(setup); } return TRUE; }
static boolean lp_setup_try_clear( struct lp_setup_context *setup, const float *color, double depth, unsigned stencil, unsigned flags ) { uint32_t zsmask = 0; uint32_t zsvalue = 0; union lp_rast_cmd_arg color_arg; unsigned i; LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); if (flags & PIPE_CLEAR_COLOR) { for (i = 0; i < 4; i++) color_arg.clear_color[i] = float_to_ubyte(color[i]); } if (flags & PIPE_CLEAR_DEPTHSTENCIL) { unsigned zmask = (flags & PIPE_CLEAR_DEPTH) ? ~0 : 0; unsigned smask = (flags & PIPE_CLEAR_STENCIL) ? ~0 : 0; zsvalue = util_pack_z_stencil(setup->fb.zsbuf->format, depth, stencil); zsmask = util_pack_uint_z_stencil(setup->fb.zsbuf->format, zmask, smask); } if (setup->state == SETUP_ACTIVE) { struct lp_scene *scene = setup->scene; /* Add the clear to existing scene. In the unusual case where * both color and depth-stencil are being cleared when there's * already been some rendering, we could discard the currently * binned scene and start again, but I don't see that as being * a common usage. */ if (flags & PIPE_CLEAR_COLOR) { if (!lp_scene_bin_everywhere( scene, LP_RAST_OP_CLEAR_COLOR, color_arg )) return FALSE; } if (flags & PIPE_CLEAR_DEPTHSTENCIL) { if (!lp_scene_bin_everywhere( scene, LP_RAST_OP_CLEAR_ZSTENCIL, lp_rast_arg_clearzs(zsvalue, zsmask) )) return FALSE; } } else { /* Put ourselves into the 'pre-clear' state, specifically to try * and accumulate multiple clears to color and depth_stencil * buffers which the app or state-tracker might issue * separately. */ set_scene_state( setup, SETUP_CLEARED, __FUNCTION__ ); setup->clear.flags |= flags; if (flags & PIPE_CLEAR_DEPTHSTENCIL) { setup->clear.zsmask |= zsmask; setup->clear.zsvalue = (setup->clear.zsvalue & ~zsmask) | (zsvalue & zsmask); } if (flags & PIPE_CLEAR_COLOR) { memcpy(setup->clear.color.clear_color, &color_arg, sizeof color_arg); } } return TRUE; }