diff options
Diffstat (limited to 'src/include/libplacebo/shaders.h')
-rw-r--r-- | src/include/libplacebo/shaders.h | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/include/libplacebo/shaders.h b/src/include/libplacebo/shaders.h new file mode 100644 index 0000000..b8046be --- /dev/null +++ b/src/include/libplacebo/shaders.h @@ -0,0 +1,273 @@ +/* + * This file is part of libplacebo. + * + * libplacebo is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libplacebo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBPLACEBO_SHADERS_H_ +#define LIBPLACEBO_SHADERS_H_ + +// This function defines the "direct" interface to libplacebo's GLSL shaders, +// suitable for use in contexts where the user controls GLSL shader compilation +// but wishes to include functions generated by libplacebo as part of their +// own rendering process. This API is normally not used for operation with +// libplacebo's higher-level constructs such as `pl_dispatch` or `pl_renderer`. + +#include <libplacebo/gpu.h> + +PL_API_BEGIN + +// Thread-safety: Unsafe +typedef struct pl_shader_t *pl_shader; + +struct pl_shader_params { + // The `id` represents an abstract identifier for the shader, to avoid + // collisions with other shaders being used as part of the same larger, + // overarching shader. This is relevant for users which want to combine + // multiple `pl_shader` objects together, in which case all `pl_shader` + // objects should have a unique `id`. + uint8_t id; + + // If `gpu` is non-NULL, then this `gpu` will be used to create objects + // such as textures and buffers, or check for required capabilities, for + // operations which depend on either of those. This is fully optional, i.e. + // these GLSL primitives are designed to be used without a dependency on + // `gpu` wherever possible - however, some features may not work, and will + // be disabled even if requested. + pl_gpu gpu; + + // The `index` represents an abstract frame index, which shaders may use + // internally to do things like temporal dithering or seeding PRNGs. If the + // user does not care about temporal dithering/debanding, or wants + // deterministic rendering, this may safely be left as 0. Otherwise, it + // should be incremented by 1 on successive frames. + uint8_t index; + + // If `glsl.version` is nonzero, then this structure will be used to + // determine the effective GLSL mode and capabilities. If `gpu` is also + // set, then this overrides `gpu->glsl`. + struct pl_glsl_version glsl; + + // If this is true, all constants in the shader will be replaced by + // dynamic variables. This is mainly useful to avoid recompilation for + // shaders which expect to have their values change constantly. + bool dynamic_constants; +}; + +#define pl_shader_params(...) (&(struct pl_shader_params) { __VA_ARGS__ }) + +// Creates a new, blank, mutable pl_shader object. +// +// Note: Rather than allocating and destroying many shaders, users are +// encouraged to reuse them (using `pl_shader_reset`) for efficiency. +PL_API pl_shader pl_shader_alloc(pl_log log, const struct pl_shader_params *params); + +// Frees a pl_shader and all resources associated with it. +PL_API void pl_shader_free(pl_shader *sh); + +// Resets a pl_shader to a blank slate, without releasing internal memory. +// If you're going to be re-generating shaders often, this function will let +// you skip the re-allocation overhead. +PL_API void pl_shader_reset(pl_shader sh, const struct pl_shader_params *params); + +// Returns whether or not a shader is in a "failed" state. Trying to modify a +// shader in illegal ways (e.g. signature mismatch) will result in the shader +// being marked as "failed". Since most pl_shader_ operations have a void +// return type, the user can use this function to figure out whether a specific +// shader operation has failed or not. This function is somewhat redundant +// since `pl_shader_finalize` will also return NULL in this case. +PL_API bool pl_shader_is_failed(const pl_shader sh); + +// Returns whether or not a pl_shader needs to be run as a compute shader. This +// will never be the case unless the `pl_glsl_version` this `pl_shader` was +// created using has `compute` support enabled. +PL_API bool pl_shader_is_compute(const pl_shader sh); + +// Returns whether or not the shader has any particular output size +// requirements. Some shaders, in particular those that sample from other +// textures, have specific output size requirements which need to be respected +// by the caller. If this is false, then the shader is compatible with every +// output size. If true, the size requirements are stored into *w and *h. +PL_API bool pl_shader_output_size(const pl_shader sh, int *w, int *h); + +// Indicates the type of signature that is associated with a shader result. +// Every shader result defines a function that may be called by the user, and +// this enum indicates the type of value that this function takes and/or +// returns. +// +// Which signature a shader ends up with depends on the type of operation being +// performed by a shader fragment, as determined by the user's calls. See below +// for more information. +enum pl_shader_sig { + PL_SHADER_SIG_NONE = 0, // no input / void output + 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_SAMPLER, // (gsampler* src_tex, vecN tex_coord) pair, + // specifics depend on how the shader was generated +}; + +// Structure encapsulating information about a shader. This is internally +// refcounted, to allow moving it around without having to create deep copies. +typedef const struct pl_shader_info_t { + // A copy of the parameters used to create the shader. + struct pl_shader_params params; + + // A list of friendly names for the semantic operations being performed by + // this shader, e.g. "color decoding" or "debanding". + const char **steps; + int num_steps; + + // As a convenience, this contains a pretty-printed version of the + // above list, with entries tallied and separated by commas + const char *description; +} *pl_shader_info; + +PL_API pl_shader_info pl_shader_info_ref(pl_shader_info info); +PL_API void pl_shader_info_deref(pl_shader_info *info); + +// Represents a finalized shader fragment. This is not a complete shader, but a +// collection of raw shader text together with description of the input +// attributes, variables and vertices it expects to be available. +struct pl_shader_res { + // Descriptive information about the shader. Note that this reference is + // attached to the shader itself - the user does not need to manually ref + // or deref `info` unless they wish to move it elsewhere. + pl_shader_info info; + + // The shader text, as literal GLSL. This will always be a function + // definition, such that the the function with the indicated name and + // signature may be called by the user. + const char *glsl; + const char *name; + enum pl_shader_sig input; // what the function expects + enum pl_shader_sig output; // what the function returns + + // For compute shaders (pl_shader_is_compute), this indicates the requested + // work group size. Otherwise, both fields are 0. The interpretation of + // these work groups is that they're tiled across the output image. + int compute_group_size[2]; + + // If this pass is a compute shader, this field indicates the shared memory + // size requirements for this shader pass. + size_t compute_shmem; + + // A set of input vertex attributes needed by this shader fragment. + const struct pl_shader_va *vertex_attribs; + int num_vertex_attribs; + + // A set of input variables needed by this shader fragment. + const struct pl_shader_var *variables; + int num_variables; + + // A list of input descriptors needed by this shader fragment, + const struct pl_shader_desc *descriptors; + int num_descriptors; + + // A list of compile-time constants used by this shader fragment. + const struct pl_shader_const *constants; + int num_constants; + + // --- Deprecated fields (see `info`) + struct pl_shader_params params PL_DEPRECATED; + const char **steps PL_DEPRECATED; + int num_steps PL_DEPRECATED; + const char *description PL_DEPRECATED; +}; + +// Represents a vertex attribute. The four values will be bound to the four +// corner vertices respectively, in row-wise order starting from the top left: +// data[0] data[1] +// data[2] data[3] +struct pl_shader_va { + struct pl_vertex_attrib attr; // VA type, excluding `offset` and `location` + const void *data[4]; +}; + +// Represents a bound shared variable / descriptor +struct pl_shader_var { + struct pl_var var; // the underlying variable description + const void *data; // the raw data (as per `pl_var_host_layout`) + bool dynamic; // if true, the value is expected to change frequently +}; + +struct pl_buffer_var { + struct pl_var var; + struct pl_var_layout layout; +}; + +typedef uint16_t pl_memory_qualifiers; +enum { + PL_MEMORY_COHERENT = 1 << 0, // supports synchronization across shader invocations + PL_MEMORY_VOLATILE = 1 << 1, // all writes are synchronized automatically + + // Note: All descriptors are also implicitly assumed to have the 'restrict' + // memory qualifier. There is currently no way to override this behavior. +}; + +struct pl_shader_desc { + struct pl_desc desc; // descriptor type, excluding `int binding` + struct pl_desc_binding binding; // contents of the descriptor binding + + // For PL_DESC_BUF_UNIFORM/STORAGE, this specifies the layout of the + // variables contained by a buffer. Ignored for the other descriptor types + struct pl_buffer_var *buffer_vars; + int num_buffer_vars; + + // For storage images and buffers, this specifies additional memory + // qualifiers on the descriptor. It's highly recommended to always use + // at least PL_MEMORY_RESTRICT. Ignored for other descriptor types. + pl_memory_qualifiers memory; +}; + +// Represents a compile-time constant. This can be lowered to a specialization +// constant to support cheaper recompilations. +struct pl_shader_const { + enum pl_var_type type; + const char *name; + const void *data; + + // If true, this constant *must* be a compile-time constant, which + // basically just overrides `pl_shader_params.dynamic_constants`. Useful + // for constants which will serve as inputs to e.g. array sizes. + bool compile_time; +}; + +// Finalize a pl_shader. It is no longer mutable at this point, and any further +// attempts to modify it result in an error. (Functions which take a `const +// pl_shader` argument do not modify the shader and may be freely +// called on an already-finalized shader) +// +// The returned pl_shader_res is bound to the lifetime of the pl_shader - and +// will only remain valid until the pl_shader is freed or reset. This function +// may be called multiple times, and will produce the same result each time. +// +// This function will return NULL if the shader is considered to be in a +// "failed" state (see pl_shader_is_failed). +PL_API const struct pl_shader_res *pl_shader_finalize(pl_shader sh); + +// Shader objects represent abstract resources that shaders need to manage in +// order to ensure their operation. This could include shader storage buffers, +// generated lookup textures, or other sorts of configured state. The body +// of a shader object is fully opaque; but the user is in charge of cleaning up +// after them and passing them to the right shader passes. +// +// Note: pl_shader_obj objects must be initialized to NULL by the caller. +typedef struct pl_shader_obj_t *pl_shader_obj; + +PL_API void pl_shader_obj_destroy(pl_shader_obj *obj); + +PL_API_END + +#endif // LIBPLACEBO_SHADERS_H_ |