PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/mesa/main/shader_query.cpp

https://gitlab.com/MJDSys/mesa
C++ | 500 lines | 296 code | 91 blank | 113 comment | 116 complexity | 944d5960a76ae5d620e62460f848c150 MD5 | raw file
Possible License(s): LGPL-2.0
  1. /*
  2. * Copyright © 2011 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. * DEALINGS IN THE SOFTWARE.
  22. */
  23. /**
  24. * \file shader_query.cpp
  25. * C-to-C++ bridge functions to query GLSL shader data
  26. *
  27. * \author Ian Romanick <ian.d.romanick@intel.com>
  28. */
  29. #include "main/core.h"
  30. #include "glsl_symbol_table.h"
  31. #include "ir.h"
  32. #include "shaderobj.h"
  33. #include "program/hash_table.h"
  34. #include "../glsl/program.h"
  35. extern "C" {
  36. #include "shaderapi.h"
  37. }
  38. void GLAPIENTRY
  39. _mesa_BindAttribLocation(GLhandleARB program, GLuint index,
  40. const GLcharARB *name)
  41. {
  42. GET_CURRENT_CONTEXT(ctx);
  43. struct gl_shader_program *const shProg =
  44. _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
  45. if (!shProg)
  46. return;
  47. if (!name)
  48. return;
  49. if (strncmp(name, "gl_", 3) == 0) {
  50. _mesa_error(ctx, GL_INVALID_OPERATION,
  51. "glBindAttribLocation(illegal name)");
  52. return;
  53. }
  54. if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
  55. _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
  56. return;
  57. }
  58. /* Replace the current value if it's already in the list. Add
  59. * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
  60. * between built-in attributes and user-defined attributes.
  61. */
  62. shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
  63. /*
  64. * Note that this attribute binding won't go into effect until
  65. * glLinkProgram is called again.
  66. */
  67. }
  68. static bool
  69. is_active_attrib(const ir_variable *var)
  70. {
  71. if (!var)
  72. return false;
  73. switch (var->data.mode) {
  74. case ir_var_shader_in:
  75. return var->data.location != -1;
  76. case ir_var_system_value:
  77. /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes):
  78. * "For GetActiveAttrib, all active vertex shader input variables
  79. * are enumerated, including the special built-in inputs gl_VertexID
  80. * and gl_InstanceID."
  81. */
  82. return var->data.location == SYSTEM_VALUE_VERTEX_ID ||
  83. var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE ||
  84. var->data.location == SYSTEM_VALUE_INSTANCE_ID;
  85. default:
  86. return false;
  87. }
  88. }
  89. void GLAPIENTRY
  90. _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
  91. GLsizei maxLength, GLsizei * length, GLint * size,
  92. GLenum * type, GLcharARB * name)
  93. {
  94. GET_CURRENT_CONTEXT(ctx);
  95. struct gl_shader_program *shProg;
  96. if (maxLength < 0) {
  97. _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)");
  98. return;
  99. }
  100. shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
  101. if (!shProg)
  102. return;
  103. if (!shProg->LinkStatus) {
  104. _mesa_error(ctx, GL_INVALID_VALUE,
  105. "glGetActiveAttrib(program not linked)");
  106. return;
  107. }
  108. if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  109. _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
  110. return;
  111. }
  112. exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
  113. unsigned current_index = 0;
  114. foreach_in_list(ir_instruction, node, ir) {
  115. const ir_variable *const var = node->as_variable();
  116. if (!is_active_attrib(var))
  117. continue;
  118. if (current_index == desired_index) {
  119. const char *var_name = var->name;
  120. /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to
  121. * consider gl_VertexIDMESA as gl_VertexID for purposes of checking
  122. * active attributes.
  123. */
  124. if (var->data.mode == ir_var_system_value &&
  125. var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
  126. var_name = "gl_VertexID";
  127. }
  128. _mesa_copy_string(name, maxLength, length, var_name);
  129. if (size)
  130. *size = (var->type->is_array()) ? var->type->length : 1;
  131. if (type)
  132. *type = var->type->gl_type;
  133. return;
  134. }
  135. current_index++;
  136. }
  137. /* If the loop did not return early, the caller must have asked for
  138. * an index that did not exit. Set an error.
  139. */
  140. _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
  141. }
  142. /* Locations associated with shader variables (array or non-array) can be
  143. * queried using its base name or using the base name appended with the
  144. * valid array index. For example, in case of below vertex shader, valid
  145. * queries can be made to know the location of "xyz", "array", "array[0]",
  146. * "array[1]", "array[2]" and "array[3]". In this example index reurned
  147. * will be 0, 0, 0, 1, 2, 3 respectively.
  148. *
  149. * [Vertex Shader]
  150. * layout(location=0) in vec4 xyz;
  151. * layout(location=1) in vec4[4] array;
  152. * void main()
  153. * { }
  154. *
  155. * This requirement came up with the addition of ARB_program_interface_query
  156. * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details.
  157. *
  158. * This utility function is used by:
  159. * _mesa_GetAttribLocation
  160. * _mesa_GetFragDataLocation
  161. * _mesa_GetFragDataIndex
  162. *
  163. * Returns 0:
  164. * if the 'name' string matches var->name.
  165. * Returns 'matched index':
  166. * if the 'name' string matches var->name appended with valid array index.
  167. */
  168. int static inline
  169. get_matching_index(const ir_variable *const var, const char *name) {
  170. unsigned idx = 0;
  171. const char *const paren = strchr(name, '[');
  172. const unsigned len = (paren != NULL) ? paren - name : strlen(name);
  173. if (paren != NULL) {
  174. if (!var->type->is_array())
  175. return -1;
  176. char *endptr;
  177. idx = (unsigned) strtol(paren + 1, &endptr, 10);
  178. const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0;
  179. /* Validate the sub string representing index in 'name' string */
  180. if ((idx > 0 && paren[1] == '0') /* leading zeroes */
  181. || (idx == 0 && idx_len > 1) /* all zeroes */
  182. || paren[1] == ' ' /* whitespace */
  183. || endptr[0] != ']' /* closing brace */
  184. || endptr[1] != '\0' /* null char */
  185. || idx_len == 0 /* missing index */
  186. || idx >= var->type->length) /* exceeding array bound */
  187. return -1;
  188. }
  189. if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0')
  190. return idx;
  191. return -1;
  192. }
  193. GLint GLAPIENTRY
  194. _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
  195. {
  196. GET_CURRENT_CONTEXT(ctx);
  197. struct gl_shader_program *const shProg =
  198. _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
  199. if (!shProg) {
  200. return -1;
  201. }
  202. if (!shProg->LinkStatus) {
  203. _mesa_error(ctx, GL_INVALID_OPERATION,
  204. "glGetAttribLocation(program not linked)");
  205. return -1;
  206. }
  207. if (!name)
  208. return -1;
  209. /* Not having a vertex shader is not an error.
  210. */
  211. if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
  212. return -1;
  213. exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
  214. foreach_in_list(ir_instruction, node, ir) {
  215. const ir_variable *const var = node->as_variable();
  216. /* The extra check against VERT_ATTRIB_GENERIC0 is because
  217. * glGetAttribLocation cannot be used on "conventional" attributes.
  218. *
  219. * From page 95 of the OpenGL 3.0 spec:
  220. *
  221. * "If name is not an active attribute, if name is a conventional
  222. * attribute, or if an error occurs, -1 will be returned."
  223. */
  224. if (var == NULL
  225. || var->data.mode != ir_var_shader_in
  226. || var->data.location == -1
  227. || var->data.location < VERT_ATTRIB_GENERIC0)
  228. continue;
  229. int index = get_matching_index(var, (const char *) name);
  230. if (index >= 0)
  231. return var->data.location + index - VERT_ATTRIB_GENERIC0;
  232. }
  233. return -1;
  234. }
  235. unsigned
  236. _mesa_count_active_attribs(struct gl_shader_program *shProg)
  237. {
  238. if (!shProg->LinkStatus
  239. || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  240. return 0;
  241. }
  242. exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
  243. unsigned i = 0;
  244. foreach_in_list(ir_instruction, node, ir) {
  245. const ir_variable *const var = node->as_variable();
  246. if (!is_active_attrib(var))
  247. continue;
  248. i++;
  249. }
  250. return i;
  251. }
  252. size_t
  253. _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
  254. {
  255. if (!shProg->LinkStatus
  256. || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
  257. return 0;
  258. }
  259. exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
  260. size_t longest = 0;
  261. foreach_in_list(ir_instruction, node, ir) {
  262. const ir_variable *const var = node->as_variable();
  263. if (var == NULL
  264. || var->data.mode != ir_var_shader_in
  265. || var->data.location == -1)
  266. continue;
  267. const size_t len = strlen(var->name);
  268. if (len >= longest)
  269. longest = len + 1;
  270. }
  271. return longest;
  272. }
  273. void GLAPIENTRY
  274. _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
  275. const GLchar *name)
  276. {
  277. _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
  278. }
  279. void GLAPIENTRY
  280. _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
  281. GLuint index, const GLchar *name)
  282. {
  283. GET_CURRENT_CONTEXT(ctx);
  284. struct gl_shader_program *const shProg =
  285. _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
  286. if (!shProg)
  287. return;
  288. if (!name)
  289. return;
  290. if (strncmp(name, "gl_", 3) == 0) {
  291. _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
  292. return;
  293. }
  294. if (index > 1) {
  295. _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
  296. return;
  297. }
  298. if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
  299. _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
  300. return;
  301. }
  302. if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
  303. _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
  304. return;
  305. }
  306. /* Replace the current value if it's already in the list. Add
  307. * FRAG_RESULT_DATA0 because that's how the linker differentiates
  308. * between built-in attributes and user-defined attributes.
  309. */
  310. shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
  311. shProg->FragDataIndexBindings->put(index, name);
  312. /*
  313. * Note that this binding won't go into effect until
  314. * glLinkProgram is called again.
  315. */
  316. }
  317. GLint GLAPIENTRY
  318. _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
  319. {
  320. GET_CURRENT_CONTEXT(ctx);
  321. struct gl_shader_program *const shProg =
  322. _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
  323. if (!shProg) {
  324. return -1;
  325. }
  326. if (!shProg->LinkStatus) {
  327. _mesa_error(ctx, GL_INVALID_OPERATION,
  328. "glGetFragDataIndex(program not linked)");
  329. return -1;
  330. }
  331. if (!name)
  332. return -1;
  333. if (strncmp(name, "gl_", 3) == 0) {
  334. _mesa_error(ctx, GL_INVALID_OPERATION,
  335. "glGetFragDataIndex(illegal name)");
  336. return -1;
  337. }
  338. /* Not having a fragment shader is not an error.
  339. */
  340. if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
  341. return -1;
  342. exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
  343. foreach_in_list(ir_instruction, node, ir) {
  344. const ir_variable *const var = node->as_variable();
  345. /* The extra check against FRAG_RESULT_DATA0 is because
  346. * glGetFragDataLocation cannot be used on "conventional" attributes.
  347. *
  348. * From page 95 of the OpenGL 3.0 spec:
  349. *
  350. * "If name is not an active attribute, if name is a conventional
  351. * attribute, or if an error occurs, -1 will be returned."
  352. */
  353. if (var == NULL
  354. || var->data.mode != ir_var_shader_out
  355. || var->data.location == -1
  356. || var->data.location < FRAG_RESULT_DATA0)
  357. continue;
  358. if (get_matching_index(var, (const char *) name) >= 0)
  359. return var->data.index;
  360. }
  361. return -1;
  362. }
  363. GLint GLAPIENTRY
  364. _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
  365. {
  366. GET_CURRENT_CONTEXT(ctx);
  367. struct gl_shader_program *const shProg =
  368. _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
  369. if (!shProg) {
  370. return -1;
  371. }
  372. if (!shProg->LinkStatus) {
  373. _mesa_error(ctx, GL_INVALID_OPERATION,
  374. "glGetFragDataLocation(program not linked)");
  375. return -1;
  376. }
  377. if (!name)
  378. return -1;
  379. if (strncmp(name, "gl_", 3) == 0) {
  380. _mesa_error(ctx, GL_INVALID_OPERATION,
  381. "glGetFragDataLocation(illegal name)");
  382. return -1;
  383. }
  384. /* Not having a fragment shader is not an error.
  385. */
  386. if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
  387. return -1;
  388. exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
  389. foreach_in_list(ir_instruction, node, ir) {
  390. const ir_variable *const var = node->as_variable();
  391. /* The extra check against FRAG_RESULT_DATA0 is because
  392. * glGetFragDataLocation cannot be used on "conventional" attributes.
  393. *
  394. * From page 95 of the OpenGL 3.0 spec:
  395. *
  396. * "If name is not an active attribute, if name is a conventional
  397. * attribute, or if an error occurs, -1 will be returned."
  398. */
  399. if (var == NULL
  400. || var->data.mode != ir_var_shader_out
  401. || var->data.location == -1
  402. || var->data.location < FRAG_RESULT_DATA0)
  403. continue;
  404. int index = get_matching_index(var, (const char *) name);
  405. if (index >= 0)
  406. return var->data.location + index - FRAG_RESULT_DATA0;
  407. }
  408. return -1;
  409. }