static void llvmpipe_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) { struct llvmpipe_screen *screen = llvmpipe_screen(pscreen); struct llvmpipe_resource *lpr = llvmpipe_resource(pt); if (lpr->dt) { /* display target */ struct sw_winsys *winsys = screen->winsys; winsys->displaytarget_destroy(winsys, lpr->dt); } else if (llvmpipe_resource_is_texture(pt)) { /* free linear image data */ if (lpr->linear_img.data) { align_free(lpr->linear_img.data); lpr->linear_img.data = NULL; } } else if (!lpr->userBuffer) { assert(lpr->data); align_free(lpr->data); } #ifdef DEBUG if (lpr->next) remove_from_list(lpr); #endif FREE(lpr); }
void * llvmpipe_resource_data(struct pipe_resource *resource) { struct llvmpipe_resource *lpr = llvmpipe_resource(resource); assert(!llvmpipe_resource_is_texture(resource)); return lpr->data; }
/** * Map a resource for read/write. */ void * llvmpipe_resource_map(struct pipe_resource *resource, unsigned level, unsigned layer, enum lp_texture_usage tex_usage) { struct llvmpipe_resource *lpr = llvmpipe_resource(resource); uint8_t *map; assert(level < LP_MAX_TEXTURE_LEVELS); assert(layer < (u_minify(resource->depth0, level) + resource->array_size - 1)); assert(tex_usage == LP_TEX_USAGE_READ || tex_usage == LP_TEX_USAGE_READ_WRITE || tex_usage == LP_TEX_USAGE_WRITE_ALL); if (lpr->dt) { /* display target */ struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen); struct sw_winsys *winsys = screen->winsys; unsigned dt_usage; if (tex_usage == LP_TEX_USAGE_READ) { dt_usage = PIPE_TRANSFER_READ; } else { dt_usage = PIPE_TRANSFER_READ_WRITE; } assert(level == 0); assert(layer == 0); /* FIXME: keep map count? */ map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage); /* install this linear image in texture data structure */ lpr->linear_img.data = map; return map; } else if (llvmpipe_resource_is_texture(resource)) { map = llvmpipe_get_texture_image(lpr, layer, level, tex_usage); return map; } else { return lpr->data; } }
void lp_scene_begin_rasterization(struct lp_scene *scene) { const struct pipe_framebuffer_state *fb = &scene->fb; int i; //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__); for (i = 0; i < scene->fb.nr_cbufs; i++) { struct pipe_surface *cbuf = scene->fb.cbufs[i]; if (llvmpipe_resource_is_texture(cbuf->texture)) { assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer); scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture, cbuf->u.tex.level); scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture, cbuf->u.tex.level, cbuf->u.tex.first_layer, LP_TEX_USAGE_READ_WRITE, LP_TEX_LAYOUT_LINEAR); } else { struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture); unsigned pixstride = util_format_get_blocksize(cbuf->format); scene->cbufs[i].stride = cbuf->texture->width0; scene->cbufs[i].map = lpr->data; scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride; } } if (fb->zsbuf) { struct pipe_surface *zsbuf = scene->fb.zsbuf; assert(zsbuf->u.tex.first_layer == zsbuf->u.tex.last_layer); scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level); scene->zsbuf.blocksize = util_format_get_blocksize(zsbuf->texture->format); scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture, zsbuf->u.tex.level, zsbuf->u.tex.first_layer, LP_TEX_USAGE_READ_WRITE, LP_TEX_LAYOUT_NONE); } }
/** * Called during state validation when LP_NEW_SAMPLER_VIEW is set. */ void lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup, unsigned num, struct pipe_sampler_view **views) { unsigned i, max_tex_num; LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); max_tex_num = MAX2(num, setup->fs.current_tex_num); for (i = 0; i < max_tex_num; i++) { struct pipe_sampler_view *view = i < num ? views[i] : NULL; if (view) { struct pipe_resource *res = view->texture; struct llvmpipe_resource *lp_tex = llvmpipe_resource(res); struct lp_jit_texture *jit_tex; jit_tex = &setup->fs.current.jit_context.textures[i]; /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&setup->fs.current_tex[i], res); if (!lp_tex->dt) { /* regular texture - setup array of mipmap level offsets */ int j; unsigned first_level = 0; unsigned last_level = 0; if (llvmpipe_resource_is_texture(res)) { first_level = view->u.tex.first_level; last_level = view->u.tex.last_level; assert(first_level <= last_level); assert(last_level <= res->last_level); jit_tex->base = lp_tex->tex_data; } else { jit_tex->base = lp_tex->data; } if (LP_PERF & PERF_TEX_MEM) { /* use dummy tile memory */ jit_tex->base = lp_dummy_tile; jit_tex->width = TILE_SIZE/8; jit_tex->height = TILE_SIZE/8; jit_tex->depth = 1; jit_tex->first_level = 0; jit_tex->last_level = 0; jit_tex->mip_offsets[0] = 0; jit_tex->row_stride[0] = 0; jit_tex->img_stride[0] = 0; } else { jit_tex->width = res->width0; jit_tex->height = res->height0; jit_tex->depth = res->depth0; jit_tex->first_level = first_level; jit_tex->last_level = last_level; if (llvmpipe_resource_is_texture(res)) { for (j = first_level; j <= last_level; j++) { jit_tex->mip_offsets[j] = lp_tex->mip_offsets[j]; jit_tex->row_stride[j] = lp_tex->row_stride[j]; jit_tex->img_stride[j] = lp_tex->img_stride[j]; } if (res->target == PIPE_TEXTURE_1D_ARRAY || res->target == PIPE_TEXTURE_2D_ARRAY || res->target == PIPE_TEXTURE_CUBE || res->target == PIPE_TEXTURE_CUBE_ARRAY) { /* * For array textures, we don't have first_layer, instead * adjust last_layer (stored as depth) plus the mip level offsets * (as we have mip-first layout can't just adjust base ptr). * XXX For mip levels, could do something similar. */ jit_tex->depth = view->u.tex.last_layer - view->u.tex.first_layer + 1; for (j = first_level; j <= last_level; j++) { jit_tex->mip_offsets[j] += view->u.tex.first_layer * lp_tex->img_stride[j]; } if (view->target == PIPE_TEXTURE_CUBE || view->target == PIPE_TEXTURE_CUBE_ARRAY) { assert(jit_tex->depth % 6 == 0); } assert(view->u.tex.first_layer <= view->u.tex.last_layer); assert(view->u.tex.last_layer < res->array_size); } } else { /* * For buffers, we don't have first_element, instead adjust * last_element (stored as width) plus the base pointer. */ unsigned view_blocksize = util_format_get_blocksize(view->format); /* probably don't really need to fill that out */ jit_tex->mip_offsets[0] = 0; jit_tex->row_stride[0] = 0; jit_tex->img_stride[0] = 0; /* everything specified in number of elements here. */ jit_tex->width = view->u.buf.last_element - view->u.buf.first_element + 1; jit_tex->base = (uint8_t *)jit_tex->base + view->u.buf.first_element * view_blocksize; /* XXX Unsure if we need to sanitize parameters? */ assert(view->u.buf.first_element <= view->u.buf.last_element); assert(view->u.buf.last_element * view_blocksize < res->width0); } } } else { /* display target texture/surface */ /* * XXX: Where should this be unmapped? */ struct llvmpipe_screen *screen = llvmpipe_screen(res->screen); struct sw_winsys *winsys = screen->winsys; jit_tex->base = winsys->displaytarget_map(winsys, lp_tex->dt, PIPE_TRANSFER_READ); jit_tex->row_stride[0] = lp_tex->row_stride[0]; jit_tex->img_stride[0] = lp_tex->img_stride[0]; jit_tex->mip_offsets[0] = 0; jit_tex->width = res->width0; jit_tex->height = res->height0; jit_tex->depth = res->depth0; jit_tex->first_level = jit_tex->last_level = 0; assert(jit_tex->base); } } else { pipe_resource_reference(&setup->fs.current_tex[i], NULL); } } setup->fs.current_tex_num = num; setup->dirty |= LP_SETUP_NEW_FS; }
static void prepare_shader_sampling( struct llvmpipe_context *lp, unsigned num, struct pipe_sampler_view **views, unsigned shader_type) { unsigned i; uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS]; uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS]; uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS]; const void *addr; assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); if (!num) return; for (i = 0; i < num; i++) { struct pipe_sampler_view *view = i < num ? views[i] : NULL; if (view) { struct pipe_resource *tex = view->texture; struct llvmpipe_resource *lp_tex = llvmpipe_resource(tex); unsigned width0 = tex->width0; unsigned num_layers = tex->depth0; unsigned first_level = 0; unsigned last_level = 0; if (!lp_tex->dt) { /* regular texture - setup array of mipmap level offsets */ struct pipe_resource *res = view->texture; int j; if (llvmpipe_resource_is_texture(res)) { first_level = view->u.tex.first_level; last_level = view->u.tex.last_level; assert(first_level <= last_level); assert(last_level <= res->last_level); addr = lp_tex->tex_data; for (j = first_level; j <= last_level; j++) { mip_offsets[j] = lp_tex->mip_offsets[j]; row_stride[j] = lp_tex->row_stride[j]; img_stride[j] = lp_tex->img_stride[j]; } if (tex->target == PIPE_TEXTURE_1D_ARRAY || tex->target == PIPE_TEXTURE_2D_ARRAY || tex->target == PIPE_TEXTURE_CUBE || tex->target == PIPE_TEXTURE_CUBE_ARRAY) { num_layers = view->u.tex.last_layer - view->u.tex.first_layer + 1; for (j = first_level; j <= last_level; j++) { mip_offsets[j] += view->u.tex.first_layer * lp_tex->img_stride[j]; } if (view->target == PIPE_TEXTURE_CUBE || view->target == PIPE_TEXTURE_CUBE_ARRAY) { assert(num_layers % 6 == 0); } assert(view->u.tex.first_layer <= view->u.tex.last_layer); assert(view->u.tex.last_layer < res->array_size); } } else { unsigned view_blocksize = util_format_get_blocksize(view->format); addr = lp_tex->data; /* probably don't really need to fill that out */ mip_offsets[0] = 0; row_stride[0] = 0; img_stride[0] = 0; /* everything specified in number of elements here. */ width0 = view->u.buf.last_element - view->u.buf.first_element + 1; addr = (uint8_t *)addr + view->u.buf.first_element * view_blocksize; assert(view->u.buf.first_element <= view->u.buf.last_element); assert(view->u.buf.last_element * view_blocksize < res->width0); } } else { /* display target texture/surface */ /* * XXX: Where should this be unmapped? */ struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen); struct sw_winsys *winsys = screen->winsys; addr = winsys->displaytarget_map(winsys, lp_tex->dt, PIPE_TRANSFER_READ); row_stride[0] = lp_tex->row_stride[0]; img_stride[0] = lp_tex->img_stride[0]; mip_offsets[0] = 0; assert(addr); } draw_set_mapped_texture(lp->draw, shader_type, i, width0, tex->height0, num_layers, first_level, last_level, addr, row_stride, img_stride, mip_offsets); } } }
/** * Free all the temporary data in a scene. */ void lp_scene_end_rasterization(struct lp_scene *scene ) { int i, j; /* Unmap color buffers */ for (i = 0; i < scene->fb.nr_cbufs; i++) { if (scene->cbufs[i].map) { struct pipe_surface *cbuf = scene->fb.cbufs[i]; if (llvmpipe_resource_is_texture(cbuf->texture)) { llvmpipe_resource_unmap(cbuf->texture, cbuf->u.tex.level, cbuf->u.tex.first_layer); } scene->cbufs[i].map = NULL; } } /* Unmap z/stencil buffer */ if (scene->zsbuf.map) { struct pipe_surface *zsbuf = scene->fb.zsbuf; llvmpipe_resource_unmap(zsbuf->texture, zsbuf->u.tex.level, zsbuf->u.tex.first_layer); scene->zsbuf.map = NULL; } /* Reset all command lists: */ for (i = 0; i < scene->tiles_x; i++) { for (j = 0; j < scene->tiles_y; j++) { struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); bin->head = NULL; bin->tail = NULL; bin->last_state = NULL; } } /* If there are any bins which weren't cleared by the loop above, * they will be caught (on debug builds at least) by this assert: */ assert(lp_scene_is_empty(scene)); /* Decrement texture ref counts */ { struct resource_ref *ref; int i, j = 0; for (ref = scene->resources; ref; ref = ref->next) { for (i = 0; i < ref->count; i++) { if (LP_DEBUG & DEBUG_SETUP) debug_printf("resource %d: %p %dx%d sz %d\n", j, (void *) ref->resource[i], ref->resource[i]->width0, ref->resource[i]->height0, llvmpipe_resource_size(ref->resource[i])); j++; pipe_resource_reference(&ref->resource[i], NULL); } } if (LP_DEBUG & DEBUG_SETUP) debug_printf("scene %d resources, sz %d\n", j, scene->resource_reference_size); } /* Free all scene data blocks: */ { struct data_block_list *list = &scene->data; struct data_block *block, *tmp; for (block = list->head->next; block; block = tmp) { tmp = block->next; FREE(block); } list->head->next = NULL; list->head->used = 0; } lp_fence_reference(&scene->fence, NULL); scene->resources = NULL; scene->scene_size = 0; scene->resource_reference_size = 0; scene->has_depthstencil_clear = FALSE; scene->alloc_failed = FALSE; util_unreference_framebuffer_state( &scene->fb ); }
static struct pipe_resource * llvmpipe_resource_create(struct pipe_screen *_screen, const struct pipe_resource *templat) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); if (!lpr) return NULL; lpr->base = *templat; pipe_reference_init(&lpr->base.reference, 1); lpr->base.screen = &screen->base; /* assert(lpr->base.bind); */ if (llvmpipe_resource_is_texture(&lpr->base)) { if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) { /* displayable surface */ if (!llvmpipe_displaytarget_layout(screen, lpr)) goto fail; } else { /* texture map */ if (!llvmpipe_texture_layout(screen, lpr)) goto fail; } } else { /* other data (vertex buffer, const buffer, etc) */ const uint bytes = templat->width0; assert(util_format_get_blocksize(templat->format) == 1); assert(templat->height0 == 1); assert(templat->depth0 == 1); assert(templat->last_level == 0); /* * Reserve some extra storage since if we'd render to a buffer we * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE. */ lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64); /* * buffers don't really have stride but it's probably safer * (for code doing same calculations for buffers and textures) * to put something sane in there. */ lpr->row_stride[0] = bytes; if (!lpr->data) goto fail; memset(lpr->data, 0, bytes); } lpr->id = id_counter++; #ifdef DEBUG insert_at_tail(&resource_list, lpr); #endif return &lpr->base; fail: FREE(lpr); return NULL; }