1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2013 Timothy Arceri All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "arrayobj.h"
27 #include "bufferobj.h"
28 #include "context.h"
29 #include "dlist.h"
30 #include "enums.h"
31 #include "fbobject.h"
32 #include "pipelineobj.h"
33 #include "queryobj.h"
34 #include "samplerobj.h"
35 #include "shaderobj.h"
36 #include "syncobj.h"
37 #include "texobj.h"
38 #include "transformfeedback.h"
39 #include "api_exec_decl.h"
40
41
42 /**
43 * Helper for _mesa_ObjectLabel() and _mesa_ObjectPtrLabel().
44 */
45 static void
set_label(struct gl_context * ctx,char ** labelPtr,const char * label,int length,const char * caller,bool ext_length)46 set_label(struct gl_context *ctx, char **labelPtr, const char *label,
47 int length, const char *caller, bool ext_length)
48 {
49 free(*labelPtr);
50 *labelPtr = NULL;
51
52 /* set new label string */
53 if (label) {
54 if ((!ext_length && length >= 0) ||
55 (ext_length && length > 0)) {
56 if (length >= MAX_LABEL_LENGTH)
57 _mesa_error(ctx, GL_INVALID_VALUE,
58 "%s(length=%d, which is not less than "
59 "GL_MAX_LABEL_LENGTH=%d)", caller, length,
60 MAX_LABEL_LENGTH);
61
62 /* explicit length */
63 *labelPtr = malloc(length+1);
64 if (*labelPtr) {
65 memcpy(*labelPtr, label, length);
66 /* length is not required to include the null terminator so
67 * add one just in case
68 */
69 (*labelPtr)[length] = '\0';
70 }
71 }
72 else {
73 if (ext_length && length < 0) {
74 _mesa_error(ctx, GL_INVALID_VALUE,
75 "%s(label length=%d, is less than zero)", caller,
76 length);
77 return;
78 }
79
80 int len = strlen(label);
81 if (len >= MAX_LABEL_LENGTH)
82 _mesa_error(ctx, GL_INVALID_VALUE,
83 "%s(label length=%d, which is not less than "
84 "GL_MAX_LABEL_LENGTH=%d)", caller, len,
85 MAX_LABEL_LENGTH);
86
87 /* null-terminated string */
88 *labelPtr = strdup(label);
89 }
90 }
91 }
92
93 /**
94 * Helper for _mesa_GetObjectLabel() and _mesa_GetObjectPtrLabel().
95 * \param src the src label (may be null)
96 * \param dst pointer to dest buffer (may be null)
97 * \param length returns length of label (may be null)
98 * \param bufsize size of dst buffer
99 */
100 static void
copy_label(const GLchar * src,GLchar * dst,GLsizei * length,GLsizei bufSize)101 copy_label(const GLchar *src, GLchar *dst, GLsizei *length, GLsizei bufSize)
102 {
103 int labelLen = 0;
104
105 /* From http://www.opengl.org/registry/specs/KHR/debug.txt:
106 * "If <length> is NULL, no length is returned. The maximum number of
107 * characters that may be written into <label>, including the null
108 * terminator, is specified by <bufSize>. If no debug label was specified
109 * for the object then <label> will contain a null-terminated empty string,
110 * and zero will be returned in <length>. If <label> is NULL and <length>
111 * is non-NULL then no string will be returned and the length of the label
112 * will be returned in <length>."
113 */
114
115 if (src)
116 labelLen = strlen(src);
117
118 if (bufSize == 0) {
119 if (length)
120 *length = labelLen;
121 return;
122 }
123
124 if (dst) {
125 if (src) {
126 if (bufSize <= labelLen)
127 labelLen = bufSize - 1;
128
129 memcpy(dst, src, labelLen);
130 }
131
132 dst[labelLen] = '\0';
133 }
134
135 if (length)
136 *length = labelLen;
137 }
138
139 /**
140 * Helper for _mesa_ObjectLabel() and _mesa_GetObjectLabel().
141 */
142 static char **
get_label_pointer(struct gl_context * ctx,GLenum identifier,GLuint name,const char * caller,bool ext_errors)143 get_label_pointer(struct gl_context *ctx, GLenum identifier, GLuint name,
144 const char *caller, bool ext_errors)
145 {
146 char **labelPtr = NULL;
147 GLenum no_match_error =
148 ext_errors ? GL_INVALID_OPERATION : GL_INVALID_VALUE;
149
150 switch (identifier) {
151 case GL_BUFFER:
152 case GL_BUFFER_OBJECT_EXT:
153 {
154 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
155 if (bufObj)
156 labelPtr = &bufObj->Label;
157 }
158 break;
159 case GL_SHADER:
160 case GL_SHADER_OBJECT_EXT:
161 {
162 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
163 if (shader)
164 labelPtr = &shader->Label;
165 }
166 break;
167 case GL_PROGRAM:
168 case GL_PROGRAM_OBJECT_EXT:
169 {
170 struct gl_shader_program *program =
171 _mesa_lookup_shader_program(ctx, name);
172 if (program)
173 labelPtr = &program->Label;
174 }
175 break;
176 case GL_VERTEX_ARRAY:
177 case GL_VERTEX_ARRAY_OBJECT_EXT:
178 {
179 struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, name);
180 if (obj)
181 labelPtr = &obj->Label;
182 }
183 break;
184 case GL_QUERY:
185 case GL_QUERY_OBJECT_EXT:
186 {
187 struct gl_query_object *query = _mesa_lookup_query_object(ctx, name);
188 if (query)
189 labelPtr = &query->Label;
190 }
191 break;
192 case GL_TRANSFORM_FEEDBACK:
193 {
194 /* From the GL 4.5 specification, page 536:
195 * "An INVALID_VALUE error is generated if name is not the name of a
196 * valid object of the type specified by identifier."
197 */
198 struct gl_transform_feedback_object *tfo =
199 _mesa_lookup_transform_feedback_object(ctx, name);
200 if (tfo && tfo->EverBound)
201 labelPtr = &tfo->Label;
202 }
203 break;
204 case GL_SAMPLER:
205 {
206 struct gl_sampler_object *so = _mesa_lookup_samplerobj(ctx, name);
207 if (so)
208 labelPtr = &so->Label;
209 }
210 break;
211 case GL_TEXTURE:
212 {
213 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
214 if (texObj && texObj->Target)
215 labelPtr = &texObj->Label;
216 }
217 break;
218 case GL_RENDERBUFFER:
219 {
220 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
221 if (rb)
222 labelPtr = &rb->Label;
223 }
224 break;
225 case GL_FRAMEBUFFER:
226 {
227 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, name);
228 if (rb)
229 labelPtr = &rb->Label;
230 }
231 break;
232 case GL_DISPLAY_LIST:
233 if (_mesa_is_desktop_gl_compat(ctx)) {
234 struct gl_display_list *list = _mesa_lookup_list(ctx, name, false);
235 if (list)
236 labelPtr = &list->Label;
237 }
238 else {
239 goto invalid_enum;
240 }
241 break;
242 case GL_PROGRAM_PIPELINE:
243 case GL_PROGRAM_PIPELINE_OBJECT_EXT:
244 {
245 struct gl_pipeline_object *pipe =
246 _mesa_lookup_pipeline_object(ctx, name);
247 if (pipe)
248 labelPtr = &pipe->Label;
249 }
250 break;
251 default:
252 goto invalid_enum;
253 }
254
255 if (NULL == labelPtr) {
256 _mesa_error(ctx, no_match_error, "%s(name = %u)", caller, name);
257 }
258
259 return labelPtr;
260
261 invalid_enum:
262 _mesa_error(ctx, GL_INVALID_ENUM, "%s(identifier = %s)",
263 caller, _mesa_enum_to_string(identifier));
264 return NULL;
265 }
266
267 void GLAPIENTRY
_mesa_LabelObjectEXT(GLenum identifier,GLuint name,GLsizei length,const GLchar * label)268 _mesa_LabelObjectEXT(GLenum identifier, GLuint name, GLsizei length,
269 const GLchar *label)
270 {
271 GET_CURRENT_CONTEXT(ctx);
272 const char *callerstr = "glLabelObjectEXT";
273 char **labelPtr;
274
275 labelPtr = get_label_pointer(ctx, identifier, name, callerstr, true);
276 if (!labelPtr)
277 return;
278
279 set_label(ctx, labelPtr, label, length, callerstr, true);
280 }
281
282 void GLAPIENTRY
_mesa_GetObjectLabelEXT(GLenum identifier,GLuint name,GLsizei bufSize,GLsizei * length,GLchar * label)283 _mesa_GetObjectLabelEXT(GLenum identifier, GLuint name, GLsizei bufSize,
284 GLsizei *length, GLchar *label)
285 {
286 GET_CURRENT_CONTEXT(ctx);
287 const char *callerstr = "glGetObjectLabelEXT";
288 char **labelPtr;
289
290 if (bufSize < 0) {
291 _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize = %d)", callerstr,
292 bufSize);
293 return;
294 }
295
296 labelPtr = get_label_pointer(ctx, identifier, name, callerstr, true);
297 if (!labelPtr)
298 return;
299
300 copy_label(*labelPtr, label, length, bufSize);
301 }
302
303 void GLAPIENTRY
_mesa_ObjectLabel(GLenum identifier,GLuint name,GLsizei length,const GLchar * label)304 _mesa_ObjectLabel(GLenum identifier, GLuint name, GLsizei length,
305 const GLchar *label)
306 {
307 GET_CURRENT_CONTEXT(ctx);
308 const char *callerstr;
309 char **labelPtr;
310
311 if (_mesa_is_desktop_gl(ctx))
312 callerstr = "glObjectLabel";
313 else
314 callerstr = "glObjectLabelKHR";
315
316 labelPtr = get_label_pointer(ctx, identifier, name, callerstr, false);
317 if (!labelPtr)
318 return;
319
320 set_label(ctx, labelPtr, label, length, callerstr, false);
321 }
322
323 void GLAPIENTRY
_mesa_GetObjectLabel(GLenum identifier,GLuint name,GLsizei bufSize,GLsizei * length,GLchar * label)324 _mesa_GetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize,
325 GLsizei *length, GLchar *label)
326 {
327 GET_CURRENT_CONTEXT(ctx);
328 const char *callerstr;
329 char **labelPtr;
330
331 if (_mesa_is_desktop_gl(ctx))
332 callerstr = "glGetObjectLabel";
333 else
334 callerstr = "glGetObjectLabelKHR";
335
336 if (bufSize < 0) {
337 _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize = %d)", callerstr,
338 bufSize);
339 return;
340 }
341
342 labelPtr = get_label_pointer(ctx, identifier, name, callerstr, false);
343 if (!labelPtr)
344 return;
345
346 copy_label(*labelPtr, label, length, bufSize);
347 }
348
349 void GLAPIENTRY
_mesa_ObjectPtrLabel(const void * ptr,GLsizei length,const GLchar * label)350 _mesa_ObjectPtrLabel(const void *ptr, GLsizei length, const GLchar *label)
351 {
352 GET_CURRENT_CONTEXT(ctx);
353 struct gl_sync_object *syncObj;
354 const char *callerstr;
355 char **labelPtr;
356
357 syncObj = _mesa_get_and_ref_sync(ctx, (void*)ptr, true);
358
359 if (_mesa_is_desktop_gl(ctx))
360 callerstr = "glObjectPtrLabel";
361 else
362 callerstr = "glObjectPtrLabelKHR";
363
364 if (!syncObj) {
365 _mesa_error(ctx, GL_INVALID_VALUE, "%s (not a valid sync object)",
366 callerstr);
367 return;
368 }
369
370 labelPtr = &syncObj->Label;
371
372 set_label(ctx, labelPtr, label, length, callerstr, false);
373 _mesa_unref_sync_object(ctx, syncObj, 1);
374 }
375
376 void GLAPIENTRY
_mesa_GetObjectPtrLabel(const void * ptr,GLsizei bufSize,GLsizei * length,GLchar * label)377 _mesa_GetObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length,
378 GLchar *label)
379 {
380 GET_CURRENT_CONTEXT(ctx);
381 struct gl_sync_object *syncObj;
382 const char *callerstr;
383 char **labelPtr;
384
385 if (_mesa_is_desktop_gl(ctx))
386 callerstr = "glGetObjectPtrLabel";
387 else
388 callerstr = "glGetObjectPtrLabelKHR";
389
390 if (bufSize < 0) {
391 _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize = %d)", callerstr,
392 bufSize);
393 return;
394 }
395
396 syncObj = _mesa_get_and_ref_sync(ctx, (void*)ptr, true);
397 if (!syncObj) {
398 _mesa_error(ctx, GL_INVALID_VALUE, "%s (not a valid sync object)",
399 callerstr);
400 return;
401 }
402
403 labelPtr = &syncObj->Label;
404
405 copy_label(*labelPtr, label, length, bufSize);
406 _mesa_unref_sync_object(ctx, syncObj, 1);
407 }
408