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 "objectlabel.h"
33 #include "pipelineobj.h"
34 #include "queryobj.h"
35 #include "samplerobj.h"
36 #include "shaderobj.h"
37 #include "syncobj.h"
38 #include "texobj.h"
39 #include "transformfeedback.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)46 set_label(struct gl_context *ctx, char **labelPtr, const char *label,
47           int length, const char *caller)
48 {
49    free(*labelPtr);
50    *labelPtr = NULL;
51 
52    /* set new label string */
53    if (label) {
54       if (length >= 0) {
55          if (length >= MAX_LABEL_LENGTH)
56             _mesa_error(ctx, GL_INVALID_VALUE,
57                         "%s(length=%d, which is not less than "
58                         "GL_MAX_LABEL_LENGTH=%d)", caller, length,
59                         MAX_LABEL_LENGTH);
60 
61          /* explicit length */
62          *labelPtr = malloc(length+1);
63          if (*labelPtr) {
64             memcpy(*labelPtr, label, length);
65             /* length is not required to include the null terminator so
66              * add one just in case
67              */
68             (*labelPtr)[length] = '\0';
69          }
70       }
71       else {
72          int len = strlen(label);
73          if (len >= MAX_LABEL_LENGTH)
74             _mesa_error(ctx, GL_INVALID_VALUE,
75                 "%s(label length=%d, which is not less than "
76                 "GL_MAX_LABEL_LENGTH=%d)", caller, len,
77                 MAX_LABEL_LENGTH);
78 
79          /* null-terminated string */
80          *labelPtr = strdup(label);
81       }
82    }
83 }
84 
85 /**
86  * Helper for _mesa_GetObjectLabel() and _mesa_GetObjectPtrLabel().
87  * \param src  the src label (may be null)
88  * \param dst  pointer to dest buffer (may be null)
89  * \param length  returns length of label (may be null)
90  * \param bufsize  size of dst buffer
91  */
92 static void
copy_label(const GLchar * src,GLchar * dst,GLsizei * length,GLsizei bufSize)93 copy_label(const GLchar *src, GLchar *dst, GLsizei *length, GLsizei bufSize)
94 {
95    int labelLen = 0;
96 
97    /* From http://www.opengl.org/registry/specs/KHR/debug.txt:
98     * "If <length> is NULL, no length is returned. The maximum number of
99     * characters that may be written into <label>, including the null
100     * terminator, is specified by <bufSize>. If no debug label was specified
101     * for the object then <label> will contain a null-terminated empty string,
102     * and zero will be returned in <length>. If <label> is NULL and <length>
103     * is non-NULL then no string will be returned and the length of the label
104     * will be returned in <length>."
105     */
106 
107    if (src)
108       labelLen = strlen(src);
109 
110    if (bufSize == 0) {
111       if (length)
112          *length = labelLen;
113       return;
114    }
115 
116    if (dst) {
117       if (src) {
118          if (bufSize <= labelLen)
119             labelLen = bufSize - 1;
120 
121          memcpy(dst, src, labelLen);
122       }
123 
124       dst[labelLen] = '\0';
125    }
126 
127    if (length)
128       *length = labelLen;
129 }
130 
131 /**
132  * Helper for _mesa_ObjectLabel() and _mesa_GetObjectLabel().
133  */
134 static char **
get_label_pointer(struct gl_context * ctx,GLenum identifier,GLuint name,const char * caller)135 get_label_pointer(struct gl_context *ctx, GLenum identifier, GLuint name,
136                   const char *caller)
137 {
138    char **labelPtr = NULL;
139 
140    switch (identifier) {
141    case GL_BUFFER:
142       {
143          struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
144          if (bufObj)
145             labelPtr = &bufObj->Label;
146       }
147       break;
148    case GL_SHADER:
149       {
150          struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
151          if (shader)
152             labelPtr = &shader->Label;
153       }
154       break;
155    case GL_PROGRAM:
156       {
157          struct gl_shader_program *program =
158             _mesa_lookup_shader_program(ctx, name);
159          if (program)
160             labelPtr = &program->Label;
161       }
162       break;
163    case GL_VERTEX_ARRAY:
164       {
165          struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, name);
166          if (obj)
167             labelPtr = &obj->Label;
168       }
169       break;
170    case GL_QUERY:
171       {
172          struct gl_query_object *query = _mesa_lookup_query_object(ctx, name);
173          if (query)
174             labelPtr = &query->Label;
175       }
176       break;
177    case GL_TRANSFORM_FEEDBACK:
178       {
179          /* From the GL 4.5 specification, page 536:
180           * "An INVALID_VALUE error is generated if name is not the name of a
181           *  valid object of the type specified by identifier."
182           */
183          struct gl_transform_feedback_object *tfo =
184             _mesa_lookup_transform_feedback_object(ctx, name);
185          if (tfo && tfo->EverBound)
186             labelPtr = &tfo->Label;
187       }
188       break;
189    case GL_SAMPLER:
190       {
191          struct gl_sampler_object *so = _mesa_lookup_samplerobj(ctx, name);
192          if (so)
193             labelPtr = &so->Label;
194       }
195       break;
196    case GL_TEXTURE:
197       {
198          struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
199          if (texObj && texObj->Target)
200             labelPtr = &texObj->Label;
201       }
202       break;
203    case GL_RENDERBUFFER:
204       {
205          struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
206          if (rb)
207             labelPtr = &rb->Label;
208       }
209       break;
210    case GL_FRAMEBUFFER:
211       {
212          struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, name);
213          if (rb)
214             labelPtr = &rb->Label;
215       }
216       break;
217    case GL_DISPLAY_LIST:
218       if (ctx->API == API_OPENGL_COMPAT) {
219          struct gl_display_list *list = _mesa_lookup_list(ctx, name, false);
220          if (list)
221             labelPtr = &list->Label;
222       }
223       else {
224          goto invalid_enum;
225       }
226       break;
227    case GL_PROGRAM_PIPELINE:
228       {
229          struct gl_pipeline_object *pipe =
230             _mesa_lookup_pipeline_object(ctx, name);
231          if (pipe)
232             labelPtr = &pipe->Label;
233       }
234       break;
235    default:
236       goto invalid_enum;
237    }
238 
239    if (NULL == labelPtr) {
240       _mesa_error(ctx, GL_INVALID_VALUE, "%s(name = %u)", caller, name);
241    }
242 
243    return labelPtr;
244 
245 invalid_enum:
246    _mesa_error(ctx, GL_INVALID_ENUM, "%s(identifier = %s)",
247                caller, _mesa_enum_to_string(identifier));
248    return NULL;
249 }
250 
251 void GLAPIENTRY
_mesa_ObjectLabel(GLenum identifier,GLuint name,GLsizei length,const GLchar * label)252 _mesa_ObjectLabel(GLenum identifier, GLuint name, GLsizei length,
253                   const GLchar *label)
254 {
255    GET_CURRENT_CONTEXT(ctx);
256    const char *callerstr;
257    char **labelPtr;
258 
259    if (_mesa_is_desktop_gl(ctx))
260       callerstr = "glObjectLabel";
261    else
262       callerstr = "glObjectLabelKHR";
263 
264    labelPtr = get_label_pointer(ctx, identifier, name, callerstr);
265    if (!labelPtr)
266       return;
267 
268    set_label(ctx, labelPtr, label, length, callerstr);
269 }
270 
271 void GLAPIENTRY
_mesa_GetObjectLabel(GLenum identifier,GLuint name,GLsizei bufSize,GLsizei * length,GLchar * label)272 _mesa_GetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize,
273                      GLsizei *length, GLchar *label)
274 {
275    GET_CURRENT_CONTEXT(ctx);
276    const char *callerstr;
277    char **labelPtr;
278 
279    if (_mesa_is_desktop_gl(ctx))
280       callerstr = "glGetObjectLabel";
281    else
282       callerstr = "glGetObjectLabelKHR";
283 
284    if (bufSize < 0) {
285       _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize = %d)", callerstr,
286                   bufSize);
287       return;
288    }
289 
290    labelPtr = get_label_pointer(ctx, identifier, name, callerstr);
291    if (!labelPtr)
292       return;
293 
294    copy_label(*labelPtr, label, length, bufSize);
295 }
296 
297 void GLAPIENTRY
_mesa_ObjectPtrLabel(const void * ptr,GLsizei length,const GLchar * label)298 _mesa_ObjectPtrLabel(const void *ptr, GLsizei length, const GLchar *label)
299 {
300    GET_CURRENT_CONTEXT(ctx);
301    struct gl_sync_object *syncObj;
302    const char *callerstr;
303    char **labelPtr;
304 
305    syncObj = _mesa_get_and_ref_sync(ctx, (void*)ptr, true);
306 
307    if (_mesa_is_desktop_gl(ctx))
308       callerstr = "glObjectPtrLabel";
309    else
310       callerstr = "glObjectPtrLabelKHR";
311 
312    if (!syncObj) {
313       _mesa_error(ctx, GL_INVALID_VALUE, "%s (not a valid sync object)",
314                   callerstr);
315       return;
316    }
317 
318    labelPtr = &syncObj->Label;
319 
320    set_label(ctx, labelPtr, label, length, callerstr);
321    _mesa_unref_sync_object(ctx, syncObj, 1);
322 }
323 
324 void GLAPIENTRY
_mesa_GetObjectPtrLabel(const void * ptr,GLsizei bufSize,GLsizei * length,GLchar * label)325 _mesa_GetObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length,
326                         GLchar *label)
327 {
328    GET_CURRENT_CONTEXT(ctx);
329    struct gl_sync_object *syncObj;
330    const char *callerstr;
331    char **labelPtr;
332 
333    if (_mesa_is_desktop_gl(ctx))
334       callerstr = "glGetObjectPtrLabel";
335    else
336       callerstr = "glGetObjectPtrLabelKHR";
337 
338    if (bufSize < 0) {
339       _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize = %d)", callerstr,
340                   bufSize);
341       return;
342    }
343 
344    syncObj = _mesa_get_and_ref_sync(ctx, (void*)ptr, true);
345    if (!syncObj) {
346       _mesa_error(ctx, GL_INVALID_VALUE, "%s (not a valid sync object)",
347                   callerstr);
348       return;
349    }
350 
351    labelPtr = &syncObj->Label;
352 
353    copy_label(*labelPtr, label, length, bufSize);
354    _mesa_unref_sync_object(ctx, syncObj, 1);
355 }
356