Shader.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. /**
  2. * Copyright (c) 2006-2016 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "common/config.h"
  22. #include "Shader.h"
  23. #include "Canvas.h"
  24. // C++
  25. #include <algorithm>
  26. #include <limits>
  27. namespace love
  28. {
  29. namespace graphics
  30. {
  31. namespace opengl
  32. {
  33. namespace
  34. {
  35. // temporarily attaches a shader program (for setting uniforms, etc)
  36. // reattaches the originally active program when destroyed
  37. struct TemporaryAttacher
  38. {
  39. TemporaryAttacher(Shader *shader)
  40. : curShader(shader)
  41. , prevShader(Shader::current)
  42. {
  43. curShader->attach(true);
  44. }
  45. ~TemporaryAttacher()
  46. {
  47. if (prevShader != nullptr)
  48. prevShader->attach();
  49. else
  50. curShader->detach();
  51. }
  52. Shader *curShader;
  53. Shader *prevShader;
  54. };
  55. } // anonymous namespace
  56. Shader *Shader::current = nullptr;
  57. Shader *Shader::defaultShader = nullptr;
  58. Shader *Shader::defaultVideoShader = nullptr;
  59. Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
  60. Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
  61. std::vector<int> Shader::textureCounters;
  62. Shader::Shader(const ShaderSource &source)
  63. : shaderSource(source)
  64. , program(0)
  65. , builtinUniforms()
  66. , builtinAttributes()
  67. , lastCanvas((Canvas *) -1)
  68. , lastViewport()
  69. , lastPointSize(0.0f)
  70. , videoTextureUnits()
  71. {
  72. if (source.vertex.empty() && source.pixel.empty())
  73. throw love::Exception("Cannot create shader: no source code!");
  74. // initialize global texture id counters if needed
  75. if ((int) textureCounters.size() < gl.getMaxTextureUnits() - 1)
  76. textureCounters.resize(gl.getMaxTextureUnits() - 1, 0);
  77. // load shader source and create program object
  78. loadVolatile();
  79. }
  80. Shader::~Shader()
  81. {
  82. if (current == this)
  83. detach();
  84. for (const auto &retainable : boundRetainables)
  85. retainable.second->release();
  86. boundRetainables.clear();
  87. unloadVolatile();
  88. }
  89. GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
  90. {
  91. GLenum glstage;
  92. const char *typestr;
  93. if (!stageNames.find(stage, typestr))
  94. typestr = "";
  95. switch (stage)
  96. {
  97. case STAGE_VERTEX:
  98. glstage = GL_VERTEX_SHADER;
  99. break;
  100. case STAGE_PIXEL:
  101. glstage = GL_FRAGMENT_SHADER;
  102. break;
  103. default:
  104. throw love::Exception("Cannot create shader object: unknown shader type.");
  105. break;
  106. }
  107. GLuint shaderid = glCreateShader(glstage);
  108. if (shaderid == 0)
  109. {
  110. if (glGetError() == GL_INVALID_ENUM)
  111. throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
  112. else
  113. throw love::Exception("Cannot create %s shader object.", typestr);
  114. }
  115. const char *src = code.c_str();
  116. GLint srclen = (GLint) code.length();
  117. glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen);
  118. glCompileShader(shaderid);
  119. GLint infologlen;
  120. glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
  121. // Get any warnings the shader compiler may have produced.
  122. if (infologlen > 0)
  123. {
  124. GLchar *infolog = new GLchar[infologlen];
  125. glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog);
  126. // Save any warnings for later querying.
  127. shaderWarnings[stage] = infolog;
  128. delete[] infolog;
  129. }
  130. GLint status;
  131. glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
  132. if (status == GL_FALSE)
  133. {
  134. glDeleteShader(shaderid);
  135. throw love::Exception("Cannot compile %s shader code:\n%s",
  136. typestr, shaderWarnings[stage].c_str());
  137. }
  138. return shaderid;
  139. }
  140. void Shader::mapActiveUniforms()
  141. {
  142. // Built-in uniform locations default to -1 (nonexistant.)
  143. for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
  144. builtinUniforms[i] = -1;
  145. uniforms.clear();
  146. GLint activeprogram = 0;
  147. glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
  148. gl.useProgram(program);
  149. GLint numuniforms;
  150. glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numuniforms);
  151. GLchar cname[256];
  152. const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
  153. for (int i = 0; i < numuniforms; i++)
  154. {
  155. GLsizei namelen = 0;
  156. GLenum gltype = 0;
  157. UniformInfo u = {};
  158. glGetActiveUniform(program, (GLuint) i, bufsize, &namelen, &u.count, &gltype, cname);
  159. u.name = std::string(cname, (size_t) namelen);
  160. u.location = glGetUniformLocation(program, u.name.c_str());
  161. u.baseType = getUniformBaseType(gltype);
  162. if (u.baseType == UNIFORM_MATRIX)
  163. u.matrix = getMatrixSize(gltype);
  164. else
  165. u.components = getUniformTypeComponents(gltype);
  166. // Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to
  167. // do this themselves, but some Android devices (galaxy tab 3 and 4)
  168. // don't seem to do it...
  169. if (u.baseType == UNIFORM_SAMPLER)
  170. glUniform1i(u.location, 0);
  171. // glGetActiveUniform appends "[0]" to the end of array uniform names...
  172. if (u.name.length() > 3)
  173. {
  174. size_t findpos = u.name.find("[0]");
  175. if (findpos != std::string::npos && findpos == u.name.length() - 3)
  176. u.name.erase(u.name.length() - 3);
  177. }
  178. // If this is a built-in (LOVE-created) uniform, store the location.
  179. BuiltinUniform builtin;
  180. if (builtinNames.find(u.name.c_str(), builtin))
  181. builtinUniforms[int(builtin)] = u.location;
  182. if (u.location != -1)
  183. uniforms[u.name] = u;
  184. }
  185. gl.useProgram(activeprogram);
  186. }
  187. bool Shader::loadVolatile()
  188. {
  189. OpenGL::TempDebugGroup debuggroup("Shader load");
  190. // Recreating the shader program will invalidate uniforms that rely on these.
  191. lastCanvas = (Canvas *) -1;
  192. lastViewport = OpenGL::Viewport();
  193. lastPointSize = -1.0f;
  194. // Invalidate the cached matrices by setting some elements to NaN.
  195. float nan = std::numeric_limits<float>::quiet_NaN();
  196. lastProjectionMatrix.setTranslation(nan, nan);
  197. lastTransformMatrix.setTranslation(nan, nan);
  198. for (int i = 0; i < 3; i++)
  199. videoTextureUnits[i] = 0;
  200. // zero out active texture list
  201. activeTexUnits.clear();
  202. activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
  203. std::vector<GLuint> shaderids;
  204. bool gammacorrect = graphics::isGammaCorrect();
  205. const ShaderSource *defaults = &defaultCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
  206. if (GLAD_ES_VERSION_2_0)
  207. defaults = &defaultCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
  208. // The shader program must have both vertex and pixel shader stages.
  209. const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
  210. const std::string &pixelcode = shaderSource.pixel.empty() ? defaults->pixel : shaderSource.pixel;
  211. try
  212. {
  213. shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode));
  214. shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode));
  215. }
  216. catch (love::Exception &)
  217. {
  218. for (GLuint id : shaderids)
  219. glDeleteShader(id);
  220. throw;
  221. }
  222. program = glCreateProgram();
  223. if (program == 0)
  224. {
  225. for (GLuint id : shaderids)
  226. glDeleteShader(id);
  227. throw love::Exception("Cannot create shader program object.");
  228. }
  229. for (GLuint id : shaderids)
  230. glAttachShader(program, id);
  231. // Bind generic vertex attribute indices to names in the shader.
  232. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
  233. {
  234. const char *name = nullptr;
  235. if (attribNames.find((VertexAttribID) i, name))
  236. glBindAttribLocation(program, i, (const GLchar *) name);
  237. }
  238. glLinkProgram(program);
  239. // Flag shaders for auto-deletion when the program object is deleted.
  240. for (GLuint id : shaderids)
  241. glDeleteShader(id);
  242. GLint status;
  243. glGetProgramiv(program, GL_LINK_STATUS, &status);
  244. if (status == GL_FALSE)
  245. {
  246. std::string warnings = getProgramWarnings();
  247. glDeleteProgram(program);
  248. program = 0;
  249. throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
  250. }
  251. // Get all active uniform variables in this shader from OpenGL.
  252. mapActiveUniforms();
  253. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
  254. {
  255. const char *name = nullptr;
  256. if (attribNames.find(VertexAttribID(i), name))
  257. builtinAttributes[i] = glGetAttribLocation(program, name);
  258. else
  259. builtinAttributes[i] = -1;
  260. }
  261. if (current == this)
  262. {
  263. // make sure glUseProgram gets called.
  264. current = nullptr;
  265. attach();
  266. checkSetBuiltinUniforms();
  267. }
  268. return true;
  269. }
  270. void Shader::unloadVolatile()
  271. {
  272. if (current == this)
  273. gl.useProgram(0);
  274. if (program != 0)
  275. {
  276. glDeleteProgram(program);
  277. program = 0;
  278. }
  279. // decrement global texture id counters for texture units which had textures bound from this shader
  280. for (size_t i = 0; i < activeTexUnits.size(); ++i)
  281. {
  282. if (activeTexUnits[i] > 0)
  283. textureCounters[i] = std::max(textureCounters[i] - 1, 0);
  284. }
  285. // active texture list is probably invalid, clear it
  286. activeTexUnits.clear();
  287. activeTexUnits.resize(gl.getMaxTextureUnits() - 1, 0);
  288. attributes.clear();
  289. // same with uniform location list
  290. uniforms.clear();
  291. // And the locations of any built-in uniform variables.
  292. for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
  293. builtinUniforms[i] = -1;
  294. shaderWarnings.clear();
  295. }
  296. std::string Shader::getProgramWarnings() const
  297. {
  298. GLint strsize, nullpos;
  299. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strsize);
  300. if (strsize == 0)
  301. return "";
  302. char *tempstr = new char[strsize];
  303. // be extra sure that the error string will be 0-terminated
  304. memset(tempstr, '\0', strsize);
  305. glGetProgramInfoLog(program, strsize, &nullpos, tempstr);
  306. tempstr[nullpos] = '\0';
  307. std::string warnings(tempstr);
  308. delete[] tempstr;
  309. return warnings;
  310. }
  311. std::string Shader::getWarnings() const
  312. {
  313. std::string warnings;
  314. const char *stagestr;
  315. // Get the individual shader stage warnings
  316. for (const auto &warning : shaderWarnings)
  317. {
  318. if (stageNames.find(warning.first, stagestr))
  319. warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
  320. }
  321. warnings += getProgramWarnings();
  322. return warnings;
  323. }
  324. void Shader::attach(bool temporary)
  325. {
  326. if (current != this)
  327. {
  328. gl.useProgram(program);
  329. current = this;
  330. // retain/release happens in Graphics::setShader.
  331. if (!temporary)
  332. {
  333. // make sure all sent textures are properly bound to their respective texture units
  334. // note: list potentially contains texture ids of deleted/invalid textures!
  335. for (int i = 0; i < (int) activeTexUnits.size(); ++i)
  336. {
  337. if (activeTexUnits[i] > 0)
  338. gl.bindTextureToUnit(activeTexUnits[i], i + 1, false);
  339. }
  340. }
  341. }
  342. }
  343. void Shader::detach()
  344. {
  345. if (defaultShader)
  346. {
  347. if (current != defaultShader)
  348. defaultShader->attach();
  349. return;
  350. }
  351. if (current != nullptr)
  352. gl.useProgram(0);
  353. current = nullptr;
  354. }
  355. const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
  356. {
  357. const auto it = uniforms.find(name);
  358. if (it == uniforms.end())
  359. return nullptr;
  360. return &(it->second);
  361. }
  362. void Shader::sendInts(const UniformInfo *info, const int *vec, int count)
  363. {
  364. if (info->baseType != UNIFORM_INT && info->baseType != UNIFORM_BOOL)
  365. return;
  366. TemporaryAttacher attacher(this);
  367. int location = info->location;
  368. switch (info->components)
  369. {
  370. case 4:
  371. glUniform4iv(location, count, vec);
  372. break;
  373. case 3:
  374. glUniform3iv(location, count, vec);
  375. break;
  376. case 2:
  377. glUniform2iv(location, count, vec);
  378. break;
  379. case 1:
  380. default:
  381. glUniform1iv(location, count, vec);
  382. break;
  383. }
  384. }
  385. void Shader::sendFloats(const UniformInfo *info, const float *vec, int count)
  386. {
  387. if (info->baseType != UNIFORM_FLOAT && info->baseType != UNIFORM_BOOL)
  388. return;
  389. TemporaryAttacher attacher(this);
  390. int location = info->location;
  391. switch (info->components)
  392. {
  393. case 4:
  394. glUniform4fv(location, count, vec);
  395. break;
  396. case 3:
  397. glUniform3fv(location, count, vec);
  398. break;
  399. case 2:
  400. glUniform2fv(location, count, vec);
  401. break;
  402. case 1:
  403. default:
  404. glUniform1fv(location, count, vec);
  405. break;
  406. }
  407. }
  408. void Shader::sendMatrices(const UniformInfo *info, const float *m, int count)
  409. {
  410. if (info->baseType != UNIFORM_MATRIX)
  411. return;
  412. TemporaryAttacher attacher(this);
  413. int location = info->location;
  414. int columns = info->matrix.columns;
  415. int rows = info->matrix.rows;
  416. if (columns == 2 && rows == 2)
  417. glUniformMatrix2fv(location, count, GL_FALSE, m);
  418. else if (columns == 3 && rows == 3)
  419. glUniformMatrix3fv(location, count, GL_FALSE, m);
  420. else if (columns == 4 && rows == 4)
  421. glUniformMatrix4fv(location, count, GL_FALSE, m);
  422. else if (columns == 2 && rows == 3)
  423. glUniformMatrix2x3fv(location, count, GL_FALSE, m);
  424. else if (columns == 2 && rows == 4)
  425. glUniformMatrix2x4fv(location, count, GL_FALSE, m);
  426. else if (columns == 3 && rows == 2)
  427. glUniformMatrix3x2fv(location, count, GL_FALSE, m);
  428. else if (columns == 3 && rows == 4)
  429. glUniformMatrix3x4fv(location, count, GL_FALSE, m);
  430. else if (columns == 4 && rows == 2)
  431. glUniformMatrix4x2fv(location, count, GL_FALSE, m);
  432. else if (columns == 4 && rows == 3)
  433. glUniformMatrix4x3fv(location, count, GL_FALSE, m);
  434. }
  435. void Shader::sendTexture(const UniformInfo *info, Texture *texture)
  436. {
  437. if (info->baseType != UNIFORM_SAMPLER)
  438. return;
  439. GLuint gltex = *(GLuint *) texture->getHandle();
  440. TemporaryAttacher attacher(this);
  441. int texunit = getTextureUnit(info->name);
  442. // bind texture to assigned texture unit and send uniform to shader program
  443. gl.bindTextureToUnit(gltex, texunit, false);
  444. glUniform1i(info->location, texunit);
  445. // increment global shader texture id counter for this texture unit, if we haven't already
  446. if (activeTexUnits[texunit-1] == 0)
  447. ++textureCounters[texunit-1];
  448. // store texture id so it can be re-bound to the proper texture unit later
  449. activeTexUnits[texunit-1] = gltex;
  450. retainObject(info->name, texture);
  451. }
  452. void Shader::retainObject(const std::string &name, Object *object)
  453. {
  454. object->retain();
  455. auto it = boundRetainables.find(name);
  456. if (it != boundRetainables.end())
  457. it->second->release();
  458. boundRetainables[name] = object;
  459. }
  460. int Shader::getTextureUnit(const std::string &name)
  461. {
  462. auto it = texUnitPool.find(name);
  463. if (it != texUnitPool.end())
  464. return it->second;
  465. int texunit = 1;
  466. // prefer texture units which are unused by all other shaders
  467. auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0);
  468. if (freeunit_it != textureCounters.end())
  469. {
  470. // we don't want to use unit 0
  471. texunit = (int) std::distance(textureCounters.begin(), freeunit_it) + 1;
  472. }
  473. else
  474. {
  475. // no completely unused texture units exist, try to use next free slot in our own list
  476. auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0);
  477. if (nextunit_it == activeTexUnits.end())
  478. throw love::Exception("No more texture units available for shader.");
  479. // we don't want to use unit 0
  480. texunit = (int) std::distance(activeTexUnits.begin(), nextunit_it) + 1;
  481. }
  482. texUnitPool[name] = texunit;
  483. return texunit;
  484. }
  485. bool Shader::hasUniform(const std::string &name) const
  486. {
  487. return uniforms.find(name) != uniforms.end();
  488. }
  489. GLint Shader::getAttribLocation(const std::string &name)
  490. {
  491. auto it = attributes.find(name);
  492. if (it != attributes.end())
  493. return it->second;
  494. GLint location = glGetAttribLocation(program, name.c_str());
  495. attributes[name] = location;
  496. return location;
  497. }
  498. bool Shader::hasVertexAttrib(VertexAttribID attrib) const
  499. {
  500. return builtinAttributes[int(attrib)] != -1;
  501. }
  502. void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
  503. {
  504. TemporaryAttacher attacher(this);
  505. // Set up the texture units that will be used by the shader to sample from
  506. // the textures, if they haven't been set up yet.
  507. if (videoTextureUnits[0] == 0)
  508. {
  509. const GLint locs[3] = {
  510. builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
  511. builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
  512. builtinUniforms[BUILTIN_VIDEO_CR_CHANNEL]
  513. };
  514. const char *names[3] = {nullptr, nullptr, nullptr};
  515. builtinNames.find(BUILTIN_VIDEO_Y_CHANNEL, names[0]);
  516. builtinNames.find(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
  517. builtinNames.find(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
  518. for (int i = 0; i < 3; i++)
  519. {
  520. if (locs[i] >= 0 && names[i] != nullptr)
  521. {
  522. videoTextureUnits[i] = getTextureUnit(names[i]);
  523. // Increment global shader texture id counter for this texture
  524. // unit, if we haven't already.
  525. if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
  526. ++textureCounters[videoTextureUnits[i] - 1];
  527. glUniform1i(locs[i], videoTextureUnits[i]);
  528. }
  529. }
  530. }
  531. const GLuint textures[3] = {ytexture, cbtexture, crtexture};
  532. // Bind the textures to their respective texture units.
  533. for (int i = 0; i < 3; i++)
  534. {
  535. if (videoTextureUnits[i] != 0)
  536. {
  537. // Store texture id so it can be re-bound later.
  538. activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
  539. gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
  540. }
  541. }
  542. }
  543. void Shader::checkSetScreenParams()
  544. {
  545. OpenGL::Viewport view = gl.getViewport();
  546. if (view == lastViewport && lastCanvas == Canvas::current)
  547. return;
  548. // In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
  549. // This lets us flip pixcoord.y when needed, to be consistent (drawing with
  550. // no Canvas active makes the y-values for pixel coordinates flipped.)
  551. GLfloat params[] = {
  552. (GLfloat) view.w, (GLfloat) view.h,
  553. 0.0f, 0.0f,
  554. };
  555. if (Canvas::current != nullptr)
  556. {
  557. // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
  558. params[2] = 1.0f;
  559. params[3] = 0.0f;
  560. }
  561. else
  562. {
  563. // gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
  564. // pixcoord.y = gl_FragCoord.y * -1.0 + height.
  565. params[2] = -1.0f;
  566. params[3] = (GLfloat) view.h;
  567. }
  568. GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
  569. if (location >= 0)
  570. {
  571. TemporaryAttacher attacher(this);
  572. glUniform4fv(location, 1, params);
  573. }
  574. lastCanvas = Canvas::current;
  575. lastViewport = view;
  576. }
  577. void Shader::checkSetPointSize(float size)
  578. {
  579. if (size == lastPointSize)
  580. return;
  581. GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
  582. if (location >= 0)
  583. {
  584. TemporaryAttacher attacher(this);
  585. glUniform1f(location, size);
  586. }
  587. lastPointSize = size;
  588. }
  589. void Shader::checkSetBuiltinUniforms()
  590. {
  591. checkSetScreenParams();
  592. // We use a more efficient method for sending transformation matrices to
  593. // the GPU on desktop GL.
  594. if (GLAD_ES_VERSION_2_0)
  595. {
  596. checkSetPointSize(gl.getPointSize());
  597. const Matrix4 &curxform = gl.matrices.transform.back();
  598. const Matrix4 &curproj = gl.matrices.projection.back();
  599. TemporaryAttacher attacher(this);
  600. bool tpmatrixneedsupdate = false;
  601. // Only upload the matrices if they've changed.
  602. if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
  603. {
  604. GLint location = builtinUniforms[BUILTIN_TRANSFORM_MATRIX];
  605. if (location >= 0)
  606. glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
  607. // Also upload the re-calculated normal matrix, if possible. The
  608. // normal matrix is the transpose of the inverse of the rotation
  609. // portion (top-left 3x3) of the transform matrix.
  610. location = builtinUniforms[BUILTIN_NORMAL_MATRIX];
  611. if (location >= 0)
  612. {
  613. Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
  614. glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
  615. }
  616. tpmatrixneedsupdate = true;
  617. lastTransformMatrix = curxform;
  618. }
  619. if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
  620. {
  621. GLint location = builtinUniforms[BUILTIN_PROJECTION_MATRIX];
  622. if (location >= 0)
  623. glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
  624. tpmatrixneedsupdate = true;
  625. lastProjectionMatrix = curproj;
  626. }
  627. if (tpmatrixneedsupdate)
  628. {
  629. GLint location = builtinUniforms[BUILTIN_TRANSFORM_PROJECTION_MATRIX];
  630. if (location >= 0)
  631. {
  632. Matrix4 tp_matrix(curproj * curxform);
  633. glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
  634. }
  635. }
  636. }
  637. }
  638. const std::map<std::string, Object *> &Shader::getBoundRetainables() const
  639. {
  640. return boundRetainables;
  641. }
  642. std::string Shader::getGLSLVersion()
  643. {
  644. const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
  645. if (tmp == nullptr)
  646. return "0.0";
  647. // the version string always begins with a version number of the format
  648. // major_number.minor_number
  649. // or
  650. // major_number.minor_number.release_number
  651. // we can keep release_number, since it does not affect the check below.
  652. std::string versionstring(tmp);
  653. size_t minorendpos = versionstring.find(' ');
  654. return versionstring.substr(0, minorendpos);
  655. }
  656. bool Shader::isSupported()
  657. {
  658. return GLAD_ES_VERSION_2_0 || (getGLSLVersion() >= "1.2");
  659. }
  660. int Shader::getUniformTypeComponents(GLenum type) const
  661. {
  662. switch (type)
  663. {
  664. case GL_INT:
  665. case GL_FLOAT:
  666. case GL_BOOL:
  667. case GL_SAMPLER_1D:
  668. case GL_SAMPLER_2D:
  669. case GL_SAMPLER_3D:
  670. return 1;
  671. case GL_INT_VEC2:
  672. case GL_FLOAT_VEC2:
  673. case GL_FLOAT_MAT2:
  674. case GL_BOOL_VEC2:
  675. return 2;
  676. case GL_INT_VEC3:
  677. case GL_FLOAT_VEC3:
  678. case GL_FLOAT_MAT3:
  679. case GL_BOOL_VEC3:
  680. return 3;
  681. case GL_INT_VEC4:
  682. case GL_FLOAT_VEC4:
  683. case GL_FLOAT_MAT4:
  684. case GL_BOOL_VEC4:
  685. return 4;
  686. default:
  687. return 1;
  688. }
  689. }
  690. Shader::MatrixSize Shader::getMatrixSize(GLenum type) const
  691. {
  692. MatrixSize m;
  693. switch (type)
  694. {
  695. case GL_FLOAT_MAT2:
  696. m.columns = m.rows = 2;
  697. break;
  698. case GL_FLOAT_MAT3:
  699. m.columns = m.rows = 3;
  700. break;
  701. case GL_FLOAT_MAT4:
  702. m.columns = m.rows = 4;
  703. break;
  704. case GL_FLOAT_MAT2x3:
  705. m.columns = 2;
  706. m.rows = 3;
  707. break;
  708. case GL_FLOAT_MAT2x4:
  709. m.columns = 2;
  710. m.rows = 4;
  711. break;
  712. case GL_FLOAT_MAT3x2:
  713. m.columns = 3;
  714. m.rows = 2;
  715. break;
  716. case GL_FLOAT_MAT3x4:
  717. m.columns = 3;
  718. m.rows = 4;
  719. break;
  720. case GL_FLOAT_MAT4x2:
  721. m.columns = 4;
  722. m.rows = 2;
  723. break;
  724. case GL_FLOAT_MAT4x3:
  725. m.columns = 4;
  726. m.rows = 3;
  727. break;
  728. }
  729. return m;
  730. }
  731. Shader::UniformType Shader::getUniformBaseType(GLenum type) const
  732. {
  733. switch (type)
  734. {
  735. case GL_INT:
  736. case GL_INT_VEC2:
  737. case GL_INT_VEC3:
  738. case GL_INT_VEC4:
  739. return UNIFORM_INT;
  740. case GL_FLOAT:
  741. case GL_FLOAT_VEC2:
  742. case GL_FLOAT_VEC3:
  743. case GL_FLOAT_VEC4:
  744. return UNIFORM_FLOAT;
  745. case GL_FLOAT_MAT2:
  746. case GL_FLOAT_MAT3:
  747. case GL_FLOAT_MAT4:
  748. case GL_FLOAT_MAT2x3:
  749. case GL_FLOAT_MAT2x4:
  750. case GL_FLOAT_MAT3x2:
  751. case GL_FLOAT_MAT3x4:
  752. case GL_FLOAT_MAT4x2:
  753. case GL_FLOAT_MAT4x3:
  754. return UNIFORM_MATRIX;
  755. case GL_BOOL:
  756. case GL_BOOL_VEC2:
  757. case GL_BOOL_VEC3:
  758. case GL_BOOL_VEC4:
  759. return UNIFORM_BOOL;
  760. case GL_SAMPLER_1D:
  761. case GL_SAMPLER_1D_SHADOW:
  762. case GL_SAMPLER_1D_ARRAY:
  763. case GL_SAMPLER_1D_ARRAY_SHADOW:
  764. case GL_SAMPLER_2D:
  765. case GL_SAMPLER_2D_MULTISAMPLE:
  766. case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
  767. case GL_SAMPLER_2D_RECT:
  768. case GL_SAMPLER_2D_RECT_SHADOW:
  769. case GL_SAMPLER_2D_SHADOW:
  770. case GL_SAMPLER_2D_ARRAY:
  771. case GL_SAMPLER_2D_ARRAY_SHADOW:
  772. case GL_SAMPLER_3D:
  773. case GL_SAMPLER_CUBE:
  774. case GL_SAMPLER_CUBE_SHADOW:
  775. case GL_SAMPLER_CUBE_MAP_ARRAY:
  776. case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
  777. return UNIFORM_SAMPLER;
  778. default:
  779. return UNIFORM_UNKNOWN;
  780. }
  781. }
  782. bool Shader::getConstant(const char *in, UniformType &out)
  783. {
  784. return uniformTypes.find(in, out);
  785. }
  786. bool Shader::getConstant(UniformType in, const char *&out)
  787. {
  788. return uniformTypes.find(in, out);
  789. }
  790. bool Shader::getConstant(const char *in, VertexAttribID &out)
  791. {
  792. return attribNames.find(in, out);
  793. }
  794. bool Shader::getConstant(VertexAttribID in, const char *&out)
  795. {
  796. return attribNames.find(in, out);
  797. }
  798. StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
  799. {
  800. {"vertex", Shader::STAGE_VERTEX},
  801. {"pixel", Shader::STAGE_PIXEL},
  802. };
  803. StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
  804. StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
  805. {
  806. {"float", Shader::UNIFORM_FLOAT},
  807. {"matrix", Shader::UNIFORM_MATRIX},
  808. {"int", Shader::UNIFORM_INT},
  809. {"bool", Shader::UNIFORM_BOOL},
  810. {"image", Shader::UNIFORM_SAMPLER},
  811. {"unknown", Shader::UNIFORM_UNKNOWN},
  812. };
  813. StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
  814. StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
  815. {
  816. {"VertexPosition", ATTRIB_POS},
  817. {"VertexTexCoord", ATTRIB_TEXCOORD},
  818. {"VertexColor", ATTRIB_COLOR},
  819. {"ConstantColor", ATTRIB_CONSTANTCOLOR},
  820. };
  821. StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
  822. StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
  823. {
  824. {"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
  825. {"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
  826. {"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
  827. {"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
  828. {"love_PointSize", Shader::BUILTIN_POINT_SIZE},
  829. {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
  830. {"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
  831. {"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
  832. {"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
  833. };
  834. StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
  835. } // opengl
  836. } // graphics
  837. } // love