PageRenderTime 58ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/base/device/program/program.cpp

https://gitlab.com/nodegraph/ngsinternal
C++ | 612 lines | 434 code | 112 blank | 66 comment | 36 complexity | f1fe38cbec1a636f50e44f0ae36681a6 MD5 | raw file
  1. #include <base/device/program/program.h>
  2. #include <base/device/deviceheadersgl.h>
  3. #include <base/device/devicedebug.h>
  4. #include <base/device/program/attributeinfo.h>
  5. #include <base/memoryallocator/taggednew.h>
  6. #include <base/device/program/shader.h>
  7. #include <base/device/program/blockuniforminfo.h>
  8. #include <base/device/program/defaultuniforminfo.h>
  9. #include <base/device/program/uniforminfo.h>
  10. #include <iostream>
  11. #include <vector>
  12. #include <cassert>
  13. namespace ngs {
  14. Program::Program() {
  15. create_name();
  16. }
  17. Program::~Program() {
  18. remove_name();
  19. }
  20. GLuint Program::get_name() {
  21. return _name;
  22. }
  23. void Program::attach_shader(const Shader& shader) {
  24. gpu(glAttachShader(_name, shader.get_name()));
  25. }
  26. void Program::detach_shader(const Shader& shader) {
  27. gpu(glDetachShader(_name, shader.get_name()));
  28. }
  29. void Program::link() {
  30. gpu(glLinkProgram(_name));
  31. if (!is_linked()) {
  32. std::cerr << "Error: linking program.\n";
  33. std::cerr << get_info_log() << "\n";
  34. std::string info = get_info_log();
  35. assert(false);
  36. } else {
  37. //std::cerr<<"Success: linking program.\n";
  38. //std::cerr<<get_info_log()<<"\n";
  39. }
  40. }
  41. bool Program::is_linked() {
  42. int state;
  43. gpu(glGetProgramiv(_name, GL_LINK_STATUS, &state));
  44. if (state == 1) {
  45. return true;
  46. }
  47. return false;
  48. }
  49. void Program::use() {
  50. gpu(glUseProgram(_name));
  51. }
  52. void Program::disable() {
  53. gpu(glUseProgram(0));
  54. }
  55. std::string Program::get_info_log() {
  56. std::string log;
  57. int length = 0;
  58. gpu(glGetProgramiv(_name, GL_INFO_LOG_LENGTH, &length));
  59. if (length > 0) {
  60. int written = 0;
  61. log.resize(length);
  62. gpu(glGetProgramInfoLog(_name, length, &written, &log[0]));
  63. }
  64. return log;
  65. }
  66. void Program::create_name() {
  67. gpu(_name=glCreateProgram());
  68. if (_name == 0) {
  69. std::cerr
  70. << "Error insufficient memory is likely. unable to create a program object name.\n";
  71. assert(false);
  72. }
  73. }
  74. void Program::remove_name() {
  75. if (_name) {
  76. gpu(glDeleteProgram(_name));
  77. _name = 0;
  78. }
  79. }
  80. // --------------------------------------------------------------------------------------------------------------
  81. // Transform Feedback.
  82. // --------------------------------------------------------------------------------------------------------------
  83. #if GLES_MAJOR_VERSION >= 3
  84. void Program::set_transform_feedback_varyings(const std::vector<std::string>& names) {
  85. size_t num = names.size();
  86. std::vector<const char*> name_pointers;
  87. name_pointers.resize(num);
  88. for (size_t i = 0; i < names.size(); i++) {
  89. name_pointers[i] = &names[i][0];
  90. }
  91. glTransformFeedbackVaryings(_name, num, &name_pointers[0],
  92. GL_INTERLEAVED_ATTRIBS); //GL_SEPARATE_ATTRIBS requires multiples feedback vbos.
  93. }
  94. #endif
  95. // --------------------------------------------------------------------------------------------------------------
  96. // Vertex shader limits.
  97. // --------------------------------------------------------------------------------------------------------------
  98. #if GLES_MAJOR_VERSION >= 3
  99. GLint Program::get_max_vertex_uniforms_in_default_block() {
  100. GLint max;
  101. gpu(glGetProgramiv(_name,GL_MAX_VERTEX_UNIFORM_COMPONENTS,&max));
  102. return max;
  103. }
  104. GLint Program::get_max_vertex_uniforms() {
  105. GLint max;
  106. gpu(glGetProgramiv(_name,GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS,&max));
  107. return max;
  108. }
  109. #endif
  110. // --------------------------------------------------------------------------------------------------------------
  111. // Frag Data.
  112. // --------------------------------------------------------------------------------------------------------------
  113. #if GLES_MAJOR_VERSION >= 3
  114. GLint Program::get_frag_data_location(const std::string& name) {
  115. // Note we prolly need to update the nvidia drivers.
  116. // glGetFragDataLocation will crash in multi threaded gl rendering
  117. // but glGetFragDataLocationEXT works just fine.
  118. gpu(GLint loc=glGetFragDataLocation(_name, name.c_str()));
  119. return loc;
  120. }
  121. #endif
  122. #if GLES_MAJOR_VERSION >= 100
  123. GLint Program::get_frag_data_index(const std::string& name) {
  124. gpu(GLint loc=glGetFragDataIndex(_name, name.c_str()));
  125. return loc;
  126. }
  127. #endif
  128. // --------------------------------------------------------------------------------------------------------------
  129. // Attributes.
  130. // --------------------------------------------------------------------------------------------------------------
  131. GLint Program::get_num_attributes() {
  132. GLint num;
  133. gpu(glGetProgramiv(_name,GL_ACTIVE_ATTRIBUTES, &num));
  134. return num;
  135. }
  136. GLint Program::get_max_attribute_location() {
  137. GLint max;
  138. gpu(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS,&max));
  139. return max;
  140. }
  141. AttributeInfo* Program::create_attribute_info(GLuint index) {
  142. // std::string name;
  143. // int buffer_size = get_max_uniform_name_length();
  144. // name.resize(buffer_size);
  145. static const int buffer_size = 2048;
  146. static char buffer[buffer_size];
  147. int size = 0;
  148. GLenum type;
  149. // Get name size and type.
  150. int written = 0;
  151. gpu(glGetActiveAttrib(_name, index, buffer_size, &written, &size, &type, buffer));
  152. // The number of written chars must be less than buffer_size -1.
  153. // Opengl won't count the NULL terminator.
  154. // So the max written value is buffer_size-1;
  155. // If we receive the max written value, then the name might actually be longer.
  156. // So we would need larger buffer_size constant in this case.
  157. assert(written<buffer_size-1);
  158. std::string name(buffer,written);
  159. // std::cerr<<"Written: " << written << "\n";
  160. // std::cerr<<"Attribute: "<<name<<"\n";
  161. // Get the attribute index location.
  162. gpu(GLint location=glGetAttribLocation(_name, name.c_str()));
  163. // Fill in the structure;
  164. AttributeInfo* attr = new_ff AttributeInfo();
  165. attr->name = name;
  166. attr->type = type;
  167. attr->size = size;
  168. attr->location = location;
  169. return attr;
  170. }
  171. std::vector<AttributeInfo*> Program::create_all_attribute_infos() {
  172. std::vector<AttributeInfo*> infos;
  173. int num = get_num_attributes();
  174. infos.resize(num);
  175. for (int i = 0; i < num; i++) {
  176. infos[i]=create_attribute_info(i);
  177. }
  178. return infos;
  179. }
  180. void Program::set_attribute_location(const AttributeInfo* info) {
  181. gpu(glBindAttribLocation(_name, info->location, info->name.c_str()););
  182. }
  183. // --------------------------------------------------------------------------------------------------------------
  184. // All uniforms.
  185. // --------------------------------------------------------------------------------------------------------------
  186. GLint Program::get_num_uniforms() {
  187. GLint num;
  188. gpu(glGetProgramiv(_name,GL_ACTIVE_UNIFORMS,&num));
  189. return num;
  190. }
  191. GLint Program::get_max_uniform_name_length() {
  192. GLint max;
  193. gpu(glGetProgramiv(_name, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max));
  194. return max;
  195. }
  196. std::string Program::get_uniform_name(GLuint uniform_index) {
  197. #if GLES_MAJOR_VERSION >= 100
  198. std::string name;
  199. int max_length = get_max_uniform_name_length();
  200. name.resize(max_length);
  201. int written = 0;
  202. gpu(glGetActiveUniformName(_name, uniform_index, max_length, &written, &name[0]));
  203. name.resize(written);
  204. return name;
  205. #else
  206. int max_length = get_max_uniform_name_length();
  207. std::string name;
  208. name.resize(max_length);
  209. int size=-1;
  210. GLenum type = GL_ZERO;
  211. int written = 0;
  212. glGetActiveUniform(_name, uniform_index, max_length, &written, &size, &type, &name[0] );
  213. name.resize(written);
  214. return name;
  215. #endif
  216. }
  217. void Program::get_uniform_names(std::vector<std::string>& names) {
  218. names.clear();
  219. // Get the number of uniforms.
  220. int num_uniforms = -1;
  221. gpu(glGetProgramiv(_name, GL_ACTIVE_UNIFORMS, &num_uniforms));
  222. // Get the max name length.
  223. int max_length = get_max_uniform_name_length();
  224. // Loop over each uniform, collecting names.
  225. for(int i=0; i<num_uniforms; ++i) {
  226. std::string name;
  227. name.resize(max_length);
  228. int size=-1;
  229. GLenum type = GL_ZERO;
  230. int written = 0;
  231. glGetActiveUniform(_name, GLuint(i), max_length, &written, &size, &type, &name[0] );
  232. name.resize(written);
  233. names.push_back(name);
  234. }
  235. }
  236. std::vector<GLuint> Program::get_uniform_indices() {
  237. std::vector<GLuint> indices;
  238. GLint num = get_num_uniforms();
  239. indices.resize(num);
  240. for (GLint i = 0; i < num; i++) {
  241. indices[i] = i;
  242. }
  243. return indices;
  244. }
  245. // This is for uniforms in named blocks.
  246. #if GLES_MAJOR_VERSION >= 3
  247. std::vector<GLuint> Program::get_uniform_indices(std::vector<std::string>& uniform_names) {
  248. GLsizei num = static_cast<GLsizei>(uniform_names.size());
  249. std::vector<const char*> temp;
  250. temp.resize(num);
  251. for (int i = 0; i < num; i++) {
  252. temp[i] = uniform_names[i].c_str();
  253. }
  254. std::vector<GLuint> indices;
  255. indices.resize(num);
  256. gpu(glGetUniformIndices(_name,num,&temp[0],&indices[0]));
  257. return indices;
  258. }
  259. #endif
  260. // --------------------------------------------------------------------------------------------------------------
  261. // Default uniforms.
  262. // --------------------------------------------------------------------------------------------------------------
  263. std::vector<GLuint> Program::get_default_uniform_indices() {
  264. std::vector<GLuint> all_indices = get_uniform_indices();
  265. GLsizei num = static_cast<GLsizei>(all_indices.size());
  266. std::vector<GLint> block_indices;
  267. block_indices.resize(num);
  268. std::vector<GLuint> indices;
  269. if (num == 0) {
  270. return indices;
  271. }
  272. // Get the block indices for all uniforms.
  273. // Default uniforms hava a block index of -1.
  274. #if GLES_MAJOR_VERSION >= 3
  275. gpu(glGetActiveUniformsiv(_name,num,&all_indices[0],GL_UNIFORM_BLOCK_INDEX,&block_indices[0]));
  276. #else
  277. for (size_t i = 0; i < all_indices.size(); i++) {
  278. char uniform_name[1024];
  279. GLsizei length;
  280. GLint size;
  281. GLenum type;
  282. glGetActiveUniform(_name, all_indices[i], 1024, &length, &size, &type,
  283. uniform_name);
  284. block_indices[i] = -1;
  285. // if (type == GL_UNIFORM_BLOCK_INDEX) {
  286. // block_indices[i] = 1; // Note this should actually be the block index of the uniform.
  287. // } else {
  288. // block_indices[i] = -1;
  289. // }
  290. }
  291. #endif
  292. for (size_t i = 0; i < block_indices.size(); i++) {
  293. if (block_indices[i] == -1) {
  294. indices.push_back(static_cast<GLuint>(i));
  295. }
  296. }
  297. return indices;
  298. }
  299. // This is for uniforms in the default unnamed block.
  300. // returns -1 on error.
  301. GLint Program::get_default_uniform_location(const char* name) {
  302. gpu(GLint location=glGetUniformLocation(_name,name););
  303. return location;
  304. }
  305. DefaultUniformInfo* Program::create_default_uniform_info(GLuint uniform_index) {
  306. std::string name;
  307. GLsizei buffer_size = get_max_uniform_name_length();
  308. name.resize(buffer_size);
  309. GLsizei written;
  310. GLint size;
  311. GLenum data_type;
  312. gpu(glGetActiveUniform(_name, uniform_index, buffer_size, &written, &size, &data_type, &name[0]));
  313. name.resize(written);
  314. GLint location = 0;
  315. if (size == 1) {
  316. location = get_default_uniform_location(name.c_str());
  317. } else {
  318. std::string start_name = name + "[0]";
  319. location = get_default_uniform_location(start_name.c_str());
  320. }
  321. // fill in the uniform_type
  322. DefaultUniformInfo* info = new_ff DefaultUniformInfo();
  323. info->set_name(name);
  324. info->set_type(data_type);
  325. info->set_num_elements(size);
  326. info->set_index(uniform_index);
  327. info->set_location(location);
  328. return info;
  329. }
  330. std::vector<DefaultUniformInfo*> Program::create_default_uniform_infos() {
  331. std::vector<GLuint> indices = get_default_uniform_indices();
  332. std::vector<DefaultUniformInfo*> infos;
  333. infos.reserve(indices.size());
  334. for (size_t i = 0; i < indices.size(); i++) {
  335. DefaultUniformInfo* info = create_default_uniform_info(indices[i]);
  336. infos.push_back(info);
  337. }
  338. return infos;
  339. }
  340. // --------------------------------------------------------------------------------------------------------------
  341. // Uniform Blocks.
  342. // --------------------------------------------------------------------------------------------------------------
  343. #if GLES_MAJOR_VERSION >= 3
  344. GLint Program::get_num_uniform_blocks() {
  345. GLint num;
  346. gpu(glGetProgramiv(_name,GL_ACTIVE_UNIFORM_BLOCKS,&num));
  347. return num;
  348. }
  349. GLuint Program::get_uniform_block_index(const char* block_name) {
  350. gpu(GLuint index=glGetUniformBlockIndex(_name,block_name););
  351. return index;
  352. }
  353. std::string Program::get_uniform_block_name(GLuint block_index) {
  354. std::string name;
  355. GLsizei buffer_size = get_max_uniform_name_length();
  356. name.resize(buffer_size);
  357. GLsizei written = 0;
  358. gpu(glGetActiveUniformBlockName(_name,block_index, buffer_size, &written, &name[0]));
  359. name.resize(written);
  360. return name;
  361. }
  362. GLint Program::get_uniform_block_size(GLuint block_index) {
  363. GLint size;
  364. gpu(glGetActiveUniformBlockiv(_name,block_index,GL_UNIFORM_BLOCK_DATA_SIZE,&size));
  365. return size;
  366. }
  367. #endif
  368. // --------------------------------------------------------------------------------------------------------------
  369. // Block Uniforms.
  370. // --------------------------------------------------------------------------------------------------------------
  371. #if GLES_MAJOR_VERSION >= 3
  372. std::vector<GLint> Program::get_block_uniform_indices(GLuint block_index) {
  373. GLint num_indices;
  374. gpu(glGetActiveUniformBlockiv(_name,block_index,GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &num_indices));
  375. std::vector<GLint> indices;
  376. indices.resize(num_indices);
  377. gpu(glGetActiveUniformBlockiv(_name,block_index,GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &indices[0]));
  378. return indices;
  379. }
  380. std::vector<GLuint> Program::get_block_uniform_indices() {
  381. std::vector<GLuint> all_indices = get_uniform_indices();
  382. GLsizei num = static_cast<GLsizei>(all_indices.size());
  383. std::vector<GLint> block_indices;
  384. block_indices.resize(num);
  385. std::vector<GLuint> indices;
  386. if (num == 0) {
  387. return indices;
  388. }
  389. // Get the block indices for all uniforms.
  390. // Default uniforms hava a block index of -1.
  391. if (glGetActiveUniformsiv) {
  392. gpu(glGetActiveUniformsiv(_name,num,&all_indices[0],GL_UNIFORM_BLOCK_INDEX,&block_indices[0]));
  393. } else {
  394. for (size_t i = 0; i < all_indices.size(); i++) {
  395. char uniform_name[1024];
  396. GLsizei length;
  397. GLint size;
  398. GLenum type;
  399. glGetActiveUniform(_name, all_indices[i], 1024, &length, &size, &type,
  400. uniform_name);
  401. if (type == GL_UNIFORM_BLOCK_INDEX) {
  402. block_indices[i] = 1; // Note this should actually be the block index of the uniform.
  403. } else {
  404. block_indices[i] = -1;
  405. }
  406. }
  407. }
  408. indices.clear();
  409. for (size_t i = 0; i < block_indices.size(); i++) {
  410. if (block_indices[i] != -1) {
  411. indices.push_back(static_cast<GLuint>(i));
  412. }
  413. }
  414. return indices;
  415. }
  416. GLint Program::get_block_uniform_offset(GLuint uniform_index) {
  417. GLint offset;
  418. gpu(glGetActiveUniformsiv(_name,1,&uniform_index,GL_UNIFORM_OFFSET,&offset));
  419. return offset;
  420. }
  421. std::vector<GLint> Program::get_block_uniform_offsets(const std::vector<GLuint>& uniform_indices) {
  422. size_t num = uniform_indices.size();
  423. std::vector<GLint> offsets;
  424. offsets.resize(num);
  425. // Note other info can be retrieved with this command also.
  426. gpu(glGetActiveUniformsiv(_name,static_cast<GLsizei>(num),&uniform_indices[0],GL_UNIFORM_OFFSET,&offsets[0]));
  427. return offsets;
  428. }
  429. BlockUniformInfo* Program::create_block_uniform_info(GLuint uniform_index) {
  430. std::string name;
  431. GLsizei buffer_size = get_max_uniform_name_length();
  432. name.resize(buffer_size);
  433. GLsizei written;
  434. GLint size;
  435. GLenum type;
  436. gpu(glGetActiveUniform(_name, uniform_index, buffer_size, &written, &size, &type, &name[0]));
  437. name.resize(written);
  438. GLint offset = get_block_uniform_offset(uniform_index);
  439. GLint block_index = get_uniform_block_index_for_block_uniform(uniform_index);
  440. // fill in the uniform_type
  441. BlockUniformInfo* info = new_ff BlockUniformInfo();
  442. info->set_name(name);
  443. info->set_type(type);
  444. info->set_num_elements(size);
  445. info->set_index(uniform_index);
  446. info->set_block_index(block_index);
  447. info->set_offset_bytes(offset);
  448. return info;
  449. }
  450. GLint Program::get_uniform_block_index_for_block_uniform(GLuint uniform_index) {
  451. GLint block_index;
  452. gpu(glGetActiveUniformsiv(_name,1,&uniform_index,GL_UNIFORM_BLOCK_INDEX,&block_index));
  453. return block_index;
  454. }
  455. #endif
  456. #if GLES_MAJOR_VERSION >= 3
  457. std::vector<BlockUniformInfo*> Program::create_block_uniform_infos(const char* name) {
  458. GLuint block_index = get_uniform_block_index(name);
  459. return create_block_uniform_infos(block_index);
  460. }
  461. std::vector<BlockUniformInfo*> Program::create_block_uniform_infos(GLuint block_index) {
  462. std::vector<GLint> indices = get_block_uniform_indices(block_index);
  463. size_t num = indices.size();
  464. std::vector<BlockUniformInfo*> infos;
  465. infos.reserve(num);
  466. for (size_t i = 0; i < num; i++) {
  467. BlockUniformInfo* info = create_block_uniform_info(indices[i]);
  468. infos.push_back(info);
  469. }
  470. return infos;
  471. }
  472. std::vector<BlockUniformInfo*> Program::create_block_uniform_infos() {
  473. std::vector<GLuint> indices = get_block_uniform_indices();
  474. std::vector<BlockUniformInfo*> infos;
  475. infos.reserve(indices.size());
  476. for (size_t i = 0; i < indices.size(); i++) {
  477. BlockUniformInfo* info = create_block_uniform_info(indices[i]);
  478. infos.push_back(info);
  479. }
  480. return infos;
  481. }
  482. #endif
  483. // --------------------------------------------------------------------------------------------------------------
  484. // Uniform Block Bindings.
  485. // --------------------------------------------------------------------------------------------------------------
  486. #if GLES_MAJOR_VERSION >= 3
  487. GLint Program::get_max_uniform_block_binding() {
  488. GLint max;
  489. gpu(glGetProgramiv(_name,GL_MAX_UNIFORM_BUFFER_BINDINGS,&max));
  490. return max;
  491. }
  492. void Program::set_uniform_block_binding(GLuint block_index,
  493. GLuint uniform_block_binding) {
  494. gpu(glUniformBlockBinding(_name,block_index,uniform_block_binding));
  495. }
  496. #endif
  497. // --------------------------------------------------------------------------------------------------------------
  498. // Internals.
  499. // --------------------------------------------------------------------------------------------------------------
  500. }