/usr/include/movit/resource_pool.h is in libmovit-dev 1.6.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | #ifndef _MOVIT_RESOURCE_POOL_H
#define _MOVIT_RESOURCE_POOL_H 1
// A ResourcePool governs resources that are shared between multiple EffectChains;
// in particular, resources that might be expensive to acquire or hold. Thus,
// if you have many EffectChains, hooking them up to the same ResourcePool is
// probably a good idea.
//
// However, hooking an EffectChain to a ResourcePool extends the OpenGL context
// demands (see effect_chain.h) to that of the ResourcePool; all chains must then
// only be used in OpenGL contexts sharing resources with each other. This is
// the reason why there isn't just one global ResourcePool singleton (although
// most practical users will just want one).
//
// Thread-safety: All functions except the constructor and destructor can be
// safely called from multiple threads at the same time, provided they have
// separate (but sharing) OpenGL contexts.
//
// Memory management (only relevant if you use multiple contexts): Some objects,
// like FBOs, are not shareable across contexts, and can only be deleted from
// the context they were created in. Thus, you will need to tell the
// ResourcePool explicitly if you delete a context, or they will leak (and the
// ResourcePool destructor will assert-fail). See clean_context().
#include <epoxy/gl.h>
#include <pthread.h>
#include <stddef.h>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
namespace movit {
class ResourcePool {
public:
// program_freelist_max_length is how many compiled programs that are unused to keep
// around after they are no longer in use (in case another EffectChain
// wants that exact program later). Shaders are expensive to compile and do not
// need a lot of resources to keep around, so this should be a reasonable number.
//
// texture_freelist_max_bytes is how many bytes of unused textures to keep around
// after they are no longer in use (in case a new texture of the same dimensions
// and format is needed). Note that the size estimate is very coarse; it does not
// take into account padding, metadata, and most importantly mipmapping.
// This means you should be prepared for actual memory usage of the freelist being
// twice this estimate or more.
ResourcePool(size_t program_freelist_max_length = 100,
size_t texture_freelist_max_bytes = 100 << 20, // 100 MB.
size_t fbo_freelist_max_length = 100, // Per context.
size_t vao_freelist_max_length = 100); // Per context.
~ResourcePool();
// All remaining functions are intended for calls from EffectChain only.
// Compile the given vertex+fragment shader pair, or fetch an already
// compiled program from the cache if possible. Keeps ownership of the
// program; you must call release_glsl_program() instead of deleting it
// when you no longer want it.
//
// If <fragment_shader_outputs> contains more than one value, the given
// outputs will be bound to fragment shader output colors in the order
// they appear in the vector. Otherwise, output order is undefined and
// determined by the OpenGL driver.
GLuint compile_glsl_program(const std::string& vertex_shader,
const std::string& fragment_shader,
const std::vector<std::string>& frag_shader_outputs);
void release_glsl_program(GLuint glsl_program_num);
// Same as the previous, but for compile shaders instead. There is currently
// no support for binding multiple outputs.
GLuint compile_glsl_compute_program(const std::string& compile_shader);
void release_glsl_compute_program(GLuint glsl_program_num);
// Since uniforms belong to the program and not to the context,
// a given GLSL program number can't be used by more than one thread
// at a time. Thus, if two threads want to use the same program
// (usually because two EffectChains share them via caching),
// we will need to make a clone. use_glsl_program() makes such
// a clone if needed, calls glUseProgram(), and returns the real
// program number that was used; this must be given to
// unuse_glsl_program() to release it. unuse_glsl_program() does not
// actually change any OpenGL state, though.
GLuint use_glsl_program(GLuint glsl_program_num);
void unuse_glsl_program(GLuint instance_program_num);
// Allocate a 2D texture of the given internal format and dimensions,
// or fetch a previous used if possible. Unbinds GL_TEXTURE_2D afterwards.
// Keeps ownership of the texture; you must call release_2d_texture() instead
// of deleting it when you no longer want it.
GLuint create_2d_texture(GLint internal_format, GLsizei width, GLsizei height);
void release_2d_texture(GLuint texture_num);
// Allocate an FBO with the the given texture(s) bound as framebuffer attachment(s),
// or fetch a previous used if possible. Unbinds GL_FRAMEBUFFER afterwards.
// Keeps ownership of the FBO; you must call release_fbo() of deleting
// it when you no longer want it.
//
// NOTE: In principle, the FBO doesn't have a resolution or pixel format;
// you can bind almost whatever texture you want to it. However, changing
// textures can have an adverse effect on performance due to validation,
// in particular on NVidia cards. Also, keep in mind that FBOs are not
// shareable across contexts, so you must have the context that's supposed
// to own the FBO current when you create or release it.
GLuint create_fbo(GLuint texture0_num,
GLuint texture1_num = 0,
GLuint texture2_num = 0,
GLuint texture3_num = 0);
void release_fbo(GLuint fbo_num);
// Create a VAO of a very specific form: All the given attribute indices
// are bound to start of the given VBO and contain two-component floats.
// Keeps ownership of the VAO; you must call release_vec2_vao() of deleting
// it when you no longer want it. VAOs are not sharable across contexts.
//
// These are not cached primarily for performance, but rather to work
// around an NVIDIA driver bug where glVertexAttribPointer() is thread-hostile
// (ie., simultaneous GL work in unrelated contexts can cause the driver
// to free() memory that was never malloc()-ed).
GLuint create_vec2_vao(const std::set<GLint> &attribute_indices,
GLuint vbo_num);
void release_vec2_vao(const GLuint vao_num);
// Informs the ResourcePool that the current context is going away soon,
// and that any resources held for it in the freelist should be deleted.
//
// You do not need to do this for the last context; the regular destructor
// will take care of that. This means that if you only ever use one
// thread/context, you never need to call this function.
void clean_context();
private:
// Delete the given program and both its shaders.
void delete_program(GLuint program_num);
// Deletes all FBOs for the given context that belong to deleted textures.
void cleanup_unlinked_fbos(void *context);
// Remove FBOs off the end of the freelist for <context>, until it
// is no more than <max_length> elements long.
void shrink_fbo_freelist(void *context, size_t max_length);
// Same, for VAOs.
void shrink_vao_freelist(void *context, size_t max_length);
// Increment the refcount, or take it off the freelist if it's zero.
void increment_program_refcount(GLuint program_num);
// If debugging is on, output shader to a temporary file, for easier debugging.
void output_debug_shader(const std::string &shader_src, const std::string &suffix);
// For a new program that's not a clone of anything, insert it into the right
// structures: Give it a refcount, and set up the program_masters / program_instances lists.
void add_master_program(GLuint program_num);
// Link the given vertex and fragment shaders into a full GLSL program.
// See compile_glsl_program() for explanation of <fragment_shader_outputs>.
static GLuint link_program(GLuint vs_obj,
GLuint fs_obj,
const std::vector<std::string>& fragment_shader_outputs);
static GLuint link_compute_program(GLuint cs_obj);
// Protects all the other elements in the class.
pthread_mutex_t lock;
size_t program_freelist_max_length, texture_freelist_max_bytes, fbo_freelist_max_length, vao_freelist_max_length;
// A mapping from vertex/fragment shader source strings to compiled program number.
std::map<std::pair<std::string, std::string>, GLuint> programs;
// A mapping from compute shader source string to compiled program number.
std::map<std::string, GLuint> compute_programs;
// A mapping from compiled program number to number of current users.
// Once this reaches zero, the program is taken out of this map and instead
// put on the freelist (after which it may be deleted).
std::map<GLuint, int> program_refcount;
// A mapping from program number to vertex and fragment shaders.
// Contains everything needed to re-link the program.
struct ShaderSpec {
GLuint vs_obj, fs_obj;
std::vector<std::string> fragment_shader_outputs;
};
std::map<GLuint, ShaderSpec> program_shaders;
struct ComputeShaderSpec {
GLuint cs_obj;
};
std::map<GLuint, ComputeShaderSpec> compute_program_shaders;
// For each program, a list of other programs that are exactly like it.
// By default, will only contain the program itself, but due to cloning
// (see use_glsl_program()), may grow. Programs are taken off this list
// while they are in use (by use_glsl_program()).
std::map<GLuint, std::stack<GLuint>> program_instances;
// For each program, the master program that created it
// (inverse of program_instances).
std::map<GLuint, GLuint> program_masters;
// A list of programs that are no longer in use, most recently freed first.
// Once this reaches <program_freelist_max_length>, the last element
// will be deleted.
std::list<GLuint> program_freelist;
struct Texture2D {
GLint internal_format;
GLsizei width, height;
};
// A mapping from texture number to format details. This is filled if the
// texture is given out to a client or on the freelist, but not if it is
// deleted from the freelist.
std::map<GLuint, Texture2D> texture_formats;
// A list of all textures that are release but not freed (most recently freed
// first), and an estimate of their current memory usage. Once
// <texture_freelist_bytes> goes above <texture_freelist_max_bytes>,
// elements are deleted off the end of the list until we are under the limit
// again.
std::list<GLuint> texture_freelist;
size_t texture_freelist_bytes;
static const unsigned num_fbo_attachments = 4;
struct FBO {
GLuint fbo_num;
// GL_INVALID_INDEX means associated to a texture that has since been deleted.
// 0 means the output isn't bound.
GLuint texture_num[num_fbo_attachments];
};
// For each context, a mapping from FBO number to format details. This is
// filled if the FBO is given out to a client or on the freelist, but
// not if it is deleted from the freelist.
std::map<std::pair<void *, GLuint>, FBO> fbo_formats;
typedef std::map<std::pair<void *, GLuint>, FBO>::iterator FBOFormatIterator;
// For each context, a list of all FBOs that are released but not freed
// (most recently freed first). Once this reaches <fbo_freelist_max_length>,
// the last element will be deleted.
//
// We store iterators directly into <fbo_format> for efficiency.
std::map<void *, std::list<FBOFormatIterator>> fbo_freelist;
// Very similar, for VAOs.
struct VAO {
GLuint vao_num;
std::set<GLint> attribute_indices;
GLuint vbo_num;
};
std::map<std::pair<void *, GLuint>, VAO> vao_formats;
typedef std::map<std::pair<void *, GLuint>, VAO>::iterator VAOFormatIterator;
std::map<void *, std::list<VAOFormatIterator>> vao_freelist;
// See the caveats at the constructor.
static size_t estimate_texture_size(const Texture2D &texture_format);
};
} // namespace movit
#endif // !defined(_MOVIT_RESOURCE_POOL_H)
|