【发布时间】:2014-12-12 06:14:49
【问题描述】:
上下文
我从事认知科学工作,因此很难传达这个问题的背景。长话短说,我们有一个严重依赖 PyGame 的现存库;我们需要将 SDL2 用于特定的实验性任务。
当我们设计实验时,我们的库扩展了一个基类Exp;它初始化PyGame,有一个简单且经过充分测试的准备序列,然后将控制权交给实验者来完成一组构成实验的抽象方法。
目标: 在切换时,杀死 PyGame 并切换到 SDL2。
问题:以下脚本(SDL2 脚本)在Exp 环境之外使用时有效。但是,当它只改变一点点(实验实现)时,会发生两件事:
- 我们使用 SDL2 加载的图像没有明显绘制(认为 SDL2 窗口可以)
- 引发异常:
CALayer position contains NaN: [nan nan]
当前嫌疑人 Pygame 和 SDL2 正在两个地方争夺命名空间,程序启动时的终端输出证明了这一点:
objc[34300]: Class SDLTranslatorResponder is implemented in both /Library/Frameworks/SDL.framework/Versions/A/SDL and /Library/Frameworks/SDL2.framework/SDL2. One of the two will be used. Which one is undefined.
objc[34300]: Class SDLApplication is implemented in both /Library/Frameworks/SDL2.framework/SDL2 and /Library/Python/2.7/site-packages/pygame/sdlmain_osx.so. One of the two will be used. Which one is undefined.
下面是工作的外部脚本和在我们的 Exp 上下文中实现它的小修改。最后,完整的错误输出在底部。
任何关于这个问题的建议将不胜感激!!!
SDL2 脚本
import sdl2
import sdl2.ext
import numpy
from PIL import Image
import time
import OpenGL.GL as gl
from scipy import misc
import os
stimDisplayRes = (1366,768) #pixel resolution of the stimDisplay
imgs = []
img_path = "path/to/jpgs"
# this loop just grabs our images; works fine in both scripts
for x in range(1, 450):
x = str(int(x * 2.5)).zfill(8)
path = os.path.join(img_path, "{0}.jpg".format(x))
imgs.append(numpy.array(Image.open(path)))
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
stimDisplay = sdl2.ext.Window("Experiment", size=stimDisplayRes,position=(0,0),flags=sdl2.SDL_WINDOW_OPENGL|sdl2.SDL_WINDOW_SHOWN| sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP |sdl2.SDL_RENDERER_ACCELERATED | sdl2.SDL_RENDERER_PRESENTVSYNC)
glContext = sdl2.SDL_GL_CreateContext(stimDisplay.window)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(0, stimDisplayRes[0],stimDisplayRes[1], 0, 0, 1)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glDisable(gl.GL_DEPTH_TEST)
sdl2.SDL_PumpEvents() # to show the windows
time.sleep(1)
def blitNumpy(numpyArray,xLoc,yLoc,xCentered=True,yCentered=True):
gl.glEnable(gl.GL_BLEND)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
ID = gl.glGenTextures(1)
gl.glBindTexture(gl.GL_TEXTURE_2D, ID)
gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_REPLACE);
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
if len(numpyArray.shape)==3: #no alpha channel
gl.glTexImage2D( gl.GL_TEXTURE_2D , 0 , gl.GL_RGBA , numpyArray.shape[1] , numpyArray.shape[0] , 0 , gl.GL_RGB , gl.GL_UNSIGNED_BYTE , numpyArray )
elif len(numpyArray.shape)==4: #alpha channel
gl.glTexImage2D( gl.GL_TEXTURE_2D , 0 , gl.GL_RGBA , numpyArray.shape[1] , numpyArray.shape[0] , 0 , gl.GL_RGBA , gl.GL_UNSIGNED_BYTE , numpyArray )
gl.glEnable(gl.GL_TEXTURE_2D)
gl.glBindTexture(gl.GL_TEXTURE_2D, ID)
gl.glBegin(gl.GL_QUADS)
x1 = xLoc + 1.5 - 0.5
x2 = xLoc + numpyArray.shape[1] - 0.0 + 0.5
y1 = yLoc + 1.0 - 0.5
y2 = yLoc + numpyArray.shape[0] - 0.5 + 0.5
if xCentered:
x1 = x1 - numpyArray.shape[1]/2.0
x2 = x2 - numpyArray.shape[1]/2.0
if yCentered:
y1 = y1 - numpyArray.shape[0]/2.0
y2 = y2 - numpyArray.shape[0]/2.0
gl.glTexCoord2f( 0 , 0 )
gl.glVertex2f( x1 , y1 )
gl.glTexCoord2f( 1 , 0 )
gl.glVertex2f( x2 , y1 )
gl.glTexCoord2f( 1 , 1)
gl.glVertex2f( x2 , y2 )
gl.glTexCoord2f( 0 , 1 )
gl.glVertex2f( x1, y2 )
gl.glEnd()
gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
gl.glDeleteTextures([ID])
del ID
gl.glDisable(gl.GL_TEXTURE_2D)
return None
# this is a little loop we're using to get our "frame rate" right; if this is made to work, I'm good from here
i = 0
j = 0
start = time.time()
while time.time()-start<10:
time.sleep(.01) #pretend to do 5ms of other work per frame
gl.glClearColor(0,0,0,1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
blitNumpy(imgs[i],0,0,xCentered=False,yCentered=False)
sdl2.SDL_GL_SwapWindow(stimDisplay.window)
i+= 1
if i == len(imgs):
i=0
j += 1
print j/(time.time()-start) # we just happen to need this metric
实验实现
我不会重新发布整个脚本;除了这里添加的内容外,我实际上什么都没有改变:
class Experiment(ExpLib.Exp):
first_run = True #
# bunch of methods that don't interact with either PyGame or SDL2—science stuff
def trial(self, trial_factors, trial_num):
if self.first_run:
pygame.quit()
self.first_run = False
time.sleep(0.1) # maybe unnecessary; just giving PyGame a chance to be fully shut down
# this next call wraps the script above; the only difference is that
# blitNumpy becomes self.blitNumpy, and our FPS loop
self.sdl_trial()
# the experiment's code will go here if I can get this to fly
控制台输出
2014-10-16 15:15:18.366 Python[34300:d07] 未捕获的异常是 提出 2014-10-16 15:15:18.366 Python[34300:d07] CALayer 位置 包含 NaN: [nan nan] 2014-10-16 15:15:18.366 Python[34300:d07] (0 核心基础 0x00007fff8fba325c exceptionPreprocess + 172 1 libobjc.A.dylib 0x00007fff86dc3e75 objc_exception_throw + 43 2 CoreFoundation
0x00007fff8fba310c +[NSException raise:format:] + 204 3 QuartzCore 0x00007fff84cc425e _ZN2CA5Layer12set_positionERKNS_4Vec2IdEEb + 158 4 石英核心 0x00007fff84cc41b7 -[CALayer 设置位置:] + 44 5 石英核心
0x00007fff84cc5e97 -[CALayer setFrame:] + 858 6 AppKit
0x00007fff8e5e837e -[_NSFullScreenTransitionOverlayWindow positionLayers] + 1790 7 AppKit
0x00007fff8e5e8e61 -[_NSFullScreenTransitionOverlayWindow startEnterFullScreenAnimationWithDuration:completionHandler:] + 55 8 AppKit 0x00007fff8e5ead76 -[_NSFullScreenTransition _startFullScreenTransitionForCGWindow:targetFrame:duration:completionHandler:] + 193 9 AppKit 0x00007fff8e5ecca6 __89-[_NSFullScreenTransition _performEnterFullScreenModeAnimating:activating:customWindows:]_block_invoke361 + 1430 10 libxpc.dylib 0x00007fff84eafca2 _xpc_connection_reply_callout + 47 11 libxpc.dylib 0x00007fff84eafc2e _xpc_connection_call_reply + 36 12 libdispatch.dylib 0x00007fff869ab2ad _dispatch_client_callout + 8 13 libdispatch.dylib 0x00007fff869b2f03 _dispatch_main_queue_callback_4CF + 333 14 核心基础 0x00007fff8fb0a679 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 9 15 CoreFoundation 0x00007fff8fac5954 CFRunLoopRun + 1636 16 CoreFoundation 0x00007fff8fac50b5 CFRunLoopRunSpecific + 309 17 HIToolbox
0x00007fff85ab9a0d RunCurrentEventLoopInMode + 226 18 HIToolbox
0x00007fff85ab97b7 ReceiveNextEventCommon + 479 19 HIToolbox
0x00007fff85ab95bc _BlockUntilNextEventMatchingListInModeWithFilter + 65 20 应用程序套件 0x00007fff8dd293de _DPSNextEvent + 1434 21 AppKit 0x00007fff8dd28a2b -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122 22 SDL
0x000000011023243c SDL_SoftStretch + 7888 23 SDL
0x0000000110211efd SDL_PumpEvents + 38 24 SDL
0x00000001102120dd SDL_EventState + 200 25 SDL
0x00000001102303f6 SDL_JoystickEventState + 82 26 joystick.so
0x000000011040313d joy_autoinit + 42 27 Python
0x000000010ff18f72 PyObject_Call + 101 28 Python
0x000000010ff9501f PyEval_CallObjectWithKeywords + 93 29 base.so
0x0000000110207c47 初始化 + 279 30 Python
0x000000010ff921ef PyEval_EvalFrameEx + 12338 31 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 32 Python
0x000000010ff36796 PyFunction_SetClosure + 809 33 Python
0x000000010ff18f72 PyObject_Call + 101 34 Python
0x000000010ff239a7 PyMethod_New + 1200 35 Python
0x000000010ff18f72 PyObject_Call + 101 36 Python
0x000000010ff92df5 PyEval_EvalFrameEx + 15416 37 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 38 Python
0x000000010ff36796 PyFunction_SetClosure + 809 39 Python
0x000000010ff18f72 PyObject_Call + 101 40 Python
0x000000010ff239a7 PyMethod_New + 1200 41 Python
0x000000010ff18f72 PyObject_Call + 101 42 Python
0x000000010ff5e6ce _PyObject_SlotCompare + 5565 43 Python
0x000000010ff5a184 _PyType_Lookup + 1343 44 Python
0x000000010ff18f72 PyObject_Call + 101 45 Python
0x000000010ff92df5 PyEval_EvalFrameEx + 15416 46 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 47 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 48 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 49 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 50 Python
0x000000010ff36796 PyFunction_SetClosure + 809 51 Python
0x000000010ff18f72 PyObject_Call + 101 52 Python
0x000000010ff93395 PyEval_EvalFrameEx + 16856 53 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 54 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 55 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 56 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 57 Python
0x000000010ff36796 PyFunction_SetClosure + 809 58 Python
0x000000010ff18f72 PyObject_Call + 101 59 Python
0x000000010ff93395 PyEval_EvalFrameEx + 16856 60 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 61 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 62 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 63 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 64 Python
0x000000010ff8ea24 PyEval_EvalCode + 54 65 Python
0x000000010ffadc2c PyParser_ASTFromFile + 306 66 Python
0x000000010ffadcd3 PyRun_FileExFlags + 137 67 Python
0x000000010ffad821 PyRun_SimpleFileExFlags + 718 68 Python
0x000000010ffbe363 Py_Main + 2995 69 libdyld.dylib
0x00007fff89e375fd 开始 + 1 70 ???
0x0000000000000002 0x0 + 2 ) 2014-10-16 15:15:18.367 Python[34300:d07] *** 由于未捕获的异常“CALayerInvalidGeometry”而终止应用程序,原因:“CALayer 位置包含 NaN:[nan 南]' *** 第一次抛出调用堆栈:( 0 CoreFoundation 0x00007fff8fba325c __exceptionPreprocess + 172 1 libobjc.A.dylib
0x00007fff86dc3e75 objc_exception_throw + 43 2 核心基础
0x00007fff8fba310c +[NSException raise:format:] + 204 3 QuartzCore 0x00007fff84cc425e _ZN2CA5Layer12set_positionERKNS_4Vec2IdEEb + 158 4 石英核心 0x00007fff84cc41b7 -[CALayer 设置位置:] + 44 5 石英核心
0x00007fff84cc5e97 -[CALayer setFrame:] + 858 6 AppKit
0x00007fff8e5e837e -[_NSFullScreenTransitionOverlayWindow positionLayers] + 1790 7 AppKit
0x00007fff8e5e8e61 -[_NSFullScreenTransitionOverlayWindow startEnterFullScreenAnimationWithDuration:completionHandler:] + 55 8 AppKit 0x00007fff8e5ead76 -[_NSFullScreenTransition _startFullScreenTransitionForCGWindow:targetFrame:duration:completionHandler:] + 193 9 AppKit 0x00007fff8e5ecca6 __89-[_NSFullScreenTransition _performEnterFullScreenModeAnimating:activating:customWindows:]_block_invoke361 + 1430 10 libxpc.dylib 0x00007fff84eafca2 _xpc_connection_reply_callout + 47 11 libxpc.dylib 0x00007fff84eafc2e _xpc_connection_call_reply + 36 12 libdispatch.dylib 0x00007fff869ab2ad _dispatch_client_callout + 8 13 libdispatch.dylib 0x00007fff869b2f03 _dispatch_main_queue_callback_4CF + 333 14 核心基础 0x00007fff8fb0a679 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 9 15 核心基础 0x00007fff8fac5954 __CFRunLoopRun + 1636 16 CoreFoundation 0x00007fff8fac50b5 CFRunLoopRunSpecific + 309 17 HIToolbox
0x00007fff85ab9a0d RunCurrentEventLoopInMode + 226 18 HIToolbox
0x00007fff85ab97b7 ReceiveNextEventCommon + 479 19 HIToolbox
0x00007fff85ab95bc _BlockUntilNextEventMatchingListInModeWithFilter + 65 20 应用程序套件 0x00007fff8dd293de _DPSNextEvent + 1434 21 AppKit 0x00007fff8dd28a2b -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122 22 SDL
0x000000011023243c SDL_SoftStretch + 7888 23 SDL
0x0000000110211efd SDL_PumpEvents + 38 24 SDL
0x00000001102120dd SDL_EventState + 200 25 SDL
0x00000001102303f6 SDL_JoystickEventState + 82 26 joystick.so
0x000000011040313d joy_autoinit + 42 27 Python
0x000000010ff18f72 PyObject_Call + 101 28 Python
0x000000010ff9501f PyEval_CallObjectWithKeywords + 93 29 base.so
0x0000000110207c47 初始化 + 279 30 Python
0x000000010ff921ef PyEval_EvalFrameEx + 12338 31 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 32 Python
0x000000010ff36796 PyFunction_SetClosure + 809 33 Python
0x000000010ff18f72 PyObject_Call + 101 34 Python
0x000000010ff239a7 PyMethod_New + 1200 35 Python
0x000000010ff18f72 PyObject_Call + 101 36 Python
0x000000010ff92df5 PyEval_EvalFrameEx + 15416 37 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 38 Python
0x000000010ff36796 PyFunction_SetClosure + 809 39 Python
0x000000010ff18f72 PyObject_Call + 101 40 Python
0x000000010ff239a7 PyMethod_New + 1200 41 Python
0x000000010ff18f72 PyObject_Call + 101 42 Python
0x000000010ff5e6ce _PyObject_SlotCompare + 5565 43 Python
0x000000010ff5a184 _PyType_Lookup + 1343 44 Python
0x000000010ff18f72 PyObject_Call + 101 45 Python
0x000000010ff92df5 PyEval_EvalFrameEx + 15416 46 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 47 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 48 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 49 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 50 Python
0x000000010ff36796 PyFunction_SetClosure + 809 51 Python
0x000000010ff18f72 PyObject_Call + 101 52 Python
0x000000010ff93395 PyEval_EvalFrameEx + 16856 53 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 54 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 55 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 56 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 57 Python
0x000000010ff36796 PyFunction_SetClosure + 809 58 Python
0x000000010ff18f72 PyObject_Call + 101 59 Python
0x000000010ff93395 PyEval_EvalFrameEx + 16856 60 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 61 Python
0x000000010ff958c8 _PyEval_SliceIndex + 929 62 Python
0x000000010ff924d4 PyEval_EvalFrameEx + 13079 63 Python
0x000000010ff8f093 PyEval_EvalCodeEx + 1641 64 Python
0x000000010ff8ea24 PyEval_EvalCode + 54 65 Python
0x000000010ffadc2c PyParser_ASTFromFile + 306 66 Python
0x000000010ffadcd3 PyRun_FileExFlags + 137 67 Python
0x000000010ffad821 PyRun_SimpleFileExFlags + 718 68 Python
0x000000010ffbe363 Py_Main + 2995 69 libdyld.dylib
0x00007fff89e375fd 开始 + 1 70 ???
0x0000000000000002 0x0 + 2 ) libc++abi.dylib: 终止于 NSException 类型的未捕获异常进程以退出代码 13 结束
【问题讨论】:
-
您正在加载
SDL1和SDL2;你不想那样做。 -
是的。我知道。我希望某个书呆子的能力超过我自己(很容易做到)的人可能会鼓起一个黑客或某种变通办法。唉。
-
绕过这个 UB 的唯一“黑客”需要与更新到 pygame2 并放弃 SDL1 一样多的工作,这是您真正需要做的。
-
是的,我承认这一点。所有的叹息。