Commit bacc24a0 authored by Niklas Haas's avatar Niklas Haas

shaders/sampling: generalize PL_SHADER_SIG_SAMPLER2D

This allows us to accept sampler types other than sampler2D. In
principle, any sampler type is supported, but due to shaders/sampling
being the only user of this API, we can restrict ourselves to only 2D
samplers in the implementation. Notably, though, we also support e.g.
PL_SAMPLER_RECT.
parent 663c8cb3
Pipeline #18073 passed with stages
in 7 minutes and 22 seconds
......@@ -2,7 +2,7 @@ project('libplacebo', ['c', 'cpp'],
license: 'LGPL2.1+',
default_options: ['c_std=c99', 'cpp_std=c++11', 'warning_level=2'],
meson_version: '>=0.49',
version: '2.71.0',
version: '2.72.0',
)
# Version number
......
......@@ -120,7 +120,8 @@ enum pl_shader_sig {
PL_SHADER_SIG_COLOR, // vec4 color (normalized so that 1.0 is the ref white)
// The following are only valid as input signatures:
PL_SHADER_SIG_SAMPLER2D, // (sampler2D src_tex, vec2 tex_coord) pair
PL_SHADER_SIG_SAMPLER, // (gsampler* src_tex, vecN tex_coord) pair,
// specifics depend on how the shader was generated
};
// Represents a finalized shader fragment. This is not a complete shader, but a
......
......@@ -40,10 +40,12 @@ struct pl_sample_src {
// 2. Have the shader take it as an argument. Doing this requires
// specifying the missing metadata of the texture backing the sampler, so
// that the shader generation can generate the correct code. In particular,
// the important fields include the texture dimensions and the sample mode.
struct pl_tex_params sampler_params;
float sampled_w, sampled_h; // dimensions of the sampled region (optional)
// that the shader generation can generate the correct code.
int tex_w, tex_h; // dimensions of the actual texture
enum pl_fmt_type format; // format of the sampler being accepted
enum pl_sampler_type sampler; // type of the sampler being accepted
enum pl_tex_sample_mode mode; // sample mode of the sampler being accepted
float sampled_w, sampled_h; // dimensions of the sampled region (optional)
// Common metadata for both sampler input types:
int components; // number of components to sample (optional)
......
......@@ -371,9 +371,8 @@ void pl_shader_append_bstr(struct pl_shader *sh, enum pl_shader_buf buf,
}
static const char *insigs[] = {
[PL_SHADER_SIG_NONE] = "",
[PL_SHADER_SIG_COLOR] = "vec4 color",
[PL_SHADER_SIG_SAMPLER2D] = "sampler2D src_tex, vec2 tex_coord",
[PL_SHADER_SIG_NONE] = "",
[PL_SHADER_SIG_COLOR] = "vec4 color",
};
static const char *outsigs[] = {
......@@ -386,6 +385,13 @@ static const char *retvals[] = {
[PL_SHADER_SIG_COLOR] = "return color;",
};
// libplacebo currently only allows 2D samplers for shader signatures
static const char *samplers2D[] = {
[PL_SAMPLER_NORMAL] = "sampler2D",
[PL_SAMPLER_RECT] = "sampler2DRect",
[PL_SAMPLER_EXTERNAL] = "samplerExternalOES",
};
ident_t sh_subpass(struct pl_shader *sh, const struct pl_shader *sub)
{
pl_assert(sh->mutable);
......@@ -428,7 +434,14 @@ ident_t sh_subpass(struct pl_shader *sh, const struct pl_shader *sub)
// Append the body as a new header function
ident_t name = sh_fresh(sh, "sub");
GLSLH("%s %s(%s) {\n", outsigs[sub->res.output], name, insigs[sub->res.input]);
if (sub->res.input == PL_SHADER_SIG_SAMPLER) {
pl_assert(sub->sampler_prefix);
GLSLH("%s %s(%c%s src_tex, vec2 tex_coord) {\n",
outsigs[sub->res.output], name,
sub->sampler_prefix, samplers2D[sub->sampler_type]);
} else {
GLSLH("%s %s(%s) {\n", outsigs[sub->res.output], name, insigs[sub->res.input]);
}
bstr_xappend(sh, &sh->buffers[SH_BUF_HEADER], sub->buffers[SH_BUF_BODY]);
GLSLH("%s\n}\n\n", retvals[sub->res.output]);
......@@ -450,7 +463,14 @@ static ident_t sh_split(struct pl_shader *sh)
// Concatenate the body onto the head as a new function
ident_t name = sh_fresh(sh, "main");
GLSLH("%s %s(%s) {\n", outsigs[sh->res.output], name, insigs[sh->res.input]);
if (sh->res.input == PL_SHADER_SIG_SAMPLER) {
pl_assert(sh->sampler_prefix);
GLSLH("%s %s(%c%s src_tex, vec2 tex_coord) {\n",
outsigs[sh->res.output], name,
sh->sampler_prefix, samplers2D[sh->sampler_type]);
} else {
GLSLH("%s %s(%s) {\n", outsigs[sh->res.output], name, insigs[sh->res.input]);
}
if (sh->buffers[SH_BUF_BODY].len) {
bstr_xappend(sh, &sh->buffers[SH_BUF_HEADER], sh->buffers[SH_BUF_BODY]);
......
......@@ -47,6 +47,8 @@ struct pl_shader {
struct bstr buffers[SH_BUF_COUNT];
bool is_compute;
bool flexible_work_groups;
enum pl_sampler_type sampler_type;
char sampler_prefix;
int fresh;
// mutable versions of the fields from pl_shader_res
......
......@@ -27,7 +27,14 @@ const struct pl_deband_params pl_deband_default_params = {
static inline struct pl_tex_params src_params(const struct pl_sample_src *src)
{
return src->tex ? src->tex->params : src->sampler_params;
if (src->tex)
return src->tex->params;
return (struct pl_tex_params) {
.w = src->tex_w,
.h = src->tex_h,
.sample_mode = src->mode,
};
}
// Helper function to compute the src/dst sizes and upscaling ratios
......@@ -36,16 +43,16 @@ static bool setup_src(struct pl_shader *sh, const struct pl_sample_src *src,
float *ratio_x, float *ratio_y, int *components,
float *scale, bool resizeable, const char **fn)
{
pl_assert(pl_tex_params_dimension(src_params(src)) == 2);
enum pl_shader_sig sig;
float src_w, src_h;
if (src->tex) {
pl_assert(pl_tex_params_dimension(src->tex->params) == 2);
sig = PL_SHADER_SIG_NONE;
src_w = pl_rect_w(src->rect);
src_h = pl_rect_h(src->rect);
} else {
sig = PL_SHADER_SIG_SAMPLER2D;
pl_assert(src->tex_w && src->tex_h);
sig = PL_SHADER_SIG_SAMPLER;
src_w = src->sampled_w;
src_h = src->sampled_h;
}
......@@ -66,7 +73,9 @@ static bool setup_src(struct pl_shader *sh, const struct pl_sample_src *src,
*scale = PL_DEF(src->scale, 1.0);
if (components) {
int tex_comps = src_params(src).format->num_components;
int tex_comps = 4;
if (src->tex)
tex_comps = src->tex->params.format->num_components;
*components = PL_DEF(src->components, tex_comps);
}
......@@ -88,26 +97,38 @@ static bool setup_src(struct pl_shader *sh, const struct pl_sample_src *src,
*src_tex = sh_bind(sh, src->tex, "src_tex", &rect, pos, size, pt);
} else {
int tex_w = src->sampler_params.w,
tex_h = src->sampler_params.h;
pl_assert(tex_w && tex_h);
if (size) {
*size = sh_var(sh, (struct pl_shader_var) {
.var = pl_var_vec2("tex_size"),
.data = &(float[2]) { tex_w, tex_h },
.data = &(float[2]) { src->tex_w, src->tex_h },
});
}
if (pt) {
float sx = 1.0 / src->tex_w, sy = 1.0 / src->tex_h;
if (src->sampler == PL_SAMPLER_RECT)
sx = sy = 1.0;
*pt = sh_var(sh, (struct pl_shader_var) {
.var = pl_var_vec2("tex_pt"),
.data = &(float[2]) { 1.0 / tex_w, 1.0 / tex_h },
.data = &(float[2]) { sx, sy },
});
}
if (fn)
*fn = sh_tex_fn(sh, src->sampler_params);
*fn = sh_tex_fn(sh, (struct pl_tex_params) { .w = 1, .d = 1 }); // 2D
sh->sampler_type = src->sampler;
pl_assert(src->format);
switch (src->format) {
case PL_FMT_FLOAT:
case PL_FMT_UNORM:
case PL_FMT_SNORM: sh->sampler_prefix = ' '; break;
case PL_FMT_UINT: sh->sampler_prefix = 'u'; break;
case PL_FMT_SINT: sh->sampler_prefix = 's'; break;
default: abort();
}
*src_tex = "src_tex";
*pos = "tex_coord";
......
......@@ -49,13 +49,17 @@ int main()
}
// Try out generation of the sampler2D interface
src.sampler_params = dummy->params;
src.tex = NULL;
src.tex_w = 100;
src.tex_h = 100;
src.format = PL_FMT_UNORM;
src.sampler = PL_SAMPLER_NORMAL;
src.mode = PL_TEX_SAMPLE_LINEAR;
pl_shader_reset(sh, &(struct pl_shader_params) { .gpu = gpu });
REQUIRE(pl_shader_sample_polar(sh, &src, &filter_params));
REQUIRE((res = pl_shader_finalize(sh)));
REQUIRE(res->input == PL_SHADER_SIG_SAMPLER2D);
REQUIRE(res->input == PL_SHADER_SIG_SAMPLER);
printf("generated sampler2D shader:\n\n%s\n", res->glsl);
pl_shader_free(&sh);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment