]> git.cworth.org Git - apitrace/commitdiff
Move retracers to their own directory.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Sat, 14 Apr 2012 16:22:57 +0000 (17:22 +0100)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Sat, 14 Apr 2012 16:22:57 +0000 (17:22 +0100)
56 files changed:
.gitignore
CMakeLists.txt
d3dretrace.hpp [deleted file]
d3dretrace.py [deleted file]
d3dretrace_main.cpp [deleted file]
glretrace.hpp [deleted file]
glretrace.py [deleted file]
glretrace_cgl.cpp [deleted file]
glretrace_egl.cpp [deleted file]
glretrace_glx.cpp [deleted file]
glretrace_main.cpp [deleted file]
glretrace_wgl.cpp [deleted file]
glstate.cpp [deleted file]
glstate.hpp [deleted file]
glstate_images.cpp [deleted file]
glstate_internal.hpp [deleted file]
glstate_params.py [deleted file]
glstate_shaders.cpp [deleted file]
glws.cpp [deleted file]
glws.hpp [deleted file]
glws_cocoa.mm [deleted file]
glws_egl_xlib.cpp [deleted file]
glws_glx.cpp [deleted file]
glws_wgl.cpp [deleted file]
retrace.cpp [deleted file]
retrace.hpp [deleted file]
retrace.py [deleted file]
retrace/.gitignore [new file with mode: 0644]
retrace/CMakeLists.txt [new file with mode: 0644]
retrace/d3dretrace.hpp [new file with mode: 0644]
retrace/d3dretrace.py [new file with mode: 0644]
retrace/d3dretrace_main.cpp [new file with mode: 0644]
retrace/glretrace.hpp [new file with mode: 0644]
retrace/glretrace.py [new file with mode: 0644]
retrace/glretrace_cgl.cpp [new file with mode: 0644]
retrace/glretrace_egl.cpp [new file with mode: 0644]
retrace/glretrace_glx.cpp [new file with mode: 0644]
retrace/glretrace_main.cpp [new file with mode: 0644]
retrace/glretrace_wgl.cpp [new file with mode: 0644]
retrace/glstate.cpp [new file with mode: 0644]
retrace/glstate.hpp [new file with mode: 0644]
retrace/glstate_images.cpp [new file with mode: 0644]
retrace/glstate_internal.hpp [new file with mode: 0644]
retrace/glstate_params.py [new file with mode: 0644]
retrace/glstate_shaders.cpp [new file with mode: 0644]
retrace/glws.cpp [new file with mode: 0644]
retrace/glws.hpp [new file with mode: 0644]
retrace/glws_cocoa.mm [new file with mode: 0644]
retrace/glws_egl_xlib.cpp [new file with mode: 0644]
retrace/glws_glx.cpp [new file with mode: 0644]
retrace/glws_wgl.cpp [new file with mode: 0644]
retrace/retrace.cpp [new file with mode: 0644]
retrace/retrace.hpp [new file with mode: 0644]
retrace/retrace.py [new file with mode: 0644]
retrace/retrace_stdc.cpp [new file with mode: 0644]
retrace_stdc.cpp [deleted file]

index 25f71f6bd043496e2daa51a2aa57bd9639bfa493..93f029ee900366ba830084dbf4e799d597fbfa39 100644 (file)
@@ -34,8 +34,6 @@ dxsdk
 eglretrace
 glproc.hpp
 glretrace
-glretrace_gl.cpp
-glstate_params.cpp
 install_manifest.txt
 qapitrace
 traces
index 855d73fc1aa19fa923b48da87d01b72dc6c0d980..1d5c99fe80e66df09d0f8f571e9057f75acbb2de 100644 (file)
@@ -304,146 +304,8 @@ add_subdirectory (wrappers)
 ##############################################################################
 # API retracers
 
-add_custom_command (
-    OUTPUT glretrace_gl.cpp
-    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/glretrace_gl.cpp
-    DEPENDS glretrace.py retrace.py specs/glapi.py specs/gltypes.py specs/stdapi.py
-)
-
-add_custom_command (
-    OUTPUT glstate_params.cpp
-    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glstate_params.py > ${CMAKE_CURRENT_BINARY_DIR}/glstate_params.cpp
-    DEPENDS glstate_params.py specs/glparams.py specs/gltypes.py specs/stdapi.py
-)
-
-add_library (retrace_common
-    glretrace_gl.cpp
-    glretrace_cgl.cpp
-    glretrace_glx.cpp
-    glretrace_wgl.cpp
-    glretrace_egl.cpp
-    glretrace_main.cpp
-    glstate.cpp
-    glstate_images.cpp
-    glstate_params.cpp
-    glstate_shaders.cpp
-    retrace.cpp
-    retrace_stdc.cpp
-    glws.cpp
-)
-
-add_dependencies (retrace_common glproc)
-
-set_property (
-    TARGET retrace_common
-    APPEND
-    PROPERTY COMPILE_DEFINITIONS "RETRACE"
-)
-
-if (WIN32 OR APPLE OR X11_FOUND)
-    add_executable (glretrace
-        ${glws_os}
-        glproc_gl.cpp
-    )
-
-    add_dependencies (glretrace glproc)
-
-    set_property (
-        TARGET glretrace
-        APPEND
-        PROPERTY COMPILE_DEFINITIONS "RETRACE"
-    )
-
-    target_link_libraries (glretrace
-        retrace_common
-        common
-        ${PNG_LIBRARIES}
-        ${ZLIB_LIBRARIES}
-        ${SNAPPY_LIBRARIES}
-    )
+add_subdirectory (retrace)
 
-    if (WIN32)
-    else ()
-        if (APPLE)
-            target_link_libraries (glretrace
-                "-framework Cocoa"
-                "-framework ApplicationServices" # CGS*
-                #"-framework OpenGL" # CGL*
-            )
-        else ()
-            target_link_libraries (glretrace ${X11_X11_LIB})
-        endif ()
-
-        target_link_libraries (glretrace
-            # gdb doesn't like when pthreads is loaded through dlopen (which happens
-            # when dlopen'ing libGL), so link pthreads to avoid this issue.  See also
-            # http://stackoverflow.com/questions/2702628/gdb-cannot-find-new-threads-generic-error
-            ${CMAKE_THREAD_LIBS_INIT}
-            dl
-        )
-
-        if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-            target_link_libraries (glretrace rt)
-        endif ()
-
-    endif ()
-
-    install (TARGETS glretrace RUNTIME DESTINATION bin) 
-endif ()
-
-if (ENABLE_EGL AND X11_FOUND AND NOT WIN32 AND NOT APPLE)
-    add_executable (eglretrace
-        glws_egl_xlib.cpp
-        glproc_egl.cpp
-    )
-
-    add_dependencies (eglretrace glproc)
-
-    set_property (
-        TARGET eglretrace
-        APPEND
-        PROPERTY COMPILE_DEFINITIONS "RETRACE"
-    )
-
-    target_link_libraries (eglretrace
-        retrace_common
-        common
-        ${PNG_LIBRARIES}
-        ${ZLIB_LIBRARIES}
-        ${SNAPPY_LIBRARIES}
-        ${X11_X11_LIB}
-        ${CMAKE_THREAD_LIBS_INIT}
-        dl
-    )
-
-    if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-        target_link_libraries (eglretrace rt)
-    endif ()
-
-    install (TARGETS eglretrace RUNTIME DESTINATION bin) 
-endif ()
-
-if (WIN32 AND DirectX_D3DX9_FOUND)
-    add_custom_command (
-        OUTPUT d3dretrace_d3d9.cpp
-        COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3dretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3dretrace_d3d9.cpp
-        DEPENDS d3dretrace.py retrace.py specs/d3d9.py specs/d3d9types.py specs/d3d9caps.py specs/winapi.py specs/stdapi.py
-    )
-
-    include_directories (SYSTEM ${DirectX_D3DX9_INCLUDE_DIR})
-    add_executable (d3dretrace
-        retrace.cpp
-        retrace_stdc.cpp
-        d3dretrace_main.cpp
-        d3dretrace_d3d9.cpp
-    )
-    target_link_libraries (d3dretrace
-        common
-        ${ZLIB_LIBRARIES}
-        ${SNAPPY_LIBRARIES}
-        ${DirectX_D3D9_LIBRARY}
-    )
-endif ()
 
 ##############################################################################
 # CLI
diff --git a/d3dretrace.hpp b/d3dretrace.hpp
deleted file mode 100644 (file)
index cac94cc..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2012 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _D3DRETRACE_HPP_
-#define _D3DRETRACE_HPP_
-
-#include "retrace.hpp"
-
-
-namespace d3dretrace {
-
-
-extern const retrace::Entry d3d9_callbacks[];
-
-
-} /* namespace d3dretrace */
-
-
-#endif /* _D3DRETRACE_HPP_ */
diff --git a/d3dretrace.py b/d3dretrace.py
deleted file mode 100644 (file)
index a2ea75e..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-##########################################################################
-#
-# Copyright 2011 Jose Fonseca
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-"""GL retracer generator."""
-
-
-import specs.stdapi as stdapi
-from specs.d3d9 import d3d9
-from retrace import Retracer
-
-
-class D3DRetracer(Retracer):
-
-    table_name = 'd3dretrace::d3d9_callbacks'
-
-    def invokeInterfaceMethod(self, interface, method):
-        if interface.name == 'IDirect3D9' and method.name == 'CreateDevice':
-            print 'HWND hWnd = createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);'
-            print 'pPresentationParameters->hDeviceWindow = hWnd;'
-            print 'hFocusWindow = hWnd;'
-
-        Retracer.invokeInterfaceMethod(self, interface, method)
-
-        if str(method.type) == 'HRESULT':
-            print r'    if (__result != S_OK) {'
-            print r'        retrace::warning(call) << "failed\n";'
-            print r'    }'
-
-        if interface.name == 'IDirect3DVertexBuffer9' and method.name == 'Lock':
-            print '        if (!SizeToLock) {'
-            print '            D3DVERTEXBUFFER_DESC Desc;'
-            print '            _this->GetDesc(&Desc);'
-            print '            SizeToLock = Desc.Size;'
-            print '        }'
-
-
-if __name__ == '__main__':
-    print r'''
-#include <string.h>
-
-#include <iostream>
-
-#include "d3d9imports.hpp"
-#include "d3dretrace.hpp"
-
-
-// XXX: Don't duplicate this code.
-
-static LRESULT CALLBACK
-WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    MINMAXINFO *pMMI;
-    switch (uMsg) {
-    case WM_GETMINMAXINFO:
-        // Allow to create a window bigger than the desktop
-        pMMI = (MINMAXINFO *)lParam;
-        pMMI->ptMaxSize.x = 60000;
-        pMMI->ptMaxSize.y = 60000;
-        pMMI->ptMaxTrackSize.x = 60000;
-        pMMI->ptMaxTrackSize.y = 60000;
-        break;
-    default:
-        break;
-    }
-
-    return DefWindowProc(hWnd, uMsg, wParam, lParam);
-}
-
-
-static HWND
-createWindow(int width, int height) {
-    static bool first = TRUE;
-    RECT rect;
-
-    if (first) {
-        WNDCLASS wc;
-        memset(&wc, 0, sizeof wc);
-        wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
-        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
-        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-        wc.lpfnWndProc = WndProc;
-        wc.lpszClassName = "d3dretrace";
-        wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
-        RegisterClass(&wc);
-        first = FALSE;
-    }
-
-    DWORD dwExStyle;
-    DWORD dwStyle;
-    HWND hWnd;
-
-    dwExStyle = 0;
-    dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
-
-    int x = 0, y = 0;
-
-    rect.left = x;
-    rect.top = y;
-    rect.right = rect.left + width;
-    rect.bottom = rect.top + height;
-
-    AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
-
-    hWnd = CreateWindowEx(dwExStyle,
-                          "d3dretrace", /* wc.lpszClassName */
-                          NULL,
-                          dwStyle,
-                          0, /* x */
-                          0, /* y */
-                          rect.right - rect.left, /* width */
-                          rect.bottom - rect.top, /* height */
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL);
-    ShowWindow(hWnd, SW_SHOW);
-    return hWnd;
-}
-
-'''
-    retracer = D3DRetracer()
-    retracer.retraceApi(d3d9)
diff --git a/d3dretrace_main.cpp b/d3dretrace_main.cpp
deleted file mode 100644 (file)
index 133f3a7..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include "os_string.hpp"
-#include "retrace.hpp"
-#include "d3dretrace.hpp"
-
-
-namespace d3dretrace {
-
-static void display(void) {
-    retrace::Retracer retracer;
-
-    retracer.addCallbacks(d3d9_callbacks);
-
-    trace::Call *call;
-
-    while ((call = retrace::parser.parse_call())) {
-        retracer.retrace(*call);
-
-        delete call;
-    }
-
-    exit(0);
-}
-
-
-static void usage(void) {
-    std::cout << 
-        "Usage: d3dretrace [OPTION] TRACE\n"
-        "Replay TRACE.\n"
-        "\n"
-        "  -v           increase output verbosity\n"
-    ;
-}
-
-
-extern "C"
-int main(int argc, char **argv)
-{
-
-    int i;
-    for (i = 1; i < argc; ++i) {
-        const char *arg = argv[i];
-
-        if (arg[0] != '-') {
-            break;
-        }
-
-        if (!strcmp(arg, "--")) {
-            break;
-        } else if (!strcmp(arg, "--help")) {
-            usage();
-            return 0;
-        } else if (!strcmp(arg, "-v")) {
-            ++retrace::verbosity;
-        } else {
-            std::cerr << "error: unknown option " << arg << "\n";
-            usage();
-            return 1;
-        }
-    }
-
-    for ( ; i < argc; ++i) {
-        if (!retrace::parser.open(argv[i])) {
-            std::cerr << "error: failed to open " << argv[i] << "\n";
-            return 1;
-        }
-
-        display();
-
-        retrace::parser.close();
-    }
-
-    return 0;
-}
-
-} /* namespace glretrace */
diff --git a/glretrace.hpp b/glretrace.hpp
deleted file mode 100644 (file)
index 8ba2a80..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _GLRETRACE_HPP_
-#define _GLRETRACE_HPP_
-
-#include "glws.hpp"
-#include "retrace.hpp"
-
-
-namespace glretrace {
-
-
-extern bool double_buffer;
-extern bool insideGlBeginEnd;
-extern glws::Profile defaultProfile;
-extern glws::Visual *visual[glws::PROFILE_MAX];
-extern glws::Drawable *drawable;
-extern glws::Context *context;
-
-extern unsigned frame;
-extern long long startTime;
-extern bool wait;
-
-extern bool benchmark;
-
-extern unsigned dump_state;
-
-void
-checkGlError(trace::Call &call);
-
-extern const retrace::Entry gl_callbacks[];
-extern const retrace::Entry cgl_callbacks[];
-extern const retrace::Entry glx_callbacks[];
-extern const retrace::Entry wgl_callbacks[];
-extern const retrace::Entry egl_callbacks[];
-
-void frame_complete(trace::Call &call);
-
-void updateDrawable(int width, int height);
-
-} /* namespace glretrace */
-
-
-#endif /* _GLRETRACE_HPP_ */
diff --git a/glretrace.py b/glretrace.py
deleted file mode 100644 (file)
index d91c8a2..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-##########################################################################
-#
-# Copyright 2010 VMware, Inc.
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-"""GL retracer generator."""
-
-
-import specs.stdapi as stdapi
-import specs.glapi as glapi
-import specs.glesapi as glesapi
-from retrace import Retracer
-
-
-class GlRetracer(Retracer):
-
-    table_name = 'glretrace::gl_callbacks'
-
-    def retraceFunction(self, function):
-        Retracer.retraceFunction(self, function)
-
-    array_pointer_function_names = set((
-        "glVertexPointer",
-        "glNormalPointer",
-        "glColorPointer",
-        "glIndexPointer",
-        "glTexCoordPointer",
-        "glEdgeFlagPointer",
-        "glFogCoordPointer",
-        "glSecondaryColorPointer",
-
-        "glInterleavedArrays",
-
-        "glVertexPointerEXT",
-        "glNormalPointerEXT",
-        "glColorPointerEXT",
-        "glIndexPointerEXT",
-        "glTexCoordPointerEXT",
-        "glEdgeFlagPointerEXT",
-        "glFogCoordPointerEXT",
-        "glSecondaryColorPointerEXT",
-
-        "glVertexAttribPointer",
-        "glVertexAttribPointerARB",
-        "glVertexAttribPointerNV",
-        "glVertexAttribIPointer",
-        "glVertexAttribIPointerEXT",
-        "glVertexAttribLPointer",
-        "glVertexAttribLPointerEXT",
-        
-        #"glMatrixIndexPointerARB",
-    ))
-
-    draw_array_function_names = set([
-        "glDrawArrays",
-        "glDrawArraysEXT",
-        "glDrawArraysIndirect",
-        "glDrawArraysInstanced",
-        "glDrawArraysInstancedARB",
-        "glDrawArraysInstancedEXT",
-        "glDrawArraysInstancedBaseInstance",
-        "glDrawMeshArraysSUN",
-        "glMultiDrawArrays",
-        "glMultiDrawArraysEXT",
-        "glMultiModeDrawArraysIBM",
-    ])
-
-    draw_elements_function_names = set([
-        "glDrawElements",
-        "glDrawElementsBaseVertex",
-        "glDrawElementsIndirect",
-        "glDrawElementsInstanced",
-        "glDrawElementsInstancedARB",
-        "glDrawElementsInstancedEXT",
-        "glDrawElementsInstancedBaseVertex",
-        "glDrawElementsInstancedBaseInstance",
-        "glDrawElementsInstancedBaseVertexBaseInstance",
-        "glDrawRangeElements",
-        "glDrawRangeElementsEXT",
-        "glDrawRangeElementsBaseVertex",
-        "glMultiDrawElements",
-        "glMultiDrawElementsBaseVertex",
-        "glMultiDrawElementsEXT",
-        "glMultiModeDrawElementsIBM",
-    ])
-
-    draw_indirect_function_names = set([
-        "glDrawArraysIndirect",
-        "glDrawElementsIndirect",
-    ])
-
-    misc_draw_function_names = set([
-        "glCallList",
-        "glCallLists",
-        "glClear",
-        "glEnd",
-        "glDrawPixels",
-        "glBlitFramebuffer",
-        "glBlitFramebufferEXT",
-    ])
-
-    bind_framebuffer_function_names = set([
-        "glBindFramebuffer",
-        "glBindFramebufferEXT",
-        "glBindFramebufferOES",
-    ])
-
-    # Names of the functions that can pack into the current pixel buffer
-    # object.  See also the ARB_pixel_buffer_object specification.
-    pack_function_names = set([
-        'glGetCompressedTexImage',
-        'glGetConvolutionFilter',
-        'glGetHistogram',
-        'glGetMinmax',
-        'glGetPixelMapfv',
-        'glGetPixelMapuiv',
-        'glGetPixelMapusv',
-        'glGetPolygonStipple',
-        'glGetSeparableFilter',
-        'glGetTexImage',
-        'glReadPixels',
-        'glGetnCompressedTexImageARB',
-        'glGetnConvolutionFilterARB',
-        'glGetnHistogramARB',
-        'glGetnMinmaxARB',
-        'glGetnPixelMapfvARB',
-        'glGetnPixelMapuivARB',
-        'glGetnPixelMapusvARB',
-        'glGetnPolygonStippleARB',
-        'glGetnSeparableFilterARB',
-        'glGetnTexImageARB',
-        'glReadnPixelsARB',
-    ])
-
-    map_function_names = set([
-        'glMapBuffer',
-        'glMapBufferARB',
-        'glMapBufferOES',
-        'glMapBufferRange',
-        'glMapNamedBufferEXT',
-        'glMapNamedBufferRangeEXT',
-        'glMapObjectBufferATI',
-    ])
-
-    unmap_function_names = set([
-        'glUnmapBuffer',
-        'glUnmapBufferARB',
-        'glUnmapBufferOES',
-        'glUnmapNamedBufferEXT',
-        'glUnmapObjectBufferATI',
-    ])
-
-    def retraceFunctionBody(self, function):
-        is_array_pointer = function.name in self.array_pointer_function_names
-        is_draw_array = function.name in self.draw_array_function_names
-        is_draw_elements = function.name in self.draw_elements_function_names
-        is_misc_draw = function.name in self.misc_draw_function_names
-
-        if is_array_pointer or is_draw_array or is_draw_elements:
-            print '    if (retrace::parser.version < 1) {'
-
-            if is_array_pointer or is_draw_array:
-                print '        GLint __array_buffer = 0;'
-                print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
-                print '        if (!__array_buffer) {'
-                self.failFunction(function)
-                print '        }'
-
-            if is_draw_elements:
-                print '        GLint __element_array_buffer = 0;'
-                print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
-                print '        if (!__element_array_buffer) {'
-                self.failFunction(function)
-                print '        }'
-            
-            print '    }'
-
-        # When no pack buffer object is bound, the pack functions are no-ops.
-        if function.name in self.pack_function_names:
-            print '    GLint __pack_buffer = 0;'
-            print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
-            print '    if (!__pack_buffer) {'
-            print '        return;'
-            print '    }'
-
-        # Pre-snapshots
-        if function.name in self.bind_framebuffer_function_names:
-            print '    assert(call.flags & trace::CALL_FLAG_SWAP_RENDERTARGET);'
-        if function.name == 'glFrameTerminatorGREMEDY':
-            print '    glretrace::frame_complete(call);'
-            return
-
-        Retracer.retraceFunctionBody(self, function)
-
-        # Post-snapshots
-        if function.name in ('glFlush', 'glFinish'):
-            print '    if (!glretrace::double_buffer) {'
-            print '        glretrace::frame_complete(call);'
-            print '    }'
-        if is_draw_array or is_draw_elements or is_misc_draw:
-            print '    assert(call.flags & trace::CALL_FLAG_RENDER);'
-
-
-    def invokeFunction(self, function):
-        # Infer the drawable size from GL calls
-        if function.name == "glViewport":
-            print '    glretrace::updateDrawable(x + width, y + height);'
-        if function.name == "glViewportArray":
-            # We are concerned about drawables so only care for the first viewport
-            print '    if (first == 0 && count > 0) {'
-            print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
-            print '        glretrace::updateDrawable(x + w, y + h);'
-            print '    }'
-        if function.name == "glViewportIndexedf":
-            print '    if (index == 0) {'
-            print '        glretrace::updateDrawable(x + w, y + h);'
-            print '    }'
-        if function.name == "glViewportIndexedfv":
-            print '    if (index == 0) {'
-            print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
-            print '        glretrace::updateDrawable(x + w, y + h);'
-            print '    }'
-        if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
-            # Some applications do all their rendering in a framebuffer, and
-            # then just blit to the drawable without ever calling glViewport.
-            print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
-
-        if function.name == "glEnd":
-            print '    glretrace::insideGlBeginEnd = false;'
-
-        if function.name.startswith('gl') and not function.name.startswith('glX'):
-            print r'    if (!glretrace::context && !glretrace::benchmark && !retrace::profiling) {'
-            print r'        retrace::warning(call) << "no current context\n";'
-            print r'    }'
-
-        if function.name == 'memcpy':
-            print '    if (!dest || !src || !n) return;'
-
-        # Destroy the buffer mapping
-        if function.name in self.unmap_function_names:
-            print r'        GLvoid *ptr = NULL;'
-            if function.name == 'glUnmapBuffer':
-                print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
-            elif function.name == 'glUnmapBufferARB':
-                print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
-            elif function.name == 'glUnmapBufferOES':
-                print r'            glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);'
-            elif function.name == 'glUnmapNamedBufferEXT':
-                print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
-            elif function.name == 'glUnmapObjectBufferATI':
-                # TODO
-                pass
-            else:
-                assert False
-            print r'        if (ptr) {'
-            print r'            retrace::delRegionByPointer(ptr);'
-            print r'        } else {'
-            print r'            retrace::warning(call) << "no current context\n";'
-            print r'        }'
-        
-        Retracer.invokeFunction(self, function)
-
-        # Error checking
-        if function.name == "glBegin":
-            print '    glretrace::insideGlBeginEnd = true;'
-        elif function.name.startswith('gl'):
-            # glGetError is not allowed inside glBegin/glEnd
-            print '    if (!glretrace::benchmark && !retrace::profiling && !glretrace::insideGlBeginEnd) {'
-            print '        glretrace::checkGlError(call);'
-            if function.name in ('glProgramStringARB', 'glProgramStringNV'):
-                print r'        GLint error_position = -1;'
-                print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
-                print r'        if (error_position != -1) {'
-                print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
-                print r'            retrace::warning(call) << error_string << "\n";'
-                print r'        }'
-            if function.name == 'glCompileShader':
-                print r'        GLint compile_status = 0;'
-                print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
-                print r'        if (!compile_status) {'
-                print r'             GLint info_log_length = 0;'
-                print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
-                print r'             GLchar *infoLog = new GLchar[info_log_length];'
-                print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
-                print r'             retrace::warning(call) << infoLog << "\n";'
-                print r'             delete [] infoLog;'
-                print r'        }'
-            if function.name == 'glLinkProgram':
-                print r'        GLint link_status = 0;'
-                print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
-                print r'        if (!link_status) {'
-                print r'             GLint info_log_length = 0;'
-                print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
-                print r'             GLchar *infoLog = new GLchar[info_log_length];'
-                print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
-                print r'             retrace::warning(call) << infoLog << "\n";'
-                print r'             delete [] infoLog;'
-                print r'        }'
-            if function.name == 'glCompileShaderARB':
-                print r'        GLint compile_status = 0;'
-                print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
-                print r'        if (!compile_status) {'
-                print r'             GLint info_log_length = 0;'
-                print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
-                print r'             GLchar *infoLog = new GLchar[info_log_length];'
-                print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
-                print r'             retrace::warning(call) << infoLog << "\n";'
-                print r'             delete [] infoLog;'
-                print r'        }'
-            if function.name == 'glLinkProgramARB':
-                print r'        GLint link_status = 0;'
-                print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
-                print r'        if (!link_status) {'
-                print r'             GLint info_log_length = 0;'
-                print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
-                print r'             GLchar *infoLog = new GLchar[info_log_length];'
-                print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
-                print r'             retrace::warning(call) << infoLog << "\n";'
-                print r'             delete [] infoLog;'
-                print r'        }'
-            if function.name in self.map_function_names:
-                print r'        if (!__result) {'
-                print r'             retrace::warning(call) << "failed to map buffer\n";'
-                print r'        }'
-            if function.name in self.unmap_function_names and function.type is not stdapi.Void:
-                print r'        if (!__result) {'
-                print r'             retrace::warning(call) << "failed to unmap buffer\n";'
-                print r'        }'
-            if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
-                print r'    GLint __orig_result = call.ret->toSInt();'
-                print r'    if (__result != __orig_result) {'
-                print r'        retrace::warning(call) << "vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
-                print r'    }'
-            if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
-                print r'    GLint __orig_result = call.ret->toSInt();'
-                print r'    if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
-                print r'        __result != GL_FRAMEBUFFER_COMPLETE) {'
-                print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
-                print r'    }'
-            print '    }'
-
-        # Query the buffer length for whole buffer mappings
-        if function.name in self.map_function_names:
-            if 'length' in function.argNames():
-                assert 'BufferRange' in function.name
-            else:
-                assert 'BufferRange' not in function.name
-                print r'    GLint length = 0;'
-                if function.name in ('glMapBuffer', 'glMapBufferOES'):
-                    print r'    glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
-                elif function.name == 'glMapBufferARB':
-                    print r'    glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
-                elif function.name == 'glMapNamedBufferEXT':
-                    print r'    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
-                elif function.name == 'glMapObjectBufferATI':
-                    print r'    glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);'
-                else:
-                    assert False
-
-    def extractArg(self, function, arg, arg_type, lvalue, rvalue):
-        if function.name in self.array_pointer_function_names and arg.name == 'pointer':
-            print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
-            return
-
-        if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
-           function.name in self.draw_indirect_function_names and arg.name == 'indirect':
-            self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
-            return
-
-        # Handle pointer with offsets into the current pack pixel buffer
-        # object.
-        if function.name in self.pack_function_names and arg.output:
-            assert isinstance(arg_type, (stdapi.Pointer, stdapi.Array, stdapi.Blob, stdapi.Opaque))
-            print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, arg_type, rvalue)
-            return
-
-        if arg.type is glapi.GLlocation \
-           and 'program' not in function.argNames():
-            print '    GLint program = -1;'
-            print '    glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
-        
-        if arg.type is glapi.GLlocationARB \
-           and 'programObj' not in function.argNames():
-            print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
-
-        Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
-
-        # Don't try to use more samples than the implementation supports
-        if arg.name == 'samples':
-            assert arg.type is glapi.GLsizei
-            print '    GLint max_samples = 0;'
-            print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
-            print '    if (samples > max_samples) {'
-            print '        samples = max_samples;'
-            print '    }'
-
-        # These parameters are referred beyond the call life-time
-        # TODO: Replace ad-hoc solution for bindable parameters with general one
-        if function.name in ('glFeedbackBuffer', 'glSelectBuffer') and arg.output:
-            print '    _allocator.bind(%s);' % arg.name
-
-
-
-if __name__ == '__main__':
-    print r'''
-#include <string.h>
-
-#include "glproc.hpp"
-#include "glretrace.hpp"
-#include "glstate.hpp"
-
-
-'''
-    api = glapi.glapi
-    api.addApi(glesapi.glesapi)
-    retracer = GlRetracer()
-    retracer.retraceApi(api)
diff --git a/glretrace_cgl.cpp b/glretrace_cgl.cpp
deleted file mode 100644 (file)
index 63b94b4..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include "glproc.hpp"
-#include "retrace.hpp"
-#include "glretrace.hpp"
-
-
-using namespace glretrace;
-
-
-typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
-typedef std::map<unsigned long long, glws::Context *> ContextMap;
-static DrawableMap drawable_map;
-static ContextMap context_map;
-static glws::Context *sharedContext = NULL;
-
-
-static glws::Drawable *
-getDrawable(unsigned long drawable_id) {
-    if (drawable_id == 0) {
-        return NULL;
-    }
-
-    /* XXX: Support multiple drawables. */
-    drawable_id = 1;
-
-    DrawableMap::const_iterator it;
-    it = drawable_map.find(drawable_id);
-    if (it == drawable_map.end()) {
-        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
-    }
-
-    return it->second;
-}
-
-
-static glws::Context *
-getContext(unsigned long long ctx) {
-    if (ctx == 0) {
-        return NULL;
-    }
-
-    ContextMap::const_iterator it;
-    it = context_map.find(ctx);
-    if (it == context_map.end()) {
-        glws::Context *context;
-        context_map[ctx] = context = glws::createContext(visual[glretrace::defaultProfile], sharedContext, glretrace::defaultProfile);
-        if (!sharedContext) {
-            sharedContext = context;
-        }
-        return context;
-    }
-
-    return it->second;
-}
-
-
-static void retrace_CGLSetCurrentContext(trace::Call &call) {
-    unsigned long long ctx = call.arg(0).toUIntPtr();
-
-    glws::Drawable *new_drawable = getDrawable(ctx);
-    glws::Context *new_context = getContext(ctx);
-
-    bool result = glws::makeCurrent(new_drawable, new_context);
-
-    if (new_drawable && new_context && result) {
-        drawable = new_drawable;
-        context = new_context;
-    } else {
-        drawable = NULL;
-        context = NULL;
-    }
-}
-
-
-static void retrace_CGLFlushDrawable(trace::Call &call) {
-    if (drawable && context) {
-        if (double_buffer) {
-            drawable->swapBuffers();
-        } else {
-            glFlush();
-        }
-
-        frame_complete(call);
-    }
-}
-
-
-const retrace::Entry glretrace::cgl_callbacks[] = {
-    {"CGLSetCurrentContext", &retrace_CGLSetCurrentContext},
-    {"CGLGetCurrentContext", &retrace::ignore},
-    {"CGLEnable", &retrace::ignore},
-    {"CGLDisable", &retrace::ignore},
-    {"CGLSetParameter", &retrace::ignore},
-    {"CGLGetParameter", &retrace::ignore},
-    {"CGLFlushDrawable", &retrace_CGLFlushDrawable},
-    {NULL, NULL},
-};
-
diff --git a/glretrace_egl.cpp b/glretrace_egl.cpp
deleted file mode 100644 (file)
index d7b14ec..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 LunarG, Inc.
- * All Rights Reserved.
- *
- * Based on glretrace_glx.cpp, which has
- *
- *   Copyright 2011 Jose Fonseca
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include "glproc.hpp"
-#include "retrace.hpp"
-#include "glretrace.hpp"
-#include "os.hpp"
-
-#ifndef EGL_OPENGL_ES_API
-#define EGL_OPENGL_ES_API              0x30A0
-#define EGL_OPENVG_API                 0x30A1
-#define EGL_OPENGL_API                 0x30A2
-#define EGL_CONTEXT_CLIENT_VERSION     0x3098
-#endif
-
-
-using namespace glretrace;
-
-
-typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
-typedef std::map<unsigned long long, glws::Context *> ContextMap;
-typedef std::map<unsigned long long, glws::Profile> ProfileMap;
-static DrawableMap drawable_map;
-static ContextMap context_map;
-static ProfileMap profile_map;
-
-static unsigned int current_api = EGL_OPENGL_ES_API;
-static glws::Profile last_profile = glws::PROFILE_COMPAT;
-
-static void
-createDrawable(unsigned long long orig_config, unsigned long long orig_surface);
-
-static glws::Drawable *
-getDrawable(unsigned long long surface_ptr) {
-    if (surface_ptr == 0) {
-        return NULL;
-    }
-
-    DrawableMap::const_iterator it;
-    it = drawable_map.find(surface_ptr);
-    if (it == drawable_map.end()) {
-        // In Fennec we get the egl window surface from Java which isn't
-        // traced, so just create a drawable if it doesn't exist in here
-        createDrawable(0, surface_ptr);
-        it = drawable_map.find(surface_ptr);
-        assert(it != drawable_map.end());
-    }
-
-    return (it != drawable_map.end()) ? it->second : NULL;
-}
-
-static glws::Context *
-getContext(unsigned long long context_ptr) {
-    if (context_ptr == 0) {
-        return NULL;
-    }
-
-    ContextMap::const_iterator it;
-    it = context_map.find(context_ptr);
-
-    return (it != context_map.end()) ? it->second : NULL;
-}
-
-static void createDrawable(unsigned long long orig_config, unsigned long long orig_surface)
-{
-    ProfileMap::iterator it = profile_map.find(orig_config);
-    glws::Profile profile;
-
-    // If the requested config is associated with a profile, use that
-    // profile. Otherwise, assume that the last used profile is what
-    // the user wants.
-    if (it != profile_map.end()) {
-        profile = it->second;
-    } else {
-        profile = last_profile;
-    }
-
-    glws::Visual *visual = glretrace::visual[profile];
-
-    glws::Drawable *drawable = glws::createDrawable(visual);
-    drawable_map[orig_surface] = drawable;
-}
-
-static void retrace_eglCreateWindowSurface(trace::Call &call) {
-    unsigned long long orig_config = call.arg(1).toUIntPtr();
-    unsigned long long orig_surface = call.ret->toUIntPtr();
-    createDrawable(orig_config, orig_surface);
-}
-
-static void retrace_eglCreatePbufferSurface(trace::Call &call) {
-    unsigned long long orig_config = call.arg(1).toUIntPtr();
-    unsigned long long orig_surface = call.ret->toUIntPtr();
-    createDrawable(orig_config, orig_surface);
-    // TODO: Respect the pbuffer dimensions too
-}
-
-static void retrace_eglDestroySurface(trace::Call &call) {
-    unsigned long long orig_surface = call.arg(1).toUIntPtr();
-
-    DrawableMap::iterator it;
-    it = drawable_map.find(orig_surface);
-
-    if (it != drawable_map.end()) {
-        if (it->second != drawable) {
-            // TODO: reference count
-            delete it->second;
-        }
-        drawable_map.erase(it);
-    }
-}
-
-static void retrace_eglBindAPI(trace::Call &call) {
-    current_api = call.arg(0).toUInt();
-}
-
-static void retrace_eglCreateContext(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    unsigned long long orig_config = call.arg(1).toUIntPtr();
-    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
-    trace::Array *attrib_array = dynamic_cast<trace::Array *>(&call.arg(3));
-    glws::Profile profile;
-
-    switch (current_api) {
-    case EGL_OPENGL_API:
-        profile = glws::PROFILE_COMPAT;
-        break;
-    case EGL_OPENGL_ES_API:
-    default:
-        profile = glws::PROFILE_ES1;
-        if (attrib_array) {
-            for (int i = 0; i < attrib_array->values.size(); i += 2) {
-                int v = attrib_array->values[i]->toSInt();
-                if (v == EGL_CONTEXT_CLIENT_VERSION) {
-                    v = attrib_array->values[i + 1]->toSInt();
-                    if (v == 2)
-                        profile = glws::PROFILE_ES2;
-                    break;
-                }
-            }
-        }
-        break;
-    }
-
-
-    glws::Context *context = glws::createContext(glretrace::visual[profile], share_context, profile);
-    if (!context) {
-        const char *name;
-        switch (profile) {
-        case glws::PROFILE_COMPAT:
-            name = "OpenGL";
-            break;
-        case glws::PROFILE_ES1:
-            name = "OpenGL ES 1.1";
-            break;
-        case glws::PROFILE_ES2:
-            name = "OpenGL ES 2.0";
-            break;
-        default:
-            name = "unknown";
-            break;
-        }
-
-        retrace::warning(call) << "Failed to create " << name << " context.\n";
-        os::abort();
-    }
-
-    context_map[orig_context] = context;
-    profile_map[orig_config] = profile;
-    last_profile = profile;
-}
-
-static void retrace_eglDestroyContext(trace::Call &call) {
-    unsigned long long orig_context = call.arg(1).toUIntPtr();
-
-    ContextMap::iterator it;
-    it = context_map.find(orig_context);
-
-    if (it != context_map.end()) {
-        delete it->second;
-        context_map.erase(it);
-    }
-}
-
-static void retrace_eglMakeCurrent(trace::Call &call) {
-    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUIntPtr());
-    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());
-
-    if (new_drawable == drawable && new_context == context) {
-        return;
-    }
-
-    if (drawable && context) {
-        glFlush();
-        if (!double_buffer) {
-            frame_complete(call);
-        }
-    }
-
-    bool result = glws::makeCurrent(new_drawable, new_context);
-
-    if (new_drawable && new_context && result) {
-        drawable = new_drawable;
-        context = new_context;
-    } else {
-        drawable = NULL;
-        context = NULL;
-    }
-}
-
-
-static void retrace_eglSwapBuffers(trace::Call &call) {
-    frame_complete(call);
-
-    if (double_buffer && drawable) {
-        drawable->swapBuffers();
-    } else {
-        glFlush();
-    }
-}
-
-const retrace::Entry glretrace::egl_callbacks[] = {
-    {"eglGetError", &retrace::ignore},
-    {"eglGetDisplay", &retrace::ignore},
-    {"eglInitialize", &retrace::ignore},
-    {"eglTerminate", &retrace::ignore},
-    {"eglQueryString", &retrace::ignore},
-    {"eglGetConfigs", &retrace::ignore},
-    {"eglChooseConfig", &retrace::ignore},
-    {"eglGetConfigAttrib", &retrace::ignore},
-    {"eglCreateWindowSurface", &retrace_eglCreateWindowSurface},
-    {"eglCreatePbufferSurface", &retrace_eglCreatePbufferSurface},
-    //{"eglCreatePixmapSurface", &retrace::ignore},
-    {"eglDestroySurface", &retrace_eglDestroySurface},
-    {"eglQuerySurface", &retrace::ignore},
-    {"eglBindAPI", &retrace_eglBindAPI},
-    {"eglQueryAPI", &retrace::ignore},
-    //{"eglWaitClient", &retrace::ignore},
-    //{"eglReleaseThread", &retrace::ignore},
-    //{"eglCreatePbufferFromClientBuffer", &retrace::ignore},
-    //{"eglSurfaceAttrib", &retrace::ignore},
-    //{"eglBindTexImage", &retrace::ignore},
-    //{"eglReleaseTexImage", &retrace::ignore},
-    {"eglSwapInterval", &retrace::ignore},
-    {"eglCreateContext", &retrace_eglCreateContext},
-    {"eglDestroyContext", &retrace_eglDestroyContext},
-    {"eglMakeCurrent", &retrace_eglMakeCurrent},
-    {"eglGetCurrentContext", &retrace::ignore},
-    {"eglGetCurrentSurface", &retrace::ignore},
-    {"eglGetCurrentDisplay", &retrace::ignore},
-    {"eglQueryContext", &retrace::ignore},
-    {"eglWaitGL", &retrace::ignore},
-    {"eglWaitNative", &retrace::ignore},
-    {"eglSwapBuffers", &retrace_eglSwapBuffers},
-    //{"eglCopyBuffers", &retrace::ignore},
-    {"eglGetProcAddress", &retrace::ignore},
-    {NULL, NULL},
-};
diff --git a/glretrace_glx.cpp b/glretrace_glx.cpp
deleted file mode 100644 (file)
index 7342908..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include "glproc.hpp"
-#include "retrace.hpp"
-#include "glretrace.hpp"
-
-
-using namespace glretrace;
-
-
-typedef std::map<unsigned long, glws::Drawable *> DrawableMap;
-typedef std::map<unsigned long long, glws::Context *> ContextMap;
-static DrawableMap drawable_map;
-static ContextMap context_map;
-
-
-static glws::Drawable *
-getDrawable(unsigned long drawable_id) {
-    if (drawable_id == 0) {
-        return NULL;
-    }
-
-    DrawableMap::const_iterator it;
-    it = drawable_map.find(drawable_id);
-    if (it == drawable_map.end()) {
-        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
-    }
-
-    return it->second;
-}
-
-static glws::Context *
-getContext(unsigned long long context_ptr) {
-    if (context_ptr == 0) {
-        return NULL;
-    }
-
-    ContextMap::const_iterator it;
-    it = context_map.find(context_ptr);
-    if (it == context_map.end()) {
-        return (context_map[context_ptr] = glws::createContext(visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile));
-    }
-
-    return it->second;
-}
-
-static void retrace_glXCreateContext(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
-
-    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
-    context_map[orig_context] = context;
-}
-
-static void retrace_glXCreateContextAttribsARB(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
-
-    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
-    context_map[orig_context] = context;
-}
-
-static void retrace_glXMakeCurrent(trace::Call &call) {
-    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
-    glws::Context *new_context = getContext(call.arg(2).toUIntPtr());
-
-    if (new_drawable == drawable && new_context == context) {
-        return;
-    }
-
-    if (drawable && context) {
-        glFlush();
-        if (!double_buffer) {
-            frame_complete(call);
-        }
-    }
-
-    bool result = glws::makeCurrent(new_drawable, new_context);
-
-    if (new_drawable && new_context && result) {
-        drawable = new_drawable;
-        context = new_context;
-    } else {
-        drawable = NULL;
-        context = NULL;
-    }
-}
-
-
-static void retrace_glXDestroyContext(trace::Call &call) {
-    glws::Context *context = getContext(call.arg(1).toUIntPtr());
-
-    if (!context) {
-        return;
-    }
-
-    delete context;
-}
-
-static void retrace_glXSwapBuffers(trace::Call &call) {
-    frame_complete(call);
-    if (double_buffer) {
-        drawable->swapBuffers();
-    } else {
-        glFlush();
-    }
-}
-
-static void retrace_glXCreateNewContext(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    glws::Context *share_context = getContext(call.arg(3).toUIntPtr());
-
-    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
-    context_map[orig_context] = context;
-}
-
-static void retrace_glXMakeContextCurrent(trace::Call &call) {
-    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
-    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());
-
-    if (new_drawable == drawable && new_context == context) {
-        return;
-    }
-
-    if (drawable && context) {
-        glFlush();
-        if (!double_buffer) {
-            frame_complete(call);
-        }
-    }
-
-    bool result = glws::makeCurrent(new_drawable, new_context);
-
-    if (new_drawable && new_context && result) {
-        drawable = new_drawable;
-        context = new_context;
-    } else {
-        drawable = NULL;
-        context = NULL;
-    }
-}
-
-const retrace::Entry glretrace::glx_callbacks[] = {
-    //{"glXBindChannelToWindowSGIX", &retrace_glXBindChannelToWindowSGIX},
-    //{"glXBindSwapBarrierNV", &retrace_glXBindSwapBarrierNV},
-    //{"glXBindSwapBarrierSGIX", &retrace_glXBindSwapBarrierSGIX},
-    //{"glXBindTexImageEXT", &retrace_glXBindTexImageEXT},
-    //{"glXChannelRectSGIX", &retrace_glXChannelRectSGIX},
-    //{"glXChannelRectSyncSGIX", &retrace_glXChannelRectSyncSGIX},
-    {"glXChooseFBConfig", &retrace::ignore},
-    {"glXChooseFBConfigSGIX", &retrace::ignore},
-    {"glXChooseVisual", &retrace::ignore},
-    //{"glXCopyContext", &retrace_glXCopyContext},
-    //{"glXCopyImageSubDataNV", &retrace_glXCopyImageSubDataNV},
-    //{"glXCopySubBufferMESA", &retrace_glXCopySubBufferMESA},
-    {"glXCreateContextAttribsARB", &retrace_glXCreateContextAttribsARB},
-    {"glXCreateContext", &retrace_glXCreateContext},
-    //{"glXCreateContextWithConfigSGIX", &retrace_glXCreateContextWithConfigSGIX},
-    //{"glXCreateGLXPbufferSGIX", &retrace_glXCreateGLXPbufferSGIX},
-    //{"glXCreateGLXPixmap", &retrace_glXCreateGLXPixmap},
-    //{"glXCreateGLXPixmapWithConfigSGIX", &retrace_glXCreateGLXPixmapWithConfigSGIX},
-    {"glXCreateNewContext", &retrace_glXCreateNewContext},
-    //{"glXCreatePbuffer", &retrace_glXCreatePbuffer},
-    //{"glXCreatePixmap", &retrace_glXCreatePixmap},
-    //{"glXCreateWindow", &retrace_glXCreateWindow},
-    //{"glXCushionSGI", &retrace_glXCushionSGI},
-    {"glXDestroyContext", &retrace_glXDestroyContext},
-    //{"glXDestroyGLXPbufferSGIX", &retrace_glXDestroyGLXPbufferSGIX},
-    //{"glXDestroyGLXPixmap", &retrace_glXDestroyGLXPixmap},
-    //{"glXDestroyPbuffer", &retrace_glXDestroyPbuffer},
-    //{"glXDestroyPixmap", &retrace_glXDestroyPixmap},
-    //{"glXDestroyWindow", &retrace_glXDestroyWindow},
-    //{"glXFreeContextEXT", &retrace_glXFreeContextEXT},
-    {"glXGetAGPOffsetMESA", &retrace::ignore},
-    {"glXGetClientString", &retrace::ignore},
-    {"glXGetConfig", &retrace::ignore},
-    {"glXGetContextIDEXT", &retrace::ignore},
-    {"glXGetCurrentContext", &retrace::ignore},
-    {"glXGetCurrentDisplayEXT", &retrace::ignore},
-    {"glXGetCurrentDisplay", &retrace::ignore},
-    {"glXGetCurrentDrawable", &retrace::ignore},
-    {"glXGetCurrentReadDrawable", &retrace::ignore},
-    {"glXGetCurrentReadDrawableSGI", &retrace::ignore},
-    {"glXGetFBConfigAttrib", &retrace::ignore},
-    {"glXGetFBConfigAttribSGIX", &retrace::ignore},
-    {"glXGetFBConfigFromVisualSGIX", &retrace::ignore},
-    {"glXGetFBConfigs", &retrace::ignore},
-    {"glXGetMscRateOML", &retrace::ignore},
-    {"glXGetProcAddressARB", &retrace::ignore},
-    {"glXGetProcAddress", &retrace::ignore},
-    {"glXGetSelectedEvent", &retrace::ignore},
-    {"glXGetSelectedEventSGIX", &retrace::ignore},
-    {"glXGetSyncValuesOML", &retrace::ignore},
-    {"glXGetVideoSyncSGI", &retrace::ignore},
-    {"glXGetVisualFromFBConfig", &retrace::ignore},
-    {"glXGetVisualFromFBConfigSGIX", &retrace::ignore},
-    //{"glXImportContextEXT", &retrace_glXImportContextEXT},
-    {"glXIsDirect", &retrace::ignore},
-    //{"glXJoinSwapGroupNV", &retrace_glXJoinSwapGroupNV},
-    //{"glXJoinSwapGroupSGIX", &retrace_glXJoinSwapGroupSGIX},
-    {"glXMakeContextCurrent", &retrace_glXMakeContextCurrent},
-    //{"glXMakeCurrentReadSGI", &retrace_glXMakeCurrentReadSGI},
-    {"glXMakeCurrent", &retrace_glXMakeCurrent},
-    {"glXQueryChannelDeltasSGIX", &retrace::ignore},
-    {"glXQueryChannelRectSGIX", &retrace::ignore},
-    {"glXQueryContextInfoEXT", &retrace::ignore},
-    {"glXQueryContext", &retrace::ignore},
-    {"glXQueryDrawable", &retrace::ignore},
-    {"glXQueryExtension", &retrace::ignore},
-    {"glXQueryExtensionsString", &retrace::ignore},
-    {"glXQueryFrameCountNV", &retrace::ignore},
-    {"glXQueryGLXPbufferSGIX", &retrace::ignore},
-    {"glXQueryMaxSwapBarriersSGIX", &retrace::ignore},
-    {"glXQueryMaxSwapGroupsNV", &retrace::ignore},
-    {"glXQueryServerString", &retrace::ignore},
-    {"glXQuerySwapGroupNV", &retrace::ignore},
-    {"glXQueryVersion", &retrace::ignore},
-    //{"glXReleaseBuffersMESA", &retrace_glXReleaseBuffersMESA},
-    //{"glXReleaseTexImageEXT", &retrace_glXReleaseTexImageEXT},
-    //{"glXResetFrameCountNV", &retrace_glXResetFrameCountNV},
-    //{"glXSelectEvent", &retrace_glXSelectEvent},
-    //{"glXSelectEventSGIX", &retrace_glXSelectEventSGIX},
-    //{"glXSet3DfxModeMESA", &retrace_glXSet3DfxModeMESA},
-    //{"glXSwapBuffersMscOML", &retrace_glXSwapBuffersMscOML},
-    {"glXSwapBuffers", &retrace_glXSwapBuffers},
-    {"glXSwapIntervalEXT", &retrace::ignore},
-    {"glXSwapIntervalSGI", &retrace::ignore},
-    //{"glXUseXFont", &retrace_glXUseXFont},
-    {"glXWaitForMscOML", &retrace::ignore},
-    {"glXWaitForSbcOML", &retrace::ignore},
-    {"glXWaitGL", &retrace::ignore},
-    {"glXWaitVideoSyncSGI", &retrace::ignore},
-    {"glXWaitX", &retrace::ignore},
-    {NULL, NULL},
-};
-
diff --git a/glretrace_main.cpp b/glretrace_main.cpp
deleted file mode 100644 (file)
index 313a563..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include "os_binary.hpp"
-#include "os_string.hpp"
-#include "os_time.hpp"
-#include "image.hpp"
-#include "retrace.hpp"
-#include "trace_callset.hpp"
-#include "glproc.hpp"
-#include "glstate.hpp"
-#include "glretrace.hpp"
-
-
-namespace glretrace {
-
-bool double_buffer = true;
-bool insideGlBeginEnd = false;
-glws::Profile defaultProfile = glws::PROFILE_COMPAT;
-glws::Visual *visual[glws::PROFILE_MAX];
-glws::Drawable *drawable = NULL;
-glws::Context *context = NULL;
-
-unsigned frame = 0;
-long long startTime = 0;
-bool wait = false;
-
-bool benchmark = false;
-static const char *compare_prefix = NULL;
-static const char *snapshot_prefix = NULL;
-static trace::CallSet snapshot_frequency;
-static trace::CallSet compare_frequency;
-
-unsigned dump_state = ~0;
-
-void
-checkGlError(trace::Call &call) {
-    GLenum error = glGetError();
-    if (error == GL_NO_ERROR) {
-        return;
-    }
-
-    std::ostream & os = retrace::warning(call);
-
-    os << "glGetError(";
-    os << call.name();
-    os << ") = ";
-
-    switch (error) {
-    case GL_INVALID_ENUM:
-        os << "GL_INVALID_ENUM";
-        break;
-    case GL_INVALID_VALUE:
-        os << "GL_INVALID_VALUE";
-        break;
-    case GL_INVALID_OPERATION:
-        os << "GL_INVALID_OPERATION";
-        break;
-    case GL_STACK_OVERFLOW:
-        os << "GL_STACK_OVERFLOW";
-        break;
-    case GL_STACK_UNDERFLOW:
-        os << "GL_STACK_UNDERFLOW";
-        break;
-    case GL_OUT_OF_MEMORY:
-        os << "GL_OUT_OF_MEMORY";
-        break;
-    case GL_INVALID_FRAMEBUFFER_OPERATION:
-        os << "GL_INVALID_FRAMEBUFFER_OPERATION";
-        break;
-    case GL_TABLE_TOO_LARGE:
-        os << "GL_TABLE_TOO_LARGE";
-        break;
-    default:
-        os << error;
-        break;
-    }
-    os << "\n";
-}
-
-/**
- * Grow the current drawble.
- *
- * We need to infer the drawable size from GL calls because the drawable sizes
- * are specified by OS specific calls which we do not trace.
- */
-void
-updateDrawable(int width, int height) {
-    if (!drawable) {
-        return;
-    }
-
-    if (drawable->visible &&
-        width  <= drawable->width &&
-        height <= drawable->height) {
-        return;
-    }
-
-    // Ignore zero area viewports
-    if (width == 0 || height == 0) {
-        return;
-    }
-
-    // Check for bound framebuffer last, as this may have a performance impact.
-    GLint draw_framebuffer = 0;
-    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
-    if (draw_framebuffer != 0) {
-        return;
-    }
-
-    drawable->resize(width, height);
-    drawable->show();
-
-    glScissor(0, 0, width, height);
-}
-
-
-static void
-snapshot(unsigned call_no) {
-    assert(snapshot_prefix || compare_prefix);
-
-    if (!drawable) {
-        return;
-    }
-
-    image::Image *ref = NULL;
-
-    if (compare_prefix) {
-        os::String filename = os::String::format("%s%010u.png", compare_prefix, call_no);
-        ref = image::readPNG(filename);
-        if (!ref) {
-            return;
-        }
-        if (retrace::verbosity >= 0) {
-            std::cout << "Read " << filename << "\n";
-        }
-    }
-
-    image::Image *src = glstate::getDrawBufferImage();
-    if (!src) {
-        return;
-    }
-
-    if (snapshot_prefix) {
-        if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
-            char comment[21];
-            snprintf(comment, sizeof comment, "%u", call_no);
-            src->writePNM(std::cout, comment);
-        } else {
-            os::String filename = os::String::format("%s%010u.png", snapshot_prefix, call_no);
-            if (src->writePNG(filename) && retrace::verbosity >= 0) {
-                std::cout << "Wrote " << filename << "\n";
-            }
-        }
-    }
-
-    if (ref) {
-        std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n";
-        delete ref;
-    }
-
-    delete src;
-}
-
-
-void frame_complete(trace::Call &call) {
-    ++frame;
-
-    if (!drawable) {
-        return;
-    }
-
-    if (!drawable->visible) {
-        retrace::warning(call) << "could not infer drawable size (glViewport never called)\n";
-    }
-}
-
-
-static void display(void) {
-    retrace::Retracer retracer;
-
-    retracer.addCallbacks(gl_callbacks);
-    retracer.addCallbacks(glx_callbacks);
-    retracer.addCallbacks(wgl_callbacks);
-    retracer.addCallbacks(cgl_callbacks);
-    retracer.addCallbacks(egl_callbacks);
-
-    startTime = os::getTime();
-    trace::Call *call;
-
-    while ((call = retrace::parser.parse_call())) {
-        bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET;
-        bool doSnapshot =
-            snapshot_frequency.contains(*call) ||
-            compare_frequency.contains(*call)
-        ;
-
-        // For calls which cause rendertargets to be swaped, we take the
-        // snapshot _before_ swapping the rendertargets.
-        if (doSnapshot && swapRenderTarget) {
-            if (call->flags & trace::CALL_FLAG_END_FRAME) {
-                // For swapbuffers/presents we still use this call number,
-                // spite not have been executed yet.
-                snapshot(call->no);
-            } else {
-                // Whereas for ordinate fbo/rendertarget changes we use the
-                // previous call's number.
-                snapshot(call->no - 1);
-            }
-        }
-
-        retracer.retrace(*call);
-
-        if (doSnapshot && !swapRenderTarget) {
-            snapshot(call->no);
-        }
-
-        if (!insideGlBeginEnd &&
-            drawable && context &&
-            call->no >= dump_state) {
-            glstate::dumpCurrentContext(std::cout);
-            exit(0);
-        }
-
-        delete call;
-    }
-
-    // Reached the end of trace
-    glFlush();
-
-    long long endTime = os::getTime();
-    float timeInterval = (endTime - startTime) * (1.0 / os::timeFrequency);
-
-    if ((retrace::verbosity >= -1) || (retrace::profiling)) {
-        std::cout << 
-            "Rendered " << frame << " frames"
-            " in " <<  timeInterval << " secs,"
-            " average of " << (frame/timeInterval) << " fps\n";
-    }
-
-    if (wait) {
-        while (glws::processEvents()) {}
-    } else {
-        exit(0);
-    }
-}
-
-
-static void usage(void) {
-    std::cout << 
-        "Usage: glretrace [OPTION] TRACE\n"
-        "Replay TRACE.\n"
-        "\n"
-        "  -b           benchmark mode (no error checking or warning messages)\n"
-        "  -p           profiling mode (run whole trace, dump profiling info)\n"
-        "  -c PREFIX    compare against snapshots\n"
-        "  -C CALLSET   calls to compare (default is every frame)\n"
-        "  -core        use core profile\n"
-        "  -db          use a double buffer visual (default)\n"
-        "  -sb          use a single buffer visual\n"
-        "  -s PREFIX    take snapshots; `-` for PNM stdout output\n"
-        "  -S CALLSET   calls to snapshot (default is every frame)\n"
-        "  -v           increase output verbosity\n"
-        "  -D CALLNO    dump state at specific call no\n"
-        "  -w           wait on final frame\n";
-}
-
-extern "C"
-int main(int argc, char **argv)
-{
-    assert(compare_frequency.empty());
-    assert(snapshot_frequency.empty());
-
-    int i;
-    for (i = 1; i < argc; ++i) {
-        const char *arg = argv[i];
-
-        if (arg[0] != '-') {
-            break;
-        }
-
-        if (!strcmp(arg, "--")) {
-            break;
-        } else if (!strcmp(arg, "-b")) {
-            benchmark = true;
-            retrace::verbosity = -1;
-            glws::debug = false;
-        } else if (!strcmp(arg, "-p")) {
-            retrace::profiling = true;
-            retrace::verbosity = -1;
-            glws::debug = false;
-        } else if (!strcmp(arg, "-c")) {
-            compare_prefix = argv[++i];
-            if (compare_frequency.empty()) {
-                compare_frequency = trace::CallSet(trace::FREQUENCY_FRAME);
-            }
-        } else if (!strcmp(arg, "-C")) {
-            compare_frequency = trace::CallSet(argv[++i]);
-            if (compare_prefix == NULL) {
-                compare_prefix = "";
-            }
-        } else if (!strcmp(arg, "-D")) {
-            dump_state = atoi(argv[++i]);
-            retrace::verbosity = -2;
-        } else if (!strcmp(arg, "-core")) {
-            defaultProfile = glws::PROFILE_CORE;
-        } else if (!strcmp(arg, "-db")) {
-            double_buffer = true;
-        } else if (!strcmp(arg, "-sb")) {
-            double_buffer = false;
-        } else if (!strcmp(arg, "--help")) {
-            usage();
-            return 0;
-        } else if (!strcmp(arg, "-s")) {
-            snapshot_prefix = argv[++i];
-            if (snapshot_frequency.empty()) {
-                snapshot_frequency = trace::CallSet(trace::FREQUENCY_FRAME);
-            }
-            if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
-                os::setBinaryMode(stdout);
-                retrace::verbosity = -2;
-            }
-        } else if (!strcmp(arg, "-S")) {
-            snapshot_frequency = trace::CallSet(argv[++i]);
-            if (snapshot_prefix == NULL) {
-                snapshot_prefix = "";
-            }
-        } else if (!strcmp(arg, "-v")) {
-            ++retrace::verbosity;
-        } else if (!strcmp(arg, "-w")) {
-            wait = true;
-        } else {
-            std::cerr << "error: unknown option " << arg << "\n";
-            usage();
-            return 1;
-        }
-    }
-
-    glws::init();
-    visual[glws::PROFILE_COMPAT] = glws::createVisual(double_buffer, glws::PROFILE_COMPAT);
-    visual[glws::PROFILE_CORE] = glws::createVisual(double_buffer, glws::PROFILE_CORE);
-    visual[glws::PROFILE_ES1] = glws::createVisual(double_buffer, glws::PROFILE_ES1);
-    visual[glws::PROFILE_ES2] = glws::createVisual(double_buffer, glws::PROFILE_ES2);
-
-    for ( ; i < argc; ++i) {
-        if (!retrace::parser.open(argv[i])) {
-            std::cerr << "error: failed to open " << argv[i] << "\n";
-            return 1;
-        }
-
-        display();
-
-        retrace::parser.close();
-    }
-
-    for (int n = 0; n < glws::PROFILE_MAX; n++) {
-        delete visual[n];
-    }
-
-    glws::cleanup();
-
-    return 0;
-}
-
-} /* namespace glretrace */
diff --git a/glretrace_wgl.cpp b/glretrace_wgl.cpp
deleted file mode 100644 (file)
index 447d177..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include "glproc.hpp"
-#include "retrace.hpp"
-#include "glretrace.hpp"
-
-
-using namespace glretrace;
-
-
-typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
-typedef std::map<unsigned long long, glws::Context *> ContextMap;
-static DrawableMap drawable_map;
-static DrawableMap pbuffer_map;
-static ContextMap context_map;
-
-
-static glws::Drawable *
-getDrawable(unsigned long long hdc) {
-    if (hdc == 0) {
-        return NULL;
-    }
-
-    DrawableMap::const_iterator it;
-    it = drawable_map.find(hdc);
-    if (it == drawable_map.end()) {
-        return (drawable_map[hdc] = glws::createDrawable(visual[glretrace::defaultProfile]));
-    }
-
-    return it->second;
-}
-
-static void retrace_wglCreateContext(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile);
-    context_map[orig_context] = context;
-}
-
-static void retrace_wglDeleteContext(trace::Call &call) {
-}
-
-static void retrace_wglMakeCurrent(trace::Call &call) {
-    if (drawable && context) {
-        glFlush();
-        if (!double_buffer) {
-            frame_complete(call);
-        }
-    }
-    
-    glws::Drawable *new_drawable = getDrawable(call.arg(0).toUIntPtr());
-    glws::Context *new_context = context_map[call.arg(1).toUIntPtr()];
-
-    bool result = glws::makeCurrent(new_drawable, new_context);
-
-    if (new_drawable && new_context && result) {
-        drawable = new_drawable;
-        context = new_context;
-    } else {
-        drawable = NULL;
-        context = NULL;
-    }
-}
-
-static void retrace_wglCopyContext(trace::Call &call) {
-}
-
-static void retrace_wglChoosePixelFormat(trace::Call &call) {
-}
-
-static void retrace_wglDescribePixelFormat(trace::Call &call) {
-}
-
-static void retrace_wglSetPixelFormat(trace::Call &call) {
-}
-
-static void retrace_wglSwapBuffers(trace::Call &call) {
-    frame_complete(call);
-    if (double_buffer) {
-        drawable->swapBuffers();
-    } else {
-        glFlush();
-    }
-}
-
-static void retrace_wglShareLists(trace::Call &call) {
-    unsigned long long hglrc1 = call.arg(0).toUIntPtr();
-    unsigned long long hglrc2 = call.arg(1).toUIntPtr();
-
-    glws::Context *share_context = context_map[hglrc1];
-    glws::Context *old_context = context_map[hglrc2];
-
-    glws::Context *new_context =
-        glws::createContext(old_context->visual, share_context, glretrace::defaultProfile);
-    if (new_context) {
-        if (context == old_context) {
-            glws::makeCurrent(drawable, new_context);
-        }
-
-        context_map[hglrc2] = new_context;
-        
-        delete old_context;
-    }
-}
-
-static void retrace_wglCreateLayerContext(trace::Call &call) {
-    retrace_wglCreateContext(call);
-}
-
-static void retrace_wglDescribeLayerPlane(trace::Call &call) {
-}
-
-static void retrace_wglSetLayerPaletteEntries(trace::Call &call) {
-}
-
-static void retrace_wglRealizeLayerPalette(trace::Call &call) {
-}
-
-static void retrace_wglSwapLayerBuffers(trace::Call &call) {
-    retrace_wglSwapBuffers(call);
-}
-
-static void retrace_wglUseFontBitmapsA(trace::Call &call) {
-}
-
-static void retrace_wglUseFontBitmapsW(trace::Call &call) {
-}
-
-static void retrace_wglSwapMultipleBuffers(trace::Call &call) {
-}
-
-static void retrace_wglUseFontOutlinesA(trace::Call &call) {
-}
-
-static void retrace_wglUseFontOutlinesW(trace::Call &call) {
-}
-
-static void retrace_wglCreateBufferRegionARB(trace::Call &call) {
-}
-
-static void retrace_wglDeleteBufferRegionARB(trace::Call &call) {
-}
-
-static void retrace_wglSaveBufferRegionARB(trace::Call &call) {
-}
-
-static void retrace_wglRestoreBufferRegionARB(trace::Call &call) {
-}
-
-static void retrace_wglChoosePixelFormatARB(trace::Call &call) {
-}
-
-static void retrace_wglMakeContextCurrentARB(trace::Call &call) {
-}
-
-static void retrace_wglCreatePbufferARB(trace::Call &call) {
-    int iWidth = call.arg(2).toUInt();
-    int iHeight = call.arg(3).toUInt();
-
-    unsigned long long orig_pbuffer = call.ret->toUIntPtr();
-    glws::Drawable *drawable = glws::createDrawable(glretrace::visual[glretrace::defaultProfile]);
-
-    drawable->resize(iWidth, iHeight);
-    drawable->show();
-
-    pbuffer_map[orig_pbuffer] = drawable;
-}
-
-static void retrace_wglGetPbufferDCARB(trace::Call &call) {
-    glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
-
-    unsigned long long orig_hdc = call.ret->toUIntPtr();
-
-    drawable_map[orig_hdc] = pbuffer;
-}
-
-static void retrace_wglReleasePbufferDCARB(trace::Call &call) {
-}
-
-static void retrace_wglDestroyPbufferARB(trace::Call &call) {
-}
-
-static void retrace_wglQueryPbufferARB(trace::Call &call) {
-}
-
-static void retrace_wglBindTexImageARB(trace::Call &call) {
-}
-
-static void retrace_wglReleaseTexImageARB(trace::Call &call) {
-}
-
-static void retrace_wglSetPbufferAttribARB(trace::Call &call) {
-}
-
-static void retrace_wglCreateContextAttribsARB(trace::Call &call) {
-    unsigned long long orig_context = call.ret->toUIntPtr();
-    glws::Context *share_context = NULL;
-
-    if (call.arg(1).toPointer()) {
-        share_context = context_map[call.arg(1).toUIntPtr()];
-    }
-
-    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
-    context_map[orig_context] = context;
-}
-
-static void retrace_wglMakeContextCurrentEXT(trace::Call &call) {
-}
-
-static void retrace_wglChoosePixelFormatEXT(trace::Call &call) {
-}
-
-static void retrace_wglSwapIntervalEXT(trace::Call &call) {
-}
-
-static void retrace_wglAllocateMemoryNV(trace::Call &call) {
-}
-
-static void retrace_wglFreeMemoryNV(trace::Call &call) {
-}
-
-static void retrace_glAddSwapHintRectWIN(trace::Call &call) {
-}
-
-static void retrace_wglGetProcAddress(trace::Call &call) {
-}
-
-const retrace::Entry glretrace::wgl_callbacks[] = {
-    {"glAddSwapHintRectWIN", &retrace_glAddSwapHintRectWIN},
-    {"wglAllocateMemoryNV", &retrace_wglAllocateMemoryNV},
-    {"wglBindTexImageARB", &retrace_wglBindTexImageARB},
-    {"wglChoosePixelFormat", &retrace_wglChoosePixelFormat},
-    {"wglChoosePixelFormatARB", &retrace_wglChoosePixelFormatARB},
-    {"wglChoosePixelFormatEXT", &retrace_wglChoosePixelFormatEXT},
-    {"wglCopyContext", &retrace_wglCopyContext},
-    {"wglCreateBufferRegionARB", &retrace_wglCreateBufferRegionARB},
-    {"wglCreateContext", &retrace_wglCreateContext},
-    {"wglCreateContextAttribsARB", &retrace_wglCreateContextAttribsARB},
-    {"wglCreateLayerContext", &retrace_wglCreateLayerContext},
-    {"wglCreatePbufferARB", &retrace_wglCreatePbufferARB},
-    {"wglDeleteBufferRegionARB", &retrace_wglDeleteBufferRegionARB},
-    {"wglDeleteContext", &retrace_wglDeleteContext},
-    {"wglDescribeLayerPlane", &retrace_wglDescribeLayerPlane},
-    {"wglDescribePixelFormat", &retrace_wglDescribePixelFormat},
-    {"wglDestroyPbufferARB", &retrace_wglDestroyPbufferARB},
-    {"wglFreeMemoryNV", &retrace_wglFreeMemoryNV},
-    {"wglGetCurrentContext", &retrace::ignore},
-    {"wglGetCurrentDC", &retrace::ignore},
-    {"wglGetCurrentReadDCARB", &retrace::ignore},
-    {"wglGetCurrentReadDCEXT", &retrace::ignore},
-    {"wglGetDefaultProcAddress", &retrace::ignore},
-    {"wglGetExtensionsStringARB", &retrace::ignore},
-    {"wglGetExtensionsStringEXT", &retrace::ignore},
-    {"wglGetLayerPaletteEntries", &retrace::ignore},
-    {"wglGetPbufferDCARB", &retrace_wglGetPbufferDCARB},
-    {"wglGetPixelFormat", &retrace::ignore},
-    {"wglGetPixelFormatAttribfvARB", &retrace::ignore},
-    {"wglGetPixelFormatAttribfvEXT", &retrace::ignore},
-    {"wglGetPixelFormatAttribivARB", &retrace::ignore},
-    {"wglGetPixelFormatAttribivEXT", &retrace::ignore},
-    {"wglGetProcAddress", &retrace_wglGetProcAddress},
-    {"wglGetSwapIntervalEXT", &retrace::ignore},
-    {"wglMakeContextCurrentARB", &retrace_wglMakeContextCurrentARB},
-    {"wglMakeContextCurrentEXT", &retrace_wglMakeContextCurrentEXT},
-    {"wglMakeCurrent", &retrace_wglMakeCurrent},
-    {"wglQueryPbufferARB", &retrace_wglQueryPbufferARB},
-    {"wglRealizeLayerPalette", &retrace_wglRealizeLayerPalette},
-    {"wglReleasePbufferDCARB", &retrace_wglReleasePbufferDCARB},
-    {"wglReleaseTexImageARB", &retrace_wglReleaseTexImageARB},
-    {"wglRestoreBufferRegionARB", &retrace_wglRestoreBufferRegionARB},
-    {"wglSaveBufferRegionARB", &retrace_wglSaveBufferRegionARB},
-    {"wglSetLayerPaletteEntries", &retrace_wglSetLayerPaletteEntries},
-    {"wglSetPbufferAttribARB", &retrace_wglSetPbufferAttribARB},
-    {"wglSetPixelFormat", &retrace_wglSetPixelFormat},
-    {"wglShareLists", &retrace_wglShareLists},
-    {"wglSwapBuffers", &retrace_wglSwapBuffers},
-    {"wglSwapIntervalEXT", &retrace_wglSwapIntervalEXT},
-    {"wglSwapLayerBuffers", &retrace_wglSwapLayerBuffers},
-    {"wglSwapMultipleBuffers", &retrace_wglSwapMultipleBuffers},
-    {"wglUseFontBitmapsA", &retrace_wglUseFontBitmapsA},
-    {"wglUseFontBitmapsW", &retrace_wglUseFontBitmapsW},
-    {"wglUseFontOutlinesA", &retrace_wglUseFontOutlinesA},
-    {"wglUseFontOutlinesW", &retrace_wglUseFontOutlinesW},
-    {NULL, NULL}
-};
-
diff --git a/glstate.cpp b/glstate.cpp
deleted file mode 100644 (file)
index 0d5a5f3..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include <algorithm>
-#include <iostream>
-
-#include "image.hpp"
-#include "json.hpp"
-#include "glproc.hpp"
-#include "glsize.hpp"
-#include "glstate.hpp"
-#include "glstate_internal.hpp"
-
-
-namespace glstate {
-
-
-Context::Context(void) {
-    memset(this, 0, sizeof *this);
-
-    const char *version = (const char *)glGetString(GL_VERSION);
-    if (version) {
-        if (version[0] == 'O' &&
-            version[1] == 'p' &&
-            version[2] == 'e' &&
-            version[3] == 'n' &&
-            version[4] == 'G' &&
-            version[5] == 'L' &&
-            version[6] == ' ' &&
-            version[7] == 'E' &&
-            version[8] == 'S' &&
-            (version[9] == ' ' || version[9] == '-')) {
-            ES = true;
-        }
-    }
-
-    ARB_draw_buffers = !ES;
-
-    // TODO: Check extensions we use below
-}
-
-void
-Context::resetPixelPackState(void) {
-    if (!ES) {
-        glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
-        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
-        glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
-        glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
-        glPixelStorei(GL_PACK_ROW_LENGTH, 0);
-        glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
-        glPixelStorei(GL_PACK_SKIP_ROWS, 0);
-        glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
-        glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
-    } else {
-        packAlignment = 4;
-        glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);
-    }
-    glPixelStorei(GL_PACK_ALIGNMENT, 1);
-}
-
-void
-Context::restorePixelPackState(void) {
-    if (!ES) {
-        glPopClientAttrib();
-    } else {
-        glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);
-    }
-}
-
-
-static const GLenum bindings[] = {
-    GL_DRAW_BUFFER,
-    GL_READ_BUFFER,
-    GL_PIXEL_PACK_BUFFER_BINDING,
-    GL_PIXEL_UNPACK_BUFFER_BINDING,
-    GL_TEXTURE_BINDING_1D,
-    GL_TEXTURE_BINDING_2D,
-    GL_TEXTURE_BINDING_3D,
-    GL_TEXTURE_BINDING_RECTANGLE,
-    GL_TEXTURE_BINDING_CUBE_MAP,
-    GL_DRAW_FRAMEBUFFER_BINDING,
-    GL_READ_FRAMEBUFFER_BINDING,
-    GL_RENDERBUFFER_BINDING,
-    GL_DRAW_BUFFER0,
-    GL_DRAW_BUFFER1,
-    GL_DRAW_BUFFER2,
-    GL_DRAW_BUFFER3,
-    GL_DRAW_BUFFER4,
-    GL_DRAW_BUFFER5,
-    GL_DRAW_BUFFER6,
-    GL_DRAW_BUFFER7,
-};
-
-
-#define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
-
-
-void dumpCurrentContext(std::ostream &os)
-{
-    JSONWriter json(os);
-
-#ifndef NDEBUG
-    GLint old_bindings[NUM_BINDINGS];
-    for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
-        old_bindings[i] = 0;
-        glGetIntegerv(bindings[i], &old_bindings[i]);
-    }
-#endif
-
-    Context context;
-
-    dumpParameters(json, context);
-    dumpShadersUniforms(json, context);
-    dumpTextures(json, context);
-    dumpFramebuffer(json, context);
-
-#ifndef NDEBUG
-    for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
-        GLint new_binding = 0;
-        glGetIntegerv(bindings[i], &new_binding);
-        if (new_binding != old_bindings[i]) {
-            std::cerr << "warning: " << enumToString(bindings[i]) << " was clobbered\n";
-        }
-    }
-#endif
-
-}
-
-
-} /* namespace glstate */
diff --git a/glstate.hpp b/glstate.hpp
deleted file mode 100644 (file)
index 6fb615f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _GLSTATE_HPP_
-#define _GLSTATE_HPP_
-
-
-#include <ostream>
-
-#include "glimports.hpp"
-
-
-namespace image {
-    class Image;
-}
-
-
-namespace glstate {
-
-
-const char *enumToString(GLenum pname);
-
-void dumpCurrentContext(std::ostream &os);
-
-image::Image *
-getDrawBufferImage(void);
-
-
-} /* namespace glstate */
-
-
-#endif /* _GLSTATE_HPP_ */
diff --git a/glstate_images.cpp b/glstate_images.cpp
deleted file mode 100644 (file)
index f16cba4..0000000
+++ /dev/null
@@ -1,1185 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include <algorithm>
-#include <iostream>
-
-#include "image.hpp"
-#include "json.hpp"
-#include "glproc.hpp"
-#include "glsize.hpp"
-#include "glstate.hpp"
-#include "glstate_internal.hpp"
-
-
-#ifdef __linux__
-#include <dlfcn.h>
-#endif
-
-#ifdef __APPLE__
-
-#include <Carbon/Carbon.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __APPLE__ */
-
-
-/* Change thi to one to force interpreting depth buffers as RGBA, which enables
- * visualizing full dynamic range, until we can transmit HDR images to the GUI */
-#define DEPTH_AS_RGBA 0
-
-
-namespace glstate {
-
-
-struct ImageDesc
-{
-    GLint width;
-    GLint height;
-    GLint depth;
-    GLint internalFormat;
-
-    inline
-    ImageDesc() :
-        width(0),
-        height(0),
-        depth(0),
-        internalFormat(GL_NONE)
-    {}
-
-    inline bool
-    valid(void) const {
-        return width > 0 && height > 0 && depth > 0;
-    }
-};
-
-
-/**
- * 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) {
-        return getActiveTextureLevelDescOES(context, target, level, desc);
-    }
-
-    glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &desc.internalFormat);
-
-    desc.width = 0;
-    glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &desc.width);
-
-    if (target == GL_TEXTURE_1D) {
-        desc.height = 1;
-        desc.depth = 1;
-    } else {
-        desc.height = 0;
-        glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &desc.height);
-        if (target != GL_TEXTURE_3D) {
-            desc.depth = 1;
-        } else {
-            desc.depth = 0;
-            glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &desc.depth);
-        }
-    }
-
-    return desc.valid();
-}
-
-
-/**
- * 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)
-{
-    ImageDesc desc;
-    if (!getActiveTextureLevelDesc(context, target, level, desc)) {
-        return;
-    }
-
-    char label[512];
-
-    GLint active_texture = GL_TEXTURE0;
-    glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
-    snprintf(label, sizeof label, "%s, %s, level = %d",
-             enumToString(active_texture), enumToString(target), level);
-
-    json.beginMember(label);
-
-    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");
-
-    json.writeNumberMember("__width__", desc.width);
-    json.writeNumberMember("__height__", desc.height);
-    json.writeNumberMember("__depth__", desc.depth);
-
-    json.writeStringMember("__format__", enumToString(desc.internalFormat));
-
-    // Hardcoded for now, but we could chose types more adequate to the
-    // texture internal format
-    json.writeStringMember("__type__", "uint8");
-    json.writeBoolMember("__normalized__", true);
-    json.writeNumberMember("__channels__", channels);
-
-    GLubyte *pixels = new GLubyte[desc.depth*desc.width*desc.height*channels];
-
-    context.resetPixelPackState();
-
-    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, channels, true, &pngBuffer, &pngBufferSize);
-    json.writeBase64(pngBuffer, pngBufferSize);
-    free(pngBuffer);
-    json.endMember(); // __data__
-
-    delete [] pixels;
-    json.endObject();
-}
-
-
-static inline void
-dumpTexture(JSONWriter &json, Context &context, GLenum target, GLenum binding)
-{
-    GLint texture_binding = 0;
-    glGetIntegerv(binding, &texture_binding);
-    if (!glIsEnabled(target) && !texture_binding) {
-        return;
-    }
-
-    GLint level = 0;
-    do {
-        ImageDesc desc;
-        if (!getActiveTextureLevelDesc(context, target, level, desc)) {
-            break;
-        }
-
-        if (target == GL_TEXTURE_CUBE_MAP) {
-            for (int face = 0; face < 6; ++face) {
-                dumpActiveTextureLevel(json, context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
-            }
-        } else {
-            dumpActiveTextureLevel(json, context, target, level);
-        }
-
-        ++level;
-    } while(true);
-}
-
-
-void
-dumpTextures(JSONWriter &json, Context &context)
-{
-    json.beginMember("textures");
-    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);
-        dumpTexture(json, context, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
-        dumpTexture(json, context, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
-        dumpTexture(json, context, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
-        dumpTexture(json, context, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
-        dumpTexture(json, context, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
-    }
-    glActiveTexture(active_texture);
-    json.endObject();
-    json.endMember(); // textures
-}
-
-
-static bool
-getDrawableBounds(GLint *width, GLint *height) {
-#if defined(__linux__)
-    if (dlsym(RTLD_DEFAULT, "eglGetCurrentContext")) {
-        EGLContext currentContext = eglGetCurrentContext();
-        if (currentContext == EGL_NO_CONTEXT) {
-            return false;
-        }
-
-        EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
-        if (currentSurface == EGL_NO_SURFACE) {
-            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;
-        }
-
-        return true;
-    }
-#endif
-
-#if defined(_WIN32)
-
-    HDC hDC = wglGetCurrentDC();
-    if (!hDC) {
-        return false;
-    }
-
-    HWND hWnd = WindowFromDC(hDC);
-    RECT rect;
-
-    if (!GetClientRect(hWnd, &rect)) {
-       return false;
-    }
-
-    *width  = rect.right  - rect.left;
-    *height = rect.bottom - rect.top;
-    return true;
-
-#elif defined(__APPLE__)
-
-    CGLContextObj ctx = CGLGetCurrentContext();
-    if (ctx == NULL) {
-        return false;
-    }
-
-    CGSConnectionID cid;
-    CGSWindowID wid;
-    CGSSurfaceID sid;
-
-    if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
-        return false;
-    }
-
-    CGRect rect;
-
-    if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
-        return false;
-    }
-
-    *width = rect.size.width;
-    *height = rect.size.height;
-    return true;
-
-#elif defined(HAVE_X11)
-
-    Display *display;
-    Drawable drawable;
-    Window root;
-    int x, y;
-    unsigned int w, h, bw, depth;
-
-    display = glXGetCurrentDisplay();
-    if (!display) {
-        return false;
-    }
-
-    drawable = glXGetCurrentDrawable();
-    if (drawable == None) {
-        return false;
-    }
-
-    if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
-        return false;
-    }
-
-    *width = w;
-    *height = h;
-    return true;
-
-#else
-
-    return false;
-
-#endif
-}
-
-
-static const GLenum texture_bindings[][2] = {
-    {GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D},
-    {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D},
-    {GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D},
-    {GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE},
-    {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP}
-};
-
-
-static bool
-bindTexture(GLint texture, GLenum &target, GLint &bound_texture)
-{
-
-    for (unsigned i = 0; i < sizeof(texture_bindings)/sizeof(texture_bindings[0]); ++i) {
-        target  = texture_bindings[i][0];
-
-        GLenum binding = texture_bindings[i][1];
-
-        while (glGetError() != GL_NO_ERROR)
-            ;
-
-        glGetIntegerv(binding, &bound_texture);
-        glBindTexture(target, texture);
-
-        if (glGetError() == GL_NO_ERROR) {
-            return true;
-        }
-
-        glBindTexture(target, bound_texture);
-    }
-
-    target = GL_NONE;
-
-    return false;
-}
-
-
-static bool
-getTextureLevelDesc(Context &context, GLint texture, GLint level, ImageDesc &desc)
-{
-    GLenum target;
-    GLint bound_texture = 0;
-    if (!bindTexture(texture, target, bound_texture)) {
-        return false;
-    }
-
-    getActiveTextureLevelDesc(context, target, level, desc);
-
-    glBindTexture(target, bound_texture);
-
-    return desc.valid();
-}
-
-
-static bool
-getBoundRenderbufferDesc(Context &context, ImageDesc &desc)
-{
-    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &desc.width);
-    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &desc.height);
-    desc.depth = 1;
-    
-    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &desc.internalFormat);
-    
-    return desc.valid();
-}
-
-
-static bool
-getRenderbufferDesc(Context &context, GLint renderbuffer, ImageDesc &desc)
-{
-    GLint bound_renderbuffer = 0;
-    glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
-    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
-
-    getBoundRenderbufferDesc(context, desc);
-
-    glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
-    
-    return desc.valid();
-}
-
-
-static bool
-getFramebufferAttachmentDesc(Context &context, GLenum target, GLenum attachment, ImageDesc &desc)
-{
-    GLint object_type = GL_NONE;
-    glGetFramebufferAttachmentParameteriv(target, attachment,
-                                          GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
-                                          &object_type);
-    if (object_type == GL_NONE) {
-        return false;
-    }
-
-    GLint object_name = 0;
-    glGetFramebufferAttachmentParameteriv(target, attachment,
-                                          GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
-                                          &object_name);
-    if (object_name == 0) {
-        return false;
-    }
-
-    if (object_type == GL_RENDERBUFFER) {
-        return getRenderbufferDesc(context, object_name, desc);
-    } else if (object_type == GL_TEXTURE) {
-        GLint texture_level = 0;
-        glGetFramebufferAttachmentParameteriv(target, attachment,
-                                              GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
-                                              &texture_level);
-        return getTextureLevelDesc(context, object_name, texture_level, desc);
-    } else {
-        std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
-        return false;
-    }
-}
-
-
-
-image::Image *
-getDrawBufferImage() {
-    GLenum format = GL_RGB;
-    GLint channels = __gl_format_channels(format);
-    if (channels > 4) {
-        return NULL;
-    }
-
-    Context context;
-
-    GLenum framebuffer_binding;
-    GLenum framebuffer_target;
-    if (context.ES) {
-        framebuffer_binding = GL_FRAMEBUFFER_BINDING;
-        framebuffer_target = GL_FRAMEBUFFER;
-    } else {
-        framebuffer_binding = GL_DRAW_FRAMEBUFFER_BINDING;
-        framebuffer_target = GL_DRAW_FRAMEBUFFER;
-    }
-
-    GLint draw_framebuffer = 0;
-    glGetIntegerv(framebuffer_binding, &draw_framebuffer);
-
-    GLint draw_buffer = GL_NONE;
-    ImageDesc desc;
-    if (draw_framebuffer) {
-        if (context.ARB_draw_buffers) {
-            glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);
-            if (draw_buffer == GL_NONE) {
-                return NULL;
-            }
-        }
-
-        if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) {
-            return NULL;
-        }
-    } else {
-        if (!context.ES) {
-            glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
-            if (draw_buffer == GL_NONE) {
-                return NULL;
-            }
-        }
-
-        if (!getDrawableBounds(&desc.width, &desc.height)) {
-            return NULL;
-        }
-
-        desc.depth = 1;
-    }
-
-    GLenum type = GL_UNSIGNED_BYTE;
-
-#if DEPTH_AS_RGBA
-    if (format == GL_DEPTH_COMPONENT) {
-        type = GL_UNSIGNED_INT;
-        channels = 4;
-    }
-#endif
-
-    image::Image *image = new image::Image(desc.width, desc.height, channels, true);
-    if (!image) {
-        return NULL;
-    }
-
-    while (glGetError() != GL_NO_ERROR) {}
-
-    GLint read_framebuffer = 0;
-    GLint read_buffer = GL_NONE;
-    if (!context.ES) {
-        glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
-
-        glGetIntegerv(GL_READ_BUFFER, &read_buffer);
-        glReadBuffer(draw_buffer);
-    }
-
-    // TODO: reset imaging state too
-    context.resetPixelPackState();
-
-    glReadPixels(0, 0, desc.width, desc.height, format, type, image->pixels);
-
-    context.restorePixelPackState();
-
-    if (!context.ES) {
-        glReadBuffer(read_buffer);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
-    }
-
-    GLenum error = glGetError();
-    if (error != GL_NO_ERROR) {
-        do {
-            std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
-            error = glGetError();
-        } while(error != GL_NO_ERROR);
-        delete image;
-        return NULL;
-    }
-     
-    return image;
-}
-
-
-/**
- * Dump the image of the currently bound read buffer.
- */
-static inline void
-dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format,
-                    GLint internalFormat = GL_NONE)
-{
-    GLint channels = __gl_format_channels(format);
-
-    Context context;
-
-    json.beginObject();
-
-    // Tell the GUI this is no ordinary object, but an image
-    json.writeStringMember("__class__", "image");
-
-    json.writeNumberMember("__width__", width);
-    json.writeNumberMember("__height__", height);
-    json.writeNumberMember("__depth__", 1);
-
-    json.writeStringMember("__format__", enumToString(internalFormat));
-
-    // Hardcoded for now, but we could chose types more adequate to the
-    // texture internal format
-    json.writeStringMember("__type__", "uint8");
-    json.writeBoolMember("__normalized__", true);
-    json.writeNumberMember("__channels__", channels);
-
-    GLenum type = GL_UNSIGNED_BYTE;
-
-#if DEPTH_AS_RGBA
-    if (format == GL_DEPTH_COMPONENT) {
-        type = GL_UNSIGNED_INT;
-        channels = 4;
-    }
-#endif
-
-    GLubyte *pixels = new GLubyte[width*height*channels];
-
-    // TODO: reset imaging state too
-    context.resetPixelPackState();
-
-    glReadPixels(0, 0, width, height, format, type, pixels);
-
-    context.restorePixelPackState();
-
-    json.beginMember("__data__");
-    char *pngBuffer;
-    int pngBufferSize;
-    image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize);
-    //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
-    //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
-    json.writeBase64(pngBuffer, pngBufferSize);
-    free(pngBuffer);
-    json.endMember(); // __data__
-
-    delete [] pixels;
-    json.endObject();
-}
-
-
-static inline GLuint
-downsampledFramebuffer(Context &context,
-                       GLuint oldFbo, GLint drawbuffer,
-                       GLint colorRb, GLint depthRb, GLint stencilRb,
-                       GLuint *rbs, GLint *numRbs)
-{
-    GLuint fbo;
-
-
-    *numRbs = 0;
-
-    glGenFramebuffers(1, &fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
-    {
-        // color buffer
-        ImageDesc desc;
-        glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
-        getBoundRenderbufferDesc(context, desc);
-
-        glGenRenderbuffers(1, &rbs[*numRbs]);
-        glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
-        glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
-        glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
-                                  GL_RENDERBUFFER, rbs[*numRbs]);
-
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-        glDrawBuffer(drawbuffer);
-        glReadBuffer(drawbuffer);
-        glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
-                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-        ++*numRbs;
-    }
-
-    if (stencilRb == depthRb && stencilRb) {
-        //combined depth and stencil buffer
-        ImageDesc desc;
-        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
-        getBoundRenderbufferDesc(context, desc);
-
-        glGenRenderbuffers(1, &rbs[*numRbs]);
-        glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
-        glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
-        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                                  GL_RENDERBUFFER, rbs[*numRbs]);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-        glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
-                          GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-        ++*numRbs;
-    } else {
-        if (depthRb) {
-            ImageDesc desc;
-            glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
-            getBoundRenderbufferDesc(context, desc);
-
-            glGenRenderbuffers(1, &rbs[*numRbs]);
-            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
-            glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
-                                      GL_DEPTH_ATTACHMENT,
-                                      GL_RENDERBUFFER, rbs[*numRbs]);
-            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
-            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-            glDrawBuffer(GL_DEPTH_ATTACHMENT);
-            glReadBuffer(GL_DEPTH_ATTACHMENT);
-            glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
-                              GL_DEPTH_BUFFER_BIT, GL_NEAREST);
-            ++*numRbs;
-        }
-        if (stencilRb) {
-            ImageDesc desc;
-            glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
-            getBoundRenderbufferDesc(context, desc);
-
-            glGenRenderbuffers(1, &rbs[*numRbs]);
-            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
-            glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
-                                      GL_STENCIL_ATTACHMENT,
-                                      GL_RENDERBUFFER, rbs[*numRbs]);
-            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
-            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-            glDrawBuffer(GL_STENCIL_ATTACHMENT);
-            glReadBuffer(GL_STENCIL_ATTACHMENT);
-            glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
-                              GL_STENCIL_BUFFER_BIT, GL_NEAREST);
-            ++*numRbs;
-        }
-    }
-
-    return fbo;
-}
-
-
-/**
- * Dump images of current draw drawable/window.
- */
-static void
-dumpDrawableImages(JSONWriter &json, Context &context)
-{
-    GLint width, height;
-
-    if (!getDrawableBounds(&width, &height)) {
-        return;
-    }
-
-    GLint draw_buffer = GL_NONE;
-    if (context.ES) {
-        draw_buffer = GL_BACK;
-    } else {
-        glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
-        glReadBuffer(draw_buffer);
-    }
-
-    if (draw_buffer != GL_NONE) {
-        GLint read_buffer = GL_NONE;
-        if (!context.ES) {
-            glGetIntegerv(GL_READ_BUFFER, &read_buffer);
-        }
-
-        GLint alpha_bits = 0;
-#if 0
-        // XXX: Ignore alpha until we are able to match the traced visual
-        glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
-#endif
-        GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
-        json.beginMember(enumToString(draw_buffer));
-        dumpReadBufferImage(json, width, height, format);
-        json.endMember();
-
-        if (!context.ES) {
-            glReadBuffer(read_buffer);
-        }
-    }
-
-    if (!context.ES) {
-        GLint depth_bits = 0;
-        glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
-        if (depth_bits) {
-            json.beginMember("GL_DEPTH_COMPONENT");
-            dumpReadBufferImage(json, width, height, GL_DEPTH_COMPONENT);
-            json.endMember();
-        }
-
-        GLint stencil_bits = 0;
-        glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
-        if (stencil_bits) {
-            json.beginMember("GL_STENCIL_INDEX");
-            dumpReadBufferImage(json, width, height, GL_STENCIL_INDEX);
-            json.endMember();
-        }
-    }
-}
-
-
-/**
- * Dump the specified framebuffer attachment.
- *
- * In the case of a color attachment, it assumes it is already bound for read.
- */
-static void
-dumpFramebufferAttachment(JSONWriter &json, Context &context, GLenum target, GLenum attachment, GLenum format)
-{
-    ImageDesc desc;
-    if (!getFramebufferAttachmentDesc(context, target, attachment, desc)) {
-        return;
-    }
-
-    json.beginMember(enumToString(attachment));
-    dumpReadBufferImage(json, desc.width, desc.height, format, desc.internalFormat);
-    json.endMember();
-}
-
-
-static void
-dumpFramebufferAttachments(JSONWriter &json, Context &context, GLenum target)
-{
-    GLint read_framebuffer = 0;
-    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
-
-    GLint read_buffer = GL_NONE;
-    glGetIntegerv(GL_READ_BUFFER, &read_buffer);
-
-    GLint max_draw_buffers = 1;
-    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
-    GLint max_color_attachments = 0;
-    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
-
-    for (GLint i = 0; i < max_draw_buffers; ++i) {
-        GLint draw_buffer = GL_NONE;
-        glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
-        if (draw_buffer != GL_NONE) {
-            glReadBuffer(draw_buffer);
-            GLint attachment;
-            if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
-                attachment = draw_buffer;
-            } else {
-                std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
-                attachment = GL_COLOR_ATTACHMENT0;
-            }
-            GLint alpha_size = 0;
-            glGetFramebufferAttachmentParameteriv(target, attachment,
-                                                  GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
-                                                  &alpha_size);
-            GLenum format = alpha_size ? GL_RGBA : GL_RGB;
-            dumpFramebufferAttachment(json, context, target, attachment, format);
-        }
-    }
-
-    glReadBuffer(read_buffer);
-
-    if (!context.ES) {
-        dumpFramebufferAttachment(json, context, target, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT);
-        dumpFramebufferAttachment(json, context, target, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX);
-    }
-
-    glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
-}
-
-
-void
-dumpFramebuffer(JSONWriter &json, Context &context)
-{
-    json.beginMember("framebuffer");
-    json.beginObject();
-
-    GLint boundDrawFbo = 0, boundReadFbo = 0;
-    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
-    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
-    if (!boundDrawFbo) {
-        dumpDrawableImages(json, context);
-    } else if (context.ES) {
-        dumpFramebufferAttachments(json, context, GL_FRAMEBUFFER);
-    } else {
-        GLint colorRb = 0, stencilRb = 0, depthRb = 0;
-        GLint draw_buffer0 = GL_NONE;
-        glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
-        bool multisample = false;
-
-        GLint boundRb = 0;
-        glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
-
-        GLint object_type;
-        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
-        if (object_type == GL_RENDERBUFFER) {
-            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &colorRb);
-            glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
-            GLint samples = 0;
-            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
-            if (samples) {
-                multisample = true;
-            }
-        }
-
-        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
-        if (object_type == GL_RENDERBUFFER) {
-            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthRb);
-            glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
-            GLint samples = 0;
-            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
-            if (samples) {
-                multisample = true;
-            }
-        }
-
-        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
-        if (object_type == GL_RENDERBUFFER) {
-            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &stencilRb);
-            glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
-            GLint samples = 0;
-            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
-            if (samples) {
-                multisample = true;
-            }
-        }
-
-        glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
-
-        GLuint rbs[3];
-        GLint numRbs = 0;
-        GLuint fboCopy = 0;
-
-        if (multisample) {
-            // glReadPixels doesnt support multisampled buffers so we need
-            // to blit the fbo to a temporary one
-            fboCopy = downsampledFramebuffer(context,
-                                             boundDrawFbo, draw_buffer0,
-                                             colorRb, depthRb, stencilRb,
-                                             rbs, &numRbs);
-        }
-
-        dumpFramebufferAttachments(json, context, GL_DRAW_FRAMEBUFFER);
-
-        if (multisample) {
-            glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
-            glDeleteRenderbuffers(numRbs, rbs);
-            glDeleteFramebuffers(1, &fboCopy);
-        }
-
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
-    }
-
-    json.endObject();
-    json.endMember(); // framebuffer
-}
-
-
-} /* namespace glstate */
diff --git a/glstate_internal.hpp b/glstate_internal.hpp
deleted file mode 100644 (file)
index aab7f98..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _GLSTATE_INTERNAL_HPP_
-#define _GLSTATE_INTERNAL_HPP_
-
-
-#include "glimports.hpp"
-
-
-class JSONWriter;
-
-
-namespace glstate {
-
-
-struct Context
-{
-    bool ES;
-
-    bool ARB_draw_buffers;
-
-    Context(void);
-
-    GLint packAlignment;
-
-    void
-    resetPixelPackState(void);
-
-    void
-    restorePixelPackState(void);
-};
-
-
-void dumpEnum(JSONWriter &json, GLenum pname);
-
-void dumpParameters(JSONWriter &json, Context &context);
-
-void dumpShadersUniforms(JSONWriter &json, Context &context);
-
-void dumpTextures(JSONWriter &json, Context &context);
-
-void dumpFramebuffer(JSONWriter &json, Context &context);
-
-
-} /* namespace glstate */
-
-
-#endif /* _GLSTATE_INTERNAL_HPP_ */
diff --git a/glstate_params.py b/glstate_params.py
deleted file mode 100644 (file)
index 7c29932..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-##########################################################################
-#
-# Copyright 2011 Jose Fonseca
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-'''Generate code to dump most GL state into JSON.'''
-
-
-from specs.stdapi import *
-
-from specs.gltypes import *
-from specs.glparams import *
-
-
-texture_targets = [
-    ('GL_TEXTURE_1D', 'GL_TEXTURE_BINDING_1D'),
-    ('GL_TEXTURE_2D', 'GL_TEXTURE_BINDING_2D'),
-    ('GL_TEXTURE_3D', 'GL_TEXTURE_BINDING_3D'),
-    ('GL_TEXTURE_RECTANGLE', 'GL_TEXTURE_BINDING_RECTANGLE'),
-    ('GL_TEXTURE_CUBE_MAP', 'GL_TEXTURE_BINDING_CUBE_MAP')
-]
-
-framebuffer_targets = [
-    ('GL_DRAW_FRAMEBUFFER', 'GL_DRAW_FRAMEBUFFER_BINDING'),
-    ('GL_READ_FRAMEBUFFER', 'GL_READ_FRAMEBUFFER_BINDING'),
-]
-
-class GetInflector:
-    '''Objects that describes how to inflect.'''
-
-    reduced_types = {
-        B: I,
-        E: I,
-        I: F,
-    }
-
-    def __init__(self, radical, inflections, suffix = ''):
-        self.radical = radical
-        self.inflections = inflections
-        self.suffix = suffix
-
-    def reduced_type(self, type):
-        if type in self.inflections:
-            return type
-        if type in self.reduced_types:
-            return self.reduced_type(self.reduced_types[type])
-        raise NotImplementedError
-
-    def inflect(self, type):
-        return self.radical + self.inflection(type) + self.suffix
-
-    def inflection(self, type):
-        type = self.reduced_type(type)
-        assert type in self.inflections
-        return self.inflections[type]
-
-    def __str__(self):
-        return self.radical + self.suffix
-
-
-class StateGetter(Visitor):
-    '''Type visitor that is able to extract the state via one of the glGet*
-    functions.
-
-    It will declare any temporary variable
-    '''
-
-    def __init__(self, radical, inflections, suffix=''):
-        self.inflector = GetInflector(radical, inflections)
-        self.suffix = suffix
-
-    def iter(self):
-        for function, type, count, name in parameters:
-            inflection = self.inflector.radical + self.suffix
-            if inflection not in function.split(','):
-                continue
-            if type is X:
-                continue
-            yield type, count, name
-
-    def __call__(self, *args):
-        pname = args[-1]
-
-        for type, count, name in self.iter():
-            if name == pname:
-                if count != 1:
-                    type = Array(type, str(count))
-
-                return type, self.visit(type, args)
-
-        raise NotImplementedError
-
-    def temp_name(self, args):
-        '''Return the name of a temporary variable to hold the state.'''
-        pname = args[-1]
-
-        return pname[3:].lower()
-
-    def visitConst(self, const, args):
-        return self.visit(const.type, args)
-
-    def visitScalar(self, type, args):
-        temp_name = self.temp_name(args)
-        elem_type = self.inflector.reduced_type(type)
-        inflection = self.inflector.inflect(type)
-        if inflection.endswith('v'):
-            print '    %s %s = 0;' % (elem_type, temp_name)
-            print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
-        else:
-            print '    %s %s = %s(%s);' % (elem_type, temp_name, inflection + self.suffix, ', '.join(args))
-        return temp_name
-
-    def visitString(self, string, args):
-        temp_name = self.temp_name(args)
-        inflection = self.inflector.inflect(string)
-        assert not inflection.endswith('v')
-        print '    %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection + self.suffix, ', '.join(args))
-        return temp_name
-
-    def visitAlias(self, alias, args):
-        return self.visitScalar(alias, args)
-
-    def visitEnum(self, enum, args):
-        return self.visit(GLint, args)
-
-    def visitBitmask(self, bitmask, args):
-        return self.visit(GLint, args)
-
-    def visitArray(self, array, args):
-        temp_name = self.temp_name(args)
-        if array.length == '1':
-            return self.visit(array.type)
-        elem_type = self.inflector.reduced_type(array.type)
-        inflection = self.inflector.inflect(array.type)
-        assert inflection.endswith('v')
-        print '    %s %s[%s + 1];' % (elem_type, temp_name, array.length)
-        print '    memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name)
-        print '    %s[%s] = (%s)0xdeadc0de;' % (temp_name, array.length, elem_type)
-        print '    %s(%s, %s);' % (inflection + self.suffix, ', '.join(args), temp_name)
-        # Simple buffer overflow detection
-        print '    assert(%s[%s] == (%s)0xdeadc0de);' % (temp_name, array.length, elem_type)
-        return temp_name
-
-    def visitOpaque(self, pointer, args):
-        temp_name = self.temp_name(args)
-        inflection = self.inflector.inflect(pointer)
-        assert inflection.endswith('v')
-        print '    GLvoid *%s;' % temp_name
-        print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
-        return temp_name
-
-
-glGet = StateGetter('glGet', {
-    B: 'Booleanv',
-    I: 'Integerv',
-    F: 'Floatv',
-    D: 'Doublev',
-    S: 'String',
-    P: 'Pointerv',
-})
-
-glGetMaterial = StateGetter('glGetMaterial', {I: 'iv', F: 'fv'})
-glGetLight = StateGetter('glGetLight', {I: 'iv', F: 'fv'})
-glGetVertexAttrib = StateGetter('glGetVertexAttrib', {I: 'iv', F: 'fv', D: 'dv', P: 'Pointerv'})
-glGetTexParameter = StateGetter('glGetTexParameter', {I: 'iv', F: 'fv'})
-glGetTexEnv = StateGetter('glGetTexEnv', {I: 'iv', F: 'fv'})
-glGetTexLevelParameter = StateGetter('glGetTexLevelParameter', {I: 'iv', F: 'fv'})
-glGetShader = StateGetter('glGetShaderiv', {I: 'iv'})
-glGetProgram = StateGetter('glGetProgram', {I: 'iv'})
-glGetProgramARB = StateGetter('glGetProgram', {I: 'iv', F: 'fv', S: 'Stringv'}, 'ARB')
-glGetFramebufferAttachmentParameter = StateGetter('glGetFramebufferAttachmentParameter', {I: 'iv'})
-
-
-class JsonWriter(Visitor):
-    '''Type visitor that will dump a value of the specified type through the
-    JSON writer.
-    
-    It expects a previously declared JSONWriter instance named "json".'''
-
-    def visitLiteral(self, literal, instance):
-        if literal.kind == 'Bool':
-            print '    json.writeBool(%s);' % instance
-        elif literal.kind in ('SInt', 'Uint', 'Float', 'Double'):
-            print '    json.writeNumber(%s);' % instance
-        else:
-            raise NotImplementedError
-
-    def visitString(self, string, instance):
-        assert string.length is None
-        print '    json.writeString((const char *)%s);' % instance
-
-    def visitEnum(self, enum, instance):
-        if enum.expr == 'GLenum':
-            print '    dumpEnum(json, %s);' % instance
-        else:
-            print '    json.writeNumber(%s);' % instance
-
-    def visitBitmask(self, bitmask, instance):
-        raise NotImplementedError
-
-    def visitAlias(self, alias, instance):
-        self.visit(alias.type, instance)
-
-    def visitOpaque(self, opaque, instance):
-        print '    json.writeNumber((size_t)%s);' % instance
-
-    __index = 0
-
-    def visitArray(self, array, instance):
-        index = '__i%u' % JsonWriter.__index
-        JsonWriter.__index += 1
-        print '    json.beginArray();'
-        print '    for (unsigned %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
-        self.visit(array.type, '%s[%s]' % (instance, index))
-        print '    }'
-        print '    json.endArray();'
-
-
-
-class StateDumper:
-    '''Class to generate code to dump all GL state in JSON format via
-    stdout.'''
-
-    def __init__(self):
-        pass
-
-    def dump(self):
-        print '#include <string.h>'
-        print
-        print '#include "json.hpp"'
-        print '#include "glproc.hpp"'
-        print '#include "glsize.hpp"'
-        print '#include "glstate.hpp"'
-        print '#include "glstate_internal.hpp"'
-        print
-        print 'namespace glstate {'
-        print
-
-        print 'const char *'
-        print 'enumToString(GLenum pname)'
-        print '{'
-        print '    switch (pname) {'
-        for name in GLenum.values:
-            print '    case %s:' % name
-            print '        return "%s";' % name
-        print '    default:'
-        print '        return NULL;'
-        print '    }'
-        print '}'
-        print
-
-        print 'static void'
-        print 'dumpFramebufferAttachementParameters(JSONWriter &json, GLenum target, GLenum attachment)'
-        print '{'
-        self.dump_attachment_parameters('target', 'attachment')
-        print '}'
-        print
-
-        print 'void'
-        print 'dumpEnum(JSONWriter &json, GLenum pname)'
-        print '{'
-        print '    const char *s = enumToString(pname);'
-        print '    if (s) {'
-        print '        json.writeString(s);'
-        print '    } else {'
-        print '        json.writeNumber(pname);'
-        print '    }'
-        print '}'
-        print
-
-        print 'void dumpParameters(JSONWriter &json, Context &context)'
-        print '{'
-        print '    json.beginMember("parameters");'
-        print '    json.beginObject();'
-        
-        self.dump_atoms(glGet)
-        
-        self.dump_material_params()
-        self.dump_light_params()
-        self.dump_vertex_attribs()
-        self.dump_program_params()
-        self.dump_texture_parameters()
-        self.dump_framebuffer_parameters()
-
-        print '    json.endObject();'
-        print '    json.endMember(); // parameters'
-        print '}'
-        print
-        
-        print '} /*namespace glstate */'
-
-    def dump_material_params(self):
-        print '    if (!context.ES) {'
-        for face in ['GL_FRONT', 'GL_BACK']:
-            print '    json.beginMember("%s");' % face
-            print '    json.beginObject();'
-            self.dump_atoms(glGetMaterial, face)
-            print '    json.endObject();'
-        print '    }'
-        print
-
-    def dump_light_params(self):
-        print '    GLint max_lights = 0;'
-        print '    __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
-        print '    for (GLint index = 0; index < max_lights; ++index) {'
-        print '        GLenum light = GL_LIGHT0 + index;'
-        print '        if (glIsEnabled(light)) {'
-        print '            char name[32];'
-        print '            snprintf(name, sizeof name, "GL_LIGHT%i", index);'
-        print '            json.beginMember(name);'
-        print '            json.beginObject();'
-        self.dump_atoms(glGetLight, '    GL_LIGHT0 + index')
-        print '            json.endObject();'
-        print '            json.endMember(); // GL_LIGHTi'
-        print '        }'
-        print '    }'
-        print
-
-    def texenv_param_target(self, name):
-        if name == 'GL_TEXTURE_LOD_BIAS':
-           return 'GL_TEXTURE_FILTER_CONTROL'
-        elif name == 'GL_COORD_REPLACE':
-           return 'GL_POINT_SPRITE'
-        else:
-           return 'GL_TEXTURE_ENV'
-
-    def dump_texenv_params(self):
-        for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
-            print '    if (!context.ES) {'
-            print '        json.beginMember("%s");' % target
-            print '        json.beginObject();'
-            for _, _, name in glGetTexEnv.iter():
-                if self.texenv_param_target(name) == target:
-                    self.dump_atom(glGetTexEnv, target, name) 
-            print '        json.endObject();'
-            print '    }'
-
-    def dump_vertex_attribs(self):
-        print '    GLint max_vertex_attribs = 0;'
-        print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
-        print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
-        print '        char name[32];'
-        print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
-        print '        json.beginMember(name);'
-        print '        json.beginObject();'
-        self.dump_atoms(glGetVertexAttrib, 'index')
-        print '        json.endObject();'
-        print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
-        print '    }'
-        print
-
-    program_targets = [
-        'GL_FRAGMENT_PROGRAM_ARB',
-        'GL_VERTEX_PROGRAM_ARB',
-    ]
-
-    def dump_program_params(self):
-        for target in self.program_targets:
-            print '    if (glIsEnabled(%s)) {' % target
-            print '        json.beginMember("%s");' % target
-            print '        json.beginObject();'
-            self.dump_atoms(glGetProgramARB, target)
-            print '        json.endObject();'
-            print '    }'
-
-    def dump_texture_parameters(self):
-        print '    {'
-        print '        GLint active_texture = GL_TEXTURE0;'
-        print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
-        print '        GLint max_texture_coords = 0;'
-        print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
-        print '        GLint max_combined_texture_image_units = 0;'
-        print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
-        print '        GLint max_units = std::min(std::max(max_combined_texture_image_units, max_texture_coords), 2);'
-        print '        for (GLint unit = 0; unit < max_units; ++unit) {'
-        print '            char name[32];'
-        print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
-        print '            json.beginMember(name);'
-        print '            glActiveTexture(GL_TEXTURE0 + unit);'
-        print '            json.beginObject();'
-        print '            GLboolean enabled;'
-        print '            GLint binding;'
-        print
-        for target, binding in texture_targets:
-            print '            // %s' % target
-            print '            enabled = GL_FALSE;'
-            print '            glGetBooleanv(%s, &enabled);' % target
-            print '            json.writeBoolMember("%s", enabled);' % target
-            print '            binding = 0;'
-            print '            glGetIntegerv(%s, &binding);' % binding
-            print '            json.writeNumberMember("%s", binding);' % binding
-            print '            if (enabled || binding) {'
-            print '                json.beginMember("%s");' % target
-            print '                json.beginObject();'
-            self.dump_atoms(glGetTexParameter, target)
-            print '                if (!context.ES) {'
-            # We only dump the first level parameters
-            self.dump_atoms(glGetTexLevelParameter, target, "0")
-            print '                }'
-            print '                json.endObject();'
-            print '                json.endMember(); // %s' % target
-            print '            }'
-            print
-        print '            if (unit < max_texture_coords) {'
-        self.dump_texenv_params()
-        print '            }'
-        print '            json.endObject();'
-        print '            json.endMember(); // GL_TEXTUREi'
-        print '        }'
-        print '        glActiveTexture(active_texture);'
-        print '    }'
-        print
-
-    def dump_framebuffer_parameters(self):
-        print '    {'
-        print '        GLint max_color_attachments = 0;'
-        print '        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);'
-        print '        GLint framebuffer;'
-        for target, binding in framebuffer_targets:
-            print '            // %s' % target
-            print '            framebuffer = 0;'
-            print '            glGetIntegerv(%s, &framebuffer);' % binding
-            print '            if (framebuffer) {'
-            print '                json.beginMember("%s");' % target
-            print '                json.beginObject();'
-            print '                for (GLint i = 0; i < max_color_attachments; ++i) {'
-            print '                    GLint color_attachment = GL_COLOR_ATTACHMENT0 + i;'
-            print '                    dumpFramebufferAttachementParameters(json, %s, color_attachment);' % target
-            print '                }'
-            print '                dumpFramebufferAttachementParameters(json, %s, GL_DEPTH_ATTACHMENT);' % target
-            print '                dumpFramebufferAttachementParameters(json, %s, GL_STENCIL_ATTACHMENT);' % target
-            print '                json.endObject();'
-            print '                json.endMember(); // %s' % target
-            print '            }'
-            print
-        print '    }'
-        print
-
-    def dump_attachment_parameters(self, target, attachment):
-        print '            {'
-        print '                GLint object_type = GL_NONE;'
-        print '                glGetFramebufferAttachmentParameteriv(%s, %s, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);' % (target, attachment)
-        print '                if (object_type != GL_NONE) {'
-        print '                    json.beginMember(enumToString(%s));' % attachment
-        print '                    json.beginObject();'
-        self.dump_atoms(glGetFramebufferAttachmentParameter, target, attachment)
-        print '                    json.endObject();'
-        print '                    json.endMember(); // GL_x_ATTACHMENT'
-        print '                }'
-        print '            }'
-
-    def dump_atoms(self, getter, *args):
-        for _, _, name in getter.iter():
-            self.dump_atom(getter, *(args + (name,))) 
-
-    def dump_atom(self, getter, *args):
-        name = args[-1]
-
-        # Avoid crash on MacOSX
-        # XXX: The right fix would be to look at the support extensions..
-        import platform
-        if name == 'GL_SAMPLER_BINDING' and platform.system() == 'Darwin':
-            return
-
-        print '        // %s' % name
-        print '        {'
-        #print '            assert(glGetError() == GL_NO_ERROR);'
-        type, value = getter(*args)
-        print '            if (glGetError() != GL_NO_ERROR) {'
-        #print '                std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
-        print '                while (glGetError() != GL_NO_ERROR) {}'
-        print '            } else {'
-        print '                json.beginMember("%s");' % name
-        JsonWriter().visit(type, value)
-        print '                json.endMember();'
-        print '            }'
-        print '        }'
-        print
-
-
-if __name__ == '__main__':
-    StateDumper().dump()
diff --git a/glstate_shaders.cpp b/glstate_shaders.cpp
deleted file mode 100644 (file)
index 11286fb..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-
-#include <algorithm>
-#include <iostream>
-#include <map>
-#include <sstream>
-
-#include "json.hpp"
-#include "glproc.hpp"
-#include "glsize.hpp"
-#include "glstate.hpp"
-#include "glstate_internal.hpp"
-
-
-namespace glstate {
-
-
-// Mapping from shader type to shader source, used to accumulated the sources
-// of different shaders with same type.
-typedef std::map<std::string, std::string> ShaderMap;
-
-
-static void
-getShaderSource(ShaderMap &shaderMap, GLuint shader)
-{
-    if (!shader) {
-        return;
-    }
-
-    GLint shader_type = 0;
-    glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
-    if (!shader_type) {
-        return;
-    }
-
-    GLint source_length = 0;
-    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
-    if (!source_length) {
-        return;
-    }
-
-    GLchar *source = new GLchar[source_length];
-    GLsizei length = 0;
-    source[0] = 0;
-    glGetShaderSource(shader, source_length, &length, source);
-
-    shaderMap[enumToString(shader_type)] += source;
-
-    delete [] source;
-}
-
-
-static void
-getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
-{
-    if (!shaderObj) {
-        return;
-    }
-
-    GLint object_type = 0;
-    glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &object_type);
-    if (object_type != GL_SHADER_OBJECT_ARB) {
-        return;
-    }
-
-    GLint shader_type = 0;
-    glGetObjectParameterivARB(shaderObj, GL_OBJECT_SUBTYPE_ARB, &shader_type);
-    if (!shader_type) {
-        return;
-    }
-
-    GLint source_length = 0;
-    glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
-    if (!source_length) {
-        return;
-    }
-
-    GLcharARB *source = new GLcharARB[source_length];
-    GLsizei length = 0;
-    source[0] = 0;
-    glGetShaderSource(shaderObj, source_length, &length, source);
-
-    shaderMap[enumToString(shader_type)] += source;
-
-    delete [] source;
-}
-
-
-static inline void
-dumpProgram(JSONWriter &json, GLint program)
-{
-    GLint attached_shaders = 0;
-    glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
-    if (!attached_shaders) {
-        return;
-    }
-
-    ShaderMap shaderMap;
-
-    GLuint *shaders = new GLuint[attached_shaders];
-    GLsizei count = 0;
-    glGetAttachedShaders(program, attached_shaders, &count, shaders);
-    std::sort(shaders, shaders + count);
-    for (GLsizei i = 0; i < count; ++ i) {
-       getShaderSource(shaderMap, shaders[i]);
-    }
-    delete [] shaders;
-
-    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
-        json.beginMember(it->first);
-        json.writeString(it->second);
-        json.endMember();
-    }
-}
-
-
-static inline void
-dumpProgramObj(JSONWriter &json, GLhandleARB programObj)
-{
-    GLint attached_shaders = 0;
-    glGetObjectParameterivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
-    if (!attached_shaders) {
-        return;
-    }
-
-    ShaderMap shaderMap;
-
-    GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
-    GLsizei count = 0;
-    glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
-    std::sort(shaderObjs, shaderObjs + count);
-    for (GLsizei i = 0; i < count; ++ i) {
-       getShaderObjSource(shaderMap, shaderObjs[i]);
-    }
-    delete [] shaderObjs;
-
-    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
-        json.beginMember(it->first);
-        json.writeString(it->second);
-        json.endMember();
-    }
-}
-
-/*
- * When fetching the uniform name of an array we usually get name[0]
- * so we need to cut the trailing "[0]" in order to properly construct
- * array names later. Otherwise we endup with stuff like
- * uniformArray[0][0],
- * uniformArray[0][1],
- * instead of
- * uniformArray[0],
- * uniformArray[1].
- */
-static std::string
-resolveUniformName(const GLchar *name,  GLint size)
-{
-    std::string qualifiedName(name);
-    if (size > 1) {
-        std::string::size_type nameLength = qualifiedName.length();
-        static const char * const arrayStart = "[0]";
-        static const int arrayStartLen = 3;
-        if (qualifiedName.rfind(arrayStart) == (nameLength - arrayStartLen)) {
-            qualifiedName = qualifiedName.substr(0, nameLength - 3);
-        }
-    }
-    return qualifiedName;
-}
-
-static void
-dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
-    GLenum elemType;
-    GLint numElems;
-    __gl_uniform_size(type, elemType, numElems);
-    if (elemType == GL_NONE) {
-        return;
-    }
-
-    GLfloat fvalues[4*4];
-    GLdouble dvalues[4*4];
-    GLint ivalues[4*4];
-    GLuint uivalues[4*4];
-
-    GLint i, j;
-
-    std::string qualifiedName = resolveUniformName(name, size);
-
-    for (i = 0; i < size; ++i) {
-        std::stringstream ss;
-        ss << qualifiedName;
-
-        if (size > 1) {
-            ss << '[' << i << ']';
-        }
-
-        std::string elemName = ss.str();
-
-        json.beginMember(elemName);
-
-        GLint location = glGetUniformLocation(program, elemName.c_str());
-
-        if (numElems > 1) {
-            json.beginArray();
-        }
-
-        switch (elemType) {
-        case GL_FLOAT:
-            glGetUniformfv(program, location, fvalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(fvalues[j]);
-            }
-            break;
-        case GL_DOUBLE:
-            glGetUniformdv(program, location, dvalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(dvalues[j]);
-            }
-            break;
-        case GL_INT:
-            glGetUniformiv(program, location, ivalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(ivalues[j]);
-            }
-            break;
-        case GL_UNSIGNED_INT:
-            glGetUniformuiv(program, location, uivalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(uivalues[j]);
-            }
-            break;
-        case GL_BOOL:
-            glGetUniformiv(program, location, ivalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeBool(ivalues[j]);
-            }
-            break;
-        default:
-            assert(0);
-            break;
-        }
-
-        if (numElems > 1) {
-            json.endArray();
-        }
-
-        json.endMember();
-    }
-}
-
-
-static void
-dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
-
-    GLenum elemType;
-    GLint numElems;
-    __gl_uniform_size(type, elemType, numElems);
-    if (elemType == GL_NONE) {
-        return;
-    }
-
-    GLfloat fvalues[4*4];
-    GLint ivalues[4*4];
-
-    GLint i, j;
-
-    std::string qualifiedName = resolveUniformName(name, size);
-
-    for (i = 0; i < size; ++i) {
-        std::stringstream ss;
-        ss << qualifiedName;
-
-        if (size > 1) {
-            ss << '[' << i << ']';
-        }
-
-        std::string elemName = ss.str();
-
-        json.beginMember(elemName);
-
-        GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
-
-        if (numElems > 1) {
-            json.beginArray();
-        }
-
-        switch (elemType) {
-        case GL_DOUBLE:
-            // glGetUniformdvARB does not exists
-        case GL_FLOAT:
-            glGetUniformfvARB(programObj, location, fvalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(fvalues[j]);
-            }
-            break;
-        case GL_UNSIGNED_INT:
-            // glGetUniformuivARB does not exists
-        case GL_INT:
-            glGetUniformivARB(programObj, location, ivalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeNumber(ivalues[j]);
-            }
-            break;
-        case GL_BOOL:
-            glGetUniformivARB(programObj, location, ivalues);
-            for (j = 0; j < numElems; ++j) {
-                json.writeBool(ivalues[j]);
-            }
-            break;
-        default:
-            assert(0);
-            break;
-        }
-
-        if (numElems > 1) {
-            json.endArray();
-        }
-
-        json.endMember();
-    }
-}
-
-
-static inline void
-dumpProgramUniforms(JSONWriter &json, GLint program)
-{
-    GLint active_uniforms = 0;
-    glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
-    if (!active_uniforms) {
-        return;
-    }
-
-    GLint active_uniform_max_length = 0;
-    glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
-    GLchar *name = new GLchar[active_uniform_max_length];
-    if (!name) {
-        return;
-    }
-
-    for (GLint index = 0; index < active_uniforms; ++index) {
-        GLsizei length = 0;
-        GLint size = 0;
-        GLenum type = GL_NONE;
-        glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
-
-        dumpUniform(json, program, size, type, name);
-    }
-
-    delete [] name;
-}
-
-
-static inline void
-dumpProgramObjUniforms(JSONWriter &json, GLhandleARB programObj)
-{
-    GLint active_uniforms = 0;
-    glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
-    if (!active_uniforms) {
-        return;
-    }
-
-    GLint active_uniform_max_length = 0;
-    glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
-    GLchar *name = new GLchar[active_uniform_max_length];
-    if (!name) {
-        return;
-    }
-
-    for (GLint index = 0; index < active_uniforms; ++index) {
-        GLsizei length = 0;
-        GLint size = 0;
-        GLenum type = GL_NONE;
-        glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
-
-        dumpUniformARB(json, programObj, size, type, name);
-    }
-
-    delete [] name;
-}
-
-
-static inline void
-dumpArbProgram(JSONWriter &json, GLenum target)
-{
-    if (!glIsEnabled(target)) {
-        return;
-    }
-
-    GLint program_length = 0;
-    glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
-    if (!program_length) {
-        return;
-    }
-
-    GLchar *source = new GLchar[program_length + 1];
-    source[0] = 0;
-    glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
-    source[program_length] = 0;
-
-    json.beginMember(enumToString(target));
-    json.writeString(source);
-    json.endMember();
-
-    delete [] source;
-}
-
-
-static inline void
-dumpArbProgramUniforms(JSONWriter &json, GLenum target, const char *prefix)
-{
-    if (!glIsEnabled(target)) {
-        return;
-    }
-
-    GLint program_parameters = 0;
-    glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
-    if (!program_parameters) {
-        return;
-    }
-
-    GLint max_program_local_parameters = 0;
-    glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
-    for (GLint index = 0; index < max_program_local_parameters; ++index) {
-        GLdouble params[4] = {0, 0, 0, 0};
-        glGetProgramLocalParameterdvARB(target, index, params);
-
-        if (!params[0] && !params[1] && !params[2] && !params[3]) {
-            continue;
-        }
-
-        char name[256];
-        snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index);
-
-        json.beginMember(name);
-        json.beginArray();
-        json.writeNumber(params[0]);
-        json.writeNumber(params[1]);
-        json.writeNumber(params[2]);
-        json.writeNumber(params[3]);
-        json.endArray();
-        json.endMember();
-    }
-
-    GLint max_program_env_parameters = 0;
-    glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
-    for (GLint index = 0; index < max_program_env_parameters; ++index) {
-        GLdouble params[4] = {0, 0, 0, 0};
-        glGetProgramEnvParameterdvARB(target, index, params);
-
-        if (!params[0] && !params[1] && !params[2] && !params[3]) {
-            continue;
-        }
-
-        char name[256];
-        snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index);
-
-        json.beginMember(name);
-        json.beginArray();
-        json.writeNumber(params[0]);
-        json.writeNumber(params[1]);
-        json.writeNumber(params[2]);
-        json.writeNumber(params[3]);
-        json.endArray();
-        json.endMember();
-    }
-}
-
-
-void
-dumpShadersUniforms(JSONWriter &json, Context &context)
-{
-    GLint program = 0;
-    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
-
-    GLhandleARB programObj = 0;
-    if (!context.ES && !program) {
-        programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
-    }
-
-    json.beginMember("shaders");
-    json.beginObject();
-    if (program) {
-        dumpProgram(json, program);
-    } else if (programObj) {
-        dumpProgramObj(json, programObj);
-    } else {
-        dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
-        dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
-    }
-    json.endObject();
-    json.endMember(); // shaders
-
-    json.beginMember("uniforms");
-    json.beginObject();
-    if (program) {
-        dumpProgramUniforms(json, program);
-    } else if (programObj) {
-        dumpProgramObjUniforms(json, programObj);
-    } else {
-        dumpArbProgramUniforms(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
-        dumpArbProgramUniforms(json, GL_VERTEX_PROGRAM_ARB, "vp.");
-    }
-    json.endObject();
-    json.endMember(); // uniforms
-}
-
-
-} /* namespace glstate */
diff --git a/glws.cpp b/glws.cpp
deleted file mode 100644 (file)
index c5c41eb..0000000
--- a/glws.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include "glws.hpp"
-
-
-namespace glws {
-
-
-bool debug = true;
-
-
-bool
-checkExtension(const char *extName, const char *extString)
-{
-   const char *p = extString;
-   const char *q = extName;
-   char c;
-   do {
-       c = *p++;
-       if (c == '\0' || c == ' ') {
-           if (q && *q == '\0') {
-               return true;
-           } else {
-               q = extName;
-           }
-       } else {
-           if (q && *q == c) {
-               ++q;
-           } else {
-               q = 0;
-           }
-       }
-   } while (c);
-   return false;
-}
-
-
-} /* namespace glws */
diff --git a/glws.hpp b/glws.hpp
deleted file mode 100644 (file)
index 9afebf4..0000000
--- a/glws.hpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-/*
- * Abstraction for GL window system specific APIs (GLX, WGL).
- */
-
-#ifndef _GLWS_HPP_
-#define _GLWS_HPP_
-
-
-#include <vector>
-
-
-namespace glws {
-
-
-enum Profile {
-    PROFILE_COMPAT = 0,
-    PROFILE_CORE,
-    PROFILE_ES1,
-    PROFILE_ES2,
-    PROFILE_MAX
-};
-
-
-extern bool debug;
-
-
-bool
-checkExtension(const char *extName, const char *extString);
-
-
-template< class T >
-class Attributes {
-protected:
-    std::vector<T> attribs;
-
-public:
-    void add(T param) {
-        attribs.push_back(param);
-    }
-
-    void add(T pname, T pvalue) {
-        add(pname);
-        add(pvalue);
-    }
-
-    void end(T terminator = 0) {
-        add(terminator);
-    }
-
-    operator T * (void) {
-        return &attribs[0];
-    }
-
-    operator const T * (void) const {
-        return &attribs[0];
-    }
-};
-
-
-class Visual
-{
-public:
-    unsigned long redMask;
-    unsigned long greenMask;
-    unsigned long blueMask;
-    unsigned long alphaMask;
-    bool doubleBuffer;
-
-    virtual ~Visual() {}
-};
-
-
-class Drawable
-{
-public:
-    const Visual *visual;
-    int width;
-    int height;
-    bool visible;
-
-    Drawable(const Visual *vis, int w, int h) :
-        visual(vis),
-        width(w),
-        height(h),
-        visible(false)
-    {}
-
-    virtual ~Drawable() {}
-    
-    virtual void
-    resize(int w, int h) {
-        width = w;
-        height = h;
-    }
-
-    virtual void
-    show(void) {
-        visible = true;
-    }
-
-    virtual void swapBuffers(void) = 0;
-};
-
-
-class Context
-{
-public:
-    const Visual *visual;
-    Profile profile;
-    
-    Context(const Visual *vis, Profile prof) :
-        visual(vis),
-        profile(prof)
-    {}
-
-    virtual ~Context() {}
-};
-
-
-void
-init(void);
-
-void
-cleanup(void);
-
-Visual *
-createVisual(bool doubleBuffer = false, Profile profile = PROFILE_COMPAT);
-
-Drawable *
-createDrawable(const Visual *visual, int width = 32, int height = 32);
-
-Context *
-createContext(const Visual *visual, Context *shareContext = 0, Profile profile = PROFILE_COMPAT);
-
-bool
-makeCurrent(Drawable *drawable, Context *context);
-
-bool
-processEvents(void);
-
-
-} /* namespace glws */
-
-
-#endif /* _GLWS_HPP_ */
diff --git a/glws_cocoa.mm b/glws_cocoa.mm
deleted file mode 100644 (file)
index 7f696fa..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-/**
- * Minimal Cocoa integration.
- *
- * See also:
- * - http://developer.apple.com/library/mac/#samplecode/CocoaGL/Introduction/Intro.html
- * - http://developer.apple.com/library/mac/#samplecode/Cocoa_With_Carbon_or_CPP/Introduction/Intro.html
- * - http://developer.apple.com/library/mac/#samplecode/glut/Introduction/Intro.html
- * - http://developer.apple.com/library/mac/#samplecode/GLEssentials/Introduction/Intro.html
- * - http://www.glfw.org/
- */
-
-
-#include <stdlib.h>
-#include <iostream>
-
-#include <Cocoa/Cocoa.h>
-
-#include "glws.hpp"
-
-
-namespace glws {
-
-
-NSAutoreleasePool *autoreleasePool = nil;
-
-
-class CocoaVisual : public Visual
-{
-public:
-    NSOpenGLPixelFormat *pixelFormat;
-
-    CocoaVisual(NSOpenGLPixelFormat *pf) :
-        pixelFormat(pf)
-    {}
-
-    ~CocoaVisual() {
-        [pixelFormat release];
-    }
-};
-
-class CocoaDrawable : public Drawable
-{
-public:
-    NSWindow *window;
-    NSOpenGLContext *currentContext;
-
-    CocoaDrawable(const Visual *vis, int w, int h) :
-        Drawable(vis, w, h),
-        currentContext(nil)
-    {
-        NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
-
-        NSRect winRect = NSMakeRect(0, 0, w, h);
-
-        window = [[NSWindow alloc]
-                         initWithContentRect:winRect
-                                   styleMask:NSTitledWindowMask |
-                                             NSClosableWindowMask |
-                                             NSMiniaturizableWindowMask
-                                     backing:NSBackingStoreRetained
-                                       defer:NO];
-        assert(window != nil);
-
-        NSOpenGLView *view = [[NSOpenGLView alloc]
-                              initWithFrame:winRect
-                                pixelFormat:pixelFormat];
-        assert(view != nil);
-
-        [window setContentView:view];
-        [window setTitle:@"glretrace"];
-
-    }
-
-    ~CocoaDrawable() {
-        [window release];
-    }
-
-    void
-    resize(int w, int h) {
-        if (w == width && h == height) {
-            return;
-        }
-
-        [window setContentSize:NSMakeSize(w, h)];
-
-        if (currentContext != nil) {
-            [currentContext update];
-            [window makeKeyAndOrderFront:nil];
-            [currentContext setView:[window contentView]];
-            [currentContext makeCurrentContext];
-        }
-
-        Drawable::resize(w, h);
-    }
-
-    void show(void) {
-        if (visible) {
-            return;
-        }
-
-        // TODO
-
-        Drawable::show();
-    }
-
-    void swapBuffers(void) {
-        if (currentContext != nil) {
-            [currentContext flushBuffer];
-        }
-    }
-};
-
-
-class CocoaContext : public Context
-{
-public:
-    NSOpenGLContext *context;
-
-    CocoaContext(const Visual *vis, Profile prof, NSOpenGLContext *ctx) :
-        Context(vis, prof),
-        context(ctx)
-    {}
-
-    ~CocoaContext() {
-        [context release];
-    }
-};
-
-
-void
-init(void) {
-    [NSApplication sharedApplication];
-
-    autoreleasePool = [[NSAutoreleasePool alloc] init];
-
-    [NSApp finishLaunching];
-}
-
-
-void
-cleanup(void) {
-    [autoreleasePool release];
-}
-
-
-Visual *
-createVisual(bool doubleBuffer, Profile profile) {
-    if (profile != PROFILE_COMPAT &&
-        profile != PROFILE_CORE) {
-        return nil;
-    }
-
-    Attributes<NSOpenGLPixelFormatAttribute> attribs;
-
-    attribs.add(NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)1);
-    attribs.add(NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24);
-    if (doubleBuffer) {
-        attribs.add(NSOpenGLPFADoubleBuffer);
-    }
-    attribs.add(NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)1);
-    attribs.add(NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)1);
-    if (profile == PROFILE_CORE) {
-#if CGL_VERSION_1_3
-        attribs.add(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
-#else
-       return NULL;
-#endif
-    }
-    attribs.end();
-
-    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
-                                     initWithAttributes:attribs];
-
-    return new CocoaVisual(pixelFormat);
-}
-
-Drawable *
-createDrawable(const Visual *visual, int width, int height)
-{
-    return new CocoaDrawable(visual, width, height);
-}
-
-Context *
-createContext(const Visual *visual, Context *shareContext, Profile profile)
-{
-    NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
-    NSOpenGLContext *share_context = nil;
-    NSOpenGLContext *context;
-
-    if (profile != PROFILE_COMPAT &&
-        profile != PROFILE_CORE) {
-        return nil;
-    }
-
-    if (shareContext) {
-        share_context = static_cast<CocoaContext*>(shareContext)->context;
-    }
-
-    context = [[NSOpenGLContext alloc]
-               initWithFormat:pixelFormat
-               shareContext:share_context];
-    assert(context != nil);
-
-    return new CocoaContext(visual, profile, context);
-}
-
-bool
-makeCurrent(Drawable *drawable, Context *context)
-{
-    if (!drawable || !context) {
-        [NSOpenGLContext clearCurrentContext];
-    } else {
-        CocoaDrawable *cocoaDrawable = static_cast<CocoaDrawable *>(drawable);
-        CocoaContext *cocoaContext = static_cast<CocoaContext *>(context);
-
-        [cocoaDrawable->window makeKeyAndOrderFront:nil];
-        [cocoaContext->context setView:[cocoaDrawable->window contentView]];
-        [cocoaContext->context makeCurrentContext];
-
-        cocoaDrawable->currentContext = cocoaContext->context;
-    }
-
-    return TRUE;
-}
-
-bool
-processEvents(void) {
-   NSEvent* event;
-
-    do {
-        event = [NSApp nextEventMatchingMask:NSAnyEventMask
-                                   untilDate:[NSDate distantPast]
-                                      inMode:NSDefaultRunLoopMode
-                                     dequeue:YES];
-        if (event)
-            [NSApp sendEvent:event];
-    } while (event);
-
-    return true;
-}
-
-
-} /* namespace glws */
diff --git a/glws_egl_xlib.cpp b/glws_egl_xlib.cpp
deleted file mode 100644 (file)
index 6655781..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 LunarG, Inc.
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include <iostream>
-
-#include <dlfcn.h>
-
-#include "glproc.hpp"
-#include "glws.hpp"
-
-
-namespace glws {
-
-
-static Display *display = NULL;
-static EGLDisplay eglDisplay = EGL_NO_DISPLAY;
-static int screen = 0;
-
-
-class EglVisual : public Visual
-{
-public:
-    EGLConfig config;
-    XVisualInfo *visinfo;
-
-    EglVisual() :
-        config(0),
-        visinfo(0)
-    {}
-
-    ~EglVisual() {
-        XFree(visinfo);
-    }
-};
-
-
-static void describeEvent(const XEvent &event) {
-    if (0) {
-        switch (event.type) {
-        case ConfigureNotify:
-            std::cerr << "ConfigureNotify";
-            break;
-        case Expose:
-            std::cerr << "Expose";
-            break;
-        case KeyPress:
-            std::cerr << "KeyPress";
-            break;
-        case MapNotify:
-            std::cerr << "MapNotify";
-            break;
-        case ReparentNotify:
-            std::cerr << "ReparentNotify";
-            break;
-        default:
-            std::cerr << "Event " << event.type;
-        }
-        std::cerr << " " << event.xany.window << "\n";
-    }
-}
-
-class EglDrawable : public Drawable
-{
-public:
-    Window window;
-    EGLSurface surface;
-    EGLint api;
-
-    EglDrawable(const Visual *vis, int w, int h) :
-        Drawable(vis, w, h), api(EGL_OPENGL_ES_API)
-    {
-        XVisualInfo *visinfo = static_cast<const EglVisual *>(visual)->visinfo;
-
-        Window root = RootWindow(display, screen);
-
-        /* window attributes */
-        XSetWindowAttributes attr;
-        attr.background_pixel = 0;
-        attr.border_pixel = 0;
-        attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
-        attr.event_mask = StructureNotifyMask;
-
-        unsigned long mask;
-        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
-
-        int x = 0, y = 0;
-
-        window = XCreateWindow(
-            display, root,
-            x, y, width, height,
-            0,
-            visinfo->depth,
-            InputOutput,
-            visinfo->visual,
-            mask,
-            &attr);
-
-        XSizeHints sizehints;
-        sizehints.x = x;
-        sizehints.y = y;
-        sizehints.width  = width;
-        sizehints.height = height;
-        sizehints.flags = USSize | USPosition;
-        XSetNormalHints(display, window, &sizehints);
-
-        const char *name = "glretrace";
-        XSetStandardProperties(
-            display, window, name, name,
-            None, (char **)NULL, 0, &sizehints);
-
-        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-
-        EGLConfig config = static_cast<const EglVisual *>(visual)->config;
-        surface = eglCreateWindowSurface(eglDisplay, config, (EGLNativeWindowType)window, NULL);
-    }
-
-    void waitForEvent(int type) {
-        XEvent event;
-        do {
-            XWindowEvent(display, window, StructureNotifyMask, &event);
-            describeEvent(event);
-        } while (event.type != type);
-    }
-
-    ~EglDrawable() {
-        eglDestroySurface(eglDisplay, surface);
-        eglWaitClient();
-        XDestroyWindow(display, window);
-        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-    }
-
-    void
-    resize(int w, int h) {
-        if (w == width && h == height) {
-            return;
-        }
-
-        eglWaitClient();
-
-        // We need to ensure that pending events are processed here, and XSync
-        // with discard = True guarantees that, but it appears the limited
-        // event processing we do so far is sufficient
-        //XSync(display, True);
-
-        Drawable::resize(w, h);
-
-        XResizeWindow(display, window, w, h);
-
-        // Tell the window manager to respect the requested size
-        XSizeHints size_hints;
-        size_hints.max_width  = size_hints.min_width  = w;
-        size_hints.max_height = size_hints.min_height = h;
-        size_hints.flags = PMinSize | PMaxSize;
-        XSetWMNormalHints(display, window, &size_hints);
-
-        waitForEvent(ConfigureNotify);
-
-        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-    }
-
-    void show(void) {
-        if (visible) {
-            return;
-        }
-
-        eglWaitClient();
-
-        XMapWindow(display, window);
-
-        waitForEvent(MapNotify);
-
-        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-
-        Drawable::show();
-    }
-
-    void swapBuffers(void) {
-        eglBindAPI(api);
-        eglSwapBuffers(eglDisplay, surface);
-    }
-};
-
-
-class EglContext : public Context
-{
-public:
-    EGLContext context;
-
-    EglContext(const Visual *vis, Profile prof, EGLContext ctx) :
-        Context(vis, prof),
-        context(ctx)
-    {}
-
-    ~EglContext() {
-        eglDestroyContext(eglDisplay, context);
-    }
-};
-
-/**
- * Load the symbols from the specified shared object into global namespace, so
- * that they can be later found by dlsym(RTLD_NEXT, ...);
- */
-static void
-load(const char *filename)
-{
-    if (!dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) {
-        std::cerr << "error: unable to open " << filename << "\n";
-        exit(1);
-    }
-}
-
-void
-init(void) {
-    load("libEGL.so.1");
-
-    display = XOpenDisplay(NULL);
-    if (!display) {
-        std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
-        exit(1);
-    }
-
-    screen = DefaultScreen(display);
-
-    eglDisplay = eglGetDisplay((EGLNativeDisplayType)display);
-    if (eglDisplay == EGL_NO_DISPLAY) {
-        std::cerr << "error: unable to get EGL display\n";
-        XCloseDisplay(display);
-        exit(1);
-    }
-
-    EGLint major, minor;
-    if (!eglInitialize(eglDisplay, &major, &minor)) {
-        std::cerr << "error: unable to initialize EGL display\n";
-        XCloseDisplay(display);
-        exit(1);
-    }
-}
-
-void
-cleanup(void) {
-    if (display) {
-        eglTerminate(eglDisplay);
-        XCloseDisplay(display);
-        display = NULL;
-    }
-}
-
-Visual *
-createVisual(bool doubleBuffer, Profile profile) {
-    EglVisual *visual = new EglVisual();
-    // possible combinations
-    const EGLint api_bits_gl[7] = {
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT,
-        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_ES_BIT,
-    };
-    const EGLint api_bits_gles1[7] = {
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
-        EGL_OPENGL_ES_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT,
-        EGL_OPENGL_ES2_BIT,
-    };
-    const EGLint api_bits_gles2[7] = {
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_ES2_BIT,
-        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
-        EGL_OPENGL_BIT,
-        EGL_OPENGL_ES_BIT,
-    };
-    const EGLint *api_bits;
-
-    switch(profile) {
-    case PROFILE_COMPAT:
-        api_bits = api_bits_gl;
-        break;
-    case PROFILE_ES1:
-        api_bits = api_bits_gles1;
-        break;
-    case PROFILE_ES2:
-        api_bits = api_bits_gles2;
-        break;
-    default:
-        return NULL;
-    };
-
-    for (int i = 0; i < 7; i++) {
-        Attributes<EGLint> attribs;
-
-        attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
-        attribs.add(EGL_RED_SIZE, 1);
-        attribs.add(EGL_GREEN_SIZE, 1);
-        attribs.add(EGL_BLUE_SIZE, 1);
-        attribs.add(EGL_ALPHA_SIZE, 1);
-        attribs.add(EGL_DEPTH_SIZE, 1);
-        attribs.add(EGL_STENCIL_SIZE, 1);
-        attribs.add(EGL_RENDERABLE_TYPE, api_bits[i]);
-        attribs.end(EGL_NONE);
-
-        EGLint num_configs, vid;
-        if (eglChooseConfig(eglDisplay, attribs, &visual->config, 1, &num_configs) &&
-            num_configs == 1 &&
-            eglGetConfigAttrib(eglDisplay, visual->config, EGL_NATIVE_VISUAL_ID, &vid)) {
-            XVisualInfo templ;
-            int num_visuals;
-
-            templ.visualid = vid;
-            visual->visinfo = XGetVisualInfo(display, VisualIDMask, &templ, &num_visuals);
-            break;
-        }
-    }
-
-    assert(visual->visinfo);
-
-    return visual;
-}
-
-Drawable *
-createDrawable(const Visual *visual, int width, int height)
-{
-    return new EglDrawable(visual, width, height);
-}
-
-Context *
-createContext(const Visual *_visual, Context *shareContext, Profile profile)
-{
-    const EglVisual *visual = static_cast<const EglVisual *>(_visual);
-    EGLContext share_context = EGL_NO_CONTEXT;
-    EGLContext context;
-    Attributes<EGLint> attribs;
-
-    if (shareContext) {
-        share_context = static_cast<EglContext*>(shareContext)->context;
-    }
-
-    EGLint api = eglQueryAPI();
-
-    switch (profile) {
-    case PROFILE_COMPAT:
-        load("libGL.so.1");
-        eglBindAPI(EGL_OPENGL_API);
-        break;
-    case PROFILE_CORE:
-        assert(0);
-        return NULL;
-    case PROFILE_ES1:
-        load("libGLESv1_CM.so.1");
-        eglBindAPI(EGL_OPENGL_ES_API);
-        break;
-    case PROFILE_ES2:
-        load("libGLESv2.so.2");
-        eglBindAPI(EGL_OPENGL_ES_API);
-        attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2);
-        break;
-    default:
-        return NULL;
-    }
-
-    attribs.end(EGL_NONE);
-
-    context = eglCreateContext(eglDisplay, visual->config, share_context, attribs);
-    if (!context)
-        return NULL;
-
-    eglBindAPI(api);
-
-    return new EglContext(visual, profile, context);
-}
-
-bool
-makeCurrent(Drawable *drawable, Context *context)
-{
-    if (!drawable || !context) {
-        return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    } else {
-        EglDrawable *eglDrawable = static_cast<EglDrawable *>(drawable);
-        EglContext *eglContext = static_cast<EglContext *>(context);
-        EGLBoolean ok;
-
-        ok = eglMakeCurrent(eglDisplay, eglDrawable->surface,
-                            eglDrawable->surface, eglContext->context);
-
-        if (ok) {
-            EGLint api;
-
-            eglQueryContext(eglDisplay, eglContext->context,
-                            EGL_CONTEXT_CLIENT_TYPE, &api);
-
-            eglDrawable->api = api;
-        }
-
-        return ok;
-    }
-}
-
-bool
-processEvents(void) {
-    while (XPending(display) > 0) {
-        XEvent event;
-        XNextEvent(display, &event);
-        describeEvent(event);
-    }
-    return true;
-}
-
-
-} /* namespace glws */
diff --git a/glws_glx.cpp b/glws_glx.cpp
deleted file mode 100644 (file)
index c151db1..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include <iostream>
-
-#include "glproc.hpp"
-#include "glws.hpp"
-
-
-namespace glws {
-
-
-static Display *display = NULL;
-static int screen = 0;
-
-static unsigned glxVersion = 0;
-static const char *extensions = 0;
-static bool has_GLX_ARB_create_context = false;
-
-
-class GlxVisual : public Visual
-{
-public:
-    GLXFBConfig fbconfig;
-    XVisualInfo *visinfo;
-
-    GlxVisual() :
-        fbconfig(0),
-        visinfo(0)
-    {}
-
-    ~GlxVisual() {
-        XFree(visinfo);
-    }
-};
-
-
-static void describeEvent(const XEvent &event) {
-    if (0) {
-        switch (event.type) {
-        case ConfigureNotify:
-            std::cerr << "ConfigureNotify";
-            break;
-        case Expose:
-            std::cerr << "Expose";
-            break;
-        case KeyPress:
-            std::cerr << "KeyPress";
-            break;
-        case MapNotify:
-            std::cerr << "MapNotify";
-            break;
-        case ReparentNotify:
-            std::cerr << "ReparentNotify";
-            break;
-        default:
-            std::cerr << "Event " << event.type;
-        }
-        std::cerr << " " << event.xany.window << "\n";
-    }
-}
-
-class GlxDrawable : public Drawable
-{
-public:
-    Window window;
-
-    GlxDrawable(const Visual *vis, int w, int h) :
-        Drawable(vis, w, h)
-    {
-        XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
-
-        Window root = RootWindow(display, screen);
-
-        /* window attributes */
-        XSetWindowAttributes attr;
-        attr.background_pixel = 0;
-        attr.border_pixel = 0;
-        attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
-        attr.event_mask = StructureNotifyMask;
-
-        unsigned long mask;
-        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
-
-        int x = 0, y = 0;
-
-        window = XCreateWindow(
-            display, root,
-            x, y, width, height,
-            0,
-            visinfo->depth,
-            InputOutput,
-            visinfo->visual,
-            mask,
-            &attr);
-
-        XSizeHints sizehints;
-        sizehints.x = x;
-        sizehints.y = y;
-        sizehints.width  = width;
-        sizehints.height = height;
-        sizehints.flags = USSize | USPosition;
-        XSetNormalHints(display, window, &sizehints);
-
-        const char *name = "glretrace";
-        XSetStandardProperties(
-            display, window, name, name,
-            None, (char **)NULL, 0, &sizehints);
-
-        glXWaitX();
-    }
-
-    void waitForEvent(int type) {
-        XEvent event;
-        do {
-            XWindowEvent(display, window, StructureNotifyMask, &event);
-            describeEvent(event);
-        } while (event.type != type);
-    }
-
-    ~GlxDrawable() {
-        XDestroyWindow(display, window);
-    }
-
-    void
-    resize(int w, int h) {
-        if (w == width && h == height) {
-            return;
-        }
-
-        glXWaitGL();
-
-        // We need to ensure that pending events are processed here, and XSync
-        // with discard = True guarantees that, but it appears the limited
-        // event processing we do so far is sufficient
-        //XSync(display, True);
-
-        Drawable::resize(w, h);
-
-        XResizeWindow(display, window, w, h);
-
-        // Tell the window manager to respect the requested size
-        XSizeHints size_hints;
-        size_hints.max_width  = size_hints.min_width  = w;
-        size_hints.max_height = size_hints.min_height = h;
-        size_hints.flags = PMinSize | PMaxSize;
-        XSetWMNormalHints(display, window, &size_hints);
-
-        waitForEvent(ConfigureNotify);
-
-        glXWaitX();
-    }
-
-    void show(void) {
-        if (visible) {
-            return;
-        }
-
-        glXWaitGL();
-
-        XMapWindow(display, window);
-
-        waitForEvent(MapNotify);
-
-        glXWaitX();
-
-        Drawable::show();
-    }
-
-    void swapBuffers(void) {
-        glXSwapBuffers(display, window);
-    }
-};
-
-
-class GlxContext : public Context
-{
-public:
-    GLXContext context;
-
-    GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
-        Context(vis, prof),
-        context(ctx)
-    {}
-
-    ~GlxContext() {
-        glXDestroyContext(display, context);
-    }
-};
-
-void
-init(void) {
-    display = XOpenDisplay(NULL);
-    if (!display) {
-        std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
-        exit(1);
-    }
-
-    screen = DefaultScreen(display);
-
-    int major = 0, minor = 0;
-    glXQueryVersion(display, &major, &minor);
-    glxVersion = (major << 8) | minor;
-
-    extensions = glXQueryExtensionsString(display, screen);
-    has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
-}
-
-void
-cleanup(void) {
-    if (display) {
-        XCloseDisplay(display);
-        display = NULL;
-    }
-}
-
-Visual *
-createVisual(bool doubleBuffer, Profile profile) {
-    if (profile != PROFILE_COMPAT &&
-        profile != PROFILE_CORE) {
-        return NULL;
-    }
-
-    GlxVisual *visual = new GlxVisual;
-
-    if (glxVersion >= 0x0103) {
-        Attributes<int> attribs;
-        attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
-        attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
-        attribs.add(GLX_RED_SIZE, 1);
-        attribs.add(GLX_GREEN_SIZE, 1);
-        attribs.add(GLX_BLUE_SIZE, 1);
-        attribs.add(GLX_ALPHA_SIZE, 1);
-        attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
-        attribs.add(GLX_DEPTH_SIZE, 1);
-        attribs.add(GLX_STENCIL_SIZE, 1);
-        attribs.end();
-
-        int num_configs = 0;
-        GLXFBConfig * fbconfigs;
-        fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
-        assert(num_configs && fbconfigs);
-        visual->fbconfig = fbconfigs[0];
-        assert(visual->fbconfig);
-        visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
-        assert(visual->visinfo);
-    } else {
-        Attributes<int> attribs;
-        attribs.add(GLX_RGBA);
-        attribs.add(GLX_RED_SIZE, 1);
-        attribs.add(GLX_GREEN_SIZE, 1);
-        attribs.add(GLX_BLUE_SIZE, 1);
-        attribs.add(GLX_ALPHA_SIZE, 1);
-        if (doubleBuffer) {
-            attribs.add(GLX_DOUBLEBUFFER);
-        }
-        attribs.add(GLX_DEPTH_SIZE, 1);
-        attribs.add(GLX_STENCIL_SIZE, 1);
-        attribs.end();
-
-        visual->visinfo = glXChooseVisual(display, screen, attribs);
-    }
-
-    return visual;
-}
-
-Drawable *
-createDrawable(const Visual *visual, int width, int height)
-{
-    return new GlxDrawable(visual, width, height);
-}
-
-Context *
-createContext(const Visual *_visual, Context *shareContext, Profile profile)
-{
-    const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
-    GLXContext share_context = NULL;
-    GLXContext context;
-
-    if (shareContext) {
-        share_context = static_cast<GlxContext*>(shareContext)->context;
-    }
-
-    if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
-        Attributes<int> attribs;
-        
-        attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
-        if (debug) {
-            attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
-        }
-
-        switch (profile) {
-        case PROFILE_COMPAT:
-            break;
-        case PROFILE_CORE:
-            // XXX: This will invariable return a 3.2 context, when supported.
-            // We probably should have a PROFILE_CORE_XX per version.
-            attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3);
-            attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2);
-            attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
-            break;
-        default:
-            return NULL;
-        }
-        
-        attribs.end();
-
-        context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
-    } else {
-        if (profile != PROFILE_COMPAT) {
-            return NULL;
-        }
-
-        if (glxVersion >= 0x103) {
-            context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
-        } else {
-            context = glXCreateContext(display, visual->visinfo, share_context, True);
-        }
-    }
-
-    if (!context) {
-        return NULL;
-    }
-
-    return new GlxContext(visual, profile, context);
-}
-
-bool
-makeCurrent(Drawable *drawable, Context *context)
-{
-    if (!drawable || !context) {
-        return glXMakeCurrent(display, None, NULL);
-    } else {
-        GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
-        GlxContext *glxContext = static_cast<GlxContext *>(context);
-
-        return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
-    }
-}
-
-bool
-processEvents(void) {
-    while (XPending(display) > 0) {
-        XEvent event;
-        XNextEvent(display, &event);
-        describeEvent(event);
-    }
-    return true;
-}
-
-
-} /* namespace glws */
diff --git a/glws_wgl.cpp b/glws_wgl.cpp
deleted file mode 100644 (file)
index efefff0..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-/*
- * WGL bindings.
- */
-
-
-#include <iostream>
-
-#include "glproc.hpp"
-#include "glws.hpp"
-
-
-namespace glws {
-
-
-/*
- * Several WGL functions come in two flavors:
- * - GDI (ChoosePixelFormat, SetPixelFormat, SwapBuffers, etc)
- * - WGL (wglChoosePixelFormat, wglSetPixelFormat, wglSwapBuffers, etc)
- *
- * The GDI entrypoints will inevitably dispatch to the first module named
- * "OPENGL32", loading "C:\Windows\System32\opengl32.dll" if none was loaded so
- * far.
- *
- * In order to use a implementation other than the one installed in the system
- * (when specified via the TRACE_LIBGL environment variable), we need to use
- * WGL entrypoints.
- *
- * See also:
- * - http://www.opengl.org/archives/resources/faq/technical/mswindows.htm
- */
-static __PFNWGLCHOOSEPIXELFORMAT pfnChoosePixelFormat = &ChoosePixelFormat;
-static __PFNWGLSETPIXELFORMAT pfnSetPixelFormat = &SetPixelFormat;
-static __PFNWGLSWAPBUFFERS pfnSwapBuffers = &SwapBuffers;
-
-
-static LRESULT CALLBACK
-WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    MINMAXINFO *pMMI;
-    switch (uMsg) {
-    case WM_GETMINMAXINFO:
-        // Allow to create a window bigger than the desktop
-        pMMI = (MINMAXINFO *)lParam;
-        pMMI->ptMaxSize.x = 60000;
-        pMMI->ptMaxSize.y = 60000;
-        pMMI->ptMaxTrackSize.x = 60000;
-        pMMI->ptMaxTrackSize.y = 60000;
-        break;
-    default:
-        break;
-    }
-
-    return DefWindowProc(hWnd, uMsg, wParam, lParam);
-}
-
-
-class WglDrawable : public Drawable
-{
-public:
-    DWORD dwExStyle;
-    DWORD dwStyle;
-    HWND hWnd;
-    HDC hDC;
-    PIXELFORMATDESCRIPTOR pfd;
-    int iPixelFormat;
-
-    WglDrawable(const Visual *vis, int width, int height) :
-        Drawable(vis, width, height)
-    {
-        static bool first = TRUE;
-        RECT rect;
-        BOOL bRet;
-
-        if (first) {
-            WNDCLASS wc;
-            memset(&wc, 0, sizeof wc);
-            wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
-            wc.hCursor = LoadCursor(NULL, IDC_ARROW);
-            wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-            wc.lpfnWndProc = WndProc;
-            wc.lpszClassName = "glretrace";
-            wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
-            RegisterClass(&wc);
-            first = FALSE;
-        }
-
-        dwExStyle = 0;
-        dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
-
-        int x = 0, y = 0;
-
-        rect.left = x;
-        rect.top = y;
-        rect.right = rect.left + width;
-        rect.bottom = rect.top + height;
-
-        AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
-
-        hWnd = CreateWindowEx(dwExStyle,
-                              "glretrace", /* wc.lpszClassName */
-                              NULL,
-                              dwStyle,
-                              0, /* x */
-                              0, /* y */
-                              rect.right - rect.left, /* width */
-                              rect.bottom - rect.top, /* height */
-                              NULL,
-                              NULL,
-                              NULL,
-                              NULL);
-        hDC = GetDC(hWnd);
-   
-        memset(&pfd, 0, sizeof pfd);
-        pfd.cColorBits = 4;
-        pfd.cRedBits = 1;
-        pfd.cGreenBits = 1;
-        pfd.cBlueBits = 1;
-        pfd.cAlphaBits = 1;
-        pfd.cDepthBits = 1;
-        pfd.cStencilBits = 1;
-        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
-        pfd.iLayerType = PFD_MAIN_PLANE;
-        pfd.iPixelType = PFD_TYPE_RGBA;
-        pfd.nSize = sizeof(pfd);
-        pfd.nVersion = 1;
-
-        if (visual->doubleBuffer) {
-           pfd.dwFlags |= PFD_DOUBLEBUFFER;
-        }
-
-        iPixelFormat = pfnChoosePixelFormat(hDC, &pfd);
-        if (iPixelFormat <= 0) {
-            std::cerr << "error: ChoosePixelFormat failed\n";
-            exit(1);
-        }
-
-        bRet = pfnSetPixelFormat(hDC, iPixelFormat, &pfd);
-        if (!bRet) {
-            std::cerr << "error: SetPixelFormat failed\n";
-            exit(1);
-        }
-    }
-
-    ~WglDrawable() {
-        ReleaseDC(hWnd, hDC);
-        DestroyWindow(hWnd);
-    }
-    
-    void
-    resize(int w, int h) {
-        if (w == width && h == height) {
-            return;
-        }
-
-        RECT rClient, rWindow;
-        GetClientRect(hWnd, &rClient);
-        GetWindowRect(hWnd, &rWindow);
-        w += (rWindow.right  - rWindow.left) - rClient.right;
-        h += (rWindow.bottom - rWindow.top)  - rClient.bottom;
-        SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
-
-        Drawable::resize(w, h);
-    }
-
-    void show(void) {
-        if (visible) {
-            return;
-        }
-
-        ShowWindow(hWnd, SW_SHOW);
-
-        Drawable::show();
-    }
-
-    void swapBuffers(void) {
-        BOOL bRet;
-        bRet = pfnSwapBuffers(hDC);
-        if (!bRet) {
-            std::cerr << "warning: SwapBuffers failed\n";
-        }
-
-        // Drain message queue to prevent window from being considered
-        // non-responsive
-        MSG msg;
-        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-        }
-    }
-};
-
-
-class WglContext : public Context
-{
-public:
-    HGLRC hglrc;
-    WglContext *shareContext;
-
-    WglContext(const Visual *vis, Profile prof, WglContext *share) :
-        Context(vis, prof),
-        hglrc(0),
-        shareContext(share)
-    {}
-
-    ~WglContext() {
-        if (hglrc) {
-            wglDeleteContext(hglrc);
-        }
-    }
-};
-
-
-void
-init(void) {
-    /*
-     * OpenGL library must be loaded by the time we call GDI.
-     */
-
-    const char * libgl_filename = getenv("TRACE_LIBGL");
-
-    if (libgl_filename) {
-        pfnChoosePixelFormat = &wglChoosePixelFormat;
-        pfnSetPixelFormat = &wglSetPixelFormat;
-        pfnSwapBuffers = &wglSwapBuffers;
-    } else {
-        libgl_filename = "OPENGL32";
-    }
-
-    __libGlHandle = LoadLibraryA(libgl_filename);
-    if (!__libGlHandle) {
-        std::cerr << "error: unable to open " << libgl_filename << "\n";
-        exit(1);
-    }
-}
-
-void
-cleanup(void) {
-}
-
-Visual *
-createVisual(bool doubleBuffer, Profile profile) {
-    if (profile != PROFILE_COMPAT) {
-        return NULL;
-    }
-
-    Visual *visual = new Visual();
-
-    visual->doubleBuffer = doubleBuffer;
-
-    return visual;
-}
-
-Drawable *
-createDrawable(const Visual *visual, int width, int height)
-{
-    return new WglDrawable(visual, width, height);
-}
-
-Context *
-createContext(const Visual *visual, Context *shareContext, Profile profile)
-{
-    if (profile != PROFILE_COMPAT) {
-        return NULL;
-    }
-
-    return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
-}
-
-bool
-makeCurrent(Drawable *drawable, Context *context)
-{
-    if (!drawable || !context) {
-        return wglMakeCurrent(NULL, NULL);
-    } else {
-        WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
-        WglContext *wglContext = static_cast<WglContext *>(context);
-
-        if (!wglContext->hglrc) {
-            wglContext->hglrc = wglCreateContext(wglDrawable->hDC);
-            if (!wglContext->hglrc) {
-                std::cerr << "error: wglCreateContext failed\n";
-                exit(1);
-                return false;
-            }
-            if (wglContext->shareContext) {
-                BOOL bRet;
-                bRet = wglShareLists(wglContext->shareContext->hglrc,
-                                     wglContext->hglrc);
-                if (!bRet) {
-                    std::cerr << "warning: wglShareLists failed\n";
-                }
-            }
-        }
-
-        return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
-    }
-}
-
-bool
-processEvents(void) {
-    // TODO
-    return true;
-}
-
-
-} /* namespace glws */
diff --git a/retrace.cpp b/retrace.cpp
deleted file mode 100644 (file)
index 1630995..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <string.h>
-#include <iostream>
-
-#include "os_time.hpp"
-#include "trace_dump.hpp"
-#include "retrace.hpp"
-
-
-namespace retrace {
-
-
-trace::Parser parser;
-
-
-int verbosity = 0;
-bool profiling = false;
-
-
-static bool call_dumped = false;
-
-
-static void dumpCall(trace::Call &call) {
-    if (verbosity >= 0 && !call_dumped) {
-        std::cout << call;
-        std::cout.flush();
-        call_dumped = true;
-    }
-}
-
-
-std::ostream &warning(trace::Call &call) {
-    dumpCall(call);
-
-    std::cerr << call.no << ": ";
-    std::cerr << "warning: ";
-
-    return std::cerr;
-}
-
-
-void ignore(trace::Call &call) {
-    (void)call;
-}
-
-void unsupported(trace::Call &call) {
-    warning(call) << "unsupported " << call.name() << " call\n";
-}
-
-inline void Retracer::addCallback(const Entry *entry) {
-    assert(entry->name);
-    assert(entry->callback);
-    map[entry->name] = entry->callback;
-}
-
-
-void Retracer::addCallbacks(const Entry *entries) {
-    while (entries->name && entries->callback) {
-        addCallback(entries++);
-    }
-}
-
-
-void Retracer::retrace(trace::Call &call) {
-    call_dumped = false;
-
-    if (verbosity >= 1) {
-        if (verbosity >= 2 ||
-            !(call.flags & trace::CALL_FLAG_VERBOSE)) {
-            dumpCall(call);
-        }
-    }
-
-    Callback callback = 0;
-
-    trace::Id id = call.sig->id;
-    if (id >= callbacks.size()) {
-        callbacks.resize(id + 1);
-        callback = 0;
-    } else {
-        callback = callbacks[id];
-    }
-
-    if (!callback) {
-        Map::const_iterator it = map.find(call.name());
-        if (it == map.end()) {
-            callback = &unsupported;
-        } else {
-            callback = it->second;
-        }
-        callbacks[id] = callback;
-    }
-
-    assert(callback);
-    assert(callbacks[id] == callback);
-
-    if (retrace::profiling) {
-        long long startTime = os::getTime();
-        callback(call);
-        long long stopTime = os::getTime();
-        float timeInterval = (stopTime - startTime) * (1.0E6 / os::timeFrequency);
-
-        std::cout
-            << call.no << " "
-            << "[" << timeInterval << " usec] "
-        ;
-        trace::dump(call, std::cout, trace::DUMP_FLAG_NO_CALL_NO | trace::DUMP_FLAG_NO_COLOR);
-    } else {
-        callback(call);
-    }
-}
-
-
-} /* namespace retrace */
diff --git a/retrace.hpp b/retrace.hpp
deleted file mode 100644 (file)
index c1e556a..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011-2012 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-#ifndef _RETRACE_HPP_
-#define _RETRACE_HPP_
-
-#include <assert.h>
-#include <string.h>
-#include <stdint.h>
-
-#include <list>
-#include <map>
-#include <ostream>
-
-#include "trace_model.hpp"
-#include "trace_parser.hpp"
-
-
-namespace retrace {
-
-
-extern trace::Parser parser;
-
-
-/**
- * Handle map.
- *
- * It is just like a regular std::map<T, T> container, but lookups of missing
- * keys return the key instead of default constructor.
- *
- * This is necessary for several GL named objects, where one can either request
- * the implementation to generate an unique name, or pick a value never used
- * before.
- *
- * XXX: In some cases, instead of returning the key, it would make more sense
- * to return an unused data value (e.g., container count).
- */
-template <class T>
-class map
-{
-private:
-    typedef std::map<T, T> base_type;
-    base_type base;
-
-public:
-
-    T & operator[] (const T &key) {
-        typename base_type::iterator it;
-        it = base.find(key);
-        if (it == base.end()) {
-            return (base[key] = key);
-        }
-        return it->second;
-    }
-    
-    const T & operator[] (const T &key) const {
-        typename base_type::const_iterator it;
-        it = base.find(key);
-        if (it == base.end()) {
-            return (base[key] = key);
-        }
-        return it->second;
-    }
-};
-
-
-/**
- * Similar to alloca(), but implemented with malloc.
- */
-class ScopedAllocator
-{
-private:
-    uintptr_t next;
-
-public:
-    ScopedAllocator() :
-        next(0) {
-    }
-
-    inline void *
-    alloc(size_t size) {
-        if (!size) {
-            return NULL;
-        }
-
-        uintptr_t * buf = static_cast<uintptr_t *>(malloc(sizeof(uintptr_t) + size));
-        if (!buf) {
-            return NULL;
-        }
-
-        *buf = next;
-        next = reinterpret_cast<uintptr_t>(buf);
-        assert((next & 1) == 0);
-
-        return static_cast<void *>(&buf[1]);
-    }
-
-    template< class T >
-    inline T *
-    alloc(size_t n = 1) {
-        return static_cast<T *>(alloc(sizeof(T) * n));
-    }
-
-    /**
-     * Allocate an array with the same dimensions as the specified value.
-     */
-    template< class T >
-    inline T *
-    alloc(const trace::Value *value) {
-        const trace::Array *array = dynamic_cast<const trace::Array *>(value);
-        if (array) {
-            return alloc<T>(array->size());
-        }
-        const trace::Null *null = dynamic_cast<const trace::Null *>(value);
-        if (null) {
-            return NULL;
-        }
-        assert(0);
-        return NULL;
-    }
-
-    /**
-     * Prevent this pointer from being automatically freed.
-     */
-    template< class T >
-    inline void
-    bind(T *ptr) {
-        if (ptr) {
-            reinterpret_cast<uintptr_t *>(ptr)[-1] |= 1;
-        }
-    }
-
-    inline
-    ~ScopedAllocator() {
-        while (next) {
-            uintptr_t temp = *reinterpret_cast<uintptr_t *>(next);
-
-            bool bind = temp & 1;
-            temp &= ~1;
-
-            if (!bind) {
-                free(reinterpret_cast<void *>(next));
-            }
-
-            next = temp;
-        }
-    }
-};
-
-
-void
-addRegion(unsigned long long address, void *buffer, unsigned long long size);
-
-void
-delRegionByPointer(void *ptr);
-
-void *
-toPointer(trace::Value &value, bool bind = false);
-
-
-/**
- * Output verbosity when retracing files.
- */
-extern int verbosity;
-
-/**
- * Add profiling data to the dump when retracing.
- */
-extern bool profiling;
-
-
-std::ostream &warning(trace::Call &call);
-
-
-void ignore(trace::Call &call);
-void unsupported(trace::Call &call);
-
-
-typedef void (*Callback)(trace::Call &call);
-
-struct Entry {
-    const char *name;
-    Callback callback;
-};
-
-
-struct stringComparer {
-  bool operator() (const char *a, const  char *b) const {
-    return strcmp(a, b) < 0;
-  }
-};
-
-
-extern const Entry stdc_callbacks[];
-
-
-class Retracer
-{
-    typedef std::map<const char *, Callback, stringComparer> Map;
-    Map map;
-
-    std::vector<Callback> callbacks;
-
-public:
-    Retracer() {
-        addCallbacks(stdc_callbacks);
-    }
-
-    virtual ~Retracer() {}
-
-    void addCallback(const Entry *entry);
-    void addCallbacks(const Entry *entries);
-
-    void retrace(trace::Call &call);
-};
-
-
-} /* namespace retrace */
-
-#endif /* _RETRACE_HPP_ */
diff --git a/retrace.py b/retrace.py
deleted file mode 100644 (file)
index 9e9af20..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-##########################################################################
-#
-# Copyright 2010 VMware, Inc.
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-"""Generic retracing code generator."""
-
-
-import sys
-
-import specs.stdapi as stdapi
-import specs.glapi as glapi
-
-
-class UnsupportedType(Exception):
-    pass
-
-
-class MutableRebuilder(stdapi.Rebuilder):
-    '''Type visitor which derives a mutable type.'''
-
-    def visitConst(self, const):
-        # Strip out const qualifier
-        return const.type
-
-    def visitAlias(self, alias):
-        # Tear the alias on type changes
-        type = self.visit(alias.type)
-        if type is alias.type:
-            return alias
-        return type
-
-    def visitReference(self, reference):
-        # Strip out references
-        return reference.type
-
-
-def lookupHandle(handle, value):
-    if handle.key is None:
-        return "__%s_map[%s]" % (handle.name, value)
-    else:
-        key_name, key_type = handle.key
-        return "__%s_map[%s][%s]" % (handle.name, key_name, value)
-
-
-class ValueAllocator(stdapi.Visitor):
-
-    def visitLiteral(self, literal, lvalue, rvalue):
-        pass
-
-    def visitConst(self, const, lvalue, rvalue):
-        self.visit(const.type, lvalue, rvalue)
-
-    def visitAlias(self, alias, lvalue, rvalue):
-        self.visit(alias.type, lvalue, rvalue)
-
-    def visitEnum(self, enum, lvalue, rvalue):
-        pass
-
-    def visitBitmask(self, bitmask, lvalue, rvalue):
-        pass
-
-    def visitArray(self, array, lvalue, rvalue):
-        print '    %s = _allocator.alloc<%s>(&%s);' % (lvalue, array.type, rvalue)
-
-    def visitPointer(self, pointer, lvalue, rvalue):
-        print '    %s = _allocator.alloc<%s>(&%s);' % (lvalue, pointer.type, rvalue)
-
-    def visitIntPointer(self, pointer, lvalue, rvalue):
-        pass
-
-    def visitObjPointer(self, pointer, lvalue, rvalue):
-        pass
-
-    def visitLinearPointer(self, pointer, lvalue, rvalue):
-        pass
-
-    def visitReference(self, reference, lvalue, rvalue):
-        self.visit(reference.type, lvalue, rvalue);
-
-    def visitHandle(self, handle, lvalue, rvalue):
-        pass
-
-    def visitBlob(self, blob, lvalue, rvalue):
-        pass
-
-    def visitString(self, string, lvalue, rvalue):
-        pass
-
-    def visitStruct(self, struct, lvalue, rvalue):
-        pass
-
-    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
-        self.visit(polymorphic.defaultType, lvalue, rvalue)
-
-    def visitOpaque(self, opaque, lvalue, rvalue):
-        pass
-
-
-class ValueDeserializer(stdapi.Visitor):
-
-    def visitLiteral(self, literal, lvalue, rvalue):
-        print '    %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
-
-    def visitConst(self, const, lvalue, rvalue):
-        self.visit(const.type, lvalue, rvalue)
-
-    def visitAlias(self, alias, lvalue, rvalue):
-        self.visit(alias.type, lvalue, rvalue)
-    
-    def visitEnum(self, enum, lvalue, rvalue):
-        print '    %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
-
-    def visitBitmask(self, bitmask, lvalue, rvalue):
-        self.visit(bitmask.type, lvalue, rvalue)
-
-    def visitArray(self, array, lvalue, rvalue):
-
-        tmp = '__a_' + array.tag + '_' + str(self.seq)
-        self.seq += 1
-
-        print '    if (%s) {' % (lvalue,)
-        print '        const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
-        length = '%s->values.size()' % (tmp,)
-        index = '__j' + array.tag
-        print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
-        try:
-            self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
-        finally:
-            print '        }'
-            print '    }'
-    
-    def visitPointer(self, pointer, lvalue, rvalue):
-        tmp = '__a_' + pointer.tag + '_' + str(self.seq)
-        self.seq += 1
-
-        print '    if (%s) {' % (lvalue,)
-        print '        const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
-        try:
-            self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
-        finally:
-            print '    }'
-
-    def visitIntPointer(self, pointer, lvalue, rvalue):
-        print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
-
-    def visitObjPointer(self, pointer, lvalue, rvalue):
-        old_lvalue = '(%s).toUIntPtr()' % (rvalue,)
-        new_lvalue = '_obj_map[%s]' % (old_lvalue,)
-        print '    if (retrace::verbosity >= 2) {'
-        print '        std::cout << std::hex << "obj 0x" << size_t(%s) << " <- 0x" << size_t(%s) << std::dec <<"\\n";' % (old_lvalue, new_lvalue)
-        print '    }'
-        print '    %s = static_cast<%s>(%s);' % (lvalue, pointer, new_lvalue)
-
-    def visitLinearPointer(self, pointer, lvalue, rvalue):
-        print '    %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
-
-    def visitReference(self, reference, lvalue, rvalue):
-        self.visit(reference.type, lvalue, rvalue);
-
-    def visitHandle(self, handle, lvalue, rvalue):
-        #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
-        self.visit(handle.type, lvalue, rvalue);
-        new_lvalue = lookupHandle(handle, lvalue)
-        print '    if (retrace::verbosity >= 2) {'
-        print '        std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
-        print '    }'
-        print '    %s = %s;' % (lvalue, new_lvalue)
-    
-    def visitBlob(self, blob, lvalue, rvalue):
-        print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
-    
-    def visitString(self, string, lvalue, rvalue):
-        print '    %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
-
-    seq = 0
-
-    def visitStruct(self, struct, lvalue, rvalue):
-        tmp = '__s_' + struct.tag + '_' + str(self.seq)
-        self.seq += 1
-
-        print '    const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
-        print '    assert(%s);' % (tmp)
-        for i in range(len(struct.members)):
-            member_type, member_name = struct.members[i]
-            self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
-
-    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
-        self.visit(polymorphic.defaultType, lvalue, rvalue)
-    
-    def visitOpaque(self, opaque, lvalue, rvalue):
-        raise UnsupportedType
-
-
-class OpaqueValueDeserializer(ValueDeserializer):
-    '''Value extractor that also understands opaque values.
-
-    Normally opaque values can't be retraced, unless they are being extracted
-    in the context of handles.'''
-
-    def visitOpaque(self, opaque, lvalue, rvalue):
-        print '    %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
-
-
-class SwizzledValueRegistrator(stdapi.Visitor):
-    '''Type visitor which will register (un)swizzled value pairs, to later be
-    swizzled.'''
-
-    def visitLiteral(self, literal, lvalue, rvalue):
-        pass
-
-    def visitAlias(self, alias, lvalue, rvalue):
-        self.visit(alias.type, lvalue, rvalue)
-    
-    def visitEnum(self, enum, lvalue, rvalue):
-        pass
-
-    def visitBitmask(self, bitmask, lvalue, rvalue):
-        pass
-
-    def visitArray(self, array, lvalue, rvalue):
-        print '    const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
-        print '    if (__a%s) {' % (array.tag)
-        length = '__a%s->values.size()' % array.tag
-        index = '__j' + array.tag
-        print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
-        try:
-            self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
-        finally:
-            print '        }'
-            print '    }'
-    
-    def visitPointer(self, pointer, lvalue, rvalue):
-        print '    const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
-        print '    if (__a%s) {' % (pointer.tag)
-        try:
-            self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
-        finally:
-            print '    }'
-    
-    def visitIntPointer(self, pointer, lvalue, rvalue):
-        pass
-    
-    def visitObjPointer(self, pointer, lvalue, rvalue):
-        print r'    _obj_map[(%s).toUIntPtr()] = %s;' % (rvalue, lvalue)
-    
-    def visitLinearPointer(self, pointer, lvalue, rvalue):
-        assert pointer.size is not None
-        if pointer.size is not None:
-            print r'    retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
-
-    def visitReference(self, reference, lvalue, rvalue):
-        pass
-    
-    def visitHandle(self, handle, lvalue, rvalue):
-        print '    %s __orig_result;' % handle.type
-        OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
-        if handle.range is None:
-            rvalue = "__orig_result"
-            entry = lookupHandle(handle, rvalue) 
-            print "    %s = %s;" % (entry, lvalue)
-            print '    if (retrace::verbosity >= 2) {'
-            print '        std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
-            print '    }'
-        else:
-            i = '__h' + handle.tag
-            lvalue = "%s + %s" % (lvalue, i)
-            rvalue = "__orig_result + %s" % (i,)
-            entry = lookupHandle(handle, rvalue) 
-            print '    for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
-            print '        {entry} = {lvalue};'.format(**locals())
-            print '        if (retrace::verbosity >= 2) {'
-            print '            std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
-            print '        }'
-            print '    }'
-    
-    def visitBlob(self, blob, lvalue, rvalue):
-        pass
-    
-    def visitString(self, string, lvalue, rvalue):
-        pass
-
-    seq = 0
-
-    def visitStruct(self, struct, lvalue, rvalue):
-        tmp = '__s_' + struct.tag + '_' + str(self.seq)
-        self.seq += 1
-
-        print '    const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
-        print '    assert(%s);' % (tmp,)
-        print '    (void)%s;' % (tmp,)
-        for i in range(len(struct.members)):
-            member_type, member_name = struct.members[i]
-            self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
-    
-    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
-        self.visit(polymorphic.defaultType, lvalue, rvalue)
-    
-    def visitOpaque(self, opaque, lvalue, rvalue):
-        pass
-
-
-class Retracer:
-
-    def retraceFunction(self, function):
-        print 'static void retrace_%s(trace::Call &call) {' % function.name
-        self.retraceFunctionBody(function)
-        print '}'
-        print
-
-    def retraceInterfaceMethod(self, interface, method):
-        print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
-        self.retraceInterfaceMethodBody(interface, method)
-        print '}'
-        print
-
-    def retraceFunctionBody(self, function):
-        assert function.sideeffects
-
-        self.deserializeArgs(function)
-        
-        self.invokeFunction(function)
-
-        self.swizzleValues(function)
-
-    def retraceInterfaceMethodBody(self, interface, method):
-        assert method.sideeffects
-
-        self.deserializeThisPointer(interface)
-
-        self.deserializeArgs(method)
-        
-        self.invokeInterfaceMethod(interface, method)
-
-        self.swizzleValues(method)
-
-    def deserializeThisPointer(self, interface):
-        print r'    %s *_this;' % (interface.name,)
-        print r'    _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
-        print r'    if (!_this) {'
-        print r'        retrace::warning(call) << "NULL this pointer\n";'
-        print r'        return;'
-        print r'    }'
-
-    def deserializeArgs(self, function):
-        print '    retrace::ScopedAllocator _allocator;'
-        print '    (void)_allocator;'
-        success = True
-        for arg in function.args:
-            arg_type = MutableRebuilder().visit(arg.type)
-            print '    %s %s;' % (arg_type, arg.name)
-            rvalue = 'call.arg(%u)' % (arg.index,)
-            lvalue = arg.name
-            try:
-                self.extractArg(function, arg, arg_type, lvalue, rvalue)
-            except UnsupportedType:
-                success =  False
-                print '    memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
-            print
-
-        if not success:
-            print '    if (1) {'
-            self.failFunction(function)
-            if function.name[-1].islower():
-                sys.stderr.write('warning: unsupported %s call\n' % function.name)
-            print '    }'
-
-    def swizzleValues(self, function):
-        for arg in function.args:
-            if arg.output:
-                arg_type = MutableRebuilder().visit(arg.type)
-                rvalue = 'call.arg(%u)' % (arg.index,)
-                lvalue = arg.name
-                try:
-                    self.regiterSwizzledValue(arg_type, lvalue, rvalue)
-                except UnsupportedType:
-                    print '    // XXX: %s' % arg.name
-        if function.type is not stdapi.Void:
-            rvalue = '*call.ret'
-            lvalue = '__result'
-            try:
-                self.regiterSwizzledValue(function.type, lvalue, rvalue)
-            except UnsupportedType:
-                raise
-                print '    // XXX: result'
-
-    def failFunction(self, function):
-        print '    if (retrace::verbosity >= 0) {'
-        print '        retrace::unsupported(call);'
-        print '    }'
-        print '    return;'
-
-    def extractArg(self, function, arg, arg_type, lvalue, rvalue):
-        ValueAllocator().visit(arg_type, lvalue, rvalue)
-        if arg.input:
-            ValueDeserializer().visit(arg_type, lvalue, rvalue)
-    
-    def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
-        try:
-            ValueAllocator().visit(arg_type, lvalue, rvalue)
-        except UnsupportedType:
-            pass
-        OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
-
-    def regiterSwizzledValue(self, type, lvalue, rvalue):
-        visitor = SwizzledValueRegistrator()
-        visitor.visit(type, lvalue, rvalue)
-
-    def invokeFunction(self, function):
-        arg_names = ", ".join(function.argNames())
-        if function.type is not stdapi.Void:
-            print '    %s __result;' % (function.type)
-            print '    __result = %s(%s);' % (function.name, arg_names)
-            print '    (void)__result;'
-        else:
-            print '    %s(%s);' % (function.name, arg_names)
-
-    def invokeInterfaceMethod(self, interface, method):
-        arg_names = ", ".join(method.argNames())
-        if method.type is not stdapi.Void:
-            print '    %s __result;' % (method.type)
-            print '    __result = _this->%s(%s);' % (method.name, arg_names)
-            print '    (void)__result;'
-        else:
-            print '    _this->%s(%s);' % (method.name, arg_names)
-
-    def filterFunction(self, function):
-        return True
-
-    table_name = 'retrace::callbacks'
-
-    def retraceApi(self, api):
-
-        print '#include "os_time.hpp"'
-        print '#include "trace_parser.hpp"'
-        print '#include "retrace.hpp"'
-        print
-
-        types = api.getAllTypes()
-        handles = [type for type in types if isinstance(type, stdapi.Handle)]
-        handle_names = set()
-        for handle in handles:
-            if handle.name not in handle_names:
-                if handle.key is None:
-                    print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
-                else:
-                    key_name, key_type = handle.key
-                    print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
-                handle_names.add(handle.name)
-        print
-
-        print 'static std::map<unsigned long long, void *> _obj_map;'
-        print
-
-        functions = filter(self.filterFunction, api.functions)
-        for function in functions:
-            if function.sideeffects:
-                self.retraceFunction(function)
-        interfaces = api.getAllInterfaces()
-        for interface in interfaces:
-            for method in interface.iterMethods():
-                if method.sideeffects:
-                    self.retraceInterfaceMethod(interface, method)
-
-        print 'const retrace::Entry %s[] = {' % self.table_name
-        for function in functions:
-            if function.sideeffects:
-                print '    {"%s", &retrace_%s},' % (function.name, function.name)
-            else:
-                print '    {"%s", &retrace::ignore},' % (function.name,)
-        for interface in interfaces:
-            for method in interface.iterMethods():                
-                if method.sideeffects:
-                    print '    {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
-                else:
-                    print '    {"%s::%s", &retrace::ignore},' % (interface.name, method.name)
-        print '    {NULL, NULL}'
-        print '};'
-        print
-
diff --git a/retrace/.gitignore b/retrace/.gitignore
new file mode 100644 (file)
index 0000000..ebcad87
--- /dev/null
@@ -0,0 +1,2 @@
+glretrace_gl.cpp
+glstate_params.cpp
diff --git a/retrace/CMakeLists.txt b/retrace/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c45b33f
--- /dev/null
@@ -0,0 +1,146 @@
+##############################################################################
+# API retracers
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+add_definitions (-DRETRACE)
+
+add_custom_command (
+    OUTPUT glretrace_gl.cpp
+    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/glretrace_gl.cpp
+    DEPENDS
+                glretrace.py
+                retrace.py
+                ${CMAKE_SOURCE_DIR}/specs/glapi.py
+                ${CMAKE_SOURCE_DIR}/specs/gltypes.py
+                ${CMAKE_SOURCE_DIR}/specs/stdapi.py
+)
+
+add_custom_command (
+    OUTPUT glstate_params.cpp
+    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/glstate_params.py > ${CMAKE_CURRENT_BINARY_DIR}/glstate_params.cpp
+    DEPENDS
+                glstate_params.py
+                ${CMAKE_SOURCE_DIR}/specs/glparams.py
+                ${CMAKE_SOURCE_DIR}/specs/gltypes.py
+                ${CMAKE_SOURCE_DIR}/specs/stdapi.py
+)
+
+add_library (retrace_common
+    glretrace_gl.cpp
+    glretrace_cgl.cpp
+    glretrace_glx.cpp
+    glretrace_wgl.cpp
+    glretrace_egl.cpp
+    glretrace_main.cpp
+    glstate.cpp
+    glstate_images.cpp
+    glstate_params.cpp
+    glstate_shaders.cpp
+    retrace.cpp
+    retrace_stdc.cpp
+    glws.cpp
+)
+
+add_dependencies (retrace_common glproc)
+
+if (WIN32 OR APPLE OR X11_FOUND)
+    add_executable (glretrace
+        ${glws_os}
+        ${CMAKE_SOURCE_DIR}/glproc_gl.cpp
+    )
+
+    add_dependencies (glretrace glproc)
+
+    target_link_libraries (glretrace
+        retrace_common
+        common
+        ${PNG_LIBRARIES}
+        ${ZLIB_LIBRARIES}
+        ${SNAPPY_LIBRARIES}
+    )
+
+    if (WIN32)
+    else ()
+        if (APPLE)
+            target_link_libraries (glretrace
+                "-framework Cocoa"
+                "-framework ApplicationServices" # CGS*
+                #"-framework OpenGL" # CGL*
+            )
+        else ()
+            target_link_libraries (glretrace ${X11_X11_LIB})
+        endif ()
+
+        target_link_libraries (glretrace
+            # gdb doesn't like when pthreads is loaded through dlopen (which happens
+            # when dlopen'ing libGL), so link pthreads to avoid this issue.  See also
+            # http://stackoverflow.com/questions/2702628/gdb-cannot-find-new-threads-generic-error
+            ${CMAKE_THREAD_LIBS_INIT}
+            dl
+        )
+
+        if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+            target_link_libraries (glretrace rt)
+        endif ()
+
+    endif ()
+
+    install (TARGETS glretrace RUNTIME DESTINATION bin) 
+endif ()
+
+if (ENABLE_EGL AND X11_FOUND AND NOT WIN32 AND NOT APPLE)
+    add_executable (eglretrace
+        glws_egl_xlib.cpp
+        ${CMAKE_SOURCE_DIR}/glproc_egl.cpp
+    )
+
+    add_dependencies (eglretrace glproc)
+
+    target_link_libraries (eglretrace
+        retrace_common
+        common
+        ${PNG_LIBRARIES}
+        ${ZLIB_LIBRARIES}
+        ${SNAPPY_LIBRARIES}
+        ${X11_X11_LIB}
+        ${CMAKE_THREAD_LIBS_INIT}
+        dl
+    )
+
+    if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+        target_link_libraries (eglretrace rt)
+    endif ()
+
+    install (TARGETS eglretrace RUNTIME DESTINATION bin) 
+endif ()
+
+if (WIN32 AND DirectX_D3DX9_FOUND)
+    add_custom_command (
+        OUTPUT d3dretrace_d3d9.cpp
+        COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/d3dretrace.py > ${CMAKE_CURRENT_BINARY_DIR}/d3dretrace_d3d9.cpp
+        DEPENDS
+                d3dretrace.py
+                retrace.py
+                ${CMAKE_SOURCE_DIR}/specs/d3d9.py
+                ${CMAKE_SOURCE_DIR}/specs/d3d9types.py
+                ${CMAKE_SOURCE_DIR}/specs/d3d9caps.py
+                ${CMAKE_SOURCE_DIR}/specs/winapi.py
+                ${CMAKE_SOURCE_DIR}/specs/stdapi.py
+    )
+
+    include_directories (SYSTEM ${DirectX_D3DX9_INCLUDE_DIR})
+    add_executable (d3dretrace
+        retrace.cpp
+        retrace_stdc.cpp
+        d3dretrace_main.cpp
+        d3dretrace_d3d9.cpp
+    )
+    target_link_libraries (d3dretrace
+        common
+        ${ZLIB_LIBRARIES}
+        ${SNAPPY_LIBRARIES}
+        ${DirectX_D3D9_LIBRARY}
+    )
+endif ()
+
diff --git a/retrace/d3dretrace.hpp b/retrace/d3dretrace.hpp
new file mode 100644 (file)
index 0000000..cac94cc
--- /dev/null
@@ -0,0 +1,41 @@
+/**************************************************************************
+ *
+ * Copyright 2012 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _D3DRETRACE_HPP_
+#define _D3DRETRACE_HPP_
+
+#include "retrace.hpp"
+
+
+namespace d3dretrace {
+
+
+extern const retrace::Entry d3d9_callbacks[];
+
+
+} /* namespace d3dretrace */
+
+
+#endif /* _D3DRETRACE_HPP_ */
diff --git a/retrace/d3dretrace.py b/retrace/d3dretrace.py
new file mode 100644 (file)
index 0000000..f472a0a
--- /dev/null
@@ -0,0 +1,145 @@
+##########################################################################
+#
+# Copyright 2011 Jose Fonseca
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+"""GL retracer generator."""
+
+
+from retrace import Retracer
+import specs.stdapi as stdapi
+from specs.d3d9 import d3d9
+
+
+class D3DRetracer(Retracer):
+
+    table_name = 'd3dretrace::d3d9_callbacks'
+
+    def invokeInterfaceMethod(self, interface, method):
+        if interface.name == 'IDirect3D9' and method.name == 'CreateDevice':
+            print 'HWND hWnd = createWindow(pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);'
+            print 'pPresentationParameters->hDeviceWindow = hWnd;'
+            print 'hFocusWindow = hWnd;'
+
+        Retracer.invokeInterfaceMethod(self, interface, method)
+
+        if str(method.type) == 'HRESULT':
+            print r'    if (__result != S_OK) {'
+            print r'        retrace::warning(call) << "failed\n";'
+            print r'    }'
+
+        if interface.name == 'IDirect3DVertexBuffer9' and method.name == 'Lock':
+            print '        if (!SizeToLock) {'
+            print '            D3DVERTEXBUFFER_DESC Desc;'
+            print '            _this->GetDesc(&Desc);'
+            print '            SizeToLock = Desc.Size;'
+            print '        }'
+
+
+if __name__ == '__main__':
+    print r'''
+#include <string.h>
+
+#include <iostream>
+
+#include "d3d9imports.hpp"
+#include "d3dretrace.hpp"
+
+
+// XXX: Don't duplicate this code.
+
+static LRESULT CALLBACK
+WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    MINMAXINFO *pMMI;
+    switch (uMsg) {
+    case WM_GETMINMAXINFO:
+        // Allow to create a window bigger than the desktop
+        pMMI = (MINMAXINFO *)lParam;
+        pMMI->ptMaxSize.x = 60000;
+        pMMI->ptMaxSize.y = 60000;
+        pMMI->ptMaxTrackSize.x = 60000;
+        pMMI->ptMaxTrackSize.y = 60000;
+        break;
+    default:
+        break;
+    }
+
+    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+static HWND
+createWindow(int width, int height) {
+    static bool first = TRUE;
+    RECT rect;
+
+    if (first) {
+        WNDCLASS wc;
+        memset(&wc, 0, sizeof wc);
+        wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+        wc.lpfnWndProc = WndProc;
+        wc.lpszClassName = "d3dretrace";
+        wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+        RegisterClass(&wc);
+        first = FALSE;
+    }
+
+    DWORD dwExStyle;
+    DWORD dwStyle;
+    HWND hWnd;
+
+    dwExStyle = 0;
+    dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
+
+    int x = 0, y = 0;
+
+    rect.left = x;
+    rect.top = y;
+    rect.right = rect.left + width;
+    rect.bottom = rect.top + height;
+
+    AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
+
+    hWnd = CreateWindowEx(dwExStyle,
+                          "d3dretrace", /* wc.lpszClassName */
+                          NULL,
+                          dwStyle,
+                          0, /* x */
+                          0, /* y */
+                          rect.right - rect.left, /* width */
+                          rect.bottom - rect.top, /* height */
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL);
+    ShowWindow(hWnd, SW_SHOW);
+    return hWnd;
+}
+
+'''
+    retracer = D3DRetracer()
+    retracer.retraceApi(d3d9)
diff --git a/retrace/d3dretrace_main.cpp b/retrace/d3dretrace_main.cpp
new file mode 100644 (file)
index 0000000..133f3a7
--- /dev/null
@@ -0,0 +1,103 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include "os_string.hpp"
+#include "retrace.hpp"
+#include "d3dretrace.hpp"
+
+
+namespace d3dretrace {
+
+static void display(void) {
+    retrace::Retracer retracer;
+
+    retracer.addCallbacks(d3d9_callbacks);
+
+    trace::Call *call;
+
+    while ((call = retrace::parser.parse_call())) {
+        retracer.retrace(*call);
+
+        delete call;
+    }
+
+    exit(0);
+}
+
+
+static void usage(void) {
+    std::cout << 
+        "Usage: d3dretrace [OPTION] TRACE\n"
+        "Replay TRACE.\n"
+        "\n"
+        "  -v           increase output verbosity\n"
+    ;
+}
+
+
+extern "C"
+int main(int argc, char **argv)
+{
+
+    int i;
+    for (i = 1; i < argc; ++i) {
+        const char *arg = argv[i];
+
+        if (arg[0] != '-') {
+            break;
+        }
+
+        if (!strcmp(arg, "--")) {
+            break;
+        } else if (!strcmp(arg, "--help")) {
+            usage();
+            return 0;
+        } else if (!strcmp(arg, "-v")) {
+            ++retrace::verbosity;
+        } else {
+            std::cerr << "error: unknown option " << arg << "\n";
+            usage();
+            return 1;
+        }
+    }
+
+    for ( ; i < argc; ++i) {
+        if (!retrace::parser.open(argv[i])) {
+            std::cerr << "error: failed to open " << argv[i] << "\n";
+            return 1;
+        }
+
+        display();
+
+        retrace::parser.close();
+    }
+
+    return 0;
+}
+
+} /* namespace glretrace */
diff --git a/retrace/glretrace.hpp b/retrace/glretrace.hpp
new file mode 100644 (file)
index 0000000..8ba2a80
--- /dev/null
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _GLRETRACE_HPP_
+#define _GLRETRACE_HPP_
+
+#include "glws.hpp"
+#include "retrace.hpp"
+
+
+namespace glretrace {
+
+
+extern bool double_buffer;
+extern bool insideGlBeginEnd;
+extern glws::Profile defaultProfile;
+extern glws::Visual *visual[glws::PROFILE_MAX];
+extern glws::Drawable *drawable;
+extern glws::Context *context;
+
+extern unsigned frame;
+extern long long startTime;
+extern bool wait;
+
+extern bool benchmark;
+
+extern unsigned dump_state;
+
+void
+checkGlError(trace::Call &call);
+
+extern const retrace::Entry gl_callbacks[];
+extern const retrace::Entry cgl_callbacks[];
+extern const retrace::Entry glx_callbacks[];
+extern const retrace::Entry wgl_callbacks[];
+extern const retrace::Entry egl_callbacks[];
+
+void frame_complete(trace::Call &call);
+
+void updateDrawable(int width, int height);
+
+} /* namespace glretrace */
+
+
+#endif /* _GLRETRACE_HPP_ */
diff --git a/retrace/glretrace.py b/retrace/glretrace.py
new file mode 100644 (file)
index 0000000..21fc499
--- /dev/null
@@ -0,0 +1,438 @@
+##########################################################################
+#
+# Copyright 2010 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+"""GL retracer generator."""
+
+
+from retrace import Retracer
+import specs.stdapi as stdapi
+import specs.glapi as glapi
+import specs.glesapi as glesapi
+
+
+class GlRetracer(Retracer):
+
+    table_name = 'glretrace::gl_callbacks'
+
+    def retraceFunction(self, function):
+        Retracer.retraceFunction(self, function)
+
+    array_pointer_function_names = set((
+        "glVertexPointer",
+        "glNormalPointer",
+        "glColorPointer",
+        "glIndexPointer",
+        "glTexCoordPointer",
+        "glEdgeFlagPointer",
+        "glFogCoordPointer",
+        "glSecondaryColorPointer",
+
+        "glInterleavedArrays",
+
+        "glVertexPointerEXT",
+        "glNormalPointerEXT",
+        "glColorPointerEXT",
+        "glIndexPointerEXT",
+        "glTexCoordPointerEXT",
+        "glEdgeFlagPointerEXT",
+        "glFogCoordPointerEXT",
+        "glSecondaryColorPointerEXT",
+
+        "glVertexAttribPointer",
+        "glVertexAttribPointerARB",
+        "glVertexAttribPointerNV",
+        "glVertexAttribIPointer",
+        "glVertexAttribIPointerEXT",
+        "glVertexAttribLPointer",
+        "glVertexAttribLPointerEXT",
+        
+        #"glMatrixIndexPointerARB",
+    ))
+
+    draw_array_function_names = set([
+        "glDrawArrays",
+        "glDrawArraysEXT",
+        "glDrawArraysIndirect",
+        "glDrawArraysInstanced",
+        "glDrawArraysInstancedARB",
+        "glDrawArraysInstancedEXT",
+        "glDrawArraysInstancedBaseInstance",
+        "glDrawMeshArraysSUN",
+        "glMultiDrawArrays",
+        "glMultiDrawArraysEXT",
+        "glMultiModeDrawArraysIBM",
+    ])
+
+    draw_elements_function_names = set([
+        "glDrawElements",
+        "glDrawElementsBaseVertex",
+        "glDrawElementsIndirect",
+        "glDrawElementsInstanced",
+        "glDrawElementsInstancedARB",
+        "glDrawElementsInstancedEXT",
+        "glDrawElementsInstancedBaseVertex",
+        "glDrawElementsInstancedBaseInstance",
+        "glDrawElementsInstancedBaseVertexBaseInstance",
+        "glDrawRangeElements",
+        "glDrawRangeElementsEXT",
+        "glDrawRangeElementsBaseVertex",
+        "glMultiDrawElements",
+        "glMultiDrawElementsBaseVertex",
+        "glMultiDrawElementsEXT",
+        "glMultiModeDrawElementsIBM",
+    ])
+
+    draw_indirect_function_names = set([
+        "glDrawArraysIndirect",
+        "glDrawElementsIndirect",
+    ])
+
+    misc_draw_function_names = set([
+        "glCallList",
+        "glCallLists",
+        "glClear",
+        "glEnd",
+        "glDrawPixels",
+        "glBlitFramebuffer",
+        "glBlitFramebufferEXT",
+    ])
+
+    bind_framebuffer_function_names = set([
+        "glBindFramebuffer",
+        "glBindFramebufferEXT",
+        "glBindFramebufferOES",
+    ])
+
+    # Names of the functions that can pack into the current pixel buffer
+    # object.  See also the ARB_pixel_buffer_object specification.
+    pack_function_names = set([
+        'glGetCompressedTexImage',
+        'glGetConvolutionFilter',
+        'glGetHistogram',
+        'glGetMinmax',
+        'glGetPixelMapfv',
+        'glGetPixelMapuiv',
+        'glGetPixelMapusv',
+        'glGetPolygonStipple',
+        'glGetSeparableFilter',
+        'glGetTexImage',
+        'glReadPixels',
+        'glGetnCompressedTexImageARB',
+        'glGetnConvolutionFilterARB',
+        'glGetnHistogramARB',
+        'glGetnMinmaxARB',
+        'glGetnPixelMapfvARB',
+        'glGetnPixelMapuivARB',
+        'glGetnPixelMapusvARB',
+        'glGetnPolygonStippleARB',
+        'glGetnSeparableFilterARB',
+        'glGetnTexImageARB',
+        'glReadnPixelsARB',
+    ])
+
+    map_function_names = set([
+        'glMapBuffer',
+        'glMapBufferARB',
+        'glMapBufferOES',
+        'glMapBufferRange',
+        'glMapNamedBufferEXT',
+        'glMapNamedBufferRangeEXT',
+        'glMapObjectBufferATI',
+    ])
+
+    unmap_function_names = set([
+        'glUnmapBuffer',
+        'glUnmapBufferARB',
+        'glUnmapBufferOES',
+        'glUnmapNamedBufferEXT',
+        'glUnmapObjectBufferATI',
+    ])
+
+    def retraceFunctionBody(self, function):
+        is_array_pointer = function.name in self.array_pointer_function_names
+        is_draw_array = function.name in self.draw_array_function_names
+        is_draw_elements = function.name in self.draw_elements_function_names
+        is_misc_draw = function.name in self.misc_draw_function_names
+
+        if is_array_pointer or is_draw_array or is_draw_elements:
+            print '    if (retrace::parser.version < 1) {'
+
+            if is_array_pointer or is_draw_array:
+                print '        GLint __array_buffer = 0;'
+                print '        glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
+                print '        if (!__array_buffer) {'
+                self.failFunction(function)
+                print '        }'
+
+            if is_draw_elements:
+                print '        GLint __element_array_buffer = 0;'
+                print '        glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &__element_array_buffer);'
+                print '        if (!__element_array_buffer) {'
+                self.failFunction(function)
+                print '        }'
+            
+            print '    }'
+
+        # When no pack buffer object is bound, the pack functions are no-ops.
+        if function.name in self.pack_function_names:
+            print '    GLint __pack_buffer = 0;'
+            print '    glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &__pack_buffer);'
+            print '    if (!__pack_buffer) {'
+            print '        return;'
+            print '    }'
+
+        # Pre-snapshots
+        if function.name in self.bind_framebuffer_function_names:
+            print '    assert(call.flags & trace::CALL_FLAG_SWAP_RENDERTARGET);'
+        if function.name == 'glFrameTerminatorGREMEDY':
+            print '    glretrace::frame_complete(call);'
+            return
+
+        Retracer.retraceFunctionBody(self, function)
+
+        # Post-snapshots
+        if function.name in ('glFlush', 'glFinish'):
+            print '    if (!glretrace::double_buffer) {'
+            print '        glretrace::frame_complete(call);'
+            print '    }'
+        if is_draw_array or is_draw_elements or is_misc_draw:
+            print '    assert(call.flags & trace::CALL_FLAG_RENDER);'
+
+
+    def invokeFunction(self, function):
+        # Infer the drawable size from GL calls
+        if function.name == "glViewport":
+            print '    glretrace::updateDrawable(x + width, y + height);'
+        if function.name == "glViewportArray":
+            # We are concerned about drawables so only care for the first viewport
+            print '    if (first == 0 && count > 0) {'
+            print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
+            print '        glretrace::updateDrawable(x + w, y + h);'
+            print '    }'
+        if function.name == "glViewportIndexedf":
+            print '    if (index == 0) {'
+            print '        glretrace::updateDrawable(x + w, y + h);'
+            print '    }'
+        if function.name == "glViewportIndexedfv":
+            print '    if (index == 0) {'
+            print '        GLfloat x = v[0], y = v[1], w = v[2], h = v[3];'
+            print '        glretrace::updateDrawable(x + w, y + h);'
+            print '    }'
+        if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'):
+            # Some applications do all their rendering in a framebuffer, and
+            # then just blit to the drawable without ever calling glViewport.
+            print '    glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));'
+
+        if function.name == "glEnd":
+            print '    glretrace::insideGlBeginEnd = false;'
+
+        if function.name.startswith('gl') and not function.name.startswith('glX'):
+            print r'    if (!glretrace::context && !glretrace::benchmark && !retrace::profiling) {'
+            print r'        retrace::warning(call) << "no current context\n";'
+            print r'    }'
+
+        if function.name == 'memcpy':
+            print '    if (!dest || !src || !n) return;'
+
+        # Destroy the buffer mapping
+        if function.name in self.unmap_function_names:
+            print r'        GLvoid *ptr = NULL;'
+            if function.name == 'glUnmapBuffer':
+                print r'            glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);'
+            elif function.name == 'glUnmapBufferARB':
+                print r'            glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);'
+            elif function.name == 'glUnmapBufferOES':
+                print r'            glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);'
+            elif function.name == 'glUnmapNamedBufferEXT':
+                print r'            glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);'
+            elif function.name == 'glUnmapObjectBufferATI':
+                # TODO
+                pass
+            else:
+                assert False
+            print r'        if (ptr) {'
+            print r'            retrace::delRegionByPointer(ptr);'
+            print r'        } else {'
+            print r'            retrace::warning(call) << "no current context\n";'
+            print r'        }'
+        
+        Retracer.invokeFunction(self, function)
+
+        # Error checking
+        if function.name == "glBegin":
+            print '    glretrace::insideGlBeginEnd = true;'
+        elif function.name.startswith('gl'):
+            # glGetError is not allowed inside glBegin/glEnd
+            print '    if (!glretrace::benchmark && !retrace::profiling && !glretrace::insideGlBeginEnd) {'
+            print '        glretrace::checkGlError(call);'
+            if function.name in ('glProgramStringARB', 'glProgramStringNV'):
+                print r'        GLint error_position = -1;'
+                print r'        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);'
+                print r'        if (error_position != -1) {'
+                print r'            const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);'
+                print r'            retrace::warning(call) << error_string << "\n";'
+                print r'        }'
+            if function.name == 'glCompileShader':
+                print r'        GLint compile_status = 0;'
+                print r'        glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);'
+                print r'        if (!compile_status) {'
+                print r'             GLint info_log_length = 0;'
+                print r'             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);'
+                print r'             GLchar *infoLog = new GLchar[info_log_length];'
+                print r'             glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);'
+                print r'             retrace::warning(call) << infoLog << "\n";'
+                print r'             delete [] infoLog;'
+                print r'        }'
+            if function.name == 'glLinkProgram':
+                print r'        GLint link_status = 0;'
+                print r'        glGetProgramiv(program, GL_LINK_STATUS, &link_status);'
+                print r'        if (!link_status) {'
+                print r'             GLint info_log_length = 0;'
+                print r'             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);'
+                print r'             GLchar *infoLog = new GLchar[info_log_length];'
+                print r'             glGetProgramInfoLog(program, info_log_length, NULL, infoLog);'
+                print r'             retrace::warning(call) << infoLog << "\n";'
+                print r'             delete [] infoLog;'
+                print r'        }'
+            if function.name == 'glCompileShaderARB':
+                print r'        GLint compile_status = 0;'
+                print r'        glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);'
+                print r'        if (!compile_status) {'
+                print r'             GLint info_log_length = 0;'
+                print r'             glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
+                print r'             GLchar *infoLog = new GLchar[info_log_length];'
+                print r'             glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);'
+                print r'             retrace::warning(call) << infoLog << "\n";'
+                print r'             delete [] infoLog;'
+                print r'        }'
+            if function.name == 'glLinkProgramARB':
+                print r'        GLint link_status = 0;'
+                print r'        glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);'
+                print r'        if (!link_status) {'
+                print r'             GLint info_log_length = 0;'
+                print r'             glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);'
+                print r'             GLchar *infoLog = new GLchar[info_log_length];'
+                print r'             glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);'
+                print r'             retrace::warning(call) << infoLog << "\n";'
+                print r'             delete [] infoLog;'
+                print r'        }'
+            if function.name in self.map_function_names:
+                print r'        if (!__result) {'
+                print r'             retrace::warning(call) << "failed to map buffer\n";'
+                print r'        }'
+            if function.name in self.unmap_function_names and function.type is not stdapi.Void:
+                print r'        if (!__result) {'
+                print r'             retrace::warning(call) << "failed to unmap buffer\n";'
+                print r'        }'
+            if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'):
+                print r'    GLint __orig_result = call.ret->toSInt();'
+                print r'    if (__result != __orig_result) {'
+                print r'        retrace::warning(call) << "vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";'
+                print r'    }'
+            if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'):
+                print r'    GLint __orig_result = call.ret->toSInt();'
+                print r'    if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&'
+                print r'        __result != GL_FRAMEBUFFER_COMPLETE) {'
+                print r'        retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";'
+                print r'    }'
+            print '    }'
+
+        # Query the buffer length for whole buffer mappings
+        if function.name in self.map_function_names:
+            if 'length' in function.argNames():
+                assert 'BufferRange' in function.name
+            else:
+                assert 'BufferRange' not in function.name
+                print r'    GLint length = 0;'
+                if function.name in ('glMapBuffer', 'glMapBufferOES'):
+                    print r'    glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);'
+                elif function.name == 'glMapBufferARB':
+                    print r'    glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);'
+                elif function.name == 'glMapNamedBufferEXT':
+                    print r'    glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);'
+                elif function.name == 'glMapObjectBufferATI':
+                    print r'    glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);'
+                else:
+                    assert False
+
+    def extractArg(self, function, arg, arg_type, lvalue, rvalue):
+        if function.name in self.array_pointer_function_names and arg.name == 'pointer':
+            print '    %s = static_cast<%s>(retrace::toPointer(%s, true));' % (lvalue, arg_type, rvalue)
+            return
+
+        if function.name in self.draw_elements_function_names and arg.name == 'indices' or\
+           function.name in self.draw_indirect_function_names and arg.name == 'indirect':
+            self.extractOpaqueArg(function, arg, arg_type, lvalue, rvalue)
+            return
+
+        # Handle pointer with offsets into the current pack pixel buffer
+        # object.
+        if function.name in self.pack_function_names and arg.output:
+            assert isinstance(arg_type, (stdapi.Pointer, stdapi.Array, stdapi.Blob, stdapi.Opaque))
+            print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, arg_type, rvalue)
+            return
+
+        if arg.type is glapi.GLlocation \
+           and 'program' not in function.argNames():
+            print '    GLint program = -1;'
+            print '    glGetIntegerv(GL_CURRENT_PROGRAM, &program);'
+        
+        if arg.type is glapi.GLlocationARB \
+           and 'programObj' not in function.argNames():
+            print '    GLhandleARB programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);'
+
+        Retracer.extractArg(self, function, arg, arg_type, lvalue, rvalue)
+
+        # Don't try to use more samples than the implementation supports
+        if arg.name == 'samples':
+            assert arg.type is glapi.GLsizei
+            print '    GLint max_samples = 0;'
+            print '    glGetIntegerv(GL_MAX_SAMPLES, &max_samples);'
+            print '    if (samples > max_samples) {'
+            print '        samples = max_samples;'
+            print '    }'
+
+        # These parameters are referred beyond the call life-time
+        # TODO: Replace ad-hoc solution for bindable parameters with general one
+        if function.name in ('glFeedbackBuffer', 'glSelectBuffer') and arg.output:
+            print '    _allocator.bind(%s);' % arg.name
+
+
+
+if __name__ == '__main__':
+    print r'''
+#include <string.h>
+
+#include "glproc.hpp"
+#include "glretrace.hpp"
+#include "glstate.hpp"
+
+
+'''
+    api = glapi.glapi
+    api.addApi(glesapi.glesapi)
+    retracer = GlRetracer()
+    retracer.retraceApi(api)
diff --git a/retrace/glretrace_cgl.cpp b/retrace/glretrace_cgl.cpp
new file mode 100644 (file)
index 0000000..63b94b4
--- /dev/null
@@ -0,0 +1,125 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include "glproc.hpp"
+#include "retrace.hpp"
+#include "glretrace.hpp"
+
+
+using namespace glretrace;
+
+
+typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
+typedef std::map<unsigned long long, glws::Context *> ContextMap;
+static DrawableMap drawable_map;
+static ContextMap context_map;
+static glws::Context *sharedContext = NULL;
+
+
+static glws::Drawable *
+getDrawable(unsigned long drawable_id) {
+    if (drawable_id == 0) {
+        return NULL;
+    }
+
+    /* XXX: Support multiple drawables. */
+    drawable_id = 1;
+
+    DrawableMap::const_iterator it;
+    it = drawable_map.find(drawable_id);
+    if (it == drawable_map.end()) {
+        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
+    }
+
+    return it->second;
+}
+
+
+static glws::Context *
+getContext(unsigned long long ctx) {
+    if (ctx == 0) {
+        return NULL;
+    }
+
+    ContextMap::const_iterator it;
+    it = context_map.find(ctx);
+    if (it == context_map.end()) {
+        glws::Context *context;
+        context_map[ctx] = context = glws::createContext(visual[glretrace::defaultProfile], sharedContext, glretrace::defaultProfile);
+        if (!sharedContext) {
+            sharedContext = context;
+        }
+        return context;
+    }
+
+    return it->second;
+}
+
+
+static void retrace_CGLSetCurrentContext(trace::Call &call) {
+    unsigned long long ctx = call.arg(0).toUIntPtr();
+
+    glws::Drawable *new_drawable = getDrawable(ctx);
+    glws::Context *new_context = getContext(ctx);
+
+    bool result = glws::makeCurrent(new_drawable, new_context);
+
+    if (new_drawable && new_context && result) {
+        drawable = new_drawable;
+        context = new_context;
+    } else {
+        drawable = NULL;
+        context = NULL;
+    }
+}
+
+
+static void retrace_CGLFlushDrawable(trace::Call &call) {
+    if (drawable && context) {
+        if (double_buffer) {
+            drawable->swapBuffers();
+        } else {
+            glFlush();
+        }
+
+        frame_complete(call);
+    }
+}
+
+
+const retrace::Entry glretrace::cgl_callbacks[] = {
+    {"CGLSetCurrentContext", &retrace_CGLSetCurrentContext},
+    {"CGLGetCurrentContext", &retrace::ignore},
+    {"CGLEnable", &retrace::ignore},
+    {"CGLDisable", &retrace::ignore},
+    {"CGLSetParameter", &retrace::ignore},
+    {"CGLGetParameter", &retrace::ignore},
+    {"CGLFlushDrawable", &retrace_CGLFlushDrawable},
+    {NULL, NULL},
+};
+
diff --git a/retrace/glretrace_egl.cpp b/retrace/glretrace_egl.cpp
new file mode 100644 (file)
index 0000000..d7b14ec
--- /dev/null
@@ -0,0 +1,284 @@
+/**************************************************************************
+ *
+ * Copyright 2011 LunarG, Inc.
+ * All Rights Reserved.
+ *
+ * Based on glretrace_glx.cpp, which has
+ *
+ *   Copyright 2011 Jose Fonseca
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glproc.hpp"
+#include "retrace.hpp"
+#include "glretrace.hpp"
+#include "os.hpp"
+
+#ifndef EGL_OPENGL_ES_API
+#define EGL_OPENGL_ES_API              0x30A0
+#define EGL_OPENVG_API                 0x30A1
+#define EGL_OPENGL_API                 0x30A2
+#define EGL_CONTEXT_CLIENT_VERSION     0x3098
+#endif
+
+
+using namespace glretrace;
+
+
+typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
+typedef std::map<unsigned long long, glws::Context *> ContextMap;
+typedef std::map<unsigned long long, glws::Profile> ProfileMap;
+static DrawableMap drawable_map;
+static ContextMap context_map;
+static ProfileMap profile_map;
+
+static unsigned int current_api = EGL_OPENGL_ES_API;
+static glws::Profile last_profile = glws::PROFILE_COMPAT;
+
+static void
+createDrawable(unsigned long long orig_config, unsigned long long orig_surface);
+
+static glws::Drawable *
+getDrawable(unsigned long long surface_ptr) {
+    if (surface_ptr == 0) {
+        return NULL;
+    }
+
+    DrawableMap::const_iterator it;
+    it = drawable_map.find(surface_ptr);
+    if (it == drawable_map.end()) {
+        // In Fennec we get the egl window surface from Java which isn't
+        // traced, so just create a drawable if it doesn't exist in here
+        createDrawable(0, surface_ptr);
+        it = drawable_map.find(surface_ptr);
+        assert(it != drawable_map.end());
+    }
+
+    return (it != drawable_map.end()) ? it->second : NULL;
+}
+
+static glws::Context *
+getContext(unsigned long long context_ptr) {
+    if (context_ptr == 0) {
+        return NULL;
+    }
+
+    ContextMap::const_iterator it;
+    it = context_map.find(context_ptr);
+
+    return (it != context_map.end()) ? it->second : NULL;
+}
+
+static void createDrawable(unsigned long long orig_config, unsigned long long orig_surface)
+{
+    ProfileMap::iterator it = profile_map.find(orig_config);
+    glws::Profile profile;
+
+    // If the requested config is associated with a profile, use that
+    // profile. Otherwise, assume that the last used profile is what
+    // the user wants.
+    if (it != profile_map.end()) {
+        profile = it->second;
+    } else {
+        profile = last_profile;
+    }
+
+    glws::Visual *visual = glretrace::visual[profile];
+
+    glws::Drawable *drawable = glws::createDrawable(visual);
+    drawable_map[orig_surface] = drawable;
+}
+
+static void retrace_eglCreateWindowSurface(trace::Call &call) {
+    unsigned long long orig_config = call.arg(1).toUIntPtr();
+    unsigned long long orig_surface = call.ret->toUIntPtr();
+    createDrawable(orig_config, orig_surface);
+}
+
+static void retrace_eglCreatePbufferSurface(trace::Call &call) {
+    unsigned long long orig_config = call.arg(1).toUIntPtr();
+    unsigned long long orig_surface = call.ret->toUIntPtr();
+    createDrawable(orig_config, orig_surface);
+    // TODO: Respect the pbuffer dimensions too
+}
+
+static void retrace_eglDestroySurface(trace::Call &call) {
+    unsigned long long orig_surface = call.arg(1).toUIntPtr();
+
+    DrawableMap::iterator it;
+    it = drawable_map.find(orig_surface);
+
+    if (it != drawable_map.end()) {
+        if (it->second != drawable) {
+            // TODO: reference count
+            delete it->second;
+        }
+        drawable_map.erase(it);
+    }
+}
+
+static void retrace_eglBindAPI(trace::Call &call) {
+    current_api = call.arg(0).toUInt();
+}
+
+static void retrace_eglCreateContext(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    unsigned long long orig_config = call.arg(1).toUIntPtr();
+    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
+    trace::Array *attrib_array = dynamic_cast<trace::Array *>(&call.arg(3));
+    glws::Profile profile;
+
+    switch (current_api) {
+    case EGL_OPENGL_API:
+        profile = glws::PROFILE_COMPAT;
+        break;
+    case EGL_OPENGL_ES_API:
+    default:
+        profile = glws::PROFILE_ES1;
+        if (attrib_array) {
+            for (int i = 0; i < attrib_array->values.size(); i += 2) {
+                int v = attrib_array->values[i]->toSInt();
+                if (v == EGL_CONTEXT_CLIENT_VERSION) {
+                    v = attrib_array->values[i + 1]->toSInt();
+                    if (v == 2)
+                        profile = glws::PROFILE_ES2;
+                    break;
+                }
+            }
+        }
+        break;
+    }
+
+
+    glws::Context *context = glws::createContext(glretrace::visual[profile], share_context, profile);
+    if (!context) {
+        const char *name;
+        switch (profile) {
+        case glws::PROFILE_COMPAT:
+            name = "OpenGL";
+            break;
+        case glws::PROFILE_ES1:
+            name = "OpenGL ES 1.1";
+            break;
+        case glws::PROFILE_ES2:
+            name = "OpenGL ES 2.0";
+            break;
+        default:
+            name = "unknown";
+            break;
+        }
+
+        retrace::warning(call) << "Failed to create " << name << " context.\n";
+        os::abort();
+    }
+
+    context_map[orig_context] = context;
+    profile_map[orig_config] = profile;
+    last_profile = profile;
+}
+
+static void retrace_eglDestroyContext(trace::Call &call) {
+    unsigned long long orig_context = call.arg(1).toUIntPtr();
+
+    ContextMap::iterator it;
+    it = context_map.find(orig_context);
+
+    if (it != context_map.end()) {
+        delete it->second;
+        context_map.erase(it);
+    }
+}
+
+static void retrace_eglMakeCurrent(trace::Call &call) {
+    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUIntPtr());
+    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());
+
+    if (new_drawable == drawable && new_context == context) {
+        return;
+    }
+
+    if (drawable && context) {
+        glFlush();
+        if (!double_buffer) {
+            frame_complete(call);
+        }
+    }
+
+    bool result = glws::makeCurrent(new_drawable, new_context);
+
+    if (new_drawable && new_context && result) {
+        drawable = new_drawable;
+        context = new_context;
+    } else {
+        drawable = NULL;
+        context = NULL;
+    }
+}
+
+
+static void retrace_eglSwapBuffers(trace::Call &call) {
+    frame_complete(call);
+
+    if (double_buffer && drawable) {
+        drawable->swapBuffers();
+    } else {
+        glFlush();
+    }
+}
+
+const retrace::Entry glretrace::egl_callbacks[] = {
+    {"eglGetError", &retrace::ignore},
+    {"eglGetDisplay", &retrace::ignore},
+    {"eglInitialize", &retrace::ignore},
+    {"eglTerminate", &retrace::ignore},
+    {"eglQueryString", &retrace::ignore},
+    {"eglGetConfigs", &retrace::ignore},
+    {"eglChooseConfig", &retrace::ignore},
+    {"eglGetConfigAttrib", &retrace::ignore},
+    {"eglCreateWindowSurface", &retrace_eglCreateWindowSurface},
+    {"eglCreatePbufferSurface", &retrace_eglCreatePbufferSurface},
+    //{"eglCreatePixmapSurface", &retrace::ignore},
+    {"eglDestroySurface", &retrace_eglDestroySurface},
+    {"eglQuerySurface", &retrace::ignore},
+    {"eglBindAPI", &retrace_eglBindAPI},
+    {"eglQueryAPI", &retrace::ignore},
+    //{"eglWaitClient", &retrace::ignore},
+    //{"eglReleaseThread", &retrace::ignore},
+    //{"eglCreatePbufferFromClientBuffer", &retrace::ignore},
+    //{"eglSurfaceAttrib", &retrace::ignore},
+    //{"eglBindTexImage", &retrace::ignore},
+    //{"eglReleaseTexImage", &retrace::ignore},
+    {"eglSwapInterval", &retrace::ignore},
+    {"eglCreateContext", &retrace_eglCreateContext},
+    {"eglDestroyContext", &retrace_eglDestroyContext},
+    {"eglMakeCurrent", &retrace_eglMakeCurrent},
+    {"eglGetCurrentContext", &retrace::ignore},
+    {"eglGetCurrentSurface", &retrace::ignore},
+    {"eglGetCurrentDisplay", &retrace::ignore},
+    {"eglQueryContext", &retrace::ignore},
+    {"eglWaitGL", &retrace::ignore},
+    {"eglWaitNative", &retrace::ignore},
+    {"eglSwapBuffers", &retrace_eglSwapBuffers},
+    //{"eglCopyBuffers", &retrace::ignore},
+    {"eglGetProcAddress", &retrace::ignore},
+    {NULL, NULL},
+};
diff --git a/retrace/glretrace_glx.cpp b/retrace/glretrace_glx.cpp
new file mode 100644 (file)
index 0000000..7342908
--- /dev/null
@@ -0,0 +1,260 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glproc.hpp"
+#include "retrace.hpp"
+#include "glretrace.hpp"
+
+
+using namespace glretrace;
+
+
+typedef std::map<unsigned long, glws::Drawable *> DrawableMap;
+typedef std::map<unsigned long long, glws::Context *> ContextMap;
+static DrawableMap drawable_map;
+static ContextMap context_map;
+
+
+static glws::Drawable *
+getDrawable(unsigned long drawable_id) {
+    if (drawable_id == 0) {
+        return NULL;
+    }
+
+    DrawableMap::const_iterator it;
+    it = drawable_map.find(drawable_id);
+    if (it == drawable_map.end()) {
+        return (drawable_map[drawable_id] = glws::createDrawable(visual[glretrace::defaultProfile]));
+    }
+
+    return it->second;
+}
+
+static glws::Context *
+getContext(unsigned long long context_ptr) {
+    if (context_ptr == 0) {
+        return NULL;
+    }
+
+    ContextMap::const_iterator it;
+    it = context_map.find(context_ptr);
+    if (it == context_map.end()) {
+        return (context_map[context_ptr] = glws::createContext(visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile));
+    }
+
+    return it->second;
+}
+
+static void retrace_glXCreateContext(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
+
+    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
+    context_map[orig_context] = context;
+}
+
+static void retrace_glXCreateContextAttribsARB(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    glws::Context *share_context = getContext(call.arg(2).toUIntPtr());
+
+    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
+    context_map[orig_context] = context;
+}
+
+static void retrace_glXMakeCurrent(trace::Call &call) {
+    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
+    glws::Context *new_context = getContext(call.arg(2).toUIntPtr());
+
+    if (new_drawable == drawable && new_context == context) {
+        return;
+    }
+
+    if (drawable && context) {
+        glFlush();
+        if (!double_buffer) {
+            frame_complete(call);
+        }
+    }
+
+    bool result = glws::makeCurrent(new_drawable, new_context);
+
+    if (new_drawable && new_context && result) {
+        drawable = new_drawable;
+        context = new_context;
+    } else {
+        drawable = NULL;
+        context = NULL;
+    }
+}
+
+
+static void retrace_glXDestroyContext(trace::Call &call) {
+    glws::Context *context = getContext(call.arg(1).toUIntPtr());
+
+    if (!context) {
+        return;
+    }
+
+    delete context;
+}
+
+static void retrace_glXSwapBuffers(trace::Call &call) {
+    frame_complete(call);
+    if (double_buffer) {
+        drawable->swapBuffers();
+    } else {
+        glFlush();
+    }
+}
+
+static void retrace_glXCreateNewContext(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    glws::Context *share_context = getContext(call.arg(3).toUIntPtr());
+
+    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
+    context_map[orig_context] = context;
+}
+
+static void retrace_glXMakeContextCurrent(trace::Call &call) {
+    glws::Drawable *new_drawable = getDrawable(call.arg(1).toUInt());
+    glws::Context *new_context = getContext(call.arg(3).toUIntPtr());
+
+    if (new_drawable == drawable && new_context == context) {
+        return;
+    }
+
+    if (drawable && context) {
+        glFlush();
+        if (!double_buffer) {
+            frame_complete(call);
+        }
+    }
+
+    bool result = glws::makeCurrent(new_drawable, new_context);
+
+    if (new_drawable && new_context && result) {
+        drawable = new_drawable;
+        context = new_context;
+    } else {
+        drawable = NULL;
+        context = NULL;
+    }
+}
+
+const retrace::Entry glretrace::glx_callbacks[] = {
+    //{"glXBindChannelToWindowSGIX", &retrace_glXBindChannelToWindowSGIX},
+    //{"glXBindSwapBarrierNV", &retrace_glXBindSwapBarrierNV},
+    //{"glXBindSwapBarrierSGIX", &retrace_glXBindSwapBarrierSGIX},
+    //{"glXBindTexImageEXT", &retrace_glXBindTexImageEXT},
+    //{"glXChannelRectSGIX", &retrace_glXChannelRectSGIX},
+    //{"glXChannelRectSyncSGIX", &retrace_glXChannelRectSyncSGIX},
+    {"glXChooseFBConfig", &retrace::ignore},
+    {"glXChooseFBConfigSGIX", &retrace::ignore},
+    {"glXChooseVisual", &retrace::ignore},
+    //{"glXCopyContext", &retrace_glXCopyContext},
+    //{"glXCopyImageSubDataNV", &retrace_glXCopyImageSubDataNV},
+    //{"glXCopySubBufferMESA", &retrace_glXCopySubBufferMESA},
+    {"glXCreateContextAttribsARB", &retrace_glXCreateContextAttribsARB},
+    {"glXCreateContext", &retrace_glXCreateContext},
+    //{"glXCreateContextWithConfigSGIX", &retrace_glXCreateContextWithConfigSGIX},
+    //{"glXCreateGLXPbufferSGIX", &retrace_glXCreateGLXPbufferSGIX},
+    //{"glXCreateGLXPixmap", &retrace_glXCreateGLXPixmap},
+    //{"glXCreateGLXPixmapWithConfigSGIX", &retrace_glXCreateGLXPixmapWithConfigSGIX},
+    {"glXCreateNewContext", &retrace_glXCreateNewContext},
+    //{"glXCreatePbuffer", &retrace_glXCreatePbuffer},
+    //{"glXCreatePixmap", &retrace_glXCreatePixmap},
+    //{"glXCreateWindow", &retrace_glXCreateWindow},
+    //{"glXCushionSGI", &retrace_glXCushionSGI},
+    {"glXDestroyContext", &retrace_glXDestroyContext},
+    //{"glXDestroyGLXPbufferSGIX", &retrace_glXDestroyGLXPbufferSGIX},
+    //{"glXDestroyGLXPixmap", &retrace_glXDestroyGLXPixmap},
+    //{"glXDestroyPbuffer", &retrace_glXDestroyPbuffer},
+    //{"glXDestroyPixmap", &retrace_glXDestroyPixmap},
+    //{"glXDestroyWindow", &retrace_glXDestroyWindow},
+    //{"glXFreeContextEXT", &retrace_glXFreeContextEXT},
+    {"glXGetAGPOffsetMESA", &retrace::ignore},
+    {"glXGetClientString", &retrace::ignore},
+    {"glXGetConfig", &retrace::ignore},
+    {"glXGetContextIDEXT", &retrace::ignore},
+    {"glXGetCurrentContext", &retrace::ignore},
+    {"glXGetCurrentDisplayEXT", &retrace::ignore},
+    {"glXGetCurrentDisplay", &retrace::ignore},
+    {"glXGetCurrentDrawable", &retrace::ignore},
+    {"glXGetCurrentReadDrawable", &retrace::ignore},
+    {"glXGetCurrentReadDrawableSGI", &retrace::ignore},
+    {"glXGetFBConfigAttrib", &retrace::ignore},
+    {"glXGetFBConfigAttribSGIX", &retrace::ignore},
+    {"glXGetFBConfigFromVisualSGIX", &retrace::ignore},
+    {"glXGetFBConfigs", &retrace::ignore},
+    {"glXGetMscRateOML", &retrace::ignore},
+    {"glXGetProcAddressARB", &retrace::ignore},
+    {"glXGetProcAddress", &retrace::ignore},
+    {"glXGetSelectedEvent", &retrace::ignore},
+    {"glXGetSelectedEventSGIX", &retrace::ignore},
+    {"glXGetSyncValuesOML", &retrace::ignore},
+    {"glXGetVideoSyncSGI", &retrace::ignore},
+    {"glXGetVisualFromFBConfig", &retrace::ignore},
+    {"glXGetVisualFromFBConfigSGIX", &retrace::ignore},
+    //{"glXImportContextEXT", &retrace_glXImportContextEXT},
+    {"glXIsDirect", &retrace::ignore},
+    //{"glXJoinSwapGroupNV", &retrace_glXJoinSwapGroupNV},
+    //{"glXJoinSwapGroupSGIX", &retrace_glXJoinSwapGroupSGIX},
+    {"glXMakeContextCurrent", &retrace_glXMakeContextCurrent},
+    //{"glXMakeCurrentReadSGI", &retrace_glXMakeCurrentReadSGI},
+    {"glXMakeCurrent", &retrace_glXMakeCurrent},
+    {"glXQueryChannelDeltasSGIX", &retrace::ignore},
+    {"glXQueryChannelRectSGIX", &retrace::ignore},
+    {"glXQueryContextInfoEXT", &retrace::ignore},
+    {"glXQueryContext", &retrace::ignore},
+    {"glXQueryDrawable", &retrace::ignore},
+    {"glXQueryExtension", &retrace::ignore},
+    {"glXQueryExtensionsString", &retrace::ignore},
+    {"glXQueryFrameCountNV", &retrace::ignore},
+    {"glXQueryGLXPbufferSGIX", &retrace::ignore},
+    {"glXQueryMaxSwapBarriersSGIX", &retrace::ignore},
+    {"glXQueryMaxSwapGroupsNV", &retrace::ignore},
+    {"glXQueryServerString", &retrace::ignore},
+    {"glXQuerySwapGroupNV", &retrace::ignore},
+    {"glXQueryVersion", &retrace::ignore},
+    //{"glXReleaseBuffersMESA", &retrace_glXReleaseBuffersMESA},
+    //{"glXReleaseTexImageEXT", &retrace_glXReleaseTexImageEXT},
+    //{"glXResetFrameCountNV", &retrace_glXResetFrameCountNV},
+    //{"glXSelectEvent", &retrace_glXSelectEvent},
+    //{"glXSelectEventSGIX", &retrace_glXSelectEventSGIX},
+    //{"glXSet3DfxModeMESA", &retrace_glXSet3DfxModeMESA},
+    //{"glXSwapBuffersMscOML", &retrace_glXSwapBuffersMscOML},
+    {"glXSwapBuffers", &retrace_glXSwapBuffers},
+    {"glXSwapIntervalEXT", &retrace::ignore},
+    {"glXSwapIntervalSGI", &retrace::ignore},
+    //{"glXUseXFont", &retrace_glXUseXFont},
+    {"glXWaitForMscOML", &retrace::ignore},
+    {"glXWaitForSbcOML", &retrace::ignore},
+    {"glXWaitGL", &retrace::ignore},
+    {"glXWaitVideoSyncSGI", &retrace::ignore},
+    {"glXWaitX", &retrace::ignore},
+    {NULL, NULL},
+};
+
diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp
new file mode 100644 (file)
index 0000000..313a563
--- /dev/null
@@ -0,0 +1,390 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include "os_binary.hpp"
+#include "os_string.hpp"
+#include "os_time.hpp"
+#include "image.hpp"
+#include "retrace.hpp"
+#include "trace_callset.hpp"
+#include "glproc.hpp"
+#include "glstate.hpp"
+#include "glretrace.hpp"
+
+
+namespace glretrace {
+
+bool double_buffer = true;
+bool insideGlBeginEnd = false;
+glws::Profile defaultProfile = glws::PROFILE_COMPAT;
+glws::Visual *visual[glws::PROFILE_MAX];
+glws::Drawable *drawable = NULL;
+glws::Context *context = NULL;
+
+unsigned frame = 0;
+long long startTime = 0;
+bool wait = false;
+
+bool benchmark = false;
+static const char *compare_prefix = NULL;
+static const char *snapshot_prefix = NULL;
+static trace::CallSet snapshot_frequency;
+static trace::CallSet compare_frequency;
+
+unsigned dump_state = ~0;
+
+void
+checkGlError(trace::Call &call) {
+    GLenum error = glGetError();
+    if (error == GL_NO_ERROR) {
+        return;
+    }
+
+    std::ostream & os = retrace::warning(call);
+
+    os << "glGetError(";
+    os << call.name();
+    os << ") = ";
+
+    switch (error) {
+    case GL_INVALID_ENUM:
+        os << "GL_INVALID_ENUM";
+        break;
+    case GL_INVALID_VALUE:
+        os << "GL_INVALID_VALUE";
+        break;
+    case GL_INVALID_OPERATION:
+        os << "GL_INVALID_OPERATION";
+        break;
+    case GL_STACK_OVERFLOW:
+        os << "GL_STACK_OVERFLOW";
+        break;
+    case GL_STACK_UNDERFLOW:
+        os << "GL_STACK_UNDERFLOW";
+        break;
+    case GL_OUT_OF_MEMORY:
+        os << "GL_OUT_OF_MEMORY";
+        break;
+    case GL_INVALID_FRAMEBUFFER_OPERATION:
+        os << "GL_INVALID_FRAMEBUFFER_OPERATION";
+        break;
+    case GL_TABLE_TOO_LARGE:
+        os << "GL_TABLE_TOO_LARGE";
+        break;
+    default:
+        os << error;
+        break;
+    }
+    os << "\n";
+}
+
+/**
+ * Grow the current drawble.
+ *
+ * We need to infer the drawable size from GL calls because the drawable sizes
+ * are specified by OS specific calls which we do not trace.
+ */
+void
+updateDrawable(int width, int height) {
+    if (!drawable) {
+        return;
+    }
+
+    if (drawable->visible &&
+        width  <= drawable->width &&
+        height <= drawable->height) {
+        return;
+    }
+
+    // Ignore zero area viewports
+    if (width == 0 || height == 0) {
+        return;
+    }
+
+    // Check for bound framebuffer last, as this may have a performance impact.
+    GLint draw_framebuffer = 0;
+    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer);
+    if (draw_framebuffer != 0) {
+        return;
+    }
+
+    drawable->resize(width, height);
+    drawable->show();
+
+    glScissor(0, 0, width, height);
+}
+
+
+static void
+snapshot(unsigned call_no) {
+    assert(snapshot_prefix || compare_prefix);
+
+    if (!drawable) {
+        return;
+    }
+
+    image::Image *ref = NULL;
+
+    if (compare_prefix) {
+        os::String filename = os::String::format("%s%010u.png", compare_prefix, call_no);
+        ref = image::readPNG(filename);
+        if (!ref) {
+            return;
+        }
+        if (retrace::verbosity >= 0) {
+            std::cout << "Read " << filename << "\n";
+        }
+    }
+
+    image::Image *src = glstate::getDrawBufferImage();
+    if (!src) {
+        return;
+    }
+
+    if (snapshot_prefix) {
+        if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
+            char comment[21];
+            snprintf(comment, sizeof comment, "%u", call_no);
+            src->writePNM(std::cout, comment);
+        } else {
+            os::String filename = os::String::format("%s%010u.png", snapshot_prefix, call_no);
+            if (src->writePNG(filename) && retrace::verbosity >= 0) {
+                std::cout << "Wrote " << filename << "\n";
+            }
+        }
+    }
+
+    if (ref) {
+        std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n";
+        delete ref;
+    }
+
+    delete src;
+}
+
+
+void frame_complete(trace::Call &call) {
+    ++frame;
+
+    if (!drawable) {
+        return;
+    }
+
+    if (!drawable->visible) {
+        retrace::warning(call) << "could not infer drawable size (glViewport never called)\n";
+    }
+}
+
+
+static void display(void) {
+    retrace::Retracer retracer;
+
+    retracer.addCallbacks(gl_callbacks);
+    retracer.addCallbacks(glx_callbacks);
+    retracer.addCallbacks(wgl_callbacks);
+    retracer.addCallbacks(cgl_callbacks);
+    retracer.addCallbacks(egl_callbacks);
+
+    startTime = os::getTime();
+    trace::Call *call;
+
+    while ((call = retrace::parser.parse_call())) {
+        bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET;
+        bool doSnapshot =
+            snapshot_frequency.contains(*call) ||
+            compare_frequency.contains(*call)
+        ;
+
+        // For calls which cause rendertargets to be swaped, we take the
+        // snapshot _before_ swapping the rendertargets.
+        if (doSnapshot && swapRenderTarget) {
+            if (call->flags & trace::CALL_FLAG_END_FRAME) {
+                // For swapbuffers/presents we still use this call number,
+                // spite not have been executed yet.
+                snapshot(call->no);
+            } else {
+                // Whereas for ordinate fbo/rendertarget changes we use the
+                // previous call's number.
+                snapshot(call->no - 1);
+            }
+        }
+
+        retracer.retrace(*call);
+
+        if (doSnapshot && !swapRenderTarget) {
+            snapshot(call->no);
+        }
+
+        if (!insideGlBeginEnd &&
+            drawable && context &&
+            call->no >= dump_state) {
+            glstate::dumpCurrentContext(std::cout);
+            exit(0);
+        }
+
+        delete call;
+    }
+
+    // Reached the end of trace
+    glFlush();
+
+    long long endTime = os::getTime();
+    float timeInterval = (endTime - startTime) * (1.0 / os::timeFrequency);
+
+    if ((retrace::verbosity >= -1) || (retrace::profiling)) {
+        std::cout << 
+            "Rendered " << frame << " frames"
+            " in " <<  timeInterval << " secs,"
+            " average of " << (frame/timeInterval) << " fps\n";
+    }
+
+    if (wait) {
+        while (glws::processEvents()) {}
+    } else {
+        exit(0);
+    }
+}
+
+
+static void usage(void) {
+    std::cout << 
+        "Usage: glretrace [OPTION] TRACE\n"
+        "Replay TRACE.\n"
+        "\n"
+        "  -b           benchmark mode (no error checking or warning messages)\n"
+        "  -p           profiling mode (run whole trace, dump profiling info)\n"
+        "  -c PREFIX    compare against snapshots\n"
+        "  -C CALLSET   calls to compare (default is every frame)\n"
+        "  -core        use core profile\n"
+        "  -db          use a double buffer visual (default)\n"
+        "  -sb          use a single buffer visual\n"
+        "  -s PREFIX    take snapshots; `-` for PNM stdout output\n"
+        "  -S CALLSET   calls to snapshot (default is every frame)\n"
+        "  -v           increase output verbosity\n"
+        "  -D CALLNO    dump state at specific call no\n"
+        "  -w           wait on final frame\n";
+}
+
+extern "C"
+int main(int argc, char **argv)
+{
+    assert(compare_frequency.empty());
+    assert(snapshot_frequency.empty());
+
+    int i;
+    for (i = 1; i < argc; ++i) {
+        const char *arg = argv[i];
+
+        if (arg[0] != '-') {
+            break;
+        }
+
+        if (!strcmp(arg, "--")) {
+            break;
+        } else if (!strcmp(arg, "-b")) {
+            benchmark = true;
+            retrace::verbosity = -1;
+            glws::debug = false;
+        } else if (!strcmp(arg, "-p")) {
+            retrace::profiling = true;
+            retrace::verbosity = -1;
+            glws::debug = false;
+        } else if (!strcmp(arg, "-c")) {
+            compare_prefix = argv[++i];
+            if (compare_frequency.empty()) {
+                compare_frequency = trace::CallSet(trace::FREQUENCY_FRAME);
+            }
+        } else if (!strcmp(arg, "-C")) {
+            compare_frequency = trace::CallSet(argv[++i]);
+            if (compare_prefix == NULL) {
+                compare_prefix = "";
+            }
+        } else if (!strcmp(arg, "-D")) {
+            dump_state = atoi(argv[++i]);
+            retrace::verbosity = -2;
+        } else if (!strcmp(arg, "-core")) {
+            defaultProfile = glws::PROFILE_CORE;
+        } else if (!strcmp(arg, "-db")) {
+            double_buffer = true;
+        } else if (!strcmp(arg, "-sb")) {
+            double_buffer = false;
+        } else if (!strcmp(arg, "--help")) {
+            usage();
+            return 0;
+        } else if (!strcmp(arg, "-s")) {
+            snapshot_prefix = argv[++i];
+            if (snapshot_frequency.empty()) {
+                snapshot_frequency = trace::CallSet(trace::FREQUENCY_FRAME);
+            }
+            if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) {
+                os::setBinaryMode(stdout);
+                retrace::verbosity = -2;
+            }
+        } else if (!strcmp(arg, "-S")) {
+            snapshot_frequency = trace::CallSet(argv[++i]);
+            if (snapshot_prefix == NULL) {
+                snapshot_prefix = "";
+            }
+        } else if (!strcmp(arg, "-v")) {
+            ++retrace::verbosity;
+        } else if (!strcmp(arg, "-w")) {
+            wait = true;
+        } else {
+            std::cerr << "error: unknown option " << arg << "\n";
+            usage();
+            return 1;
+        }
+    }
+
+    glws::init();
+    visual[glws::PROFILE_COMPAT] = glws::createVisual(double_buffer, glws::PROFILE_COMPAT);
+    visual[glws::PROFILE_CORE] = glws::createVisual(double_buffer, glws::PROFILE_CORE);
+    visual[glws::PROFILE_ES1] = glws::createVisual(double_buffer, glws::PROFILE_ES1);
+    visual[glws::PROFILE_ES2] = glws::createVisual(double_buffer, glws::PROFILE_ES2);
+
+    for ( ; i < argc; ++i) {
+        if (!retrace::parser.open(argv[i])) {
+            std::cerr << "error: failed to open " << argv[i] << "\n";
+            return 1;
+        }
+
+        display();
+
+        retrace::parser.close();
+    }
+
+    for (int n = 0; n < glws::PROFILE_MAX; n++) {
+        delete visual[n];
+    }
+
+    glws::cleanup();
+
+    return 0;
+}
+
+} /* namespace glretrace */
diff --git a/retrace/glretrace_wgl.cpp b/retrace/glretrace_wgl.cpp
new file mode 100644 (file)
index 0000000..447d177
--- /dev/null
@@ -0,0 +1,309 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glproc.hpp"
+#include "retrace.hpp"
+#include "glretrace.hpp"
+
+
+using namespace glretrace;
+
+
+typedef std::map<unsigned long long, glws::Drawable *> DrawableMap;
+typedef std::map<unsigned long long, glws::Context *> ContextMap;
+static DrawableMap drawable_map;
+static DrawableMap pbuffer_map;
+static ContextMap context_map;
+
+
+static glws::Drawable *
+getDrawable(unsigned long long hdc) {
+    if (hdc == 0) {
+        return NULL;
+    }
+
+    DrawableMap::const_iterator it;
+    it = drawable_map.find(hdc);
+    if (it == drawable_map.end()) {
+        return (drawable_map[hdc] = glws::createDrawable(visual[glretrace::defaultProfile]));
+    }
+
+    return it->second;
+}
+
+static void retrace_wglCreateContext(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], NULL, glretrace::defaultProfile);
+    context_map[orig_context] = context;
+}
+
+static void retrace_wglDeleteContext(trace::Call &call) {
+}
+
+static void retrace_wglMakeCurrent(trace::Call &call) {
+    if (drawable && context) {
+        glFlush();
+        if (!double_buffer) {
+            frame_complete(call);
+        }
+    }
+    
+    glws::Drawable *new_drawable = getDrawable(call.arg(0).toUIntPtr());
+    glws::Context *new_context = context_map[call.arg(1).toUIntPtr()];
+
+    bool result = glws::makeCurrent(new_drawable, new_context);
+
+    if (new_drawable && new_context && result) {
+        drawable = new_drawable;
+        context = new_context;
+    } else {
+        drawable = NULL;
+        context = NULL;
+    }
+}
+
+static void retrace_wglCopyContext(trace::Call &call) {
+}
+
+static void retrace_wglChoosePixelFormat(trace::Call &call) {
+}
+
+static void retrace_wglDescribePixelFormat(trace::Call &call) {
+}
+
+static void retrace_wglSetPixelFormat(trace::Call &call) {
+}
+
+static void retrace_wglSwapBuffers(trace::Call &call) {
+    frame_complete(call);
+    if (double_buffer) {
+        drawable->swapBuffers();
+    } else {
+        glFlush();
+    }
+}
+
+static void retrace_wglShareLists(trace::Call &call) {
+    unsigned long long hglrc1 = call.arg(0).toUIntPtr();
+    unsigned long long hglrc2 = call.arg(1).toUIntPtr();
+
+    glws::Context *share_context = context_map[hglrc1];
+    glws::Context *old_context = context_map[hglrc2];
+
+    glws::Context *new_context =
+        glws::createContext(old_context->visual, share_context, glretrace::defaultProfile);
+    if (new_context) {
+        if (context == old_context) {
+            glws::makeCurrent(drawable, new_context);
+        }
+
+        context_map[hglrc2] = new_context;
+        
+        delete old_context;
+    }
+}
+
+static void retrace_wglCreateLayerContext(trace::Call &call) {
+    retrace_wglCreateContext(call);
+}
+
+static void retrace_wglDescribeLayerPlane(trace::Call &call) {
+}
+
+static void retrace_wglSetLayerPaletteEntries(trace::Call &call) {
+}
+
+static void retrace_wglRealizeLayerPalette(trace::Call &call) {
+}
+
+static void retrace_wglSwapLayerBuffers(trace::Call &call) {
+    retrace_wglSwapBuffers(call);
+}
+
+static void retrace_wglUseFontBitmapsA(trace::Call &call) {
+}
+
+static void retrace_wglUseFontBitmapsW(trace::Call &call) {
+}
+
+static void retrace_wglSwapMultipleBuffers(trace::Call &call) {
+}
+
+static void retrace_wglUseFontOutlinesA(trace::Call &call) {
+}
+
+static void retrace_wglUseFontOutlinesW(trace::Call &call) {
+}
+
+static void retrace_wglCreateBufferRegionARB(trace::Call &call) {
+}
+
+static void retrace_wglDeleteBufferRegionARB(trace::Call &call) {
+}
+
+static void retrace_wglSaveBufferRegionARB(trace::Call &call) {
+}
+
+static void retrace_wglRestoreBufferRegionARB(trace::Call &call) {
+}
+
+static void retrace_wglChoosePixelFormatARB(trace::Call &call) {
+}
+
+static void retrace_wglMakeContextCurrentARB(trace::Call &call) {
+}
+
+static void retrace_wglCreatePbufferARB(trace::Call &call) {
+    int iWidth = call.arg(2).toUInt();
+    int iHeight = call.arg(3).toUInt();
+
+    unsigned long long orig_pbuffer = call.ret->toUIntPtr();
+    glws::Drawable *drawable = glws::createDrawable(glretrace::visual[glretrace::defaultProfile]);
+
+    drawable->resize(iWidth, iHeight);
+    drawable->show();
+
+    pbuffer_map[orig_pbuffer] = drawable;
+}
+
+static void retrace_wglGetPbufferDCARB(trace::Call &call) {
+    glws::Drawable *pbuffer = pbuffer_map[call.arg(0).toUIntPtr()];
+
+    unsigned long long orig_hdc = call.ret->toUIntPtr();
+
+    drawable_map[orig_hdc] = pbuffer;
+}
+
+static void retrace_wglReleasePbufferDCARB(trace::Call &call) {
+}
+
+static void retrace_wglDestroyPbufferARB(trace::Call &call) {
+}
+
+static void retrace_wglQueryPbufferARB(trace::Call &call) {
+}
+
+static void retrace_wglBindTexImageARB(trace::Call &call) {
+}
+
+static void retrace_wglReleaseTexImageARB(trace::Call &call) {
+}
+
+static void retrace_wglSetPbufferAttribARB(trace::Call &call) {
+}
+
+static void retrace_wglCreateContextAttribsARB(trace::Call &call) {
+    unsigned long long orig_context = call.ret->toUIntPtr();
+    glws::Context *share_context = NULL;
+
+    if (call.arg(1).toPointer()) {
+        share_context = context_map[call.arg(1).toUIntPtr()];
+    }
+
+    glws::Context *context = glws::createContext(glretrace::visual[glretrace::defaultProfile], share_context, glretrace::defaultProfile);
+    context_map[orig_context] = context;
+}
+
+static void retrace_wglMakeContextCurrentEXT(trace::Call &call) {
+}
+
+static void retrace_wglChoosePixelFormatEXT(trace::Call &call) {
+}
+
+static void retrace_wglSwapIntervalEXT(trace::Call &call) {
+}
+
+static void retrace_wglAllocateMemoryNV(trace::Call &call) {
+}
+
+static void retrace_wglFreeMemoryNV(trace::Call &call) {
+}
+
+static void retrace_glAddSwapHintRectWIN(trace::Call &call) {
+}
+
+static void retrace_wglGetProcAddress(trace::Call &call) {
+}
+
+const retrace::Entry glretrace::wgl_callbacks[] = {
+    {"glAddSwapHintRectWIN", &retrace_glAddSwapHintRectWIN},
+    {"wglAllocateMemoryNV", &retrace_wglAllocateMemoryNV},
+    {"wglBindTexImageARB", &retrace_wglBindTexImageARB},
+    {"wglChoosePixelFormat", &retrace_wglChoosePixelFormat},
+    {"wglChoosePixelFormatARB", &retrace_wglChoosePixelFormatARB},
+    {"wglChoosePixelFormatEXT", &retrace_wglChoosePixelFormatEXT},
+    {"wglCopyContext", &retrace_wglCopyContext},
+    {"wglCreateBufferRegionARB", &retrace_wglCreateBufferRegionARB},
+    {"wglCreateContext", &retrace_wglCreateContext},
+    {"wglCreateContextAttribsARB", &retrace_wglCreateContextAttribsARB},
+    {"wglCreateLayerContext", &retrace_wglCreateLayerContext},
+    {"wglCreatePbufferARB", &retrace_wglCreatePbufferARB},
+    {"wglDeleteBufferRegionARB", &retrace_wglDeleteBufferRegionARB},
+    {"wglDeleteContext", &retrace_wglDeleteContext},
+    {"wglDescribeLayerPlane", &retrace_wglDescribeLayerPlane},
+    {"wglDescribePixelFormat", &retrace_wglDescribePixelFormat},
+    {"wglDestroyPbufferARB", &retrace_wglDestroyPbufferARB},
+    {"wglFreeMemoryNV", &retrace_wglFreeMemoryNV},
+    {"wglGetCurrentContext", &retrace::ignore},
+    {"wglGetCurrentDC", &retrace::ignore},
+    {"wglGetCurrentReadDCARB", &retrace::ignore},
+    {"wglGetCurrentReadDCEXT", &retrace::ignore},
+    {"wglGetDefaultProcAddress", &retrace::ignore},
+    {"wglGetExtensionsStringARB", &retrace::ignore},
+    {"wglGetExtensionsStringEXT", &retrace::ignore},
+    {"wglGetLayerPaletteEntries", &retrace::ignore},
+    {"wglGetPbufferDCARB", &retrace_wglGetPbufferDCARB},
+    {"wglGetPixelFormat", &retrace::ignore},
+    {"wglGetPixelFormatAttribfvARB", &retrace::ignore},
+    {"wglGetPixelFormatAttribfvEXT", &retrace::ignore},
+    {"wglGetPixelFormatAttribivARB", &retrace::ignore},
+    {"wglGetPixelFormatAttribivEXT", &retrace::ignore},
+    {"wglGetProcAddress", &retrace_wglGetProcAddress},
+    {"wglGetSwapIntervalEXT", &retrace::ignore},
+    {"wglMakeContextCurrentARB", &retrace_wglMakeContextCurrentARB},
+    {"wglMakeContextCurrentEXT", &retrace_wglMakeContextCurrentEXT},
+    {"wglMakeCurrent", &retrace_wglMakeCurrent},
+    {"wglQueryPbufferARB", &retrace_wglQueryPbufferARB},
+    {"wglRealizeLayerPalette", &retrace_wglRealizeLayerPalette},
+    {"wglReleasePbufferDCARB", &retrace_wglReleasePbufferDCARB},
+    {"wglReleaseTexImageARB", &retrace_wglReleaseTexImageARB},
+    {"wglRestoreBufferRegionARB", &retrace_wglRestoreBufferRegionARB},
+    {"wglSaveBufferRegionARB", &retrace_wglSaveBufferRegionARB},
+    {"wglSetLayerPaletteEntries", &retrace_wglSetLayerPaletteEntries},
+    {"wglSetPbufferAttribARB", &retrace_wglSetPbufferAttribARB},
+    {"wglSetPixelFormat", &retrace_wglSetPixelFormat},
+    {"wglShareLists", &retrace_wglShareLists},
+    {"wglSwapBuffers", &retrace_wglSwapBuffers},
+    {"wglSwapIntervalEXT", &retrace_wglSwapIntervalEXT},
+    {"wglSwapLayerBuffers", &retrace_wglSwapLayerBuffers},
+    {"wglSwapMultipleBuffers", &retrace_wglSwapMultipleBuffers},
+    {"wglUseFontBitmapsA", &retrace_wglUseFontBitmapsA},
+    {"wglUseFontBitmapsW", &retrace_wglUseFontBitmapsW},
+    {"wglUseFontOutlinesA", &retrace_wglUseFontOutlinesA},
+    {"wglUseFontOutlinesW", &retrace_wglUseFontOutlinesW},
+    {NULL, NULL}
+};
+
diff --git a/retrace/glstate.cpp b/retrace/glstate.cpp
new file mode 100644 (file)
index 0000000..0d5a5f3
--- /dev/null
@@ -0,0 +1,155 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+
+#include "image.hpp"
+#include "json.hpp"
+#include "glproc.hpp"
+#include "glsize.hpp"
+#include "glstate.hpp"
+#include "glstate_internal.hpp"
+
+
+namespace glstate {
+
+
+Context::Context(void) {
+    memset(this, 0, sizeof *this);
+
+    const char *version = (const char *)glGetString(GL_VERSION);
+    if (version) {
+        if (version[0] == 'O' &&
+            version[1] == 'p' &&
+            version[2] == 'e' &&
+            version[3] == 'n' &&
+            version[4] == 'G' &&
+            version[5] == 'L' &&
+            version[6] == ' ' &&
+            version[7] == 'E' &&
+            version[8] == 'S' &&
+            (version[9] == ' ' || version[9] == '-')) {
+            ES = true;
+        }
+    }
+
+    ARB_draw_buffers = !ES;
+
+    // TODO: Check extensions we use below
+}
+
+void
+Context::resetPixelPackState(void) {
+    if (!ES) {
+        glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
+        glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+        glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
+        glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
+        glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+        glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
+        glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+        glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+        glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
+    } else {
+        packAlignment = 4;
+        glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);
+    }
+    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+}
+
+void
+Context::restorePixelPackState(void) {
+    if (!ES) {
+        glPopClientAttrib();
+    } else {
+        glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);
+    }
+}
+
+
+static const GLenum bindings[] = {
+    GL_DRAW_BUFFER,
+    GL_READ_BUFFER,
+    GL_PIXEL_PACK_BUFFER_BINDING,
+    GL_PIXEL_UNPACK_BUFFER_BINDING,
+    GL_TEXTURE_BINDING_1D,
+    GL_TEXTURE_BINDING_2D,
+    GL_TEXTURE_BINDING_3D,
+    GL_TEXTURE_BINDING_RECTANGLE,
+    GL_TEXTURE_BINDING_CUBE_MAP,
+    GL_DRAW_FRAMEBUFFER_BINDING,
+    GL_READ_FRAMEBUFFER_BINDING,
+    GL_RENDERBUFFER_BINDING,
+    GL_DRAW_BUFFER0,
+    GL_DRAW_BUFFER1,
+    GL_DRAW_BUFFER2,
+    GL_DRAW_BUFFER3,
+    GL_DRAW_BUFFER4,
+    GL_DRAW_BUFFER5,
+    GL_DRAW_BUFFER6,
+    GL_DRAW_BUFFER7,
+};
+
+
+#define NUM_BINDINGS sizeof(bindings)/sizeof(bindings[0])
+
+
+void dumpCurrentContext(std::ostream &os)
+{
+    JSONWriter json(os);
+
+#ifndef NDEBUG
+    GLint old_bindings[NUM_BINDINGS];
+    for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
+        old_bindings[i] = 0;
+        glGetIntegerv(bindings[i], &old_bindings[i]);
+    }
+#endif
+
+    Context context;
+
+    dumpParameters(json, context);
+    dumpShadersUniforms(json, context);
+    dumpTextures(json, context);
+    dumpFramebuffer(json, context);
+
+#ifndef NDEBUG
+    for (unsigned i = 0; i < NUM_BINDINGS; ++i) {
+        GLint new_binding = 0;
+        glGetIntegerv(bindings[i], &new_binding);
+        if (new_binding != old_bindings[i]) {
+            std::cerr << "warning: " << enumToString(bindings[i]) << " was clobbered\n";
+        }
+    }
+#endif
+
+}
+
+
+} /* namespace glstate */
diff --git a/retrace/glstate.hpp b/retrace/glstate.hpp
new file mode 100644 (file)
index 0000000..6fb615f
--- /dev/null
@@ -0,0 +1,54 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _GLSTATE_HPP_
+#define _GLSTATE_HPP_
+
+
+#include <ostream>
+
+#include "glimports.hpp"
+
+
+namespace image {
+    class Image;
+}
+
+
+namespace glstate {
+
+
+const char *enumToString(GLenum pname);
+
+void dumpCurrentContext(std::ostream &os);
+
+image::Image *
+getDrawBufferImage(void);
+
+
+} /* namespace glstate */
+
+
+#endif /* _GLSTATE_HPP_ */
diff --git a/retrace/glstate_images.cpp b/retrace/glstate_images.cpp
new file mode 100644 (file)
index 0000000..f16cba4
--- /dev/null
@@ -0,0 +1,1185 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+
+#include "image.hpp"
+#include "json.hpp"
+#include "glproc.hpp"
+#include "glsize.hpp"
+#include "glstate.hpp"
+#include "glstate_internal.hpp"
+
+
+#ifdef __linux__
+#include <dlfcn.h>
+#endif
+
+#ifdef __APPLE__
+
+#include <Carbon/Carbon.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+OSStatus CGSGetSurfaceBounds(CGSConnectionID, CGWindowID, CGSSurfaceID, CGRect *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPLE__ */
+
+
+/* Change thi to one to force interpreting depth buffers as RGBA, which enables
+ * visualizing full dynamic range, until we can transmit HDR images to the GUI */
+#define DEPTH_AS_RGBA 0
+
+
+namespace glstate {
+
+
+struct ImageDesc
+{
+    GLint width;
+    GLint height;
+    GLint depth;
+    GLint internalFormat;
+
+    inline
+    ImageDesc() :
+        width(0),
+        height(0),
+        depth(0),
+        internalFormat(GL_NONE)
+    {}
+
+    inline bool
+    valid(void) const {
+        return width > 0 && height > 0 && depth > 0;
+    }
+};
+
+
+/**
+ * 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) {
+        return getActiveTextureLevelDescOES(context, target, level, desc);
+    }
+
+    glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &desc.internalFormat);
+
+    desc.width = 0;
+    glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &desc.width);
+
+    if (target == GL_TEXTURE_1D) {
+        desc.height = 1;
+        desc.depth = 1;
+    } else {
+        desc.height = 0;
+        glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &desc.height);
+        if (target != GL_TEXTURE_3D) {
+            desc.depth = 1;
+        } else {
+            desc.depth = 0;
+            glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &desc.depth);
+        }
+    }
+
+    return desc.valid();
+}
+
+
+/**
+ * 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)
+{
+    ImageDesc desc;
+    if (!getActiveTextureLevelDesc(context, target, level, desc)) {
+        return;
+    }
+
+    char label[512];
+
+    GLint active_texture = GL_TEXTURE0;
+    glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
+    snprintf(label, sizeof label, "%s, %s, level = %d",
+             enumToString(active_texture), enumToString(target), level);
+
+    json.beginMember(label);
+
+    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");
+
+    json.writeNumberMember("__width__", desc.width);
+    json.writeNumberMember("__height__", desc.height);
+    json.writeNumberMember("__depth__", desc.depth);
+
+    json.writeStringMember("__format__", enumToString(desc.internalFormat));
+
+    // Hardcoded for now, but we could chose types more adequate to the
+    // texture internal format
+    json.writeStringMember("__type__", "uint8");
+    json.writeBoolMember("__normalized__", true);
+    json.writeNumberMember("__channels__", channels);
+
+    GLubyte *pixels = new GLubyte[desc.depth*desc.width*desc.height*channels];
+
+    context.resetPixelPackState();
+
+    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, channels, true, &pngBuffer, &pngBufferSize);
+    json.writeBase64(pngBuffer, pngBufferSize);
+    free(pngBuffer);
+    json.endMember(); // __data__
+
+    delete [] pixels;
+    json.endObject();
+}
+
+
+static inline void
+dumpTexture(JSONWriter &json, Context &context, GLenum target, GLenum binding)
+{
+    GLint texture_binding = 0;
+    glGetIntegerv(binding, &texture_binding);
+    if (!glIsEnabled(target) && !texture_binding) {
+        return;
+    }
+
+    GLint level = 0;
+    do {
+        ImageDesc desc;
+        if (!getActiveTextureLevelDesc(context, target, level, desc)) {
+            break;
+        }
+
+        if (target == GL_TEXTURE_CUBE_MAP) {
+            for (int face = 0; face < 6; ++face) {
+                dumpActiveTextureLevel(json, context, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
+            }
+        } else {
+            dumpActiveTextureLevel(json, context, target, level);
+        }
+
+        ++level;
+    } while(true);
+}
+
+
+void
+dumpTextures(JSONWriter &json, Context &context)
+{
+    json.beginMember("textures");
+    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);
+        dumpTexture(json, context, GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D);
+        dumpTexture(json, context, GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D);
+        dumpTexture(json, context, GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D);
+        dumpTexture(json, context, GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE);
+        dumpTexture(json, context, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP);
+    }
+    glActiveTexture(active_texture);
+    json.endObject();
+    json.endMember(); // textures
+}
+
+
+static bool
+getDrawableBounds(GLint *width, GLint *height) {
+#if defined(__linux__)
+    if (dlsym(RTLD_DEFAULT, "eglGetCurrentContext")) {
+        EGLContext currentContext = eglGetCurrentContext();
+        if (currentContext == EGL_NO_CONTEXT) {
+            return false;
+        }
+
+        EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
+        if (currentSurface == EGL_NO_SURFACE) {
+            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;
+        }
+
+        return true;
+    }
+#endif
+
+#if defined(_WIN32)
+
+    HDC hDC = wglGetCurrentDC();
+    if (!hDC) {
+        return false;
+    }
+
+    HWND hWnd = WindowFromDC(hDC);
+    RECT rect;
+
+    if (!GetClientRect(hWnd, &rect)) {
+       return false;
+    }
+
+    *width  = rect.right  - rect.left;
+    *height = rect.bottom - rect.top;
+    return true;
+
+#elif defined(__APPLE__)
+
+    CGLContextObj ctx = CGLGetCurrentContext();
+    if (ctx == NULL) {
+        return false;
+    }
+
+    CGSConnectionID cid;
+    CGSWindowID wid;
+    CGSSurfaceID sid;
+
+    if (CGLGetSurface(ctx, &cid, &wid, &sid) != kCGLNoError) {
+        return false;
+    }
+
+    CGRect rect;
+
+    if (CGSGetSurfaceBounds(cid, wid, sid, &rect) != 0) {
+        return false;
+    }
+
+    *width = rect.size.width;
+    *height = rect.size.height;
+    return true;
+
+#elif defined(HAVE_X11)
+
+    Display *display;
+    Drawable drawable;
+    Window root;
+    int x, y;
+    unsigned int w, h, bw, depth;
+
+    display = glXGetCurrentDisplay();
+    if (!display) {
+        return false;
+    }
+
+    drawable = glXGetCurrentDrawable();
+    if (drawable == None) {
+        return false;
+    }
+
+    if (!XGetGeometry(display, drawable, &root, &x, &y, &w, &h, &bw, &depth)) {
+        return false;
+    }
+
+    *width = w;
+    *height = h;
+    return true;
+
+#else
+
+    return false;
+
+#endif
+}
+
+
+static const GLenum texture_bindings[][2] = {
+    {GL_TEXTURE_1D, GL_TEXTURE_BINDING_1D},
+    {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D},
+    {GL_TEXTURE_3D, GL_TEXTURE_BINDING_3D},
+    {GL_TEXTURE_RECTANGLE, GL_TEXTURE_BINDING_RECTANGLE},
+    {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP}
+};
+
+
+static bool
+bindTexture(GLint texture, GLenum &target, GLint &bound_texture)
+{
+
+    for (unsigned i = 0; i < sizeof(texture_bindings)/sizeof(texture_bindings[0]); ++i) {
+        target  = texture_bindings[i][0];
+
+        GLenum binding = texture_bindings[i][1];
+
+        while (glGetError() != GL_NO_ERROR)
+            ;
+
+        glGetIntegerv(binding, &bound_texture);
+        glBindTexture(target, texture);
+
+        if (glGetError() == GL_NO_ERROR) {
+            return true;
+        }
+
+        glBindTexture(target, bound_texture);
+    }
+
+    target = GL_NONE;
+
+    return false;
+}
+
+
+static bool
+getTextureLevelDesc(Context &context, GLint texture, GLint level, ImageDesc &desc)
+{
+    GLenum target;
+    GLint bound_texture = 0;
+    if (!bindTexture(texture, target, bound_texture)) {
+        return false;
+    }
+
+    getActiveTextureLevelDesc(context, target, level, desc);
+
+    glBindTexture(target, bound_texture);
+
+    return desc.valid();
+}
+
+
+static bool
+getBoundRenderbufferDesc(Context &context, ImageDesc &desc)
+{
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &desc.width);
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &desc.height);
+    desc.depth = 1;
+    
+    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &desc.internalFormat);
+    
+    return desc.valid();
+}
+
+
+static bool
+getRenderbufferDesc(Context &context, GLint renderbuffer, ImageDesc &desc)
+{
+    GLint bound_renderbuffer = 0;
+    glGetIntegerv(GL_RENDERBUFFER_BINDING, &bound_renderbuffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
+
+    getBoundRenderbufferDesc(context, desc);
+
+    glBindRenderbuffer(GL_RENDERBUFFER, bound_renderbuffer);
+    
+    return desc.valid();
+}
+
+
+static bool
+getFramebufferAttachmentDesc(Context &context, GLenum target, GLenum attachment, ImageDesc &desc)
+{
+    GLint object_type = GL_NONE;
+    glGetFramebufferAttachmentParameteriv(target, attachment,
+                                          GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+                                          &object_type);
+    if (object_type == GL_NONE) {
+        return false;
+    }
+
+    GLint object_name = 0;
+    glGetFramebufferAttachmentParameteriv(target, attachment,
+                                          GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+                                          &object_name);
+    if (object_name == 0) {
+        return false;
+    }
+
+    if (object_type == GL_RENDERBUFFER) {
+        return getRenderbufferDesc(context, object_name, desc);
+    } else if (object_type == GL_TEXTURE) {
+        GLint texture_level = 0;
+        glGetFramebufferAttachmentParameteriv(target, attachment,
+                                              GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
+                                              &texture_level);
+        return getTextureLevelDesc(context, object_name, texture_level, desc);
+    } else {
+        std::cerr << "warning: unexpected GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = " << object_type << "\n";
+        return false;
+    }
+}
+
+
+
+image::Image *
+getDrawBufferImage() {
+    GLenum format = GL_RGB;
+    GLint channels = __gl_format_channels(format);
+    if (channels > 4) {
+        return NULL;
+    }
+
+    Context context;
+
+    GLenum framebuffer_binding;
+    GLenum framebuffer_target;
+    if (context.ES) {
+        framebuffer_binding = GL_FRAMEBUFFER_BINDING;
+        framebuffer_target = GL_FRAMEBUFFER;
+    } else {
+        framebuffer_binding = GL_DRAW_FRAMEBUFFER_BINDING;
+        framebuffer_target = GL_DRAW_FRAMEBUFFER;
+    }
+
+    GLint draw_framebuffer = 0;
+    glGetIntegerv(framebuffer_binding, &draw_framebuffer);
+
+    GLint draw_buffer = GL_NONE;
+    ImageDesc desc;
+    if (draw_framebuffer) {
+        if (context.ARB_draw_buffers) {
+            glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer);
+            if (draw_buffer == GL_NONE) {
+                return NULL;
+            }
+        }
+
+        if (!getFramebufferAttachmentDesc(context, framebuffer_target, draw_buffer, desc)) {
+            return NULL;
+        }
+    } else {
+        if (!context.ES) {
+            glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
+            if (draw_buffer == GL_NONE) {
+                return NULL;
+            }
+        }
+
+        if (!getDrawableBounds(&desc.width, &desc.height)) {
+            return NULL;
+        }
+
+        desc.depth = 1;
+    }
+
+    GLenum type = GL_UNSIGNED_BYTE;
+
+#if DEPTH_AS_RGBA
+    if (format == GL_DEPTH_COMPONENT) {
+        type = GL_UNSIGNED_INT;
+        channels = 4;
+    }
+#endif
+
+    image::Image *image = new image::Image(desc.width, desc.height, channels, true);
+    if (!image) {
+        return NULL;
+    }
+
+    while (glGetError() != GL_NO_ERROR) {}
+
+    GLint read_framebuffer = 0;
+    GLint read_buffer = GL_NONE;
+    if (!context.ES) {
+        glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, draw_framebuffer);
+
+        glGetIntegerv(GL_READ_BUFFER, &read_buffer);
+        glReadBuffer(draw_buffer);
+    }
+
+    // TODO: reset imaging state too
+    context.resetPixelPackState();
+
+    glReadPixels(0, 0, desc.width, desc.height, format, type, image->pixels);
+
+    context.restorePixelPackState();
+
+    if (!context.ES) {
+        glReadBuffer(read_buffer);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
+    }
+
+    GLenum error = glGetError();
+    if (error != GL_NO_ERROR) {
+        do {
+            std::cerr << "warning: " << enumToString(error) << " while getting snapshot\n";
+            error = glGetError();
+        } while(error != GL_NO_ERROR);
+        delete image;
+        return NULL;
+    }
+     
+    return image;
+}
+
+
+/**
+ * Dump the image of the currently bound read buffer.
+ */
+static inline void
+dumpReadBufferImage(JSONWriter &json, GLint width, GLint height, GLenum format,
+                    GLint internalFormat = GL_NONE)
+{
+    GLint channels = __gl_format_channels(format);
+
+    Context context;
+
+    json.beginObject();
+
+    // Tell the GUI this is no ordinary object, but an image
+    json.writeStringMember("__class__", "image");
+
+    json.writeNumberMember("__width__", width);
+    json.writeNumberMember("__height__", height);
+    json.writeNumberMember("__depth__", 1);
+
+    json.writeStringMember("__format__", enumToString(internalFormat));
+
+    // Hardcoded for now, but we could chose types more adequate to the
+    // texture internal format
+    json.writeStringMember("__type__", "uint8");
+    json.writeBoolMember("__normalized__", true);
+    json.writeNumberMember("__channels__", channels);
+
+    GLenum type = GL_UNSIGNED_BYTE;
+
+#if DEPTH_AS_RGBA
+    if (format == GL_DEPTH_COMPONENT) {
+        type = GL_UNSIGNED_INT;
+        channels = 4;
+    }
+#endif
+
+    GLubyte *pixels = new GLubyte[width*height*channels];
+
+    // TODO: reset imaging state too
+    context.resetPixelPackState();
+
+    glReadPixels(0, 0, width, height, format, type, pixels);
+
+    context.restorePixelPackState();
+
+    json.beginMember("__data__");
+    char *pngBuffer;
+    int pngBufferSize;
+    image::writePixelsToBuffer(pixels, width, height, channels, true, &pngBuffer, &pngBufferSize);
+    //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels)
+    //          <<", after = "<<pngBufferSize << ", ratio = " << double(width * height * channels * sizeof *pixels)/pngBufferSize;
+    json.writeBase64(pngBuffer, pngBufferSize);
+    free(pngBuffer);
+    json.endMember(); // __data__
+
+    delete [] pixels;
+    json.endObject();
+}
+
+
+static inline GLuint
+downsampledFramebuffer(Context &context,
+                       GLuint oldFbo, GLint drawbuffer,
+                       GLint colorRb, GLint depthRb, GLint stencilRb,
+                       GLuint *rbs, GLint *numRbs)
+{
+    GLuint fbo;
+
+
+    *numRbs = 0;
+
+    glGenFramebuffers(1, &fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    {
+        // color buffer
+        ImageDesc desc;
+        glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
+        getBoundRenderbufferDesc(context, desc);
+
+        glGenRenderbuffers(1, &rbs[*numRbs]);
+        glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+        glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawbuffer,
+                                  GL_RENDERBUFFER, rbs[*numRbs]);
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+        glDrawBuffer(drawbuffer);
+        glReadBuffer(drawbuffer);
+        glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
+                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        ++*numRbs;
+    }
+
+    if (stencilRb == depthRb && stencilRb) {
+        //combined depth and stencil buffer
+        ImageDesc desc;
+        glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
+        getBoundRenderbufferDesc(context, desc);
+
+        glGenRenderbuffers(1, &rbs[*numRbs]);
+        glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+        glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                  GL_RENDERBUFFER, rbs[*numRbs]);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+        glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
+                          GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        ++*numRbs;
+    } else {
+        if (depthRb) {
+            ImageDesc desc;
+            glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
+            getBoundRenderbufferDesc(context, desc);
+
+            glGenRenderbuffers(1, &rbs[*numRbs]);
+            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+            glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                      GL_DEPTH_ATTACHMENT,
+                                      GL_RENDERBUFFER, rbs[*numRbs]);
+            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+            glDrawBuffer(GL_DEPTH_ATTACHMENT);
+            glReadBuffer(GL_DEPTH_ATTACHMENT);
+            glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
+                              GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+            ++*numRbs;
+        }
+        if (stencilRb) {
+            ImageDesc desc;
+            glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
+            getBoundRenderbufferDesc(context, desc);
+
+            glGenRenderbuffers(1, &rbs[*numRbs]);
+            glBindRenderbuffer(GL_RENDERBUFFER, rbs[*numRbs]);
+            glRenderbufferStorage(GL_RENDERBUFFER, desc.internalFormat, desc.width, desc.height);
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+                                      GL_STENCIL_ATTACHMENT,
+                                      GL_RENDERBUFFER, rbs[*numRbs]);
+            glBindFramebuffer(GL_READ_FRAMEBUFFER, oldFbo);
+            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+            glDrawBuffer(GL_STENCIL_ATTACHMENT);
+            glReadBuffer(GL_STENCIL_ATTACHMENT);
+            glBlitFramebuffer(0, 0, desc.width, desc.height, 0, 0, desc.width, desc.height,
+                              GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+            ++*numRbs;
+        }
+    }
+
+    return fbo;
+}
+
+
+/**
+ * Dump images of current draw drawable/window.
+ */
+static void
+dumpDrawableImages(JSONWriter &json, Context &context)
+{
+    GLint width, height;
+
+    if (!getDrawableBounds(&width, &height)) {
+        return;
+    }
+
+    GLint draw_buffer = GL_NONE;
+    if (context.ES) {
+        draw_buffer = GL_BACK;
+    } else {
+        glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
+        glReadBuffer(draw_buffer);
+    }
+
+    if (draw_buffer != GL_NONE) {
+        GLint read_buffer = GL_NONE;
+        if (!context.ES) {
+            glGetIntegerv(GL_READ_BUFFER, &read_buffer);
+        }
+
+        GLint alpha_bits = 0;
+#if 0
+        // XXX: Ignore alpha until we are able to match the traced visual
+        glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
+#endif
+        GLenum format = alpha_bits ? GL_RGBA : GL_RGB;
+        json.beginMember(enumToString(draw_buffer));
+        dumpReadBufferImage(json, width, height, format);
+        json.endMember();
+
+        if (!context.ES) {
+            glReadBuffer(read_buffer);
+        }
+    }
+
+    if (!context.ES) {
+        GLint depth_bits = 0;
+        glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
+        if (depth_bits) {
+            json.beginMember("GL_DEPTH_COMPONENT");
+            dumpReadBufferImage(json, width, height, GL_DEPTH_COMPONENT);
+            json.endMember();
+        }
+
+        GLint stencil_bits = 0;
+        glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
+        if (stencil_bits) {
+            json.beginMember("GL_STENCIL_INDEX");
+            dumpReadBufferImage(json, width, height, GL_STENCIL_INDEX);
+            json.endMember();
+        }
+    }
+}
+
+
+/**
+ * Dump the specified framebuffer attachment.
+ *
+ * In the case of a color attachment, it assumes it is already bound for read.
+ */
+static void
+dumpFramebufferAttachment(JSONWriter &json, Context &context, GLenum target, GLenum attachment, GLenum format)
+{
+    ImageDesc desc;
+    if (!getFramebufferAttachmentDesc(context, target, attachment, desc)) {
+        return;
+    }
+
+    json.beginMember(enumToString(attachment));
+    dumpReadBufferImage(json, desc.width, desc.height, format, desc.internalFormat);
+    json.endMember();
+}
+
+
+static void
+dumpFramebufferAttachments(JSONWriter &json, Context &context, GLenum target)
+{
+    GLint read_framebuffer = 0;
+    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &read_framebuffer);
+
+    GLint read_buffer = GL_NONE;
+    glGetIntegerv(GL_READ_BUFFER, &read_buffer);
+
+    GLint max_draw_buffers = 1;
+    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
+    GLint max_color_attachments = 0;
+    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
+
+    for (GLint i = 0; i < max_draw_buffers; ++i) {
+        GLint draw_buffer = GL_NONE;
+        glGetIntegerv(GL_DRAW_BUFFER0 + i, &draw_buffer);
+        if (draw_buffer != GL_NONE) {
+            glReadBuffer(draw_buffer);
+            GLint attachment;
+            if (draw_buffer >= GL_COLOR_ATTACHMENT0 && draw_buffer < GL_COLOR_ATTACHMENT0 + max_color_attachments) {
+                attachment = draw_buffer;
+            } else {
+                std::cerr << "warning: unexpected GL_DRAW_BUFFER" << i << " = " << draw_buffer << "\n";
+                attachment = GL_COLOR_ATTACHMENT0;
+            }
+            GLint alpha_size = 0;
+            glGetFramebufferAttachmentParameteriv(target, attachment,
+                                                  GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+                                                  &alpha_size);
+            GLenum format = alpha_size ? GL_RGBA : GL_RGB;
+            dumpFramebufferAttachment(json, context, target, attachment, format);
+        }
+    }
+
+    glReadBuffer(read_buffer);
+
+    if (!context.ES) {
+        dumpFramebufferAttachment(json, context, target, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT);
+        dumpFramebufferAttachment(json, context, target, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX);
+    }
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer);
+}
+
+
+void
+dumpFramebuffer(JSONWriter &json, Context &context)
+{
+    json.beginMember("framebuffer");
+    json.beginObject();
+
+    GLint boundDrawFbo = 0, boundReadFbo = 0;
+    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundDrawFbo);
+    glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundReadFbo);
+    if (!boundDrawFbo) {
+        dumpDrawableImages(json, context);
+    } else if (context.ES) {
+        dumpFramebufferAttachments(json, context, GL_FRAMEBUFFER);
+    } else {
+        GLint colorRb = 0, stencilRb = 0, depthRb = 0;
+        GLint draw_buffer0 = GL_NONE;
+        glGetIntegerv(GL_DRAW_BUFFER0, &draw_buffer0);
+        bool multisample = false;
+
+        GLint boundRb = 0;
+        glGetIntegerv(GL_RENDERBUFFER_BINDING, &boundRb);
+
+        GLint object_type;
+        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
+        if (object_type == GL_RENDERBUFFER) {
+            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, draw_buffer0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &colorRb);
+            glBindRenderbuffer(GL_RENDERBUFFER, colorRb);
+            GLint samples = 0;
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
+            if (samples) {
+                multisample = true;
+            }
+        }
+
+        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
+        if (object_type == GL_RENDERBUFFER) {
+            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthRb);
+            glBindRenderbuffer(GL_RENDERBUFFER, depthRb);
+            GLint samples = 0;
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
+            if (samples) {
+                multisample = true;
+            }
+        }
+
+        glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);
+        if (object_type == GL_RENDERBUFFER) {
+            glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &stencilRb);
+            glBindRenderbuffer(GL_RENDERBUFFER, stencilRb);
+            GLint samples = 0;
+            glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
+            if (samples) {
+                multisample = true;
+            }
+        }
+
+        glBindRenderbuffer(GL_RENDERBUFFER, boundRb);
+
+        GLuint rbs[3];
+        GLint numRbs = 0;
+        GLuint fboCopy = 0;
+
+        if (multisample) {
+            // glReadPixels doesnt support multisampled buffers so we need
+            // to blit the fbo to a temporary one
+            fboCopy = downsampledFramebuffer(context,
+                                             boundDrawFbo, draw_buffer0,
+                                             colorRb, depthRb, stencilRb,
+                                             rbs, &numRbs);
+        }
+
+        dumpFramebufferAttachments(json, context, GL_DRAW_FRAMEBUFFER);
+
+        if (multisample) {
+            glBindRenderbuffer(GL_RENDERBUFFER_BINDING, boundRb);
+            glDeleteRenderbuffers(numRbs, rbs);
+            glDeleteFramebuffers(1, &fboCopy);
+        }
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, boundReadFbo);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundDrawFbo);
+    }
+
+    json.endObject();
+    json.endMember(); // framebuffer
+}
+
+
+} /* namespace glstate */
diff --git a/retrace/glstate_internal.hpp b/retrace/glstate_internal.hpp
new file mode 100644 (file)
index 0000000..aab7f98
--- /dev/null
@@ -0,0 +1,71 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _GLSTATE_INTERNAL_HPP_
+#define _GLSTATE_INTERNAL_HPP_
+
+
+#include "glimports.hpp"
+
+
+class JSONWriter;
+
+
+namespace glstate {
+
+
+struct Context
+{
+    bool ES;
+
+    bool ARB_draw_buffers;
+
+    Context(void);
+
+    GLint packAlignment;
+
+    void
+    resetPixelPackState(void);
+
+    void
+    restorePixelPackState(void);
+};
+
+
+void dumpEnum(JSONWriter &json, GLenum pname);
+
+void dumpParameters(JSONWriter &json, Context &context);
+
+void dumpShadersUniforms(JSONWriter &json, Context &context);
+
+void dumpTextures(JSONWriter &json, Context &context);
+
+void dumpFramebuffer(JSONWriter &json, Context &context);
+
+
+} /* namespace glstate */
+
+
+#endif /* _GLSTATE_INTERNAL_HPP_ */
diff --git a/retrace/glstate_params.py b/retrace/glstate_params.py
new file mode 100644 (file)
index 0000000..e1f90d0
--- /dev/null
@@ -0,0 +1,505 @@
+##########################################################################
+#
+# Copyright 2011 Jose Fonseca
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+'''Generate code to dump most GL state into JSON.'''
+
+
+import retrace # to adjust sys.path
+
+from specs.stdapi import *
+
+from specs.gltypes import *
+from specs.glparams import *
+
+
+texture_targets = [
+    ('GL_TEXTURE_1D', 'GL_TEXTURE_BINDING_1D'),
+    ('GL_TEXTURE_2D', 'GL_TEXTURE_BINDING_2D'),
+    ('GL_TEXTURE_3D', 'GL_TEXTURE_BINDING_3D'),
+    ('GL_TEXTURE_RECTANGLE', 'GL_TEXTURE_BINDING_RECTANGLE'),
+    ('GL_TEXTURE_CUBE_MAP', 'GL_TEXTURE_BINDING_CUBE_MAP')
+]
+
+framebuffer_targets = [
+    ('GL_DRAW_FRAMEBUFFER', 'GL_DRAW_FRAMEBUFFER_BINDING'),
+    ('GL_READ_FRAMEBUFFER', 'GL_READ_FRAMEBUFFER_BINDING'),
+]
+
+class GetInflector:
+    '''Objects that describes how to inflect.'''
+
+    reduced_types = {
+        B: I,
+        E: I,
+        I: F,
+    }
+
+    def __init__(self, radical, inflections, suffix = ''):
+        self.radical = radical
+        self.inflections = inflections
+        self.suffix = suffix
+
+    def reduced_type(self, type):
+        if type in self.inflections:
+            return type
+        if type in self.reduced_types:
+            return self.reduced_type(self.reduced_types[type])
+        raise NotImplementedError
+
+    def inflect(self, type):
+        return self.radical + self.inflection(type) + self.suffix
+
+    def inflection(self, type):
+        type = self.reduced_type(type)
+        assert type in self.inflections
+        return self.inflections[type]
+
+    def __str__(self):
+        return self.radical + self.suffix
+
+
+class StateGetter(Visitor):
+    '''Type visitor that is able to extract the state via one of the glGet*
+    functions.
+
+    It will declare any temporary variable
+    '''
+
+    def __init__(self, radical, inflections, suffix=''):
+        self.inflector = GetInflector(radical, inflections)
+        self.suffix = suffix
+
+    def iter(self):
+        for function, type, count, name in parameters:
+            inflection = self.inflector.radical + self.suffix
+            if inflection not in function.split(','):
+                continue
+            if type is X:
+                continue
+            yield type, count, name
+
+    def __call__(self, *args):
+        pname = args[-1]
+
+        for type, count, name in self.iter():
+            if name == pname:
+                if count != 1:
+                    type = Array(type, str(count))
+
+                return type, self.visit(type, args)
+
+        raise NotImplementedError
+
+    def temp_name(self, args):
+        '''Return the name of a temporary variable to hold the state.'''
+        pname = args[-1]
+
+        return pname[3:].lower()
+
+    def visitConst(self, const, args):
+        return self.visit(const.type, args)
+
+    def visitScalar(self, type, args):
+        temp_name = self.temp_name(args)
+        elem_type = self.inflector.reduced_type(type)
+        inflection = self.inflector.inflect(type)
+        if inflection.endswith('v'):
+            print '    %s %s = 0;' % (elem_type, temp_name)
+            print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
+        else:
+            print '    %s %s = %s(%s);' % (elem_type, temp_name, inflection + self.suffix, ', '.join(args))
+        return temp_name
+
+    def visitString(self, string, args):
+        temp_name = self.temp_name(args)
+        inflection = self.inflector.inflect(string)
+        assert not inflection.endswith('v')
+        print '    %s %s = (%s)%s(%s);' % (string, temp_name, string, inflection + self.suffix, ', '.join(args))
+        return temp_name
+
+    def visitAlias(self, alias, args):
+        return self.visitScalar(alias, args)
+
+    def visitEnum(self, enum, args):
+        return self.visit(GLint, args)
+
+    def visitBitmask(self, bitmask, args):
+        return self.visit(GLint, args)
+
+    def visitArray(self, array, args):
+        temp_name = self.temp_name(args)
+        if array.length == '1':
+            return self.visit(array.type)
+        elem_type = self.inflector.reduced_type(array.type)
+        inflection = self.inflector.inflect(array.type)
+        assert inflection.endswith('v')
+        print '    %s %s[%s + 1];' % (elem_type, temp_name, array.length)
+        print '    memset(%s, 0, %s * sizeof *%s);' % (temp_name, array.length, temp_name)
+        print '    %s[%s] = (%s)0xdeadc0de;' % (temp_name, array.length, elem_type)
+        print '    %s(%s, %s);' % (inflection + self.suffix, ', '.join(args), temp_name)
+        # Simple buffer overflow detection
+        print '    assert(%s[%s] == (%s)0xdeadc0de);' % (temp_name, array.length, elem_type)
+        return temp_name
+
+    def visitOpaque(self, pointer, args):
+        temp_name = self.temp_name(args)
+        inflection = self.inflector.inflect(pointer)
+        assert inflection.endswith('v')
+        print '    GLvoid *%s;' % temp_name
+        print '    %s(%s, &%s);' % (inflection + self.suffix, ', '.join(args), temp_name)
+        return temp_name
+
+
+glGet = StateGetter('glGet', {
+    B: 'Booleanv',
+    I: 'Integerv',
+    F: 'Floatv',
+    D: 'Doublev',
+    S: 'String',
+    P: 'Pointerv',
+})
+
+glGetMaterial = StateGetter('glGetMaterial', {I: 'iv', F: 'fv'})
+glGetLight = StateGetter('glGetLight', {I: 'iv', F: 'fv'})
+glGetVertexAttrib = StateGetter('glGetVertexAttrib', {I: 'iv', F: 'fv', D: 'dv', P: 'Pointerv'})
+glGetTexParameter = StateGetter('glGetTexParameter', {I: 'iv', F: 'fv'})
+glGetTexEnv = StateGetter('glGetTexEnv', {I: 'iv', F: 'fv'})
+glGetTexLevelParameter = StateGetter('glGetTexLevelParameter', {I: 'iv', F: 'fv'})
+glGetShader = StateGetter('glGetShaderiv', {I: 'iv'})
+glGetProgram = StateGetter('glGetProgram', {I: 'iv'})
+glGetProgramARB = StateGetter('glGetProgram', {I: 'iv', F: 'fv', S: 'Stringv'}, 'ARB')
+glGetFramebufferAttachmentParameter = StateGetter('glGetFramebufferAttachmentParameter', {I: 'iv'})
+
+
+class JsonWriter(Visitor):
+    '''Type visitor that will dump a value of the specified type through the
+    JSON writer.
+    
+    It expects a previously declared JSONWriter instance named "json".'''
+
+    def visitLiteral(self, literal, instance):
+        if literal.kind == 'Bool':
+            print '    json.writeBool(%s);' % instance
+        elif literal.kind in ('SInt', 'Uint', 'Float', 'Double'):
+            print '    json.writeNumber(%s);' % instance
+        else:
+            raise NotImplementedError
+
+    def visitString(self, string, instance):
+        assert string.length is None
+        print '    json.writeString((const char *)%s);' % instance
+
+    def visitEnum(self, enum, instance):
+        if enum.expr == 'GLenum':
+            print '    dumpEnum(json, %s);' % instance
+        else:
+            print '    json.writeNumber(%s);' % instance
+
+    def visitBitmask(self, bitmask, instance):
+        raise NotImplementedError
+
+    def visitAlias(self, alias, instance):
+        self.visit(alias.type, instance)
+
+    def visitOpaque(self, opaque, instance):
+        print '    json.writeNumber((size_t)%s);' % instance
+
+    __index = 0
+
+    def visitArray(self, array, instance):
+        index = '__i%u' % JsonWriter.__index
+        JsonWriter.__index += 1
+        print '    json.beginArray();'
+        print '    for (unsigned %s = 0; %s < %s; ++%s) {' % (index, index, array.length, index)
+        self.visit(array.type, '%s[%s]' % (instance, index))
+        print '    }'
+        print '    json.endArray();'
+
+
+
+class StateDumper:
+    '''Class to generate code to dump all GL state in JSON format via
+    stdout.'''
+
+    def __init__(self):
+        pass
+
+    def dump(self):
+        print '#include <string.h>'
+        print
+        print '#include "json.hpp"'
+        print '#include "glproc.hpp"'
+        print '#include "glsize.hpp"'
+        print '#include "glstate.hpp"'
+        print '#include "glstate_internal.hpp"'
+        print
+        print 'namespace glstate {'
+        print
+
+        print 'const char *'
+        print 'enumToString(GLenum pname)'
+        print '{'
+        print '    switch (pname) {'
+        for name in GLenum.values:
+            print '    case %s:' % name
+            print '        return "%s";' % name
+        print '    default:'
+        print '        return NULL;'
+        print '    }'
+        print '}'
+        print
+
+        print 'static void'
+        print 'dumpFramebufferAttachementParameters(JSONWriter &json, GLenum target, GLenum attachment)'
+        print '{'
+        self.dump_attachment_parameters('target', 'attachment')
+        print '}'
+        print
+
+        print 'void'
+        print 'dumpEnum(JSONWriter &json, GLenum pname)'
+        print '{'
+        print '    const char *s = enumToString(pname);'
+        print '    if (s) {'
+        print '        json.writeString(s);'
+        print '    } else {'
+        print '        json.writeNumber(pname);'
+        print '    }'
+        print '}'
+        print
+
+        print 'void dumpParameters(JSONWriter &json, Context &context)'
+        print '{'
+        print '    json.beginMember("parameters");'
+        print '    json.beginObject();'
+        
+        self.dump_atoms(glGet)
+        
+        self.dump_material_params()
+        self.dump_light_params()
+        self.dump_vertex_attribs()
+        self.dump_program_params()
+        self.dump_texture_parameters()
+        self.dump_framebuffer_parameters()
+
+        print '    json.endObject();'
+        print '    json.endMember(); // parameters'
+        print '}'
+        print
+        
+        print '} /*namespace glstate */'
+
+    def dump_material_params(self):
+        print '    if (!context.ES) {'
+        for face in ['GL_FRONT', 'GL_BACK']:
+            print '    json.beginMember("%s");' % face
+            print '    json.beginObject();'
+            self.dump_atoms(glGetMaterial, face)
+            print '    json.endObject();'
+        print '    }'
+        print
+
+    def dump_light_params(self):
+        print '    GLint max_lights = 0;'
+        print '    __glGetIntegerv(GL_MAX_LIGHTS, &max_lights);'
+        print '    for (GLint index = 0; index < max_lights; ++index) {'
+        print '        GLenum light = GL_LIGHT0 + index;'
+        print '        if (glIsEnabled(light)) {'
+        print '            char name[32];'
+        print '            snprintf(name, sizeof name, "GL_LIGHT%i", index);'
+        print '            json.beginMember(name);'
+        print '            json.beginObject();'
+        self.dump_atoms(glGetLight, '    GL_LIGHT0 + index')
+        print '            json.endObject();'
+        print '            json.endMember(); // GL_LIGHTi'
+        print '        }'
+        print '    }'
+        print
+
+    def texenv_param_target(self, name):
+        if name == 'GL_TEXTURE_LOD_BIAS':
+           return 'GL_TEXTURE_FILTER_CONTROL'
+        elif name == 'GL_COORD_REPLACE':
+           return 'GL_POINT_SPRITE'
+        else:
+           return 'GL_TEXTURE_ENV'
+
+    def dump_texenv_params(self):
+        for target in ['GL_TEXTURE_ENV', 'GL_TEXTURE_FILTER_CONTROL', 'GL_POINT_SPRITE']:
+            print '    if (!context.ES) {'
+            print '        json.beginMember("%s");' % target
+            print '        json.beginObject();'
+            for _, _, name in glGetTexEnv.iter():
+                if self.texenv_param_target(name) == target:
+                    self.dump_atom(glGetTexEnv, target, name) 
+            print '        json.endObject();'
+            print '    }'
+
+    def dump_vertex_attribs(self):
+        print '    GLint max_vertex_attribs = 0;'
+        print '    __glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attribs);'
+        print '    for (GLint index = 0; index < max_vertex_attribs; ++index) {'
+        print '        char name[32];'
+        print '        snprintf(name, sizeof name, "GL_VERTEX_ATTRIB_ARRAY%i", index);'
+        print '        json.beginMember(name);'
+        print '        json.beginObject();'
+        self.dump_atoms(glGetVertexAttrib, 'index')
+        print '        json.endObject();'
+        print '        json.endMember(); // GL_VERTEX_ATTRIB_ARRAYi'
+        print '    }'
+        print
+
+    program_targets = [
+        'GL_FRAGMENT_PROGRAM_ARB',
+        'GL_VERTEX_PROGRAM_ARB',
+    ]
+
+    def dump_program_params(self):
+        for target in self.program_targets:
+            print '    if (glIsEnabled(%s)) {' % target
+            print '        json.beginMember("%s");' % target
+            print '        json.beginObject();'
+            self.dump_atoms(glGetProgramARB, target)
+            print '        json.endObject();'
+            print '    }'
+
+    def dump_texture_parameters(self):
+        print '    {'
+        print '        GLint active_texture = GL_TEXTURE0;'
+        print '        glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);'
+        print '        GLint max_texture_coords = 0;'
+        print '        glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);'
+        print '        GLint max_combined_texture_image_units = 0;'
+        print '        glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);'
+        print '        GLint max_units = std::min(std::max(max_combined_texture_image_units, max_texture_coords), 2);'
+        print '        for (GLint unit = 0; unit < max_units; ++unit) {'
+        print '            char name[32];'
+        print '            snprintf(name, sizeof name, "GL_TEXTURE%i", unit);'
+        print '            json.beginMember(name);'
+        print '            glActiveTexture(GL_TEXTURE0 + unit);'
+        print '            json.beginObject();'
+        print '            GLboolean enabled;'
+        print '            GLint binding;'
+        print
+        for target, binding in texture_targets:
+            print '            // %s' % target
+            print '            enabled = GL_FALSE;'
+            print '            glGetBooleanv(%s, &enabled);' % target
+            print '            json.writeBoolMember("%s", enabled);' % target
+            print '            binding = 0;'
+            print '            glGetIntegerv(%s, &binding);' % binding
+            print '            json.writeNumberMember("%s", binding);' % binding
+            print '            if (enabled || binding) {'
+            print '                json.beginMember("%s");' % target
+            print '                json.beginObject();'
+            self.dump_atoms(glGetTexParameter, target)
+            print '                if (!context.ES) {'
+            # We only dump the first level parameters
+            self.dump_atoms(glGetTexLevelParameter, target, "0")
+            print '                }'
+            print '                json.endObject();'
+            print '                json.endMember(); // %s' % target
+            print '            }'
+            print
+        print '            if (unit < max_texture_coords) {'
+        self.dump_texenv_params()
+        print '            }'
+        print '            json.endObject();'
+        print '            json.endMember(); // GL_TEXTUREi'
+        print '        }'
+        print '        glActiveTexture(active_texture);'
+        print '    }'
+        print
+
+    def dump_framebuffer_parameters(self):
+        print '    {'
+        print '        GLint max_color_attachments = 0;'
+        print '        glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);'
+        print '        GLint framebuffer;'
+        for target, binding in framebuffer_targets:
+            print '            // %s' % target
+            print '            framebuffer = 0;'
+            print '            glGetIntegerv(%s, &framebuffer);' % binding
+            print '            if (framebuffer) {'
+            print '                json.beginMember("%s");' % target
+            print '                json.beginObject();'
+            print '                for (GLint i = 0; i < max_color_attachments; ++i) {'
+            print '                    GLint color_attachment = GL_COLOR_ATTACHMENT0 + i;'
+            print '                    dumpFramebufferAttachementParameters(json, %s, color_attachment);' % target
+            print '                }'
+            print '                dumpFramebufferAttachementParameters(json, %s, GL_DEPTH_ATTACHMENT);' % target
+            print '                dumpFramebufferAttachementParameters(json, %s, GL_STENCIL_ATTACHMENT);' % target
+            print '                json.endObject();'
+            print '                json.endMember(); // %s' % target
+            print '            }'
+            print
+        print '    }'
+        print
+
+    def dump_attachment_parameters(self, target, attachment):
+        print '            {'
+        print '                GLint object_type = GL_NONE;'
+        print '                glGetFramebufferAttachmentParameteriv(%s, %s, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &object_type);' % (target, attachment)
+        print '                if (object_type != GL_NONE) {'
+        print '                    json.beginMember(enumToString(%s));' % attachment
+        print '                    json.beginObject();'
+        self.dump_atoms(glGetFramebufferAttachmentParameter, target, attachment)
+        print '                    json.endObject();'
+        print '                    json.endMember(); // GL_x_ATTACHMENT'
+        print '                }'
+        print '            }'
+
+    def dump_atoms(self, getter, *args):
+        for _, _, name in getter.iter():
+            self.dump_atom(getter, *(args + (name,))) 
+
+    def dump_atom(self, getter, *args):
+        name = args[-1]
+
+        # Avoid crash on MacOSX
+        # XXX: The right fix would be to look at the support extensions..
+        import platform
+        if name == 'GL_SAMPLER_BINDING' and platform.system() == 'Darwin':
+            return
+
+        print '        // %s' % name
+        print '        {'
+        #print '            assert(glGetError() == GL_NO_ERROR);'
+        type, value = getter(*args)
+        print '            if (glGetError() != GL_NO_ERROR) {'
+        #print '                std::cerr << "warning: %s(%s) failed\\n";' % (inflection, name)
+        print '                while (glGetError() != GL_NO_ERROR) {}'
+        print '            } else {'
+        print '                json.beginMember("%s");' % name
+        JsonWriter().visit(type, value)
+        print '                json.endMember();'
+        print '            }'
+        print '        }'
+        print
+
+
+if __name__ == '__main__':
+    StateDumper().dump()
diff --git a/retrace/glstate_shaders.cpp b/retrace/glstate_shaders.cpp
new file mode 100644 (file)
index 0000000..11286fb
--- /dev/null
@@ -0,0 +1,532 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <sstream>
+
+#include "json.hpp"
+#include "glproc.hpp"
+#include "glsize.hpp"
+#include "glstate.hpp"
+#include "glstate_internal.hpp"
+
+
+namespace glstate {
+
+
+// Mapping from shader type to shader source, used to accumulated the sources
+// of different shaders with same type.
+typedef std::map<std::string, std::string> ShaderMap;
+
+
+static void
+getShaderSource(ShaderMap &shaderMap, GLuint shader)
+{
+    if (!shader) {
+        return;
+    }
+
+    GLint shader_type = 0;
+    glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
+    if (!shader_type) {
+        return;
+    }
+
+    GLint source_length = 0;
+    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
+    if (!source_length) {
+        return;
+    }
+
+    GLchar *source = new GLchar[source_length];
+    GLsizei length = 0;
+    source[0] = 0;
+    glGetShaderSource(shader, source_length, &length, source);
+
+    shaderMap[enumToString(shader_type)] += source;
+
+    delete [] source;
+}
+
+
+static void
+getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
+{
+    if (!shaderObj) {
+        return;
+    }
+
+    GLint object_type = 0;
+    glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &object_type);
+    if (object_type != GL_SHADER_OBJECT_ARB) {
+        return;
+    }
+
+    GLint shader_type = 0;
+    glGetObjectParameterivARB(shaderObj, GL_OBJECT_SUBTYPE_ARB, &shader_type);
+    if (!shader_type) {
+        return;
+    }
+
+    GLint source_length = 0;
+    glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
+    if (!source_length) {
+        return;
+    }
+
+    GLcharARB *source = new GLcharARB[source_length];
+    GLsizei length = 0;
+    source[0] = 0;
+    glGetShaderSource(shaderObj, source_length, &length, source);
+
+    shaderMap[enumToString(shader_type)] += source;
+
+    delete [] source;
+}
+
+
+static inline void
+dumpProgram(JSONWriter &json, GLint program)
+{
+    GLint attached_shaders = 0;
+    glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
+    if (!attached_shaders) {
+        return;
+    }
+
+    ShaderMap shaderMap;
+
+    GLuint *shaders = new GLuint[attached_shaders];
+    GLsizei count = 0;
+    glGetAttachedShaders(program, attached_shaders, &count, shaders);
+    std::sort(shaders, shaders + count);
+    for (GLsizei i = 0; i < count; ++ i) {
+       getShaderSource(shaderMap, shaders[i]);
+    }
+    delete [] shaders;
+
+    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
+        json.beginMember(it->first);
+        json.writeString(it->second);
+        json.endMember();
+    }
+}
+
+
+static inline void
+dumpProgramObj(JSONWriter &json, GLhandleARB programObj)
+{
+    GLint attached_shaders = 0;
+    glGetObjectParameterivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
+    if (!attached_shaders) {
+        return;
+    }
+
+    ShaderMap shaderMap;
+
+    GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
+    GLsizei count = 0;
+    glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
+    std::sort(shaderObjs, shaderObjs + count);
+    for (GLsizei i = 0; i < count; ++ i) {
+       getShaderObjSource(shaderMap, shaderObjs[i]);
+    }
+    delete [] shaderObjs;
+
+    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
+        json.beginMember(it->first);
+        json.writeString(it->second);
+        json.endMember();
+    }
+}
+
+/*
+ * When fetching the uniform name of an array we usually get name[0]
+ * so we need to cut the trailing "[0]" in order to properly construct
+ * array names later. Otherwise we endup with stuff like
+ * uniformArray[0][0],
+ * uniformArray[0][1],
+ * instead of
+ * uniformArray[0],
+ * uniformArray[1].
+ */
+static std::string
+resolveUniformName(const GLchar *name,  GLint size)
+{
+    std::string qualifiedName(name);
+    if (size > 1) {
+        std::string::size_type nameLength = qualifiedName.length();
+        static const char * const arrayStart = "[0]";
+        static const int arrayStartLen = 3;
+        if (qualifiedName.rfind(arrayStart) == (nameLength - arrayStartLen)) {
+            qualifiedName = qualifiedName.substr(0, nameLength - 3);
+        }
+    }
+    return qualifiedName;
+}
+
+static void
+dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
+    GLenum elemType;
+    GLint numElems;
+    __gl_uniform_size(type, elemType, numElems);
+    if (elemType == GL_NONE) {
+        return;
+    }
+
+    GLfloat fvalues[4*4];
+    GLdouble dvalues[4*4];
+    GLint ivalues[4*4];
+    GLuint uivalues[4*4];
+
+    GLint i, j;
+
+    std::string qualifiedName = resolveUniformName(name, size);
+
+    for (i = 0; i < size; ++i) {
+        std::stringstream ss;
+        ss << qualifiedName;
+
+        if (size > 1) {
+            ss << '[' << i << ']';
+        }
+
+        std::string elemName = ss.str();
+
+        json.beginMember(elemName);
+
+        GLint location = glGetUniformLocation(program, elemName.c_str());
+
+        if (numElems > 1) {
+            json.beginArray();
+        }
+
+        switch (elemType) {
+        case GL_FLOAT:
+            glGetUniformfv(program, location, fvalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(fvalues[j]);
+            }
+            break;
+        case GL_DOUBLE:
+            glGetUniformdv(program, location, dvalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(dvalues[j]);
+            }
+            break;
+        case GL_INT:
+            glGetUniformiv(program, location, ivalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(ivalues[j]);
+            }
+            break;
+        case GL_UNSIGNED_INT:
+            glGetUniformuiv(program, location, uivalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(uivalues[j]);
+            }
+            break;
+        case GL_BOOL:
+            glGetUniformiv(program, location, ivalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeBool(ivalues[j]);
+            }
+            break;
+        default:
+            assert(0);
+            break;
+        }
+
+        if (numElems > 1) {
+            json.endArray();
+        }
+
+        json.endMember();
+    }
+}
+
+
+static void
+dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
+
+    GLenum elemType;
+    GLint numElems;
+    __gl_uniform_size(type, elemType, numElems);
+    if (elemType == GL_NONE) {
+        return;
+    }
+
+    GLfloat fvalues[4*4];
+    GLint ivalues[4*4];
+
+    GLint i, j;
+
+    std::string qualifiedName = resolveUniformName(name, size);
+
+    for (i = 0; i < size; ++i) {
+        std::stringstream ss;
+        ss << qualifiedName;
+
+        if (size > 1) {
+            ss << '[' << i << ']';
+        }
+
+        std::string elemName = ss.str();
+
+        json.beginMember(elemName);
+
+        GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
+
+        if (numElems > 1) {
+            json.beginArray();
+        }
+
+        switch (elemType) {
+        case GL_DOUBLE:
+            // glGetUniformdvARB does not exists
+        case GL_FLOAT:
+            glGetUniformfvARB(programObj, location, fvalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(fvalues[j]);
+            }
+            break;
+        case GL_UNSIGNED_INT:
+            // glGetUniformuivARB does not exists
+        case GL_INT:
+            glGetUniformivARB(programObj, location, ivalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeNumber(ivalues[j]);
+            }
+            break;
+        case GL_BOOL:
+            glGetUniformivARB(programObj, location, ivalues);
+            for (j = 0; j < numElems; ++j) {
+                json.writeBool(ivalues[j]);
+            }
+            break;
+        default:
+            assert(0);
+            break;
+        }
+
+        if (numElems > 1) {
+            json.endArray();
+        }
+
+        json.endMember();
+    }
+}
+
+
+static inline void
+dumpProgramUniforms(JSONWriter &json, GLint program)
+{
+    GLint active_uniforms = 0;
+    glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
+    if (!active_uniforms) {
+        return;
+    }
+
+    GLint active_uniform_max_length = 0;
+    glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
+    GLchar *name = new GLchar[active_uniform_max_length];
+    if (!name) {
+        return;
+    }
+
+    for (GLint index = 0; index < active_uniforms; ++index) {
+        GLsizei length = 0;
+        GLint size = 0;
+        GLenum type = GL_NONE;
+        glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
+
+        dumpUniform(json, program, size, type, name);
+    }
+
+    delete [] name;
+}
+
+
+static inline void
+dumpProgramObjUniforms(JSONWriter &json, GLhandleARB programObj)
+{
+    GLint active_uniforms = 0;
+    glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
+    if (!active_uniforms) {
+        return;
+    }
+
+    GLint active_uniform_max_length = 0;
+    glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
+    GLchar *name = new GLchar[active_uniform_max_length];
+    if (!name) {
+        return;
+    }
+
+    for (GLint index = 0; index < active_uniforms; ++index) {
+        GLsizei length = 0;
+        GLint size = 0;
+        GLenum type = GL_NONE;
+        glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
+
+        dumpUniformARB(json, programObj, size, type, name);
+    }
+
+    delete [] name;
+}
+
+
+static inline void
+dumpArbProgram(JSONWriter &json, GLenum target)
+{
+    if (!glIsEnabled(target)) {
+        return;
+    }
+
+    GLint program_length = 0;
+    glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
+    if (!program_length) {
+        return;
+    }
+
+    GLchar *source = new GLchar[program_length + 1];
+    source[0] = 0;
+    glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
+    source[program_length] = 0;
+
+    json.beginMember(enumToString(target));
+    json.writeString(source);
+    json.endMember();
+
+    delete [] source;
+}
+
+
+static inline void
+dumpArbProgramUniforms(JSONWriter &json, GLenum target, const char *prefix)
+{
+    if (!glIsEnabled(target)) {
+        return;
+    }
+
+    GLint program_parameters = 0;
+    glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
+    if (!program_parameters) {
+        return;
+    }
+
+    GLint max_program_local_parameters = 0;
+    glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
+    for (GLint index = 0; index < max_program_local_parameters; ++index) {
+        GLdouble params[4] = {0, 0, 0, 0};
+        glGetProgramLocalParameterdvARB(target, index, params);
+
+        if (!params[0] && !params[1] && !params[2] && !params[3]) {
+            continue;
+        }
+
+        char name[256];
+        snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index);
+
+        json.beginMember(name);
+        json.beginArray();
+        json.writeNumber(params[0]);
+        json.writeNumber(params[1]);
+        json.writeNumber(params[2]);
+        json.writeNumber(params[3]);
+        json.endArray();
+        json.endMember();
+    }
+
+    GLint max_program_env_parameters = 0;
+    glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
+    for (GLint index = 0; index < max_program_env_parameters; ++index) {
+        GLdouble params[4] = {0, 0, 0, 0};
+        glGetProgramEnvParameterdvARB(target, index, params);
+
+        if (!params[0] && !params[1] && !params[2] && !params[3]) {
+            continue;
+        }
+
+        char name[256];
+        snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index);
+
+        json.beginMember(name);
+        json.beginArray();
+        json.writeNumber(params[0]);
+        json.writeNumber(params[1]);
+        json.writeNumber(params[2]);
+        json.writeNumber(params[3]);
+        json.endArray();
+        json.endMember();
+    }
+}
+
+
+void
+dumpShadersUniforms(JSONWriter &json, Context &context)
+{
+    GLint program = 0;
+    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
+
+    GLhandleARB programObj = 0;
+    if (!context.ES && !program) {
+        programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
+    }
+
+    json.beginMember("shaders");
+    json.beginObject();
+    if (program) {
+        dumpProgram(json, program);
+    } else if (programObj) {
+        dumpProgramObj(json, programObj);
+    } else {
+        dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
+        dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
+    }
+    json.endObject();
+    json.endMember(); // shaders
+
+    json.beginMember("uniforms");
+    json.beginObject();
+    if (program) {
+        dumpProgramUniforms(json, program);
+    } else if (programObj) {
+        dumpProgramObjUniforms(json, programObj);
+    } else {
+        dumpArbProgramUniforms(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
+        dumpArbProgramUniforms(json, GL_VERTEX_PROGRAM_ARB, "vp.");
+    }
+    json.endObject();
+    json.endMember(); // uniforms
+}
+
+
+} /* namespace glstate */
diff --git a/retrace/glws.cpp b/retrace/glws.cpp
new file mode 100644 (file)
index 0000000..c5c41eb
--- /dev/null
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "glws.hpp"
+
+
+namespace glws {
+
+
+bool debug = true;
+
+
+bool
+checkExtension(const char *extName, const char *extString)
+{
+   const char *p = extString;
+   const char *q = extName;
+   char c;
+   do {
+       c = *p++;
+       if (c == '\0' || c == ' ') {
+           if (q && *q == '\0') {
+               return true;
+           } else {
+               q = extName;
+           }
+       } else {
+           if (q && *q == c) {
+               ++q;
+           } else {
+               q = 0;
+           }
+       }
+   } while (c);
+   return false;
+}
+
+
+} /* namespace glws */
diff --git a/retrace/glws.hpp b/retrace/glws.hpp
new file mode 100644 (file)
index 0000000..9afebf4
--- /dev/null
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Abstraction for GL window system specific APIs (GLX, WGL).
+ */
+
+#ifndef _GLWS_HPP_
+#define _GLWS_HPP_
+
+
+#include <vector>
+
+
+namespace glws {
+
+
+enum Profile {
+    PROFILE_COMPAT = 0,
+    PROFILE_CORE,
+    PROFILE_ES1,
+    PROFILE_ES2,
+    PROFILE_MAX
+};
+
+
+extern bool debug;
+
+
+bool
+checkExtension(const char *extName, const char *extString);
+
+
+template< class T >
+class Attributes {
+protected:
+    std::vector<T> attribs;
+
+public:
+    void add(T param) {
+        attribs.push_back(param);
+    }
+
+    void add(T pname, T pvalue) {
+        add(pname);
+        add(pvalue);
+    }
+
+    void end(T terminator = 0) {
+        add(terminator);
+    }
+
+    operator T * (void) {
+        return &attribs[0];
+    }
+
+    operator const T * (void) const {
+        return &attribs[0];
+    }
+};
+
+
+class Visual
+{
+public:
+    unsigned long redMask;
+    unsigned long greenMask;
+    unsigned long blueMask;
+    unsigned long alphaMask;
+    bool doubleBuffer;
+
+    virtual ~Visual() {}
+};
+
+
+class Drawable
+{
+public:
+    const Visual *visual;
+    int width;
+    int height;
+    bool visible;
+
+    Drawable(const Visual *vis, int w, int h) :
+        visual(vis),
+        width(w),
+        height(h),
+        visible(false)
+    {}
+
+    virtual ~Drawable() {}
+    
+    virtual void
+    resize(int w, int h) {
+        width = w;
+        height = h;
+    }
+
+    virtual void
+    show(void) {
+        visible = true;
+    }
+
+    virtual void swapBuffers(void) = 0;
+};
+
+
+class Context
+{
+public:
+    const Visual *visual;
+    Profile profile;
+    
+    Context(const Visual *vis, Profile prof) :
+        visual(vis),
+        profile(prof)
+    {}
+
+    virtual ~Context() {}
+};
+
+
+void
+init(void);
+
+void
+cleanup(void);
+
+Visual *
+createVisual(bool doubleBuffer = false, Profile profile = PROFILE_COMPAT);
+
+Drawable *
+createDrawable(const Visual *visual, int width = 32, int height = 32);
+
+Context *
+createContext(const Visual *visual, Context *shareContext = 0, Profile profile = PROFILE_COMPAT);
+
+bool
+makeCurrent(Drawable *drawable, Context *context);
+
+bool
+processEvents(void);
+
+
+} /* namespace glws */
+
+
+#endif /* _GLWS_HPP_ */
diff --git a/retrace/glws_cocoa.mm b/retrace/glws_cocoa.mm
new file mode 100644 (file)
index 0000000..7f696fa
--- /dev/null
@@ -0,0 +1,270 @@
+/**************************************************************************
+ *
+ * Copyright 2011 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/**
+ * Minimal Cocoa integration.
+ *
+ * See also:
+ * - http://developer.apple.com/library/mac/#samplecode/CocoaGL/Introduction/Intro.html
+ * - http://developer.apple.com/library/mac/#samplecode/Cocoa_With_Carbon_or_CPP/Introduction/Intro.html
+ * - http://developer.apple.com/library/mac/#samplecode/glut/Introduction/Intro.html
+ * - http://developer.apple.com/library/mac/#samplecode/GLEssentials/Introduction/Intro.html
+ * - http://www.glfw.org/
+ */
+
+
+#include <stdlib.h>
+#include <iostream>
+
+#include <Cocoa/Cocoa.h>
+
+#include "glws.hpp"
+
+
+namespace glws {
+
+
+NSAutoreleasePool *autoreleasePool = nil;
+
+
+class CocoaVisual : public Visual
+{
+public:
+    NSOpenGLPixelFormat *pixelFormat;
+
+    CocoaVisual(NSOpenGLPixelFormat *pf) :
+        pixelFormat(pf)
+    {}
+
+    ~CocoaVisual() {
+        [pixelFormat release];
+    }
+};
+
+class CocoaDrawable : public Drawable
+{
+public:
+    NSWindow *window;
+    NSOpenGLContext *currentContext;
+
+    CocoaDrawable(const Visual *vis, int w, int h) :
+        Drawable(vis, w, h),
+        currentContext(nil)
+    {
+        NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
+
+        NSRect winRect = NSMakeRect(0, 0, w, h);
+
+        window = [[NSWindow alloc]
+                         initWithContentRect:winRect
+                                   styleMask:NSTitledWindowMask |
+                                             NSClosableWindowMask |
+                                             NSMiniaturizableWindowMask
+                                     backing:NSBackingStoreRetained
+                                       defer:NO];
+        assert(window != nil);
+
+        NSOpenGLView *view = [[NSOpenGLView alloc]
+                              initWithFrame:winRect
+                                pixelFormat:pixelFormat];
+        assert(view != nil);
+
+        [window setContentView:view];
+        [window setTitle:@"glretrace"];
+
+    }
+
+    ~CocoaDrawable() {
+        [window release];
+    }
+
+    void
+    resize(int w, int h) {
+        if (w == width && h == height) {
+            return;
+        }
+
+        [window setContentSize:NSMakeSize(w, h)];
+
+        if (currentContext != nil) {
+            [currentContext update];
+            [window makeKeyAndOrderFront:nil];
+            [currentContext setView:[window contentView]];
+            [currentContext makeCurrentContext];
+        }
+
+        Drawable::resize(w, h);
+    }
+
+    void show(void) {
+        if (visible) {
+            return;
+        }
+
+        // TODO
+
+        Drawable::show();
+    }
+
+    void swapBuffers(void) {
+        if (currentContext != nil) {
+            [currentContext flushBuffer];
+        }
+    }
+};
+
+
+class CocoaContext : public Context
+{
+public:
+    NSOpenGLContext *context;
+
+    CocoaContext(const Visual *vis, Profile prof, NSOpenGLContext *ctx) :
+        Context(vis, prof),
+        context(ctx)
+    {}
+
+    ~CocoaContext() {
+        [context release];
+    }
+};
+
+
+void
+init(void) {
+    [NSApplication sharedApplication];
+
+    autoreleasePool = [[NSAutoreleasePool alloc] init];
+
+    [NSApp finishLaunching];
+}
+
+
+void
+cleanup(void) {
+    [autoreleasePool release];
+}
+
+
+Visual *
+createVisual(bool doubleBuffer, Profile profile) {
+    if (profile != PROFILE_COMPAT &&
+        profile != PROFILE_CORE) {
+        return nil;
+    }
+
+    Attributes<NSOpenGLPixelFormatAttribute> attribs;
+
+    attribs.add(NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)1);
+    attribs.add(NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24);
+    if (doubleBuffer) {
+        attribs.add(NSOpenGLPFADoubleBuffer);
+    }
+    attribs.add(NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)1);
+    attribs.add(NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)1);
+    if (profile == PROFILE_CORE) {
+#if CGL_VERSION_1_3
+        attribs.add(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
+#else
+       return NULL;
+#endif
+    }
+    attribs.end();
+
+    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
+                                     initWithAttributes:attribs];
+
+    return new CocoaVisual(pixelFormat);
+}
+
+Drawable *
+createDrawable(const Visual *visual, int width, int height)
+{
+    return new CocoaDrawable(visual, width, height);
+}
+
+Context *
+createContext(const Visual *visual, Context *shareContext, Profile profile)
+{
+    NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
+    NSOpenGLContext *share_context = nil;
+    NSOpenGLContext *context;
+
+    if (profile != PROFILE_COMPAT &&
+        profile != PROFILE_CORE) {
+        return nil;
+    }
+
+    if (shareContext) {
+        share_context = static_cast<CocoaContext*>(shareContext)->context;
+    }
+
+    context = [[NSOpenGLContext alloc]
+               initWithFormat:pixelFormat
+               shareContext:share_context];
+    assert(context != nil);
+
+    return new CocoaContext(visual, profile, context);
+}
+
+bool
+makeCurrent(Drawable *drawable, Context *context)
+{
+    if (!drawable || !context) {
+        [NSOpenGLContext clearCurrentContext];
+    } else {
+        CocoaDrawable *cocoaDrawable = static_cast<CocoaDrawable *>(drawable);
+        CocoaContext *cocoaContext = static_cast<CocoaContext *>(context);
+
+        [cocoaDrawable->window makeKeyAndOrderFront:nil];
+        [cocoaContext->context setView:[cocoaDrawable->window contentView]];
+        [cocoaContext->context makeCurrentContext];
+
+        cocoaDrawable->currentContext = cocoaContext->context;
+    }
+
+    return TRUE;
+}
+
+bool
+processEvents(void) {
+   NSEvent* event;
+
+    do {
+        event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                   untilDate:[NSDate distantPast]
+                                      inMode:NSDefaultRunLoopMode
+                                     dequeue:YES];
+        if (event)
+            [NSApp sendEvent:event];
+    } while (event);
+
+    return true;
+}
+
+
+} /* namespace glws */
diff --git a/retrace/glws_egl_xlib.cpp b/retrace/glws_egl_xlib.cpp
new file mode 100644 (file)
index 0000000..6655781
--- /dev/null
@@ -0,0 +1,441 @@
+/**************************************************************************
+ *
+ * Copyright 2011 LunarG, Inc.
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+#include <dlfcn.h>
+
+#include "glproc.hpp"
+#include "glws.hpp"
+
+
+namespace glws {
+
+
+static Display *display = NULL;
+static EGLDisplay eglDisplay = EGL_NO_DISPLAY;
+static int screen = 0;
+
+
+class EglVisual : public Visual
+{
+public:
+    EGLConfig config;
+    XVisualInfo *visinfo;
+
+    EglVisual() :
+        config(0),
+        visinfo(0)
+    {}
+
+    ~EglVisual() {
+        XFree(visinfo);
+    }
+};
+
+
+static void describeEvent(const XEvent &event) {
+    if (0) {
+        switch (event.type) {
+        case ConfigureNotify:
+            std::cerr << "ConfigureNotify";
+            break;
+        case Expose:
+            std::cerr << "Expose";
+            break;
+        case KeyPress:
+            std::cerr << "KeyPress";
+            break;
+        case MapNotify:
+            std::cerr << "MapNotify";
+            break;
+        case ReparentNotify:
+            std::cerr << "ReparentNotify";
+            break;
+        default:
+            std::cerr << "Event " << event.type;
+        }
+        std::cerr << " " << event.xany.window << "\n";
+    }
+}
+
+class EglDrawable : public Drawable
+{
+public:
+    Window window;
+    EGLSurface surface;
+    EGLint api;
+
+    EglDrawable(const Visual *vis, int w, int h) :
+        Drawable(vis, w, h), api(EGL_OPENGL_ES_API)
+    {
+        XVisualInfo *visinfo = static_cast<const EglVisual *>(visual)->visinfo;
+
+        Window root = RootWindow(display, screen);
+
+        /* window attributes */
+        XSetWindowAttributes attr;
+        attr.background_pixel = 0;
+        attr.border_pixel = 0;
+        attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
+        attr.event_mask = StructureNotifyMask;
+
+        unsigned long mask;
+        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+        int x = 0, y = 0;
+
+        window = XCreateWindow(
+            display, root,
+            x, y, width, height,
+            0,
+            visinfo->depth,
+            InputOutput,
+            visinfo->visual,
+            mask,
+            &attr);
+
+        XSizeHints sizehints;
+        sizehints.x = x;
+        sizehints.y = y;
+        sizehints.width  = width;
+        sizehints.height = height;
+        sizehints.flags = USSize | USPosition;
+        XSetNormalHints(display, window, &sizehints);
+
+        const char *name = "glretrace";
+        XSetStandardProperties(
+            display, window, name, name,
+            None, (char **)NULL, 0, &sizehints);
+
+        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+
+        EGLConfig config = static_cast<const EglVisual *>(visual)->config;
+        surface = eglCreateWindowSurface(eglDisplay, config, (EGLNativeWindowType)window, NULL);
+    }
+
+    void waitForEvent(int type) {
+        XEvent event;
+        do {
+            XWindowEvent(display, window, StructureNotifyMask, &event);
+            describeEvent(event);
+        } while (event.type != type);
+    }
+
+    ~EglDrawable() {
+        eglDestroySurface(eglDisplay, surface);
+        eglWaitClient();
+        XDestroyWindow(display, window);
+        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+    }
+
+    void
+    resize(int w, int h) {
+        if (w == width && h == height) {
+            return;
+        }
+
+        eglWaitClient();
+
+        // We need to ensure that pending events are processed here, and XSync
+        // with discard = True guarantees that, but it appears the limited
+        // event processing we do so far is sufficient
+        //XSync(display, True);
+
+        Drawable::resize(w, h);
+
+        XResizeWindow(display, window, w, h);
+
+        // Tell the window manager to respect the requested size
+        XSizeHints size_hints;
+        size_hints.max_width  = size_hints.min_width  = w;
+        size_hints.max_height = size_hints.min_height = h;
+        size_hints.flags = PMinSize | PMaxSize;
+        XSetWMNormalHints(display, window, &size_hints);
+
+        waitForEvent(ConfigureNotify);
+
+        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+    }
+
+    void show(void) {
+        if (visible) {
+            return;
+        }
+
+        eglWaitClient();
+
+        XMapWindow(display, window);
+
+        waitForEvent(MapNotify);
+
+        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+
+        Drawable::show();
+    }
+
+    void swapBuffers(void) {
+        eglBindAPI(api);
+        eglSwapBuffers(eglDisplay, surface);
+    }
+};
+
+
+class EglContext : public Context
+{
+public:
+    EGLContext context;
+
+    EglContext(const Visual *vis, Profile prof, EGLContext ctx) :
+        Context(vis, prof),
+        context(ctx)
+    {}
+
+    ~EglContext() {
+        eglDestroyContext(eglDisplay, context);
+    }
+};
+
+/**
+ * Load the symbols from the specified shared object into global namespace, so
+ * that they can be later found by dlsym(RTLD_NEXT, ...);
+ */
+static void
+load(const char *filename)
+{
+    if (!dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) {
+        std::cerr << "error: unable to open " << filename << "\n";
+        exit(1);
+    }
+}
+
+void
+init(void) {
+    load("libEGL.so.1");
+
+    display = XOpenDisplay(NULL);
+    if (!display) {
+        std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
+        exit(1);
+    }
+
+    screen = DefaultScreen(display);
+
+    eglDisplay = eglGetDisplay((EGLNativeDisplayType)display);
+    if (eglDisplay == EGL_NO_DISPLAY) {
+        std::cerr << "error: unable to get EGL display\n";
+        XCloseDisplay(display);
+        exit(1);
+    }
+
+    EGLint major, minor;
+    if (!eglInitialize(eglDisplay, &major, &minor)) {
+        std::cerr << "error: unable to initialize EGL display\n";
+        XCloseDisplay(display);
+        exit(1);
+    }
+}
+
+void
+cleanup(void) {
+    if (display) {
+        eglTerminate(eglDisplay);
+        XCloseDisplay(display);
+        display = NULL;
+    }
+}
+
+Visual *
+createVisual(bool doubleBuffer, Profile profile) {
+    EglVisual *visual = new EglVisual();
+    // possible combinations
+    const EGLint api_bits_gl[7] = {
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT,
+        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_ES_BIT,
+    };
+    const EGLint api_bits_gles1[7] = {
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
+        EGL_OPENGL_ES_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT,
+        EGL_OPENGL_ES2_BIT,
+    };
+    const EGLint api_bits_gles2[7] = {
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_ES2_BIT,
+        EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
+        EGL_OPENGL_BIT,
+        EGL_OPENGL_ES_BIT,
+    };
+    const EGLint *api_bits;
+
+    switch(profile) {
+    case PROFILE_COMPAT:
+        api_bits = api_bits_gl;
+        break;
+    case PROFILE_ES1:
+        api_bits = api_bits_gles1;
+        break;
+    case PROFILE_ES2:
+        api_bits = api_bits_gles2;
+        break;
+    default:
+        return NULL;
+    };
+
+    for (int i = 0; i < 7; i++) {
+        Attributes<EGLint> attribs;
+
+        attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
+        attribs.add(EGL_RED_SIZE, 1);
+        attribs.add(EGL_GREEN_SIZE, 1);
+        attribs.add(EGL_BLUE_SIZE, 1);
+        attribs.add(EGL_ALPHA_SIZE, 1);
+        attribs.add(EGL_DEPTH_SIZE, 1);
+        attribs.add(EGL_STENCIL_SIZE, 1);
+        attribs.add(EGL_RENDERABLE_TYPE, api_bits[i]);
+        attribs.end(EGL_NONE);
+
+        EGLint num_configs, vid;
+        if (eglChooseConfig(eglDisplay, attribs, &visual->config, 1, &num_configs) &&
+            num_configs == 1 &&
+            eglGetConfigAttrib(eglDisplay, visual->config, EGL_NATIVE_VISUAL_ID, &vid)) {
+            XVisualInfo templ;
+            int num_visuals;
+
+            templ.visualid = vid;
+            visual->visinfo = XGetVisualInfo(display, VisualIDMask, &templ, &num_visuals);
+            break;
+        }
+    }
+
+    assert(visual->visinfo);
+
+    return visual;
+}
+
+Drawable *
+createDrawable(const Visual *visual, int width, int height)
+{
+    return new EglDrawable(visual, width, height);
+}
+
+Context *
+createContext(const Visual *_visual, Context *shareContext, Profile profile)
+{
+    const EglVisual *visual = static_cast<const EglVisual *>(_visual);
+    EGLContext share_context = EGL_NO_CONTEXT;
+    EGLContext context;
+    Attributes<EGLint> attribs;
+
+    if (shareContext) {
+        share_context = static_cast<EglContext*>(shareContext)->context;
+    }
+
+    EGLint api = eglQueryAPI();
+
+    switch (profile) {
+    case PROFILE_COMPAT:
+        load("libGL.so.1");
+        eglBindAPI(EGL_OPENGL_API);
+        break;
+    case PROFILE_CORE:
+        assert(0);
+        return NULL;
+    case PROFILE_ES1:
+        load("libGLESv1_CM.so.1");
+        eglBindAPI(EGL_OPENGL_ES_API);
+        break;
+    case PROFILE_ES2:
+        load("libGLESv2.so.2");
+        eglBindAPI(EGL_OPENGL_ES_API);
+        attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2);
+        break;
+    default:
+        return NULL;
+    }
+
+    attribs.end(EGL_NONE);
+
+    context = eglCreateContext(eglDisplay, visual->config, share_context, attribs);
+    if (!context)
+        return NULL;
+
+    eglBindAPI(api);
+
+    return new EglContext(visual, profile, context);
+}
+
+bool
+makeCurrent(Drawable *drawable, Context *context)
+{
+    if (!drawable || !context) {
+        return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    } else {
+        EglDrawable *eglDrawable = static_cast<EglDrawable *>(drawable);
+        EglContext *eglContext = static_cast<EglContext *>(context);
+        EGLBoolean ok;
+
+        ok = eglMakeCurrent(eglDisplay, eglDrawable->surface,
+                            eglDrawable->surface, eglContext->context);
+
+        if (ok) {
+            EGLint api;
+
+            eglQueryContext(eglDisplay, eglContext->context,
+                            EGL_CONTEXT_CLIENT_TYPE, &api);
+
+            eglDrawable->api = api;
+        }
+
+        return ok;
+    }
+}
+
+bool
+processEvents(void) {
+    while (XPending(display) > 0) {
+        XEvent event;
+        XNextEvent(display, &event);
+        describeEvent(event);
+    }
+    return true;
+}
+
+
+} /* namespace glws */
diff --git a/retrace/glws_glx.cpp b/retrace/glws_glx.cpp
new file mode 100644 (file)
index 0000000..c151db1
--- /dev/null
@@ -0,0 +1,377 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+#include "glproc.hpp"
+#include "glws.hpp"
+
+
+namespace glws {
+
+
+static Display *display = NULL;
+static int screen = 0;
+
+static unsigned glxVersion = 0;
+static const char *extensions = 0;
+static bool has_GLX_ARB_create_context = false;
+
+
+class GlxVisual : public Visual
+{
+public:
+    GLXFBConfig fbconfig;
+    XVisualInfo *visinfo;
+
+    GlxVisual() :
+        fbconfig(0),
+        visinfo(0)
+    {}
+
+    ~GlxVisual() {
+        XFree(visinfo);
+    }
+};
+
+
+static void describeEvent(const XEvent &event) {
+    if (0) {
+        switch (event.type) {
+        case ConfigureNotify:
+            std::cerr << "ConfigureNotify";
+            break;
+        case Expose:
+            std::cerr << "Expose";
+            break;
+        case KeyPress:
+            std::cerr << "KeyPress";
+            break;
+        case MapNotify:
+            std::cerr << "MapNotify";
+            break;
+        case ReparentNotify:
+            std::cerr << "ReparentNotify";
+            break;
+        default:
+            std::cerr << "Event " << event.type;
+        }
+        std::cerr << " " << event.xany.window << "\n";
+    }
+}
+
+class GlxDrawable : public Drawable
+{
+public:
+    Window window;
+
+    GlxDrawable(const Visual *vis, int w, int h) :
+        Drawable(vis, w, h)
+    {
+        XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
+
+        Window root = RootWindow(display, screen);
+
+        /* window attributes */
+        XSetWindowAttributes attr;
+        attr.background_pixel = 0;
+        attr.border_pixel = 0;
+        attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
+        attr.event_mask = StructureNotifyMask;
+
+        unsigned long mask;
+        mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+        int x = 0, y = 0;
+
+        window = XCreateWindow(
+            display, root,
+            x, y, width, height,
+            0,
+            visinfo->depth,
+            InputOutput,
+            visinfo->visual,
+            mask,
+            &attr);
+
+        XSizeHints sizehints;
+        sizehints.x = x;
+        sizehints.y = y;
+        sizehints.width  = width;
+        sizehints.height = height;
+        sizehints.flags = USSize | USPosition;
+        XSetNormalHints(display, window, &sizehints);
+
+        const char *name = "glretrace";
+        XSetStandardProperties(
+            display, window, name, name,
+            None, (char **)NULL, 0, &sizehints);
+
+        glXWaitX();
+    }
+
+    void waitForEvent(int type) {
+        XEvent event;
+        do {
+            XWindowEvent(display, window, StructureNotifyMask, &event);
+            describeEvent(event);
+        } while (event.type != type);
+    }
+
+    ~GlxDrawable() {
+        XDestroyWindow(display, window);
+    }
+
+    void
+    resize(int w, int h) {
+        if (w == width && h == height) {
+            return;
+        }
+
+        glXWaitGL();
+
+        // We need to ensure that pending events are processed here, and XSync
+        // with discard = True guarantees that, but it appears the limited
+        // event processing we do so far is sufficient
+        //XSync(display, True);
+
+        Drawable::resize(w, h);
+
+        XResizeWindow(display, window, w, h);
+
+        // Tell the window manager to respect the requested size
+        XSizeHints size_hints;
+        size_hints.max_width  = size_hints.min_width  = w;
+        size_hints.max_height = size_hints.min_height = h;
+        size_hints.flags = PMinSize | PMaxSize;
+        XSetWMNormalHints(display, window, &size_hints);
+
+        waitForEvent(ConfigureNotify);
+
+        glXWaitX();
+    }
+
+    void show(void) {
+        if (visible) {
+            return;
+        }
+
+        glXWaitGL();
+
+        XMapWindow(display, window);
+
+        waitForEvent(MapNotify);
+
+        glXWaitX();
+
+        Drawable::show();
+    }
+
+    void swapBuffers(void) {
+        glXSwapBuffers(display, window);
+    }
+};
+
+
+class GlxContext : public Context
+{
+public:
+    GLXContext context;
+
+    GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
+        Context(vis, prof),
+        context(ctx)
+    {}
+
+    ~GlxContext() {
+        glXDestroyContext(display, context);
+    }
+};
+
+void
+init(void) {
+    display = XOpenDisplay(NULL);
+    if (!display) {
+        std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
+        exit(1);
+    }
+
+    screen = DefaultScreen(display);
+
+    int major = 0, minor = 0;
+    glXQueryVersion(display, &major, &minor);
+    glxVersion = (major << 8) | minor;
+
+    extensions = glXQueryExtensionsString(display, screen);
+    has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
+}
+
+void
+cleanup(void) {
+    if (display) {
+        XCloseDisplay(display);
+        display = NULL;
+    }
+}
+
+Visual *
+createVisual(bool doubleBuffer, Profile profile) {
+    if (profile != PROFILE_COMPAT &&
+        profile != PROFILE_CORE) {
+        return NULL;
+    }
+
+    GlxVisual *visual = new GlxVisual;
+
+    if (glxVersion >= 0x0103) {
+        Attributes<int> attribs;
+        attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
+        attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
+        attribs.add(GLX_RED_SIZE, 1);
+        attribs.add(GLX_GREEN_SIZE, 1);
+        attribs.add(GLX_BLUE_SIZE, 1);
+        attribs.add(GLX_ALPHA_SIZE, 1);
+        attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
+        attribs.add(GLX_DEPTH_SIZE, 1);
+        attribs.add(GLX_STENCIL_SIZE, 1);
+        attribs.end();
+
+        int num_configs = 0;
+        GLXFBConfig * fbconfigs;
+        fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
+        assert(num_configs && fbconfigs);
+        visual->fbconfig = fbconfigs[0];
+        assert(visual->fbconfig);
+        visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
+        assert(visual->visinfo);
+    } else {
+        Attributes<int> attribs;
+        attribs.add(GLX_RGBA);
+        attribs.add(GLX_RED_SIZE, 1);
+        attribs.add(GLX_GREEN_SIZE, 1);
+        attribs.add(GLX_BLUE_SIZE, 1);
+        attribs.add(GLX_ALPHA_SIZE, 1);
+        if (doubleBuffer) {
+            attribs.add(GLX_DOUBLEBUFFER);
+        }
+        attribs.add(GLX_DEPTH_SIZE, 1);
+        attribs.add(GLX_STENCIL_SIZE, 1);
+        attribs.end();
+
+        visual->visinfo = glXChooseVisual(display, screen, attribs);
+    }
+
+    return visual;
+}
+
+Drawable *
+createDrawable(const Visual *visual, int width, int height)
+{
+    return new GlxDrawable(visual, width, height);
+}
+
+Context *
+createContext(const Visual *_visual, Context *shareContext, Profile profile)
+{
+    const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
+    GLXContext share_context = NULL;
+    GLXContext context;
+
+    if (shareContext) {
+        share_context = static_cast<GlxContext*>(shareContext)->context;
+    }
+
+    if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
+        Attributes<int> attribs;
+        
+        attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
+        if (debug) {
+            attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
+        }
+
+        switch (profile) {
+        case PROFILE_COMPAT:
+            break;
+        case PROFILE_CORE:
+            // XXX: This will invariable return a 3.2 context, when supported.
+            // We probably should have a PROFILE_CORE_XX per version.
+            attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3);
+            attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2);
+            attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
+            break;
+        default:
+            return NULL;
+        }
+        
+        attribs.end();
+
+        context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
+    } else {
+        if (profile != PROFILE_COMPAT) {
+            return NULL;
+        }
+
+        if (glxVersion >= 0x103) {
+            context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
+        } else {
+            context = glXCreateContext(display, visual->visinfo, share_context, True);
+        }
+    }
+
+    if (!context) {
+        return NULL;
+    }
+
+    return new GlxContext(visual, profile, context);
+}
+
+bool
+makeCurrent(Drawable *drawable, Context *context)
+{
+    if (!drawable || !context) {
+        return glXMakeCurrent(display, None, NULL);
+    } else {
+        GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
+        GlxContext *glxContext = static_cast<GlxContext *>(context);
+
+        return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
+    }
+}
+
+bool
+processEvents(void) {
+    while (XPending(display) > 0) {
+        XEvent event;
+        XNextEvent(display, &event);
+        describeEvent(event);
+    }
+    return true;
+}
+
+
+} /* namespace glws */
diff --git a/retrace/glws_wgl.cpp b/retrace/glws_wgl.cpp
new file mode 100644 (file)
index 0000000..efefff0
--- /dev/null
@@ -0,0 +1,332 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/*
+ * WGL bindings.
+ */
+
+
+#include <iostream>
+
+#include "glproc.hpp"
+#include "glws.hpp"
+
+
+namespace glws {
+
+
+/*
+ * Several WGL functions come in two flavors:
+ * - GDI (ChoosePixelFormat, SetPixelFormat, SwapBuffers, etc)
+ * - WGL (wglChoosePixelFormat, wglSetPixelFormat, wglSwapBuffers, etc)
+ *
+ * The GDI entrypoints will inevitably dispatch to the first module named
+ * "OPENGL32", loading "C:\Windows\System32\opengl32.dll" if none was loaded so
+ * far.
+ *
+ * In order to use a implementation other than the one installed in the system
+ * (when specified via the TRACE_LIBGL environment variable), we need to use
+ * WGL entrypoints.
+ *
+ * See also:
+ * - http://www.opengl.org/archives/resources/faq/technical/mswindows.htm
+ */
+static __PFNWGLCHOOSEPIXELFORMAT pfnChoosePixelFormat = &ChoosePixelFormat;
+static __PFNWGLSETPIXELFORMAT pfnSetPixelFormat = &SetPixelFormat;
+static __PFNWGLSWAPBUFFERS pfnSwapBuffers = &SwapBuffers;
+
+
+static LRESULT CALLBACK
+WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    MINMAXINFO *pMMI;
+    switch (uMsg) {
+    case WM_GETMINMAXINFO:
+        // Allow to create a window bigger than the desktop
+        pMMI = (MINMAXINFO *)lParam;
+        pMMI->ptMaxSize.x = 60000;
+        pMMI->ptMaxSize.y = 60000;
+        pMMI->ptMaxTrackSize.x = 60000;
+        pMMI->ptMaxTrackSize.y = 60000;
+        break;
+    default:
+        break;
+    }
+
+    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+class WglDrawable : public Drawable
+{
+public:
+    DWORD dwExStyle;
+    DWORD dwStyle;
+    HWND hWnd;
+    HDC hDC;
+    PIXELFORMATDESCRIPTOR pfd;
+    int iPixelFormat;
+
+    WglDrawable(const Visual *vis, int width, int height) :
+        Drawable(vis, width, height)
+    {
+        static bool first = TRUE;
+        RECT rect;
+        BOOL bRet;
+
+        if (first) {
+            WNDCLASS wc;
+            memset(&wc, 0, sizeof wc);
+            wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+            wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+            wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+            wc.lpfnWndProc = WndProc;
+            wc.lpszClassName = "glretrace";
+            wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+            RegisterClass(&wc);
+            first = FALSE;
+        }
+
+        dwExStyle = 0;
+        dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
+
+        int x = 0, y = 0;
+
+        rect.left = x;
+        rect.top = y;
+        rect.right = rect.left + width;
+        rect.bottom = rect.top + height;
+
+        AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
+
+        hWnd = CreateWindowEx(dwExStyle,
+                              "glretrace", /* wc.lpszClassName */
+                              NULL,
+                              dwStyle,
+                              0, /* x */
+                              0, /* y */
+                              rect.right - rect.left, /* width */
+                              rect.bottom - rect.top, /* height */
+                              NULL,
+                              NULL,
+                              NULL,
+                              NULL);
+        hDC = GetDC(hWnd);
+   
+        memset(&pfd, 0, sizeof pfd);
+        pfd.cColorBits = 4;
+        pfd.cRedBits = 1;
+        pfd.cGreenBits = 1;
+        pfd.cBlueBits = 1;
+        pfd.cAlphaBits = 1;
+        pfd.cDepthBits = 1;
+        pfd.cStencilBits = 1;
+        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+        pfd.iLayerType = PFD_MAIN_PLANE;
+        pfd.iPixelType = PFD_TYPE_RGBA;
+        pfd.nSize = sizeof(pfd);
+        pfd.nVersion = 1;
+
+        if (visual->doubleBuffer) {
+           pfd.dwFlags |= PFD_DOUBLEBUFFER;
+        }
+
+        iPixelFormat = pfnChoosePixelFormat(hDC, &pfd);
+        if (iPixelFormat <= 0) {
+            std::cerr << "error: ChoosePixelFormat failed\n";
+            exit(1);
+        }
+
+        bRet = pfnSetPixelFormat(hDC, iPixelFormat, &pfd);
+        if (!bRet) {
+            std::cerr << "error: SetPixelFormat failed\n";
+            exit(1);
+        }
+    }
+
+    ~WglDrawable() {
+        ReleaseDC(hWnd, hDC);
+        DestroyWindow(hWnd);
+    }
+    
+    void
+    resize(int w, int h) {
+        if (w == width && h == height) {
+            return;
+        }
+
+        RECT rClient, rWindow;
+        GetClientRect(hWnd, &rClient);
+        GetWindowRect(hWnd, &rWindow);
+        w += (rWindow.right  - rWindow.left) - rClient.right;
+        h += (rWindow.bottom - rWindow.top)  - rClient.bottom;
+        SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
+
+        Drawable::resize(w, h);
+    }
+
+    void show(void) {
+        if (visible) {
+            return;
+        }
+
+        ShowWindow(hWnd, SW_SHOW);
+
+        Drawable::show();
+    }
+
+    void swapBuffers(void) {
+        BOOL bRet;
+        bRet = pfnSwapBuffers(hDC);
+        if (!bRet) {
+            std::cerr << "warning: SwapBuffers failed\n";
+        }
+
+        // Drain message queue to prevent window from being considered
+        // non-responsive
+        MSG msg;
+        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+    }
+};
+
+
+class WglContext : public Context
+{
+public:
+    HGLRC hglrc;
+    WglContext *shareContext;
+
+    WglContext(const Visual *vis, Profile prof, WglContext *share) :
+        Context(vis, prof),
+        hglrc(0),
+        shareContext(share)
+    {}
+
+    ~WglContext() {
+        if (hglrc) {
+            wglDeleteContext(hglrc);
+        }
+    }
+};
+
+
+void
+init(void) {
+    /*
+     * OpenGL library must be loaded by the time we call GDI.
+     */
+
+    const char * libgl_filename = getenv("TRACE_LIBGL");
+
+    if (libgl_filename) {
+        pfnChoosePixelFormat = &wglChoosePixelFormat;
+        pfnSetPixelFormat = &wglSetPixelFormat;
+        pfnSwapBuffers = &wglSwapBuffers;
+    } else {
+        libgl_filename = "OPENGL32";
+    }
+
+    __libGlHandle = LoadLibraryA(libgl_filename);
+    if (!__libGlHandle) {
+        std::cerr << "error: unable to open " << libgl_filename << "\n";
+        exit(1);
+    }
+}
+
+void
+cleanup(void) {
+}
+
+Visual *
+createVisual(bool doubleBuffer, Profile profile) {
+    if (profile != PROFILE_COMPAT) {
+        return NULL;
+    }
+
+    Visual *visual = new Visual();
+
+    visual->doubleBuffer = doubleBuffer;
+
+    return visual;
+}
+
+Drawable *
+createDrawable(const Visual *visual, int width, int height)
+{
+    return new WglDrawable(visual, width, height);
+}
+
+Context *
+createContext(const Visual *visual, Context *shareContext, Profile profile)
+{
+    if (profile != PROFILE_COMPAT) {
+        return NULL;
+    }
+
+    return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
+}
+
+bool
+makeCurrent(Drawable *drawable, Context *context)
+{
+    if (!drawable || !context) {
+        return wglMakeCurrent(NULL, NULL);
+    } else {
+        WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
+        WglContext *wglContext = static_cast<WglContext *>(context);
+
+        if (!wglContext->hglrc) {
+            wglContext->hglrc = wglCreateContext(wglDrawable->hDC);
+            if (!wglContext->hglrc) {
+                std::cerr << "error: wglCreateContext failed\n";
+                exit(1);
+                return false;
+            }
+            if (wglContext->shareContext) {
+                BOOL bRet;
+                bRet = wglShareLists(wglContext->shareContext->hglrc,
+                                     wglContext->hglrc);
+                if (!bRet) {
+                    std::cerr << "warning: wglShareLists failed\n";
+                }
+            }
+        }
+
+        return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
+    }
+}
+
+bool
+processEvents(void) {
+    // TODO
+    return true;
+}
+
+
+} /* namespace glws */
diff --git a/retrace/retrace.cpp b/retrace/retrace.cpp
new file mode 100644 (file)
index 0000000..1630995
--- /dev/null
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+#include <iostream>
+
+#include "os_time.hpp"
+#include "trace_dump.hpp"
+#include "retrace.hpp"
+
+
+namespace retrace {
+
+
+trace::Parser parser;
+
+
+int verbosity = 0;
+bool profiling = false;
+
+
+static bool call_dumped = false;
+
+
+static void dumpCall(trace::Call &call) {
+    if (verbosity >= 0 && !call_dumped) {
+        std::cout << call;
+        std::cout.flush();
+        call_dumped = true;
+    }
+}
+
+
+std::ostream &warning(trace::Call &call) {
+    dumpCall(call);
+
+    std::cerr << call.no << ": ";
+    std::cerr << "warning: ";
+
+    return std::cerr;
+}
+
+
+void ignore(trace::Call &call) {
+    (void)call;
+}
+
+void unsupported(trace::Call &call) {
+    warning(call) << "unsupported " << call.name() << " call\n";
+}
+
+inline void Retracer::addCallback(const Entry *entry) {
+    assert(entry->name);
+    assert(entry->callback);
+    map[entry->name] = entry->callback;
+}
+
+
+void Retracer::addCallbacks(const Entry *entries) {
+    while (entries->name && entries->callback) {
+        addCallback(entries++);
+    }
+}
+
+
+void Retracer::retrace(trace::Call &call) {
+    call_dumped = false;
+
+    if (verbosity >= 1) {
+        if (verbosity >= 2 ||
+            !(call.flags & trace::CALL_FLAG_VERBOSE)) {
+            dumpCall(call);
+        }
+    }
+
+    Callback callback = 0;
+
+    trace::Id id = call.sig->id;
+    if (id >= callbacks.size()) {
+        callbacks.resize(id + 1);
+        callback = 0;
+    } else {
+        callback = callbacks[id];
+    }
+
+    if (!callback) {
+        Map::const_iterator it = map.find(call.name());
+        if (it == map.end()) {
+            callback = &unsupported;
+        } else {
+            callback = it->second;
+        }
+        callbacks[id] = callback;
+    }
+
+    assert(callback);
+    assert(callbacks[id] == callback);
+
+    if (retrace::profiling) {
+        long long startTime = os::getTime();
+        callback(call);
+        long long stopTime = os::getTime();
+        float timeInterval = (stopTime - startTime) * (1.0E6 / os::timeFrequency);
+
+        std::cout
+            << call.no << " "
+            << "[" << timeInterval << " usec] "
+        ;
+        trace::dump(call, std::cout, trace::DUMP_FLAG_NO_CALL_NO | trace::DUMP_FLAG_NO_COLOR);
+    } else {
+        callback(call);
+    }
+}
+
+
+} /* namespace retrace */
diff --git a/retrace/retrace.hpp b/retrace/retrace.hpp
new file mode 100644 (file)
index 0000000..c1e556a
--- /dev/null
@@ -0,0 +1,242 @@
+/**************************************************************************
+ *
+ * Copyright 2011-2012 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _RETRACE_HPP_
+#define _RETRACE_HPP_
+
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <list>
+#include <map>
+#include <ostream>
+
+#include "trace_model.hpp"
+#include "trace_parser.hpp"
+
+
+namespace retrace {
+
+
+extern trace::Parser parser;
+
+
+/**
+ * Handle map.
+ *
+ * It is just like a regular std::map<T, T> container, but lookups of missing
+ * keys return the key instead of default constructor.
+ *
+ * This is necessary for several GL named objects, where one can either request
+ * the implementation to generate an unique name, or pick a value never used
+ * before.
+ *
+ * XXX: In some cases, instead of returning the key, it would make more sense
+ * to return an unused data value (e.g., container count).
+ */
+template <class T>
+class map
+{
+private:
+    typedef std::map<T, T> base_type;
+    base_type base;
+
+public:
+
+    T & operator[] (const T &key) {
+        typename base_type::iterator it;
+        it = base.find(key);
+        if (it == base.end()) {
+            return (base[key] = key);
+        }
+        return it->second;
+    }
+    
+    const T & operator[] (const T &key) const {
+        typename base_type::const_iterator it;
+        it = base.find(key);
+        if (it == base.end()) {
+            return (base[key] = key);
+        }
+        return it->second;
+    }
+};
+
+
+/**
+ * Similar to alloca(), but implemented with malloc.
+ */
+class ScopedAllocator
+{
+private:
+    uintptr_t next;
+
+public:
+    ScopedAllocator() :
+        next(0) {
+    }
+
+    inline void *
+    alloc(size_t size) {
+        if (!size) {
+            return NULL;
+        }
+
+        uintptr_t * buf = static_cast<uintptr_t *>(malloc(sizeof(uintptr_t) + size));
+        if (!buf) {
+            return NULL;
+        }
+
+        *buf = next;
+        next = reinterpret_cast<uintptr_t>(buf);
+        assert((next & 1) == 0);
+
+        return static_cast<void *>(&buf[1]);
+    }
+
+    template< class T >
+    inline T *
+    alloc(size_t n = 1) {
+        return static_cast<T *>(alloc(sizeof(T) * n));
+    }
+
+    /**
+     * Allocate an array with the same dimensions as the specified value.
+     */
+    template< class T >
+    inline T *
+    alloc(const trace::Value *value) {
+        const trace::Array *array = dynamic_cast<const trace::Array *>(value);
+        if (array) {
+            return alloc<T>(array->size());
+        }
+        const trace::Null *null = dynamic_cast<const trace::Null *>(value);
+        if (null) {
+            return NULL;
+        }
+        assert(0);
+        return NULL;
+    }
+
+    /**
+     * Prevent this pointer from being automatically freed.
+     */
+    template< class T >
+    inline void
+    bind(T *ptr) {
+        if (ptr) {
+            reinterpret_cast<uintptr_t *>(ptr)[-1] |= 1;
+        }
+    }
+
+    inline
+    ~ScopedAllocator() {
+        while (next) {
+            uintptr_t temp = *reinterpret_cast<uintptr_t *>(next);
+
+            bool bind = temp & 1;
+            temp &= ~1;
+
+            if (!bind) {
+                free(reinterpret_cast<void *>(next));
+            }
+
+            next = temp;
+        }
+    }
+};
+
+
+void
+addRegion(unsigned long long address, void *buffer, unsigned long long size);
+
+void
+delRegionByPointer(void *ptr);
+
+void *
+toPointer(trace::Value &value, bool bind = false);
+
+
+/**
+ * Output verbosity when retracing files.
+ */
+extern int verbosity;
+
+/**
+ * Add profiling data to the dump when retracing.
+ */
+extern bool profiling;
+
+
+std::ostream &warning(trace::Call &call);
+
+
+void ignore(trace::Call &call);
+void unsupported(trace::Call &call);
+
+
+typedef void (*Callback)(trace::Call &call);
+
+struct Entry {
+    const char *name;
+    Callback callback;
+};
+
+
+struct stringComparer {
+  bool operator() (const char *a, const  char *b) const {
+    return strcmp(a, b) < 0;
+  }
+};
+
+
+extern const Entry stdc_callbacks[];
+
+
+class Retracer
+{
+    typedef std::map<const char *, Callback, stringComparer> Map;
+    Map map;
+
+    std::vector<Callback> callbacks;
+
+public:
+    Retracer() {
+        addCallbacks(stdc_callbacks);
+    }
+
+    virtual ~Retracer() {}
+
+    void addCallback(const Entry *entry);
+    void addCallbacks(const Entry *entries);
+
+    void retrace(trace::Call &call);
+};
+
+
+} /* namespace retrace */
+
+#endif /* _RETRACE_HPP_ */
diff --git a/retrace/retrace.py b/retrace/retrace.py
new file mode 100644 (file)
index 0000000..369c13b
--- /dev/null
@@ -0,0 +1,505 @@
+##########################################################################
+#
+# Copyright 2010 VMware, Inc.
+# All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+##########################################################################/
+
+
+"""Generic retracing code generator."""
+
+
+# Adjust path
+import os.path
+import sys
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+
+
+import specs.stdapi as stdapi
+import specs.glapi as glapi
+
+
+class UnsupportedType(Exception):
+    pass
+
+
+class MutableRebuilder(stdapi.Rebuilder):
+    '''Type visitor which derives a mutable type.'''
+
+    def visitConst(self, const):
+        # Strip out const qualifier
+        return const.type
+
+    def visitAlias(self, alias):
+        # Tear the alias on type changes
+        type = self.visit(alias.type)
+        if type is alias.type:
+            return alias
+        return type
+
+    def visitReference(self, reference):
+        # Strip out references
+        return reference.type
+
+
+def lookupHandle(handle, value):
+    if handle.key is None:
+        return "__%s_map[%s]" % (handle.name, value)
+    else:
+        key_name, key_type = handle.key
+        return "__%s_map[%s][%s]" % (handle.name, key_name, value)
+
+
+class ValueAllocator(stdapi.Visitor):
+
+    def visitLiteral(self, literal, lvalue, rvalue):
+        pass
+
+    def visitConst(self, const, lvalue, rvalue):
+        self.visit(const.type, lvalue, rvalue)
+
+    def visitAlias(self, alias, lvalue, rvalue):
+        self.visit(alias.type, lvalue, rvalue)
+
+    def visitEnum(self, enum, lvalue, rvalue):
+        pass
+
+    def visitBitmask(self, bitmask, lvalue, rvalue):
+        pass
+
+    def visitArray(self, array, lvalue, rvalue):
+        print '    %s = _allocator.alloc<%s>(&%s);' % (lvalue, array.type, rvalue)
+
+    def visitPointer(self, pointer, lvalue, rvalue):
+        print '    %s = _allocator.alloc<%s>(&%s);' % (lvalue, pointer.type, rvalue)
+
+    def visitIntPointer(self, pointer, lvalue, rvalue):
+        pass
+
+    def visitObjPointer(self, pointer, lvalue, rvalue):
+        pass
+
+    def visitLinearPointer(self, pointer, lvalue, rvalue):
+        pass
+
+    def visitReference(self, reference, lvalue, rvalue):
+        self.visit(reference.type, lvalue, rvalue);
+
+    def visitHandle(self, handle, lvalue, rvalue):
+        pass
+
+    def visitBlob(self, blob, lvalue, rvalue):
+        pass
+
+    def visitString(self, string, lvalue, rvalue):
+        pass
+
+    def visitStruct(self, struct, lvalue, rvalue):
+        pass
+
+    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
+        self.visit(polymorphic.defaultType, lvalue, rvalue)
+
+    def visitOpaque(self, opaque, lvalue, rvalue):
+        pass
+
+
+class ValueDeserializer(stdapi.Visitor):
+
+    def visitLiteral(self, literal, lvalue, rvalue):
+        print '    %s = (%s).to%s();' % (lvalue, rvalue, literal.kind)
+
+    def visitConst(self, const, lvalue, rvalue):
+        self.visit(const.type, lvalue, rvalue)
+
+    def visitAlias(self, alias, lvalue, rvalue):
+        self.visit(alias.type, lvalue, rvalue)
+    
+    def visitEnum(self, enum, lvalue, rvalue):
+        print '    %s = static_cast<%s>((%s).toSInt());' % (lvalue, enum, rvalue)
+
+    def visitBitmask(self, bitmask, lvalue, rvalue):
+        self.visit(bitmask.type, lvalue, rvalue)
+
+    def visitArray(self, array, lvalue, rvalue):
+
+        tmp = '__a_' + array.tag + '_' + str(self.seq)
+        self.seq += 1
+
+        print '    if (%s) {' % (lvalue,)
+        print '        const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
+        length = '%s->values.size()' % (tmp,)
+        index = '__j' + array.tag
+        print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
+        try:
+            self.visit(array.type, '%s[%s]' % (lvalue, index), '*%s->values[%s]' % (tmp, index))
+        finally:
+            print '        }'
+            print '    }'
+    
+    def visitPointer(self, pointer, lvalue, rvalue):
+        tmp = '__a_' + pointer.tag + '_' + str(self.seq)
+        self.seq += 1
+
+        print '    if (%s) {' % (lvalue,)
+        print '        const trace::Array *%s = dynamic_cast<const trace::Array *>(&%s);' % (tmp, rvalue)
+        try:
+            self.visit(pointer.type, '%s[0]' % (lvalue,), '*%s->values[0]' % (tmp,))
+        finally:
+            print '    }'
+
+    def visitIntPointer(self, pointer, lvalue, rvalue):
+        print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, pointer, rvalue)
+
+    def visitObjPointer(self, pointer, lvalue, rvalue):
+        old_lvalue = '(%s).toUIntPtr()' % (rvalue,)
+        new_lvalue = '_obj_map[%s]' % (old_lvalue,)
+        print '    if (retrace::verbosity >= 2) {'
+        print '        std::cout << std::hex << "obj 0x" << size_t(%s) << " <- 0x" << size_t(%s) << std::dec <<"\\n";' % (old_lvalue, new_lvalue)
+        print '    }'
+        print '    %s = static_cast<%s>(%s);' % (lvalue, pointer, new_lvalue)
+
+    def visitLinearPointer(self, pointer, lvalue, rvalue):
+        print '    %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, pointer, rvalue)
+
+    def visitReference(self, reference, lvalue, rvalue):
+        self.visit(reference.type, lvalue, rvalue);
+
+    def visitHandle(self, handle, lvalue, rvalue):
+        #OpaqueValueDeserializer().visit(handle.type, lvalue, rvalue);
+        self.visit(handle.type, lvalue, rvalue);
+        new_lvalue = lookupHandle(handle, lvalue)
+        print '    if (retrace::verbosity >= 2) {'
+        print '        std::cout << "%s " << size_t(%s) << " <- " << size_t(%s) << "\\n";' % (handle.name, lvalue, new_lvalue)
+        print '    }'
+        print '    %s = %s;' % (lvalue, new_lvalue)
+    
+    def visitBlob(self, blob, lvalue, rvalue):
+        print '    %s = static_cast<%s>((%s).toPointer());' % (lvalue, blob, rvalue)
+    
+    def visitString(self, string, lvalue, rvalue):
+        print '    %s = (%s)((%s).toString());' % (lvalue, string.expr, rvalue)
+
+    seq = 0
+
+    def visitStruct(self, struct, lvalue, rvalue):
+        tmp = '__s_' + struct.tag + '_' + str(self.seq)
+        self.seq += 1
+
+        print '    const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
+        print '    assert(%s);' % (tmp)
+        for i in range(len(struct.members)):
+            member_type, member_name = struct.members[i]
+            self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
+
+    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
+        self.visit(polymorphic.defaultType, lvalue, rvalue)
+    
+    def visitOpaque(self, opaque, lvalue, rvalue):
+        raise UnsupportedType
+
+
+class OpaqueValueDeserializer(ValueDeserializer):
+    '''Value extractor that also understands opaque values.
+
+    Normally opaque values can't be retraced, unless they are being extracted
+    in the context of handles.'''
+
+    def visitOpaque(self, opaque, lvalue, rvalue):
+        print '    %s = static_cast<%s>(retrace::toPointer(%s));' % (lvalue, opaque, rvalue)
+
+
+class SwizzledValueRegistrator(stdapi.Visitor):
+    '''Type visitor which will register (un)swizzled value pairs, to later be
+    swizzled.'''
+
+    def visitLiteral(self, literal, lvalue, rvalue):
+        pass
+
+    def visitAlias(self, alias, lvalue, rvalue):
+        self.visit(alias.type, lvalue, rvalue)
+    
+    def visitEnum(self, enum, lvalue, rvalue):
+        pass
+
+    def visitBitmask(self, bitmask, lvalue, rvalue):
+        pass
+
+    def visitArray(self, array, lvalue, rvalue):
+        print '    const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (array.tag, rvalue)
+        print '    if (__a%s) {' % (array.tag)
+        length = '__a%s->values.size()' % array.tag
+        index = '__j' + array.tag
+        print '        for (size_t {i} = 0; {i} < {length}; ++{i}) {{'.format(i = index, length = length)
+        try:
+            self.visit(array.type, '%s[%s]' % (lvalue, index), '*__a%s->values[%s]' % (array.tag, index))
+        finally:
+            print '        }'
+            print '    }'
+    
+    def visitPointer(self, pointer, lvalue, rvalue):
+        print '    const trace::Array *__a%s = dynamic_cast<const trace::Array *>(&%s);' % (pointer.tag, rvalue)
+        print '    if (__a%s) {' % (pointer.tag)
+        try:
+            self.visit(pointer.type, '%s[0]' % (lvalue,), '*__a%s->values[0]' % (pointer.tag,))
+        finally:
+            print '    }'
+    
+    def visitIntPointer(self, pointer, lvalue, rvalue):
+        pass
+    
+    def visitObjPointer(self, pointer, lvalue, rvalue):
+        print r'    _obj_map[(%s).toUIntPtr()] = %s;' % (rvalue, lvalue)
+    
+    def visitLinearPointer(self, pointer, lvalue, rvalue):
+        assert pointer.size is not None
+        if pointer.size is not None:
+            print r'    retrace::addRegion((%s).toUIntPtr(), %s, %s);' % (rvalue, lvalue, pointer.size)
+
+    def visitReference(self, reference, lvalue, rvalue):
+        pass
+    
+    def visitHandle(self, handle, lvalue, rvalue):
+        print '    %s __orig_result;' % handle.type
+        OpaqueValueDeserializer().visit(handle.type, '__orig_result', rvalue);
+        if handle.range is None:
+            rvalue = "__orig_result"
+            entry = lookupHandle(handle, rvalue) 
+            print "    %s = %s;" % (entry, lvalue)
+            print '    if (retrace::verbosity >= 2) {'
+            print '        std::cout << "{handle.name} " << {rvalue} << " -> " << {lvalue} << "\\n";'.format(**locals())
+            print '    }'
+        else:
+            i = '__h' + handle.tag
+            lvalue = "%s + %s" % (lvalue, i)
+            rvalue = "__orig_result + %s" % (i,)
+            entry = lookupHandle(handle, rvalue) 
+            print '    for ({handle.type} {i} = 0; {i} < {handle.range}; ++{i}) {{'.format(**locals())
+            print '        {entry} = {lvalue};'.format(**locals())
+            print '        if (retrace::verbosity >= 2) {'
+            print '            std::cout << "{handle.name} " << ({rvalue}) << " -> " << ({lvalue}) << "\\n";'.format(**locals())
+            print '        }'
+            print '    }'
+    
+    def visitBlob(self, blob, lvalue, rvalue):
+        pass
+    
+    def visitString(self, string, lvalue, rvalue):
+        pass
+
+    seq = 0
+
+    def visitStruct(self, struct, lvalue, rvalue):
+        tmp = '__s_' + struct.tag + '_' + str(self.seq)
+        self.seq += 1
+
+        print '    const trace::Struct *%s = dynamic_cast<const trace::Struct *>(&%s);' % (tmp, rvalue)
+        print '    assert(%s);' % (tmp,)
+        print '    (void)%s;' % (tmp,)
+        for i in range(len(struct.members)):
+            member_type, member_name = struct.members[i]
+            self.visit(member_type, '%s.%s' % (lvalue, member_name), '*%s->members[%s]' % (tmp, i))
+    
+    def visitPolymorphic(self, polymorphic, lvalue, rvalue):
+        self.visit(polymorphic.defaultType, lvalue, rvalue)
+    
+    def visitOpaque(self, opaque, lvalue, rvalue):
+        pass
+
+
+class Retracer:
+
+    def retraceFunction(self, function):
+        print 'static void retrace_%s(trace::Call &call) {' % function.name
+        self.retraceFunctionBody(function)
+        print '}'
+        print
+
+    def retraceInterfaceMethod(self, interface, method):
+        print 'static void retrace_%s__%s(trace::Call &call) {' % (interface.name, method.name)
+        self.retraceInterfaceMethodBody(interface, method)
+        print '}'
+        print
+
+    def retraceFunctionBody(self, function):
+        assert function.sideeffects
+
+        self.deserializeArgs(function)
+        
+        self.invokeFunction(function)
+
+        self.swizzleValues(function)
+
+    def retraceInterfaceMethodBody(self, interface, method):
+        assert method.sideeffects
+
+        self.deserializeThisPointer(interface)
+
+        self.deserializeArgs(method)
+        
+        self.invokeInterfaceMethod(interface, method)
+
+        self.swizzleValues(method)
+
+    def deserializeThisPointer(self, interface):
+        print r'    %s *_this;' % (interface.name,)
+        print r'    _this = static_cast<%s *>(_obj_map[call.arg(0).toUIntPtr()]);' % (interface.name,)
+        print r'    if (!_this) {'
+        print r'        retrace::warning(call) << "NULL this pointer\n";'
+        print r'        return;'
+        print r'    }'
+
+    def deserializeArgs(self, function):
+        print '    retrace::ScopedAllocator _allocator;'
+        print '    (void)_allocator;'
+        success = True
+        for arg in function.args:
+            arg_type = MutableRebuilder().visit(arg.type)
+            print '    %s %s;' % (arg_type, arg.name)
+            rvalue = 'call.arg(%u)' % (arg.index,)
+            lvalue = arg.name
+            try:
+                self.extractArg(function, arg, arg_type, lvalue, rvalue)
+            except UnsupportedType:
+                success =  False
+                print '    memset(&%s, 0, sizeof %s); // FIXME' % (arg.name, arg.name)
+            print
+
+        if not success:
+            print '    if (1) {'
+            self.failFunction(function)
+            if function.name[-1].islower():
+                sys.stderr.write('warning: unsupported %s call\n' % function.name)
+            print '    }'
+
+    def swizzleValues(self, function):
+        for arg in function.args:
+            if arg.output:
+                arg_type = MutableRebuilder().visit(arg.type)
+                rvalue = 'call.arg(%u)' % (arg.index,)
+                lvalue = arg.name
+                try:
+                    self.regiterSwizzledValue(arg_type, lvalue, rvalue)
+                except UnsupportedType:
+                    print '    // XXX: %s' % arg.name
+        if function.type is not stdapi.Void:
+            rvalue = '*call.ret'
+            lvalue = '__result'
+            try:
+                self.regiterSwizzledValue(function.type, lvalue, rvalue)
+            except UnsupportedType:
+                raise
+                print '    // XXX: result'
+
+    def failFunction(self, function):
+        print '    if (retrace::verbosity >= 0) {'
+        print '        retrace::unsupported(call);'
+        print '    }'
+        print '    return;'
+
+    def extractArg(self, function, arg, arg_type, lvalue, rvalue):
+        ValueAllocator().visit(arg_type, lvalue, rvalue)
+        if arg.input:
+            ValueDeserializer().visit(arg_type, lvalue, rvalue)
+    
+    def extractOpaqueArg(self, function, arg, arg_type, lvalue, rvalue):
+        try:
+            ValueAllocator().visit(arg_type, lvalue, rvalue)
+        except UnsupportedType:
+            pass
+        OpaqueValueDeserializer().visit(arg_type, lvalue, rvalue)
+
+    def regiterSwizzledValue(self, type, lvalue, rvalue):
+        visitor = SwizzledValueRegistrator()
+        visitor.visit(type, lvalue, rvalue)
+
+    def invokeFunction(self, function):
+        arg_names = ", ".join(function.argNames())
+        if function.type is not stdapi.Void:
+            print '    %s __result;' % (function.type)
+            print '    __result = %s(%s);' % (function.name, arg_names)
+            print '    (void)__result;'
+        else:
+            print '    %s(%s);' % (function.name, arg_names)
+
+    def invokeInterfaceMethod(self, interface, method):
+        arg_names = ", ".join(method.argNames())
+        if method.type is not stdapi.Void:
+            print '    %s __result;' % (method.type)
+            print '    __result = _this->%s(%s);' % (method.name, arg_names)
+            print '    (void)__result;'
+        else:
+            print '    _this->%s(%s);' % (method.name, arg_names)
+
+    def filterFunction(self, function):
+        return True
+
+    table_name = 'retrace::callbacks'
+
+    def retraceApi(self, api):
+
+        print '#include "os_time.hpp"'
+        print '#include "trace_parser.hpp"'
+        print '#include "retrace.hpp"'
+        print
+
+        types = api.getAllTypes()
+        handles = [type for type in types if isinstance(type, stdapi.Handle)]
+        handle_names = set()
+        for handle in handles:
+            if handle.name not in handle_names:
+                if handle.key is None:
+                    print 'static retrace::map<%s> __%s_map;' % (handle.type, handle.name)
+                else:
+                    key_name, key_type = handle.key
+                    print 'static std::map<%s, retrace::map<%s> > __%s_map;' % (key_type, handle.type, handle.name)
+                handle_names.add(handle.name)
+        print
+
+        print 'static std::map<unsigned long long, void *> _obj_map;'
+        print
+
+        functions = filter(self.filterFunction, api.functions)
+        for function in functions:
+            if function.sideeffects:
+                self.retraceFunction(function)
+        interfaces = api.getAllInterfaces()
+        for interface in interfaces:
+            for method in interface.iterMethods():
+                if method.sideeffects:
+                    self.retraceInterfaceMethod(interface, method)
+
+        print 'const retrace::Entry %s[] = {' % self.table_name
+        for function in functions:
+            if function.sideeffects:
+                print '    {"%s", &retrace_%s},' % (function.name, function.name)
+            else:
+                print '    {"%s", &retrace::ignore},' % (function.name,)
+        for interface in interfaces:
+            for method in interface.iterMethods():                
+                if method.sideeffects:
+                    print '    {"%s::%s", &retrace_%s__%s},' % (interface.name, method.name, interface.name, method.name)
+                else:
+                    print '    {"%s::%s", &retrace::ignore},' % (interface.name, method.name)
+        print '    {NULL, NULL}'
+        print '};'
+        print
+
diff --git a/retrace/retrace_stdc.cpp b/retrace/retrace_stdc.cpp
new file mode 100644 (file)
index 0000000..e6b108b
--- /dev/null
@@ -0,0 +1,280 @@
+/**************************************************************************
+ *
+ * Copyright 2011 Jose Fonseca
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <assert.h>
+
+#include <string.h>
+
+
+
+#include "trace_parser.hpp"
+#include "retrace.hpp"
+
+
+namespace retrace {
+
+struct Region
+{
+    void *buffer;
+    unsigned long long size;
+};
+
+typedef std::map<unsigned long long, Region> RegionMap;
+static RegionMap regionMap;
+
+
+static inline bool
+contains(RegionMap::iterator &it, unsigned long long address) {
+    return it->first <= address && (it->first + it->second.size) > address;
+}
+
+
+static inline bool
+intersects(RegionMap::iterator &it, unsigned long long start, unsigned long long size) {
+    unsigned long it_start = it->first;
+    unsigned long it_stop  = it->first + it->second.size;
+    unsigned long stop = start + size;
+    return it_start < stop && start < it_stop;
+}
+
+
+// Iterator to the first region that contains the address, or the first after
+static RegionMap::iterator
+lowerBound(unsigned long long address) {
+    RegionMap::iterator it = regionMap.lower_bound(address);
+
+    while (it != regionMap.begin()) {
+        RegionMap::iterator pred = it;
+        --pred;
+        if (contains(pred, address)) {
+            it = pred;
+        } else {
+            break;
+        }
+    }
+
+    return it;
+}
+
+// Iterator to the first region that starts after the address
+static RegionMap::iterator
+upperBound(unsigned long long address) {
+    RegionMap::iterator it = regionMap.upper_bound(address);
+
+    return it;
+}
+
+void
+addRegion(unsigned long long address, void *buffer, unsigned long long size)
+{
+    if (retrace::verbosity >= 2) {
+        std::cout
+            << "region "
+            << std::hex
+            << "0x" << address << "-0x" << (address + size)
+            << " -> "
+            << "0x" << (uintptr_t)buffer << "-0x" << ((uintptr_t)buffer + size)
+            << std::dec
+            << "\n";
+    }
+
+    if (!address) {
+        // Ignore NULL pointer
+        assert(!buffer);
+        return;
+    }
+
+#ifndef NDEBUG
+    RegionMap::iterator start = lowerBound(address);
+    RegionMap::iterator stop = upperBound(address + size);
+    if (0) {
+        // Forget all regions that intersect this new one.
+        regionMap.erase(start, stop);
+    } else {
+        for (RegionMap::iterator it = start; it != stop; ++it) {
+            std::cerr << std::hex << "warning: "
+                "region 0x" << address << "-0x" << (address + size) << " "
+                "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
+            assert(intersects(it, address, size));
+        }
+    }
+#endif
+
+    assert(buffer);
+
+    Region region;
+    region.buffer = buffer;
+    region.size = size;
+
+    regionMap[address] = region;
+}
+
+static RegionMap::iterator
+lookupRegion(unsigned long long address) {
+    RegionMap::iterator it = regionMap.lower_bound(address);
+
+    if (it == regionMap.end() ||
+        it->first > address) {
+        if (it == regionMap.begin()) {
+            return regionMap.end();
+        } else {
+            --it;
+        }
+    }
+
+    assert(contains(it, address));
+    return it;
+}
+
+void
+delRegion(unsigned long long address) {
+    RegionMap::iterator it = lookupRegion(address);
+    if (it != regionMap.end()) {
+        regionMap.erase(it);
+    } else {
+        assert(0);
+    }
+}
+
+
+void
+delRegionByPointer(void *ptr) {
+    for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
+        if (it->second.buffer == ptr) {
+            regionMap.erase(it);
+            return;
+        }
+    }
+    assert(0);
+}
+
+void *
+lookupAddress(unsigned long long address) {
+    RegionMap::iterator it = lookupRegion(address);
+    if (it != regionMap.end()) {
+        unsigned long long offset = address - it->first;
+        assert(offset < it->second.size);
+        void *addr = (char *)it->second.buffer + offset;
+
+        if (retrace::verbosity >= 2) {
+            std::cout
+                << "region "
+                << std::hex
+                << "0x" << address
+                << " <- "
+                << "0x" << (uintptr_t)addr
+                << std::dec
+                << "\n";
+        }
+
+        return addr;
+    }
+
+    if (address >= 0x00400000) {
+        std::cerr << "warning: could not translate address 0x" << std::hex << address << std::dec << "\n";
+    }
+
+    return (void *)(uintptr_t)address;
+}
+
+
+class Translator : protected trace::Visitor
+{
+protected:
+    bool bind;
+
+    void *result;
+
+    void visit(trace::Null *) {
+        result = NULL;
+    }
+
+    void visit(trace::Blob *blob) {
+        result = blob->toPointer(bind);
+    }
+
+    void visit(trace::Pointer *p) {
+        result = lookupAddress(p->value);
+    }
+
+public:
+    Translator(bool _bind) :
+        bind(_bind),
+        result(NULL)
+    {}
+
+    void * operator() (trace::Value *node) {
+        _visit(node);
+        return result;
+    }
+};
+
+
+void *
+toPointer(trace::Value &value, bool bind) {
+    return Translator(bind) (&value);
+}
+
+
+static void retrace_malloc(trace::Call &call) {
+    size_t size = call.arg(0).toUInt();
+    unsigned long long address = call.ret->toUIntPtr();
+
+    if (!address) {
+        return;
+    }
+
+    void *buffer = malloc(size);
+    if (!buffer) {
+        std::cerr << "error: failed to allocated " << size << " bytes.";
+        return;
+    }
+
+    addRegion(address, buffer, size);
+}
+
+
+static void retrace_memcpy(trace::Call &call) {
+    void * dest = toPointer(call.arg(0));
+    void * src  = toPointer(call.arg(1));
+    size_t n    = call.arg(2).toUInt();
+
+    if (!dest || !src || !n) {
+        return;
+    }
+
+    memcpy(dest, src, n);
+}
+
+
+const retrace::Entry stdc_callbacks[] = {
+    {"malloc", &retrace_malloc},
+    {"memcpy", &retrace_memcpy},
+    {NULL, NULL}
+};
+
+
+} /* retrace */
diff --git a/retrace_stdc.cpp b/retrace_stdc.cpp
deleted file mode 100644 (file)
index e6b108b..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2011 Jose Fonseca
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- **************************************************************************/
-
-
-#include <assert.h>
-
-#include <string.h>
-
-
-
-#include "trace_parser.hpp"
-#include "retrace.hpp"
-
-
-namespace retrace {
-
-struct Region
-{
-    void *buffer;
-    unsigned long long size;
-};
-
-typedef std::map<unsigned long long, Region> RegionMap;
-static RegionMap regionMap;
-
-
-static inline bool
-contains(RegionMap::iterator &it, unsigned long long address) {
-    return it->first <= address && (it->first + it->second.size) > address;
-}
-
-
-static inline bool
-intersects(RegionMap::iterator &it, unsigned long long start, unsigned long long size) {
-    unsigned long it_start = it->first;
-    unsigned long it_stop  = it->first + it->second.size;
-    unsigned long stop = start + size;
-    return it_start < stop && start < it_stop;
-}
-
-
-// Iterator to the first region that contains the address, or the first after
-static RegionMap::iterator
-lowerBound(unsigned long long address) {
-    RegionMap::iterator it = regionMap.lower_bound(address);
-
-    while (it != regionMap.begin()) {
-        RegionMap::iterator pred = it;
-        --pred;
-        if (contains(pred, address)) {
-            it = pred;
-        } else {
-            break;
-        }
-    }
-
-    return it;
-}
-
-// Iterator to the first region that starts after the address
-static RegionMap::iterator
-upperBound(unsigned long long address) {
-    RegionMap::iterator it = regionMap.upper_bound(address);
-
-    return it;
-}
-
-void
-addRegion(unsigned long long address, void *buffer, unsigned long long size)
-{
-    if (retrace::verbosity >= 2) {
-        std::cout
-            << "region "
-            << std::hex
-            << "0x" << address << "-0x" << (address + size)
-            << " -> "
-            << "0x" << (uintptr_t)buffer << "-0x" << ((uintptr_t)buffer + size)
-            << std::dec
-            << "\n";
-    }
-
-    if (!address) {
-        // Ignore NULL pointer
-        assert(!buffer);
-        return;
-    }
-
-#ifndef NDEBUG
-    RegionMap::iterator start = lowerBound(address);
-    RegionMap::iterator stop = upperBound(address + size);
-    if (0) {
-        // Forget all regions that intersect this new one.
-        regionMap.erase(start, stop);
-    } else {
-        for (RegionMap::iterator it = start; it != stop; ++it) {
-            std::cerr << std::hex << "warning: "
-                "region 0x" << address << "-0x" << (address + size) << " "
-                "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
-            assert(intersects(it, address, size));
-        }
-    }
-#endif
-
-    assert(buffer);
-
-    Region region;
-    region.buffer = buffer;
-    region.size = size;
-
-    regionMap[address] = region;
-}
-
-static RegionMap::iterator
-lookupRegion(unsigned long long address) {
-    RegionMap::iterator it = regionMap.lower_bound(address);
-
-    if (it == regionMap.end() ||
-        it->first > address) {
-        if (it == regionMap.begin()) {
-            return regionMap.end();
-        } else {
-            --it;
-        }
-    }
-
-    assert(contains(it, address));
-    return it;
-}
-
-void
-delRegion(unsigned long long address) {
-    RegionMap::iterator it = lookupRegion(address);
-    if (it != regionMap.end()) {
-        regionMap.erase(it);
-    } else {
-        assert(0);
-    }
-}
-
-
-void
-delRegionByPointer(void *ptr) {
-    for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
-        if (it->second.buffer == ptr) {
-            regionMap.erase(it);
-            return;
-        }
-    }
-    assert(0);
-}
-
-void *
-lookupAddress(unsigned long long address) {
-    RegionMap::iterator it = lookupRegion(address);
-    if (it != regionMap.end()) {
-        unsigned long long offset = address - it->first;
-        assert(offset < it->second.size);
-        void *addr = (char *)it->second.buffer + offset;
-
-        if (retrace::verbosity >= 2) {
-            std::cout
-                << "region "
-                << std::hex
-                << "0x" << address
-                << " <- "
-                << "0x" << (uintptr_t)addr
-                << std::dec
-                << "\n";
-        }
-
-        return addr;
-    }
-
-    if (address >= 0x00400000) {
-        std::cerr << "warning: could not translate address 0x" << std::hex << address << std::dec << "\n";
-    }
-
-    return (void *)(uintptr_t)address;
-}
-
-
-class Translator : protected trace::Visitor
-{
-protected:
-    bool bind;
-
-    void *result;
-
-    void visit(trace::Null *) {
-        result = NULL;
-    }
-
-    void visit(trace::Blob *blob) {
-        result = blob->toPointer(bind);
-    }
-
-    void visit(trace::Pointer *p) {
-        result = lookupAddress(p->value);
-    }
-
-public:
-    Translator(bool _bind) :
-        bind(_bind),
-        result(NULL)
-    {}
-
-    void * operator() (trace::Value *node) {
-        _visit(node);
-        return result;
-    }
-};
-
-
-void *
-toPointer(trace::Value &value, bool bind) {
-    return Translator(bind) (&value);
-}
-
-
-static void retrace_malloc(trace::Call &call) {
-    size_t size = call.arg(0).toUInt();
-    unsigned long long address = call.ret->toUIntPtr();
-
-    if (!address) {
-        return;
-    }
-
-    void *buffer = malloc(size);
-    if (!buffer) {
-        std::cerr << "error: failed to allocated " << size << " bytes.";
-        return;
-    }
-
-    addRegion(address, buffer, size);
-}
-
-
-static void retrace_memcpy(trace::Call &call) {
-    void * dest = toPointer(call.arg(0));
-    void * src  = toPointer(call.arg(1));
-    size_t n    = call.arg(2).toUInt();
-
-    if (!dest || !src || !n) {
-        return;
-    }
-
-    memcpy(dest, src, n);
-}
-
-
-const retrace::Entry stdc_callbacks[] = {
-    {"malloc", &retrace_malloc},
-    {"memcpy", &retrace_memcpy},
-    {NULL, NULL}
-};
-
-
-} /* retrace */