-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix createFontMem to not use garbage-collected memory #17
Fix createFontMem to not use garbage-collected memory #17
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thank you! Looked through the nanovg & freetype and this was definitely buggy, good catch! Two minor comments to address before merging.
copyCStringLen (from, len) = | ||
let intLen = fromIntegral len | ||
in do | ||
to <- mallocBytes intLen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add a comment that this is freed by NanovVG as part of nvgDeleteGL3
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Feel free to change it to your liking if you think it could be improved.
Also thanks for maintenance and looking at it rather promptly!
Co-authored-by: Moritz Kiefer <moritz.kiefer@purelyfunctional.org>
Please excuse me this gentle nudge, but I was wondering if there was a chance for this fix to land in a hackage release soonish. I was looking into using the fixed version in monomer. I understand it may not be a priority though. |
I just uploaded 0.8.1.0 to hackage which includes your fix. |
Thank you so much! |
np, thanks for the fix! |
I've been using monomer as well and have been tracking down a large memory leak with images for a while now. I eventually traced it back to this PR. I don't want to reverse this PR but it should be known that the default method of rendering an image with monomer uses For instance, I have had plenty of success just doing something like: image cxt ch cw flags imgData = useAsPtr imgData $ \p -> do
image' <- createImageRGBA'_ cxt ch cw (bitMask flags) p
free p
return . safeImage $ image' If it is the case that deleteGL3 is meant to free this copy then I can accept that too to make a PR over at the monomer library. |
Ah, I was wrong with my comment here then, sorry.
Totally missed nvgCreateImageMem nanovg-hs/src/NanoVG/Internal/Image.chs Lines 32 to 33 in 283516a
If the same |
Sure thing, I submitted a PR #20 for |
I have another question after thinking about this for some time, and maybe you've answered this elsewhere already @klausweiss, was using a |
Or perhaps doing this to copy the bytestring in Monomer before passing it here. copyAllocateByteString :: ByteString -> IO ByteString
copyAllocateByteString bs =
useAsCStringLen bs $ \(cch, l) -> do
let intLen = fromIntegral l
to <- mallocBytes intLen
copyBytes to cch intLen
packCStringLen (to, l) |
To answer your question, I've never heard of |
I've had problems when using
createFontMem
. I didn't use the action directly, but via the monomer library (see the related PR there - fjvallarino/monomer#199 (comment)). Long story short, text wouldn't render when I usedcreateFontMem
but would withcreateFont
and the same file.What I believe is happening: while the font is in memory when
fonsAddFontMem
is called, it very likely is garbage-collected after the FFI call finishes. The freed memory is reused for another purpose by the Haskell runtime, but from the C point of view the pointer is still valid. When the font is to be used, the same pointer is used (now pointing to gibberish) and the text isn't rendered - garbage in, garbage out.I tried proving it, but ended up in the FreeType internals which was just a bit too much for me. I have a non-functional monomer example though, which the changes here fix (see the linked PR).
The binding tells
fontstash
that it manages the memory of the font bytes on its own (by passing0
to thefreeData
argument):nanovg-hs/src/NanoVG/Internal/Text.chs
Lines 107 to 112 in cc8dfa0
The solution is to tell
fontstash
to manage the memory allocated for font bytes and to malloc it manually, so that it's not garbage-collected. Note that's also whatfonsAddFont
does -nanovg-hs/nanovg/src/fontstash.h
Lines 922 to 929 in cc8dfa0
Happy to hear your thoughts.