Mac 上的 OpenGL 操作

发布于 2024-10-29 06:32:41 字数 241 浏览 1 评论 0原文

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

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

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

This is really architecture question or 'how does it work' question than a problem to solve.

Apple documentation claims that CGL is lowest level api for managing OpenGL contexts, yet is lacks functionality that allows to connect a context to a window.
AGL and Cocoa can bind a context to a window without a problem though, so the question is - how do they do that if they are built upon CGL?

The obvious way appears to be that they use CGL to render to offscreen memory and are then capable of compositing this somehow. If this is so, how does that happen?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

皓月长歌 2024-11-05 06:32:41

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

There is a private function CGLSetSurface that connects a surface that is part of a window to a GL context created with CGLCreateContext. Both AGL and Cocoa use this function internally.

初懵 2024-11-05 06:32:41

完整示例:

/*
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, ®ion);
        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);

}

Complete example:

/*
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, ®ion);
        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);

}
酷到爆炸 2024-11-05 06:32:41

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

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

I didn't revisit the question ever since, this is what I was able to make out of it:
The undocumented api's that float around the net appear to be a missing block from all that - I was able to CGLSetSurface without it returning an error, however it didn't do all that much in the end. Apparently there is some other stuff that needs to be done to make everything work on such a low level.

In all, there doesn't appear to be a sane way to control everything through CGL. The way to handle everything is like everyone else is doing apparently - through Cocoa classes (using CGL for all the stuff other then attaching to window is fine though after that point).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文