windows - cocoa 消息循环? (与 Windows 消息循环相比)

标签 windows cocoa message-loop

在尝试将我的游戏引擎移植到 Mac 时,我偶然发现了一个基本(但很大)的问题。在 Windows 上,我的主要代码如下所示(非常简化):

PeekMessage(...) // check for windows messages
switch (msg.message)
{
case WM_QUIT: ...;
case WM_LBUTTONDOWN: ...;
...
}
TranslateMessage(&msg);
DispatchMessage (&msg);

for (std::vector<CMyBackgroundThread*>::iterator it = mythreads.begin(); it != mythreads.end(); ++it)
{
  (*it)->processEvents();
}

... do other useful stuff like look if the window has resized and other stuff...

drawFrame(); // draw a frame using opengl
SwapBuffers(hDC); // swap backbuffer/frontbuffer

if (g_sleep > 0) Sleep(g_sleep);

我已经读到这不是 mac 方式。 mac 方法正在检查某种事件,例如屏幕的垂直同步以呈现新帧。但如您所见,我想做的不仅仅是渲染,我希望其他线程也能完成工作。有些线程需要比每 1/60 秒更快的速度被调用。 (顺便说一下,我的线程基础结构是:线程将事件放入同步队列,主线程调用 processEvents 处理主线程内同步队列中的项目。这用于网络内容、图像加载/处理内容、perlin 噪声一代,等等……等等……)

我很想能够以类似的方式做到这一点,但关于这方面的信息很少。我不介意将渲染放在垂直同步事件上(我也会在 Windows 上实现它),但我希望对其余代码有更多的响应能力。

这样看:我希望能够在 GPU 处理其他事情的同时处理其余的事情,我不想等待垂直同步然后开始处理应该已经处理过的事情然后才开始向 GPU 发送内容。你明白我的意思吗?

如果我需要从一个完全不同的角度来看这个,请告诉我。

如果我需要为此阅读书籍/指南/教程/任何内容,请告诉我要阅读的内容!

我不是 cocoa 开发人员,我不是 object-c 程序员,我的游戏引擎完全是 C++,但我对 xcode 的了解足以让一个窗口出现并显示我在该窗口中绘制的内容。它只是不像我的 Windows 版本那样更新,因为我不知道如何正确更新。

更新:我什至认为我需要某种循环,即使我想在垂直回溯上同步。 MacOSX 文档上的 OpenGL 编程显示这是通过设置 SwapInterval 来完成的。因此,如果我理解正确的话,在 Mac 上进行实时渲染时,我总是需要某种循环,使用 swapInterval 设置来降低功耗。这是真的吗?

最佳答案

虽然我不是世界上唯一一个试图实现这一目标的人,但似乎没有人愿意回答这个问题(不是针对你们 stackoverflow 的家伙,而是针对知道它是如何工作的 mac 开发人员)。 这就是为什么我想改变这种典型的行为并帮助那些正在寻找同样东西的人。换句话说:我找到了解决方案!我仍然需要进一步改进这段代码,但基本上就是这样了!

1/当你需要一个真正的自己的循环时,就像在windows中一样,你需要自己处理。因此,让 cocoa 构建您的标准代码,但采用 main.m(如有必要,将其更改为 c++ 的 .mm,在本例中是因为我使用了 c++)并删除唯一的一行代码。您将不允许 Cocoa 为您设置您的应用程序/窗口/ View 。

2/Cocoa 通常会为您创建一个 AutoreleasePool。它可以帮助您进行内存管理。现在,这将不再发生,因此您需要对其进行初始化。您在 main 函数中的第一行将是:


    [[NSAutoreleasePool alloc] init];

3/现在您需要设置您的应用程序委托(delegate)。 XCode 向导已经为您设置了一个 AppDelegate 类,因此您只需使用该类即可。此外,该向导已经设置了您的主菜单,并且可能将其命名为 MainMenu.xib。默认的就可以开始了。确保在#import 行之后#import "YourAppDelegate.h"。然后在您的主函数中添加以下代码:


    [NSApplication sharedApplication];
    [NSApp setDelegate:[[[YourAppDelegate alloc] init] autorelease]];
    [NSBundle loadNibNamed:@"MainMenu" owner:[NSApp delegate]];
    [NSApp finishLaunching];

4/Mac OS 现在知道应用程序是关于什么的,将向其添加一个主菜单。无论如何运行它不会做太多事情,因为还没有窗口。让我们创建它:


    [Window setDelegate:[NSApp delegate]];
    [Window setAcceptsMouseMovedEvents:TRUE];
    [Window setIsVisible:TRUE];
    [Window makeKeyAndOrderFront:nil];
    [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask];

为了展示您在这里可以做什么,我添加了一个标题栏并启用了关闭按钮。你可以做更多,但我也需要先研究这个。

5/现在如果你运行它,你可能会幸运地看到一个微秒的窗口,但你可能什么也看不到,因为......程序还没有进入循环。让我们添加一个循环并监听传入的事件:


    bool quit = false;
    while (!quit)
    {
        NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES];
        switch([(NSEvent *)event type])
        {
        case NSKeyDown:
            quit = true;
            break;
        default:
            [NSApp sendEvent:event];
            break;
        }
        [event release];
    }

如果你运行它,你会看到窗口出现,并且它会一直可见,直到你按下一个键。当您按下该键时,应用程序将立即退出。

就是这样!但要小心……查看事件监视器。您将看到您的应用程序正在使用 100% 的 CPU。为什么?因为循环不会将 CPU 置于 sleep 模式。现在由你决定。你可以让自己轻松一点,睡一觉(10000);同时。这会做很多,但不是最佳的。我可能会使用 opengl 的垂直同步来确保 CPU 没有被过度使用,我也会等待来 self 的线程的事件。也许我什至会自己检查过去的时间并计算 sleep 时间以计算每帧的总时间,这样我就有了一个不错的帧率。

有关 Opengl 的帮助:

1/将cocoa.opengl框架添加到项目中。

2/在 [Window...] 之前放置:


    NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs];
    NSOpenGLContext *OGLContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:NULL];
    [format release];

3/在 [Window setDelegate:...] 之后:


    [OGLContext setView:[Window contentView]];

4/在窗口处理之后的某处,放置:


    [OGLContext makeCurrentContext];

5/[事件发布]后,放:


    glClearColor(1, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    [OGLContext flushBuffer];

这将在我的 mac book pro 2011 上以 3300 的帧速率清除您的窗口以完全变红。

同样,这段代码并不完整。当您单击关闭按钮并重新打开它时,它将不再起作用。我可能需要为此 Hook 事件,但我还不知道(经过进一步研究,这些事情可以在 AppDelegate 中完成)。此外,可能还有很多其他事情要做/考虑。但这是一个开始。请随时纠正我/填写我/...

如果我完全正确,我可能会为此设置一个教程网页,如果没有人比我强的话。

希望对大家有帮助!

关于windows - cocoa 消息循环? (与 Windows 消息循环相比),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6649664/

相关文章:

macos - 在swift中添加通知观察者

cocoa - 当进程或应用程序被终止/强制终止时收到通知吗?

c# - 消息循环正在阻塞应用程序

mfc - MFC中的消息循环

php - Wincache 扩展无法在 IIS 上正常工作(它仍然很慢|

regex - 如何使用 Eclipse 或 PowerGREP 搜索和替换文件中的 block ?

objective-c - HelperApp 无法从 PrefPane 读取用户默认值

c++ - 在 WM_CREATE 中创建子窗口,同一线程的相关性?

windows - Windows 上两个网络套接字之间的管道数据

windows - 如何在 Windows 中创建 Chrome 风格的程序自更新?