1306 line
38 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010-2015 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // This program is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #include <lol/engine-internal.h>
  13. #include <cstring>
  14. #include <cstdio>
  15. #if defined(_WIN32) && !defined(_XBOX)
  16. # define WIN32_LEAN_AND_MEAN
  17. # include <windows.h>
  18. # if defined USE_D3D9
  19. # include <algorithm>
  20. using std::min;
  21. using std::max;
  22. # include <d3d9.h>
  23. # include <d3dx9shader.h>
  24. # endif
  25. #elif defined _XBOX
  26. # include <xtl.h>
  27. # undef near /* Fuck Microsoft */
  28. # undef far /* Fuck Microsoft again */
  29. #endif
  30. #include "pegtl.hh"
  31. #include "lolgl.h"
  32. namespace lol
  33. {
  34. struct ShaderType
  35. {
  36. enum Value
  37. {
  38. Vertex = 1,
  39. Fragment,
  40. Geometry,
  41. TessControl,
  42. TessEval,
  43. }
  44. m_value;
  45. inline ShaderType(Value v) : m_value(v) {}
  46. inline ShaderType(int v) : m_value((Value)v) {}
  47. inline operator Value() { return m_value; }
  48. };
  49. static const char* attribute_names[] =
  50. {
  51. "in_Position",
  52. "in_BlendWeight",
  53. "in_BlendIndices",
  54. "in_Normal",
  55. "in_PointSize",
  56. "in_TexCoord",
  57. "in_TexCoordExt",
  58. "in_Tangent",
  59. "in_Binormal",
  60. "in_TessFactor",
  61. "in_PositionT",
  62. "in_Color",
  63. "in_Fog",
  64. "in_Depth",
  65. "in_Sample"
  66. };
  67. /*
  68. * Shader implementation class
  69. */
  70. class ShaderData
  71. {
  72. friend class Shader;
  73. private:
  74. String m_name;
  75. #if defined USE_D3D9
  76. IDirect3DDevice9 *m_dev;
  77. IDirect3DVertexShader9 *vert_shader;
  78. IDirect3DPixelShader9 *frag_shader;
  79. ID3DXConstantTable *vert_table, *frag_table;
  80. #elif defined _XBOX
  81. D3DDevice *m_dev;
  82. D3DVertexShader *vert_shader;
  83. D3DPixelShader *frag_shader;
  84. ID3DXConstantTable *vert_table, *frag_table;
  85. #else
  86. GLuint prog_id, vert_id, frag_id;
  87. // Benlitz: using a simple array could be faster since there is never more than a few attribute locations to store
  88. map<uint64_t, GLint> attrib_locations;
  89. map<uint64_t, bool> attrib_errors;
  90. #endif
  91. uint32_t vert_crc, frag_crc;
  92. /* Shader patcher */
  93. static int GetVersion();
  94. static String Patch(String const &code, ShaderType type);
  95. /* Global shader cache */
  96. static Shader *shaders[];
  97. static hash<char const *> Hash;
  98. static int nshaders;
  99. };
  100. Shader *ShaderData::shaders[256];
  101. hash<char const *> ShaderData::Hash;
  102. int ShaderData::nshaders = 0;
  103. /*
  104. * LolFx parser
  105. */
  106. using namespace pegtl;
  107. struct lolfx_parser
  108. {
  109. public:
  110. lolfx_parser(String const &code)
  111. : m_section("header")
  112. {
  113. basic_parse_string<struct lolfx>(std::string(code.C()), this);
  114. }
  115. public:
  116. String m_section;
  117. map<String, String> m_programs;
  118. private:
  119. struct do_title : action_base<do_title>
  120. {
  121. static void apply(std::string const &ctx, lolfx_parser *that)
  122. {
  123. that->m_section = ctx.c_str();
  124. }
  125. };
  126. struct do_code : action_base<do_code>
  127. {
  128. static void apply(std::string const &ctx, lolfx_parser *that)
  129. {
  130. that->m_programs[that->m_section] = ctx.c_str();
  131. }
  132. };
  133. // title <- '[' (!']')+ ']' .{eol}
  134. struct title
  135. : seq<one<'['>,
  136. ifapply<plus<not_one<']'>>, do_title>,
  137. one<']'>,
  138. until<eol, any>> {};
  139. // FIXME: I’m using this rule because the ifapply<> above also
  140. // gets triggered when using at<> which is non-consuming.
  141. struct title_ignore
  142. : seq<one<'['>,
  143. plus<not_one<']'>>,
  144. one<']'>,
  145. until<eol, any>> {};
  146. // code_line <- .{eol}
  147. struct code_line
  148. : until<eol, any> {};
  149. // code_section < code_line{&(title / eof)}
  150. struct code_section
  151. : ifapply<until<at<sor<title_ignore, eof>>, code_line>, do_code> {};
  152. // shader < title code_section
  153. struct shader
  154. : seq<title, code_section> {};
  155. // header < code_section
  156. struct header
  157. : code_section {};
  158. // lolfx < header code_section*
  159. struct lolfx
  160. : seq<header, star<shader>> {};
  161. };
  162. /*
  163. * Public Shader class
  164. */
  165. Shader *Shader::Create(String const &name, String const &code)
  166. {
  167. lolfx_parser p(code);
  168. ASSERT(p.m_programs.has_key("vert.glsl"),
  169. "no vertex shader in %s", name.C());
  170. ASSERT(p.m_programs.has_key("frag.glsl"),
  171. "no fragment shader in %s", name.C());
  172. String vert = p.m_programs["vert.glsl"];
  173. String frag = p.m_programs["frag.glsl"];
  174. uint32_t new_vert_crc = ShaderData::Hash(vert);
  175. uint32_t new_frag_crc = ShaderData::Hash(frag);
  176. for (int n = 0; n < ShaderData::nshaders; n++)
  177. {
  178. if (ShaderData::shaders[n]->data->vert_crc == new_vert_crc
  179. && ShaderData::shaders[n]->data->frag_crc == new_frag_crc)
  180. {
  181. return ShaderData::shaders[n];
  182. }
  183. }
  184. Shader *ret = new Shader(name, vert, frag);
  185. ShaderData::shaders[ShaderData::nshaders] = ret;
  186. ShaderData::nshaders++;
  187. return ret;
  188. }
  189. void Shader::Destroy(Shader *shader)
  190. {
  191. /* XXX: do nothing! the shader should remain in cache */
  192. UNUSED(shader);
  193. }
  194. Shader::Shader(String const &name,
  195. String const &vert, String const &frag)
  196. : data(new ShaderData())
  197. {
  198. data->m_name = name;
  199. #if defined USE_D3D9 || defined _XBOX
  200. ID3DXBuffer *shader_code, *error_msg;
  201. HRESULT hr;
  202. D3DXMACRO macros[] =
  203. {
  204. #if defined _XBOX
  205. { "_XBOX", "1" },
  206. #endif
  207. { nullptr, nullptr }
  208. };
  209. #else
  210. char errbuf[4096];
  211. String shader_code;
  212. GLchar const *gl_code;
  213. GLint status;
  214. GLsizei len;
  215. #endif
  216. /* Compile vertex shader */
  217. data->vert_crc = ShaderData::Hash(vert);
  218. #if defined USE_D3D9 || defined _XBOX
  219. # if defined USE_D3D9
  220. data->m_dev = (IDirect3DDevice9 *)g_renderer->GetDevice();
  221. # elif defined _XBOX
  222. data->m_dev = (D3DDevice *)g_renderer->GetDevice();
  223. # endif
  224. hr = D3DXCompileShader(vert, (UINT)strlen(vert), macros, nullptr, "main",
  225. "vs_3_0", 0, &shader_code, &error_msg,
  226. &data->vert_table);
  227. if (FAILED(hr))
  228. {
  229. Log::Error("failed to compile vertex shader %s: %s\n", name.C(),
  230. error_msg ? error_msg->GetBufferPointer() : "error");
  231. Log::Error("shader source:\n%s\n", vert);
  232. }
  233. data->m_dev->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
  234. &data->vert_shader);
  235. shader_code->Release();
  236. #else
  237. shader_code = ShaderData::Patch(vert, ShaderType::Vertex);
  238. data->vert_id = glCreateShader(GL_VERTEX_SHADER);
  239. gl_code = shader_code.C();
  240. glShaderSource(data->vert_id, 1, &gl_code, nullptr);
  241. glCompileShader(data->vert_id);
  242. glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
  243. glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
  244. if (status != GL_TRUE)
  245. {
  246. Log::Error("failed to compile vertex shader %s: %s\n",
  247. name.C(), errbuf);
  248. Log::Error("shader source:\n%s\n", shader_code.C());
  249. }
  250. else if (len > 16)
  251. {
  252. Log::Debug("compile log for vertex shader %s: %s\n", name.C(), errbuf);
  253. Log::Debug("shader source:\n%s\n", shader_code.C());
  254. }
  255. #endif
  256. /* Compile fragment shader */
  257. data->frag_crc = ShaderData::Hash(frag);
  258. #if defined USE_D3D9 || defined _XBOX
  259. hr = D3DXCompileShader(frag, (UINT)strlen(frag), macros, nullptr, "main",
  260. "ps_3_0", 0, &shader_code, &error_msg,
  261. &data->frag_table);
  262. if (FAILED(hr))
  263. {
  264. Log::Error("failed to compile fragment shader %s: %s\n", name.C(),
  265. error_msg ? error_msg->GetBufferPointer() : "error");
  266. Log::Error("shader source:\n%s\n", frag);
  267. }
  268. data->m_dev->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
  269. &data->frag_shader);
  270. shader_code->Release();
  271. #else
  272. shader_code = ShaderData::Patch(frag, ShaderType::Fragment);
  273. data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
  274. gl_code = shader_code.C();
  275. glShaderSource(data->frag_id, 1, &gl_code, nullptr);
  276. glCompileShader(data->frag_id);
  277. glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
  278. glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
  279. if (status != GL_TRUE)
  280. {
  281. Log::Error("failed to compile fragment shader %s: %s\n",
  282. name.C(), errbuf);
  283. Log::Error("shader source:\n%s\n", shader_code.C());
  284. }
  285. else if (len > 16)
  286. {
  287. Log::Debug("compile log for fragment shader %s: %s\n",
  288. name.C(), errbuf);
  289. Log::Debug("shader source:\n%s\n", shader_code.C());
  290. }
  291. #endif
  292. #if defined USE_D3D9 || defined _XBOX
  293. /* FIXME: this is only debug code, we don't need it. */
  294. D3DXCONSTANTTABLE_DESC desc;
  295. data->frag_table->GetDesc(&desc);
  296. for (int i = 0; i < desc.Constants; i++)
  297. {
  298. D3DXCONSTANT_DESC cdesc;
  299. UINT count = 1;
  300. D3DXHANDLE h = data->frag_table->GetConstant(nullptr, i);
  301. data->frag_table->GetConstantDesc(h, &cdesc, &count);
  302. }
  303. data->vert_table->GetDesc(&desc);
  304. for (int i = 0; i < desc.Constants; i++)
  305. {
  306. D3DXCONSTANT_DESC cdesc;
  307. UINT count = 1;
  308. D3DXHANDLE h = data->vert_table->GetConstant(nullptr, i);
  309. data->frag_table->GetConstantDesc(h, &cdesc, &count);
  310. }
  311. #else
  312. /* Create program */
  313. data->prog_id = glCreateProgram();
  314. glAttachShader(data->prog_id, data->vert_id);
  315. glAttachShader(data->prog_id, data->frag_id);
  316. glLinkProgram(data->prog_id);
  317. glGetProgramInfoLog(data->prog_id, sizeof(errbuf), &len, errbuf);
  318. glGetProgramiv(data->prog_id, GL_LINK_STATUS, &status);
  319. if (status != GL_TRUE)
  320. {
  321. Log::Error("failed to link program %s: %s\n", name.C(), errbuf);
  322. }
  323. else if (len > 16)
  324. {
  325. Log::Debug("link log for program %s: %s\n", name.C(), errbuf);
  326. }
  327. GLint validated;
  328. glValidateProgram(data->prog_id);
  329. glGetProgramiv(data->prog_id, GL_VALIDATE_STATUS, &validated);
  330. if (validated != GL_TRUE)
  331. {
  332. Log::Error("failed to validate program %s\n", name.C());
  333. }
  334. GLint num_attribs;
  335. glGetProgramiv(data->prog_id, GL_ACTIVE_ATTRIBUTES, &num_attribs);
  336. #if EMSCRIPTEN //WebGL doesn't support GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, so chose a default size value.
  337. GLint max_len = 256;
  338. #else
  339. GLint max_len;
  340. glGetProgramiv(data->prog_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
  341. #endif
  342. char* name_buffer = new char[max_len];
  343. for (int i = 0; i < num_attribs; ++i)
  344. {
  345. int attrib_len;
  346. int attrib_size;
  347. int attrib_type;
  348. glGetActiveAttrib(data->prog_id, i, max_len, &attrib_len, (GLint*)&attrib_size, (GLenum*)&attrib_type, name_buffer);
  349. String name(name_buffer);
  350. int index = -1;
  351. VertexUsage usage = VertexUsage::MAX;
  352. for (int j = 0; j < (int)VertexUsage::MAX; ++j)
  353. {
  354. if (name.StartsWith(attribute_names[j]) ||
  355. name.StartsWith(String(attribute_names[j]).ToLower()))
  356. {
  357. usage = VertexUsage(j);
  358. char* idx_ptr = name.C() + strlen(attribute_names[j]);
  359. index = strtol(idx_ptr, nullptr, 10);
  360. break;
  361. }
  362. }
  363. if (usage == VertexUsage::MAX || index == -1)
  364. {
  365. Log::Error("unable to parse attribute semantic from name: %s\n",
  366. name_buffer);
  367. }
  368. else
  369. {
  370. GLint location = glGetAttribLocation(data->prog_id, name_buffer);
  371. uint64_t flags = (uint64_t)(uint16_t)usage.ToScalar() << 16;
  372. flags |= (uint64_t)(uint16_t)index;
  373. // TODO: this is here just in case. Remove this once everything has been correctly tested
  374. #if _DEBUG
  375. if (data->attrib_locations.has_key(flags))
  376. {
  377. Log::Error("error while parsing attribute semantics in %s\n",
  378. name.C());
  379. }
  380. #endif
  381. data->attrib_locations[flags] = location;
  382. }
  383. }
  384. delete[] name_buffer;
  385. #endif
  386. }
  387. int Shader::GetAttribCount() const
  388. {
  389. return (int)data->attrib_locations.count();
  390. }
  391. ShaderAttrib Shader::GetAttribLocation(VertexUsage usage, int index) const
  392. {
  393. ShaderAttrib ret;
  394. ret.m_flags = (uint64_t)(uint16_t)usage.ToScalar() << 16;
  395. ret.m_flags |= (uint64_t)(uint16_t)index;
  396. #if defined USE_D3D9 || defined _XBOX
  397. #else
  398. GLint l = -1;
  399. if (!data->attrib_locations.try_get(ret.m_flags, l))
  400. {
  401. /* Only spit an error once, we don’t need to flood the console. */
  402. if (!data->attrib_errors.has_key(ret.m_flags))
  403. {
  404. Log::Error("attribute %s not found in shader %s\n",
  405. usage.ToString().C(), data->m_name.C());
  406. data->attrib_errors[ret.m_flags] = true;
  407. }
  408. }
  409. ret.m_flags |= (uint64_t)(uint32_t)l << 32;
  410. #endif
  411. return ret;
  412. }
  413. ShaderUniform Shader::GetUniformLocation(String const& uni) const
  414. {
  415. return GetUniformLocation(uni.C());
  416. }
  417. ShaderUniform Shader::GetUniformLocation(char const *uni) const
  418. {
  419. ShaderUniform ret;
  420. #if defined USE_D3D9 || defined _XBOX
  421. /* Global variables are prefixed with "$" */
  422. String tmpname = String("$") + uni;
  423. D3DXCONSTANT_DESC cdesc;
  424. D3DXHANDLE hr;
  425. UINT count;
  426. count = 0;
  427. hr = data->frag_table->GetConstantByName(nullptr, tmpname.C());
  428. if (hr)
  429. data->frag_table->GetConstantDesc(hr, &cdesc, &count);
  430. if (count)
  431. {
  432. ret.frag = cdesc.RegisterIndex;
  433. ret.flags |= 1;
  434. }
  435. count = 0;
  436. hr = data->vert_table->GetConstantByName(nullptr, tmpname.C());
  437. if (hr)
  438. data->vert_table->GetConstantDesc(hr, &cdesc, &count);
  439. if (count)
  440. {
  441. ret.vert = cdesc.RegisterIndex;
  442. ret.flags |= 2;
  443. }
  444. #else
  445. ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
  446. ret.vert = 0;
  447. #endif
  448. return ret;
  449. }
  450. /*
  451. * Uniform setters for scalars
  452. */
  453. void Shader::SetUniform(ShaderUniform const &uni, int i)
  454. {
  455. #if defined USE_D3D9 || defined _XBOX
  456. SetUniform(uni, ivec4(i, 0, 0, 0));
  457. #else
  458. glUniform1i((GLint)uni.frag, i);
  459. #endif
  460. }
  461. void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
  462. {
  463. #if defined USE_D3D9 || defined _XBOX
  464. SetUniform(uni, ivec4(v, 0, 0));
  465. #else
  466. glUniform2i((GLint)uni.frag, v.x, v.y);
  467. #endif
  468. }
  469. void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
  470. {
  471. #if defined USE_D3D9 || defined _XBOX
  472. SetUniform(uni, ivec4(v, 0));
  473. #else
  474. glUniform3i((GLint)uni.frag, v.x, v.y, v.z);
  475. #endif
  476. }
  477. void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
  478. {
  479. #if defined USE_D3D9 || defined _XBOX
  480. if (uni.flags & 1)
  481. data->m_dev->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
  482. if (uni.flags & 2)
  483. data->m_dev->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
  484. #else
  485. glUniform4i((GLint)uni.frag, v.x, v.y, v.z, v.w);
  486. #endif
  487. }
  488. void Shader::SetUniform(ShaderUniform const &uni, float f)
  489. {
  490. #if defined USE_D3D9 || defined _XBOX
  491. SetUniform(uni, vec4(f, 0, 0, 0));
  492. #else
  493. glUniform1f((GLint)uni.frag, f);
  494. #endif
  495. }
  496. void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
  497. {
  498. #if defined USE_D3D9 || defined _XBOX
  499. SetUniform(uni, vec4(v, 0, 0));
  500. #else
  501. glUniform2fv((GLint)uni.frag, 1, &v[0]);
  502. #endif
  503. }
  504. void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
  505. {
  506. #if defined USE_D3D9 || defined _XBOX
  507. SetUniform(uni, vec4(v, 0));
  508. #else
  509. glUniform3fv((GLint)uni.frag, 1, &v[0]);
  510. #endif
  511. }
  512. void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
  513. {
  514. #if defined USE_D3D9 || defined _XBOX
  515. if (uni.flags & 1)
  516. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
  517. if (uni.flags & 2)
  518. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
  519. #else
  520. glUniform4fv((GLint)uni.frag, 1, &v[0]);
  521. #endif
  522. }
  523. void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
  524. {
  525. #if defined USE_D3D9 || defined _XBOX
  526. /* FIXME: do we need padding here like for the mat3 version? */
  527. if (uni.flags & 1)
  528. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
  529. if (uni.flags & 2)
  530. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
  531. #else
  532. glUniformMatrix2fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  533. #endif
  534. }
  535. void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
  536. {
  537. #if defined USE_D3D9 || defined _XBOX
  538. /* Padding matrix columns is necessary on DirectX. We need to create
  539. * a new data structure; a 4×4 matrix will do. */
  540. mat4 tmp(m, 1.0f);
  541. if (uni.flags & 1)
  542. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
  543. if (uni.flags & 2)
  544. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
  545. #else
  546. glUniformMatrix3fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  547. #endif
  548. }
  549. void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
  550. {
  551. #if defined USE_D3D9 || defined _XBOX
  552. if (uni.flags & 1)
  553. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
  554. if (uni.flags & 2)
  555. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
  556. #else
  557. glUniformMatrix4fv((GLint)uni.frag, 1, GL_FALSE, &m[0][0]);
  558. #endif
  559. }
  560. void Shader::SetUniform(ShaderUniform const &uni, TextureUniform tex, int index)
  561. {
  562. #if defined USE_D3D9 || defined _XBOX
  563. data->m_dev->SetTexture(index, (LPDIRECT3DTEXTURE9)tex.m_flags);
  564. data->m_dev->SetSamplerState(index, D3DSAMP_MAGFILTER, tex.m_attrib & 0xff);
  565. data->m_dev->SetSamplerState(index, D3DSAMP_MINFILTER, (tex.m_attrib >> 8) & 0xff);
  566. data->m_dev->SetSamplerState(index, D3DSAMP_MIPFILTER, (tex.m_attrib >> 16) & 0xff);
  567. #else
  568. glActiveTexture(GL_TEXTURE0 + index);
  569. //glEnable(GL_TEXTURE_2D);
  570. glBindTexture(GL_TEXTURE_2D, (int)tex.m_flags);
  571. SetUniform(uni, index);
  572. #endif
  573. }
  574. /*
  575. * Uniform setters for arrays
  576. */
  577. void Shader::SetUniform(ShaderUniform const &uni, array<float> const &v)
  578. {
  579. #if defined USE_D3D9 || defined _XBOX
  580. /* FIXME: this will not work properly because we don't know how tell DX9
  581. * it's a bunch of floats instead of vec4. */
  582. if (uni.flags & 1)
  583. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
  584. &v[0], v.Count() / 4);
  585. if (uni.flags & 2)
  586. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
  587. &v[0], v.Count() / 4);
  588. #else
  589. glUniform1fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0]);
  590. #endif
  591. }
  592. void Shader::SetUniform(ShaderUniform const &uni, array<vec2> const &v)
  593. {
  594. #if defined USE_D3D9 || defined _XBOX
  595. /* FIXME: this will not work properly because we don't know how tell DX9
  596. * it's a bunch of vec2 instead of vec4. */
  597. if (uni.flags & 1)
  598. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
  599. &v[0][0], v.Count() / 2);
  600. if (uni.flags & 2)
  601. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
  602. &v[0][0], v.Count() / 2);
  603. #else
  604. glUniform2fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]);
  605. #endif
  606. }
  607. void Shader::SetUniform(ShaderUniform const &uni, array<vec3> const &v)
  608. {
  609. #if defined USE_D3D9 || defined _XBOX
  610. /* FIXME: this will not work properly because we don't know how tell DX9
  611. * it's a bunch of vec3 instead of vec4. */
  612. if (uni.flags & 1)
  613. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
  614. &v[0][0], v.Count());
  615. if (uni.flags & 2)
  616. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
  617. &v[0][0], v.Count());
  618. #else
  619. glUniform3fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]);
  620. #endif
  621. }
  622. void Shader::SetUniform(ShaderUniform const &uni, array<vec4> const &v)
  623. {
  624. #if defined USE_D3D9 || defined _XBOX
  625. if (uni.flags & 1)
  626. data->m_dev->SetPixelShaderConstantF((UINT)uni.frag,
  627. &v[0][0], v.Count());
  628. if (uni.flags & 2)
  629. data->m_dev->SetVertexShaderConstantF((UINT)uni.vert,
  630. &v[0][0], v.Count());
  631. #else
  632. glUniform4fv((GLint)uni.frag, (GLsizei)v.Count(), &v[0][0]);
  633. #endif
  634. }
  635. void Shader::Bind() const
  636. {
  637. #if defined USE_D3D9 || defined _XBOX
  638. HRESULT hr;
  639. hr = data->m_dev->SetVertexShader(data->vert_shader);
  640. hr = data->m_dev->SetPixelShader(data->frag_shader);
  641. #else
  642. glUseProgram(data->prog_id);
  643. #endif
  644. }
  645. void Shader::Unbind() const
  646. {
  647. #if defined USE_D3D9 || defined _XBOX
  648. HRESULT hr;
  649. hr = data->m_dev->SetVertexShader(nullptr);
  650. hr = data->m_dev->SetPixelShader(nullptr);
  651. #else
  652. /* FIXME: untested */
  653. glUseProgram(0);
  654. #endif
  655. }
  656. Shader::~Shader()
  657. {
  658. #if defined USE_D3D9 || defined _XBOX
  659. data->vert_shader->Release();
  660. data->vert_table->Release();
  661. data->frag_shader->Release();
  662. data->frag_table->Release();
  663. #else
  664. glDetachShader(data->prog_id, data->vert_id);
  665. glDetachShader(data->prog_id, data->frag_id);
  666. glDeleteShader(data->vert_id);
  667. glDeleteShader(data->frag_id);
  668. glDeleteProgram(data->prog_id);
  669. #endif
  670. delete data;
  671. }
  672. /* Try to detect shader compiler features */
  673. int ShaderData::GetVersion()
  674. {
  675. static int version = 0;
  676. #if !defined USE_D3D9 && !defined _XBOX
  677. if (!version)
  678. {
  679. #if defined HAVE_GLES_2X
  680. /* GLES 2.x supports #version 100, that's all. */
  681. return 100;
  682. #else
  683. char buf[4096];
  684. GLsizei len;
  685. int id = glCreateShader(GL_VERTEX_SHADER);
  686. /* Can we compile 1.30 shaders? */
  687. char const *test130 =
  688. "#version 130\n"
  689. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  690. glShaderSource(id, 1, &test130, nullptr);
  691. glCompileShader(id);
  692. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  693. if (len <= 0)
  694. version = 130;
  695. /* If not, can we compile 1.20 shaders? */
  696. if (!version)
  697. {
  698. char const *test120 =
  699. "#version 120\n"
  700. "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
  701. glShaderSource(id, 1, &test120, nullptr);
  702. glCompileShader(id);
  703. glGetShaderInfoLog(id, sizeof(buf), &len, buf);
  704. if (len <= 0)
  705. version = 120;
  706. }
  707. /* Otherwise, assume we can compile 1.10 shaders. */
  708. if (!version)
  709. version = 110;
  710. glDeleteShader(id);
  711. #endif
  712. }
  713. #endif
  714. return version;
  715. }
  716. /*
  717. * Simple shader source patching for old GLSL versions.
  718. */
  719. String ShaderData::Patch(String const &code, ShaderType type)
  720. {
  721. int ver_driver = GetVersion();
  722. String patched_code = code;
  723. if (ver_driver >= 130)
  724. return patched_code;
  725. int ver_shader = 110;
  726. char *parser = strstr(patched_code.C(), "#version");
  727. if (parser)
  728. ver_shader = atoi(parser + strlen("#version"));
  729. /* This is GL ES, we only know version 100. */
  730. if (ver_shader > 100 && ver_driver == 100)
  731. {
  732. /* FIXME: this isn't elegant but honestly, we don't care, this
  733. * whole file is going to die soon. */
  734. char *p = strstr(patched_code.C(), "#version");
  735. if (p)
  736. {
  737. p += 8;
  738. while (*p == ' ')
  739. p++;
  740. if (p[0] == '1' && p[1] && p[2])
  741. p[1] = p[2] = '0';
  742. }
  743. }
  744. if (ver_shader > 120 && ver_driver <= 120)
  745. {
  746. char const *end = patched_code.C() + patched_code.Count() + 1;
  747. /* Find main() */
  748. parser = strstr(patched_code.C(), "main");
  749. if (!parser) return patched_code;
  750. parser = strstr(parser, "(");
  751. if (!parser) return patched_code;
  752. parser = strstr(parser, ")");
  753. if (!parser) return patched_code;
  754. parser = strstr(parser, "{");
  755. if (!parser) return patched_code;
  756. char *main = parser + 1;
  757. /* Perform main() replaces */
  758. char const * const main_replaces[] =
  759. {
  760. #if 0
  761. "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
  762. "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
  763. "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
  764. "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
  765. "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
  766. "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
  767. "in vec2 in_MultiTexCoord0;",
  768. "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
  769. "in vec2 in_MultiTexCoord1;",
  770. "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
  771. "in vec2 in_MultiTexCoord2;",
  772. "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
  773. "in vec2 in_MultiTexCoord3;",
  774. "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
  775. "in vec2 in_MultiTexCoord4;",
  776. "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
  777. "in vec2 in_MultiTexCoord5;",
  778. "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
  779. "in vec2 in_MultiTexCoord6;",
  780. "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
  781. "in vec2 in_MultiTexCoord7;",
  782. "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
  783. #endif
  784. nullptr
  785. };
  786. for (char const * const *rep = main_replaces; rep[0]; rep += 2)
  787. {
  788. char *match = strstr(patched_code.C(), rep[0]);
  789. if (match && match < main)
  790. {
  791. size_t l0 = strlen(rep[0]);
  792. size_t l1 = strlen(rep[1]);
  793. memmove(main + l1, main, end - main);
  794. memcpy(main, rep[1], l1);
  795. memset(match, ' ', l0);
  796. main += l1;
  797. end += l1;
  798. }
  799. }
  800. /* Perform small replaces */
  801. char const * const fast_replaces[] =
  802. {
  803. "#version 130", "#version 120",
  804. "in vec2", type == ShaderType::Vertex ? "attribute vec2" : "varying vec2",
  805. "in vec3", type == ShaderType::Vertex ? "attribute vec3" : "varying vec3",
  806. "in vec4", type == ShaderType::Vertex ? "attribute vec4" : "varying vec4",
  807. "in mat4", type == ShaderType::Vertex ? "attribute mat4" : "varying mat4",
  808. "out vec2", "varying vec2",
  809. "out vec3", "varying vec3",
  810. "out vec4", "varying vec4",
  811. "out mat4", "varying mat4",
  812. nullptr
  813. };
  814. for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
  815. {
  816. char *match;
  817. while ((match = strstr(patched_code.C(), rep[0])))
  818. {
  819. size_t l0 = strlen(rep[0]);
  820. size_t l1 = strlen(rep[1]);
  821. if (l1 > l0)
  822. memmove(match + l1, match + l0, (end - match) - l0);
  823. memcpy(match, rep[1], l1);
  824. if (l1 < l0)
  825. memset(match + l0, ' ', l1 - l0);
  826. end += l1 - l0;
  827. }
  828. }
  829. }
  830. patched_code.Resize(strlen(patched_code.C()));
  831. return patched_code;
  832. }
  833. static const String g_ret = "\n";
  834. static const String g_eol = ";";
  835. static const String g_bop = "{";
  836. static const String g_bcl = "}";
  837. static const String g_tab = " ";
  838. //----
  839. String Shader::GetVariablePrefix(const ShaderVariable variable)
  840. {
  841. switch (variable.ToScalar())
  842. {
  843. case ShaderVariable::Attribute: return String("in_");
  844. case ShaderVariable::Uniform: return String("u_");
  845. case ShaderVariable::Varying: return String("pass_");
  846. case ShaderVariable::InOut:
  847. default: return String();
  848. }
  849. }
  850. //----
  851. String Shader::GetVariableQualifier(const ShaderVariable variable)
  852. {
  853. switch (variable.ToScalar())
  854. {
  855. case ShaderVariable::Attribute: return String("attribute");
  856. case ShaderVariable::Uniform: return String("uniform");
  857. case ShaderVariable::Varying: return String("varying");
  858. case ShaderVariable::InOut:
  859. default: return String();
  860. }
  861. }
  862. //----
  863. String Shader::GetFunctionQualifier(const ShaderVariable variable, const ShaderProgram program)
  864. {
  865. switch (program.ToScalar())
  866. {
  867. case ShaderProgram::Geometry:
  868. {
  869. //TODO : L O L ----------------
  870. return String();
  871. }
  872. case ShaderProgram::Vertex:
  873. {
  874. switch (variable.ToScalar())
  875. {
  876. case ShaderVariable::Attribute: return String("in");
  877. case ShaderVariable::Uniform: return String("in");
  878. case ShaderVariable::Varying: return String("inout");
  879. case ShaderVariable::InOut: return String("inout");
  880. default: return String();
  881. }
  882. return String();
  883. }
  884. case ShaderProgram::Pixel:
  885. {
  886. switch (variable.ToScalar())
  887. {
  888. case ShaderVariable::Attribute: return String("in");
  889. case ShaderVariable::Uniform: return String("in");
  890. case ShaderVariable::Varying: return String("in");
  891. case ShaderVariable::InOut: return String("inout");
  892. default: return String();
  893. }
  894. return String();
  895. }
  896. default:
  897. {
  898. return String();
  899. }
  900. }
  901. }
  902. //----
  903. String Shader::GetProgramQualifier(const ShaderProgram program)
  904. {
  905. switch (program.ToScalar())
  906. {
  907. case ShaderProgram::Geometry: return String(); //TODO : L O L ---------
  908. case ShaderProgram::Vertex: return String("[vert.glsl]");
  909. case ShaderProgram::Pixel: return String("[frag.glsl]");
  910. default: return String();
  911. }
  912. }
  913. //----
  914. String Shader::GetProgramOutVariable(const ShaderProgram program)
  915. {
  916. switch (program.ToScalar())
  917. {
  918. case ShaderProgram::Geometry: return String(); //TODO : L O L ---------
  919. case ShaderProgram::Vertex: return String("gl_Position");
  920. case ShaderProgram::Pixel: return String("gl_FragColor");
  921. default: return String();
  922. }
  923. }
  924. //----
  925. String Shader::GetProgramOutVariableLocal(const ShaderProgram program)
  926. {
  927. switch (program.ToScalar())
  928. {
  929. case ShaderProgram::Geometry: return String(); //TODO : L O L ---------
  930. case ShaderProgram::Vertex: return String("out_position");
  931. case ShaderProgram::Pixel: return String("out_frag_color");
  932. default: return String();
  933. }
  934. }
  935. //ShaderVar -------------------------------------------------------------------
  936. ShaderVar ShaderVar::GetShaderOut(ShaderProgram program)
  937. {
  938. switch (program.ToScalar())
  939. {
  940. case ShaderProgram::Geometry: //TODO : L O L ------------------------------
  941. default: ASSERT(false); return ShaderVar();
  942. case ShaderProgram::Vertex: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program));
  943. case ShaderProgram::Pixel: return ShaderVar(ShaderVariable::InOut, ShaderVariableType::Vec4, Shader::GetProgramOutVariableLocal(program));
  944. }
  945. }
  946. //Shader Block implementation class -------------------------------------------
  947. void ShaderBlock::AddVar(ShaderVar const& var)
  948. {
  949. ShaderVariable qualifier = var.GetQualifier();
  950. String type = var.GetType();
  951. String name = Shader::GetVariablePrefix(qualifier) + var.m_name;
  952. ASSERT(!m_parameters[qualifier.ToScalar()].has_key(name));
  953. m_parameters[qualifier.ToScalar()][name] = type;
  954. }
  955. //----
  956. void ShaderBlock::AddCallParameters(map<String, String> const& variables, String& result)
  957. {
  958. array<String> keys = variables.keys();
  959. for (String key : keys)
  960. {
  961. if (result.Count() > 0)
  962. result += ", ";
  963. result += key;
  964. }
  965. }
  966. //----
  967. void ShaderBlock::AddDefinitionParameters(const ShaderVariable type, const ShaderProgram program, map<String, String>& variables, String& result)
  968. {
  969. array<String> keys = variables.keys();
  970. for (String key : keys)
  971. {
  972. if (result.Count() > 0)
  973. result += ", ";
  974. result += Shader::GetFunctionQualifier(type, program) + " ";
  975. result += variables[key];
  976. result += String(" ");
  977. result += key;
  978. }
  979. }
  980. //----
  981. void ShaderBlock::Build(const ShaderProgram program, String& call, String& function)
  982. {
  983. ASSERT(m_name.Count());
  984. ASSERT(m_parameters[ShaderVariable::InOut].count());
  985. //Build call in main
  986. String call_name = String("Call_") + m_name;
  987. call = call_name + "(";
  988. String call_parameters;
  989. for (int i = 0; i < ShaderVariable::MAX; i++)
  990. AddCallParameters(/*(ShaderVariable)i, */m_parameters[i], call_parameters);
  991. call += call_parameters + ");";
  992. //Build function declaration
  993. function = String("void ") + call_name + "(";
  994. String def_parameters;
  995. for (int i = 0; i < ShaderVariable::MAX; i++)
  996. AddDefinitionParameters((ShaderVariable)i, program, m_parameters[i], def_parameters);
  997. function += def_parameters + ")" + g_ret +
  998. "{" + g_ret +
  999. m_code_main + ((m_code_main.EndsWith(g_ret)) ? (String()) : (g_ret)) +
  1000. "}";
  1001. }
  1002. //Shader Builder implementation class -----------------------------------------
  1003. ShaderBuilder::ShaderBuilder(String const& name, String const& version)
  1004. : m_name(name), m_version(version)
  1005. {
  1006. ASSERT(name.Count());
  1007. ASSERT(version.Count());
  1008. }
  1009. //----
  1010. ShaderBuilder::~ShaderBuilder()
  1011. {
  1012. }
  1013. //----
  1014. String const& ShaderBuilder::GetName()
  1015. {
  1016. return m_name;
  1017. }
  1018. //----
  1019. ShaderBuilder& ShaderBuilder::operator<<(const ShaderProgram program)
  1020. {
  1021. m_current_program = program;
  1022. return *this;
  1023. }
  1024. //----
  1025. ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock* block)
  1026. {
  1027. ASSERT(m_current_program != ShaderProgram::MAX);
  1028. m_blocks[m_current_program.ToScalar()].PushUnique(block);
  1029. return *this;
  1030. }
  1031. //----
  1032. ShaderBuilder& ShaderBuilder::operator<<(ShaderBlock const& block)
  1033. {
  1034. ASSERT(m_current_program != ShaderProgram::MAX);
  1035. m_blocks[m_current_program.ToScalar()].PushUnique(new ShaderBlock(block));
  1036. return *this;
  1037. }
  1038. //----
  1039. String ShaderBuilder::AddSlotOutVariableLocal(const ShaderProgram program)
  1040. {
  1041. ShaderVariable var = ShaderVariable::InOut;
  1042. String result = Shader::GetProgramOutVariableLocal(program);
  1043. switch (program.ToScalar())
  1044. {
  1045. case ShaderProgram::Geometry:
  1046. {
  1047. //TODO : L O L ----------------
  1048. break;
  1049. }
  1050. case ShaderProgram::Vertex:
  1051. {
  1052. m_parameters[program.ToScalar()][var.ToScalar()][result] = "vec4";
  1053. break;
  1054. }
  1055. case ShaderProgram::Pixel:
  1056. {
  1057. m_parameters[program.ToScalar()][var.ToScalar()][result] = "vec4";
  1058. break;
  1059. }
  1060. default:
  1061. {
  1062. break;
  1063. }
  1064. }
  1065. return result;
  1066. }
  1067. //----
  1068. void ShaderBuilder::MergeParameters(map<String, String>& variables, map<String, String>& merged)
  1069. {
  1070. array<String> keys = variables.keys();
  1071. for (String key : keys)
  1072. {
  1073. bool has_key = merged.has_key(key);
  1074. //Key exists, check the type to make sure it's the same
  1075. ASSERT(!has_key || (has_key && merged[key] == variables[key]),
  1076. "has_key=%d, key=%s merged[key]=%s, variables[key]=%s\n",
  1077. (int)has_key, key.C(), merged[key].C(), variables[key].C());
  1078. //does not exist, had it
  1079. if (!has_key)
  1080. merged[key] = variables[key];
  1081. }
  1082. }
  1083. //----
  1084. void ShaderBuilder::Build(String& code)
  1085. {
  1086. //Cleanup first
  1087. for (int prog = 0; prog < ShaderProgram::MAX; prog++)
  1088. for (int var = 0; var < ShaderVariable::MAX; var++)
  1089. m_parameters[prog][var].empty();
  1090. //Start building
  1091. for (int prog = 0; prog < ShaderProgram::MAX; prog++)
  1092. {
  1093. //Add default local out in merged variables
  1094. String out_local_var = AddSlotOutVariableLocal((ShaderProgram)prog);
  1095. if (!out_local_var.Count())
  1096. continue;
  1097. //Merge all variables
  1098. for (int var = 0; var < ShaderVariable::MAX; var++)
  1099. for (int block = 0; block < m_blocks[prog].Count(); block++)
  1100. MergeParameters(m_blocks[prog][block]->m_parameters[var], m_parameters[prog][var]);
  1101. //Actually write code
  1102. code += Shader::GetProgramQualifier((ShaderProgram)prog) + g_ret;
  1103. //Add actual code
  1104. code += String("#version ") + m_version + g_ret + g_ret;
  1105. //Added shader variables
  1106. for (int var = 0; var < ShaderVariable::InOut; var++)
  1107. {
  1108. array<String> keys = m_parameters[prog][var].keys();
  1109. if (keys.Count())
  1110. {
  1111. code += String("//- ") + Shader::GetVariableQualifier((ShaderVariable)var) + " ----" + g_ret;
  1112. for (String key : keys)
  1113. {
  1114. code += Shader::GetVariableQualifier((ShaderVariable)var) + " ";
  1115. code += m_parameters[prog][var][key] + " " + key + ";" + g_ret;
  1116. }
  1117. if (var + 1 < ShaderVariable::InOut)
  1118. code += g_ret;
  1119. }
  1120. }
  1121. code += g_ret;
  1122. //Build Blocks code and add it
  1123. array<String> calls;
  1124. for (int block = 0; block < m_blocks[prog].Count(); block++)
  1125. {
  1126. String call;
  1127. String function;
  1128. m_blocks[prog][block]->Build(ShaderProgram(prog), call, function);
  1129. calls << call;
  1130. if (m_blocks[prog][block]->m_code_custom.Count())
  1131. {
  1132. code += String("//- ") + m_blocks[prog][block]->GetName() + " custom code ----" + g_ret;
  1133. code += m_blocks[prog][block]->m_code_custom + g_ret + g_ret;
  1134. }
  1135. code += String("//- ") + m_blocks[prog][block]->GetName() + " main code ----" + g_ret;
  1136. code += function + g_ret + g_ret;
  1137. }
  1138. //Added main definition
  1139. code += String("//- Main ----") + g_ret +
  1140. String("void main(void)") + g_ret + "{" + g_ret;
  1141. //Add local variables
  1142. int var = ShaderVariable::InOut;
  1143. array<String> keys = m_parameters[prog][var].keys();
  1144. for (String key : keys)
  1145. {
  1146. if (keys.Count())
  1147. {
  1148. code += g_tab + m_parameters[prog][var][key] + " " + key + ";" + g_ret;
  1149. }
  1150. }
  1151. code += g_ret;
  1152. //Add calls
  1153. code += g_tab + String("//- Calls ----") + g_ret;
  1154. for (String call : calls)
  1155. code += g_tab + call + g_ret;
  1156. code += g_ret;
  1157. code += g_tab + Shader::GetProgramOutVariable((ShaderProgram)prog) + " = " + out_local_var + ";" + g_ret +
  1158. String("}") + g_ret + g_ret;
  1159. }
  1160. }
  1161. } /* namespace lol */