Canvas EventType_Render and less memory usage
Canvas EventType_Render and less memory usage
Why the canvas gadget does not have a EventType_Render event? It would make things much easier to let the os notify when the canvas needs to be drawn instead of having to guees it.
I also noticed it consumes a lot of memory, i know is double buffered but a canvas at fullscreen at 4k resolution takes 40MB. I did some tests double buffering using gdi plus directly an it just uses 4MB.
I also noticed it consumes a lot of memory, i know is double buffered but a canvas at fullscreen at 4k resolution takes 40MB. I did some tests double buffering using gdi plus directly an it just uses 4MB.
Re: Canvas EventType_Render and less memory usage
What do you mean by guess it ? The canvas is automatically refreshed from the back image on the WM_PAINT event, so you don't have to worry about that. About the memory size, a 4k pic is 3840x2160x4 bytes so about 33MB. How did you have 4MB only meme usage with GDI + ?
Re: Canvas EventType_Render and less memory usage
Hi Fred,
what i mean with guess it is that now we have to call a canvas draw function every time is created, resized, shown, etc..
If there was a render event we had to call it only inside that render event. The system notifies you when it needs to be drawn instead of you having to decide when to draw, basically what you do when you use the api directly when you handle the WM_PAINT.
About the memory usage this code takes only 1.6MB at fullscreen on 4k and it's double buffered.
I am missing something?
what i mean with guess it is that now we have to call a canvas draw function every time is created, resized, shown, etc..
If there was a render event we had to call it only inside that render event. The system notifies you when it needs to be drawn instead of you having to decide when to draw, basically what you do when you use the api directly when you handle the WM_PAINT.
About the memory usage this code takes only 1.6MB at fullscreen on 4k and it's double buffered.
I am missing something?
Code: Select all
;GDIPDoubleBuffer.pb
EnableExplicit
Import "gdiplus.lib"
GdipFillRectangle(graphics.i, brush.i, x.f, y.f, width.f, height.f)
GdipCreateFromHDC(hdc.i, graphics.i)
GdipGraphicsClear(graphics.i, color.l)
GdipCreateSolidFill(color.l, brush.i)
GdipDeleteBrush(brush.i)
GdipDeleteGraphics(graphics.i)
GdiplusStartup(token.i, input.i, output.i)
GdiplusShutdown(token.i)
EndImport
;- GdiplusStartupInput
Structure GdiplusStartupInput Align #PB_Structure_AlignC
GdiplusVersion.l
DebugEventCallback.i
SuppressBackgroundThread.l
SuppressExternalCodecs.l
EndStructure
#AlphaShift = 24
#RedShift = 16
#GreenShift = 8
#BlueShift = 0
#AlphaMask = $ff000000
#RedMask = $00ff0000
#GreenMask = $0000ff00
#BlueMask = $000000ff
Macro ARGB(a, r, g, b)
(((b) << #BlueShift) | ((g) << #GreenShift) | ((r) << #RedShift) | ((a) << #AlphaShift))
EndMacro
;- _APP
Structure _APP
win.i
cont.i
contOldProc.i
EndStructure
Global._APP app
Procedure.i cont_onPaint(hwnd.i, msg.l, wparam.i, lparam.i)
Protected.PAINTSTRUCT ps
Protected.i hdc, memDC, memBM, memOldObj, memGraphics
Protected.i brush, pen
Protected.RECT rc
Protected.l color1, color2
Protected.l rectSize
hdc = BeginPaint_(hwnd, @ps)
;Create memory graphics
GetClientRect_(hwnd, @rc)
memDc = CreateCompatibleDC_(hdc)
memBM = CreateCompatibleBitmap_(hdc, rc\right, rc\bottom)
memOldObj = SelectObject_(memDC, memBM)
GdipCreateFromHDC(memDc, @memGraphics)
;Draw to memory graphics
color1 = ARGB(255, 255, 0, 0)
color2 = ARGB(255, 0, 0, 255)
rectSize = DesktopScaledX(200)
GdipGraphicsClear(memGraphics, color2)
GdipCreateSolidFill(color1, @brush)
GdipFillRectangle(memGraphics, brush, (rc\right / 2) - (rectSize / 2), (rc\bottom / 2) - (rectSize / 2), rectSize, rectSize)
;Copy to dc
BitBlt_(hdc, 0, 0, rc\right, rc\bottom, memDc, 0, 0, #SRCCOPY)
;Release
SelectObject_(memDc, memOldObj)
DeleteObject_(memBm)
DeleteDC_(memDc)
GdipDeleteBrush(brush)
GdipDeleteGraphics(memGraphics)
EndPaint_(hwnd, @ps)
ProcedureReturn 0
EndProcedure
Procedure.i cont_proc(hwnd.i, msg.l, wparam.i, lparam.i)
Select msg
Case #WM_ERASEBKGND : ProcedureReturn 1
Case #WM_PAINT : ProcedureReturn cont_onPaint(hwnd.i, msg.l, wparam.i, lparam.i)
EndSelect
ProcedureReturn CallWindowProc_(app\contOldProc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure win_onSize()
ResizeGadget(app\cont, 0, 0, WindowWidth(app\win), WindowHeight(app\win))
EndProcedure
Procedure main()
Protected.l ev
Protected.GdiplusStartupInput su
Protected.i gdipToken
;Init gdip
su\GdiplusVersion = 1
su\DebugEventCallback = #Null
su\SuppressBackgroundThread = #False
su\SuppressExternalCodecs = #False
GdiplusStartup(@gdipToken, @su, #Null)
app\win = OpenWindow(#PB_Any, 10, 10, 600, 400, "Test", #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
app\cont = ContainerGadget(#PB_Any, 0, 0, 0, 0)
app\contOldProc = SetWindowLongPtr_(GadgetID(app\cont), #GWLP_WNDPROC, @cont_proc())
BindEvent(#PB_Event_SizeWindow, @win_onSize())
win_onSize()
Repeat
ev = WaitWindowEvent()
Until ev = #PB_Event_CloseWindow
GdiplusShutdown(gdipToken)
EndProcedure
main()
Re: Canvas EventType_Render and less memory usage
I don't understand your intention. You have to call your drawing function anyway. The internal drawing process makes sure the current picture is redrawn when needed, and if the canvas is resized it's clear that you have to react to adapt the picture to the new size. How would the internal function know what to draw?
Also there's no difference between manually calling your drawing function or binding it with BindGadgetEvent (I know there's some difference, butt this does not matter here). You have to call your drawing function anyway.
So, why the need for a custom reaction on the repaint notification?
Also there's no difference between manually calling your drawing function or binding it with BindGadgetEvent (I know there's some difference, butt this does not matter here). You have to call your drawing function anyway.
So, why the need for a custom reaction on the repaint notification?
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: Canvas EventType_Render and less memory usage
For me is more logical being notified when to draw than having to draw after resizing for example, but PB uses a different drawing model and it won't change, no problem.
But what about the memory usage?
With the previous example at 4k fullscreen:
CanvasGadget 25MB
Gdip api 1.6MB
But what about the memory usage?
With the previous example at 4k fullscreen:
CanvasGadget 25MB
Gdip api 1.6MB
Re: Canvas EventType_Render and less memory usage
I think so too.Justin wrote: Sat Sep 28, 2024 3:22 pm For me is more logical being notified when to draw than having to draw after resizing for example
Re: Canvas EventType_Render and less memory usage
Your are drawing directly on the window's buffer that's why it doesn't take extra memory, but for every WM_PAINT event, you will have to redraw all your picture from scratch which can be very time consuming (or you need a backbuffer to store your pic, like the canvas does for really fast redraw).
Re: Canvas EventType_Render and less memory usage
@Justin, @mestnyi: I can't follow. The redraw functions do e internally just repaint, what's already put on the canvas. Why should I take control? I just need to repaint, e.g. if the size changes, because the content changes. If there was a window above my canvas and now not anymore, the repaint just paints again what's already on the canvas. This is a serious question: Why should I do this myself?
Good morning, that's a nice tnetennba!
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Re: Canvas EventType_Render and less memory usage
Just where are you getting your memory usage readings? Task manager? This isn't entirely trustworthy. It tells the truth but not necessarily the whole truth.Justin wrote: Sat Sep 28, 2024 12:28 pm About the memory usage this code takes only 1.6MB at fullscreen on 4k and it's double buffered.
I am missing something?
I ran your code on my laptop (which doesn't have a 4k display) and it's using about 40Mb according to Process Explorer but Task Manager only reports 3Mb.
The GDI code lives in a shared DLL. Consequently, its memory allocations may not show as private to your process because they may be being shared across multiple processes.
However, the canvas gadget is a PB specific library and is statically linked into the process. It will only be used by your program so its allocations will be entirely attributable to the parent process and will be reported accordingly.
I suspect that what you're seeing as a difference in memory is that in which the system is unable to definitively assign to a single process because its being shared, or is being reported somewhere else. On my machine the memory consumption of dwm.exe peaks and drops when I start and stop your process. This is the "Desktop Window Manager" process, so this doesn't surprise me.
Re: Canvas EventType_Render and less memory usage
@Fred,
if it's a matter of speed i would prefer less speed and less ram, i don't think i would notice anything in a nowadays computer when drawing a custom gadget. 25mb for drawing a simple window is to much imo, just a personal choice.
How about a flag #PB_Canvas_NoBackBuffer to use the method i posted?
@spikey,
where did you read 40mb?
This is what process explorer showed here

test is gdip 1988 + 11348 = 13336
test2 is canvas 26316 + 40896 = 67212
@jacdelad,
pb uses a different drawing model, the point is not having to redraw after resizing, if you look at my explample i had to do nothing when i resized the container it was redrawn automatically becasuse the system called wm_paint. But like i said pb uses another system, it's ok.
if it's a matter of speed i would prefer less speed and less ram, i don't think i would notice anything in a nowadays computer when drawing a custom gadget. 25mb for drawing a simple window is to much imo, just a personal choice.
How about a flag #PB_Canvas_NoBackBuffer to use the method i posted?
@spikey,
where did you read 40mb?
This is what process explorer showed here

test is gdip 1988 + 11348 = 13336
test2 is canvas 26316 + 40896 = 67212
@jacdelad,
pb uses a different drawing model, the point is not having to redraw after resizing, if you look at my explample i had to do nothing when i resized the container it was redrawn automatically becasuse the system called wm_paint. But like i said pb uses another system, it's ok.
Re: Canvas EventType_Render and less memory usage
Process Explorer, as well but I wouldn't worry if that's higher than you're expecting. This machine has a broken BitDefender installation and I'm procrastinating about doing an OS re-install because its really time consuming. I didn't think properly about the implications of that before posting, I shouldn't have quoted specific values. Sorry!
My point was not to fall into the taking Task Manager at face value trap (but you haven't) and that you may not be seeing the entire memory load when using shared DLLs and so may not be comparing apples with apples entirely. Application memory usage is more complicated than most people expect.
But if you already know how to use Process Explorer I'm probably not telling you anything you didn't already know!