1b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick/*
2b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * Copyright © 2011 Intel Corporation
3b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick *
4b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * Permission is hereby granted, free of charge, to any person obtaining a
5b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * copy of this software and associated documentation files (the "Software"),
6b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * to deal in the Software without restriction, including without limitation
7b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * and/or sell copies of the Software, and to permit persons to whom the
9b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * Software is furnished to do so, subject to the following conditions:
10b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick *
11b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * The above copyright notice and this permission notice (including the next
12b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * paragraph) shall be included in all copies or substantial portions of the
13b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * Software.
14b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick *
15b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * DEALINGS IN THE SOFTWARE.
22b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick */
23b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
24b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick/**
25b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * \file shader_query.cpp
26b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * C-to-C++ bridge functions to query GLSL shader data
27b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick *
28b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick * \author Ian Romanick <ian.d.romanick@intel.com>
29b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick */
30b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
31b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick#include "main/core.h"
32b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick#include "glsl_symbol_table.h"
33b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick#include "ir.h"
34b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick#include "shaderobj.h"
35015d4f61ef9116c9e844299ab9f2b15c653c0450Ian Romanick#include "program/hash_table.h"
3684d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick#include "../glsl/program.h"
37b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
38b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanickextern "C" {
39b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick#include "shaderapi.h"
40b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick}
41b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
422fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanickvoid GLAPIENTRY
432fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
442fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick                            const GLcharARB *name)
452fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick{
462fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   GET_CURRENT_CONTEXT(ctx);
472fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
482fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   struct gl_shader_program *const shProg =
492fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
502fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   if (!shProg)
512fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      return;
522fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
532fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   if (!name)
542fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      return;
552fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
562fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   if (strncmp(name, "gl_", 3) == 0) {
572fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      _mesa_error(ctx, GL_INVALID_OPERATION,
582fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick                  "glBindAttribLocation(illegal name)");
592fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      return;
602fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   }
612fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
622fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   if (index >= ctx->Const.VertexProgram.MaxAttribs) {
632fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
642fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick      return;
652fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   }
662fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
67a339ee8d852c08ce7af51a518e0b18b9f0ab324cIan Romanick   /* Replace the current value if it's already in the list.  Add
68a339ee8d852c08ce7af51a518e0b18b9f0ab324cIan Romanick    * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
69015d4f61ef9116c9e844299ab9f2b15c653c0450Ian Romanick    * between built-in attributes and user-defined attributes.
70015d4f61ef9116c9e844299ab9f2b15c653c0450Ian Romanick    */
71015d4f61ef9116c9e844299ab9f2b15c653c0450Ian Romanick   shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
722fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
732fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick   /*
742fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick    * Note that this attribute binding won't go into effect until
752fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick    * glLinkProgram is called again.
762fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick    */
772fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick}
782fd80534f01a5c684c47eff3946f412192ae3c0bIan Romanick
797a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanickvoid GLAPIENTRY
8084d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick_mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index,
817a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick                         GLsizei maxLength, GLsizei * length, GLint * size,
827a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick                         GLenum * type, GLcharARB * name)
837a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick{
847a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick   GET_CURRENT_CONTEXT(ctx);
857a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick   struct gl_shader_program *shProg;
867a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
877a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
887a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick   if (!shProg)
897a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick      return;
907a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
9184d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   if (!shProg->LinkStatus) {
9284d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      _mesa_error(ctx, GL_INVALID_VALUE,
9384d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick                  "glGetActiveAttrib(program not linked)");
9484d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      return;
9584d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   }
967a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
9784d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
9884d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
997a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick      return;
1007a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick   }
1017a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
10284d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
10384d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   unsigned current_index = 0;
10484d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
10584d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   foreach_list(node, ir) {
10684d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
10784d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
10884d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      if (var == NULL
10984d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	  || var->mode != ir_var_in
110e6c314f7d2ed99714376fec6b7509a55535fa3ffIan Romanick	  || var->location == -1)
11184d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	 continue;
11284d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
11384d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      if (current_index == desired_index) {
11484d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	 _mesa_copy_string(name, maxLength, length, var->name);
1157a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
11684d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	 if (size)
11784d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	    *size = (var->type->is_array()) ? var->type->length : 1;
1187a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
11984d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	 if (type)
12084d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	    *type = var->type->gl_type;
12184d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
12284d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick	 return;
12384d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      }
12484d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
12584d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick      current_index++;
12684d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   }
12784d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick
12884d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   /* If the loop did not return early, the caller must have asked for
12984d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick    * an index that did not exit.  Set an error.
13084d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick    */
13184d71a07bb06fe5fe231b8983558fbd3608ec6f0Ian Romanick   _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
1327a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick}
1337a80c1bbc56b61525634f2b699f995e863dfade2Ian Romanick
134b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan RomanickGLint GLAPIENTRY
135b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
136b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick{
137b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   GET_CURRENT_CONTEXT(ctx);
138b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   struct gl_shader_program *const shProg =
139b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
140b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
141b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   if (!shProg) {
142b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      return -1;
143b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   }
144b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
145b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   if (!shProg->LinkStatus) {
146b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      _mesa_error(ctx, GL_INVALID_OPERATION,
147b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick                  "glGetAttribLocation(program not linked)");
148b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      return -1;
149b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   }
150b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
151b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   if (!name)
152b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      return -1;
153b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
154b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   /* Not having a vertex shader is not an error.
155b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick    */
156b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
157b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      return -1;
158b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
159b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
160b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   foreach_list(node, ir) {
161b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
162b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
163b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      /* The extra check against VERT_ATTRIB_GENERIC0 is because
164b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       * glGetAttribLocation cannot be used on "conventional" attributes.
165b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       *
166b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       * From page 95 of the OpenGL 3.0 spec:
167b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       *
168b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       *     "If name is not an active attribute, if name is a conventional
169b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       *     attribute, or if an error occurs, -1 will be returned."
170b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick       */
171b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      if (var == NULL
172b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick	  || var->mode != ir_var_in
173b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick	  || var->location == -1
174b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick	  || var->location < VERT_ATTRIB_GENERIC0)
175b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick	 continue;
176b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
177b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick      if (strcmp(var->name, name) == 0)
178b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick	 return var->location - VERT_ATTRIB_GENERIC0;
179b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   }
180b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick
181b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick   return -1;
182b7fa0d0727a3a9e1f64d3cfc7a0f157b35dec09eIan Romanick}
183c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
184c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
185c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanickunsigned
186c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick_mesa_count_active_attribs(struct gl_shader_program *shProg)
187c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick{
188c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   if (!shProg->LinkStatus
189c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick       || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
190c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick      return 0;
191c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   }
192c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
193c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
194c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   unsigned i = 0;
195c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
196c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   foreach_list(node, ir) {
197c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
198c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
199c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick      if (var == NULL
200c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick	  || var->mode != ir_var_in
201e6c314f7d2ed99714376fec6b7509a55535fa3ffIan Romanick	  || var->location == -1)
202c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick	 continue;
203c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
204c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick      i++;
205c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   }
206c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick
207c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick   return i;
208c097c63aa880e2b84e6b1d78a8808d42864f72fcIan Romanick}
20924409ba1968cc49cbde6a111464c91271babc68aIan Romanick
21024409ba1968cc49cbde6a111464c91271babc68aIan Romanick
21124409ba1968cc49cbde6a111464c91271babc68aIan Romanicksize_t
21224409ba1968cc49cbde6a111464c91271babc68aIan Romanick_mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
21324409ba1968cc49cbde6a111464c91271babc68aIan Romanick{
21424409ba1968cc49cbde6a111464c91271babc68aIan Romanick   if (!shProg->LinkStatus
21524409ba1968cc49cbde6a111464c91271babc68aIan Romanick       || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
21624409ba1968cc49cbde6a111464c91271babc68aIan Romanick      return 0;
21724409ba1968cc49cbde6a111464c91271babc68aIan Romanick   }
21824409ba1968cc49cbde6a111464c91271babc68aIan Romanick
21924409ba1968cc49cbde6a111464c91271babc68aIan Romanick   exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
22024409ba1968cc49cbde6a111464c91271babc68aIan Romanick   size_t longest = 0;
22124409ba1968cc49cbde6a111464c91271babc68aIan Romanick
22224409ba1968cc49cbde6a111464c91271babc68aIan Romanick   foreach_list(node, ir) {
22324409ba1968cc49cbde6a111464c91271babc68aIan Romanick      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
22424409ba1968cc49cbde6a111464c91271babc68aIan Romanick
22524409ba1968cc49cbde6a111464c91271babc68aIan Romanick      if (var == NULL
22624409ba1968cc49cbde6a111464c91271babc68aIan Romanick	  || var->mode != ir_var_in
227e6c314f7d2ed99714376fec6b7509a55535fa3ffIan Romanick	  || var->location == -1)
22824409ba1968cc49cbde6a111464c91271babc68aIan Romanick	 continue;
22924409ba1968cc49cbde6a111464c91271babc68aIan Romanick
23024409ba1968cc49cbde6a111464c91271babc68aIan Romanick      const size_t len = strlen(var->name);
23124409ba1968cc49cbde6a111464c91271babc68aIan Romanick      if (len >= longest)
23224409ba1968cc49cbde6a111464c91271babc68aIan Romanick	 longest = len + 1;
23324409ba1968cc49cbde6a111464c91271babc68aIan Romanick   }
23424409ba1968cc49cbde6a111464c91271babc68aIan Romanick
23524409ba1968cc49cbde6a111464c91271babc68aIan Romanick   return longest;
23624409ba1968cc49cbde6a111464c91271babc68aIan Romanick}
2374464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
2384464a4b27b66f832acbe52b0a002c04415924c14Ian Romanickvoid GLAPIENTRY
2394464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
2404464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick			   const GLchar *name)
2414464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick{
242f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
243f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie}
244f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
245f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlievoid GLAPIENTRY
246f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie_mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
247f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie                                  GLuint index, const GLchar *name)
248f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie{
2494464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   GET_CURRENT_CONTEXT(ctx);
2504464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
2514464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   struct gl_shader_program *const shProg =
252f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
2534464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   if (!shProg)
2544464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick      return;
2554464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
2564464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   if (!name)
2574464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick      return;
2584464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
2594464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   if (strncmp(name, "gl_", 3) == 0) {
260f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
261f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return;
262f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
263f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
264f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (index > 1) {
265f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
266f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return;
267f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
268f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
269f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
270f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
2714464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick      return;
2724464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   }
2734464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
274f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
275f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
2764464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick      return;
2774464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   }
2784464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick
2794464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   /* Replace the current value if it's already in the list.  Add
2804464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    * FRAG_RESULT_DATA0 because that's how the linker differentiates
2814464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    * between built-in attributes and user-defined attributes.
2824464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    */
283b12b5d9ab5c0153c93ca5ad9cd93cb36e41be4ebIan Romanick   shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
284f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   shProg->FragDataIndexBindings->put(index, name);
2854464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick   /*
2864464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    * Note that this binding won't go into effect until
2874464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    * glLinkProgram is called again.
2884464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick    */
289f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
290f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie}
291f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
292f8cf79936b42405a8366613b80e3bde21aadaa02Dave AirlieGLint GLAPIENTRY
293f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie_mesa_GetFragDataIndex(GLuint program, const GLchar *name)
294f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie{
295f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   GET_CURRENT_CONTEXT(ctx);
296f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   struct gl_shader_program *const shProg =
297f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
298f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
299f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (!shProg) {
300f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return -1;
301f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
302f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
303f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (!shProg->LinkStatus) {
304f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_OPERATION,
305f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie                  "glGetFragDataIndex(program not linked)");
306f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return -1;
307f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
308f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
309f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (!name)
310f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return -1;
311f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
312f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (strncmp(name, "gl_", 3) == 0) {
313f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      _mesa_error(ctx, GL_INVALID_OPERATION,
314f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie                  "glGetFragDataIndex(illegal name)");
315f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return -1;
316f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
317f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
318f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   /* Not having a fragment shader is not an error.
319f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie    */
320f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
321f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      return -1;
322f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
323f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
324f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   foreach_list(node, ir) {
325f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
326f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
327f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      /* The extra check against FRAG_RESULT_DATA0 is because
328f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       * glGetFragDataLocation cannot be used on "conventional" attributes.
329f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       *
330f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       * From page 95 of the OpenGL 3.0 spec:
331f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       *
332f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       *     "If name is not an active attribute, if name is a conventional
333f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       *     attribute, or if an error occurs, -1 will be returned."
334f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie       */
335f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      if (var == NULL
336f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie          || var->mode != ir_var_out
337f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie          || var->location == -1
338f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie          || var->location < FRAG_RESULT_DATA0)
339f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie         continue;
340f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
341f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie      if (strcmp(var->name, name) == 0)
342f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie         return var->index;
343f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   }
344f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie
345f8cf79936b42405a8366613b80e3bde21aadaa02Dave Airlie   return -1;
3464464a4b27b66f832acbe52b0a002c04415924c14Ian Romanick}
34759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
34859012c31337f104aedfe69ca6d3cf784581df544Ian RomanickGLint GLAPIENTRY
34959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick_mesa_GetFragDataLocation(GLuint program, const GLchar *name)
35059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick{
35159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   GET_CURRENT_CONTEXT(ctx);
35259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   struct gl_shader_program *const shProg =
35359012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
35459012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
35559012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   if (!shProg) {
35659012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      return -1;
35759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   }
35859012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
35959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   if (!shProg->LinkStatus) {
36059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      _mesa_error(ctx, GL_INVALID_OPERATION,
36159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick                  "glGetFragDataLocation(program not linked)");
36259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      return -1;
36359012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   }
36459012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
36559012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   if (!name)
36659012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      return -1;
36759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
36859012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   if (strncmp(name, "gl_", 3) == 0) {
36959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      _mesa_error(ctx, GL_INVALID_OPERATION,
37059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick                  "glGetFragDataLocation(illegal name)");
37159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      return -1;
37259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   }
37359012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
37459012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   /* Not having a fragment shader is not an error.
37559012c31337f104aedfe69ca6d3cf784581df544Ian Romanick    */
37659012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
37759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      return -1;
37859012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
37959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
38059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   foreach_list(node, ir) {
38159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
38259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
38359012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      /* The extra check against FRAG_RESULT_DATA0 is because
38459012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       * glGetFragDataLocation cannot be used on "conventional" attributes.
38559012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       *
38659012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       * From page 95 of the OpenGL 3.0 spec:
38759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       *
38859012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       *     "If name is not an active attribute, if name is a conventional
38959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       *     attribute, or if an error occurs, -1 will be returned."
39059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick       */
39159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      if (var == NULL
39259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick	  || var->mode != ir_var_out
39359012c31337f104aedfe69ca6d3cf784581df544Ian Romanick	  || var->location == -1
39459012c31337f104aedfe69ca6d3cf784581df544Ian Romanick	  || var->location < FRAG_RESULT_DATA0)
39559012c31337f104aedfe69ca6d3cf784581df544Ian Romanick	 continue;
39659012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
39759012c31337f104aedfe69ca6d3cf784581df544Ian Romanick      if (strcmp(var->name, name) == 0)
39859012c31337f104aedfe69ca6d3cf784581df544Ian Romanick	 return var->location - FRAG_RESULT_DATA0;
39959012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   }
40059012c31337f104aedfe69ca6d3cf784581df544Ian Romanick
40159012c31337f104aedfe69ca6d3cf784581df544Ian Romanick   return -1;
40259012c31337f104aedfe69ca6d3cf784581df544Ian Romanick}
403