diff options
Diffstat (limited to 'media/mca/filterfw/native/core/shader_program.h')
-rw-r--r-- | media/mca/filterfw/native/core/shader_program.h | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/media/mca/filterfw/native/core/shader_program.h b/media/mca/filterfw/native/core/shader_program.h new file mode 100644 index 0000000..2063175 --- /dev/null +++ b/media/mca/filterfw/native/core/shader_program.h @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_FILTERFW_CORE_SHADER_PROGRAM_H +#define ANDROID_FILTERFW_CORE_SHADER_PROGRAM_H + +#include <vector> +#include <map> +#include <string> + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <EGL/egl.h> + +#include "core/gl_env.h" +#include "core/value.h" + +namespace android { +namespace filterfw { + +class GLFrame; +class GLFrameBufferHandle; +class GLTextureHandle; +class Quad; +class VertexFrame; + +typedef GLint ProgramVar; + +// A ShaderProgram is a Program object that holds a GLSL shader implementation. +// It provides functionality for compiling, linking, and executing the shader. +// On top of that, it provides access to the shaders source code, uniforms, +// attributes, and other properties. +// By default a ShaderProgram provides its own vertex shader. However, a custom +// vertex shader may be passed and used instead. +// When implementing a vertex shader, the following attribute names have special +// meaning: +// +// - a_position: The vertex position +// - a_texcoord: The texture cooridnates +// +// The shader program will bind these attributes to the correct values, if they +// are present in the vertex shader source code. +// +// When implementing the fragment shader, the following variable names must be +// defined: +// +// - tex_sampler_<n>: The n'th input texture. For instance, use tex_sampler_0 +// for the first input texture. Must be a uniform sampler2D. +// - v_texcoord: The current texture coordinate. +// +// If more input textures are given than the shader can handle, this will result +// in an error. +// +class ShaderProgram { + public: + // General Functionality /////////////////////////////////////////////////// + // Create a new shader program with the given fragment shader source code. + // A default vertex shader is used, which renders the input texture to a + // rectangular region of the output texture. You can modify the input and + // output regions by using the SetSourceRegion(...) and SetTargetRegion(...) + // (and related) functions below. + // This program will not be executable until you have compiled and linked + // it. + // Note, that the ShaderProgram does NOT take ownership of the GLEnv. The + // caller must make sure the GLEnv stays valid as long as the GLFrame is + // alive. + explicit ShaderProgram(GLEnv* gl_env, const std::string& fragment_shader); + + // Create a new shader program with the given fragment and vertex shader + // source code. This program will not be executable until you have compiled + // and linked it. + // Note, that the ShaderProgram does NOT take ownership of the GLEnv. The + // caller must make sure the GLEnv stays valid as long as the GLFrame is + // alive. + ShaderProgram(GLEnv* gl_env, + const std::string& vertex_shader, + const std::string& fragment_shader); + + // Destructor. + ~ShaderProgram(); + + // Process the given input frames and write the result to the output frame. + // Returns false if there was an error processing. + bool Process(const std::vector<const GLFrame*>& inputs, GLFrame* output); + + // Same as above, but pass GL interfaces rather than frame objects. Use this + // only if you are not working on Frame objects, but rather directly on GL + // textures and FBOs. + bool Process(const std::vector<const GLTextureHandle*>& input, + GLFrameBufferHandle* output); + + // Compile and link the shader source code. Returns true if compilation + // and linkage was successful. Compilation and linking error messages are + // written to the error log. + bool CompileAndLink(); + + // Returns true if this Program has been compiled and linked successfully. + bool IsExecutable() const { + return program_ != 0; + } + + // Returns true if the shader program variable is valid. + static bool IsVarValid(ProgramVar var); + + // Special ShaderPrograms ////////////////////////////////////////////////// + // A (compiled) shader program which assigns the sampled pixels from the + // input to the output. Note that transformations may be applied to achieve + // effects such as cropping, scaling or rotation. + // The caller takes ownership of the result! + static ShaderProgram* CreateIdentity(GLEnv* env); + + // Geometry //////////////////////////////////////////////////////////////// + // These functions modify the source and target regions used during + // rasterization. Note, that these functions will ONLY take effect if + // the default vertex shader is used, or your custom vertex shader defines + // the a_position and a_texcoord attributes. + + // Set the program to read from a subregion of the input frame, given by + // the origin (x, y) and dimensions (width, height). Values are considered + // normalized between 0.0 and 1.0. If this region exceeds the input frame + // dimensions the results are undefined. + void SetSourceRect(float x, float y, float width, float height) ; + + // Set the program to read from a subregion of the input frame, given by + // the passed Quad. Values are considered normalized between 0.0 and 1.0. + // The Quad points are expected to be in the order top-left, top-right, + // bottom-left, bottom-right. + // If this region exceeds the input frame dimensions the results are + // undefined. + void SetSourceRegion(const Quad& quad); + + // Set the program to write to a subregion of the output frame, given by + // the origin (x, y) and dimensions (width, height). Values are considered + // normalized between 0.0 and 1.0. If this region exceeds the output frame + // dimensions the image will be clipped. + void SetTargetRect(float x, float y, float width, float height); + + // Set the program to write to a subregion of the output frame, given by + // the passed Quad. Values are considered normalized between 0.0 and 1.0. + // The Quad points are expected to be in the order top-left, top-right, + // bottom-left, bottom-right. + // If this region exceeds the output frame dimensions the image will be + // clipped. + void SetTargetRegion(const Quad& quad); + + // Uniform Variable access ///////////////////////////////////////////////// + // Note: In order to get and set uniforms, the program must have been + // successfully compiled and linked. Otherwise, the getters will return an + // invalid ProgramVar variable (check with IsVarValid()). + // When setting values, the value type must be match the type of the uniform + // in the shader. For instance, a vector of 3 elements cannot be assigned to + // a vec2. Similarly, an integer value cannot be assigned to a float value. + // Such a type mismatch will result in failure to set the value (which will + // remain untouched). Check the return value of the setters to determine + // success. + + // Returns the maximum number of uniforms supported by this implementation. + static int MaxUniformCount(); + + // Returns a handle to the uniform with the given name, or invalid if no + // such uniform variable exists in the shader. + ProgramVar GetUniform(const std::string& name) const; + + // Set the specified uniform value to the given integer value. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, int value); + + // Set the specified uniform value to the given float value. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, float value); + + // Set the specified uniform value to the given values. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, const int* values, int count); + + // Set the specified uniform value to the given values. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, const float* values, int count); + + // Set the specified uniform value to the given vector value. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, const std::vector<int>& values); + + // Set the specified uniform value to the given vector value. Returns true + // if the assignment was successful. + bool SetUniformValue(ProgramVar var, const std::vector<float>& values); + + // Generic variable setter, which in the case of GL programs always attempts + // to set the value of a uniform variable with the given name. Only values + // of type float, float array (or vector), and int are supported. + bool SetUniformValue(const std::string& name, const Value& value); + + // Generic variable getter, which in the case of GL programs always attempts + // to get the value of a uniform variable with the given name. + Value GetUniformValue(const std::string& name); + + // Returns the default name of the input texture uniform variable for the + // given input index. + static std::string InputTextureUniformName(int index); + + // Attribute access //////////////////////////////////////////////////////// + // Note: In order to get and set attributes, the program must have been + // successfully compiled and linked. Otherwise, the getters will return an + // invalid ProgramVar variable (check with IsVarValid()). Constant attribute + // values must be floats. Attribute pointers must be associated with a + // specific type, which can be any of the following: + // GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT, + // GL_FIXED, GL_HALF_FLOAT_OES. + // When storing vertex data, it is recommended to use VertexFrames when + // possible as these will be kept in GPU memory, and no copying of vertex + // attributes between system and GPU memory needs to take place. + + // Returns the maximum number of attributes supported by this + // implementation. + static int MaxAttributeCount(); + + // Returns a handle to the attribute with the given name, or invalid if no + // such attribute exists in the vertex shader. + ProgramVar GetAttribute(const std::string& name) const; + + // Set an attribute value that will be constant for each vertex. Returns + // true if the assignment was successful. + bool SetConstAttributeValue(ProgramVar var, float value); + + // Set an attribute vector value that will be constant for each vertex. + // Returns true if the assignment was successful. + bool SetConstAttributeValue(ProgramVar var, const std::vector<float>& value); + + // Set attribute values that differ across vertexes, using a VertexFrame. + // This is the recommended method of specifying vertex data, that does not + // change from iteration to iteration. The parameters are as follows: + // var: The shader variable to bind the values to. + // data: The vertex frame which holds the vertex data. This may be a + // superset of the data required for this particular vertex. Use the + // offset and stride to select the correct data portion. + // type: The type of the data values. This may differ from the type of the + // shader variables. See the normalize flag on how values are + // converted. + // components: The number of components per value. Valid values are 1-4. + // stride: The delta of one element to the next in bytes. + // offset: The offset of the first element. + // normalize: True, if not float values should be normalized to the range + // 0-1, when converted to a float. + // Returns true, if the assignment was successful. + bool SetAttributeValues(ProgramVar var, + const VertexFrame* data, + GLenum type, + int components, + int stride, + int offset, + bool normalize); + + // Set attribute values that differ across vertexes, using a data buffer. + // This is the recommended method of specifying vertex data, if your data + // changes often. Note that this data may need to be copied to GPU memory + // for each render pass. Please see above for a description of the + // parameters. + // Note: The data passed here MUST be valid until all executions of this + // Program instance have been completed! + bool SetAttributeValues(ProgramVar var, + const uint8_t* data, + GLenum type, + int components, + int stride, + int offset, + bool normalize); + + // Convenience method for setting vertex values using a vector of floats. + // The components parameter specifies how many elements per variable should + // be assigned (The variable must be able to fit the number of components). + // It must be a value between 1 and 4. + // While this method is not as flexible as the methods above, this can be + // used when more advanced methods are not necessary. Note, that if your + // vertex data does not change, it is recommended to use a VertexFrame. + bool SetAttributeValues(ProgramVar var, + const std::vector<float>& data, + int components); + + // Same as above, but using a float pointer instead of vector. Pass the + // total number of elements in total. + bool SetAttributeValues(ProgramVar var, + const float* data, + int total, + int components); + + // By default, rendering only uses the first 4 vertices. You should only + // adjust this value if you are providing your own vertex attributes with + // a count unequal to 4. Adjust this value before calling Process(). + void SetVertexCount(int count); + + // Returns the default name of the attribute used to hold the texture + // coordinates. Use this when you need to access the texture coordinate + // attribute of the shader's default vertex shader. + static const std::string& TexCoordAttributeName() { + static std::string s_texcoord("a_texcoord"); + return s_texcoord; + } + + // Returns the default name of the attribute used to hold the output + // coordinates. Use this when you need to access the output coordinate + // attribute of the shader's default vertex shader. + static const std::string& PositionAttributeName() { + static std::string s_position("a_position"); + return s_position; + } + + // Rendering /////////////////////////////////////////////////////////////// + // Set the draw mode, which can be any of GL_POINTS, GL_LINES, + // GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, + // GL_TRIANGLE_FAN. The default is GL_TRIANGLE_STRIP. + // Warning: Do NOT change this if you are not specifying your own vertex + // data with SetAttributeValues(...). + void SetDrawMode(GLenum mode); + + // If you are doing your own drawing you should call this before beginning + // to draw. This will activate the program, push all used attributes, and + // clear the frame if requested. You do not need to call this if you are + // not doing your own GL drawing! + bool BeginDraw(); + + // Render a single frame with the given input textures. You may override + // this, if you need custom rendering behavior. However, you must take + // care of the following things when overriding: + // - Use the correct program (e.g. by calling UseProgram()). + // - Bind the given textures + // - Bind vertex attributes + // - Draw + bool RenderFrame(const std::vector<GLuint>& textures, + const std::vector<GLenum>& targets); + + // Pass true to clear the output frame before rendering. The color used + // to clear is set in SetClearColor(). + void SetClearsOutput(bool clears); + + // Set the color used to clear the output frame before rendering. You + // must activate clearing by calling SetClearsOutput(true). + void SetClearColor(float red, float green, float blue, float alpha); + + // Set the number of tiles to split rendering into. Higher tile numbers + // will affect performance negatively, but will allow other GPU threads + // to render more frequently. Defaults to 1, 1. + void SetTileCounts(int x_count, int y_count); + + // Enable or Disable Blending + // Set to true to enable, false to disable. + void SetBlendEnabled(bool enable) { + blending_ = enable; + } + + // Specify pixel arithmetic for blending + // The values of sfactor and dfactor can be: + // GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, + // GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, + // GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA_SATURATE + // Default values for blending are set to: + // sfactor = GL_SRC_ALPHA + // dfactor = GL_ONE_MINUS_SRC_ALPHA + void SetBlendFunc(int sfactor, int dfactor) { + sfactor_ = sfactor; + dfactor_ = dfactor; + } + + // Accessing the Compiled Program ////////////////////////////////////////// + // Use the compiled and linked program for rendering. You should not need + // to call this, unless you are implementing your own rendering method. + bool UseProgram(); + + // Other Properties //////////////////////////////////////////////////////// + // Returns the maximum number of varyings supported by this implementation. + static int MaxVaryingCount(); + + // Returns the maximum number of texture units supported by this + // implementation. + static int MaxTextureUnits(); + + // Lower level functionality /////////////////////////////////////////////// + // Compile the shader with the given source. The shader_type must be either + // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. + static GLuint CompileShader(GLenum shader_type, const char* source); + + // Link the compiled shader objects and return the resulting program. + static GLuint LinkProgram(GLuint* shaders, GLuint count); + + // Returns the lowest texture unit that will be used to bind textures. + GLuint BaseTextureUnit() const { + return base_texture_unit_; + } + + // Sets the lowest texture unit that will be used to bind textures. The + // default value is GL_TEXTURE0. + void SetBaseTextureUnit(GLuint texture_unit) { + base_texture_unit_ = texture_unit; + } + + private: + // Structure to store vertex attribute data. + struct VertexAttrib { + bool is_const; + int index; + bool normalized; + int stride; + int components; + int offset; + GLenum type; + GLuint vbo; + const void* values; + float* owned_data; + + VertexAttrib(); + }; + typedef std::map<ProgramVar, VertexAttrib> VertexAttribMap; + + struct RGBAColor { + float red; + float green; + float blue; + float alpha; + + RGBAColor() : red(0), green(0), blue(0), alpha(1) { + } + }; + + // Scans for all uniforms in the shader and creates index -> id map. + void ScanUniforms(); + + // Returns the index of the given uniform. The caller must make sure + // that the variable id passed is valid. + GLuint IndexOfUniform(ProgramVar var); + + // Binds the given input textures. + bool BindInputTextures(const std::vector<GLuint>& textures, + const std::vector<GLenum>& targets); + + // Sets the default source and target coordinates. + void SetDefaultCoords(); + + // Pushes the specified coordinates to the shader attribute. + bool PushCoords(ProgramVar attr, float* coords); + + // Pushes the source coordinates. + bool PushSourceCoords(float* coords); + + // Pushes the target coordinates. + bool PushTargetCoords(float* coords); + + // Performs (simple) GL drawing. + bool Draw(); + + // Performs tiled GL drawing. + bool DrawTiled(); + + // Yields to other GPU threads. + void Yield(); + + // Helper method to assert that the variable value passed has the correct + // total size. + static bool CheckValueCount(const std::string& var_type, + const std::string& var_name, + int expected_count, + int components, + int value_size); + + // Helper method to assert that the variable value passed has a size, that + // is compatible with the type size (must be divisible). + static bool CheckValueMult(const std::string& var_type, + const std::string& var_name, + int components, + int value_size); + + // Checks that the variable is valid. Logs an error and returns false if + // not. + static bool CheckVarValid(ProgramVar var); + + // Returns true if the uniform specified by var is an active uniform in the + // program. + bool CheckUniformValid(ProgramVar var); + + // Store an attribute to use when rendering. + bool StoreAttribute(VertexAttrib attrib); + + // Push all assigned attributes before rendering. + bool PushAttributes(); + + // Pop all assigned attributes after rendering. + bool PopAttributes(); + + // The shader source code + std::string fragment_shader_source_; + std::string vertex_shader_source_; + + // The compiled shaders and linked program + GLuint fragment_shader_; + GLuint vertex_shader_; + GLuint program_; + + // The GL environment this shader lives in. + GLEnv* gl_env_; + + // The lowest texture unit this program will use + GLuint base_texture_unit_; + + // The current source and target coordinates to render from/to. + float* source_coords_; + float* target_coords_; + + // True, if the program has control over both source and target coordinates. + bool manage_coordinates_; + + // The number of tiles to split rendering into. + int tile_x_count_; + int tile_y_count_; + + // List of attribute data that we need to set before rendering + VertexAttribMap attrib_values_; + + // The number of vertices to render + int vertex_count_; + + // The draw mode used during rendering + GLenum draw_mode_; + + // True, iff the output frame is cleared before rendering + bool clears_; + + // The color used to clear the output frame. + RGBAColor clear_color_; + + // Set to true to enable blending. + bool blending_; + int sfactor_; + int dfactor_; + + // Map from uniform ids to indices + std::map<ProgramVar, GLuint> uniform_indices_; +}; + +} // namespace filterfw +} // namespace android + +#endif // ANDROID_FILTERFW_CORE_SHADER_PROGRAM_H |