Shader.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. /**
  2. * Copyright (c) 2006-2017 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 "Graphics.h"
  24. // C++
  25. #include <algorithm>
  26. #include <limits>
  27. #include <sstream>
  28. namespace love
  29. {
  30. namespace graphics
  31. {
  32. namespace opengl
  33. {
  34. Shader::Shader(const ShaderSource &source)
  35. : love::graphics::Shader(source)
  36. , program(0)
  37. , builtinUniforms()
  38. , builtinAttributes()
  39. , canvasWasActive(false)
  40. , lastViewport()
  41. , lastPointSize(0.0f)
  42. , videoTextureUnits()
  43. {
  44. // load shader source and create program object
  45. loadVolatile();
  46. }
  47. Shader::~Shader()
  48. {
  49. unloadVolatile();
  50. for (const auto &p : uniforms)
  51. {
  52. // Allocated with malloc().
  53. if (p.second.data != nullptr)
  54. free(p.second.data);
  55. if (p.second.baseType == UNIFORM_SAMPLER)
  56. {
  57. for (int i = 0; i < p.second.count; i++)
  58. {
  59. if (p.second.textures[i] != nullptr)
  60. p.second.textures[i]->release();
  61. }
  62. delete[] p.second.textures;
  63. }
  64. }
  65. }
  66. GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
  67. {
  68. GLenum glstage;
  69. const char *typestr;
  70. if (!getConstant(stage, typestr))
  71. typestr = "";
  72. switch (stage)
  73. {
  74. case STAGE_VERTEX:
  75. glstage = GL_VERTEX_SHADER;
  76. break;
  77. case STAGE_PIXEL:
  78. glstage = GL_FRAGMENT_SHADER;
  79. break;
  80. default:
  81. throw love::Exception("Cannot create shader object: unknown shader type.");
  82. break;
  83. }
  84. GLuint shaderid = glCreateShader(glstage);
  85. if (shaderid == 0)
  86. {
  87. if (glGetError() == GL_INVALID_ENUM)
  88. throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
  89. else
  90. throw love::Exception("Cannot create %s shader object.", typestr);
  91. }
  92. const char *src = code.c_str();
  93. GLint srclen = (GLint) code.length();
  94. glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen);
  95. glCompileShader(shaderid);
  96. GLint infologlen;
  97. glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
  98. // Get any warnings the shader compiler may have produced.
  99. if (infologlen > 0)
  100. {
  101. GLchar *infolog = new GLchar[infologlen];
  102. glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog);
  103. // Save any warnings for later querying.
  104. shaderWarnings[stage] = infolog;
  105. delete[] infolog;
  106. }
  107. GLint status;
  108. glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
  109. if (status == GL_FALSE)
  110. {
  111. glDeleteShader(shaderid);
  112. throw love::Exception("Cannot compile %s shader code:\n%s",
  113. typestr, shaderWarnings[stage].c_str());
  114. }
  115. return shaderid;
  116. }
  117. void Shader::mapActiveUniforms()
  118. {
  119. // Built-in uniform locations default to -1 (nonexistent.)
  120. for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
  121. builtinUniforms[i] = -1;
  122. GLint activeprogram = 0;
  123. glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
  124. gl.useProgram(program);
  125. GLint numuniforms;
  126. glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numuniforms);
  127. GLchar cname[256];
  128. const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
  129. std::map<std::string, UniformInfo> olduniforms = uniforms;
  130. uniforms.clear();
  131. for (int i = 0; i < numuniforms; i++)
  132. {
  133. GLsizei namelen = 0;
  134. GLenum gltype = 0;
  135. UniformInfo u = {};
  136. glGetActiveUniform(program, (GLuint) i, bufsize, &namelen, &u.count, &gltype, cname);
  137. u.name = std::string(cname, (size_t) namelen);
  138. u.location = glGetUniformLocation(program, u.name.c_str());
  139. u.baseType = getUniformBaseType(gltype);
  140. if (u.baseType == UNIFORM_MATRIX)
  141. u.matrix = getMatrixSize(gltype);
  142. else
  143. u.components = getUniformTypeComponents(gltype);
  144. // glGetActiveUniform appends "[0]" to the end of array uniform names...
  145. if (u.name.length() > 3)
  146. {
  147. size_t findpos = u.name.find("[0]");
  148. if (findpos != std::string::npos && findpos == u.name.length() - 3)
  149. u.name.erase(u.name.length() - 3);
  150. }
  151. // If this is a built-in (LOVE-created) uniform, store the location.
  152. BuiltinUniform builtin;
  153. if (getConstant(u.name.c_str(), builtin))
  154. builtinUniforms[int(builtin)] = u.location;
  155. if (u.location == -1)
  156. continue;
  157. // Make sure previously set uniform data is preserved, and shader-
  158. // initialized values are retrieved.
  159. auto oldu = olduniforms.find(u.name);
  160. if (oldu != olduniforms.end())
  161. {
  162. u.data = oldu->second.data;
  163. u.textures = oldu->second.textures;
  164. updateUniform(&u, u.count, true);
  165. if (u.baseType == UNIFORM_SAMPLER)
  166. {
  167. // Make sure all stored textures have their Volatiles loaded
  168. // before the sendTextures call, since it calls getHandle().
  169. for (int i = 0; i < u.count; i++)
  170. {
  171. if (u.textures[i] == nullptr)
  172. continue;
  173. Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
  174. if (v != nullptr)
  175. v->loadVolatile();
  176. }
  177. sendTextures(&u, u.textures, u.count, true);
  178. }
  179. }
  180. else
  181. {
  182. size_t datasize = 0;
  183. switch (u.baseType)
  184. {
  185. case UNIFORM_FLOAT:
  186. datasize = sizeof(float) * u.components * u.count;
  187. u.data = malloc(datasize);
  188. break;
  189. case UNIFORM_INT:
  190. case UNIFORM_BOOL:
  191. case UNIFORM_SAMPLER:
  192. datasize = sizeof(int) * u.components * u.count;
  193. u.data = malloc(datasize);
  194. break;
  195. case UNIFORM_UINT:
  196. datasize = sizeof(unsigned int) * u.components * u.count;
  197. u.data = malloc(datasize);
  198. break;
  199. case UNIFORM_MATRIX:
  200. datasize = sizeof(float) * (u.matrix.rows * u.matrix.columns) * u.count;
  201. u.data = malloc(datasize);
  202. break;
  203. default:
  204. break;
  205. }
  206. if (datasize > 0)
  207. {
  208. memset(u.data, 0, datasize);
  209. if (u.baseType == UNIFORM_SAMPLER)
  210. {
  211. // Initialize all samplers to 0. Both GLSL and GLSL ES are
  212. // supposed to do this themselves, but some Android devices
  213. // (galaxy tab 3 and 4) don't seem to do it...
  214. glUniform1iv(u.location, u.count, u.ints);
  215. u.textures = new Texture*[u.count];
  216. memset(u.textures, 0, sizeof(Texture *) * u.count);
  217. }
  218. }
  219. size_t offset = 0;
  220. // Store any shader-initialized values in our own memory.
  221. for (int i = 0; i < u.count; i++)
  222. {
  223. GLint location = u.location;
  224. if (u.count > 1)
  225. {
  226. std::ostringstream ss;
  227. ss << i;
  228. std::string indexname = u.name + "[" + ss.str() + "]";
  229. location = glGetUniformLocation(program, indexname.c_str());
  230. }
  231. if (location == -1)
  232. continue;
  233. switch (u.baseType)
  234. {
  235. case UNIFORM_FLOAT:
  236. glGetUniformfv(program, location, &u.floats[offset]);
  237. offset += u.components;
  238. break;
  239. case UNIFORM_INT:
  240. case UNIFORM_BOOL:
  241. glGetUniformiv(program, location, &u.ints[offset]);
  242. offset += u.components;
  243. break;
  244. case UNIFORM_UINT:
  245. glGetUniformuiv(program, location, &u.uints[offset]);
  246. offset += u.components;
  247. break;
  248. case UNIFORM_MATRIX:
  249. glGetUniformfv(program, location, &u.floats[offset]);
  250. offset += u.matrix.rows * u.matrix.columns;
  251. break;
  252. default:
  253. break;
  254. }
  255. }
  256. }
  257. uniforms[u.name] = u;
  258. }
  259. // Make sure uniforms that existed before but don't exist anymore are
  260. // cleaned up. This theoretically shouldn't happen, but...
  261. for (const auto &p : olduniforms)
  262. {
  263. if (uniforms.find(p.first) == uniforms.end())
  264. {
  265. free(p.second.data);
  266. if (p.second.baseType != UNIFORM_SAMPLER)
  267. continue;
  268. for (int i = 0; i < p.second.count; i++)
  269. {
  270. if (p.second.textures[i] != nullptr)
  271. p.second.textures[i]->release();
  272. }
  273. delete[] p.second.textures;
  274. }
  275. }
  276. gl.useProgram(activeprogram);
  277. }
  278. bool Shader::loadVolatile()
  279. {
  280. OpenGL::TempDebugGroup debuggroup("Shader load");
  281. // Recreating the shader program will invalidate uniforms that rely on these.
  282. canvasWasActive = false;
  283. lastViewport = Rect();
  284. lastPointSize = -1.0f;
  285. // Invalidate the cached matrices by setting some elements to NaN.
  286. float nan = std::numeric_limits<float>::quiet_NaN();
  287. lastProjectionMatrix.setTranslation(nan, nan);
  288. lastTransformMatrix.setTranslation(nan, nan);
  289. for (int i = 0; i < 3; i++)
  290. videoTextureUnits[i] = 0;
  291. // zero out active texture list
  292. textureUnits.clear();
  293. textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
  294. std::vector<GLuint> shaderids;
  295. auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
  296. const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode();
  297. // The shader program must have both vertex and pixel shader stages.
  298. const std::string &vertexcode = shaderSource.vertex.empty() ? defaults.vertex : shaderSource.vertex;
  299. const std::string &pixelcode = shaderSource.pixel.empty() ? defaults.pixel : shaderSource.pixel;
  300. try
  301. {
  302. shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode));
  303. shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode));
  304. }
  305. catch (love::Exception &)
  306. {
  307. for (GLuint id : shaderids)
  308. glDeleteShader(id);
  309. throw;
  310. }
  311. program = glCreateProgram();
  312. if (program == 0)
  313. {
  314. for (GLuint id : shaderids)
  315. glDeleteShader(id);
  316. throw love::Exception("Cannot create shader program object.");
  317. }
  318. for (GLuint id : shaderids)
  319. glAttachShader(program, id);
  320. // Bind generic vertex attribute indices to names in the shader.
  321. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
  322. {
  323. const char *name = nullptr;
  324. if (getConstant((VertexAttribID) i, name))
  325. glBindAttribLocation(program, i, (const GLchar *) name);
  326. }
  327. glLinkProgram(program);
  328. // Flag shaders for auto-deletion when the program object is deleted.
  329. for (GLuint id : shaderids)
  330. glDeleteShader(id);
  331. GLint status;
  332. glGetProgramiv(program, GL_LINK_STATUS, &status);
  333. if (status == GL_FALSE)
  334. {
  335. std::string warnings = getProgramWarnings();
  336. glDeleteProgram(program);
  337. program = 0;
  338. throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
  339. }
  340. // Get all active uniform variables in this shader from OpenGL.
  341. mapActiveUniforms();
  342. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
  343. {
  344. const char *name = nullptr;
  345. if (getConstant(VertexAttribID(i), name))
  346. builtinAttributes[i] = glGetAttribLocation(program, name);
  347. else
  348. builtinAttributes[i] = -1;
  349. }
  350. if (current == this)
  351. {
  352. // make sure glUseProgram gets called.
  353. current = nullptr;
  354. attach();
  355. updateBuiltinUniforms();
  356. }
  357. return true;
  358. }
  359. void Shader::unloadVolatile()
  360. {
  361. if (program != 0)
  362. {
  363. if (current == this)
  364. gl.useProgram(0);
  365. glDeleteProgram(program);
  366. program = 0;
  367. }
  368. // active texture list is probably invalid, clear it
  369. textureUnits.clear();
  370. textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
  371. attributes.clear();
  372. // And the locations of any built-in uniform variables.
  373. for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
  374. builtinUniforms[i] = -1;
  375. shaderWarnings.clear();
  376. }
  377. std::string Shader::getProgramWarnings() const
  378. {
  379. GLint strsize, nullpos;
  380. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strsize);
  381. if (strsize == 0)
  382. return "";
  383. char *tempstr = new char[strsize];
  384. // be extra sure that the error string will be 0-terminated
  385. memset(tempstr, '\0', strsize);
  386. glGetProgramInfoLog(program, strsize, &nullpos, tempstr);
  387. tempstr[nullpos] = '\0';
  388. std::string warnings(tempstr);
  389. delete[] tempstr;
  390. return warnings;
  391. }
  392. std::string Shader::getWarnings() const
  393. {
  394. std::string warnings;
  395. const char *stagestr;
  396. // Get the individual shader stage warnings
  397. for (const auto &warning : shaderWarnings)
  398. {
  399. if (getConstant(warning.first, stagestr))
  400. warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
  401. }
  402. warnings += getProgramWarnings();
  403. return warnings;
  404. }
  405. void Shader::attach(bool temporary)
  406. {
  407. if (current != this)
  408. {
  409. gl.useProgram(program);
  410. current = this;
  411. // retain/release happens in Graphics::setShader.
  412. if (!temporary)
  413. {
  414. // Make sure all textures are properly bound to their respective
  415. // texture units.
  416. for (int i = 1; i < (int) textureUnits.size(); ++i)
  417. {
  418. if (textureUnits[i].active)
  419. gl.bindTextureToUnit(textureUnits[i].texture, i, false);
  420. }
  421. // send any pending uniforms to the shader program.
  422. for (const auto &p : pendingUniformUpdates)
  423. updateUniform(p.first, p.second);
  424. pendingUniformUpdates.clear();
  425. }
  426. }
  427. }
  428. const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
  429. {
  430. const auto it = uniforms.find(name);
  431. if (it == uniforms.end())
  432. return nullptr;
  433. return &(it->second);
  434. }
  435. void Shader::updateUniform(const UniformInfo *info, int count, bool internalUpdate)
  436. {
  437. if (current != this)
  438. {
  439. pendingUniformUpdates.push_back(std::make_pair(info, count));
  440. return;
  441. }
  442. if (!internalUpdate)
  443. flushStreamDraws();
  444. int location = info->location;
  445. UniformType type = info->baseType;
  446. if (type == UNIFORM_FLOAT)
  447. {
  448. switch (info->components)
  449. {
  450. case 1:
  451. glUniform1fv(location, count, info->floats);
  452. break;
  453. case 2:
  454. glUniform2fv(location, count, info->floats);
  455. break;
  456. case 3:
  457. glUniform3fv(location, count, info->floats);
  458. break;
  459. case 4:
  460. glUniform4fv(location, count, info->floats);
  461. break;
  462. }
  463. }
  464. else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
  465. {
  466. switch (info->components)
  467. {
  468. case 1:
  469. glUniform1iv(location, count, info->ints);
  470. break;
  471. case 2:
  472. glUniform2iv(location, count, info->ints);
  473. break;
  474. case 3:
  475. glUniform3iv(location, count, info->ints);
  476. break;
  477. case 4:
  478. glUniform4iv(location, count, info->ints);
  479. break;
  480. }
  481. }
  482. else if (type == UNIFORM_UINT)
  483. {
  484. switch (info->components)
  485. {
  486. case 1:
  487. glUniform1uiv(location, count, info->uints);
  488. break;
  489. case 2:
  490. glUniform2uiv(location, count, info->uints);
  491. break;
  492. case 3:
  493. glUniform3uiv(location, count, info->uints);
  494. break;
  495. case 4:
  496. glUniform4uiv(location, count, info->uints);
  497. break;
  498. }
  499. }
  500. else if (type == UNIFORM_MATRIX)
  501. {
  502. int columns = info->matrix.columns;
  503. int rows = info->matrix.rows;
  504. if (columns == 2 && rows == 2)
  505. glUniformMatrix2fv(location, count, GL_FALSE, info->floats);
  506. else if (columns == 3 && rows == 3)
  507. glUniformMatrix3fv(location, count, GL_FALSE, info->floats);
  508. else if (columns == 4 && rows == 4)
  509. glUniformMatrix4fv(location, count, GL_FALSE, info->floats);
  510. else if (columns == 2 && rows == 3)
  511. glUniformMatrix2x3fv(location, count, GL_FALSE, info->floats);
  512. else if (columns == 2 && rows == 4)
  513. glUniformMatrix2x4fv(location, count, GL_FALSE, info->floats);
  514. else if (columns == 3 && rows == 2)
  515. glUniformMatrix3x2fv(location, count, GL_FALSE, info->floats);
  516. else if (columns == 3 && rows == 4)
  517. glUniformMatrix3x4fv(location, count, GL_FALSE, info->floats);
  518. else if (columns == 4 && rows == 2)
  519. glUniformMatrix4x2fv(location, count, GL_FALSE, info->floats);
  520. else if (columns == 4 && rows == 3)
  521. glUniformMatrix4x3fv(location, count, GL_FALSE, info->floats);
  522. }
  523. }
  524. int Shader::getFreeTextureUnits(int count)
  525. {
  526. int startunit = -1;
  527. // Ignore the first texture unit for Shader-local texture bindings.
  528. for (int i = 1; i < (int) textureUnits.size(); i++)
  529. {
  530. if (!textureUnits[i].active && i + count <= (int) textureUnits.size())
  531. {
  532. startunit = i;
  533. break;
  534. }
  535. }
  536. if (startunit == -1)
  537. throw love::Exception("No more texture units available for shader.");
  538. return startunit;
  539. }
  540. void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate)
  541. {
  542. if (info->baseType != UNIFORM_SAMPLER)
  543. return;
  544. bool shaderactive = current == this;
  545. if (!internalUpdate && shaderactive)
  546. flushStreamDraws();
  547. count = std::min(count, info->count);
  548. bool updateuniform = false;
  549. // Make sure the shader's samplers are associated with texture units.
  550. for (int i = 0; i < count; i++)
  551. {
  552. if (info->ints[i] == 0 && textures[i] != nullptr)
  553. {
  554. int texunit = getFreeTextureUnits(1);
  555. textureUnits[texunit].active = true;
  556. info->ints[i] = texunit;
  557. updateuniform = true;
  558. }
  559. }
  560. if (updateuniform)
  561. updateUniform(info, count, internalUpdate);
  562. // Bind the textures to the texture units.
  563. for (int i = 0; i < count; i++)
  564. {
  565. if (textures[i] != nullptr)
  566. textures[i]->retain();
  567. if (info->textures[i] != nullptr)
  568. info->textures[i]->release();
  569. info->textures[i] = textures[i];
  570. int texunit = info->ints[i];
  571. if (textures[i] != nullptr)
  572. {
  573. GLuint gltex = (GLuint) textures[i]->getHandle();
  574. if (shaderactive)
  575. gl.bindTextureToUnit(gltex, texunit, false);
  576. // Store texture id so it can be re-bound to the texture unit later.
  577. textureUnits[texunit].texture = gltex;
  578. }
  579. else
  580. {
  581. if (shaderactive)
  582. gl.bindTextureToUnit((GLuint) 0, texunit, false);
  583. textureUnits[texunit].texture = 0;
  584. textureUnits[texunit].active = false;
  585. }
  586. }
  587. }
  588. void Shader::flushStreamDraws() const
  589. {
  590. if (current == this)
  591. {
  592. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  593. if (gfx != nullptr)
  594. gfx->flushStreamDraws();
  595. }
  596. }
  597. bool Shader::hasUniform(const std::string &name) const
  598. {
  599. return uniforms.find(name) != uniforms.end();
  600. }
  601. GLint Shader::getAttribLocation(const std::string &name)
  602. {
  603. auto it = attributes.find(name);
  604. if (it != attributes.end())
  605. return it->second;
  606. GLint location = glGetAttribLocation(program, name.c_str());
  607. attributes[name] = location;
  608. return location;
  609. }
  610. void Shader::setVideoTextures(ptrdiff_t ytexture, ptrdiff_t cbtexture, ptrdiff_t crtexture)
  611. {
  612. // Set up the texture units that will be used by the shader to sample from
  613. // the textures, if they haven't been set up yet.
  614. if (videoTextureUnits[0] == 0)
  615. {
  616. const BuiltinUniform builtins[3] = {
  617. BUILTIN_VIDEO_Y_CHANNEL,
  618. BUILTIN_VIDEO_CB_CHANNEL,
  619. BUILTIN_VIDEO_CR_CHANNEL,
  620. };
  621. for (int i = 0; i < 3; i++)
  622. {
  623. GLint loc = builtinUniforms[builtins[i]];
  624. const char *name = nullptr;;
  625. if (loc >= 0 && getConstant(builtins[i], name) && name != nullptr)
  626. {
  627. const UniformInfo *info = getUniformInfo(name);
  628. if (info == nullptr)
  629. continue;
  630. videoTextureUnits[i] = getFreeTextureUnits(1);
  631. textureUnits[videoTextureUnits[i]].active = true;
  632. info->ints[0] = videoTextureUnits[i];
  633. updateUniform(info, 1);
  634. }
  635. }
  636. }
  637. const GLuint textures[3] = {(GLuint) ytexture, (GLuint) cbtexture, (GLuint) crtexture};
  638. // Bind the textures to their respective texture units.
  639. for (int i = 0; i < 3; i++)
  640. {
  641. if (videoTextureUnits[i] != 0)
  642. {
  643. // Store texture id so it can be re-bound later.
  644. textureUnits[videoTextureUnits[i]].texture = textures[i];
  645. if (current == this)
  646. gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
  647. }
  648. }
  649. }
  650. void Shader::updateScreenParams()
  651. {
  652. Rect view = gl.getViewport();
  653. auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
  654. bool canvasActive = gfx->isCanvasActive();
  655. if ((view == lastViewport && canvasWasActive == canvasActive) || current != this)
  656. return;
  657. // In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
  658. // This lets us flip pixcoord.y when needed, to be consistent (drawing with
  659. // no Canvas active makes the y-values for pixel coordinates flipped.)
  660. GLfloat params[] = {
  661. (GLfloat) view.w, (GLfloat) view.h,
  662. 0.0f, 0.0f,
  663. };
  664. if (canvasActive)
  665. {
  666. // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
  667. params[2] = 1.0f;
  668. params[3] = 0.0f;
  669. }
  670. else
  671. {
  672. // gl_FragCoord.y is flipped when drawing to the screen, so we un-flip:
  673. // pixcoord.y = gl_FragCoord.y * -1.0 + height.
  674. params[2] = -1.0f;
  675. params[3] = (GLfloat) view.h;
  676. }
  677. GLint location = builtinUniforms[BUILTIN_SCREEN_SIZE];
  678. if (location >= 0)
  679. glUniform4fv(location, 1, params);
  680. canvasWasActive = canvasActive;
  681. lastViewport = view;
  682. }
  683. void Shader::updatePointSize(float size)
  684. {
  685. if (size == lastPointSize || current != this)
  686. return;
  687. GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
  688. if (location >= 0)
  689. glUniform1f(location, size);
  690. lastPointSize = size;
  691. }
  692. void Shader::updateBuiltinUniforms()
  693. {
  694. if (current != this)
  695. return;
  696. updateScreenParams();
  697. if (GLAD_ES_VERSION_2_0)
  698. updatePointSize(gl.getPointSize());
  699. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  700. const Matrix4 &curproj = gfx->getProjection();
  701. const Matrix4 &curxform = gfx->getTransform();
  702. bool tpmatrixneedsupdate = false;
  703. // Only upload the matrices if they've changed.
  704. if (memcmp(curxform.getElements(), lastTransformMatrix.getElements(), sizeof(float) * 16) != 0)
  705. {
  706. GLint location = builtinUniforms[BUILTIN_TRANSFORM_MATRIX];
  707. if (location >= 0)
  708. glUniformMatrix4fv(location, 1, GL_FALSE, curxform.getElements());
  709. // Also upload the re-calculated normal matrix, if possible. The normal
  710. // matrix is the transpose of the inverse of the rotation portion
  711. // (top-left 3x3) of the transform matrix.
  712. location = builtinUniforms[BUILTIN_NORMAL_MATRIX];
  713. if (location >= 0)
  714. {
  715. Matrix3 normalmatrix = Matrix3(curxform).transposedInverse();
  716. glUniformMatrix3fv(location, 1, GL_FALSE, normalmatrix.getElements());
  717. }
  718. tpmatrixneedsupdate = true;
  719. lastTransformMatrix = curxform;
  720. }
  721. if (memcmp(curproj.getElements(), lastProjectionMatrix.getElements(), sizeof(float) * 16) != 0)
  722. {
  723. GLint location = builtinUniforms[BUILTIN_PROJECTION_MATRIX];
  724. if (location >= 0)
  725. glUniformMatrix4fv(location, 1, GL_FALSE, curproj.getElements());
  726. tpmatrixneedsupdate = true;
  727. lastProjectionMatrix = curproj;
  728. }
  729. if (tpmatrixneedsupdate)
  730. {
  731. GLint location = builtinUniforms[BUILTIN_TRANSFORM_PROJECTION_MATRIX];
  732. if (location >= 0)
  733. {
  734. Matrix4 tp_matrix(curproj, curxform);
  735. glUniformMatrix4fv(location, 1, GL_FALSE, tp_matrix.getElements());
  736. }
  737. }
  738. }
  739. std::string Shader::getGLSLVersion()
  740. {
  741. const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
  742. if (tmp == nullptr)
  743. return "0.0";
  744. // the version string always begins with a version number of the format
  745. // major_number.minor_number
  746. // or
  747. // major_number.minor_number.release_number
  748. // we can keep release_number, since it does not affect the check below.
  749. std::string versionstring(tmp);
  750. size_t minorendpos = versionstring.find(' ');
  751. return versionstring.substr(0, minorendpos);
  752. }
  753. bool Shader::isSupported()
  754. {
  755. return GLAD_ES_VERSION_2_0 || (getGLSLVersion() >= "1.2");
  756. }
  757. int Shader::getUniformTypeComponents(GLenum type) const
  758. {
  759. switch (type)
  760. {
  761. case GL_INT:
  762. case GL_UNSIGNED_INT:
  763. case GL_FLOAT:
  764. case GL_BOOL:
  765. case GL_SAMPLER_1D:
  766. case GL_SAMPLER_2D:
  767. case GL_SAMPLER_3D:
  768. return 1;
  769. case GL_INT_VEC2:
  770. case GL_UNSIGNED_INT_VEC2:
  771. case GL_FLOAT_VEC2:
  772. case GL_FLOAT_MAT2:
  773. case GL_BOOL_VEC2:
  774. return 2;
  775. case GL_INT_VEC3:
  776. case GL_UNSIGNED_INT_VEC3:
  777. case GL_FLOAT_VEC3:
  778. case GL_FLOAT_MAT3:
  779. case GL_BOOL_VEC3:
  780. return 3;
  781. case GL_INT_VEC4:
  782. case GL_UNSIGNED_INT_VEC4:
  783. case GL_FLOAT_VEC4:
  784. case GL_FLOAT_MAT4:
  785. case GL_BOOL_VEC4:
  786. return 4;
  787. default:
  788. return 1;
  789. }
  790. }
  791. Shader::MatrixSize Shader::getMatrixSize(GLenum type) const
  792. {
  793. MatrixSize m;
  794. switch (type)
  795. {
  796. case GL_FLOAT_MAT2:
  797. m.columns = m.rows = 2;
  798. break;
  799. case GL_FLOAT_MAT3:
  800. m.columns = m.rows = 3;
  801. break;
  802. case GL_FLOAT_MAT4:
  803. m.columns = m.rows = 4;
  804. break;
  805. case GL_FLOAT_MAT2x3:
  806. m.columns = 2;
  807. m.rows = 3;
  808. break;
  809. case GL_FLOAT_MAT2x4:
  810. m.columns = 2;
  811. m.rows = 4;
  812. break;
  813. case GL_FLOAT_MAT3x2:
  814. m.columns = 3;
  815. m.rows = 2;
  816. break;
  817. case GL_FLOAT_MAT3x4:
  818. m.columns = 3;
  819. m.rows = 4;
  820. break;
  821. case GL_FLOAT_MAT4x2:
  822. m.columns = 4;
  823. m.rows = 2;
  824. break;
  825. case GL_FLOAT_MAT4x3:
  826. m.columns = 4;
  827. m.rows = 3;
  828. break;
  829. }
  830. return m;
  831. }
  832. Shader::UniformType Shader::getUniformBaseType(GLenum type) const
  833. {
  834. switch (type)
  835. {
  836. case GL_INT:
  837. case GL_INT_VEC2:
  838. case GL_INT_VEC3:
  839. case GL_INT_VEC4:
  840. return UNIFORM_INT;
  841. case GL_UNSIGNED_INT:
  842. case GL_UNSIGNED_INT_VEC2:
  843. case GL_UNSIGNED_INT_VEC3:
  844. case GL_UNSIGNED_INT_VEC4:
  845. return UNIFORM_UINT;
  846. case GL_FLOAT:
  847. case GL_FLOAT_VEC2:
  848. case GL_FLOAT_VEC3:
  849. case GL_FLOAT_VEC4:
  850. return UNIFORM_FLOAT;
  851. case GL_FLOAT_MAT2:
  852. case GL_FLOAT_MAT3:
  853. case GL_FLOAT_MAT4:
  854. case GL_FLOAT_MAT2x3:
  855. case GL_FLOAT_MAT2x4:
  856. case GL_FLOAT_MAT3x2:
  857. case GL_FLOAT_MAT3x4:
  858. case GL_FLOAT_MAT4x2:
  859. case GL_FLOAT_MAT4x3:
  860. return UNIFORM_MATRIX;
  861. case GL_BOOL:
  862. case GL_BOOL_VEC2:
  863. case GL_BOOL_VEC3:
  864. case GL_BOOL_VEC4:
  865. return UNIFORM_BOOL;
  866. case GL_SAMPLER_1D:
  867. case GL_SAMPLER_1D_SHADOW:
  868. case GL_SAMPLER_1D_ARRAY:
  869. case GL_SAMPLER_1D_ARRAY_SHADOW:
  870. case GL_SAMPLER_2D:
  871. case GL_SAMPLER_2D_MULTISAMPLE:
  872. case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
  873. case GL_SAMPLER_2D_RECT:
  874. case GL_SAMPLER_2D_RECT_SHADOW:
  875. case GL_SAMPLER_2D_SHADOW:
  876. case GL_SAMPLER_2D_ARRAY:
  877. case GL_SAMPLER_2D_ARRAY_SHADOW:
  878. case GL_SAMPLER_3D:
  879. case GL_SAMPLER_CUBE:
  880. case GL_SAMPLER_CUBE_SHADOW:
  881. case GL_SAMPLER_CUBE_MAP_ARRAY:
  882. case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
  883. return UNIFORM_SAMPLER;
  884. default:
  885. return UNIFORM_UNKNOWN;
  886. }
  887. }
  888. } // opengl
  889. } // graphics
  890. } // love