understand MEMDEV better.

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • understand MEMDEV better.

      Hi,
      I have a small sample code:

      C Source Code

      1. #include "GUI.h"
      2. #include "WM.h"
      3. static void _cbBkWin(WM_MESSAGE *pMsg)
      4. {
      5. switch (pMsg->MsgId)
      6. {
      7. case WM_PAINT:
      8. GUI_SetBkColor(GUI_DARKRED);
      9. GUI_Clear();
      10. break;
      11. default:
      12. WM_DefaultProc(pMsg);
      13. break;
      14. }
      15. }
      16. static void _cbWin(WM_MESSAGE *pMsg)
      17. {
      18. switch (pMsg->MsgId)
      19. {
      20. case WM_PAINT:
      21. GUI_SetBkColor(GUI_DARKGREEN);
      22. GUI_Clear();
      23. GUI_SetColor(GUI_BLUE);
      24. GUI_DrawRect(2,2,15,12);
      25. {
      26. GUI_MEMDEV_Handle hMemPrev;
      27. GUI_MEMDEV_Handle hMemOverlay;
      28. hMemOverlay = GUI_MEMDEV_CreateFixed(0, 0, 10, 10, GUI_MEMDEV_NOTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888);
      29. hMemPrev = GUI_MEMDEV_Select(hMemOverlay);
      30. GUI_SetBkColor(GUI_WHITE);
      31. GUI_Clear();
      32. GUI_MEMDEV_Select(hMemPrev);
      33. GUI_MEMDEV_WriteAt(hMemOverlay, 5, 5);
      34. GUI_MEMDEV_Delete(hMemOverlay);
      35. }
      36. break;
      37. default:
      38. WM_DefaultProc(pMsg);
      39. break;
      40. }
      41. }
      42. void MainTask(void)
      43. {
      44. GUI_Init();
      45. GUI_EnableAlpha(1);
      46. WM_SetSize(WM_HBKWIN, LCD_GetXSize(), LCD_GetYSize());
      47. WM_SetCallback(WM_HBKWIN, _cbBkWin);
      48. WM_SetCreateFlags(WM_CF_MEMDEV);
      49. WM_EnableMemdev(WM_HBKWIN);
      50. WM_HWIN hWin;
      51. hWin = WM_CreateWindow(5, 5, 30, 25, WM_CF_SHOW | WM_CF_MEMDEV, _cbWin, 0);
      52. while(1) GUI_Delay(2000);
      53. }
      Display All


      the result of this code is:



      This is strange and counterintuitive. I created a square MEMDEV of side 10 and filled it with white and then wrote it down at position 5,5.


      Really GUI_*() functions work in the coordinates of the window (in the example there is GUI_DrawRect()) while GUI_MEMDEV_WriteAt() works in absolute coordinates?


      Then I try to put an offset to the GUI_MEMDEV_WriteAt():


      C Source Code

      1. GUI_MEMDEV_WriteAt(hMemOverlay, 5+5, 5+5);
      And the result is


      I can't explain that. It is beyond my comprehension.
      It seems that there is the shadow of the square at the position I want but it is white only in the lower right corner.

      Another thing I don't understand is the parameters of the GUI_MEMDEV_CreateFixed(). I don't understand the sense of imposing an origin if then I can write it to an arbitrary position

      For example if I modify the MEMDEV creation in this way:

      C Source Code

      1. hMemOverlay = GUI_MEMDEV_CreateFixed(30, 30, 10, 10, GUI_MEMDEV_NOTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888);

      I get this:


      Again, I can not understand the behavior. ;(


      at the end of it all the question is: how do I create a memdev, paint it white and then place it at an arbitrary position inside a window?

      best regards


      Max
    • Hi,

      There are several issues you should try to avoid or get rid of.

      1. As you already assumed, memory device coordinates are relative to the top left of the screen. This is because they are independent of the Window Manager and you have to add the screen coordinate of the window to position the memory device should be drawn. WM_GetWindowOrgX() and WM_GetWindowOrgY() will do the trick.

      2. You create the memory device in WM_PAINT and fill it with white. The problem here is related to clipping and the clip rect which is currently set. The memory device gets created at (0 | 0) but the clip rect starts at (5 | 5) (the window origin). This results in not filling the entire memory device and you get just a small rectangle.
      So you could either create the memory device at the position of the window (WM_GetWindowOrgX(), WM_GetWindowOrgY()) or set another clip rect. I recommend the first solution.

      3. Try to avoid the GUI_EnableAlpha(1), it has a very big impact on the overall performance and in most cases it is not required.

      4. Avoid using the WM_CF_MEMDEV flag. This can be used as a last option against flickering but causes an overhead in regards of drawing. Any drawing operation will be performed in an automatic memory device and than this device gets drawn to the screen. Without the flag the drawing will be performed directly to the screen (or in case of multibuffering into the backbuffer, or with a cache into the cache). To avoid flickering use multibuffering or a cached driver version.
      Beside the overhead it can get even worse if not enough memory is available. If that is the case there is not only one memory device for a window but several small devices. This will produce even more overhead because of all the small devices.

      I have made some changes to your code and added another window. _cbWin0 shows the way I would do it. Here the memory device gets created and filled only once and not each time the the window receives a WM_PAINT message. Also you don't have to bother about any clipping rectangles, beacuse we are in WM_CREATE. The device gets deleted once the window gets deleted.
      In _cbWin1 I did only small changes to your code. There I receive the x and y origin of the window in screen coordinates and use them while creating the device (now it is within the clipping rectangle) and while drawing the device at (5 | 5).

      C Source Code

      1. #include "DIALOG.h"
      2. /*********************************************************************
      3. *
      4. * External data
      5. *
      6. **********************************************************************
      7. */
      8. /*********************************************************************
      9. *
      10. * Static code
      11. *
      12. **********************************************************************
      13. */
      14. /*********************************************************************
      15. *
      16. * _cbBkWin
      17. */
      18. static void _cbBkWin(WM_MESSAGE *pMsg) {
      19. switch (pMsg->MsgId) {
      20. case WM_PAINT:
      21. GUI_SetBkColor(GUI_DARKRED);
      22. GUI_Clear();
      23. break;
      24. default:
      25. WM_DefaultProc(pMsg);
      26. break;
      27. }
      28. }
      29. /*********************************************************************
      30. *
      31. * _cbWin
      32. */
      33. static void _cbWin0(WM_MESSAGE *pMsg) {
      34. GUI_MEMDEV_Handle hMemPrev;
      35. static GUI_MEMDEV_Handle hMemOverlay;
      36. int xOff;
      37. int yOff;
      38. switch (pMsg->MsgId) {
      39. case WM_CREATE:
      40. hMemOverlay = GUI_MEMDEV_CreateFixed(0, 0, 10, 10, GUI_MEMDEV_NOTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888);
      41. hMemPrev = GUI_MEMDEV_Select(hMemOverlay);
      42. GUI_SetBkColor(GUI_WHITE);
      43. GUI_Clear();
      44. GUI_MEMDEV_Select(hMemPrev);
      45. break;
      46. case WM_PAINT:
      47. GUI_SetBkColor(GUI_DARKGREEN);
      48. GUI_Clear();
      49. GUI_SetColor(GUI_BLUE);
      50. GUI_DrawRect(2,2,15,12);
      51. {
      52. xOff = WM_GetWindowOrgX(pMsg->hWin);
      53. yOff = WM_GetWindowOrgY(pMsg->hWin);
      54. GUI_MEMDEV_WriteAt(hMemOverlay, xOff + 5, yOff + 5);
      55. }
      56. break;
      57. case WM_DELETE:
      58. GUI_MEMDEV_Delete(hMemOverlay);
      59. break;
      60. default:
      61. WM_DefaultProc(pMsg);
      62. break;
      63. }
      64. }
      65. /*********************************************************************
      66. *
      67. * _cbWin
      68. */
      69. static void _cbWin1(WM_MESSAGE *pMsg) {
      70. GUI_MEMDEV_Handle hMemPrev;
      71. GUI_MEMDEV_Handle hMemOverlay;
      72. int xOff;
      73. int yOff;
      74. switch (pMsg->MsgId) {
      75. case WM_PAINT:
      76. GUI_SetBkColor(GUI_DARKGREEN);
      77. GUI_Clear();
      78. GUI_SetColor(GUI_BLUE);
      79. GUI_DrawRect(2,2,15,12);
      80. {
      81. xOff = WM_GetWindowOrgX(pMsg->hWin);
      82. yOff = WM_GetWindowOrgY(pMsg->hWin);
      83. hMemOverlay = GUI_MEMDEV_CreateFixed(xOff, yOff, 10, 10, GUI_MEMDEV_NOTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888);
      84. hMemPrev = GUI_MEMDEV_Select(hMemOverlay);
      85. GUI_SetBkColor(GUI_WHITE);
      86. GUI_Clear();
      87. GUI_MEMDEV_Select(hMemPrev);
      88. GUI_MEMDEV_WriteAt(hMemOverlay, xOff + 5, yOff + 5);
      89. GUI_MEMDEV_Delete(hMemOverlay);
      90. }
      91. break;
      92. default:
      93. WM_DefaultProc(pMsg);
      94. break;
      95. }
      96. }
      97. /*********************************************************************
      98. *
      99. * Public code
      100. *
      101. **********************************************************************
      102. */
      103. /*********************************************************************
      104. *
      105. * MainTask
      106. */
      107. void MainTask(void) {
      108. WM_HWIN hWin;
      109. GUI_Init();
      110. //GUI_EnableAlpha(1);
      111. WM_SetSize(WM_HBKWIN, LCD_GetXSize(), LCD_GetYSize());
      112. WM_SetCallback(WM_HBKWIN, _cbBkWin);
      113. //WM_SetCreateFlags(WM_CF_MEMDEV);
      114. //WM_EnableMemdev(WM_HBKWIN);
      115. hWin = WM_CreateWindow(5, 5, 30, 25, WM_CF_SHOW/* | WM_CF_MEMDEV*/, _cbWin0, 0);
      116. hWin = WM_CreateWindow(40, 5, 30, 25, WM_CF_SHOW/* | WM_CF_MEMDEV*/, _cbWin1, 0);
      117. while(1) {
      118. GUI_Delay(2000);
      119. }
      120. }
      Display All
      Best regards,
      Sven
    • I caught your point. However, there are some details of your code that I would like to discuss

      in _cbWin0() at line 38 you declare hMemOverlay as static. This is a problem if you create two windows using _cbWin0. Two GUI_MEMDEV_Handle objects are created in memory but the first created will become orphan since the second one will overwrite the handle hMemOverlay (that is the only one static handle). and both windows will use the same (the second one created) MEMDEV. This can be This can be corrected by using user data to maintain the handle of MEMDEV. MEMDEVs must not be created in WM_CREATE but offline after window creation and saved in user data.

      There are, however, other problems related to the fact that the windows can be moved (changes their origin) and resized (if the MEMDEV should have a size related to the size of the window itself). In all these cases the MEMDEV should be recreated with new parameters.
      In _cbWin1() the MEMDEV is created and destroyed every time WM_PAINT is called. I wonder how much performance ovehead this causes.

      best regards
      Max
    • Hi,

      Yes, you are right. If two window use the same callback, a static device is not a good idea. Your solution with user data sounds good. But I don't see any problem if only one window uses this callback.

      If you create, fill, and draw the device within the paint event, I don't really see any benefits from using it. Why don't you draw directly into the window?

      It doesn't has such a big impact on the performance, but as said I don't really see a reason why drawing into a memory device instead of drawing directly into the window. Without the device it would also become more handy.

      Regards,
      Sven