Error Exception: vpi_UnablePictureCreate (vpi) in VP75

Discussions related to Visual Prolog
altur
Posts: 7
Joined: 17 Aug 2010 17:50

Error Exception: vpi_UnablePictureCreate (vpi) in VP75

Unread post by altur » 5 Oct 2014 9:36

There are arbitrary number of objects with their coordinates in program. After some actions the objects positions change and it is displayed on screen. To avoid of flickering I use pictureCanvas for drawing. The simplest model is here (buf_75m.zip).
By input of big number of objects (more then 100) there is happened the error:
========================================
Dump: 2014-10-05 12:48:52
----------------------------------------
Exception: vpi_UnablePictureCreate (vpi)

Unable to create a valid picture

Predicate name = vpiExceptionRaiser
SourceCursor = pfc\vpi\vpi.pro(253,9)
ExtraInfo = pict_Close: Cannot create picture
error code = 6100

raised 2014-10-05 12:48:46
ThreadId: 2512
Class name: vpi
Predicate name: vpiExceptionRaiser


d:\program files\visual prolog 7.5 pe\pfc\exception\exception.pro(198)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipKernel.dll (0x140083A5)
d:\program files\visual prolog 7.5 pe\pfc\exception\exception.pro(198)
d:\program files\visual prolog 7.5 pe\pfc\exception\exception.pro(182)
d:\program files\visual prolog 7.5 pe\pfc\vpi\vpi.pro(253)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x15310D7A)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x15316E3C)
d:\program files\visual prolog 7.5 pe\pfc\gui\picturecanvas.pro(38)
plotter\myform.pro(42)
plotter\myform.pro(30)
d:\program files\visual prolog 7.5 pe\pfc\gui\window.pro(1087)
d:\program files\visual prolog 7.5 pe\pfc\gui\window.pro(1993)
d:\program files\visual prolog 7.5 pe\pfc\gui\documentwindow.pro(279)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipKernel.dll (0x14008735)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x15310C1F)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x15315D37)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x15313A7C)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x1531DB54)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x1531C63F)
D:\WINDOWS\system32\USER32.dll (0x7E368734)
D:\WINDOWS\system32\USER32.dll (0x7E368816)
D:\WINDOWS\system32\USER32.dll (0x7E37927B)
D:\WINDOWS\system32\USER32.dll (0x7E3792E3)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x1531BEB2)
D:\WINDOWS\system32\USER32.dll (0x7E368734)
D:\WINDOWS\system32\USER32.dll (0x7E368816)
D:\WINDOWS\system32\USER32.dll (0x7E3689CD)
D:\WINDOWS\system32\USER32.dll (0x7E368A10)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipVpi.dll (0x1531A4FD)
d:\program files\visual prolog 7.5 pe\pfc\vpi\vpi.pro(21)
d:\program files\visual prolog 7.5 pe\pfc\windowsapi\exe_api\exe_api.pro(63)
d:\program files\visual prolog 7.5 pe\pfc\application\exe\mainexe.pro(21)
main.pro(14)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipKernel.dll (0x1400884B)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\vipKernel.dll (0x14008B0B)
d:\Documents and Settings\Admin\Мои документы\Visual Prolog Projects\buf_75m\Exe\buf_vip75.exe (0x0050CCAC)

----------------------------------------
OS information:

Microsoft Windows XP Professional Service Pack 3 (Build 2600)
Number Of Processors: 2 PageSize: 4096 Processor: 586 level: 6 revision: 5894
ProcessorNameString: Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
VendorIdentifier: GenuineIntel
Identifier: x86 Family 6 Model 23 Stepping 6
~MHz: 3005

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 5 Oct 2014 9:43

I can't add attachment. So set main code:

Code: Select all

class circle : circle     open core predicates     getCreatedObjects:(circle*) procedure (o).     setCreatedObjects:(circle*) procedure (i).     draw_circlist:(windowGDI). end class circle   interface circle     open core,vpiDomains domains     coor=pnt.     numCircle=integer. properties     coor:coor. end interface circle   implement circle     open core,vpiDomains facts     coor:coor:=erroneous. class facts    createdObjects:circle*:=[]. clauses     new():-         addToObjectList(This). clauses     getCreatedObjects(Circles):-Circles=createdObjects.     setCreatedObjects(Circles):-createdObjects:=Circles. predicates     addToObjectList:(circle). clauses     addToObjectList(NewCircle):-         createdObjects:=[NewCircle|createdObjects].       draw_circlist(GDI):-         getCreatedObjects(CircList),         foreach Circ= list::getMember_nd(CircList) do             Circ:coor=Pnt,Pnt=pnt(X,Y),             math::random(3)=Rx,math::random(3)=Ry,             GDI:drawEllipse(rct(X+Rx-10,Y+Ry-10,X+Rx+10,Y+Ry+10))         end foreach. end implement circle   implement myform     inherits formWindow     open core, vpiDomains class facts     canvas :pictureCanvas:=erroneous.     switch:string:="indefinite". clauses     display(Parent) = Form :-         Form = new(Parent),         Form:show().   clauses     new(Parent):-         formWindow::new(Parent),         generatedInitialize().   predicates     onMenuItem : window::menuItemListener. clauses     onMenuItem(_Source, resourceIdentifiers::id_input):-switch:="input",!. %        profileMemory::profileBegin("memprofile.vipmp").     onMenuItem(_Source, resourceIdentifiers::id_test):-switch="run",!,         switch:="indefinite".     onMenuItem(_Source, resourceIdentifiers::id_test):-         switch:="run",         main_cycle(This),!.     onMenuItem(_Source, _MenuTAG).   class predicates     main_cycle:(formWindow) determ. clauses     main_cycle(MyForm):-         std::repeat(),              WinGDI = MyForm:getWindowGDI(),             MyForm:getClientSize(W,H),             canvas := pictureCanvas::new(W,H),             circle::draw_circList(canvas),             WinGDI:pictDraw(canvas :getPicture(), pnt(0,0), rop_SrcCopy),             _IsSuccessful = vpi::processEvents(),             prov_end(),!.   class predicates     prov_end:() determ. clauses     prov_end():-switch<>"run".   predicates     onMouseDown : window::mouseDownListener. clauses     onMouseDown(_Source, Pnt, _ShiftControlAlt, _Button):-         switch="input",!,         circle::new()=Circle,Circle:coor:=Pnt,         invalidate().     onMouseDown(_Source, _Point, _ShiftControlAlt, _Button).   predicates     onPaint : window::paintResponder. clauses     onPaint(_Source, _Rectangle, GDI):-         circle::draw_CircList(GDI),         fail.     onPaint(_Source, _Rectangle, _GDI).

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 5 Oct 2014 11:31

When I try add attachment it is appeared
Upload Error: Could not upload Attachment to ./files/buf_75_166.zip
What to do?

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 6 Oct 2014 11:38

Unfortunately, the forum can currently not accept attachments at all.

We are investigating the problem (i.e. the attachment problem).
Last edited by Thomas Linder Puls on 6 Oct 2014 12:19, edited 1 time in total.
Regards Thomas Linder Puls
PDC

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 6 Oct 2014 12:13

I do not know why you get the mentioned error. But your code is strange.

In the paint listener you draw directly in the window, but outside the paint you also draw (that is where you use the picture canvas).

You should do all painting in the paint listener (i.e. no painting outside the paint listener). So basically you should move your picture drawing into the paint listener.

Furthermore, your loop will use all available processor power on drawing (even if nothing have happened).

Also the construction with calling vpiProcessEvents seems a bit strange and at least unclear.

Basically you should paint in the paint listener, the other parts of your code should trigger painting by invalidating regions (typically everything) of your drawing/window.

(Also notice that "canvas" does not have to be a fact variable, you never need to "remember" it, it is only used in three lines in a clause).
Regards Thomas Linder Puls
PDC

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 6 Oct 2014 15:51

In the paint listener you draw directly in the window, but outside the paint you also draw (that is where you use the picture canvas)
Furthermore, your loop will use all available processor power on drawing (even if nothing have happened)...
Also the construction with calling vpiProcessEvents seems a bit strange and at least unclear.
The program must show evolution of system as quick as possible, so it uses all available processor power. But to stop execution it is applied vpiProcessEvents at the end of loop repeat->system changing-> vpiProcessEvents, after that it is possible to make some corrections of objects (with menu and mouse etc.).

dominique f pannier
VIP Member
Posts: 98
Joined: 23 Sep 2002 23:01

Unread post by dominique f pannier » 7 Oct 2014 9:48

Hi,
I enter this conversation about this :
If the system is complex (consist of many objects) it is appeared flickering
I soon raised an issue on it in the following post :
http://discuss.visual-prolog.com/viewto ... flickering
But actually this behavior persists in 7.5.
:roll:
Regards
Dominique Pannier

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 7 Oct 2014 10:47

Your idea of double buffering is correct, first you draw to some internal "buffer" (a pictureCanvas should be file for that) and then you display the buffer in the window (without erasing the background window first, as you are going to fill it all out).

But the rest is not so good:
  • you should only update the window in the paint listener regardless of what else your program does.
  • Things will not speed up if you spend time drawing the same thing several times, so you should only draw as response to something having happened.
Basically you should create two seperate things:

  • A paint listener that can draw all your objects in the window (using double buffering if you wish)
  • A routine that update your object state
Even though the problem you reported is actually in the painting I will sketch how the object state routine could look. I don't know how anything about the state, but I assume that you basically want to run a loop that:
  • Update the state
  • Update drawing in the window
Each step in the loop essentially looks like this:

Code: Select all

predicates     step : (). clauses     step() :-         updateState(),         invalidate(). % invalidate the formWindow to trigger drawing
The loop itself could look like this:

Code: Select all

predicates     loop : (). clauses     loop() :-         step(),         if notFinished() then             postAction(loop)         end if.
Creating loops using postAction is much better than doing vpi::processEvents. The basic loop step will "do something" and then place the next step in the windows event queue. That way other events like user input and drawing will also happen in the loop.

Using postAction the loop will run as fast as possible. Using delayCall you can create pauses in the loop:

Code: Select all

predicates     loop : (). clauses     loop() :-         step(),         if notFinished() then             delayCall(100, loop) % 100 ms delay before next step         end if.
Regards Thomas Linder Puls
PDC

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 7 Oct 2014 12:55

Notice that when using double buffering it is essential to skip the erase background step (otherwise things will flicker anyway) but setting a suitable erase background responder:

Code: Select all

clauses     new():-         generatedInitialize(),         setEraseBackgroundResponder({ = noEraseBackground }).
This responder should be set on the window in which you paint your "buffer" (in a double buffer process).
Regards Thomas Linder Puls
PDC

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 7 Oct 2014 16:02

Thank you, it is very important for me to have some primitives, examples, thats were so many in help to old Prologs, and not enough in VP7.x!
I try to change my code according to your advices, but some things remain unclear.

Code: Select all

implement myform     inherits formWindow     open core, vpiDomains   class facts     switch:string:="indefinite".   clauses     display(Parent) = Form :-         Form = new(Parent),         Form:show().   clauses     new(Parent):-         formWindow::new(Parent),         generatedInitialize().   predicates     onMenuItem : window::menuItemListener. clauses     onMenuItem(_Source, resourceIdentifiers::id_input):-switch:="input",!.     onMenuItem(_Source, resourceIdentifiers::id_test):-switch="run",!,         switch:="indefinite".     onMenuItem(_Source, resourceIdentifiers::id_test):-         switch:="run",         This:loop(),!.     onMenuItem(_Source, _MenuTAG).   predicates     onMouseDown : window::mouseDownListener. clauses     onMouseDown(_Source, Pnt, _ShiftControlAlt, _Button):-         switch="input",!,         circle::new()=Circle,Circle:coor:=Pnt,         invalidate().     onMouseDown(_Source, _Point, _ShiftControlAlt, _Button).   predicates     onPaint : window::paintResponder. clauses     onPaint(_Source, _Rectangle, GDI):-         draw_CircList(GDI),         fail.     onPaint(_Source, _Rectangle, _GDI).   class predicates     draw_circlist:(windowGDI). clauses     draw_circlist(Canvas):-         circle::getCreatedObjects(CircList),         foreach Circ= list::getMember_nd(CircList) do             Circ:coor=Pnt,Pnt=pnt(X,Y),             math::random(3)=Rx,math::random(3)=Ry,             Canvas:drawEllipse(rct(X+Rx-10,Y+Ry-10,X+Rx+10,Y+Ry+10))         end foreach.   predicates     loop:(). clauses     loop():-WinGDI = This:getWindowGDI(),             This:getClientSize(W,H),             Canvas = pictureCanvas::new(W,H),      %            Canvas:invalidate(), %not work      %            This: invalidate(),     %draw in window, not in pictureCanvas            draw_circList(Canvas),             WinGDI:pictDraw(Canvas :getPicture(), pnt(0,0), rop_SrcCopy),            if notFinished() then               postAction(loop) end if.   class predicates     notFinished:() determ. clauses     notFinished():-switch="run".
- How can I apply invalidate() (to use paint Listener instead direct drawing) in predicate loop()?
The loop itself could look like this:

Code: Select all

predicates     loop : (). clauses     loop() :-         step(),         if notFinished() then             postAction(loop)         end if.
Creating loops using postAction is much better than doing vpi::processEvents. The basic loop step will "do something" and then place the next step in the windows event queue. That way other events like user input and drawing will also happen in the loop.

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 8 Oct 2014 5:22

loop repeat->system changing-> vpiProcessEvents
Here "system changing" I imply as selforganization of system without intervention of user.

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 8 Oct 2014 8:31

altur wrote:
- How can I apply invalidate() (to use paint Listener instead direct drawing) in predicate loop()?
The invalidate is applied in the step (which is part of the loop):

Code: Select all

predicates     step : (). clauses     step() :-         updateState(),         invalidate(). % invalidate the formWindow to trigger drawing
altur wrote:
The loop itself could look like this:

Code: Select all

predicates     loop : (). clauses     loop() :-         step(),         if notFinished() then             postAction(loop)         end if.
Creating loops using postAction is much better than doing vpi::processEvents. The basic loop step will "do something" and then place the next step in the windows event queue. That way other events like user input and drawing will also happen in the loop.
Answer: ... and then place the next step in the windows event queue.

The loop does not directly loop instead it places the next step in the event queue. The event queue will also receive all other events (menu, mouse, keyboard, paint, etc). So all events will still be active and each of your loop steps will be mixed into this "stream" of events. I.e. the system is fully responsive and your loop will also run.

The main difference between this strategy and using vpi::processEvents is that using this strategy you move your loop into the normal event handling, with vpi::processEvents you move the normal event handling into your loop. The postAction-aproach is safer because it has least influence on the programs normal behavior.
altur wrote:
I was afraid of that. I will try your code and see what happens.
Regards Thomas Linder Puls
PDC

altur
Posts: 7
Joined: 17 Aug 2010 17:50

Unread post by altur » 10 Oct 2014 7:24

Thank you for your teaching.
When I organized the loop in my sample program as you recommended, the mentioned error not appeared even with hundreds of objects.
But the access to menu I could get only with processEvent() predicate. It was not founded the predicate updateSystem() in VP7.5, only predicate update(), but it not help.
The latest redaction of this sample:

Code: Select all

implement myform     inherits formWindow     open core, vpiDomains   facts     switch:string:="indefinite".   clauses     display(Parent) = Form :-         Form = new(Parent),         Form:show().   clauses     new(Parent):-         formWindow::new(Parent),         generatedInitialize(),         setEraseBackgroundResponder({ = noEraseBackground }).   predicates     onMenuItem : window::menuItemListener. clauses     onMenuItem(_Source, resourceIdentifiers::id_input):-switch:="input",!.     onMenuItem(_Source, resourceIdentifiers::id_test):-switch="run",!,         switch:="indefinite".     onMenuItem(_Source, resourceIdentifiers::id_test):-switch:="run",         This:loop(),!.     onMenuItem(_Source, _MenuTAG).   predicates     onMouseDown : window::mouseDownListener. clauses     onMouseDown(_Source, Pnt, _ShiftControlAlt, _Button):-switch="input",!,         circle::new()=Circle,Circle:coor:=Pnt,         invalidate().     onMouseDown(_Source, _Point, _ShiftControlAlt, _Button).   predicates     onPaint : window::paintResponder. clauses     onPaint(_Source, _Rectangle, GDI):-        This:getClientSize(W,H),        Canvas = pictureCanvas::new(W,H),        draw_CircList(Canvas),        Gdi:pictDraw(Canvas :getPicture(), pnt(0,0), rop_SrcCopy),        fail.     onPaint(_Source, _Rectangle, _GDI).   predicates     loop:(). clauses     loop():-        step(),       if nofFinished() then        postAction(loop) end if.   predicates     step:(). clauses     step():- %       update(),       _IsSuccessful = vpi::processEvents(),         invalidate().   predicates     nofFinished:() determ. clauses     nofFinished():-switch="run".   class predicates     draw_circlist:(pictureCanvas). clauses     draw_circlist(PictureCanvas):-         circle::getCreatedObjects(CircList),       foreach Circ= list::getMember_nd(CircList) do           Circ:coor=Pnt,Pnt=pnt(X,Y),           math::random(3)=Rx,math::random(3)=Ry,           PictureCanvas:drawEllipse(rct(X+Rx-10,Y+Ry-10,X+Rx+10,Y+Ry+10))       end foreach.

User avatar
Thomas Linder Puls
VIP Member
Posts: 1624
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls » 13 Oct 2014 11:45

It seems you are right, using postAction is a little too efficient: It seems that Windows will only place paint events in the event queue when there are no other events in the queue (and when using postAction there will always be an event in the queue). Also as you mention it is not possible to get menu events into the event queue (maybe because the menu cannot be drawn).

Instead of switching back to vpi::processEvents I think yo should use delayCall(1, loop), this will cause a 1 milli second delay before the next iteration is performed.
Regards Thomas Linder Puls
PDC

Post Reply