2
// Copyright (c) 2010-2012 Linaro Limited
4
// All rights reserved. This program and the accompanying materials
5
// are made available under the terms of the MIT License which accompanies
6
// this distribution, and is available at
7
// http://www.opensource.org/licenses/mit-license.php
10
// Alexandros Frantzis <alexandros.frantzis@linaro.org>
11
// Jesse Barker <jesse.barker@linaro.org>
16
#include "shader-source.h"
22
* Holds default precision values for all shader types
23
* (even the unknown type, which is hardwired to default precision values)
25
std::vector<ShaderSource::Precision>
26
ShaderSource::default_precision_(ShaderSource::ShaderTypeUnknown + 1);
29
* Loads the contents of a file into a string.
31
* @param filename the name of the file
32
* @param str the string to put the contents of the file into
35
ShaderSource::load_file(const std::string& filename, std::string& str)
37
std::auto_ptr<std::istream> is_ptr(Util::get_resource(filename));
38
std::istream& inputFile(*is_ptr);
42
Log::error("Failed to open \"%s\"\n", filename.c_str());
47
while (getline(inputFile, curLine))
58
* Appends a string to the shader source.
60
* @param str the string to append
63
ShaderSource::append(const std::string &str)
69
* Appends the contents of a file to the shader source.
71
* @param filename the name of the file to append
74
ShaderSource::append_file(const std::string &filename)
77
if (load_file(filename, source))
82
* Replaces a string in the source with another string.
84
* @param remove the string to replace
85
* @param insert the string to replace with
88
ShaderSource::replace(const std::string &remove, const std::string &insert)
90
std::string::size_type pos = 0;
91
std::string str(source_.str());
93
while ((pos = str.find(remove, pos)) != std::string::npos) {
94
str.replace(pos, remove.size(), insert);
103
* Replaces a string in the source with the contents of a file.
105
* @param remove the string to replace
106
* @param filename the name of the file to read from
109
ShaderSource::replace_with_file(const std::string &remove, const std::string &filename)
112
if (load_file(filename, source))
113
replace(remove, source);
117
* Adds a string (usually containing a constant definition) at
118
* global (per shader) scope.
120
* The string is placed after any default precision qualifiers.
122
* @param str the string to add
125
ShaderSource::add_global(const std::string &str)
127
std::string::size_type pos = 0;
128
std::string source(source_.str());
130
/* Find the last precision qualifier */
131
pos = source.rfind("precision");
133
if (pos != std::string::npos) {
135
* Find the next #endif line of a preprocessor block that contains
136
* the precision qualifier.
138
std::string::size_type pos_if = source.find("#if", pos);
139
std::string::size_type pos_endif = source.find("#endif", pos);
141
if (pos_endif != std::string::npos && pos_endif < pos_if)
144
/* Go to the next line */
145
pos = source.find("\n", pos);
146
if (pos != std::string::npos)
152
source.insert(pos, str);
159
* Adds a string (usually containing a constant definition) at
160
* global (per shader) scope.
162
* The string is placed after any default precision qualifiers.
164
* @param function the function to add the string into
165
* @param str the string to add
168
ShaderSource::add_local(const std::string &str, const std::string &function)
170
std::string::size_type pos = 0;
171
std::string source(source_.str());
173
/* Find the function */
174
pos = source.find(function);
175
pos = source.find('{', pos);
177
/* Go to the next line */
178
pos = source.find("\n", pos);
179
if (pos != std::string::npos)
182
source.insert(pos, str);
189
* Adds a string (usually containing a constant definition) to a shader source
191
* If the function parameter is empty, the string will be added to global
192
* scope, after any precision definitions.
194
* @param str the string to add
195
* @param function if not empty, the function to add the string into
198
ShaderSource::add(const std::string &str, const std::string &function)
200
if (!function.empty())
201
add_local(str, function);
207
* Adds a float constant definition.
209
* @param name the name of the constant
210
* @param f the value of the constant
211
* @param function if not empty, the function to put the definition in
214
ShaderSource::add_const(const std::string &name, float f,
215
const std::string &function)
217
std::stringstream ss;
219
ss << "const float " << name << " = " << std::fixed << f << ";" << std::endl;
221
add(ss.str(), function);
225
* Adds a float array constant definition.
227
* Note that various GLSL versions (including ES) don't support
230
* @param name the name of the constant
231
* @param v the value of the constant
232
* @param function if not empty, the function to put the definition in
235
ShaderSource::add_const(const std::string &name, std::vector<float> &array,
236
const std::string &function)
238
std::stringstream ss;
240
ss << "const float " << name << "[" << array.size() << "] = {" << std::fixed;
241
for(std::vector<float>::const_iterator iter = array.begin();
246
if (iter + 1 != array.end())
247
ss << ", " << std::endl;
250
ss << "};" << std::endl;
252
add(ss.str(), function);
256
* Adds a vec2 constant definition.
258
* @param name the name of the constant
259
* @param v the value of the constant
260
* @param function if not empty, the function to put the definition in
263
ShaderSource::add_const(const std::string &name, const LibMatrix::vec2 &v,
264
const std::string &function)
266
std::stringstream ss;
268
ss << "const vec2 " << name << " = vec2(" << std::fixed;
269
ss << v.x() << ", " << v.y() << ");" << std::endl;
271
add(ss.str(), function);
275
* Adds a vec3 constant definition.
277
* @param name the name of the constant
278
* @param v the value of the constant
279
* @param function if not empty, the function to put the definition in
282
ShaderSource::add_const(const std::string &name, const LibMatrix::vec3 &v,
283
const std::string &function)
285
std::stringstream ss;
287
ss << "const vec3 " << name << " = vec3(" << std::fixed;
288
ss << v.x() << ", " << v.y() << ", " << v.z() << ");" << std::endl;
290
add(ss.str(), function);
294
* Adds a vec4 constant definition.
296
* @param name the name of the constant
297
* @param v the value of the constant
298
* @param function if not empty, the function to put the definition in
301
ShaderSource::add_const(const std::string &name, const LibMatrix::vec4 &v,
302
const std::string &function)
304
std::stringstream ss;
306
ss << "const vec4 " << name << " = vec4(" << std::fixed;
307
ss << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << ");" << std::endl;
309
add(ss.str(), function);
313
* Adds a mat3 constant definition.
315
* @param name the name of the constant
316
* @param v the value of the constant
317
* @param function if not empty, the function to put the definition in
320
ShaderSource::add_const(const std::string &name, const LibMatrix::mat3 &m,
321
const std::string &function)
323
std::stringstream ss;
325
ss << "const mat3 " << name << " = mat3(" << std::fixed;
326
ss << m[0][0] << ", " << m[1][0] << ", " << m[2][0] << "," << std::endl;
327
ss << m[0][1] << ", " << m[1][1] << ", " << m[2][1] << "," << std::endl;
328
ss << m[0][2] << ", " << m[1][2] << ", " << m[2][2] << std::endl;
329
ss << ");" << std::endl;
331
add(ss.str(), function);
335
* Adds a float array declaration and initialization.
337
* @param name the name of the array
338
* @param array the array values
339
* @param init_function the function to put the initialization in
340
* @param decl_function if not empty, the function to put the declaration in
343
ShaderSource::add_array(const std::string &name, std::vector<float> &array,
344
const std::string &init_function,
345
const std::string &decl_function)
347
if (init_function.empty() || name.empty())
350
std::stringstream ss;
351
ss << "float " << name << "[" << array.size() << "];" << std::endl;
353
std::string decl(ss.str());
359
for(std::vector<float>::const_iterator iter = array.begin();
363
ss << name << "[" << iter - array.begin() << "] = " << *iter << ";" << std::endl;
366
add(ss.str(), init_function);
368
add(decl, decl_function);
372
* Gets the ShaderType for this ShaderSource.
374
* If the ShaderType is unknown, an attempt is made to infer
375
* the type from the shader source contents.
377
* @return the ShaderType
379
ShaderSource::ShaderType
382
/* Try to infer the type from the source contents */
383
if (type_ == ShaderSource::ShaderTypeUnknown) {
384
std::string source(source_.str());
386
if (source.find("gl_FragColor") != std::string::npos)
387
type_ = ShaderSource::ShaderTypeFragment;
388
else if (source.find("gl_Position") != std::string::npos)
389
type_ = ShaderSource::ShaderTypeVertex;
391
Log::debug("Cannot infer shader type from contents. Leaving it Unknown.\n");
398
* Helper function that emits a precision statement.
400
* @param ss the stringstream to add the statement to
401
* @param val the precision value
402
* @param type_str the variable type to apply the precision value to
405
ShaderSource::emit_precision(std::stringstream& ss, ShaderSource::PrecisionValue val,
406
const std::string& type_str)
408
static const char *precision_map[] = {
409
"lowp", "mediump", "highp", NULL
412
if (val == ShaderSource::PrecisionValueHigh) {
413
if (type_ == ShaderSource::ShaderTypeFragment)
414
ss << "#ifdef GL_FRAGMENT_PRECISION_HIGH" << std::endl;
416
ss << "precision highp " << type_str << ";" << std::endl;
418
if (type_ == ShaderSource::ShaderTypeFragment) {
419
ss << "#else" << std::endl;
420
ss << "precision mediump " << type_str << ";" << std::endl;
421
ss << "#endif" << std::endl;
424
else if (val >= 0 && val < ShaderSource::PrecisionValueDefault) {
425
ss << "precision " << precision_map[val] << " ";
426
ss << type_str << ";" << std::endl;
429
/* There is no default precision in the fragment shader, so set it to mediump */
430
if (val == ShaderSource::PrecisionValueDefault
431
&& type_str == "float" && type_ == ShaderSource::ShaderTypeFragment)
433
ss << "precision mediump float;" << std::endl;
438
* Gets a string containing the complete shader source.
440
* Precision statements are applied at this point.
442
* @return the shader source
447
/* Decide which precision values to use */
448
ShaderSource::Precision precision;
450
/* Ensure we have tried to infer the type from the contents */
453
if (precision_has_been_set_)
454
precision = precision_;
456
precision = default_precision(type_);
458
/* Create the precision statements */
459
std::stringstream ss;
461
emit_precision(ss, precision.int_precision, "int");
462
emit_precision(ss, precision.float_precision, "float");
463
emit_precision(ss, precision.sampler2d_precision, "sampler2D");
464
emit_precision(ss, precision.samplercube_precision, "samplerCube");
466
std::string precision_str(ss.str());
467
if (!precision_str.empty()) {
468
precision_str.insert(0, "#ifdef GL_ES\n");
469
precision_str.insert(precision_str.size(), "#endif\n");
472
return precision_str + source_.str();
476
* Sets the precision that will be used for this shader.
478
* This overrides any default values set with ShaderSource::default_*_precision().
480
* @param precision the precision to set
483
ShaderSource::precision(const ShaderSource::Precision& precision)
485
precision_ = precision;
486
precision_has_been_set_ = true;
490
* Gets the precision that will be used for this shader.
492
* @return the precision
494
const ShaderSource::Precision&
495
ShaderSource::precision()
501
* Sets the default precision that will be used for a shaders type.
503
* If type is ShaderTypeUnknown the supplied precision is used for all
506
* This can be overriden per ShaderSource object by using ::precision().
508
* @param precision the default precision to set
509
* @param type the ShaderType to use the precision for
512
ShaderSource::default_precision(const ShaderSource::Precision& precision,
513
ShaderSource::ShaderType type)
515
if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
516
type = ShaderSource::ShaderTypeUnknown;
518
if (type == ShaderSource::ShaderTypeUnknown) {
519
for (size_t i = 0; i < ShaderSource::ShaderTypeUnknown; i++)
520
default_precision_[i] = precision;
523
default_precision_[type] = precision;
528
* Gets the default precision that will be used for a shader type.
530
* It is valid to use a type of ShaderTypeUnknown. This will always
531
* return a Precision with default values.
533
* @param type the ShaderType to get the precision of
535
* @return the precision
537
const ShaderSource::Precision&
538
ShaderSource::default_precision(ShaderSource::ShaderType type)
540
if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
541
type = ShaderSource::ShaderTypeUnknown;
543
return default_precision_[type];
546
/****************************************
547
* ShaderSource::Precision constructors *
548
****************************************/
551
* Creates a ShaderSource::Precision with default precision values.
553
ShaderSource::Precision::Precision() :
554
int_precision(ShaderSource::PrecisionValueDefault),
555
float_precision(ShaderSource::PrecisionValueDefault),
556
sampler2d_precision(ShaderSource::PrecisionValueDefault),
557
samplercube_precision(ShaderSource::PrecisionValueDefault)
562
* Creates a ShaderSource::Precision using the supplied precision values.
564
ShaderSource::Precision::Precision(ShaderSource::PrecisionValue int_p,
565
ShaderSource::PrecisionValue float_p,
566
ShaderSource::PrecisionValue sampler2d_p,
567
ShaderSource::PrecisionValue samplercube_p) :
568
int_precision(int_p), float_precision(float_p),
569
sampler2d_precision(sampler2d_p), samplercube_precision(samplercube_p)
574
* Creates a ShaderSource::Precision from a string representation of
577
* The string format is:
578
* "<int>,<float>,<sampler2d>,<samplercube>"
580
* Each precision value is one of "high", "medium", "low" or "default".
582
* @param precision_values the string representation of the precision values
584
ShaderSource::Precision::Precision(const std::string& precision_values) :
585
int_precision(ShaderSource::PrecisionValueDefault),
586
float_precision(ShaderSource::PrecisionValueDefault),
587
sampler2d_precision(ShaderSource::PrecisionValueDefault),
588
samplercube_precision(ShaderSource::PrecisionValueDefault)
590
std::vector<std::string> elems;
592
Util::split(precision_values, ',', elems);
594
for (size_t i = 0; i < elems.size() && i < 4; i++) {
595
const std::string& pstr(elems[i]);
596
ShaderSource::PrecisionValue pval;
599
pval = ShaderSource::PrecisionValueHigh;
600
else if (pstr == "medium")
601
pval = ShaderSource::PrecisionValueMedium;
602
else if (pstr == "low")
603
pval = ShaderSource::PrecisionValueLow;
605
pval = ShaderSource::PrecisionValueDefault;
608
case 0: int_precision = pval; break;
609
case 1: float_precision = pval; break;
610
case 2: sampler2d_precision = pval; break;
611
case 3: samplercube_precision = pval; break;