/** * Add a reference to a resource by the scene. */ boolean lp_scene_add_resource_reference(struct lp_scene *scene, struct pipe_resource *resource, boolean initializing_scene) { struct resource_ref *ref, **last = &scene->resources; int i; /* Look at existing resource blocks: */ for (ref = scene->resources; ref; ref = ref->next) { last = &ref->next; /* Search for this resource: */ for (i = 0; i < ref->count; i++) if (ref->resource[i] == resource) return TRUE; if (ref->count < RESOURCE_REF_SZ) { /* If the block is half-empty, then append the reference here. */ break; } } /* Create a new block if no half-empty block was found. */ if (!ref) { assert(*last == NULL); *last = lp_scene_alloc(scene, sizeof *ref); if (*last == NULL) return FALSE; ref = *last; memset(ref, 0, sizeof *ref); } /* Append the reference to the reference block. */ pipe_resource_reference(&ref->resource[ref->count++], resource); scene->resource_reference_size += llvmpipe_resource_size(resource); /* Heuristic to advise scene flushes. This isn't helpful in the * initial setup of the scene, but after that point flush on the * next resource added which exceeds 64MB in referenced texture * data. */ if (!initializing_scene && scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE) return FALSE; return TRUE; }
struct cmd_block * lp_scene_new_cmd_block( struct lp_scene *scene, struct cmd_bin *bin ) { struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block)); if (block) { if (bin->tail) { bin->tail->next = block; bin->tail = block; } else { bin->head = block; bin->tail = block; } //memset(block, 0, sizeof *block); block->next = NULL; block->count = 0; } return block; }
static boolean begin_binning( struct lp_setup_context *setup ) { struct lp_scene *scene = setup->scene; boolean need_zsload = FALSE; boolean ok; assert(scene); assert(scene->fence == NULL); /* Always create a fence: */ scene->fence = lp_fence_create(MAX2(1, setup->num_threads)); if (!scene->fence) return FALSE; ok = try_update_scene_state(setup); if (!ok) return FALSE; if (setup->fb.zsbuf && ((setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && util_format_is_depth_and_stencil(setup->fb.zsbuf->format)) need_zsload = TRUE; LP_DBG(DEBUG_SETUP, "%s color clear bufs: %x depth: %s\n", __FUNCTION__, setup->clear.flags >> 2, need_zsload ? "clear": "load"); if (setup->clear.flags & PIPE_CLEAR_COLOR) { unsigned cbuf; for (cbuf = 0; cbuf < setup->fb.nr_cbufs; cbuf++) { assert(PIPE_CLEAR_COLOR0 == 1 << 2); if (setup->clear.flags & (1 << (2 + cbuf))) { union lp_rast_cmd_arg clearrb_arg; struct lp_rast_clear_rb *cc_scene = (struct lp_rast_clear_rb *) lp_scene_alloc(scene, sizeof(struct lp_rast_clear_rb)); if (!cc_scene) { return FALSE; } cc_scene->cbuf = cbuf; cc_scene->color_val = setup->clear.color_val[cbuf]; clearrb_arg.clear_rb = cc_scene; if (!lp_scene_bin_everywhere(scene, LP_RAST_OP_CLEAR_COLOR, clearrb_arg)) return FALSE; } } } if (setup->fb.zsbuf) { if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) { ok = lp_scene_bin_everywhere( scene, LP_RAST_OP_CLEAR_ZSTENCIL, lp_rast_arg_clearzs( setup->clear.zsvalue, setup->clear.zsmask)); if (!ok) return FALSE; } } setup->clear.flags = 0; setup->clear.zsmask = 0; setup->clear.zsvalue = 0; scene->had_queries = !!setup->active_binned_queries; LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__); 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; 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. */ 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; }