From 3d29e75a5f59639c3b9dfed26cd41ab13c0d60fc Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Thu, 28 Aug 2014 05:13:35 +0200 Subject: [PATCH] softpipe: handle vertex texture sampling when using llvm for draw Pretty trivial, just fill in the offsets and such. The implementation is near 100% copy and paste from llvmpipe. Should be useful for debugging. No piglit change when not using SOFTPIPE_USE_LLVM=1. Now that it can do the same tests with and without using llvm for vs/gs, with llvm more pass, the only things failing only with llvm seems to be edgeflags tests and vs/gs-pow-float-float (and for the latter I'm not convinced the zero tolerance it requires is somehow mandated by glsl). Reviewed-by: Jose Fonseca --- src/gallium/drivers/llvmpipe/lp_setup.c | 2 +- .../drivers/llvmpipe/lp_state_sampler.c | 2 +- src/gallium/drivers/softpipe/sp_context.h | 2 + src/gallium/drivers/softpipe/sp_draw_arrays.c | 15 ++ src/gallium/drivers/softpipe/sp_screen.c | 18 +- src/gallium/drivers/softpipe/sp_state.h | 15 ++ .../drivers/softpipe/sp_state_sampler.c | 156 ++++++++++++++++++ src/gallium/drivers/softpipe/sp_texture.c | 34 ++-- src/gallium/drivers/softpipe/sp_texture.h | 1 + 9 files changed, 209 insertions(+), 36 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index e85c4ca9c3d..7d0c8cc847a 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -873,7 +873,7 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup, /* probably don't really need to fill that out */ jit_tex->mip_offsets[0] = 0; jit_tex->row_stride[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; diff --git a/src/gallium/drivers/llvmpipe/lp_state_sampler.c b/src/gallium/drivers/llvmpipe/lp_state_sampler.c index 0180e99fca0..21da6290574 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_sampler.c +++ b/src/gallium/drivers/llvmpipe/lp_state_sampler.c @@ -266,7 +266,7 @@ prepare_shader_sampling( /* probably don't really need to fill that out */ mip_offsets[0] = 0; row_stride[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; diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h index aac35f7bf58..50a73369c1d 100644 --- a/src/gallium/drivers/softpipe/sp_context.h +++ b/src/gallium/drivers/softpipe/sp_context.h @@ -85,6 +85,8 @@ struct softpipe_context { struct pipe_viewport_state viewport; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer index_buffer; + struct pipe_resource *mapped_vs_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS]; + struct pipe_resource *mapped_gs_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS]; struct draw_so_target *so_targets[PIPE_MAX_SO_BUFFERS]; unsigned num_so_targets; diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c index b75c10f3f05..03fcf64fd2e 100644 --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c @@ -41,6 +41,7 @@ #include "sp_query.h" #include "sp_state.h" #include "sp_texture.h" +#include "sp_screen.h" #include "draw/draw_context.h" @@ -123,6 +124,15 @@ softpipe_draw_vbo(struct pipe_context *pipe, draw_set_mapped_so_targets(draw, sp->num_so_targets, sp->so_targets); + if (softpipe_screen(sp->pipe.screen)->use_llvm) { + softpipe_prepare_vertex_sampling(sp, + sp->num_sampler_views[PIPE_SHADER_VERTEX], + sp->sampler_views[PIPE_SHADER_VERTEX]); + softpipe_prepare_geometry_sampling(sp, + sp->num_sampler_views[PIPE_SHADER_GEOMETRY], + sp->sampler_views[PIPE_SHADER_GEOMETRY]); + } + if (sp->gs && !sp->gs->shader.tokens) { /* we have an empty geometry shader with stream output, so attach the stream output info to the current vertex shader */ @@ -146,6 +156,11 @@ softpipe_draw_vbo(struct pipe_context *pipe, draw_set_mapped_so_targets(draw, 0, NULL); + if (softpipe_screen(sp->pipe.screen)->use_llvm) { + softpipe_cleanup_vertex_sampling(sp); + softpipe_cleanup_geometry_sampling(sp); + } + /* * TODO: Flush only when a user vertex/index buffer is present * (or even better, modify draw module to do this diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c index f6fddfe66c1..956d59c02ba 100644 --- a/src/gallium/drivers/softpipe/sp_screen.c +++ b/src/gallium/drivers/softpipe/sp_screen.c @@ -242,20 +242,10 @@ softpipe_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe return tgsi_exec_get_shader_param(param); case PIPE_SHADER_VERTEX: case PIPE_SHADER_GEOMETRY: - switch (param) { - case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: - case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: - if (sp_screen->use_llvm) - /* Softpipe doesn't yet know how to tell draw/llvm about textures */ - return 0; - else - return PIPE_MAX_SAMPLERS; - default: - if (sp_screen->use_llvm) - return draw_get_shader_param(shader, param); - else - return draw_get_shader_param_no_llvm(shader, param); - } + if (sp_screen->use_llvm) + return draw_get_shader_param(shader, param); + else + return draw_get_shader_param_no_llvm(shader, param); default: return 0; } diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h index 775a1f50c9c..c35534c931d 100644 --- a/src/gallium/drivers/softpipe/sp_state.h +++ b/src/gallium/drivers/softpipe/sp_state.h @@ -192,5 +192,20 @@ softpipe_find_fs_variant(struct softpipe_context *softpipe, struct sp_fragment_shader *fs, const struct sp_fragment_shader_variant_key *key); +void +softpipe_prepare_vertex_sampling(struct softpipe_context *ctx, + unsigned num, + struct pipe_sampler_view **views); +void +softpipe_cleanup_vertex_sampling(struct softpipe_context *ctx); + + +void +softpipe_prepare_geometry_sampling(struct softpipe_context *ctx, + unsigned num, + struct pipe_sampler_view **views); +void +softpipe_cleanup_geometry_sampling(struct softpipe_context *ctx); + #endif diff --git a/src/gallium/drivers/softpipe/sp_state_sampler.c b/src/gallium/drivers/softpipe/sp_state_sampler.c index e51241892e1..e56fb5b1485 100644 --- a/src/gallium/drivers/softpipe/sp_state_sampler.c +++ b/src/gallium/drivers/softpipe/sp_state_sampler.c @@ -31,6 +31,7 @@ #include "util/u_memory.h" #include "util/u_inlines.h" +#include "util/u_format.h" #include "draw/draw_context.h" @@ -39,6 +40,8 @@ #include "sp_texture.h" #include "sp_tex_sample.h" #include "sp_tex_tile_cache.h" +#include "sp_screen.h" +#include "state_tracker/sw_winsys.h" /** @@ -159,6 +162,159 @@ softpipe_delete_sampler_state(struct pipe_context *pipe, } +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 */ + struct pipe_resource *res = view->texture; + int j; + + if (res->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 (res->target == PIPE_TEXTURE_1D_ARRAY || + res->target == PIPE_TEXTURE_2D_ARRAY || + res->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 (res->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); + } + } +} + + +/** + * Called during state validation when SP_NEW_TEXTURE is set. + */ +void +softpipe_prepare_vertex_sampling(struct softpipe_context *sp, + unsigned num, + struct pipe_sampler_view **views) +{ + prepare_shader_sampling(sp, num, views, PIPE_SHADER_VERTEX, + sp->mapped_vs_tex); +} + +void +softpipe_cleanup_vertex_sampling(struct softpipe_context *ctx) +{ + unsigned i; + for (i = 0; i < Elements(ctx->mapped_vs_tex); i++) { + pipe_resource_reference(&ctx->mapped_vs_tex[i], NULL); + } +} + + +/** + * Called during state validation when SP_NEW_TEXTURE is set. + */ +void +softpipe_prepare_geometry_sampling(struct softpipe_context *sp, + unsigned num, + struct pipe_sampler_view **views) +{ + prepare_shader_sampling(sp, num, views, PIPE_SHADER_GEOMETRY, + sp->mapped_gs_tex); +} + +void +softpipe_cleanup_geometry_sampling(struct softpipe_context *ctx) +{ + unsigned i; + for (i = 0; i < Elements(ctx->mapped_gs_tex); i++) { + pipe_resource_reference(&ctx->mapped_gs_tex[i], NULL); + } +} + + void softpipe_init_sampler_funcs(struct pipe_context *pipe) { diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c index 6538e46db09..c2df71e41a5 100644 --- a/src/gallium/drivers/softpipe/sp_texture.c +++ b/src/gallium/drivers/softpipe/sp_texture.c @@ -63,7 +63,9 @@ softpipe_resource_layout(struct pipe_screen *screen, uint64_t buffer_size = 0; for (level = 0; level <= pt->last_level; level++) { - unsigned slices; + unsigned slices, nblocksy; + + nblocksy = util_format_get_nblocksy(pt->format, height); if (pt->target == PIPE_TEXTURE_CUBE) slices = 6; @@ -76,8 +78,15 @@ softpipe_resource_layout(struct pipe_screen *screen, spr->level_offset[level] = buffer_size; - buffer_size += (uint64_t) util_format_get_nblocksy(pt->format, height) * - slices * spr->stride[level]; + /* if row_stride * height > SP_MAX_TEXTURE_SIZE */ + if ((uint64_t)spr->stride[level] * nblocksy > SP_MAX_TEXTURE_SIZE) { + /* image too large */ + return FALSE; + } + + spr->img_stride[level] = spr->stride[level] * nblocksy; + + buffer_size += (uint64_t) spr->img_stride[level] * slices; width = u_minify(width, 1); height = u_minify(height, 1); @@ -253,22 +262,9 @@ static unsigned sp_get_tex_image_offset(const struct softpipe_resource *spr, unsigned level, unsigned layer) { - const unsigned hgt = u_minify(spr->base.height0, level); - const unsigned nblocksy = util_format_get_nblocksy(spr->base.format, hgt); unsigned offset = spr->level_offset[level]; - if (spr->base.target == PIPE_TEXTURE_CUBE || - spr->base.target == PIPE_TEXTURE_CUBE_ARRAY || - spr->base.target == PIPE_TEXTURE_3D || - spr->base.target == PIPE_TEXTURE_2D_ARRAY) { - offset += layer * nblocksy * spr->stride[level]; - } - else if (spr->base.target == PIPE_TEXTURE_1D_ARRAY) { - offset += layer * spr->stride[level]; - } - else { - assert(layer == 0); - } + offset += layer * spr->img_stride[level]; return offset; } @@ -354,8 +350,6 @@ softpipe_transfer_map(struct pipe_context *pipe, struct softpipe_transfer *spt; struct pipe_transfer *pt; enum pipe_format format = resource->format; - const unsigned hgt = u_minify(spr->base.height0, level); - const unsigned nblocksy = util_format_get_nblocksy(format, hgt); uint8_t *map; assert(resource); @@ -414,7 +408,7 @@ softpipe_transfer_map(struct pipe_context *pipe, pt->usage = usage; pt->box = *box; pt->stride = spr->stride[level]; - pt->layer_stride = pt->stride * nblocksy; + pt->layer_stride = spr->img_stride[level]; spt->offset = sp_get_tex_image_offset(spr, level, box->z); diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h index 90f35e11631..1701bf574d9 100644 --- a/src/gallium/drivers/softpipe/sp_texture.h +++ b/src/gallium/drivers/softpipe/sp_texture.h @@ -47,6 +47,7 @@ struct softpipe_resource unsigned long level_offset[SP_MAX_TEXTURE_2D_LEVELS]; unsigned stride[SP_MAX_TEXTURE_2D_LEVELS]; + unsigned img_stride[SP_MAX_TEXTURE_2D_LEVELS]; /** * Display target, only valid for PIPE_TEXTURE_2D with the -- 2.30.2