]> git.cworth.org Git - apitrace/blobdiff - glstate_images.cpp
Drop TRACE_EGL.
[apitrace] / glstate_images.cpp
index 93dc55c5ac9aa3336d62b35e54a8d62294e53fc7..2c7c66b407dae4192199b09f72bb05d51e8e98f4 100644 (file)
 #include "glstate_internal.hpp"
 
 
+#ifdef __linux__
+#include <dlfcn.h>
+#endif
+
 #ifdef __APPLE__
 
 #include <Carbon/Carbon.h>
@@ -84,12 +88,152 @@ struct ImageDesc
 };
 
 
+/**
+ * OpenGL ES does not support glGetTexLevelParameteriv, but it is possible to
+ * probe whether a texture has a given size by crafting a dummy glTexSubImage()
+ * call.
+ */
+static bool
+probeTextureLevelSizeOES(GLenum target, GLint level, const GLint size[3]) {
+    while (glGetError() != GL_NO_ERROR)
+        ;
+
+    GLenum internalFormat = GL_RGBA;
+    GLenum type = GL_UNSIGNED_BYTE;
+    GLint dummy = 0;
+
+    switch (target) {
+    case GL_TEXTURE_2D:
+    case GL_TEXTURE_CUBE_MAP:
+    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:
+        glTexSubImage2D(target, level, size[0], size[1], 0, 0, internalFormat, type, &dummy);
+        break;
+    case GL_TEXTURE_3D_OES:
+        glTexSubImage3DOES(target, level, size[0], size[1], size[2], 0, 0, 0, internalFormat, type, &dummy);
+    default:
+        assert(0);
+        return false;
+    }
+
+    GLenum error = glGetError();
+
+    if (0) {
+        std::cerr << "(" << size[0] << ", " << size[1] << ", " << size[2] << ") = " << enumToString(error) << "\n";
+    }
+
+    if (error == GL_NO_ERROR) {
+        return true;
+    }
+
+    while (glGetError() != GL_NO_ERROR)
+        ;
+
+    return false;
+}
+
+
+/**
+ * Bisect the texture size along an axis.
+ *
+ * It is assumed that the texture exists.
+ */
+static GLint
+bisectTextureLevelSizeOES(GLenum target, GLint level, GLint axis, GLint max) {
+    GLint size[3] = {0, 0, 0};
+
+    assert(axis < 3);
+    assert(max >= 0);
+
+    GLint min = 0;
+    while (true) {
+        GLint test = (min + max) / 2;
+        if (test == min) {
+            return min;
+        }
+
+        size[axis] = test;
+
+        if (probeTextureLevelSizeOES(target, level, size)) {
+            min = test;
+        } else {
+            max = test;
+        }
+    }
+}
+
+
+/**
+ * Special path to obtain texture size on OpenGL ES, that does not rely on
+ * glGetTexLevelParameteriv
+ */
+static bool
+getActiveTextureLevelDescOES(Context &context, GLenum target, GLint level, ImageDesc &desc)
+{
+    if (target == GL_TEXTURE_1D) {
+        // OpenGL ES does not support 1D textures
+        return false;
+    }
+
+    const GLint size[3] = {1, 1, 1}; 
+    if (!probeTextureLevelSizeOES(target, level, size)) {
+        return false;
+    }
+
+    // XXX: mere guess
+    desc.internalFormat = GL_RGBA;
+
+    GLint maxSize = 0;
+    switch (target) {
+    case GL_TEXTURE_2D:
+        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+        desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize);
+        desc.height = bisectTextureLevelSizeOES(target, level, 1, maxSize);
+        desc.depth = 1;
+        break;
+    case GL_TEXTURE_CUBE_MAP:
+    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:
+        glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxSize);
+        desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize);
+        desc.height = desc.width;
+        desc.depth = 1;
+        break;
+    case GL_TEXTURE_3D_OES:
+        glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_OES, &maxSize);
+        desc.width = bisectTextureLevelSizeOES(target, level, 0, maxSize);
+        desc.width = bisectTextureLevelSizeOES(target, level, 1, maxSize);
+        desc.depth = bisectTextureLevelSizeOES(target, level, 2, maxSize);
+        break;
+    default:
+        return false;
+    }
+
+    if (0) {
+        std::cerr
+            << enumToString(target) << " "
+            << level << " "
+            << desc.width << "x" << desc.height << "x" << desc.depth
+            << "\n";
+    }
+
+    return desc.valid();
+}
+
+
 static inline bool
 getActiveTextureLevelDesc(Context &context, GLenum target, GLint level, ImageDesc &desc)
 {
     if (context.ES) {
-        // XXX: OpenGL ES does not support glGetTexLevelParameteriv
-        return false;
+        return getActiveTextureLevelDescOES(context, target, level, desc);
     }
 
     glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &desc.internalFormat);
@@ -115,6 +259,77 @@ 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 void
 dumpActiveTextureLevel(JSONWriter &json, Context &context, GLenum target, GLint level)
 {
@@ -153,7 +368,11 @@ dumpActiveTextureLevel(JSONWriter &json, Context &context, GLenum target, GLint
 
     context.resetPixelPackState();
 
-    glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    if (context.ES) {
+        getTexImageOES(target, level, desc, pixels);
+    } else {
+        glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    }
 
     context.restorePixelPackState();
 
@@ -228,31 +447,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) {