By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,548 Members | 1,735 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,548 IT Pros & Developers. It's quick & easy.

fast image display: can garbage collection be forced?

P: 1
Hi there,

I am using a device context (DC) and a buffer to successfully draw to screen. However, when I update the DC at very high frame rate and drag the frame containing the image very quickly over the screen or I drag another window on top of the fast display, I get errors (Pyassertion ....). I believe those are related to a conflict between the thread that is updating the buffer (over which I have control) and the thread that is doing the garbage collection. From what I understand, the drawing to screen should happen when exiting my OnPaint or DisplayImage function and the DC object is destroyed. However, I believe the actual drawing only happens when garbage collection of the DC occurs. So for high frame rates, the thread doing the garbage collection (and thus displaying the image) collides with my thread writing a new image to the buffer. If I had control over both threads I would use a lock, but I can't. Therefore, the question is: is there a way that I can force the garbage collection? and if that is not the problem, how can I prevent threads I don't have access to, from accessing a given variable (e.g. my image buffer)??? If only writing a few thousands/millions values was an atomic operation...

Below is some sample code where I display images. Notice that I made the images deliverately small, so that writing a new image to the buffer takes (just a guess) a comparable amount of time to that required for doing the garbage collection.

Thanks a million for taking the time to read this!!

Alf

BTW- I could not pay a beefy consultancy fee for this, but I'll be happy to buy lunch or dinner for a robust solution to this!! It's driving me insane.

Expand|Select|Wrap|Line Numbers
  1. # test code for fast image display
  2. import wx
  3.  
  4. class wxRGBDisplayPanel(wx.Panel):
  5.  
  6. def __init__(self,window_parent,width,height):
  7.  
  8.         wx.Panel.__init__(self,window_parent,-1)
  9.  
  10.         # event binding
  11.         self.Bind(wx.EVT_PAINT,self.OnPaint,self)
  12.         self.Bind(wx.EVT_ERASE_BACKGROUND,self.__do_nothing_,self)
  13.  
  14.         # setting the panel size
  15.         self.SetClientSize((width,height))
  16.  
  17.         # setting the background color
  18.         self.SetBackgroundColour('gray')
  19.  
  20.         # initializing the bitmap
  21.         self.image_buffer = wx.EmptyBitmap(width,height)
  22.  
  23.  
  24.     def DisplayImage(self, width, height, pointer_to_data_stream):
  25.         try:
  26.  
  27.             self.image_buffer  = wx.BitmapFromBuffer(width, height,
  28.                                               pointer_to_data_stream)
  29.  
  30.             # creating device context (DC) to contain the drawing. This
  31.             # DC CANNOT be a global parameter, i.e. self.dc            
  32.             dc = wx.BufferedDC(wx.ClientDC(self),self.image_buffer)
  33.  
  34.             dc.SetBrush(wx.TRANSPARENT_BRUSH)
  35.         except: pass
  36.  
  37.  
  38.     def OnPaint(self,event):
  39.  
  40.         # dumping the bitmap to screen
  41.         dc = wx.BufferedPaintDC(self,self.image_buffer)
  42.         event.Skip()
  43.  
  44.     def __do_nothing_(self,event):
  45.         pass
  46.  
  47.  
  48. if __name__ == '__main__':
  49.  
  50.     import time, threading
  51.  
  52.     class DemoFrame(wx.Frame):
  53.  
  54.         def __init__(self):
  55.  
  56.             wx.Frame.__init__(self,None,pos=(0,0),
  57.                               style = (wx.DEFAULT_FRAME_STYLE)^(wx.RESIZE_BORDER|wx.MAXIMIZE_BOX))
  58.  
  59.             image_height = 30
  60.             image_width  = 200
  61.  
  62.             # Setting the size of the drawable area
  63.             self.SetClientSize((image_width,image_height))
  64.  
  65.             # creating the actual display panel
  66.             self.panel = wxRGBDisplayPanel(self,image_width,image_height)
  67.  
  68.             # This is a clumsy way of bringing the screen to the front
  69.             self.Iconize()
  70.             self.Restore()
  71.  
  72.  
  73.         def CreateDummyImage(self, width, height,coefficient=1,shift=0):
  74.  
  75.             image = ""        
  76.             for row_index in range(height):
  77.                 for column_index in range(width):
  78.                     image = image + 3*chr((coefficient*column_index+shift)%255)
  79.             return image
  80.  
  81.  
  82.  
  83.         def Loop(self):
  84.  
  85.             # creating the display thread
  86.             t=threading.Thread(target=self.__loop,name="loop thread")
  87.  
  88.             # getting the size of the drawable area
  89.             size = self.GetClientSize()
  90.  
  91.             # creating dummy images
  92.             self.data_stream_list = []
  93.  
  94.             print 'generating dummy images, patience please...'
  95.             for k in range(5):            
  96.                 self.data_stream_list.append(
  97.                     self.CreateDummyImage(size.width,size.height,3,k*10))
  98.  
  99.             # starting the thread
  100.             t.start()
  101.  
  102.  
  103.         def __loop(self):
  104.  
  105.             initial_time = time.clock()
  106.             n_frames     = 300000
  107.  
  108.             (width,height) = self.GetClientSize()
  109.  
  110.             # drawing other elements
  111.             for k in range(n_frames):
  112.                 self.panel.DisplayImage(width, height,
  113.                     self.data_stream_list[k%len(self.data_stream_list)])
  114.  
  115.  
  116.             elapsed_time = time.clock() - initial_time
  117.  
  118.             size = self.GetClientSize()
  119.  
  120.             print str(int(n_frames/elapsed_time)) + ' frames per second (' +\
  121.                   str(int(size.width)) + 'x' + str(int(size.height)) + ' pixels)'
  122.  
  123.  
  124.     # creating the mandatory application
  125.     app = wx.PySimpleApp()
  126.  
  127.     # initializing the window
  128.     frm = DemoFrame()
  129.  
  130.     # displaying the frame
  131.     frm.Show()
  132.  
  133.     # start the loop
  134.     frm.Loop()
  135.  
  136.     # starting the main loop
  137.     app.MainLoop()
Apr 3 '07 #1
Share this question for a faster answer!
Share on Google+

Post your reply

Sign in to post your reply or Sign up for a free account.