From patchwork Mon Sep 19 16:29:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alexandros.frantzis@linaro.org X-Patchwork-Id: 4185 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 8421C23EF6 for ; Mon, 19 Sep 2011 16:29:16 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id 65FC0A18266 for ; Mon, 19 Sep 2011 16:29:16 +0000 (UTC) Received: by fxe23 with SMTP id 23so5831306fxe.11 for ; Mon, 19 Sep 2011 09:29:16 -0700 (PDT) Received: by 10.223.63.8 with SMTP id z8mr5355160fah.84.1316449756068; Mon, 19 Sep 2011 09:29:16 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.18.198 with SMTP id y6cs45690lad; Mon, 19 Sep 2011 09:29:15 -0700 (PDT) Received: by 10.227.38.81 with SMTP id a17mr2956315wbe.55.1316449754318; Mon, 19 Sep 2011 09:29:14 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id ek3si13099469wbb.56.2011.09.19.09.29.14 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 19 Sep 2011 09:29:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1R5giX-0003Gd-Qe for ; Mon, 19 Sep 2011 16:29:13 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id BA4CFE01A0 for ; Mon, 19 Sep 2011 16:29:13 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: glmark2 X-Launchpad-Branch: ~glmark2-dev/glmark2/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 138 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~glmark2-dev/glmark2/trunk] Rev 138: ShaderSource: Add support for setting shader precision at runtime using per-scene options. Message-Id: <20110919162913.14543.63512.launchpad@ackee.canonical.com> Date: Mon, 19 Sep 2011 16:29:13 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="13980"; Instance="initZopeless config overlay" X-Launchpad-Hash: 21393b717ba4ec3c8c1c7754676c247e022b388f Merge authors: Alexandros Frantzis (afrantzis) Related merge proposals: https://code.launchpad.net/~linaro-graphics-wg/glmark2/shader-precision/+merge/75515 proposed by: Alexandros Frantzis (afrantzis) review: Approve - Jesse Barker (jesse-barker) ------------------------------------------------------------ revno: 138 [merge] committer: Alexandros Frantzis branch nick: trunk timestamp: Mon 2011-09-19 19:18:59 +0300 message: ShaderSource: Add support for setting shader precision at runtime using per-scene options. modified: data/shaders/bump-normals.frag data/shaders/bump-poly.frag data/shaders/conditionals.frag data/shaders/desktop-blur.frag data/shaders/desktop.frag data/shaders/effect-2d-convolution.frag data/shaders/function.frag data/shaders/light-advanced.frag data/shaders/light-basic-tex.frag data/shaders/light-basic.frag data/shaders/light-phong.frag data/shaders/loop.frag src/scene-build.cpp src/scene-desktop.cpp src/scene-texture.cpp src/scene.cpp src/shader-source.cpp src/shader-source.h --- lp:glmark2 https://code.launchpad.net/~glmark2-dev/glmark2/trunk You are subscribed to branch lp:glmark2. To unsubscribe from this branch go to https://code.launchpad.net/~glmark2-dev/glmark2/trunk/+edit-subscription === modified file 'data/shaders/bump-normals.frag' --- data/shaders/bump-normals.frag 2011-07-27 15:02:27 +0000 +++ data/shaders/bump-normals.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - uniform sampler2D NormalMap; uniform mat4 NormalMatrix; === modified file 'data/shaders/bump-poly.frag' --- data/shaders/bump-poly.frag 2011-07-27 15:02:27 +0000 +++ data/shaders/bump-poly.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec3 Normal; void main(void) === modified file 'data/shaders/conditionals.frag' --- data/shaders/conditionals.frag 2011-07-07 13:59:05 +0000 +++ data/shaders/conditionals.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec4 dummy; void main(void) === modified file 'data/shaders/desktop-blur.frag' --- data/shaders/desktop-blur.frag 2011-09-12 15:39:23 +0000 +++ data/shaders/desktop-blur.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - uniform sampler2D Texture0; varying vec2 TextureCoord; === modified file 'data/shaders/desktop.frag' --- data/shaders/desktop.frag 2011-09-09 13:57:53 +0000 +++ data/shaders/desktop.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - uniform sampler2D MaterialTexture0; varying vec2 TextureCoord; === modified file 'data/shaders/effect-2d-convolution.frag' --- data/shaders/effect-2d-convolution.frag 2011-07-28 14:06:56 +0000 +++ data/shaders/effect-2d-convolution.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - uniform sampler2D Texture0; varying vec2 TextureCoord; === modified file 'data/shaders/function.frag' --- data/shaders/function.frag 2011-07-07 13:16:12 +0000 +++ data/shaders/function.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec4 dummy; float process(float d) === modified file 'data/shaders/light-advanced.frag' --- data/shaders/light-advanced.frag 2011-07-27 15:02:27 +0000 +++ data/shaders/light-advanced.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec3 Normal; void main(void) === modified file 'data/shaders/light-basic-tex.frag' --- data/shaders/light-basic-tex.frag 2010-07-28 14:52:54 +0000 +++ data/shaders/light-basic-tex.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - uniform sampler2D MaterialTexture0; varying vec4 Color; === modified file 'data/shaders/light-basic.frag' --- data/shaders/light-basic.frag 2010-07-28 14:52:54 +0000 +++ data/shaders/light-basic.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec4 Color; varying vec2 TextureCoord; === modified file 'data/shaders/light-phong.frag' --- data/shaders/light-phong.frag 2011-09-13 16:08:19 +0000 +++ data/shaders/light-phong.frag 2011-09-19 16:18:59 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec3 vertex_normal; varying vec4 vertex_position; === modified file 'data/shaders/loop.frag' --- data/shaders/loop.frag 2011-07-08 12:48:36 +0000 +++ data/shaders/loop.frag 2011-09-14 16:53:37 +0000 @@ -1,7 +1,3 @@ -#ifdef GL_ES -precision mediump float; -#endif - varying vec4 dummy; uniform int FragmentLoops; === modified file 'src/scene-build.cpp' --- src/scene-build.cpp 2011-09-16 12:04:44 +0000 +++ src/scene-build.cpp 2011-09-19 16:18:59 +0000 @@ -45,6 +45,26 @@ int SceneBuild::load() { + mRotationSpeed = 36.0f; + + mRunning = false; + + return 1; +} + +void SceneBuild::unload() +{ + mMesh.reset(); + +} + +void SceneBuild::setup() +{ + using LibMatrix::vec3; + + Scene::setup(); + + /* Set up shaders */ static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert"); static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.frag"); static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f); @@ -59,28 +79,9 @@ if (!Scene::load_shaders_from_strings(mProgram, vtx_source.str(), frg_source.str())) { - return 0; + return; } - mRotationSpeed = 36.0f; - - mRunning = false; - - return 1; -} - -void SceneBuild::unload() -{ - mProgram.stop(); - mProgram.release(); -} - -void SceneBuild::setup() -{ - using LibMatrix::vec3; - - Scene::setup(); - Model model; bool modelLoaded(false); const std::string& whichModel(mOptions["model"].value); @@ -150,6 +151,7 @@ SceneBuild::teardown() { mProgram.stop(); + mProgram.release(); mMesh.reset(); === modified file 'src/scene-desktop.cpp' --- src/scene-desktop.cpp 2011-09-19 15:34:58 +0000 +++ src/scene-desktop.cpp 2011-09-19 16:18:59 +0000 @@ -600,16 +600,12 @@ int SceneDesktop::load() { - priv_->screen.init(); - priv_->desktop.init(); return 1; } void SceneDesktop::unload() { - priv_->desktop.release(); - priv_->screen.release(); } void @@ -642,6 +638,8 @@ glDepthMask(GL_FALSE); /* Set up the screen and desktop RenderObjects */ + priv_->screen.init(); + priv_->desktop.init(); priv_->screen.size(LibMatrix::vec2(mCanvas.width(), mCanvas.height())); priv_->desktop.size(LibMatrix::vec2(mCanvas.width(), mCanvas.height())); @@ -696,6 +694,9 @@ glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); + priv_->desktop.release(); + priv_->screen.release(); + Scene::teardown(); } === modified file 'src/scene-texture.cpp' --- src/scene-texture.cpp 2011-08-31 21:22:27 +0000 +++ src/scene-texture.cpp 2011-09-14 16:44:46 +0000 @@ -44,11 +44,6 @@ int SceneTexture::load() { - static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert"); - static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic-tex.frag"); - static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f); - static const LibMatrix::vec4 materialDiffuse(1.0f, 1.0f, 1.0f, 1.0f); - Model model; if(!model.load_3ds(GLMARK_DATA_PATH"/models/cube.3ds")) @@ -58,7 +53,27 @@ model.convert_to_mesh(mCubeMesh); mCubeMesh.build_vbo(); + mRotationSpeed = LibMatrix::vec3(36.0f, 36.0f, 36.0f); + + mRunning = false; + + return 1; +} + +void SceneTexture::unload() +{ + mCubeMesh.reset(); +} + +void SceneTexture::setup() +{ + Scene::setup(); + // Load shaders + static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert"); + static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic-tex.frag"); + static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f); + static const LibMatrix::vec4 materialDiffuse(1.0f, 1.0f, 1.0f, 1.0f); ShaderSource vtx_source(vtx_shader_filename); ShaderSource frg_source(frg_shader_filename); @@ -69,7 +84,7 @@ if (!Scene::load_shaders_from_strings(mProgram, vtx_source.str(), frg_source.str())) { - return 0; + return; } std::vector attrib_locations; @@ -78,25 +93,6 @@ attrib_locations.push_back(mProgram["texcoord"].location()); mCubeMesh.set_attrib_locations(attrib_locations); - mRotationSpeed = LibMatrix::vec3(36.0f, 36.0f, 36.0f); - - mRunning = false; - - return 1; -} - -void SceneTexture::unload() -{ - mCubeMesh.reset(); - - mProgram.stop(); - mProgram.release(); -} - -void SceneTexture::setup() -{ - Scene::setup(); - // Create texture according to selected filtering GLint min_filter = GL_NONE; GLint mag_filter = GL_NONE; @@ -130,6 +126,8 @@ void SceneTexture::teardown() { mProgram.stop(); + mProgram.release(); + glDeleteTextures(1, &mTexture); Scene::teardown(); === modified file 'src/scene.cpp' --- src/scene.cpp 2011-07-05 09:14:41 +0000 +++ src/scene.cpp 2011-09-15 09:04:17 +0000 @@ -23,6 +23,7 @@ */ #include "scene.h" #include "log.h" +#include "shader-source.h" #include #include #include @@ -38,6 +39,12 @@ { mOptions["duration"] = Scene::Option("duration", "10.0", "The duration of each benchmark in seconds"); + mOptions["vertex-precision"] = Scene::Option("vertex-precision", + "default,default,default,default", + "The precision values for the vertex shader (\"int,float,sampler2d,samplercube\")"); + mOptions["fragment-precision"] = Scene::Option("fragment-precision", + "default,default,default,default", + "The precision values for the fragment shader (\"int,float,sampler2d,samplercube\")"); } Scene::~Scene() @@ -57,6 +64,17 @@ { stringstream ss(mOptions["duration"].value); ss >> mDuration; + + ShaderSource::default_precision( + ShaderSource::Precision(mOptions["vertex-precision"].value), + ShaderSource::ShaderTypeVertex + ); + + ShaderSource::default_precision( + ShaderSource::Precision(mOptions["fragment-precision"].value), + ShaderSource::ShaderTypeFragment + ); + } void Scene::teardown() === modified file 'src/shader-source.cpp' --- src/shader-source.cpp 2011-08-10 13:53:02 +0000 +++ src/shader-source.cpp 2011-09-15 09:04:17 +0000 @@ -29,6 +29,13 @@ #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::default_precision_(ShaderSource::ShaderTypeUnknown + 1); + +/** * Loads the contents of a file into a string. * * @param filename the name of the file @@ -351,3 +358,246 @@ 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; + + 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: + * ",,," + * + * 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 elems; + + Util::split(precision_values, ',', elems); + + 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; + } + } +} === modified file 'src/shader-source.h' --- src/shader-source.h 2011-07-28 08:44:31 +0000 +++ src/shader-source.h 2011-09-15 09:04:17 +0000 @@ -32,8 +32,16 @@ class ShaderSource { public: - ShaderSource() {} - ShaderSource(const std::string &filename) { append_file(filename); } + enum ShaderType { + ShaderTypeVertex, + ShaderTypeFragment, + ShaderTypeUnknown + }; + + ShaderSource(ShaderType type = ShaderTypeUnknown) : + precision_has_been_set_(false), type_(type) {} + ShaderSource(const std::string &filename, ShaderType type = ShaderTypeUnknown) : + precision_has_been_set_(false), type_(type) { append_file(filename); } void append(const std::string &str); void append_file(const std::string &filename); @@ -58,12 +66,46 @@ const std::string &init_function, const std::string &decl_function = ""); - std::string str() { return source_.str(); } + ShaderType type(); + std::string str(); + + enum PrecisionValue { + PrecisionValueLow, + PrecisionValueMedium, + PrecisionValueHigh, + PrecisionValueDefault, + }; + + struct Precision { + Precision(); + Precision(PrecisionValue int_p, PrecisionValue float_p, + PrecisionValue sampler2d_p, PrecisionValue samplercube_p); + Precision(const std::string& list); + + PrecisionValue int_precision; + PrecisionValue float_precision; + PrecisionValue sampler2d_precision; + PrecisionValue samplercube_precision; + }; + + void precision(const Precision& precision); + const Precision& precision(); + + static void default_precision(const Precision& precision, + ShaderType type = ShaderTypeUnknown); + static const Precision& default_precision(ShaderType type); private: void add_global(const std::string &str); void add_local(const std::string &str, const std::string &function); bool load_file(const std::string& filename, std::string& str); + void emit_precision(std::stringstream& ss, ShaderSource::PrecisionValue val, + const std::string& type_str); std::stringstream source_; + Precision precision_; + bool precision_has_been_set_; + ShaderType type_; + + static std::vector default_precision_; };