【问题标题】:OpenGL on Mac operationMac上的OpenGL操作
【发布时间】:2017-06-08 08:07:01
【问题描述】:

这实际上是架构问题或“它是如何工作的”问题,而不是要解决的问题。

Apple 文档声称 CGL 是用于管理 OpenGL 上下文的最低级别 api,但缺少允许将上下文连接到窗口的功能。 AGL 和 Cocoa 可以毫无问题地将上下文绑定到窗口,所以问题是 - 如果它们是基于 CGL 构建的,它们如何做到这一点?

显而易见的方法似乎是他们使用 CGL 渲染到屏幕外内存,然后能够以某种方式合成它。如果是这样,那是怎么发生的?

【问题讨论】:

    标签: cocoa macos opengl


    【解决方案1】:

    有一个私有函数 CGLSetSurface 将作为窗口一部分的表面连接到使用 CGLCreateContext 创建的 GL 上下文。 AGL 和 Cocoa 都在内部使用这个函数。

    【讨论】:

    • 太好了,谢谢。这看起来很不错。对于那些感兴趣的人,这里有一些带有感兴趣签名的链接:linklink。这个值多少钱还有待观察;)
    • @史蒂夫。您是否成功使用了这些未记录的方法?结果如何?
    【解决方案2】:

    完整示例:

    /*
    mkdir -p build/test.app/Contents/MacOS
    clang++ --std=c++11 
     -fno-exceptions
     -fno-rtti
     -mmacosx-version-min=10.9
     -Wno-writable-strings
     -Wno-deprecated-declarations
     -framework OpenGL
     -framework Carbon
     -g gui8.cpp
     -o build/test.app/Contents/MacOS/test
    
    
     */
    
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    #include <ApplicationServices/ApplicationServices.h>
    #include <Carbon/Carbon.h>
    #include <OpenGL/CGLTypes.h>
    #include <OpenGL/CGLCurrent.h>
    #include <OpenGL/OpenGL.h>
    #include <OpenGL/gl.h>
    
    typedef int CGSConnectionID;
    typedef int CGSWindowID;
    typedef int CGSSurfaceID;
    
    typedef uint32_t _CGWindowID;
    
    extern "C" {
    
    typedef int CGSConnection;
    typedef int CGSWindow;
    typedef int CGSValue;
    
    typedef enum _CGSWindowOrderingMode {
       kCGSOrderAbove                =  1, // Window is ordered above target.
       kCGSOrderBelow                = -1, // Window is ordered below target.
       kCGSOrderOut                  =  0  // Window is removed from the on-screen window list.
    } CGSWindowOrderingMode;
    
    typedef void *CGSRegion;
    typedef CGSRegion *CGSRegionRef;
    typedef CGSWindow *CGSWindowRef;
    
    extern CGError CGSNewWindow( CGSConnection cid, int, float, float, const CGSRegion, CGSWindowRef);
    extern CGError CGSNewRegionWithRect( const CGRect * rect, CGSRegionRef newRegion );
    extern OSStatus CGSOrderWindow(CGSConnection cid, CGSWindow win, CGSWindowOrderingMode place, CGSWindow relativeToWindow /* nullable */);
    extern OSStatus CGSSetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue value);
    extern CGSConnectionID CGSMainConnectionID(void);
    extern CGError CGSAddSurface(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID *sid);
    extern CGError CGSSetSurfaceBounds(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID sid, CGRect rect);
    extern CGError CGSOrderSurface(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID sid, int a, int b);
    extern OSStatus CGSMoveWindow(const CGSConnection cid, const CGSWindow wid, CGPoint *point);
    extern CGLError CGLSetSurface(CGLContextObj gl, CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid);
    
    }
    #define kCGSBufferedBackingType 2
    
    
    int main () {
    
        CGLContextObj cgl_context = NULL;
        CGSWindow window = 0;
    
        int width = 500, height = 500;
        CGPoint window_pos = { .x = 200, .y = 200 };
        bool quit = false;
    
        CGSConnectionID connection_id = CGSMainConnectionID();
        assert(connection_id);
    
        {
    
            CGSRegion region = NULL;
            CGRect r = CGRectMake(0,0, width, height);
            auto err1 = CGSNewRegionWithRect(&r, &region);
            assert(region);
            auto err2 = CGSNewWindow(connection_id, kCGSBufferedBackingType, window_pos.x, window_pos.y, region, &window);
            assert(window);
            auto err3 = CGSOrderWindow(connection_id, window, kCGSOrderAbove, 0);
            assert (err3 == kCGErrorSuccess);
    
    
            CGLPixelFormatAttribute attributes[] = {
                kCGLPFADoubleBuffer,
                kCGLPFAAccelerated, // Hardware rendering
                // kCGLPFARendererID, (CGLPixelFormatAttribute) kCGLRendererGenericFloatID, // Software rendering
                (CGLPixelFormatAttribute)0
            };
    
            CGLPixelFormatObj pix;
            GLint num;
            auto err4 = CGLChoosePixelFormat(attributes, &pix, &num);
            assert(err4 == kCGLNoError); // CGLErrorString(err1)
            assert(pix);
    
            CGLCreateContext(pix, NULL, &cgl_context);
            assert(cgl_context);
            CGLDestroyPixelFormat(pix);
            CGLSetCurrentContext(cgl_context);
    
            GLint v_sync_enabled = 1;
            CGLSetParameter(cgl_context, kCGLCPSwapInterval, &v_sync_enabled);
    
            CGSSurfaceID surface_id = 0;
            auto err5 = CGSAddSurface(connection_id, window, &surface_id);
            assert(err5 == kCGErrorSuccess);
            auto err6 = CGSSetSurfaceBounds(connection_id, window, surface_id, CGRectMake(0, 0, width, height));
            assert(err6 == kCGErrorSuccess);
            auto err7 = CGSOrderSurface(connection_id, window, surface_id, 1, 0);
            assert(err7 == kCGErrorSuccess);
    
            auto err8 = CGLSetSurface(cgl_context, connection_id, window, surface_id);
            assert(err8 == kCGLNoError);
    
            GLint drawable = 0;
            CGLGetParameter(cgl_context, kCGLCPHasDrawable, &drawable);
            assert(drawable == 1);
    
    
    
    
        }
    
        assert(glGetError() == GL_NO_ERROR);
    
        CGPoint drag_starting_position;
        bool drag_started = false;
        while (!quit) {
    
            glClearColor(1,1,0,1);
            glClear(GL_COLOR_BUFFER_BIT);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            static float a = 0;
            glRotatef(a * 1000, 0, 0, 1);
            // printf("a: %f\n", a);
            a= a + .001;
            glBegin(GL_QUADS);
            if (a>1.5) a=0;
            glColor4f(0,a,1,1);
            glVertex2f(0.25, 0.25);
            glVertex2f(0.75, 0.25);
            glVertex2f(0.75, 0.75);
            glVertex2f(0.25, 0.75);
            glEnd();
    
            auto err1 = CGLFlushDrawable(cgl_context);
            assert(err1 == kCGLNoError);
    
            assert(glGetError() == GL_NO_ERROR);
    
        }
    
        CGLSetCurrentContext(NULL);
        CGLDestroyContext(cgl_context);
    
    }
    

    【讨论】:

    • 这太不可思议了
    【解决方案3】:

    从那以后我就再也没有重新讨论过这个问题,这就是我能够从中得出的结论: 漂浮在网络上的未记录的 api 似乎是所有这些中的一个缺失块 - 我能够CGLSetSurface 而不返回错误,但它最终并没有做那么多。显然,还需要做一些其他的事情才能让一切都在如此低的水平上运行。

    总而言之,似乎没有一种理智的方式可以通过CGL 控制一切。处理所有事情的方式显然就像其他人所做的一样 - 通过Cocoa classes使用 CGL 处理除附加到窗口之外的所有内容都可以,尽管在那之后)。

    【讨论】:

    • 您实际上可以使用 CGL 完成所有操作,使用更多未记录的 API...您可以使用CGSNewWindow 制作窗口,CGSOrderWindow 将其置于最前面,CGSMoveWindow 用于移动它周围....
    猜你喜欢
    • 2015-04-18
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 2013-09-09
    • 1970-01-01
    相关资源
    最近更新 更多