static void gdi_present(struct pipe_screen *screen, struct pipe_resource *res, HDC hDC) { /* This will fail if any interposing layer (trace, debug, etc) has * been introduced between the state-trackers and the pipe driver. * * Ideally this would get replaced with a call to * pipe_screen::flush_frontbuffer(). * * Failing that, it may be necessary for intervening layers to wrap * other structs such as this stw_winsys as well... */ struct sw_winsys *winsys = NULL; struct sw_displaytarget *dt = NULL; #ifdef HAVE_LLVMPIPE if (use_llvmpipe) { winsys = llvmpipe_screen(screen)->winsys; dt = llvmpipe_resource(res)->dt; gdi_sw_display(winsys, dt, hDC); return; } #endif winsys = softpipe_screen(screen)->winsys, dt = softpipe_resource(res)->dt, gdi_sw_display(winsys, dt, hDC); }
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); }
/** * Called during state validation when LP_NEW_SAMPLER_VIEW is set. */ void llvmpipe_prepare_vertex_sampling(struct llvmpipe_context *lp, unsigned num, struct pipe_sampler_view **views) { unsigned i; uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS]; uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS]; const void *data[DRAW_MAX_TEXTURE_LEVELS]; assert(num <= PIPE_MAX_VERTEX_SAMPLERS); if (!num) return; for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; 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); /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&lp->mapped_vs_tex[i], tex); if (!lp_tex->dt) { /* regular texture - setup array of mipmap level pointers */ int j; for (j = 0; j <= tex->last_level; j++) { data[j] = llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ, LP_TEX_LAYOUT_LINEAR); row_stride[j] = lp_tex->row_stride[j]; img_stride[j] = lp_tex->img_stride[j]; } } 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; data[0] = 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]; assert(data[0]); } draw_set_mapped_texture(lp->draw, i, tex->width0, tex->height0, tex->depth0, tex->last_level, row_stride, img_stride, data); } } }
void * llvmpipe_resource_data(struct pipe_resource *resource) { struct llvmpipe_resource *lpr = llvmpipe_resource(resource); assert(!resource_is_texture(resource)); return lpr->data; }
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); if (lpr->tiled[0].data) { align_free(lpr->tiled[0].data); lpr->tiled[0].data = NULL; } FREE(lpr->layout[0]); } else if (resource_is_texture(pt)) { /* regular texture */ uint level; /* free linear image data */ for (level = 0; level < Elements(lpr->linear); level++) { if (lpr->linear[level].data) { align_free(lpr->linear[level].data); lpr->linear[level].data = NULL; } } /* free tiled image data */ for (level = 0; level < Elements(lpr->tiled); level++) { if (lpr->tiled[level].data) { align_free(lpr->tiled[level].data); lpr->tiled[level].data = NULL; } } /* free layout flag arrays */ for (level = 0; level < Elements(lpr->tiled); level++) { FREE(lpr->layout[level]); lpr->layout[level] = NULL; } } else if (!lpr->userBuffer) { assert(lpr->data); align_free(lpr->data); } #ifdef DEBUG if (lpr->next) remove_from_list(lpr); #endif FREE(lpr); }
static void llvmpipe_flush_frontbuffer(struct pipe_screen *_screen, struct pipe_surface *surface, void *context_private) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; struct llvmpipe_resource *texture = llvmpipe_resource(surface->texture); assert(texture->dt); if (texture->dt) winsys->displaytarget_display(winsys, texture->dt, context_private); }
/** * Begining rasterization of a tile. * \param x window X position of the tile, in pixels * \param y window Y position of the tile, in pixels */ static void lp_rast_tile_begin(struct lp_rasterizer_task *task, const struct cmd_bin *bin) { const struct lp_scene *scene = task->scene; enum lp_texture_usage usage; LP_DBG(DEBUG_RAST, "%s %d,%d\n", __FUNCTION__, bin->x, bin->y); task->bin = bin; task->x = bin->x * TILE_SIZE; task->y = bin->y * TILE_SIZE; /* reset pointers to color tile(s) */ memset(task->color_tiles, 0, sizeof(task->color_tiles)); /* get pointer to depth/stencil tile */ { struct pipe_surface *zsbuf = task->scene->fb.zsbuf; if (zsbuf) { struct llvmpipe_resource *lpt = llvmpipe_resource(zsbuf->texture); if (scene->has_depthstencil_clear) usage = LP_TEX_USAGE_WRITE_ALL; else usage = LP_TEX_USAGE_READ_WRITE; /* "prime" the tile: convert data from linear to tiled if necessary * and update the tile's layout info. */ (void) llvmpipe_get_texture_tile(lpt, zsbuf->u.tex.first_layer, zsbuf->u.tex.level, usage, task->x, task->y); /* Get actual pointer to the tile data. Note that depth/stencil * data is tiled differently than color data. */ task->depth_tile = lp_rast_get_depth_block_pointer(task, task->x, task->y); assert(task->depth_tile); } else { task->depth_tile = NULL; } } }
/** * 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; } }
static void llvmpipe_flush_frontbuffer(struct pipe_screen *_screen, struct pipe_resource *resource, unsigned level, unsigned layer, void *context_private, struct pipe_box *sub_box) { struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; struct llvmpipe_resource *texture = llvmpipe_resource(resource); assert(texture->dt); if (texture->dt) winsys->displaytarget_display(winsys, texture->dt, context_private, sub_box); }
/** * Unmap a resource. */ void llvmpipe_resource_unmap(struct pipe_resource *resource, unsigned level, unsigned layer) { struct llvmpipe_resource *lpr = llvmpipe_resource(resource); if (lpr->dt) { /* display target */ struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen); struct sw_winsys *winsys = lp_screen->winsys; assert(level == 0); assert(layer == 0); winsys->displaytarget_unmap(winsys, lpr->dt); } }
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); } }
/** * Convert the color tile from tiled to linear layout. * This is generally only done when we're flushing the scene just prior to * SwapBuffers. If we didn't do this here, we'd have to convert the entire * tiled color buffer to linear layout in the llvmpipe_texture_unmap() * function. It's better to do it here to take advantage of * threading/parallelism. * This is a bin command which is stored in all bins. */ static void lp_rast_store_linear_color( struct lp_rasterizer_task *task ) { const struct lp_scene *scene = task->scene; unsigned buf; for (buf = 0; buf < scene->fb.nr_cbufs; buf++) { struct pipe_surface *cbuf = scene->fb.cbufs[buf]; const unsigned layer = cbuf->u.tex.first_layer; const unsigned level = cbuf->u.tex.level; struct llvmpipe_resource *lpt = llvmpipe_resource(cbuf->texture); if (!task->color_tiles[buf]) continue; llvmpipe_unswizzle_cbuf_tile(lpt, layer, level, task->x, task->y, task->color_tiles[buf]); } }
/** * Unmap a resource. */ void llvmpipe_resource_unmap(struct pipe_resource *resource, unsigned level, unsigned layer) { struct llvmpipe_resource *lpr = llvmpipe_resource(resource); if (lpr->dt) { /* display target */ struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen); struct sw_winsys *winsys = lp_screen->winsys; assert(level == 0); assert(layer == 0); /* make sure linear image is up to date */ (void) llvmpipe_get_texture_image(lpr, layer, level, LP_TEX_USAGE_READ, LP_TEX_LAYOUT_LINEAR); winsys->displaytarget_unmap(winsys, lpr->dt); } }
/** * 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 lp_resource_copy(struct pipe_context *pipe, struct pipe_resource *dst, struct pipe_subresource subdst, unsigned dstx, unsigned dsty, unsigned dstz, struct pipe_resource *src, struct pipe_subresource subsrc, unsigned srcx, unsigned srcy, unsigned srcz, unsigned width, unsigned height) { /* XXX what about the dstz/srcz parameters - zslice wasn't used... */ struct llvmpipe_resource *src_tex = llvmpipe_resource(src); struct llvmpipe_resource *dst_tex = llvmpipe_resource(dst); const enum pipe_format format = src_tex->base.format; llvmpipe_flush_resource(pipe, dst, subdst.face, subdst.level, 0, /* flush_flags */ FALSE, /* read_only */ TRUE, /* cpu_access */ FALSE, /* do_not_block */ "blit dest"); llvmpipe_flush_resource(pipe, src, subsrc.face, subsrc.level, 0, /* flush_flags */ TRUE, /* read_only */ TRUE, /* cpu_access */ FALSE, /* do_not_block */ "blit src"); /* printf("surface copy from %u to %u: %u,%u to %u,%u %u x %u\n", src_tex->id, dst_tex->id, srcx, srcy, dstx, dsty, width, height); */ /* set src tiles to linear layout */ { unsigned tx, ty, tw, th; unsigned x, y; adjust_to_tile_bounds(srcx, srcy, width, height, &tx, &ty, &tw, &th); for (y = 0; y < th; y += TILE_SIZE) { for (x = 0; x < tw; x += TILE_SIZE) { (void) llvmpipe_get_texture_tile_linear(src_tex, subsrc.face, subsrc.level, LP_TEX_USAGE_READ, tx + x, ty + y); } } } /* set dst tiles to linear layout */ { unsigned tx, ty, tw, th; unsigned x, y; enum lp_texture_usage usage; adjust_to_tile_bounds(dstx, dsty, width, height, &tx, &ty, &tw, &th); for (y = 0; y < th; y += TILE_SIZE) { boolean contained_y = ty + y >= dsty && ty + y + TILE_SIZE <= dsty + height ? TRUE : FALSE; for (x = 0; x < tw; x += TILE_SIZE) { boolean contained_x = tx + x >= dstx && tx + x + TILE_SIZE <= dstx + width ? TRUE : FALSE; /* * Set the usage mode to WRITE_ALL for the tiles which are * completely contained by the dest rectangle. */ if (contained_y && contained_x) usage = LP_TEX_USAGE_WRITE_ALL; else usage = LP_TEX_USAGE_READ_WRITE; (void) llvmpipe_get_texture_tile_linear(dst_tex, subdst.face, subdst.level, usage, tx + x, ty + y); } } } /* copy */ { const ubyte *src_linear_ptr = llvmpipe_get_texture_image_address(src_tex, subsrc.face, subsrc.level, LP_TEX_LAYOUT_LINEAR); ubyte *dst_linear_ptr = llvmpipe_get_texture_image_address(dst_tex, subdst.face, subdst.level, LP_TEX_LAYOUT_LINEAR); if (dst_linear_ptr && src_linear_ptr) { util_copy_rect(dst_linear_ptr, format, llvmpipe_resource_stride(&dst_tex->base, subdst.level), dstx, dsty, width, height, src_linear_ptr, llvmpipe_resource_stride(&src_tex->base, subsrc.level), srcx, srcy); } } }
/** * Draw vertex arrays, with optional indexing, optional instancing. * All the other drawing functions are implemented in terms of this function. * Basically, map the vertex buffers (and drawing surfaces), then hand off * the drawing to the 'draw' module. */ static void llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { struct llvmpipe_context *lp = llvmpipe_context(pipe); struct draw_context *draw = lp->draw; const void *mapped_indices = NULL; unsigned i; if (!llvmpipe_check_render_cond(lp)) return; if (info->indirect) { util_draw_indirect(pipe, info); return; } if (lp->dirty) llvmpipe_update_derived( lp ); /* * Map vertex buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { const void *buf = lp->vertex_buffer[i].is_user_buffer ? lp->vertex_buffer[i].buffer.user : NULL; size_t size = ~0; if (!buf) { if (!lp->vertex_buffer[i].buffer.resource) { continue; } buf = llvmpipe_resource_data(lp->vertex_buffer[i].buffer.resource); size = lp->vertex_buffer[i].buffer.resource->width0; } draw_set_mapped_vertex_buffer(draw, i, buf, size); } /* Map index buffer, if present */ if (info->index_size) { unsigned available_space = ~0; mapped_indices = info->has_user_indices ? info->index.user : NULL; if (!mapped_indices) { mapped_indices = llvmpipe_resource_data(info->index.resource); available_space = info->index.resource->width0; } draw_set_indexes(draw, (ubyte *) mapped_indices, info->index_size, available_space); } for (i = 0; i < lp->num_so_targets; i++) { void *buf = 0; if (lp->so_targets[i]) { buf = llvmpipe_resource(lp->so_targets[i]->target.buffer)->data; lp->so_targets[i]->mapping = buf; } } draw_set_mapped_so_targets(draw, lp->num_so_targets, lp->so_targets); llvmpipe_prepare_vertex_sampling(lp, lp->num_sampler_views[PIPE_SHADER_VERTEX], lp->sampler_views[PIPE_SHADER_VERTEX]); llvmpipe_prepare_geometry_sampling(lp, lp->num_sampler_views[PIPE_SHADER_GEOMETRY], lp->sampler_views[PIPE_SHADER_GEOMETRY]); if (lp->gs && lp->gs->no_tokens) { /* we have an empty geometry shader with stream output, so attach the stream output info to the current vertex shader */ if (lp->vs) { draw_vs_attach_so(lp->vs, &lp->gs->stream_output); } } draw_collect_pipeline_statistics(draw, lp->active_statistics_queries > 0); /* draw! */ draw_vbo(draw, info); /* * unmap vertex/index buffers */ for (i = 0; i < lp->num_vertex_buffers; i++) { draw_set_mapped_vertex_buffer(draw, i, NULL, 0); } if (mapped_indices) { draw_set_indexes(draw, NULL, 0, 0); } draw_set_mapped_so_targets(draw, 0, NULL); if (lp->gs && lp->gs->no_tokens) { /* we have attached stream output to the vs for rendering, now lets reset it */ if (lp->vs) { draw_vs_reset_so(lp->vs); } } /* * TODO: Flush only when a user vertex/index buffer is present * (or even better, modify draw module to do this * internally when this condition is seen?) */ draw_flush(draw); }
/** * 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; LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; 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); struct lp_jit_texture *jit_tex; jit_tex = &setup->fs.current.jit_context.textures[i]; jit_tex->width = tex->width0; jit_tex->height = tex->height0; jit_tex->first_level = view->u.tex.first_level; jit_tex->last_level = tex->last_level; if (tex->target == PIPE_TEXTURE_3D) { jit_tex->depth = tex->depth0; } else { jit_tex->depth = tex->array_size; } /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&setup->fs.current_tex[i], tex); if (!lp_tex->dt) { /* regular texture - setup array of mipmap level offsets */ void *mip_ptr; int j; /* * XXX this is messed up we don't want to accidentally trigger * tiled->linear conversion for levels we don't need. * So ask for first_level data (which will allocate all levels) * then if successful get base ptr. */ mip_ptr = llvmpipe_get_texture_image_all(lp_tex, view->u.tex.first_level, LP_TEX_USAGE_READ, LP_TEX_LAYOUT_LINEAR); if ((LP_PERF & PERF_TEX_MEM) || !mip_ptr) { /* out of memory - 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; } else { jit_tex->base = lp_tex->linear_img.data; } for (j = view->u.tex.first_level; j <= tex->last_level; j++) { mip_ptr = llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ, LP_TEX_LAYOUT_LINEAR); jit_tex->mip_offsets[j] = (uint8_t *)mip_ptr - (uint8_t *)jit_tex->base; /* * could get mip offset directly but need call above to * invoke tiled->linear conversion. */ assert(lp_tex->linear_mip_offsets[j] == jit_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 (jit_tex->base == lp_dummy_tile) { /* out of memory - use dummy tile memory */ jit_tex->mip_offsets[j] = 0; jit_tex->row_stride[j] = 0; jit_tex->img_stride[j] = 0; } } } 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; 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; assert(jit_tex->base); } } } 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); } } }
/** * 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; LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); assert(num <= PIPE_MAX_SAMPLERS); for (i = 0; i < PIPE_MAX_SAMPLERS; 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); struct lp_jit_texture *jit_tex; jit_tex = &setup->fs.current.jit_context.textures[i]; jit_tex->width = tex->width0; jit_tex->height = tex->height0; jit_tex->depth = tex->depth0; jit_tex->last_level = tex->last_level; /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&setup->fs.current_tex[i], tex); if (!lp_tex->dt) { /* regular texture - setup array of mipmap level pointers */ int j; for (j = 0; j <= tex->last_level; j++) { jit_tex->data[j] = llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ, LP_TEX_LAYOUT_LINEAR); jit_tex->row_stride[j] = lp_tex->row_stride[j]; jit_tex->img_stride[j] = lp_tex->img_stride[j]; if (!jit_tex->data[j]) { /* out of memory - use dummy tile memory */ jit_tex->data[j] = lp_dummy_tile; jit_tex->width = TILE_SIZE; jit_tex->height = TILE_SIZE; jit_tex->depth = 1; jit_tex->last_level = 0; jit_tex->row_stride[j] = 0; jit_tex->img_stride[j] = 0; } } } 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; jit_tex->data[0] = 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]; assert(jit_tex->data[0]); } } } setup->dirty |= LP_SETUP_NEW_FS; }
static void lp_resource_copy(struct pipe_context *pipe, struct pipe_resource *dst, unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz, struct pipe_resource *src, unsigned src_level, const struct pipe_box *src_box) { /* XXX this used to ignore srcz/dstz * assume it works the same for cube and 3d */ struct llvmpipe_resource *src_tex = llvmpipe_resource(src); struct llvmpipe_resource *dst_tex = llvmpipe_resource(dst); const enum pipe_format format = src_tex->base.format; unsigned width = src_box->width; unsigned height = src_box->height; assert(src_box->depth == 1); /* Fallback for buffers. */ if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box); return; } llvmpipe_flush_resource(pipe, dst, dst_level, dstz, FALSE, /* read_only */ TRUE, /* cpu_access */ FALSE, /* do_not_block */ "blit dest"); llvmpipe_flush_resource(pipe, src, src_level, src_box->z, TRUE, /* read_only */ TRUE, /* cpu_access */ FALSE, /* do_not_block */ "blit src"); /* printf("surface copy from %u lvl %u to %u lvl %u: %u,%u,%u to %u,%u,%u %u x %u x %u\n", src_tex->id, src_level, dst_tex->id, dst_level, src_box->x, src_box->y, src_box->z, dstx, dsty, dstz, src_box->width, src_box->height, src_box->depth); */ /* set src tiles to linear layout */ { unsigned tx, ty, tw, th; unsigned x, y; adjust_to_tile_bounds(src_box->x, src_box->y, width, height, &tx, &ty, &tw, &th); for (y = 0; y < th; y += TILE_SIZE) { for (x = 0; x < tw; x += TILE_SIZE) { (void) llvmpipe_get_texture_tile_linear(src_tex, src_box->z, src_level, LP_TEX_USAGE_READ, tx + x, ty + y); } } } /* set dst tiles to linear layout */ { unsigned tx, ty, tw, th; unsigned x, y; enum lp_texture_usage usage; adjust_to_tile_bounds(dstx, dsty, width, height, &tx, &ty, &tw, &th); for (y = 0; y < th; y += TILE_SIZE) { boolean contained_y = ty + y >= dsty && ty + y + TILE_SIZE <= dsty + height ? TRUE : FALSE; for (x = 0; x < tw; x += TILE_SIZE) { boolean contained_x = tx + x >= dstx && tx + x + TILE_SIZE <= dstx + width ? TRUE : FALSE; /* * Set the usage mode to WRITE_ALL for the tiles which are * completely contained by the dest rectangle. */ if (contained_y && contained_x) usage = LP_TEX_USAGE_WRITE_ALL; else usage = LP_TEX_USAGE_READ_WRITE; (void) llvmpipe_get_texture_tile_linear(dst_tex, dstz, dst_level, usage, tx + x, ty + y); } } } /* copy */ { const ubyte *src_linear_ptr = llvmpipe_get_texture_image_address(src_tex, src_box->z, src_level, LP_TEX_LAYOUT_LINEAR); ubyte *dst_linear_ptr = llvmpipe_get_texture_image_address(dst_tex, dstz, dst_level, LP_TEX_LAYOUT_LINEAR); if (dst_linear_ptr && src_linear_ptr) { util_copy_rect(dst_linear_ptr, format, llvmpipe_resource_stride(&dst_tex->base, dst_level), dstx, dsty, width, height, src_linear_ptr, llvmpipe_resource_stride(&src_tex->base, src_level), src_box->x, src_box->y); } } }