blob: 1b4ef8f8b9e3c792e1580473746714f0ec1e0f8d [file] [log] [blame]
José Fonseca2e3fff62011-05-19 10:45:04 +01001/**************************************************************************
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>
José Fonsecaa15b7fe2011-07-16 21:08:16 -070028
José Fonseca2e3fff62011-05-19 10:45:04 +010029#include <algorithm>
José Fonsecaa15b7fe2011-07-16 21:08:16 -070030#include <iostream>
José Fonseca2e3fff62011-05-19 10:45:04 +010031
32#include "image.hpp"
Jose Fonsecae8ba0792015-05-01 12:38:03 +010033#include "state_writer.hpp"
José Fonseca2e3fff62011-05-19 10:45:04 +010034#include "glproc.hpp"
José Fonseca1e087c72013-08-19 16:42:07 +010035#include "glws.hpp"
José Fonseca2e3fff62011-05-19 10:45:04 +010036#include "glsize.hpp"
37#include "glstate.hpp"
Tianpu Han1627e882012-01-19 14:22:02 +010038#include "glstate_internal.hpp"
José Fonseca2e3fff62011-05-19 10:45:04 +010039
40
41namespace glstate {
42
43
Jose Fonseca4cff7bd2016-04-10 23:06:15 +010044PixelPackState::PixelPackState(const Context &context)
45{
46 desktop = !context.ES;
47 texture_3d = context.texture_3d;
48 pixel_buffer_object = context.pixel_buffer_object;
Jose Fonseca901fe892017-08-04 14:37:47 +010049 color_buffer_float = context.ARB_color_buffer_float;
José Fonseca6accc9e2015-01-07 22:25:14 +000050
José Fonseca72351ec2013-01-23 16:15:40 +000051 // 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;
Jose Fonseca901fe892017-08-04 14:37:47 +010061 clamp_read_color = GL_FIXED_ONLY;
José Fonseca72351ec2013-01-23 16:15:40 +000062
63 // Get current state
64 glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +010065 if (desktop) {
José Fonseca72351ec2013-01-23 16:15:40 +000066 glGetIntegerv(GL_PACK_LSB_FIRST, &pack_lsb_first);
67 glGetIntegerv(GL_PACK_ROW_LENGTH, &pack_row_length);
José Fonseca72351ec2013-01-23 16:15:40 +000068 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);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +010071 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) {
José Fonseca72351ec2013-01-23 16:15:40 +000077 glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &pixel_pack_buffer_binding);
78 }
Jose Fonseca901fe892017-08-04 14:37:47 +010079 if (color_buffer_float) {
80 glGetIntegerv(GL_CLAMP_READ_COLOR, &clamp_read_color);
81 }
José Fonseca72351ec2013-01-23 16:15:40 +000082
83 // Reset state for compact images
84 glPixelStorei(GL_PACK_ALIGNMENT, 1);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +010085 if (desktop) {
Tianpu Han1627e882012-01-19 14:22:02 +010086 glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
87 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
José Fonseca72351ec2013-01-23 16:15:40 +000088 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
89 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
90 glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +010091 if (texture_3d) {
92 glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
93 glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
94 }
95 }
96 if (pixel_buffer_object) {
José Fonseca72351ec2013-01-23 16:15:40 +000097 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
Tianpu Han1627e882012-01-19 14:22:02 +010098 }
Jose Fonseca901fe892017-08-04 14:37:47 +010099 if (color_buffer_float) {
100 glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
101 }
Tianpu Han1627e882012-01-19 14:22:02 +0100102}
José Fonsecab5f5caa2011-06-02 23:12:58 +0100103
José Fonseca6accc9e2015-01-07 22:25:14 +0000104PixelPackState::~PixelPackState() {
José Fonseca72351ec2013-01-23 16:15:40 +0000105 glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +0100106 if (desktop) {
José Fonseca72351ec2013-01-23 16:15:40 +0000107 glPixelStorei(GL_PACK_LSB_FIRST, pack_lsb_first);
108 glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length);
José Fonseca72351ec2013-01-23 16:15:40 +0000109 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);
Jose Fonseca4cff7bd2016-04-10 23:06:15 +0100112 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) {
José Fonseca72351ec2013-01-23 16:15:40 +0000118 glBindBuffer(GL_PIXEL_PACK_BUFFER, pixel_pack_buffer_binding);
Tianpu Han1627e882012-01-19 14:22:02 +0100119 }
Jose Fonseca901fe892017-08-04 14:37:47 +0100120 if (color_buffer_float) {
121 glClampColor(GL_CLAMP_READ_COLOR, clamp_read_color);
122 }
José Fonsecab5f5caa2011-06-02 23:12:58 +0100123}
124
Gabe Dagani9ff44052017-11-28 09:30:15 -0600125TempId::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
155TempId::~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
183TextureBinding::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
195TextureBinding::~TextureBinding() {
196 if (prev_id != id) {
197 glBindTexture(target, prev_id);
198 }
199}
José Fonsecab5f5caa2011-06-02 23:12:58 +0100200
José Fonseca9a0280d2015-01-29 16:03:11 +0000201static GLenum
202getBufferBinding(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;
Gabe Daganie0d7fc32018-01-09 15:40:37 -0600212 case GL_DRAW_BUFFER:
213 return GL_DRAW_BUFFER;
José Fonseca9a0280d2015-01-29 16:03:11 +0000214 case GL_DRAW_INDIRECT_BUFFER:
215 return GL_DRAW_INDIRECT_BUFFER_BINDING;
Gabe Dagani9ff44052017-11-28 09:30:15 -0600216 case GL_FRAMEBUFFER:
217 return GL_FRAMEBUFFER_BINDING;
José Fonseca9a0280d2015-01-29 16:03:11 +0000218 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;
Gabe Daganie0d7fc32018-01-09 15:40:37 -0600228 case GL_READ_BUFFER:
229 return GL_READ_BUFFER;
Gabe Dagani9ff44052017-11-28 09:30:15 -0600230 case GL_RENDERBUFFER:
231 return GL_RENDERBUFFER_BINDING;
José Fonseca9a0280d2015-01-29 16:03:11 +0000232 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
247BufferBinding::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) {
Gabe Dagani9ff44052017-11-28 09:30:15 -0600256 switch(target)
257 {
Gabe Daganie0d7fc32018-01-09 15:40:37 -0600258 case GL_DRAW_BUFFER:
259 glDrawBuffer(buffer);
260 break;
261 case GL_READ_BUFFER:
262 glReadBuffer(buffer);
263 break;
Gabe Dagani9ff44052017-11-28 09:30:15 -0600264 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 }
José Fonseca9a0280d2015-01-29 16:03:11 +0000274 }
275}
276
277BufferBinding::~BufferBinding() {
278 if (prevBuffer != buffer) {
Gabe Dagani9ff44052017-11-28 09:30:15 -0600279 switch(target)
280 {
Gabe Daganie0d7fc32018-01-09 15:40:37 -0600281 case GL_DRAW_BUFFER:
282 glDrawBuffer(prevBuffer);
283 break;
284 case GL_READ_BUFFER:
285 glReadBuffer(prevBuffer);
286 break;
Gabe Dagani9ff44052017-11-28 09:30:15 -0600287 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 }
José Fonseca9a0280d2015-01-29 16:03:11 +0000297 }
298}
299
300
301BufferMapping::BufferMapping() :
302 target(GL_NONE),
303 buffer(0),
304 map_pointer(NULL),
305 unmap(false)
306{
307}
308
309GLvoid *
310BufferMapping::map(GLenum _target, GLuint _buffer)
311{
Jose Fonsecaf6305d32016-02-09 16:50:30 +0000312 if (target == _target && buffer == _buffer) {
313 return map_pointer;
314 }
315
José Fonseca9a0280d2015-01-29 16:03:11 +0000316 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
352BufferMapping::~BufferMapping() {
353 if (unmap) {
354 BufferBinding bb(target, buffer);
355
356 GLenum ret = glUnmapBuffer(target);
357 assert(ret == GL_TRUE);
Jose Fonseca649e3312015-05-21 16:13:13 +0100358 (void)ret;
José Fonseca9a0280d2015-01-29 16:03:11 +0000359 }
360}
361
362
José Fonseca056f2de2014-11-09 15:23:46 +0000363void
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100364dumpBoolean(StateWriter &writer, GLboolean value)
José Fonseca056f2de2014-11-09 15:23:46 +0000365{
366 switch (value) {
367 case GL_FALSE:
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100368 writer.writeString("GL_FALSE");
José Fonseca056f2de2014-11-09 15:23:46 +0000369 break;
370 case GL_TRUE:
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100371 writer.writeString("GL_TRUE");
José Fonseca056f2de2014-11-09 15:23:46 +0000372 break;
373 default:
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100374 writer.writeInt(static_cast<GLint>(value));
José Fonseca056f2de2014-11-09 15:23:46 +0000375 break;
376 }
377}
378
379
380void
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100381dumpEnum(StateWriter &writer, GLenum pname)
José Fonseca056f2de2014-11-09 15:23:46 +0000382{
383 const char *s = enumToString(pname);
384 if (s) {
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100385 writer.writeString(s);
José Fonseca056f2de2014-11-09 15:23:46 +0000386 } else {
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100387 writer.writeInt(pname);
José Fonseca056f2de2014-11-09 15:23:46 +0000388 }
389}
390
391
José Fonseca17f8a322013-10-09 18:40:14 -0700392/**
José Fonseca651251c2014-05-10 16:33:50 +0100393 * 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.
José Fonseca17f8a322013-10-09 18:40:14 -0700397 */
José Fonseca651251c2014-05-10 16:33:50 +0100398char *
399getObjectLabel(Context &context, GLenum identifier, GLuint name)
José Fonseca17f8a322013-10-09 18:40:14 -0700400{
401 if (!name) {
José Fonseca651251c2014-05-10 16:33:50 +0100402 return NULL;
José Fonseca17f8a322013-10-09 18:40:14 -0700403 }
404
José Fonseca651251c2014-05-10 16:33:50 +0100405 GLsizei length = 0;
José Fonseca788d9ce2014-02-04 19:02:04 +0000406 if (context.KHR_debug) {
José Fonseca788d9ce2014-02-04 19:02:04 +0000407 /*
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 }
José Fonseca17f8a322013-10-09 18:40:14 -0700426 }
José Fonseca788d9ce2014-02-04 19:02:04 +0000427 if (context.EXT_debug_label) {
José Fonseca788d9ce2014-02-04 19:02:04 +0000428 glGetObjectLabelEXT(identifier, name, 0, &length, NULL);
José Fonseca651251c2014-05-10 16:33:50 +0100429 }
430 if (!length) {
431 return NULL;
432 }
José Fonseca788d9ce2014-02-04 19:02:04 +0000433
José Fonseca651251c2014-05-10 16:33:50 +0100434 char *label = (char *)calloc(length + 1, 1);
435 if (!label) {
436 return NULL;
437 }
José Fonseca788d9ce2014-02-04 19:02:04 +0000438
José Fonseca651251c2014-05-10 16:33:50 +0100439 if (context.KHR_debug) {
440 glGetObjectLabel(identifier, name, length + 1, NULL, label);
441 }
442 if (context.EXT_debug_label) {
José Fonseca788d9ce2014-02-04 19:02:04 +0000443 glGetObjectLabelEXT(identifier, name, length + 1, NULL, label);
José Fonseca651251c2014-05-10 16:33:50 +0100444 }
José Fonseca788d9ce2014-02-04 19:02:04 +0000445
José Fonseca651251c2014-05-10 16:33:50 +0100446 if (label[0] == '\0') {
José Fonseca788d9ce2014-02-04 19:02:04 +0000447 free(label);
José Fonseca651251c2014-05-10 16:33:50 +0100448 return NULL;
449 }
450
451 return label;
452}
453
454
455/**
456 * Dump a GL_KHR_debug/GL_EXT_debug_label object label.
457 */
458void
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100459dumpObjectLabel(StateWriter &writer, Context &context, GLenum identifier, GLuint name, const char *member) {
José Fonseca651251c2014-05-10 16:33:50 +0100460 char *label = getObjectLabel(context, identifier, name);
461 if (!label) {
José Fonseca17f8a322013-10-09 18:40:14 -0700462 return;
463 }
José Fonseca651251c2014-05-10 16:33:50 +0100464
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100465 writer.writeStringMember(member, label);
José Fonseca651251c2014-05-10 16:33:50 +0100466 free(label);
José Fonseca17f8a322013-10-09 18:40:14 -0700467}
468
469
José Fonseca4f8e71e2011-06-07 20:58:52 +0100470static 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,
José Fonsecac71647d2013-05-30 19:17:38 +0100476 GL_TEXTURE_BINDING_1D_ARRAY,
José Fonseca4f8e71e2011-06-07 20:58:52 +0100477 GL_TEXTURE_BINDING_2D,
José Fonsecac71647d2013-05-30 19:17:38 +0100478 GL_TEXTURE_BINDING_2D_ARRAY,
479 GL_TEXTURE_BINDING_2D_MULTISAMPLE,
480 GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY,
José Fonseca4f8e71e2011-06-07 20:58:52 +0100481 GL_TEXTURE_BINDING_3D,
482 GL_TEXTURE_BINDING_RECTANGLE,
483 GL_TEXTURE_BINDING_CUBE_MAP,
José Fonsecac71647d2013-05-30 19:17:38 +0100484 GL_TEXTURE_BINDING_CUBE_MAP_ARRAY,
José Fonseca4f8e71e2011-06-07 20:58:52 +0100485 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,
José Fonseca55992742014-12-31 18:42:56 +0000496 GL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
497 GL_UNIFORM_BUFFER_BINDING,
José Fonseca4f8e71e2011-06-07 20:58:52 +0100498};
499
500
501#define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
502
503
José Fonseca516f4f62014-12-18 16:10:09 +0000504static void APIENTRY
505debugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
506 GLsizei length, const GLchar* message, const void *userParam)
507{
Jose Fonseca57883232016-02-19 12:31:40 +0000508 // 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
José Fonseca516f4f62014-12-18 16:10:09 +0000517 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:
José Fonseca4e019de2014-12-31 14:40:31 +0000525 severityStr = " low";
526 break;
José Fonseca516f4f62014-12-18 16:10:09 +0000527 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
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100609void dumpCurrentContext(StateWriter &writer)
José Fonseca2e3fff62011-05-19 10:45:04 +0100610{
José Fonseca4f8e71e2011-06-07 20:58:52 +0100611
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
Tianpu Han1627e882012-01-19 14:22:02 +0100620 Context context;
621
José Fonseca516f4f62014-12-18 16:10:09 +0000622 /* 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
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100633 dumpParameters(writer, context);
José Fonseca516f4f62014-12-18 16:10:09 +0000634
635 // Use our own debug-message callback.
636 if (context.KHR_debug) {
637 glDebugMessageCallback(debugMessageCallback, NULL);
638 }
639
Jose Fonsecae8ba0792015-05-01 12:38:03 +0100640 dumpShadersUniforms(writer, context);
641 dumpTextures(writer, context);
642 dumpFramebuffer(writer, context);
José Fonseca4f8e71e2011-06-07 20:58:52 +0100643
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
José Fonseca516f4f62014-12-18 16:10:09 +0000654 // Restore debug message callback
655 if (context.KHR_debug) {
656 glDebugMessageCallback(prevDebugCallbackFunction, prevDebugCallbackUserParam);
657 }
José Fonseca2e3fff62011-05-19 10:45:04 +0100658}
659
660
661} /* namespace glstate */