llvmpipe: add fragment shader image support

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
This commit is contained in:
Dave Airlie 2019-07-20 14:28:23 +10:00
parent dc2357070c
commit 2909c654b0
11 changed files with 334 additions and 8 deletions

View File

@ -83,9 +83,11 @@ struct llvmpipe_context {
struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
struct pipe_shader_buffer ssbos[PIPE_SHADER_TYPES][LP_MAX_TGSI_SHADER_BUFFERS];
struct pipe_image_view images[PIPE_SHADER_TYPES][LP_MAX_TGSI_SHADER_IMAGES];
unsigned num_samplers[PIPE_SHADER_TYPES];
unsigned num_sampler_views[PIPE_SHADER_TYPES];
unsigned num_images[PIPE_SHADER_TYPES];
unsigned num_vertex_buffers;

View File

@ -684,6 +684,77 @@ lp_setup_set_fs_ssbos(struct lp_setup_context *setup,
setup->dirty |= LP_SETUP_NEW_SSBOS;
}
void
lp_setup_set_fs_images(struct lp_setup_context *setup,
unsigned num,
struct pipe_image_view *images)
{
unsigned i;
LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) images);
assert(num <= ARRAY_SIZE(setup->images));
for (i = 0; i < num; ++i) {
struct pipe_image_view *image = &images[i];
util_copy_image_view(&setup->images[i].current, &images[i]);
struct pipe_resource *res = image->resource;
struct llvmpipe_resource *lp_res = llvmpipe_resource(res);
struct lp_jit_image *jit_image;
jit_image = &setup->fs.current.jit_context.images[i];
if (!lp_res)
continue;
if (!lp_res->dt) {
/* regular texture - setup array of mipmap level offsets */
if (llvmpipe_resource_is_texture(res)) {
jit_image->base = lp_res->tex_data;
} else
jit_image->base = lp_res->data;
jit_image->width = res->width0;
jit_image->height = res->height0;
jit_image->depth = res->depth0;
if (llvmpipe_resource_is_texture(res)) {
uint32_t mip_offset = lp_res->mip_offsets[image->u.tex.level];
jit_image->width = u_minify(jit_image->width, image->u.tex.level);
jit_image->height = u_minify(jit_image->height, image->u.tex.level);
if (res->target == PIPE_TEXTURE_1D_ARRAY ||
res->target == PIPE_TEXTURE_2D_ARRAY ||
res->target == PIPE_TEXTURE_3D ||
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_image->depth = image->u.tex.last_layer - image->u.tex.first_layer + 1;
mip_offset += image->u.tex.first_layer * lp_res->img_stride[image->u.tex.level];
} else
jit_image->depth = u_minify(jit_image->depth, image->u.tex.level);
jit_image->row_stride = lp_res->row_stride[image->u.tex.level];
jit_image->img_stride = lp_res->img_stride[image->u.tex.level];
jit_image->base = (uint8_t *)jit_image->base + mip_offset;
}
else {
unsigned view_blocksize = util_format_get_blocksize(image->format);
jit_image->width = image->u.buf.size / view_blocksize;
jit_image->base = (uint8_t *)jit_image->base + image->u.buf.offset;
}
}
}
for (; i < ARRAY_SIZE(setup->images); i++) {
util_copy_image_view(&setup->images[i].current, NULL);
}
setup->dirty |= LP_SETUP_NEW_IMAGES;
}
void
lp_setup_set_alpha_ref_value( struct lp_setup_context *setup,
@ -1017,6 +1088,11 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup,
return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE;
}
for (i = 0; i < ARRAY_SIZE(setup->images); i++) {
if (setup->images[i].current.resource == texture)
return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE;
}
return LP_UNREFERENCED;
}

View File

@ -109,6 +109,11 @@ lp_setup_set_fs_ssbos(struct lp_setup_context *setup,
unsigned num,
struct pipe_shader_buffer *buffers);
void
lp_setup_set_fs_images(struct lp_setup_context *setup,
unsigned num,
struct pipe_image_view *images);
void
lp_setup_set_alpha_ref_value( struct lp_setup_context *setup,
float alpha_ref_value );

View File

@ -50,6 +50,7 @@
#define LP_SETUP_NEW_SCISSOR 0x08
#define LP_SETUP_NEW_VIEWPORTS 0x10
#define LP_SETUP_NEW_SSBOS 0x20
#define LP_SETUP_NEW_IMAGES 0x40
struct lp_setup_variant;
@ -148,6 +149,10 @@ struct lp_setup_context
struct pipe_shader_buffer current;
} ssbos[LP_MAX_TGSI_SHADER_BUFFERS];
struct {
struct pipe_image_view current;
} images[LP_MAX_TGSI_SHADER_IMAGES];
struct {
struct pipe_blend_color current;
uint8_t *stored;

View File

@ -57,7 +57,7 @@
#define LP_NEW_SO 0x20000
#define LP_NEW_SO_BUFFERS 0x40000
#define LP_NEW_FS_SSBOS 0x80000
#define LP_NEW_FS_IMAGES 0x100000
struct vertex_info;

View File

@ -260,6 +260,11 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
ARRAY_SIZE(llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]),
llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]);
if (llvmpipe->dirty & LP_NEW_FS_IMAGES)
lp_setup_set_fs_images(llvmpipe->setup,
ARRAY_SIZE(llvmpipe->images[PIPE_SHADER_FRAGMENT]),
llvmpipe->images[PIPE_SHADER_FRAGMENT]);
if (llvmpipe->dirty & (LP_NEW_SAMPLER_VIEW))
lp_setup_set_fragment_sampler_views(llvmpipe->setup,
llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT],

View File

@ -300,6 +300,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
LLVMValueRef num_loop,
struct lp_build_interp_soa_context *interp,
const struct lp_build_sampler_soa *sampler,
const struct lp_build_image_soa *image,
LLVMValueRef mask_store,
LLVMValueRef (*out_color)[4],
LLVMValueRef depth_ptr,
@ -497,6 +498,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
params.info = &shader->info.base;
params.ssbo_ptr = ssbo_ptr;
params.ssbo_sizes_ptr = num_ssbo_ptr;
params.image = image;
/* Build the actual shader */
lp_build_tgsi_soa(gallivm, tokens, &params,
@ -2450,6 +2452,7 @@ generate_fragment(struct llvmpipe_context *lp,
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
struct lp_build_sampler_soa *sampler;
struct lp_build_image_soa *image;
struct lp_build_interp_soa_context interp;
LLVMValueRef fs_mask[16 / 4];
LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][TGSI_NUM_CHANNELS][16 / 4];
@ -2596,6 +2599,7 @@ generate_fragment(struct llvmpipe_context *lp,
/* code generated texture sampling */
sampler = lp_llvm_sampler_soa_create(key->samplers);
image = lp_llvm_image_soa_create(lp_fs_variant_key_images(key));
num_fs = 16 / fs_type.length; /* number of loops per 4x4 stamp */
/* for 1d resources only run "upper half" of stamp */
@ -2650,6 +2654,7 @@ generate_fragment(struct llvmpipe_context *lp,
num_loop,
&interp,
sampler,
image,
mask_store, /* output */
color_store,
depth_ptr,
@ -2684,7 +2689,7 @@ generate_fragment(struct llvmpipe_context *lp,
}
sampler->destroy(sampler);
image->destroy(image);
/* Loop over color outputs / color buffers to do blending.
*/
for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
@ -2813,6 +2818,21 @@ dump_fs_variant_key(struct lp_fragment_shader_variant_key *key)
texture->pot_height,
texture->pot_depth);
}
struct lp_image_static_state *images = lp_fs_variant_key_images(key);
for (i = 0; i < key->nr_images; ++i) {
const struct lp_static_texture_state *image = &images[i].image_state;
debug_printf("image[%u] = \n", i);
debug_printf(" .format = %s\n",
util_format_name(image->format));
debug_printf(" .target = %s\n",
util_str_tex_target(image->target, TRUE));
debug_printf(" .level_zero_only = %u\n",
image->level_zero_only);
debug_printf(" .pot = %u %u %u\n",
image->pot_width,
image->pot_height,
image->pot_depth);
}
}
@ -2936,6 +2956,7 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
struct lp_fragment_shader *shader;
int nr_samplers;
int nr_sampler_views;
int nr_images;
int i;
shader = CALLOC_STRUCT(lp_fragment_shader);
@ -2960,8 +2981,8 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
nr_samplers = shader->info.base.file_max[TGSI_FILE_SAMPLER] + 1;
nr_sampler_views = shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
shader->variant_key_size = lp_fs_variant_key_size(MAX2(nr_samplers, nr_sampler_views));
nr_images = shader->info.base.file_max[TGSI_FILE_IMAGE] + 1;
shader->variant_key_size = lp_fs_variant_key_size(MAX2(nr_samplers, nr_sampler_views), nr_images);
for (i = 0; i < shader->info.base.num_inputs; i++) {
shader->inputs[i].usage_mask = shader->info.base.input_usage_mask[i];
@ -3187,6 +3208,32 @@ llvmpipe_set_shader_buffers(struct pipe_context *pipe,
}
}
static void
llvmpipe_set_shader_images(struct pipe_context *pipe,
enum pipe_shader_type shader, unsigned start_slot,
unsigned count, const struct pipe_image_view *images)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
unsigned i, idx;
draw_flush(llvmpipe->draw);
for (i = start_slot, idx = 0; i < start_slot + count; i++, idx++) {
const struct pipe_image_view *image = images ? &images[idx] : NULL;
util_copy_image_view(&llvmpipe->images[shader][i], image);
}
llvmpipe->num_images[shader] = start_slot + count;
if (shader == PIPE_SHADER_VERTEX ||
shader == PIPE_SHADER_GEOMETRY) {
draw_set_images(llvmpipe->draw,
shader,
llvmpipe->images[shader],
start_slot + count);
} else
llvmpipe->dirty |= LP_NEW_FS_IMAGES;
}
/**
* Return the blend factor equivalent to a destination alpha of one.
*/
@ -3413,6 +3460,16 @@ make_variant_key(struct llvmpipe_context *lp,
}
}
}
struct lp_image_static_state *lp_image;
lp_image = lp_fs_variant_key_images(key);
key->nr_images = shader->info.base.file_max[TGSI_FILE_IMAGE] + 1;
for (i = 0; i < key->nr_images; ++i) {
if (shader->info.base.file_mask[TGSI_FILE_IMAGE] & (1 << i)) {
lp_sampler_static_texture_state_image(&lp_image[i].image_state,
&lp->images[PIPE_SHADER_FRAGMENT][i]);
}
}
return key;
}
@ -3542,6 +3599,7 @@ llvmpipe_init_fs_funcs(struct llvmpipe_context *llvmpipe)
llvmpipe->pipe.set_constant_buffer = llvmpipe_set_constant_buffer;
llvmpipe->pipe.set_shader_buffers = llvmpipe_set_shader_buffers;
llvmpipe->pipe.set_shader_images = llvmpipe_set_shader_images;
}

View File

@ -59,6 +59,11 @@ struct lp_sampler_static_state
};
struct lp_image_static_state
{
struct lp_static_texture_state image_state;
};
struct lp_fragment_shader_variant_key
{
struct pipe_depth_state depth;
@ -73,6 +78,7 @@ struct lp_fragment_shader_variant_key
unsigned nr_cbufs:8;
unsigned nr_samplers:8; /* actually derivable from just the shader */
unsigned nr_sampler_views:8; /* actually derivable from just the shader */
unsigned nr_images:8; /* actually derivable from just the shader */
unsigned flatshade:1;
unsigned occlusion_count:1;
unsigned resource_1d:1;
@ -82,18 +88,28 @@ struct lp_fragment_shader_variant_key
enum pipe_format cbuf_format[PIPE_MAX_COLOR_BUFS];
struct lp_sampler_static_state samplers[1];
/* followed by variable number of images */
};
#define LP_FS_MAX_VARIANT_KEY_SIZE \
(sizeof(struct lp_fragment_shader_variant_key) + \
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state))
PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state) +\
PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state))
static inline size_t
lp_fs_variant_key_size(unsigned nr_samplers)
lp_fs_variant_key_size(unsigned nr_samplers, unsigned nr_images)
{
unsigned samplers = nr_samplers > 1 ? (nr_samplers - 1) : 0;
return (sizeof(struct lp_fragment_shader_variant_key) +
samplers * sizeof(struct lp_sampler_static_state));
samplers * sizeof(struct lp_sampler_static_state) +
nr_images * sizeof(struct lp_image_static_state));
}
static inline struct lp_image_static_state *
lp_fs_variant_key_images(struct lp_fragment_shader_variant_key *key)
{
return (struct lp_image_static_state *)
&key->samplers[key->nr_samplers];
}
/** doubly-linked list item */

View File

@ -78,6 +78,23 @@ struct lp_llvm_sampler_soa
struct llvmpipe_sampler_dynamic_state dynamic_state;
};
struct llvmpipe_image_dynamic_state
{
struct lp_sampler_dynamic_state base;
const struct lp_image_static_state *static_state;
};
/**
* This is the bridge between our sampler and the TGSI translator.
*/
struct lp_llvm_image_soa
{
struct lp_build_image_soa base;
struct llvmpipe_image_dynamic_state dynamic_state;
};
/**
* Fetch the specified member of the lp_jit_texture structure.
@ -221,6 +238,80 @@ LP_LLVM_SAMPLER_MEMBER(lod_bias, LP_JIT_SAMPLER_LOD_BIAS, TRUE)
LP_LLVM_SAMPLER_MEMBER(border_color, LP_JIT_SAMPLER_BORDER_COLOR, FALSE)
/**
* Fetch the specified member of the lp_jit_image structure.
* \param emit_load if TRUE, emit the LLVM load instruction to actually
* fetch the field's value. Otherwise, just emit the
* GEP code to address the field.
*
* @sa http://llvm.org/docs/GetElementPtr.html
*/
static LLVMValueRef
lp_llvm_image_member(const struct lp_sampler_dynamic_state *base,
struct gallivm_state *gallivm,
LLVMValueRef context_ptr,
unsigned image_unit,
unsigned member_index,
const char *member_name,
boolean emit_load)
{
LLVMBuilderRef builder = gallivm->builder;
LLVMValueRef indices[4];
LLVMValueRef ptr;
LLVMValueRef res;
assert(image_unit < PIPE_MAX_SHADER_IMAGES);
/* context[0] */
indices[0] = lp_build_const_int32(gallivm, 0);
/* context[0].images */
indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_IMAGES);
/* context[0].images[unit] */
indices[2] = lp_build_const_int32(gallivm, image_unit);
/* context[0].images[unit].member */
indices[3] = lp_build_const_int32(gallivm, member_index);
ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
if (emit_load)
res = LLVMBuildLoad(builder, ptr, "");
else
res = ptr;
lp_build_name(res, "context.image%u.%s", image_unit, member_name);
return res;
}
/**
* Helper macro to instantiate the functions that generate the code to
* fetch the members of lp_jit_image to fulfill the sampler code
* generator requests.
*
* This complexity is the price we have to pay to keep the image
* sampler code generator a reusable module without dependencies to
* llvmpipe internals.
*/
#define LP_LLVM_IMAGE_MEMBER(_name, _index, _emit_load) \
static LLVMValueRef \
lp_llvm_image_##_name( const struct lp_sampler_dynamic_state *base, \
struct gallivm_state *gallivm, \
LLVMValueRef context_ptr, \
unsigned image_unit) \
{ \
return lp_llvm_image_member(base, gallivm, context_ptr, \
image_unit, _index, #_name, _emit_load ); \
}
LP_LLVM_IMAGE_MEMBER(width, LP_JIT_IMAGE_WIDTH, TRUE)
LP_LLVM_IMAGE_MEMBER(height, LP_JIT_IMAGE_HEIGHT, TRUE)
LP_LLVM_IMAGE_MEMBER(depth, LP_JIT_IMAGE_DEPTH, TRUE)
LP_LLVM_IMAGE_MEMBER(base_ptr, LP_JIT_IMAGE_BASE, TRUE)
LP_LLVM_IMAGE_MEMBER(row_stride, LP_JIT_IMAGE_ROW_STRIDE, TRUE)
LP_LLVM_IMAGE_MEMBER(img_stride, LP_JIT_IMAGE_IMG_STRIDE, TRUE)
#if LP_USE_TEXTURE_CACHE
static LLVMValueRef
lp_llvm_texture_cache_ptr(const struct lp_sampler_dynamic_state *base,
@ -324,3 +415,66 @@ lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state)
return &sampler->base;
}
static void
lp_llvm_image_soa_destroy(struct lp_build_image_soa *image)
{
FREE(image);
}
static void
lp_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
struct gallivm_state *gallivm,
const struct lp_img_params *params)
{
struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
unsigned image_index = params->image_index;
assert(image_index < PIPE_MAX_SHADER_IMAGES);
lp_build_img_op_soa(&image->dynamic_state.static_state[image_index].image_state,
&image->dynamic_state.base,
gallivm, params);
}
/**
* Fetch the texture size.
*/
static void
lp_llvm_image_soa_emit_size_query(const struct lp_build_image_soa *base,
struct gallivm_state *gallivm,
const struct lp_sampler_size_query_params *params)
{
struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
assert(params->texture_unit < PIPE_MAX_SHADER_IMAGES);
lp_build_size_query_soa(gallivm,
&image->dynamic_state.static_state[params->texture_unit].image_state,
&image->dynamic_state.base,
params);
}
struct lp_build_image_soa *
lp_llvm_image_soa_create(const struct lp_image_static_state *static_state)
{
struct lp_llvm_image_soa *image;
image = CALLOC_STRUCT(lp_llvm_image_soa);
if (!image)
return NULL;
image->base.destroy = lp_llvm_image_soa_destroy;
image->base.emit_op = lp_llvm_image_soa_emit_op;
image->base.emit_size_query = lp_llvm_image_soa_emit_size_query;
image->dynamic_state.base.width = lp_llvm_image_width;
image->dynamic_state.base.height = lp_llvm_image_height;
image->dynamic_state.base.depth = lp_llvm_image_depth;
image->dynamic_state.base.base_ptr = lp_llvm_image_base_ptr;
image->dynamic_state.base.row_stride = lp_llvm_image_row_stride;
image->dynamic_state.base.img_stride = lp_llvm_image_img_stride;
image->dynamic_state.static_state = static_state;
return &image->base;
}

View File

@ -33,6 +33,7 @@
struct lp_sampler_static_state;
struct lp_image_static_state;
/**
* Whether texture cache is used for s3tc textures.
@ -46,4 +47,7 @@ struct lp_sampler_static_state;
struct lp_build_sampler_soa *
lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *key);
struct lp_build_image_soa *
lp_llvm_image_soa_create(const struct lp_image_static_state *key);
#endif /* LP_TEX_SAMPLE_H */

View File

@ -647,7 +647,8 @@ llvmpipe_is_resource_referenced( struct pipe_context *pipe,
if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL |
PIPE_BIND_RENDER_TARGET |
PIPE_BIND_SAMPLER_VIEW |
PIPE_BIND_SHADER_BUFFER)))
PIPE_BIND_SHADER_BUFFER |
PIPE_BIND_SHADER_IMAGE)))
return LP_UNREFERENCED;
return lp_setup_is_resource_referenced(llvmpipe->setup, presource);