我使用XShm扩展在linux中绘制和 *** 作图像。
为了不使屏幕闪烁,我将send_event = TRUE传递给XShmputimage ,然后在调用XScmputimage之后立即使用XIfEvent等待事件。
这样,我正在进行图像绘制阻塞,直到它显示在窗口表面上才能更改图像。
通常一切正常。 但有时候,当我进行密集的图像绘制时,事件似乎永远不会到来,并且绘图过程也会挂起。
创build虚拟设备
通过C ++检查以太网上的windows计算机
如何更新命令行输出?
如何使用另一个DLL为Qt制作第三方插件?
在编译affdex linux示例应用程序时未定义对进程(std :: __ cxx11 :: basic_string …)的引用
在哪里看到的问题? 是否使用XIfEvent适合这个任务? 事件如何从消息队列中消失?
在某些情况下, ShmCompletion可能不发送事件(如果send_event = TRUE)还是发送不同于ShmCompletion事件? (例如在一些内部错误或什么?)
编辑:
经过一些更多的研究,我发现只有当窗口pipe理器密集地生成事件到窗口时,才会发生这样的挂起。 例如,当我通过拖动它的angular来调整窗口的大小。
EDIT2:
我尝试了几种方法来解决这个问题,但没有成功。 最后,我不得不使用一些超时,并在一段时间后取消等待。 但当然这是肮脏的黑客,我想修复它。
那么,如果send_event = TRUE,XShmputimage不发送事件的原因是什么,或者是否有可能从消息队列中消失?
EDIT3:
这里是有问题的代码(FASM):
cinvoke XShmputimage,......,TRUE .loop: lea eax,[.event] cinvoke XCheckTypedEvent,[display],[ShmCompletionEvent],eax test eax,eax jz .loop ; there is no message
注意:XShmputimage总是返回TRUE,无论事件检查是否挂起,所以我没有把错误检查后。
EDIT4:
由于请求我张贴绘图function的整个代码。 代码使用了FASM的一些macros库,但至less这些想法是清楚的(我希望)
请注意,此代码包含限制事件仅等待20ms的解决方法代码。 没有这个超时,等待循环就会永远挂起。 根据Xshm文档中的build议调用XShmGetEventBase获取XShm事件的编号。
; Draws the image on a OS provIDed window surface. proc DrawImageRect,.where,.pImage,.xDst,.yDst,.xSrc,.ySrc,.wIDth,.height .event XEvent rb 256 begin pushad mov esi,[.pImage] test esi,esi jz .exit mov ebx,[esi+timage.ximage] cinvoke XCreateGC,[hApplicationdisplay],[.where],0 mov edi,eax cinvoke XShmputimage,edi,[esi+timage.ximage],[.xSrc],[.ySrc],[.xDst],[.yDst],[.wIDth],[.height],TRUE stdcall GetTimestamp lea esi,[eax+20] ; 20ms timeout .loop: lea eax,eax jnz .finish stdcall GetTimestamp cmp eax,esi jb .loop .finish: cinvoke XFreeGC,edi .exit: popad return endp
这里是应用程序的主要事件循环的代码。
过程__ProcessOnesystemEvent只是将事件分派给GUI对象,并忽略它不使用的所有事件。 它根本不处理ShmCompletionEvent 。
在应用程序中创build的所有窗口的事件掩码为: ExposureMask+FocusChangeMask+KeyPressMask+keyreleaseMask+buttonPressMask+buttonReleaseMask+EnterWindowMask+LeaveWindowMask+PointerMotionMask+StructureNotifyMask
proc ProcessSystemEvents .event XEvent rb 256 begin push ebx ecx edx .event_loop: ; check for quit get eax,[pApplication],TApplication:MainWindow test eax,eax jz .continue cmp DWord [eax],0 jne .continue cinvoke XFlush,[hApplicationdisplay] xor eax,eax mov [fGlobalTerminate],1 stc pop edx ecx ebx return .continue: cinvoke XPending,[hApplicationdisplay] test eax,eax jz .noevents push edi ecx lea edi,[.event] mov ecx,sizeof.XEvent/4 xor eax,eax rep stosd pop ecx edi lea ebx,[.event] cinvoke XNextEvent,ebx stdcall __ProcessOnesystemEvent,ebx jmp .event_loop .noevents: clc pop edx ecx ebx return endp
完整的源代码在存储库中可用,但这是一个非常大的项目,不容易导航。 讨论的来源是在登机手续8453c99b1283def8 。
文件: “freshlib / graphics / images.asm”和“freshlib / graphics / linux / images.asm”是关于图像绘制的。
文件: “freshlib / gui / Main.asm”和“freshlib / gui / linux / Main.asm”是关于应用程序中处理的一般事件。
如何从TDirect2DCanvas(Direct2D rendertarget)复制数据?
在.NET中占用固定的地址
C / C ++程序中的讹误堆栈问题
如何使用arm-linux-androIDeabi编译器
这是linux内核代码中的任何一种macros吗?
什么是X服务器在做什么?
如果传递给XShmputimage的参数超出了调用中连接到XImage的共享内存区域的几何图形,则X服务器可以 并将抑制ShmCompletionEvent 。 服务器根据先前存储的给定共享区域的限制检查X / Y和宽度/高度,如果调用参数超出范围,则服务器将返回BadValue , 禁止绘制 *** 作并抑制完成事件。
以上是你的图书馆正在发生的事情。 就是这样:
主事件调度程序是ProcessSystemEvents 。 它执行一个XEventNext ,并根据事件类型,使用一个跳转表.jump_table分派到一个事件特定的处理函数。
Expose事件的事件特定函数是.expose
.expose函数将依次使用XExposeEvent结构中的X / Y和宽度/高度值调用DrawImageRect 。 这是错误的,并且是错误的真正来源,我们将会马上看到。
DrawImageRect将在调用XShmputimage传递这些值
X 服务器中的XShmputimage处理程序将检查这些参数,并拒绝它们是否超出范围。
参数被拒绝,因为它们来自暴露事件,并且与窗口的几何形状有关,而不是与XShmputimage调用中使用的XImage相连的共享内存的几何形状。
具体来说,如果窗口刚刚被调整大小(例如由窗口管理器)并且被放大,并且已经有事先调整大小的ConfigureNotify事件。 现在,使用新的Expose事件,它将具有更大的宽度/高度,这将超出服务器知道的共享内存区域的宽度/高度。
客户端负责调整窗口大小调整事件等,并以扩大的大小拆卸/重新创建共享内存区域。 这没有完成,是错误的来源。
注意:要完全清楚这一点,服务器只能报告错误,不做任何事情有几个原因:
服务器知道窗口[和其大小]。
它知道XImage,它的共享内存区域和大小
但它们只在XShmputimage调用[AFAIK]
即使服务器可以关联它们,也不能调整shmarea
这是因为它没有办法将客户端重新连接到客户端
只有客户端可以通过XShmDetach/XShmAttach
以下是来自c5c765bc7e提交的相关源文件的编辑版本。 他们已经被清理了一下,所以只剩下最密切的部分了。 一些行已被截断或包裹,以消除水平滚动。
这些文件已经注释了NOTE和NOTE/BUG ,这是我在分析它们的时候做的。
gui / Main.asm顶级通用主循环。 没什么可看的。
; file: gui/Main.asm ; _____________________________________________________________________________ ;| | ;| ..::Freshlib::.. Free,open source. licensed under "BSD 2-clause" license." | ;|_____________________________________________________________________________| ; ; Description: Main procedure of GUI application library. ; ; Target OS: Any ; ; DependencIEs: ; ; Notes: Organize the main message/event loop needed by every GUI engine. ; This file contains only OS independent part and includes OS dependent ; files. ;______________________________________________________________________________ module "Main library" proc Run begin .mainloop: stdcall ProcessSystemEvents jc .terminate mov eax,[pApplication] test eax,eax jz .eventok get ecx,eax,TApplication:OnIDle jecxz .eventok stdcall ecx,eax .eventok: stdcall WaitForSystemEvent jmp .mainloop .terminate: DeBUGMsg "Terminate GUI application!" return endp include '%TargetoS%/Main.asm' endmodule
gui / linux / Main.asm事件处理程序
; file: gui/linux/Main.asm ; _____________________________________________________________________________ ;| | ;| ..::Freshlib::.. Free,open source. licensed under "BSD 2-clause" license." | ;|_____________________________________________________________________________| ; ; Description: Main procedure of GUI application library. ; ; Target OS: linux ; ; DependencIEs: ; ; Notes: Organize the main message/event loop needed by every GUI engine. ;______________________________________________________________________________ body ProcessSystemEvents ; NOTE: this is the storage for the dequeued event -- all dispatch routines ; should use it and process it .event XEvent rb 256 begin push ebx ecx edx .event_loop: ; check for quit get eax,eax jz .continue ; ??????????? cmp DWord [eax],1 stc pop edx ecx ebx return ; NOTE: it is wasteful for the main loop to call WaitForSystemEvent,then call ; us and we do XPending on the first loop -- we already kNow we have at least ; one event waiting in the queue .continue: cinvoke XPending,ebx jmp .event_loop .noevents: clc pop edx ecx ebx return endp body WaitForSystemEvent .event XEvent begin push eax ecx edx lea eax,[.event] cinvoke XPeekEvent,eax pop edx ecx eax return endp proc __ProcessOnesystemEvent,.linux_event begin pushad mov ebx,[.linux_event] ; mov eax,[ebx+XEvent.type] ; cmp eax,[ShmCompletionEvent] ; je .shm_completion stdcall _Getwindowstruct,[ebx+XEvent.window] jc .notprocessed test eax,eax jz .notprocessed mov esi,eax mov ecx,[ebx+XEvent.type] cmp ecx,LASTEvent jae .notprocessed mov ecx,[.jump_table+4*ecx] jecxz .notprocessed jmp ecx .notprocessed: popad stc return .finish: popad clc return ;.shm_completion: ; DeBUGMsg "Put back completion event!" ; ; int3 ; cinvoke xputBackEvent,ebx ; jmp .finish ;......................................................................... ; seMove and seResize events. ;------------------------------------------------------------------------- .moveresize: ; NOTE/BUG!!!!: we must not only process a resize/move request,but we must also ; adjust the size of the shmarea attached to the XImage -- that is _not_ being ; done. (eg) if the window is enlarged,the shmarea must be enlarged cinvoke XCheckTypeDWindowEvent,[ebx+XConfigureEvent.window],ConfigureNotify,ebx test eax,eax jnz .moveresize ; resize event... mov eax,[esi+twindow._wIDth] mov edx,[esi+twindow._height] cmp eax,[ebx+XConfigureEvent.wIDth] jne .resize cmp edx,[ebx+XConfigureEvent.height] je .is_move .resize: exec esi,twindow:EventResize,[ebx+XConfigureEvent.wIDth],[ebx+XConfigureEvent.height] ; move event... .is_move: mov eax,[esi+twindow._x] mov edx,[esi+twindow._y] cmp eax,[ebx+XConfigureEvent.x] jne .move cmp eax,[ebx+XConfigureEvent.y] je .finish .move: exec esi,twindow:EventMove,[ebx+XConfigureEvent.x],[ebx+XConfigureEvent.y] jmp .finish ;......................................................................... ; DestroyNotify handler it invalIDates the handle in twindow structure and ; then destroys twindow. .destroy: test esi,esi jz .finish mov [esi+twindow.handle],0 destroy esi jmp .finish ;......................................................................... ; Window paint event .expose: get edi,esi,twindow:imgScreen ; NOTE:BUG!!!!! ; ; if the window has been resized (eg enlarged),these values are wrong! ; they relate to the _window_ but _not_ the shmarea that is attached to the ; XImage ; ; however,DrawImageRect will call XShmputimage with these values,they ; will exceed the geometry of what the X server kNows about the shmarea and ; it will return BadValue and _suppress_ the completion event for XShmputimage stdcall DrawImageRect,[esi+twindow.handle],[ebx+XExposeEvent.x],[ebx+XExposeEvent.y],[ebx+XExposeEvent.wIDth],[ebx+XExposeEvent.height] jmp .finish ;......................................................................... ; Mouse event handlers .mousemove: cinvoke XCheckTypeDWindowEvent,MotionNotify,eax jnz .mousemove stdcall ServeMenuMouseMove,[ebx+XMotionEvent.window],[ebx+XMotionEvent.x],[ebx+XMotionEvent.y],[ebx+XMotionEvent.state] jc .finish cinvoke XCheckTypeDWindowEvent,eax jnz .mousemove mov edi,[__MouseTarget] test edi,edi jz .search_target_move stdcall __GetrelativeXY,[ebx+XMotionEvent.y] jmp .target_move .search_target_move: exec esi,twindow:ChildByXY,TRUE mov edi,eax .target_move: cmp edi,[__LastPointeDWindow] je .move_event cmp [__LastPointeDWindow],0 je .leave_ok exec [__LastPointeDWindow],twindow:EventMouseLeave .leave_ok: mov [__LastPointeDWindow],edi exec edi,twindow:EventMouseEnter .move_event: exec edi,twindow:EventMouseMove,ecx,edx,[ebx+XMotionEvent.state] jmp .finish ;......................................................................... ; event jump table .jump_table dd 0 ; event 0 dd 0 ; event 1 dd .key_press ; KeyPress = 2 dd .key_release ; keyrelease = 3 dd .mouse_btn_press ; buttonPress = 4 dd .mouse_btn_release ; buttonRelease = 5 dd .mousemove ; MotionNotify = 6 dd 0 ; EnterNotify = 7 dd 0 ; LeaveNotify = 8 dd .focusin ; FocusIn = 9 dd .focusout ; FocusOut = 10 dd 0 ; KeymapNotify = 11 dd .expose ; Expose = 12 dd 0 ; GraphicsExpose = 13 dd 0 ; NoExpose = 14 dd 0 ; VisibilityNotify = 15 dd 0 ; CreateNotify = 16 dd .destroy ; DestroyNotify = 17 dd 0 ; UnmapNotify = 18 dd 0 ; MapNotify = 19 dd 0 ; MapRequest = 20 dd 0 ; ReparentNotify = 21 dd .moveresize ; ConfigureNotify = 22 dd 0 ; ConfigureRequest = 23 dd 0 ; GravityNotify = 24 dd 0 ; ResizeRequest = 25 dd 0 ; CirculateNotify = 26 dd 0 ; CirculateRequest = 27 dd 0 ; PropertyNotify = 28 dd 0 ; SelectionClear = 29 dd 0 ; SelectionRequest = 30 dd 0 ; SelectionNotify = 31 dd 0 ; colormapNotify = 32 dd .clIEntmessage ; ClIEntMessage = 33 dd .mapPing_notify ; MapPingNotify = 34
graphics / linux / images.asm图像绘制代码[包括DrawImageRect函数]和共享内存创建/销毁代码。
; file: graphics/linux/images.asm ; _____________________________________________________________________________ ;| | ;| ..::Freshlib::.. Free,open source. licensed under "BSD 2-clause" license." | ;|_____________________________________________________________________________| ; ; Description: Memory based images manipulation library. ; ; Target OS: linux ; ; DependencIEs: memory.asm ; ; Notes: ;______________________________________________________________________________ uses libX11,xshm struct timage .wIDth dd ? ; wIDth in pixels. .height dd ? ; height in pixels. .pPixels dd ? ; pointer to the pixel memory. ; os dependent data .ximage dd ? .shminfo XShmSegmentInfo ends body CreateImage begin pushad stdcall GetMem,sizeof.timage jc .finish mov esi,eax xor eax,eax inc eax mov ecx,[.wIDth] mov edx,[.height] cmp ecx,0 cmovle ecx,eax cmp edx,0 cmovle edx,eax mov [esi+timage.wIDth],ecx mov [esi+timage.height],edx lea eax,[4*ecx] imul eax,edx cinvoke shmget,IPC_PRIVATE,IPC_CREAT or 777o test eax,eax Js .error mov [esi+timage.shminfo.ShmID],eax cinvoke shmat,0 cmp eax,-1 je .error_free mov [esi+timage.shminfo.Addr],eax mov [esi+timage.pPixels],eax mov [esi+timage.shminfo.fReadonly],1 lea ebx,[esi+timage.shminfo] cinvoke XShmCreateImage,$20,Zpixmap,ebx,[esi+timage.wIDth],[esi+timage.height] mov [esi+timage.ximage],eax cinvoke XShmAttach,ebx clc mov [esp+4*regEAX],esi .finish: popad return .error_free: cinvoke shmctl,[ebx+XShmSegmentInfo.ShmID],IPC_RMID,0 .error: stdcall FreeMem,esi stc jmp .finish endp body DestroyImage begin pushad mov esi,[.ptrImage] test esi,esi jz .finish lea eax,[esi+timage.shminfo] cinvoke XShmDetach,eax cinvoke XDestroyImage,[esi+timage.ximage] cinvoke shmdt,[esi+timage.shminfo.Addr] cinvoke shmctl,[esi+timage.shminfo.ShmID],0 stdcall FreeMem,esi .finish: popad return endp ;if used ___CheckCompletionEvent ;___CheckCompletionEvent: ; ;virtual at esp+4 ; .display dd ? ; .pEvent dd ? ; .user dd ? ;end virtual ; ;; timeout ; stdcall GetTimestamp ; cmp eax,[.user] ; jbe @f ; ; DeBUGMsg "Timeout!" ; ; mov eax,1 ; retn ; ;@@: ; mov eax,[.pEvent] ;.pEvent ; mov eax,[eax+XEvent.type] ; ; cmp eax,[ShmCompletionEvent] ; sete al ; movzx eax,al ; retn ;end if body DrawImageRect .event XEvent rb 256 begin pushad mov esi,[esi+timage.ximage] ; NOTE: is this necessary? it seems wasteful to create and destroy a GC ; repeatedly. Dunno,does this _have_ to be done here,_every_ time? cinvoke XCreateGC,eax ; NOTE/BUG: The return ShmCompletionEvent will be suppressed due to a BadValue ; if the X/Y and wIDth/height parameters given to us by caller exceed the ; geometry/range of the shmarea attached to .ximage ; ; the routine that calls us is .expose and it _is_ giving us bad values. it is ; passing us X/Y wIDth/height related to an exposure event of the .where ; _window_ which we put in the call. The X server will compare these against ; the size of the shmarea of timage.xmage and complain if we exceed the bounds cinvoke XShmputimage,TRUE ; NOTE/BUG: this code should _not_ be looPing on XCheckTypedEvent because it ; disrupts the normal event processing. if we want to be "synchronous" on this ; we should loop on the main event dispatcher (ProcessSystemEvents) and let it ; dispatch to a callback we create. we can set a "pending" flag that our [not ; yet existent] dispatch routine can clear ; THIS CODE SOMETIMES CAUSES HANGS! stdcall GetTimestamp lea esi,[eax+20] .loop: lea eax,edi .exit: popad return endp
Xext / shm.c检查并处理XShmputimage调用的X服务器代码。
// file: Xext/shm.c static int ProcShmputimage(ClIEntPtr clIEnt) { GCPtr pGC; DrawablePtr pDraw; long length; ShmDescPtr shmdesc; REQUEST(xShmputimageReq); REQUEST_SIZE_MATCH(xShmputimageReq); VALIDATE_DRAWABLE_AND_GC(stuff->drawable,pDraw,DixWriteAccess); VERIFY_SHMPTR(stuff->shmseg,stuff->offset,FALSE,shmdesc,clIEnt); // NOTE: value must be _exactly_ 0/1 if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) return BadValue; if (stuff->format == XYBitmap) { if (stuff->depth != 1) return BadMatch; length = pixmapBytePad(stuff->totalWIDth,1); } else if (stuff->format == XYpixmap) { if (pDraw->depth != stuff->depth) return BadMatch; length = pixmapBytePad(stuff->totalWIDth,1); length *= stuff->depth; } else if (stuff->format == Zpixmap) { if (pDraw->depth != stuff->depth) return BadMatch; length = pixmapBytePad(stuff->totalWIDth,stuff->depth); } else { clIEnt->errorValue = stuff->format; return BadValue; } // NOTE/BUG: The following block is the "check parameters" code. If the // given drawing parameters of the request (eg X,Y,wIDth,height) [or // combinations thereof] exceed the geometry/size of the shmarea,the // BadValue error is being returned here and the code to send a return // event will _not_ be executed. The BUG isn't really here,it's on the // clIEnt sIDe,but it's the clIEnt sIDe BUG that causes the event to be // suppressed /* * There's a potential integer overflow in this check: * VERIFY_SHMSIZE(shmdesc,length * stuff->totalHeight,* clIEnt); * the version below ought to avoID it */ if (stuff->totalHeight != 0 && length > (shmdesc->size - stuff->offset) / stuff->totalHeight) { clIEnt->errorValue = stuff->totalWIDth; return BadValue; } if (stuff->srcX > stuff->totalWIDth) { clIEnt->errorValue = stuff->srcX; return BadValue; } if (stuff->srcY > stuff->totalHeight) { clIEnt->errorValue = stuff->srcY; return BadValue; } if ((stuff->srcX + stuff->srcWIDth) > stuff->totalWIDth) { clIEnt->errorValue = stuff->srcWIDth; return BadValue; } if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) { clIEnt->errorValue = stuff->srcHeight; return BadValue; } // NOTE: this is where the drawing takes place if ((((stuff->format == Zpixmap) && (stuff->srcX == 0)) || ((stuff->format != Zpixmap) && (stuff->srcX < screenInfo.bitmapScanlinePad) && ((stuff->format == XYBitmap) || ((stuff->srcY == 0) && (stuff->srcHeight == stuff->totalHeight))))) && ((stuff->srcX + stuff->srcWIDth) == stuff->totalWIDth)) (*pGC->ops->Putimage) (pDraw,pGC,stuff->depth,stuff->dstX,stuff->dstY,stuff->totalWIDth,stuff->srcHeight,stuff->srcX,stuff->format,shmdesc->addr + stuff->offset + (stuff->srcY * length)); else doShmputimage(pDraw,stuff->totalHeight,stuff->srcY,stuff->srcWIDth,shmdesc->addr + stuff->offset); // NOTE: this is where the return event gets sent if (stuff->sendEvent) { xShmCompletionEvent ev = { .type = ShmCompletionCode,.drawable = stuff->drawable,.minorEvent = X_Shmputimage,.majorEvent = ShmReqCode,.shmseg = stuff->shmseg,.offset = stuff->offset }; WriteEventsToClIEnt(clIEnt,1,(xEvent *) &ev); } return Success; }
你的源代码将是我们可以分析的最终作品,但是由于我对Assembly的理解很少,所以我会在宏观层面给你一个答案。 确切的答案仍然是我不知道的。
我遇到的事件太多,只是它创建这个问题,而不是事件的正常发生,这意味着你的框架将用尽虚拟内存,或者在上一个事件释放内存之前触发另一个事件框架。 在这种情况下,你可以做很少的事情
尝试检查是否有任何内存泄漏。在一帧事件结束后,尝试清理内存或在触发新内存之前正确结束该对象。
你也可以开发一个机制来让第二帧等待第一帧来克服。 在C / C ++中,我们使用如Mutex这样的许多同步方法或select系统调用。 如果你的设计遵循这种模式,那么你可以做到这些
如果你有权限改变分配给你窗口的内存,尝试增加它。 因为有一件事情肯定(根据你的解释),这是一些记忆问题。
回复编辑3看起来你正在调用一些方法cinvoke 。 如何在内部处理甚至是我不知道的。 你为什么不直接用C语言来实现它呢?我确信无论你工作的是什么目标,你都会得到一些交叉编译器。
总结以上是内存溢出为你收集整理的悬挂XShmPutImage事件通知全部内容,希望文章能够帮你解决悬挂XShmPutImage事件通知所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)