]> git.cworth.org Git - apitrace/blobdiff - glstate_images.cpp
Move tracers to wrappers subdirectory.
[apitrace] / glstate_images.cpp
index eb7d7a898db796dc67733ad5bc5073becaeca17f..f16cba41194a3c5b58ff219b1ec8fcc70d6c762a 100644 (file)
 #include "glstate_internal.hpp"
 
 
+#ifdef __linux__
+#include <dlfcn.h>
+#endif
+
 #ifdef __APPLE__
 
 #include <Carbon/Carbon.h>
@@ -255,6 +259,97 @@ getActiveTextureLevelDesc(Context &context, GLenum target, GLint level, ImageDes
 }
 
 
+/**
+ * OpenGL ES does not support glGetTexImage. Obtain the pixels by attaching the
+ * texture to a framebuffer.
+ */
+static inline void
+getTexImageOES(GLenum target, GLint level, ImageDesc &desc, GLubyte *pixels)
+{
+    memset(pixels, 0x80, desc.height * desc.width * 4);
+
+    GLenum texture_binding = GL_NONE;
+    switch (target) {
+    case GL_TEXTURE_2D:
+        texture_binding = GL_TEXTURE_BINDING_2D;
+        break;
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        texture_binding = GL_TEXTURE_BINDING_CUBE_MAP;
+        break;
+    case GL_TEXTURE_3D_OES:
+        texture_binding = GL_TEXTURE_BINDING_3D_OES;
+    default:
+        return;
+    }
+
+    GLint texture = 0;
+    glGetIntegerv(texture_binding, &texture);
+    if (!texture) {
+        return;
+    }
+
+    GLint prev_fbo = 0;
+    GLuint fbo = 0;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
+    glGenFramebuffers(1, &fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    GLenum status;
+
+    switch (target) {
+    case GL_TEXTURE_2D:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level);
+        status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+        if (status != GL_FRAMEBUFFER_COMPLETE) {
+            std::cerr << __FUNCTION__ << ": " << enumToString(status) << "\n";
+        }
+        glReadPixels(0, 0, desc.width, desc.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+        break;
+    case GL_TEXTURE_3D_OES:
+        for (int i = 0; i < desc.depth; i++) {
+            glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture, level, i);
+            glReadPixels(0, 0, desc.width, desc.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels + 4 * i * desc.width * desc.height);
+        }
+        break;
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
+
+    glDeleteFramebuffers(1, &fbo);
+}
+
+
+static inline GLboolean
+isDepthFormat(GLenum internalFormat)
+{
+   switch (internalFormat) {
+   case GL_DEPTH_COMPONENT:
+   case GL_DEPTH_COMPONENT16:
+   case GL_DEPTH_COMPONENT24:
+   case GL_DEPTH_COMPONENT32:
+   case GL_DEPTH_COMPONENT32F:
+   case GL_DEPTH_COMPONENT32F_NV:
+   case GL_DEPTH_STENCIL:
+   case GL_DEPTH24_STENCIL8:
+   case GL_DEPTH32F_STENCIL8:
+   case GL_DEPTH32F_STENCIL8_NV:
+      return GL_TRUE;
+   }
+   return GL_FALSE;
+}
+
+
 static inline void
 dumpActiveTextureLevel(JSONWriter &json, Context &context, GLenum target, GLint level)
 {
@@ -274,6 +369,16 @@ dumpActiveTextureLevel(JSONWriter &json, Context &context, GLenum target, GLint
 
     json.beginObject();
 
+    GLuint channels;
+    GLenum format;
+    if (!context.ES && isDepthFormat(desc.internalFormat)) {
+       format = GL_DEPTH_COMPONENT;
+       channels = 1;
+    } else {
+       format = GL_RGBA;
+       channels = 4;
+    }
+
     // Tell the GUI this is no ordinary object, but an image
     json.writeStringMember("__class__", "image");
 
@@ -287,20 +392,24 @@ dumpActiveTextureLevel(JSONWriter &json, Context &context, GLenum target, GLint
     // texture internal format
     json.writeStringMember("__type__", "uint8");
     json.writeBoolMember("__normalized__", true);
-    json.writeNumberMember("__channels__", 4);
+    json.writeNumberMember("__channels__", channels);
 
-    GLubyte *pixels = new GLubyte[desc.depth*desc.width*desc.height*4];
+    GLubyte *pixels = new GLubyte[desc.depth*desc.width*desc.height*channels];
 
     context.resetPixelPackState();
 
-    glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    if (context.ES) {
+        getTexImageOES(target, level, desc, pixels);
+    } else {
+        glGetTexImage(target, level, format, GL_UNSIGNED_BYTE, pixels);
+    }
 
     context.restorePixelPackState();
 
     json.beginMember("__data__");
     char *pngBuffer;
     int pngBufferSize;
-    image::writePixelsToBuffer(pixels, desc.width, desc.height, 4, true, &pngBuffer, &pngBufferSize);
+    image::writePixelsToBuffer(pixels, desc.width, desc.height, channels, true, &pngBuffer, &pngBufferSize);
     json.writeBase64(pngBuffer, pngBufferSize);
     free(pngBuffer);
     json.endMember(); // __data__
@@ -346,11 +455,20 @@ dumpTextures(JSONWriter &json, Context &context)
     json.beginObject();
     GLint active_texture = GL_TEXTURE0;
     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
+
     GLint max_texture_coords = 0;
     glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
     GLint max_combined_texture_image_units = 0;
     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
     GLint max_units = std::max(max_combined_texture_image_units, max_texture_coords);
+
+    /*
+     * At least the Android software GL implementation doesn't return the
+     * proper value for this, but rather returns 0. The GL(ES) specification
+     * mandates a minimum value of 2, so use this as a fall-back value.
+     */
+    max_units = std::min(max_units, 2);
+
     for (GLint unit = 0; unit < max_units; ++unit) {
         GLenum texture = GL_TEXTURE0 + unit;
         glActiveTexture(texture);
@@ -368,31 +486,33 @@ dumpTextures(JSONWriter &json, Context &context)
 
 static bool
 getDrawableBounds(GLint *width, GLint *height) {
-#if defined(TRACE_EGL)
+#if defined(__linux__)
+    if (dlsym(RTLD_DEFAULT, "eglGetCurrentContext")) {
+        EGLContext currentContext = eglGetCurrentContext();
+        if (currentContext == EGL_NO_CONTEXT) {
+            return false;
+        }
 
-    EGLContext currentContext = eglGetCurrentContext();
-    if (currentContext == EGL_NO_CONTEXT) {
-        return false;
-    }
+        EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+        if (currentSurface == EGL_NO_SURFACE) {
+            return false;
+        }
 
-    EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
-    if (currentSurface == EGL_NO_SURFACE) {
-        return false;
-    }
+        EGLDisplay currentDisplay = eglGetCurrentDisplay();
+        if (currentDisplay == EGL_NO_DISPLAY) {
+            return false;
+        }
 
-    EGLDisplay currentDisplay = eglGetCurrentDisplay();
-    if (currentDisplay == EGL_NO_DISPLAY) {
-        return false;
-    }
+        if (!eglQuerySurface(currentDisplay, currentSurface, EGL_WIDTH, width) ||
+            !eglQuerySurface(currentDisplay, currentSurface, EGL_HEIGHT, height)) {
+            return false;
+        }
 
-    if (!eglQuerySurface(currentDisplay, currentSurface, EGL_WIDTH, width) ||
-        !eglQuerySurface(currentDisplay, currentSurface, EGL_HEIGHT, height)) {
-        return false;
+        return true;
     }
+#endif
 
-    return true;
-
-#elif defined(_WIN32)
+#if defined(_WIN32)
 
     HDC hDC = wglGetCurrentDC();
     if (!hDC) {