aboutsummaryrefslogtreecommitdiff
path: root/tests/glmark2/src/libmatrix/shader-source.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/glmark2/src/libmatrix/shader-source.cc')
-rw-r--r--tests/glmark2/src/libmatrix/shader-source.cc615
1 files changed, 615 insertions, 0 deletions
diff --git a/tests/glmark2/src/libmatrix/shader-source.cc b/tests/glmark2/src/libmatrix/shader-source.cc
new file mode 100644
index 00000000..bf80d21e
--- /dev/null
+++ b/tests/glmark2/src/libmatrix/shader-source.cc
@@ -0,0 +1,615 @@
+//
+// Copyright (c) 2010-2012 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#include <istream>
+#include <memory>
+
+#include "shader-source.h"
+#include "log.h"
+#include "vec.h"
+#include "util.h"
+
+/**
+ * Holds default precision values for all shader types
+ * (even the unknown type, which is hardwired to default precision values)
+ */
+std::vector<ShaderSource::Precision>
+ShaderSource::default_precision_(ShaderSource::ShaderTypeUnknown + 1);
+
+/**
+ * Loads the contents of a file into a string.
+ *
+ * @param filename the name of the file
+ * @param str the string to put the contents of the file into
+ */
+bool
+ShaderSource::load_file(const std::string& filename, std::string& str)
+{
+ std::auto_ptr<std::istream> is_ptr(Util::get_resource(filename));
+ std::istream& inputFile(*is_ptr);
+
+ if (!inputFile)
+ {
+ Log::error("Failed to open \"%s\"\n", filename.c_str());
+ return false;
+ }
+
+ std::string curLine;
+ while (getline(inputFile, curLine))
+ {
+ str += curLine;
+ str += '\n';
+ }
+
+ return true;
+}
+
+
+/**
+ * Appends a string to the shader source.
+ *
+ * @param str the string to append
+ */
+void
+ShaderSource::append(const std::string &str)
+{
+ source_ << str;
+}
+
+/**
+ * Appends the contents of a file to the shader source.
+ *
+ * @param filename the name of the file to append
+ */
+void
+ShaderSource::append_file(const std::string &filename)
+{
+ std::string source;
+ if (load_file(filename, source))
+ source_ << source;
+}
+
+/**
+ * Replaces a string in the source with another string.
+ *
+ * @param remove the string to replace
+ * @param insert the string to replace with
+ */
+void
+ShaderSource::replace(const std::string &remove, const std::string &insert)
+{
+ std::string::size_type pos = 0;
+ std::string str(source_.str());
+
+ while ((pos = str.find(remove, pos)) != std::string::npos) {
+ str.replace(pos, remove.size(), insert);
+ pos++;
+ }
+
+ source_.clear();
+ source_.str(str);
+}
+
+/**
+ * Replaces a string in the source with the contents of a file.
+ *
+ * @param remove the string to replace
+ * @param filename the name of the file to read from
+ */
+void
+ShaderSource::replace_with_file(const std::string &remove, const std::string &filename)
+{
+ std::string source;
+ if (load_file(filename, source))
+ replace(remove, source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) at
+ * global (per shader) scope.
+ *
+ * The string is placed after any default precision qualifiers.
+ *
+ * @param str the string to add
+ */
+void
+ShaderSource::add_global(const std::string &str)
+{
+ std::string::size_type pos = 0;
+ std::string source(source_.str());
+
+ /* Find the last precision qualifier */
+ pos = source.rfind("precision");
+
+ if (pos != std::string::npos) {
+ /*
+ * Find the next #endif line of a preprocessor block that contains
+ * the precision qualifier.
+ */
+ std::string::size_type pos_if = source.find("#if", pos);
+ std::string::size_type pos_endif = source.find("#endif", pos);
+
+ if (pos_endif != std::string::npos && pos_endif < pos_if)
+ pos = pos_endif;
+
+ /* Go to the next line */
+ pos = source.find("\n", pos);
+ if (pos != std::string::npos)
+ pos++;
+ }
+ else
+ pos = 0;
+
+ source.insert(pos, str);
+
+ source_.clear();
+ source_.str(source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) at
+ * global (per shader) scope.
+ *
+ * The string is placed after any default precision qualifiers.
+ *
+ * @param function the function to add the string into
+ * @param str the string to add
+ */
+void
+ShaderSource::add_local(const std::string &str, const std::string &function)
+{
+ std::string::size_type pos = 0;
+ std::string source(source_.str());
+
+ /* Find the function */
+ pos = source.find(function);
+ pos = source.find('{', pos);
+
+ /* Go to the next line */
+ pos = source.find("\n", pos);
+ if (pos != std::string::npos)
+ pos++;
+
+ source.insert(pos, str);
+
+ source_.clear();
+ source_.str(source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) to a shader source
+ *
+ * If the function parameter is empty, the string will be added to global
+ * scope, after any precision definitions.
+ *
+ * @param str the string to add
+ * @param function if not empty, the function to add the string into
+ */
+void
+ShaderSource::add(const std::string &str, const std::string &function)
+{
+ if (!function.empty())
+ add_local(str, function);
+ else
+ add_global(str);
+}
+
+/**
+ * Adds a float constant definition.
+ *
+ * @param name the name of the constant
+ * @param f the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, float f,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const float " << name << " = " << std::fixed << f << ";" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a float array constant definition.
+ *
+ * Note that various GLSL versions (including ES) don't support
+ * array constants.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, std::vector<float> &array,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const float " << name << "[" << array.size() << "] = {" << std::fixed;
+ for(std::vector<float>::const_iterator iter = array.begin();
+ iter != array.end();
+ iter++)
+ {
+ ss << *iter;
+ if (iter + 1 != array.end())
+ ss << ", " << std::endl;
+ }
+
+ ss << "};" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec2 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec2 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec2 " << name << " = vec2(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec3 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec3 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec3 " << name << " = vec3(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ", " << v.z() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec4 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec4 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec4 " << name << " = vec4(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a mat3 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::mat3 &m,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const mat3 " << name << " = mat3(" << std::fixed;
+ ss << m[0][0] << ", " << m[1][0] << ", " << m[2][0] << "," << std::endl;
+ ss << m[0][1] << ", " << m[1][1] << ", " << m[2][1] << "," << std::endl;
+ ss << m[0][2] << ", " << m[1][2] << ", " << m[2][2] << std::endl;
+ ss << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a float array declaration and initialization.
+ *
+ * @param name the name of the array
+ * @param array the array values
+ * @param init_function the function to put the initialization in
+ * @param decl_function if not empty, the function to put the declaration in
+ */
+void
+ShaderSource::add_array(const std::string &name, std::vector<float> &array,
+ const std::string &init_function,
+ const std::string &decl_function)
+{
+ if (init_function.empty() || name.empty())
+ return;
+
+ std::stringstream ss;
+ ss << "float " << name << "[" << array.size() << "];" << std::endl;
+
+ std::string decl(ss.str());
+
+ ss.clear();
+ ss.str("");
+ ss << std::fixed;
+
+ for(std::vector<float>::const_iterator iter = array.begin();
+ iter != array.end();
+ iter++)
+ {
+ ss << name << "[" << iter - array.begin() << "] = " << *iter << ";" << std::endl;
+ }
+
+ add(ss.str(), init_function);
+
+ add(decl, decl_function);
+}
+
+/**
+ * Gets the ShaderType for this ShaderSource.
+ *
+ * If the ShaderType is unknown, an attempt is made to infer
+ * the type from the shader source contents.
+ *
+ * @return the ShaderType
+ */
+ShaderSource::ShaderType
+ShaderSource::type()
+{
+ /* Try to infer the type from the source contents */
+ if (type_ == ShaderSource::ShaderTypeUnknown) {
+ std::string source(source_.str());
+
+ if (source.find("gl_FragColor") != std::string::npos)
+ type_ = ShaderSource::ShaderTypeFragment;
+ else if (source.find("gl_Position") != std::string::npos)
+ type_ = ShaderSource::ShaderTypeVertex;
+ else
+ Log::debug("Cannot infer shader type from contents. Leaving it Unknown.\n");
+ }
+
+ return type_;
+}
+
+/**
+ * Helper function that emits a precision statement.
+ *
+ * @param ss the stringstream to add the statement to
+ * @param val the precision value
+ * @param type_str the variable type to apply the precision value to
+ */
+void
+ShaderSource::emit_precision(std::stringstream& ss, ShaderSource::PrecisionValue val,
+ const std::string& type_str)
+{
+ static const char *precision_map[] = {
+ "lowp", "mediump", "highp", NULL
+ };
+
+ if (val == ShaderSource::PrecisionValueHigh) {
+ if (type_ == ShaderSource::ShaderTypeFragment)
+ ss << "#ifdef GL_FRAGMENT_PRECISION_HIGH" << std::endl;
+
+ ss << "precision highp " << type_str << ";" << std::endl;
+
+ if (type_ == ShaderSource::ShaderTypeFragment) {
+ ss << "#else" << std::endl;
+ ss << "precision mediump " << type_str << ";" << std::endl;
+ ss << "#endif" << std::endl;
+ }
+ }
+ else if (val >= 0 && val < ShaderSource::PrecisionValueDefault) {
+ ss << "precision " << precision_map[val] << " ";
+ ss << type_str << ";" << std::endl;
+ }
+
+ /* There is no default precision in the fragment shader, so set it to mediump */
+ if (val == ShaderSource::PrecisionValueDefault
+ && type_str == "float" && type_ == ShaderSource::ShaderTypeFragment)
+ {
+ ss << "precision mediump float;" << std::endl;
+ }
+}
+
+/**
+ * Gets a string containing the complete shader source.
+ *
+ * Precision statements are applied at this point.
+ *
+ * @return the shader source
+ */
+std::string
+ShaderSource::str()
+{
+ /* Decide which precision values to use */
+ ShaderSource::Precision precision;
+
+ /* Ensure we have tried to infer the type from the contents */
+ type();
+
+ if (precision_has_been_set_)
+ precision = precision_;
+ else
+ precision = default_precision(type_);
+
+ /* Create the precision statements */
+ std::stringstream ss;
+
+ emit_precision(ss, precision.int_precision, "int");
+ emit_precision(ss, precision.float_precision, "float");
+ emit_precision(ss, precision.sampler2d_precision, "sampler2D");
+ emit_precision(ss, precision.samplercube_precision, "samplerCube");
+
+ std::string precision_str(ss.str());
+ if (!precision_str.empty()) {
+ precision_str.insert(0, "#ifdef GL_ES\n");
+ precision_str.insert(precision_str.size(), "#endif\n");
+ }
+
+ return precision_str + source_.str();
+}
+
+/**
+ * Sets the precision that will be used for this shader.
+ *
+ * This overrides any default values set with ShaderSource::default_*_precision().
+ *
+ * @param precision the precision to set
+ */
+void
+ShaderSource::precision(const ShaderSource::Precision& precision)
+{
+ precision_ = precision;
+ precision_has_been_set_ = true;
+}
+
+/**
+ * Gets the precision that will be used for this shader.
+ *
+ * @return the precision
+ */
+const ShaderSource::Precision&
+ShaderSource::precision()
+{
+ return precision_;
+}
+
+/**
+ * Sets the default precision that will be used for a shaders type.
+ *
+ * If type is ShaderTypeUnknown the supplied precision is used for all
+ * shader types.
+ *
+ * This can be overriden per ShaderSource object by using ::precision().
+ *
+ * @param precision the default precision to set
+ * @param type the ShaderType to use the precision for
+ */
+void
+ShaderSource::default_precision(const ShaderSource::Precision& precision,
+ ShaderSource::ShaderType type)
+{
+ if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
+ type = ShaderSource::ShaderTypeUnknown;
+
+ if (type == ShaderSource::ShaderTypeUnknown) {
+ for (size_t i = 0; i < ShaderSource::ShaderTypeUnknown; i++)
+ default_precision_[i] = precision;
+ }
+ else {
+ default_precision_[type] = precision;
+ }
+}
+
+/**
+ * Gets the default precision that will be used for a shader type.
+ *
+ * It is valid to use a type of ShaderTypeUnknown. This will always
+ * return a Precision with default values.
+ *
+ * @param type the ShaderType to get the precision of
+ *
+ * @return the precision
+ */
+const ShaderSource::Precision&
+ShaderSource::default_precision(ShaderSource::ShaderType type)
+{
+ if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
+ type = ShaderSource::ShaderTypeUnknown;
+
+ return default_precision_[type];
+}
+
+/****************************************
+ * ShaderSource::Precision constructors *
+ ****************************************/
+
+/**
+ * Creates a ShaderSource::Precision with default precision values.
+ */
+ShaderSource::Precision::Precision() :
+ int_precision(ShaderSource::PrecisionValueDefault),
+ float_precision(ShaderSource::PrecisionValueDefault),
+ sampler2d_precision(ShaderSource::PrecisionValueDefault),
+ samplercube_precision(ShaderSource::PrecisionValueDefault)
+{
+}
+
+/**
+ * Creates a ShaderSource::Precision using the supplied precision values.
+ */
+ShaderSource::Precision::Precision(ShaderSource::PrecisionValue int_p,
+ ShaderSource::PrecisionValue float_p,
+ ShaderSource::PrecisionValue sampler2d_p,
+ ShaderSource::PrecisionValue samplercube_p) :
+ int_precision(int_p), float_precision(float_p),
+ sampler2d_precision(sampler2d_p), samplercube_precision(samplercube_p)
+{
+}
+
+/**
+ * Creates a ShaderSource::Precision from a string representation of
+ * precision values.
+ *
+ * The string format is:
+ * "<int>,<float>,<sampler2d>,<samplercube>"
+ *
+ * Each precision value is one of "high", "medium", "low" or "default".
+ *
+ * @param precision_values the string representation of the precision values
+ */
+ShaderSource::Precision::Precision(const std::string& precision_values) :
+ int_precision(ShaderSource::PrecisionValueDefault),
+ float_precision(ShaderSource::PrecisionValueDefault),
+ sampler2d_precision(ShaderSource::PrecisionValueDefault),
+ samplercube_precision(ShaderSource::PrecisionValueDefault)
+{
+ std::vector<std::string> elems;
+
+ Util::split(precision_values, ',', elems, Util::SplitModeNormal);
+
+ for (size_t i = 0; i < elems.size() && i < 4; i++) {
+ const std::string& pstr(elems[i]);
+ ShaderSource::PrecisionValue pval;
+
+ if (pstr == "high")
+ pval = ShaderSource::PrecisionValueHigh;
+ else if (pstr == "medium")
+ pval = ShaderSource::PrecisionValueMedium;
+ else if (pstr == "low")
+ pval = ShaderSource::PrecisionValueLow;
+ else
+ pval = ShaderSource::PrecisionValueDefault;
+
+ switch(i) {
+ case 0: int_precision = pval; break;
+ case 1: float_precision = pval; break;
+ case 2: sampler2d_precision = pval; break;
+ case 3: samplercube_precision = pval; break;
+ default: break;
+ }
+ }
+}