/* * 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; }
/** * Called by vbuf code when we're about to draw something. */ static boolean try_update_scene_state( struct lp_setup_context *setup ) { boolean new_scene = (setup->fs.stored == NULL); struct lp_scene *scene = setup->scene; assert(scene); if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { uint8_t *stored; unsigned i, j; stored = lp_scene_alloc_aligned(scene, 4 * 16, 16); if (!stored) { assert(!new_scene); return FALSE; } /* smear each blend color component across 16 ubyte elements */ for (i = 0; i < 4; ++i) { uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); for (j = 0; j < 16; ++j) stored[i*16 + j] = c; } setup->blend_color.stored = stored; setup->fs.current.jit_context.blend_color = setup->blend_color.stored; setup->dirty |= LP_SETUP_NEW_FS; } if(setup->dirty & LP_SETUP_NEW_CONSTANTS) { struct pipe_resource *buffer = setup->constants.current; if(buffer) { unsigned current_size = buffer->width0; const void *current_data = llvmpipe_resource_data(buffer); /* TODO: copy only the actually used constants? */ if(setup->constants.stored_size != current_size || !setup->constants.stored_data || memcmp(setup->constants.stored_data, current_data, current_size) != 0) { void *stored; stored = lp_scene_alloc(scene, current_size); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, current_data, current_size); setup->constants.stored_size = current_size; setup->constants.stored_data = stored; } } else { setup->constants.stored_size = 0; setup->constants.stored_data = NULL; } setup->fs.current.jit_context.constants = setup->constants.stored_data; setup->dirty |= LP_SETUP_NEW_FS; } if (setup->dirty & LP_SETUP_NEW_FS) { if (!setup->fs.stored || memcmp(setup->fs.stored, &setup->fs.current, sizeof setup->fs.current) != 0) { struct lp_rast_state *stored; uint i; /* The fs state that's been stored in the scene is different from * the new, current state. So allocate a new lp_rast_state object * and append it to the bin's setup data buffer. */ stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, &setup->fs.current, sizeof setup->fs.current); setup->fs.stored = stored; /* The scene now references the textures in the rasterization * state record. Note that now. */ for (i = 0; i < Elements(setup->fs.current_tex); i++) { if (setup->fs.current_tex[i]) { if (!lp_scene_add_resource_reference(scene, setup->fs.current_tex[i], new_scene)) { assert(!new_scene); return FALSE; } } } } } if (setup->dirty & LP_SETUP_NEW_SCISSOR) { setup->draw_region = setup->framebuffer; if (setup->scissor_test) { u_rect_possible_intersection(&setup->scissor, &setup->draw_region); } } setup->dirty = 0; assert(setup->fs.stored); return TRUE; }
/** * Called by vbuf code when we're about to draw something. * * This function stores all dirty state in the current scene's display list * memory, via lp_scene_alloc(). We can not pass pointers of mutable state to * the JIT functions, as the JIT functions will be called later on, most likely * on a different thread. * * When processing dirty state it is imperative that we don't refer to any * pointers previously allocated with lp_scene_alloc() in this function (or any * function) as they may belong to a scene freed since then. */ static boolean try_update_scene_state( struct lp_setup_context *setup ) { static const float fake_const_buf[4]; boolean new_scene = (setup->fs.stored == NULL); struct lp_scene *scene = setup->scene; unsigned i; assert(scene); if (setup->dirty & LP_SETUP_NEW_VIEWPORTS) { /* * Record new depth range state for changes due to viewport updates. * * TODO: Collapse the existing viewport and depth range information * into one structure, for access by JIT. */ struct lp_jit_viewport *stored; stored = (struct lp_jit_viewport *) lp_scene_alloc(scene, sizeof setup->viewports); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, setup->viewports, sizeof setup->viewports); setup->fs.current.jit_context.viewports = stored; setup->dirty |= LP_SETUP_NEW_FS; } if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { uint8_t *stored; float* fstored; unsigned i, j; unsigned size; /* Alloc u8_blend_color (16 x i8) and f_blend_color (4 or 8 x f32) */ size = 4 * 16 * sizeof(uint8_t); size += (LP_MAX_VECTOR_LENGTH / 4) * sizeof(float); stored = lp_scene_alloc_aligned(scene, size, LP_MIN_VECTOR_ALIGN); if (!stored) { assert(!new_scene); return FALSE; } /* Store floating point colour */ fstored = (float*)(stored + 4*16); for (i = 0; i < (LP_MAX_VECTOR_LENGTH / 4); ++i) { fstored[i] = setup->blend_color.current.color[i % 4]; } /* smear each blend color component across 16 ubyte elements */ for (i = 0; i < 4; ++i) { uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); for (j = 0; j < 16; ++j) stored[i*16 + j] = c; } setup->blend_color.stored = stored; setup->fs.current.jit_context.u8_blend_color = stored; setup->fs.current.jit_context.f_blend_color = fstored; setup->dirty |= LP_SETUP_NEW_FS; } if (setup->dirty & LP_SETUP_NEW_CONSTANTS) { for (i = 0; i < ARRAY_SIZE(setup->constants); ++i) { struct pipe_resource *buffer = setup->constants[i].current.buffer; const unsigned current_size = MIN2(setup->constants[i].current.buffer_size, LP_MAX_TGSI_CONST_BUFFER_SIZE); const ubyte *current_data = NULL; int num_constants; STATIC_ASSERT(DATA_BLOCK_SIZE >= LP_MAX_TGSI_CONST_BUFFER_SIZE); if (buffer) { /* resource buffer */ current_data = (ubyte *) llvmpipe_resource_data(buffer); } else if (setup->constants[i].current.user_buffer) { /* user-space buffer */ current_data = (ubyte *) setup->constants[i].current.user_buffer; } if (current_data) { current_data += setup->constants[i].current.buffer_offset; /* TODO: copy only the actually used constants? */ if (setup->constants[i].stored_size != current_size || !setup->constants[i].stored_data || memcmp(setup->constants[i].stored_data, current_data, current_size) != 0) { void *stored; stored = lp_scene_alloc(scene, current_size); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, current_data, current_size); setup->constants[i].stored_size = current_size; setup->constants[i].stored_data = stored; } setup->fs.current.jit_context.constants[i] = setup->constants[i].stored_data; } else { setup->constants[i].stored_size = 0; setup->constants[i].stored_data = NULL; setup->fs.current.jit_context.constants[i] = fake_const_buf; } num_constants = setup->constants[i].stored_size / (sizeof(float) * 4); setup->fs.current.jit_context.num_constants[i] = num_constants; setup->dirty |= LP_SETUP_NEW_FS; } } if (setup->dirty & LP_SETUP_NEW_FS) { if (!setup->fs.stored || memcmp(setup->fs.stored, &setup->fs.current, sizeof setup->fs.current) != 0) { struct lp_rast_state *stored; /* The fs state that's been stored in the scene is different from * the new, current state. So allocate a new lp_rast_state object * and append it to the bin's setup data buffer. */ stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, &setup->fs.current, sizeof setup->fs.current); setup->fs.stored = stored; /* The scene now references the textures in the rasterization * state record. Note that now. */ for (i = 0; i < ARRAY_SIZE(setup->fs.current_tex); i++) { if (setup->fs.current_tex[i]) { if (!lp_scene_add_resource_reference(scene, setup->fs.current_tex[i], new_scene)) { assert(!new_scene); return FALSE; } } } } } if (setup->dirty & LP_SETUP_NEW_SCISSOR) { unsigned i; for (i = 0; i < PIPE_MAX_VIEWPORTS; ++i) { setup->draw_regions[i] = setup->framebuffer; if (setup->scissor_test) { u_rect_possible_intersection(&setup->scissors[i], &setup->draw_regions[i]); } } } setup->dirty = 0; assert(setup->fs.stored); return TRUE; }
/** * Called by vbuf code when we're about to draw something. */ static boolean try_update_scene_state( struct lp_setup_context *setup ) { boolean new_scene = (setup->fs.stored == NULL); struct lp_scene *scene = setup->scene; unsigned i; assert(scene); if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { uint8_t *stored; float* fstored; unsigned i, j; unsigned size; /* Alloc u8_blend_color (16 x i8) and f_blend_color (4 or 8 x f32) */ size = 4 * 16 * sizeof(uint8_t); size += (LP_MAX_VECTOR_LENGTH / 4) * sizeof(float); stored = lp_scene_alloc_aligned(scene, size, LP_MAX_VECTOR_LENGTH); if (!stored) { assert(!new_scene); return FALSE; } /* Store floating point colour */ fstored = (float*)(stored + 4*16); for (i = 0; i < (LP_MAX_VECTOR_LENGTH / 4); ++i) { fstored[i] = setup->blend_color.current.color[i % 4]; } /* smear each blend color component across 16 ubyte elements */ for (i = 0; i < 4; ++i) { uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); for (j = 0; j < 16; ++j) stored[i*16 + j] = c; } setup->blend_color.stored = stored; setup->fs.current.jit_context.u8_blend_color = stored; setup->fs.current.jit_context.f_blend_color = fstored; setup->dirty |= LP_SETUP_NEW_FS; } if (setup->dirty & LP_SETUP_NEW_CONSTANTS) { for (i = 0; i < Elements(setup->constants); ++i) { struct pipe_resource *buffer = setup->constants[i].current.buffer; const unsigned current_size = setup->constants[i].current.buffer_size; const ubyte *current_data = NULL; if (buffer) { /* resource buffer */ current_data = (ubyte *) llvmpipe_resource_data(buffer); } else if (setup->constants[i].current.user_buffer) { /* user-space buffer */ current_data = (ubyte *) setup->constants[i].current.user_buffer; } if (current_data) { current_data += setup->constants[i].current.buffer_offset; /* TODO: copy only the actually used constants? */ if (setup->constants[i].stored_size != current_size || !setup->constants[i].stored_data || memcmp(setup->constants[i].stored_data, current_data, current_size) != 0) { void *stored; stored = lp_scene_alloc(scene, current_size); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, current_data, current_size); setup->constants[i].stored_size = current_size; setup->constants[i].stored_data = stored; } } else { setup->constants[i].stored_size = 0; setup->constants[i].stored_data = NULL; } setup->fs.current.jit_context.constants[i] = setup->constants[i].stored_data; setup->dirty |= LP_SETUP_NEW_FS; } } if (setup->dirty & LP_SETUP_NEW_FS) { if (!setup->fs.stored || memcmp(setup->fs.stored, &setup->fs.current, sizeof setup->fs.current) != 0) { struct lp_rast_state *stored; /* The fs state that's been stored in the scene is different from * the new, current state. So allocate a new lp_rast_state object * and append it to the bin's setup data buffer. */ stored = (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); if (!stored) { assert(!new_scene); return FALSE; } memcpy(stored, &setup->fs.current, sizeof setup->fs.current); setup->fs.stored = stored; /* The scene now references the textures in the rasterization * state record. Note that now. */ for (i = 0; i < Elements(setup->fs.current_tex); i++) { if (setup->fs.current_tex[i]) { if (!lp_scene_add_resource_reference(scene, setup->fs.current_tex[i], new_scene)) { assert(!new_scene); return FALSE; } } } } } if (setup->dirty & LP_SETUP_NEW_SCISSOR) { setup->draw_region = setup->framebuffer; if (setup->scissor_test) { u_rect_possible_intersection(&setup->scissor, &setup->draw_region); } } setup->dirty = 0; assert(setup->fs.stored); return TRUE; }