1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25 
26 
27 #include <string.h>
28 
29 #include <algorithm>
30 #include <iostream>
31 
32 #include "image.hpp"
33 #include "state_writer.hpp"
34 #include "glproc.hpp"
35 #include "glws.hpp"
36 #include "glsize.hpp"
37 #include "glstate.hpp"
38 #include "glstate_internal.hpp"
39 
40 
41 namespace glstate {
42 
43 
PixelPackState(const Context & context)44 PixelPackState::PixelPackState(const Context &context)
45 {
46     desktop = !context.ES;
47     texture_3d = context.texture_3d;
48     pixel_buffer_object = context.pixel_buffer_object;
49     color_buffer_float = context.ARB_color_buffer_float;
50 
51     // Start with default state
52     pack_alignment = 4;
53     pack_image_height = 0;
54     pack_lsb_first = GL_FALSE;
55     pack_row_length = 0;
56     pack_skip_images = 0;
57     pack_skip_pixels = 0;
58     pack_skip_rows = 0;
59     pack_swap_bytes = GL_FALSE;
60     pixel_pack_buffer_binding = 0;
61     clamp_read_color = GL_FIXED_ONLY;
62 
63     // Get current state
64     glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
65     if (desktop) {
66         glGetIntegerv(GL_PACK_LSB_FIRST, &pack_lsb_first);
67         glGetIntegerv(GL_PACK_ROW_LENGTH, &pack_row_length);
68         glGetIntegerv(GL_PACK_SKIP_PIXELS, &pack_skip_pixels);
69         glGetIntegerv(GL_PACK_SKIP_ROWS, &pack_skip_rows);
70         glGetIntegerv(GL_PACK_SWAP_BYTES, &pack_swap_bytes);
71         if (texture_3d) {
72             glGetIntegerv(GL_PACK_IMAGE_HEIGHT, &pack_image_height);
73             glGetIntegerv(GL_PACK_SKIP_IMAGES, &pack_skip_images);
74         }
75     }
76     if (pixel_buffer_object) {
77         glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &pixel_pack_buffer_binding);
78     }
79     if (color_buffer_float) {
80         glGetIntegerv(GL_CLAMP_READ_COLOR, &clamp_read_color);
81     }
82 
83     // Reset state for compact images
84     glPixelStorei(GL_PACK_ALIGNMENT, 1);
85     if (desktop) {
86         glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
87         glPixelStorei(GL_PACK_ROW_LENGTH, 0);
88         glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
89         glPixelStorei(GL_PACK_SKIP_ROWS, 0);
90         glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
91         if (texture_3d) {
92             glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
93             glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
94         }
95     }
96     if (pixel_buffer_object) {
97         glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
98     }
99     if (color_buffer_float) {
100         glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
101     }
102 }
103 
~PixelPackState()104 PixelPackState::~PixelPackState() {
105     glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
106     if (desktop) {
107         glPixelStorei(GL_PACK_LSB_FIRST, pack_lsb_first);
108         glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length);
109         glPixelStorei(GL_PACK_SKIP_PIXELS, pack_skip_pixels);
110         glPixelStorei(GL_PACK_SKIP_ROWS, pack_skip_rows);
111         glPixelStorei(GL_PACK_SWAP_BYTES, pack_swap_bytes);
112         if (texture_3d) {
113             glPixelStorei(GL_PACK_IMAGE_HEIGHT, pack_image_height);
114             glPixelStorei(GL_PACK_SKIP_IMAGES, pack_skip_images);
115         }
116     }
117     if (pixel_buffer_object) {
118         glBindBuffer(GL_PIXEL_PACK_BUFFER, pixel_pack_buffer_binding);
119     }
120     if (color_buffer_float) {
121         glClampColor(GL_CLAMP_READ_COLOR, clamp_read_color);
122     }
123 }
124 
TempId(GLenum _target)125 TempId::TempId(GLenum _target) :
126     target(_target),
127     id(0)
128 {
129     switch (target){
130     case GL_ARRAY_BUFFER:
131         glGenBuffers(1, &id);
132         break;
133     case GL_FRAMEBUFFER:
134         glGenFramebuffers(1, &id);
135         break;
136     case GL_PROGRAM:
137         id = glCreateProgram();
138         break;
139     case GL_RENDERBUFFER:
140         glGenRenderbuffers(1, &id);
141         break;
142     case GL_TEXTURE:
143         glGenTextures(1, &id);
144         break;
145     case GL_VERTEX_ARRAY:
146         glGenVertexArrays(1, &id);
147         break;
148     default:
149         assert(false);
150         id = 0;
151         return;
152     }
153 }
154 
~TempId()155 TempId::~TempId()
156 {
157     switch (target){
158     case GL_ARRAY_BUFFER:
159         glDeleteBuffers(1, &id);
160         break;
161     case GL_FRAMEBUFFER:
162         glDeleteFramebuffers(1, &id);
163         break;
164     case GL_PROGRAM:
165         glDeleteProgram(id);
166         break;
167     case GL_RENDERBUFFER:
168         glGenRenderbuffers(1, &id);
169         break;
170     case GL_TEXTURE:
171         glDeleteTextures(1, &id);
172         break;
173     case GL_VERTEX_ARRAY:
174         glGenVertexArrays(1, &id);
175         break;
176     default:
177         assert(false);
178         id = 0;
179         return;
180     }
181 }
182 
TextureBinding(GLenum _target,GLuint _id)183 TextureBinding::TextureBinding(GLenum _target, GLuint _id) :
184     target(_target),
185     id(_id),
186     prev_id(0)
187 {
188     GLenum binding = getTextureBinding(target);
189     glGetIntegerv(binding, (GLint *) &prev_id);
190     if (prev_id != id) {
191         glBindTexture(target, id);
192     }
193 }
194 
~TextureBinding()195 TextureBinding::~TextureBinding() {
196     if (prev_id != id) {
197         glBindTexture(target, prev_id);
198     }
199 }
200 
201 static GLenum
getBufferBinding(GLenum target)202 getBufferBinding(GLenum target) {
203     switch (target) {
204     case GL_ARRAY_BUFFER:
205         return GL_ARRAY_BUFFER_BINDING;
206     case GL_ATOMIC_COUNTER_BUFFER:
207         return GL_ATOMIC_COUNTER_BUFFER_BINDING;
208     case GL_COPY_READ_BUFFER:
209         return GL_COPY_READ_BUFFER_BINDING;
210     case GL_COPY_WRITE_BUFFER:
211         return GL_COPY_WRITE_BUFFER_BINDING;
212     case GL_DRAW_BUFFER:
213         return GL_DRAW_BUFFER;
214     case GL_DRAW_INDIRECT_BUFFER:
215         return GL_DRAW_INDIRECT_BUFFER_BINDING;
216     case GL_FRAMEBUFFER:
217         return GL_FRAMEBUFFER_BINDING;
218     case GL_DISPATCH_INDIRECT_BUFFER:
219         return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
220     case GL_ELEMENT_ARRAY_BUFFER:
221         return GL_ELEMENT_ARRAY_BUFFER_BINDING;
222     case GL_PIXEL_PACK_BUFFER:
223         return GL_PIXEL_PACK_BUFFER_BINDING;
224     case GL_PIXEL_UNPACK_BUFFER:
225         return GL_PIXEL_UNPACK_BUFFER_BINDING;
226     case GL_QUERY_BUFFER:
227         return GL_QUERY_BUFFER_BINDING;
228     case GL_READ_BUFFER:
229         return GL_READ_BUFFER;
230     case GL_RENDERBUFFER:
231         return GL_RENDERBUFFER_BINDING;
232     case GL_SHADER_STORAGE_BUFFER:
233         return GL_SHADER_STORAGE_BUFFER_BINDING;
234     case GL_TEXTURE_BUFFER:
235         return GL_TEXTURE_BUFFER;
236     case GL_TRANSFORM_FEEDBACK_BUFFER:
237         return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
238     case GL_UNIFORM_BUFFER:
239         return GL_UNIFORM_BUFFER_BINDING;
240     default:
241         assert(false);
242         return GL_NONE;
243     }
244 }
245 
246 
BufferBinding(GLenum _target,GLuint _buffer)247 BufferBinding::BufferBinding(GLenum _target, GLuint _buffer) :
248     target(_target),
249     buffer(_buffer),
250     prevBuffer(0)
251 {
252     GLenum binding = getBufferBinding(target);
253     glGetIntegerv(binding, (GLint *) &prevBuffer);
254 
255     if (prevBuffer != buffer) {
256         switch(target)
257         {
258         case GL_DRAW_BUFFER:
259             glDrawBuffer(buffer);
260             break;
261         case GL_READ_BUFFER:
262             glReadBuffer(buffer);
263             break;
264         case GL_FRAMEBUFFER:
265             glBindFramebuffer(target, buffer);
266             break;
267         case GL_RENDERBUFFER:
268             glBindRenderbuffer(target, buffer);
269             break;
270         default:
271             glBindBuffer(target, buffer);
272             break;
273         }
274     }
275 }
276 
~BufferBinding()277 BufferBinding::~BufferBinding() {
278     if (prevBuffer != buffer) {
279         switch(target)
280         {
281         case GL_DRAW_BUFFER:
282             glDrawBuffer(prevBuffer);
283             break;
284         case GL_READ_BUFFER:
285             glReadBuffer(prevBuffer);
286             break;
287         case GL_FRAMEBUFFER:
288             glBindFramebuffer(target, prevBuffer);
289             break;
290         case GL_RENDERBUFFER:
291             glBindRenderbuffer(target, prevBuffer);
292             break;
293         default:
294             glBindBuffer(target, prevBuffer);
295             break;
296         }
297     }
298 }
299 
300 
BufferMapping()301 BufferMapping::BufferMapping() :
302     target(GL_NONE),
303     buffer(0),
304     map_pointer(NULL),
305     unmap(false)
306 {
307 }
308 
309 GLvoid *
map(GLenum _target,GLuint _buffer)310 BufferMapping::map(GLenum _target, GLuint _buffer)
311 {
312     if (target == _target && buffer == _buffer) {
313         return map_pointer;
314     }
315 
316     target = _target;
317     buffer = _buffer;
318     map_pointer = NULL;
319     unmap = false;
320 
321     BufferBinding bb(target, buffer);
322 
323     // Recursive mappings of the same buffer are not allowed.  And with the
324     // pursuit of persistent mappings for performance this will become more
325     // and more common.
326     GLint mapped = GL_FALSE;
327     glGetBufferParameteriv(target, GL_BUFFER_MAPPED, &mapped);
328     if (mapped) {
329         glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &map_pointer);
330         assert(map_pointer != NULL);
331 
332         GLint map_offset = 0;
333         glGetBufferParameteriv(target, GL_BUFFER_MAP_OFFSET, &map_offset);
334         if (map_offset != 0) {
335             std::cerr << "warning: " << enumToString(target) << " buffer " << buffer << " is already mapped with offset " << map_offset << "\n";
336             // FIXME: This most likely won't work.  We should remap the
337             // buffer with the full range, then re-map when done.  This
338             // should never happen in practice with persistent mappings
339             // though.
340             map_pointer = (GLubyte *)map_pointer - map_offset;
341         }
342     } else {
343         map_pointer = glMapBuffer(target, GL_READ_ONLY);
344         if (map_pointer) {
345             unmap = true;
346         }
347     }
348 
349     return map_pointer;
350 }
351 
~BufferMapping()352 BufferMapping::~BufferMapping() {
353     if (unmap) {
354         BufferBinding bb(target, buffer);
355 
356         GLenum ret = glUnmapBuffer(target);
357         assert(ret == GL_TRUE);
358         (void)ret;
359     }
360 }
361 
362 
363 void
dumpBoolean(StateWriter & writer,GLboolean value)364 dumpBoolean(StateWriter &writer, GLboolean value)
365 {
366     switch (value) {
367     case GL_FALSE:
368         writer.writeString("GL_FALSE");
369         break;
370     case GL_TRUE:
371         writer.writeString("GL_TRUE");
372         break;
373     default:
374         writer.writeInt(static_cast<GLint>(value));
375         break;
376     }
377 }
378 
379 
380 void
dumpEnum(StateWriter & writer,GLenum pname)381 dumpEnum(StateWriter &writer, GLenum pname)
382 {
383     const char *s = enumToString(pname);
384     if (s) {
385         writer.writeString(s);
386     } else {
387         writer.writeInt(pname);
388     }
389 }
390 
391 
392 /**
393  * Get a GL_KHR_debug/GL_EXT_debug_label object label.
394  *
395  * The returned string should be destroyed with free() when no longer
396  * necessary.
397  */
398 char *
getObjectLabel(Context & context,GLenum identifier,GLuint name)399 getObjectLabel(Context &context, GLenum identifier, GLuint name)
400 {
401     if (!name) {
402         return NULL;
403     }
404 
405     GLsizei length = 0;
406     if (context.KHR_debug) {
407         /*
408          * XXX: According to
409          * http://www.khronos.org/registry/gles/extensions/KHR/debug.txt
410          * description of glGetObjectLabel:
411          *
412          *   "If <label> is NULL and <length> is non-NULL then no string will
413          *   be returned and the length of the label will be returned in
414          *   <length>."
415          *
416          * However NVIDIA 319.60 drivers return a zero length in such
417          * circumstances.  310.14 drivers worked fine though.  So, just rely on
418          * GL_MAX_LABEL_LENGTH instead, which might waste a bit of memory, but
419          * should work reliably everywhere.
420          */
421         if (0) {
422             glGetObjectLabel(identifier, name, 0, &length, NULL);
423         } else {
424             glGetIntegerv(GL_MAX_LABEL_LENGTH, &length);
425         }
426     }
427     if (context.EXT_debug_label) {
428         glGetObjectLabelEXT(identifier, name, 0, &length, NULL);
429     }
430     if (!length) {
431         return NULL;
432     }
433 
434     char *label = (char *)calloc(length + 1, 1);
435     if (!label) {
436         return NULL;
437     }
438 
439     if (context.KHR_debug) {
440         glGetObjectLabel(identifier, name, length + 1, NULL, label);
441     }
442     if (context.EXT_debug_label) {
443         glGetObjectLabelEXT(identifier, name, length + 1, NULL, label);
444     }
445 
446     if (label[0] == '\0') {
447         free(label);
448         return NULL;
449     }
450 
451     return label;
452 }
453 
454 
455 /**
456  * Dump a GL_KHR_debug/GL_EXT_debug_label object label.
457  */
458 void
dumpObjectLabel(StateWriter & writer,Context & context,GLenum identifier,GLuint name,const char * member)459 dumpObjectLabel(StateWriter &writer, Context &context, GLenum identifier, GLuint name, const char *member) {
460     char *label = getObjectLabel(context, identifier, name);
461     if (!label) {
462         return;
463     }
464 
465     writer.writeStringMember(member, label);
466     free(label);
467 }
468 
469 
470 static const GLenum bindings[] = {
471     GL_DRAW_BUFFER,
472     GL_READ_BUFFER,
473     GL_PIXEL_PACK_BUFFER_BINDING,
474     GL_PIXEL_UNPACK_BUFFER_BINDING,
475     GL_TEXTURE_BINDING_1D,
476     GL_TEXTURE_BINDING_1D_ARRAY,
477     GL_TEXTURE_BINDING_2D,
478     GL_TEXTURE_BINDING_2D_ARRAY,
479     GL_TEXTURE_BINDING_2D_MULTISAMPLE,
480     GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY,
481     GL_TEXTURE_BINDING_3D,
482     GL_TEXTURE_BINDING_RECTANGLE,
483     GL_TEXTURE_BINDING_CUBE_MAP,
484     GL_TEXTURE_BINDING_CUBE_MAP_ARRAY,
485     GL_DRAW_FRAMEBUFFER_BINDING,
486     GL_READ_FRAMEBUFFER_BINDING,
487     GL_RENDERBUFFER_BINDING,
488     GL_DRAW_BUFFER0,
489     GL_DRAW_BUFFER1,
490     GL_DRAW_BUFFER2,
491     GL_DRAW_BUFFER3,
492     GL_DRAW_BUFFER4,
493     GL_DRAW_BUFFER5,
494     GL_DRAW_BUFFER6,
495     GL_DRAW_BUFFER7,
496     GL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
497     GL_UNIFORM_BUFFER_BINDING,
498 };
499 
500 
501 #define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
502 
503 
504 static void APIENTRY
debugMessageCallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)505 debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
506                      GLsizei length, const GLchar* message, const void *userParam)
507 {
508     // Ignore NVIDIA buffer usage warnings: when dumping we inevitably use
509     // buffers differently than declared
510     if (source == GL_DEBUG_SOURCE_API &&
511         type == GL_DEBUG_TYPE_OTHER &&
512         id == 131188 &&
513         severity == GL_DEBUG_SEVERITY_LOW) {
514         return;
515     };
516 
517     const char *severityStr = "";
518     switch (severity) {
519     case GL_DEBUG_SEVERITY_HIGH:
520         severityStr = " high";
521         break;
522     case GL_DEBUG_SEVERITY_MEDIUM:
523         break;
524     case GL_DEBUG_SEVERITY_LOW:
525         severityStr = " low";
526         break;
527     case GL_DEBUG_SEVERITY_NOTIFICATION:
528         /* ignore */
529         return;
530     default:
531         assert(0);
532     }
533 
534     const char *sourceStr = "";
535     switch (source) {
536     case GL_DEBUG_SOURCE_API:
537         break;
538     case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
539         sourceStr = " window system";
540         break;
541     case GL_DEBUG_SOURCE_SHADER_COMPILER:
542         sourceStr = " shader compiler";
543         break;
544     case GL_DEBUG_SOURCE_THIRD_PARTY:
545         sourceStr = " third party";
546         break;
547     case GL_DEBUG_SOURCE_APPLICATION:
548         sourceStr = " application";
549         break;
550     case GL_DEBUG_SOURCE_OTHER:
551         break;
552     default:
553         assert(0);
554     }
555 
556     const char *typeStr = "";
557     switch (type) {
558     case GL_DEBUG_TYPE_ERROR:
559         typeStr = " error";
560         break;
561     case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
562         typeStr = " deprecated behaviour";
563         break;
564     case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
565         typeStr = " undefined behaviour";
566         break;
567     case GL_DEBUG_TYPE_PORTABILITY:
568         typeStr = " portability issue";
569         break;
570     case GL_DEBUG_TYPE_PERFORMANCE:
571         return;
572     default:
573         assert(0);
574         /* fall-through */
575     case GL_DEBUG_TYPE_OTHER:
576         typeStr = " issue";
577         break;
578     case GL_DEBUG_TYPE_MARKER:
579     case GL_DEBUG_TYPE_PUSH_GROUP:
580     case GL_DEBUG_TYPE_POP_GROUP:
581         return;
582     }
583 
584     std::cerr << "warning: message:" << severityStr << sourceStr << typeStr;
585 
586     if (id) {
587         std::cerr << " " << id;
588     }
589 
590     std::cerr << ": ";
591 
592     std::cerr << message;
593 
594     // Write new line if not included in the message already.
595     size_t messageLen = strlen(message);
596     if (!messageLen ||
597         (message[messageLen - 1] != '\n' &&
598          message[messageLen - 1] != '\r')) {
599        std::cerr << std::endl;
600     }
601 
602     /* To help debug bugs in glstate. */
603     if (0) {
604         os::breakpoint();
605     }
606 }
607 
608 
dumpCurrentContext(StateWriter & writer)609 void dumpCurrentContext(StateWriter &writer)
610 {
611 
612 #ifndef NDEBUG
613     GLint old_bindings[NUM_BINDINGS];
614     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
615         old_bindings[i] = 0;
616         glGetIntegerv(bindings[i], &old_bindings[i]);
617     }
618 #endif
619 
620     Context context;
621 
622     /* Temporarily disable messages, as dumpParameters blindlessly tries to
623      * get state, regardless the respective extension is supported or not.
624      */
625     GLDEBUGPROC prevDebugCallbackFunction = 0;
626     void *prevDebugCallbackUserParam = 0;
627     if (context.KHR_debug) {
628         glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, (GLvoid **) &prevDebugCallbackFunction);
629         glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &prevDebugCallbackUserParam);
630         glDebugMessageCallback(NULL, NULL);
631     }
632 
633     dumpParameters(writer, context);
634 
635     // Use our own debug-message callback.
636     if (context.KHR_debug) {
637         glDebugMessageCallback(debugMessageCallback, NULL);
638     }
639 
640     dumpShadersUniforms(writer, context);
641     dumpTextures(writer, context);
642     dumpFramebuffer(writer, context);
643 
644 #ifndef NDEBUG
645     for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
646         GLint new_binding = 0;
647         glGetIntegerv(bindings[i], &new_binding);
648         if (new_binding != old_bindings[i]) {
649             std::cerr << "warning: " << enumToString(bindings[i]) << " was clobbered\n";
650         }
651     }
652 #endif
653 
654     // Restore debug message callback
655     if (context.KHR_debug) {
656         glDebugMessageCallback(prevDebugCallbackFunction, prevDebugCallbackUserParam);
657     }
658 }
659 
660 
661 } /* namespace glstate */
662