blitter: cache blit programs in a hash table

Instead of just caching the fragment shaders and use some tables
cache all shaders and use a hash table.

Related: https://gitlab.freedesktop.org/virgl/virglrenderer/-/issues/125

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-by: Corentin Noël <corentin.noel@collabora.com>.
macos/master
Gert Wollny 3 years ago
parent da47de63a1
commit d3f2c692f9
  1. 172
      src/vrend_blitter.c

@ -29,12 +29,16 @@
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_hash_table.h"
#include "util/u_texture.h"
#include "vrend_shader.h"
#include "vrend_renderer.h"
#include "vrend_blitter.h"
#define XXH_INLINE_ALL
#include "util/xxhash.h"
#define DEST_SWIZZLE_SNIPPET_SIZE 64
#define BLIT_USE_GLES (1 << 0)
@ -57,18 +61,11 @@ struct vrend_blitter_ctx {
GLuint vaoid;
struct util_hash_table *blit_programs;
GLuint vs;
GLuint fs_texfetch_col[PIPE_MAX_TEXTURE_TYPES];
GLuint fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES];
GLuint fs_texfetch_depth_msaa[PIPE_MAX_TEXTURE_TYPES];
GLuint fs_texfetch_col_swizzle;
GLuint fb_id;
// Parameters related to the creation of fs_texfetch_col_swizzle
unsigned fs_texfetch_col_swizzle_nr_samples;
bool fs_texfetch_col_swizzle_has_swizzle;
uint8_t fs_texfetch_col_swizzle_swizzle[4];
unsigned dst_width;
unsigned dst_height;
@ -89,6 +86,18 @@ struct blit_swizzle_and_type {
bool is_array;
};
struct blit_prog_key {
bool is_color: 1;
bool is_msaa: 1;
uint8_t num_samples;
int pipe_tex_target;
struct {
bool has_swizzle;
enum virgl_formats src_format;
uint8_t swizzle[4];
} texcol;
};
static GLint blit_shader_build_and_check(GLenum shader_type, const char *buf)
{
GLint param;
@ -310,26 +319,38 @@ static GLuint blit_build_frag_depth(struct vrend_blitter_ctx *blit_ctx, int tgsi
static GLuint blit_get_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples)
{
assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
GLuint *shader = nr_samples > 0 ? &blit_ctx->fs_texfetch_depth_msaa[pipe_tex_target]
: &blit_ctx->fs_texfetch_depth[pipe_tex_target];
if (!*shader) {
unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
*shader = blit_build_frag_depth(blit_ctx, tgsi_tex, nr_samples > 0);
}
return *shader;
struct blit_prog_key key = {
.is_color = false,
.is_msaa = nr_samples > 0,
.num_samples = nr_samples,
.pipe_tex_target = pipe_tex_target,
};
void *shader = util_hash_table_get(blit_ctx->blit_programs, &key);
GLuint prog_id;
if (shader) {
prog_id = (GLuint)((size_t)(shader) & 0xffffffff);
} else {
prog_id = glCreateProgram();
glAttachShader(prog_id, blit_ctx->vs);
unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, key.num_samples);
GLuint fs_id = blit_build_frag_depth(blit_ctx, tgsi_tex, key.is_msaa);
glAttachShader(prog_id, fs_id);
if(!blit_shader_link_and_check(prog_id))
return 0;
glDeleteShader(fs_id);
util_hash_table_set(blit_ctx->blit_programs, &key, (void *)(size_t)prog_id);
}
return prog_id;
}
static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
int pipe_tex_target,
unsigned nr_samples,
const struct vrend_format_table *src_entry,
const uint8_t swizzle[static 4])
int pipe_tex_target,
unsigned nr_samples,
const struct vrend_format_table *src_entry,
const uint8_t swizzle[static 4])
{
assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
bool needs_swizzle = false;
for (uint i = 0; i < 4; ++i) {
if (swizzle[i] != i) {
@ -338,38 +359,59 @@ static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
}
}
GLuint *shader;
if (needs_swizzle || nr_samples > 1) {
shader = &blit_ctx->fs_texfetch_col_swizzle;
if (*shader &&
(blit_ctx->fs_texfetch_col_swizzle_nr_samples != nr_samples ||
blit_ctx->fs_texfetch_col_swizzle_has_swizzle != needs_swizzle ||
(needs_swizzle && memcmp(blit_ctx->fs_texfetch_col_swizzle_swizzle, swizzle, 4)))) {
glDeleteShader(*shader);
*shader = 0;
}
blit_ctx->fs_texfetch_col_swizzle_has_swizzle = needs_swizzle;
if (needs_swizzle)
memcpy(blit_ctx->fs_texfetch_col_swizzle_swizzle, swizzle, 4);
blit_ctx->fs_texfetch_col_swizzle_nr_samples = nr_samples;
} else {
shader = &blit_ctx->fs_texfetch_col[pipe_tex_target];
}
struct blit_prog_key key = {
.is_color = true,
.is_msaa = nr_samples > 0,
.num_samples = nr_samples,
.pipe_tex_target = pipe_tex_target
};
if (!*shader) {
key.texcol.src_format = src_entry->format;
key.texcol.has_swizzle = needs_swizzle;
if (key.texcol.has_swizzle)
memcpy(key.texcol.swizzle, swizzle, 4);
unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
enum tgsi_return_type tgsi_ret = tgsi_ret_for_format(src_entry->format);
GLuint prog_id = 0;
void *shader = util_hash_table_get(blit_ctx->blit_programs, &key);
// Integer textures are resolved using just one sample
if (shader) {
prog_id = (GLuint)((size_t)(shader) & 0xffffffff);
} else {
prog_id = glCreateProgram();
glAttachShader(prog_id, blit_ctx->vs);
unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, key.num_samples);
enum tgsi_return_type tgsi_ret = tgsi_ret_for_format(src_entry->format);
int msaa_samples = nr_samples > 0 ? (tgsi_ret == TGSI_RETURN_TYPE_UNORM ? nr_samples : 1) : 0;
*shader = blit_build_frag_tex_col(blit_ctx, tgsi_tex, tgsi_ret,
swizzle, msaa_samples);
GLuint fs_id = blit_build_frag_tex_col(blit_ctx, tgsi_tex, tgsi_ret, swizzle, msaa_samples);
glAttachShader(prog_id, fs_id);
if(!blit_shader_link_and_check(prog_id))
return 0;
glDeleteShader(fs_id);
util_hash_table_set(blit_ctx->blit_programs, &key, (void *)(size_t)prog_id);
}
return *shader;
return prog_id;
}
static uint32_t program_hash_func(void *key)
{
return XXH32(key, sizeof(struct blit_prog_key), 0);
}
static int program_comp_func(void *key1, void *key2)
{
return memcmp(key1, key2, sizeof(struct blit_prog_key));
}
static void program_destroy_func(void *shader_id)
{
GLuint id = ((uint64_t)(shader_id)) & 0xffffffff;
glDeleteProgram(id);
}
static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
{
struct virgl_gl_ctx_param ctx_params;
@ -379,7 +421,10 @@ static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
return;
}
blit_ctx->initialised = true;
vrend_blit_ctx.blit_programs = util_hash_table_create(program_hash_func,
program_comp_func,
program_destroy_func);
blit_ctx->use_gles = epoxy_is_desktop_gl() == 0;
ctx_params.shared = true;
for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
@ -409,6 +454,8 @@ static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
if (!blit_ctx->use_gles)
glEnable(GL_FRAMEBUFFER_SRGB);
blit_ctx->initialised = true;
}
static void blitter_set_rectangle(struct vrend_blitter_ctx *blit_ctx,
@ -700,7 +747,6 @@ void vrend_renderer_blit_gl(ASSERTED struct vrend_context *ctx,
const struct vrend_blit_info *info)
{
struct vrend_blitter_ctx *blit_ctx = &vrend_blit_ctx;
GLuint fs_id;
int dst_z;
struct blit_point src0, src1;
@ -717,24 +763,23 @@ void vrend_renderer_blit_gl(ASSERTED struct vrend_context *ctx,
vrend_renderer_init_blit_ctx(blit_ctx);
blitter_set_points(blit_ctx, &info->b, src_res, dst_res, &src0, &src1);
GLuint prog_id = glCreateProgram();
glAttachShader(prog_id, blit_ctx->vs);
GLuint prog_id;
if (blit_depth) {
fs_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target,
src_res->base.nr_samples);
prog_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target,
src_res->base.nr_samples);
} else {
VREND_DEBUG(dbg_blit, ctx, "BLIT: applying swizzle during blit: (%d %d %d %d)\n",
info->swizzle[0], info->swizzle[1], info->swizzle[2], info->swizzle[3]);
fs_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target,
src_res->base.nr_samples,
orig_src_entry,
info->swizzle);
prog_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target,
src_res->base.nr_samples,
orig_src_entry,
info->swizzle);
}
glAttachShader(prog_id, fs_id);
if(!blit_shader_link_and_check(prog_id))
if (!prog_id) {
vrend_printf("Blitter: unable to create or find shader program\n");
return;
}
glUseProgram(prog_id);
@ -789,7 +834,6 @@ void vrend_renderer_blit_gl(ASSERTED struct vrend_context *ctx,
}
glUseProgram(0);
glDeleteProgram(prog_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@ -801,5 +845,7 @@ void vrend_blitter_fini(void)
{
vrend_blit_ctx.initialised = false;
vrend_clicbs->destroy_gl_context(vrend_blit_ctx.gl_context);
if (vrend_blit_ctx.blit_programs)
util_hash_table_destroy(vrend_blit_ctx.blit_programs);
memset(&vrend_blit_ctx, 0, sizeof(vrend_blit_ctx));
}

Loading…
Cancel
Save