static void update_tgsi_samplers( struct softpipe_context *softpipe ) { unsigned i, sh; set_shader_sampler(softpipe, PIPE_SHADER_VERTEX, softpipe->vs->max_sampler); set_shader_sampler(softpipe, PIPE_SHADER_FRAGMENT, softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]); if (softpipe->gs) { set_shader_sampler(softpipe, PIPE_SHADER_GEOMETRY, softpipe->gs->max_sampler); } /* XXX is this really necessary here??? */ for (sh = 0; sh < ARRAY_SIZE(softpipe->tex_cache); sh++) { for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[sh][i]; if (tc && tc->texture) { struct softpipe_resource *spt = softpipe_resource(tc->texture); if (spt->timestamp != tc->timestamp) { sp_tex_tile_cache_validate_texture( tc ); /* _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp); */ tc->timestamp = spt->timestamp; } } } } }
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 update_tgsi_samplers( struct softpipe_context *softpipe ) { unsigned i; softpipe_reset_sampler_variants( softpipe ); for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { struct softpipe_tex_tile_cache *tc = softpipe->fragment_tex_cache[i]; if (tc && tc->texture) { struct softpipe_resource *spt = softpipe_resource(tc->texture); if (spt->timestamp != tc->timestamp) { sp_tex_tile_cache_validate_texture( tc ); /* _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp); */ tc->timestamp = spt->timestamp; } } } for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { struct softpipe_tex_tile_cache *tc = softpipe->vertex_tex_cache[i]; if (tc && tc->texture) { struct softpipe_resource *spt = softpipe_resource(tc->texture); if (spt->timestamp != tc->timestamp) { sp_tex_tile_cache_validate_texture(tc); tc->timestamp = spt->timestamp; } } } for (i = 0; i < PIPE_MAX_GEOMETRY_SAMPLERS; i++) { struct softpipe_tex_tile_cache *tc = softpipe->geometry_tex_cache[i]; if (tc && tc->texture) { struct softpipe_resource *spt = softpipe_resource(tc->texture); if (spt->timestamp != tc->timestamp) { sp_tex_tile_cache_validate_texture(tc); tc->timestamp = spt->timestamp; } } } }
/* This is often overriden by the co-state tracker. */ static void softpipe_flush_frontbuffer(struct pipe_screen *_screen, struct pipe_resource *resource, unsigned level, unsigned layer, void *context_private) { struct softpipe_screen *screen = softpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; struct softpipe_resource *texture = softpipe_resource(resource); assert(texture->dt); if (texture->dt) winsys->displaytarget_display(winsys, texture->dt, context_private); }
static boolean softpipe_resource_get_handle(struct pipe_screen *screen, struct pipe_resource *pt, struct winsys_handle *whandle) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; struct softpipe_resource *spr = softpipe_resource(pt); assert(spr->dt); if (!spr->dt) return FALSE; return winsys->displaytarget_get_handle(winsys, spr->dt, whandle); }
static void gdi_softpipe_present(struct pipe_screen *screen, struct pipe_surface *surface, HDC hDC) { /* This will fail if any interposing layer (trace, debug, etc) has * been introduced between the state-trackers and softpipe. * * 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... */ gdi_sw_display(softpipe_screen(screen)->winsys, softpipe_resource(surface->texture)->dt, hDC); }
static void softpipe_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) { struct softpipe_screen *screen = softpipe_screen(pscreen); struct softpipe_resource *spr = softpipe_resource(pt); if (spr->dt) { /* display target */ struct sw_winsys *winsys = screen->winsys; winsys->displaytarget_destroy(winsys, spr->dt); } else if (!spr->userBuffer) { /* regular texture */ align_free(spr->data); } FREE(spr); }
/** * Find/create an sp_sampler_variant object for sampling the given texture, * sampler and tex unit. * * Note that the tex unit is significant. We can't re-use a sampler * variant for multiple texture units because the sampler variant contains * the texture object pointer. If the texture object pointer were stored * somewhere outside the sampler variant, we could re-use samplers for * multiple texture units. */ static struct sp_sampler_variant * get_sampler_variant( unsigned unit, struct sp_sampler *sampler, struct pipe_sampler_view *view, unsigned processor ) { struct softpipe_resource *sp_texture = softpipe_resource(view->texture); struct sp_sampler_variant *v = NULL; union sp_sampler_key key; /* if this fails, widen the key.unit field and update this assertion */ assert(PIPE_MAX_SAMPLERS <= 16); key.bits.target = sp_texture->base.target; key.bits.is_pot = sp_texture->pot; key.bits.processor = processor; key.bits.unit = unit; key.bits.swizzle_r = view->swizzle_r; key.bits.swizzle_g = view->swizzle_g; key.bits.swizzle_b = view->swizzle_b; key.bits.swizzle_a = view->swizzle_a; key.bits.pad = 0; if (sampler->current && key.value == sampler->current->key.value) { v = sampler->current; } if (v == NULL) { for (v = sampler->variants; v; v = v->next) if (v->key.value == key.value) break; if (v == NULL) { v = sp_create_sampler_variant( &sampler->base, key ); v->next = sampler->variants; sampler->variants = v; } } sampler->current = v; return v; }
/** * Unmap memory mapping for given pipe_transfer object. */ static void softpipe_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct softpipe_resource *spr; assert(transfer->resource); spr = softpipe_resource(transfer->resource); if (spr->dt) { /* display target */ struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; winsys->displaytarget_unmap(winsys, spr->dt); } if (transfer->usage & PIPE_TRANSFER_WRITE) { /* Mark the texture as dirty to expire the tile caches. */ spr->timestamp++; } }
/** * Create memory mapping for given pipe_transfer object. */ static void * softpipe_transfer_map(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct softpipe_transfer *spt = softpipe_transfer(transfer); struct softpipe_resource *spr = softpipe_resource(transfer->resource); struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; uint8_t *map; /* resources backed by display target treated specially: */ if (spr->dt) { map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage); } else { map = spr->data; } if (map == NULL) return NULL; else return map + spt->offset; }
static void update_tgsi_samplers( struct softpipe_context *softpipe ) { unsigned i, sh; softpipe_reset_sampler_variants( softpipe ); for (sh = 0; sh < Elements(softpipe->tex_cache); sh++) { for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[sh][i]; if (tc && tc->texture) { struct softpipe_resource *spt = softpipe_resource(tc->texture); if (spt->timestamp != tc->timestamp) { sp_tex_tile_cache_validate_texture( tc ); /* _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp); */ tc->timestamp = spt->timestamp; } } } } }
/** * Geta pipe_transfer object which is used for moving data in/out of * a resource object. * \param pipe rendering context * \param resource the resource to transfer in/out of * \param level which mipmap level * \param usage bitmask of PIPE_TRANSFER_x flags * \param box the 1D/2D/3D region of interest */ static struct pipe_transfer * softpipe_get_transfer(struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box) { struct softpipe_resource *spr = softpipe_resource(resource); struct softpipe_transfer *spt; assert(resource); assert(level <= resource->last_level); /* make sure the requested region is in the image bounds */ assert(box->x + box->width <= u_minify(resource->width0, level)); if (resource->target == PIPE_TEXTURE_1D_ARRAY) { assert(box->y + box->height <= resource->array_size); } else { assert(box->y + box->height <= u_minify(resource->height0, level)); if (resource->target == PIPE_TEXTURE_2D_ARRAY) { assert(box->z + box->depth <= resource->array_size); } else if (resource->target == PIPE_TEXTURE_CUBE) { assert(box->z < 6); } else { assert(box->z + box->depth <= (u_minify(resource->depth0, level))); } } /* * Transfers, like other pipe operations, must happen in order, so flush the * context if necessary. */ if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { boolean read_only = !(usage & PIPE_TRANSFER_WRITE); boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); if (!softpipe_flush_resource(pipe, resource, level, box->depth > 1 ? -1 : box->z, 0, /* flush_flags */ read_only, TRUE, /* cpu_access */ do_not_block)) { /* * It would have blocked, but state tracker requested no to. */ assert(do_not_block); return NULL; } } spt = CALLOC_STRUCT(softpipe_transfer); if (spt) { struct pipe_transfer *pt = &spt->base; enum pipe_format format = resource->format; const unsigned hgt = u_minify(spr->base.height0, level); const unsigned nblocksy = util_format_get_nblocksy(format, hgt); pipe_resource_reference(&pt->resource, resource); pt->level = level; pt->usage = usage; pt->box = *box; pt->stride = spr->stride[level]; pt->layer_stride = pt->stride * nblocksy; spt->offset = sp_get_tex_image_offset(spr, level, box->z); spt->offset += box->y / util_format_get_blockheight(format) * spt->base.stride + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); return pt; } return NULL; }
/** * Geta pipe_transfer object which is used for moving data in/out of * a resource object. * \param pipe rendering context * \param resource the resource to transfer in/out of * \param level which mipmap level * \param usage bitmask of PIPE_TRANSFER_x flags * \param box the 1D/2D/3D region of interest */ static void * softpipe_transfer_map(struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **transfer) { struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; struct softpipe_resource *spr = softpipe_resource(resource); struct softpipe_transfer *spt; struct pipe_transfer *pt; enum pipe_format format = resource->format; uint8_t *map; assert(resource); assert(level <= resource->last_level); /* make sure the requested region is in the image bounds */ assert(box->x + box->width <= (int) u_minify(resource->width0, level)); if (resource->target == PIPE_TEXTURE_1D_ARRAY) { assert(box->y + box->height <= (int) resource->array_size); } else { assert(box->y + box->height <= (int) u_minify(resource->height0, level)); if (resource->target == PIPE_TEXTURE_2D_ARRAY) { assert(box->z + box->depth <= (int) resource->array_size); } else if (resource->target == PIPE_TEXTURE_CUBE) { assert(box->z < 6); } else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) { assert(box->z <= (int) resource->array_size); } else { assert(box->z + box->depth <= (int) u_minify(resource->depth0, level)); } } /* * Transfers, like other pipe operations, must happen in order, so flush the * context if necessary. */ if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { boolean read_only = !(usage & PIPE_TRANSFER_WRITE); boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); if (!softpipe_flush_resource(pipe, resource, level, box->depth > 1 ? -1 : box->z, 0, /* flush_flags */ read_only, TRUE, /* cpu_access */ do_not_block)) { /* * It would have blocked, but state tracker requested no to. */ assert(do_not_block); return NULL; } } spt = CALLOC_STRUCT(softpipe_transfer); if (!spt) return NULL; pt = &spt->base; pipe_resource_reference(&pt->resource, resource); pt->level = level; pt->usage = usage; pt->box = *box; pt->stride = spr->stride[level]; pt->layer_stride = spr->img_stride[level]; spt->offset = softpipe_get_tex_image_offset(spr, level, box->z); spt->offset += box->y / util_format_get_blockheight(format) * spt->base.stride + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); /* resources backed by display target treated specially: */ if (spr->dt) { map = winsys->displaytarget_map(winsys, spr->dt, usage); } else { map = spr->data; } if (!map) { pipe_resource_reference(&pt->resource, NULL); FREE(spt); return NULL; } *transfer = pt; return map + spt->offset; }
static void prepare_shader_sampling( struct softpipe_context *sp, unsigned num, struct pipe_sampler_view **views, unsigned shader_type, struct pipe_resource *mapped_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS]) { 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 < 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 softpipe_resource *sp_tex = softpipe_resource(tex); unsigned width0 = tex->width0; unsigned num_layers = tex->depth0; unsigned first_level = 0; unsigned last_level = 0; /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&mapped_tex[i], tex); if (!sp_tex->dt) { /* regular texture - setup array of mipmap level offsets */ MAYBE_UNUSED struct pipe_resource *res = view->texture; int j; if (view->target != PIPE_BUFFER) { 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 = sp_tex->data; for (j = first_level; j <= last_level; j++) { mip_offsets[j] = sp_tex->level_offset[j]; row_stride[j] = sp_tex->stride[j]; img_stride[j] = sp_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 * sp_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 = sp_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 softpipe_screen *screen = softpipe_screen(tex->screen); struct sw_winsys *winsys = screen->winsys; addr = winsys->displaytarget_map(winsys, sp_tex->dt, PIPE_TRANSFER_READ); row_stride[0] = sp_tex->stride[0]; img_stride[0] = sp_tex->img_stride[0]; mip_offsets[0] = 0; assert(addr); } draw_set_mapped_texture(sp->draw, shader_type, i, width0, tex->height0, num_layers, first_level, last_level, addr, row_stride, img_stride, mip_offsets); } } }