BlitzMaxNG Garbage collector issues

Started by Ashmoor, June 14, 2020, 21:00:08

Previous topic - Next topic

Ashmoor

@derron
I finally processed all the hints. Thank you!

I didn't know Funtion/Method arguments take precedence over Fields or Globals, now I do.

Regarding writefile, I didn't know that it deletes all content of the file upon opening it. I thought that it does what pressing insert does when typing.

So initiating a pixmap like this: basePM:TPixmap = LockImage(img) does not need UnlockImage(img)?


Ashmoor

I updated the code:

Code (blitzmax) Select

SuperStrict



Global myImg:TImage=LoadImage("graphics/p1_wallpaper.bmp")

Const BI_RGB:Int = 0

Const SPI_SETDESKWALLPAPER:Int = 20
Const SPIF_UPDATEINIFILE:Int = 01


'-----------------------------------------
'
' save an image as a bmp file
'
'------------------------------------------
Global bfh_Type:Short
Global bfh_Size:Int
Global bfh_Reserved:Int = 0
Global bfh_OffBits:Int

Global bfh_header_size:Int = 2 + 4 + 4 + 4
Global cnt#=0

'----------------------------------------------------------------

'----------------------------------------------------------------


Global wallPath$=CurrentDir()+"/graphics/savedwallpp.bmp"
Print wallPath
Print "proc wp:"+(CurrentDir()+"/graphics/savedwallpp.bmp")
Global blackAlpha:Float=0.2

Graphics 800,600
SetBlend ALPHABLEND

Repeat
Cls
DrawImage (myImg,0,0)
SetAlpha (blackAlpha)
SetColor(0,0,0)
DrawRect(0,0,800,600)
SetColor(255,255,255)
SetAlpha(1.0)
Flip

If KeyHit(KEY_ESCAPE) Or AppTerminate() Then End
If KeyHit(KEY_W) Then
'GCSuspend()
'AddBlackToImage(myImg,blackAlpha)
SaveBitmapFromImage(AddBlackToImage(myImg,blackAlpha))

'Wallpaper_Set(wallPath) 'CurrentDir()+"/graphics/savedwallpp.bmp"
cnt:+1
'GCResume()
EndIf

If KeyHit (KEY_P) Then blackAlpha:+0.1
If KeyHit(KEY_O) Then blackAlpha:-0.1



Forever


SaveBitmapFromImage(AddBlackToImage( myImg))
Wallpaper_Set(wallPath) 'CurrentDir()+"/graphics/savedwallpp.bmp"

Wallpaper_Set(wallPath) 'CurrentDir()+"/graphics/savedwallpp.bmp"

'----------------------------------------------------------------



Extern "Win32"
Function SystemParametersInfo:Int(action:Int, param:Int, vparam:Byte Ptr, winini:Int) "win32"="WINBOOL __stdcall  SystemParametersInfo(UINT ,UINT ,PVOID ,UINT )!" '"SystemParametersInfoA@16"
Function SystemParametersInfoW:Int(uiAction:UInt, uiParam:UInt, pvParam:Byte Ptr, fWinIni:UInt) "win32"="WINBOOL __stdcall  SystemParametersInfoW(UINT ,UINT ,PVOID ,UINT )!"
'Function GetLastError() = "GetLastError@0"
End Extern

Function Wallpaper_Set(filename:Byte Ptr)
'note: filename must be real path of the image, not truncated relative path.
Print "filename:"+filename[0]
Local res:Int 'this is to check if the wallpaper was set or an error happened
res=SystemParametersInfo(SPI_SETDESKWALLPAPER, Null, filename, SPIF_UPDATEINIFILE)
Print "res:"+res

EndFunction



Type BitmapInfoHeader
Field biSize:Int
Field biWidth:Int
Field biHeight:Int
Field biPlanes:Short
Field biBitCount:Short
Field biCompression:Int
Field biSizeImage:Int
Field biXPelsPerMeter:Int
Field biYPelsPerMeter:Int
Field biClrUsed:Int
Field biClrImportant:Int
EndType


Function Img_ToBmp2:Int(img:TImage, file:TStream)

    Print "ImgToBMP start"
Local pxmp:TPixmap
Local y:Int
Local bank1:TBank

    pxmp = LockImage(img, , True, False)
If (pxmp = Null)
Return False
    EndIf
       
    file = TStream(file)
Local ptr1:Byte Ptr
ptr1 = pxmp.pixels       


bank1 = CreateStaticBank(ptr1, pxmp.pitch )

For y = 0 To 1000
        WriteBank(bank1, file, 0, pxmp.pitch )
Print " test loop "+y
Next
   
UnlockImage(img)
   
Print "imgTOBMP done "
    Return True

EndFunction


'Summary: Writes an TImage to an open file stream as a BMP format.
Function Img_ToBmp:Int(img:TImage, file:TStream)
Local pxmp:TPixmap, x:Int, y:Int, ptr1:Byte Ptr
Local r:Int, g:Int, b:Int
Local bank1:TBank, size:Int
Local file_size:Int, data_size:Int
Local bih:BitmapInfoHeader=New BitmapInfoHeader

Print "ImgToBMP start"

pxmp = LockImage(img, , True, False)
If (pxmp = Null)
Return False
EndIf

file = LittleEndianStream(file)

If (pxmp.format <> PF_BGR888)
pxmp = pxmp.Convert(PF_BGR888)
EndIf

ptr1 = pxmp.pixels

data_size = pxmp.height * pxmp.pitch
file_size = data_size + bfh_header_size + SizeOf(bih)

'go at start of file
SeekStream(file, 0)

'write file header

bfh_Type = Asc("B") + ( Asc("M") Shl 8 )
WriteShort(file, bfh_Type)

bfh_Size = file_size
WriteInt(file, bfh_Size)

bfh_Reserved = 0
WriteInt(file, bfh_Reserved)

bfh_OffBits= bfh_header_size + SizeOf(bih)
WriteInt(file, bfh_OffBits)


'write info header
bih = New BitmapInfoHeader
bih.biSize = SizeOf(bih)
bih.biWidth = pxmp.width
bih.biHeight = pxmp.height
bih.biPlanes = 1
bih.biBitCount = 24
bih.biCompression = BI_RGB
bih.biSizeImage = data_size
bih.biXPelsPerMeter = 2835
bih.biYPelsPerMeter = 2835
bih.biClrUsed = 0
bih.biClrImportant = 0
bank1 = CreateStaticBank(bih, SizeOf(bih) )
WriteBank(bank1, file, 0, SizeOf(bih) )

'write it top-down
ptr1 :+ (data_size - pxmp.pitch)
For y = 0 Until pxmp.height

bank1 = CreateStaticBank(ptr1, pxmp.pitch )
WriteBank(bank1, file, 0, pxmp.pitch )

ptr1 :- pxmp.pitch
Next


UnlockImage(img)
Print "imgTOBMP done"
Return True
EndFunction


'Summary: Opens a stream and writes ssImg to it as BMP format.
Function SaveBitmapFromImage:Int(ssImg:TImage)
'note: this will save a bmp to my roaming file.
Print "SBFI start"
Local path:String = "graphics/savedwallpp.bmp"
Local file:TStream = WriteFile(path)

If Not file
Print "failed to open existing or to create new file ~q" + path + "~q for writing."
Return False
Else
If Img_ToBmp(ssImg,file)
Print path + " image was created"
CloseStream(file)
Return True
EndIf
EndIf

End Function



Function AddBlackToImage:TImage(img:TImage, alpha:Float=0.3)
'alpha is in the transparency with witch the black box is drawn on top
Print "add black to img start"
Local w:Int = ImageWidth(img)
Local h:Int = ImageHeight(img)

Local r:Float, g:Float, b:Float
Local pixel:Int
Local imgPixel:TRGBvector= New TRGBvector

Local basePM:TPixmap = LockImage(img)
Local finalPM:TPixmap = TPixmap.Create(w, h, PF_RGB888)

Print "here1"

'basePM =
UnlockImage(img)

Print "here2"
For Local i:Int = 0 Until h
For Local j:Int = 0 Until w
pixel = ReadPixel(basePM, j, i)
'imgPixel = GetRGBvectorFromPixel(pixel)
GetRGBvectorFromPixel1(pixel, imgPixel)
imgPixel.DarkenByPercent(alpha)
pixel = GetPixelFromRGBvector(imgPixel)
WritePixel(finalPM, j, i, pixel)
Next
Next
Print "here3"
Local retImg:TImage = LoadImage(finalPM)

Print "add black to img done"

Return retImg

End Function


Type TRGBvector
Field r:Float
Field g:Float
Field b:Float

Method DrawSelf()
Local rStr:String
Local gStr:String
Local bStr:String

rStr = r
rStr = rStr[..5]
gStr = g
gStr = gStr[..5]
bStr = b
bStr = bStr[..5]

DrawText("r:" + rStr + " g:" + gStr + " b:" + bStr, 10, 30)

End Method

'Summary: Adds a little bit of black into
Method DarkenByPercent(alpha:Float)
'This is equivalent to drawing a black pixel on top of current one using "alpha" transparncy
r = Truncate255(r - (r * alpha))
g = Truncate255(g - (g * alpha))
b = Truncate255(b - (b * alpha))
EndMethod

'Summary: Tweaks brightness of all channels (-1 to 1)
Method AdjustBrightness(br:Float)
'This will add/remove a percent of each channel, acting somewhat like overlay layer.
'it is not perfect because on the negative side of the curve it should
'remove a percent of the missing value
'eg: 245 has 10 missing so at br=-1.0 it should be -235, that woud be similar to the br>0

r = Truncate255(r + (r * br))
g = Truncate255(g + (g * br))
b = Truncate255(b + (b * br))

EndMethod

'Summary: Sets RGB values
Method SetRGB:Int(r:Int, g:Int, b:Int)
Self.r = r
Self.g = g
Self.b = b
End Method

EndType


'Summary: Returns RGBvector from int pixel value
Function GetRGBvectorFromPixel:TRGBvector(rgb:Int)
If cnt>=1 Then Print "here 4"
Local rgbV:TRGBvector= New TRGBvector
If cnt>=1 Then Print "here 5"
Local r:Float = ((rgb Shr 16) & $ff) / 255:Float
Local g:Float = ((rgb Shr 8) & $ff) / 255:Float
Local b:Float = ((rgb) & $ff) / 255:Float

r = r * 255; g = g * 255; b = b * 255

rgbV.r = r; rgbV.g = g; rgbV.b = b

Return rgbV

End Function

'Summary: Returns RGBvector from int pixel value
Function GetRGBvectorFromPixel1(rgb:Int, rgbV:TRGBvector Var)

Local r:Float = ((rgb Shr 16) & $ff) / 255:Float
Local g:Float = ((rgb Shr 8) & $ff) / 255:Float
Local b:Float = ((rgb) & $ff) / 255:Float

r = r * 255; g = g * 255; b = b * 255

rgbV.r = r; rgbV.g = g; rgbV.b = b

End Function


'Summary: truncates a value to the interval [0,255]
Function Truncate255:Float(val:Float)
If val < 0 Then val = 0
If val > 255 Then val = 255

Return val
End Function

Function GetPixelFromRGBvector:Int(vec:TRGBvector)
Local pixel:Int

Local r:Int = vec.r
Local g:Int = vec.g
Local b:Int = vec.b

pixel = $ff000000 | (r Shl 16) | (g Shl 8) | b


Return pixel

End Function


and tried it with GDB again, here is the output:

Starting program: M:\gamedev\33 mosaics\programming tests\bmx NG save bitmap.debug.exe
[New Thread 18072.0x3cdc]
warning: FTH: (18072): *** Fault tolerant heap shim applied to current process. This is usually due to previous crashes. ***
[New Thread 18072.0x3490]
[New Thread 18072.0x35a4]
[New Thread 18072.0x3934]
[New Thread 18072.0x35b4]
[New Thread 18072.0x2f00]
[New Thread 18072.0x23cc]
[New Thread 18072.0x3870]
[New Thread 18072.0x3b24]
[New Thread 18072.0x2cdc]
[New Thread 18072.0x4880]
[New Thread 18072.0x41c]
[New Thread 18072.0x1218]
[New Thread 18072.0x27b8]
[Thread 18072.0x27b8 exited with code 0]
[New Thread 18072.0x468]
[New Thread 18072.0x2758]
[New Thread 18072.0x4290]
[New Thread 18072.0xf08]
[New Thread 18072.0x49ac]
[New Thread 18072.0xc2c]
[New Thread 18072.0x19c0]
[Thread 18072.0xc2c exited with code 0]
[Thread 18072.0x19c0 exited with code 0]
[Thread 18072.0x49ac exited with code 0]
[New Thread 18072.0x4834]
[New Thread 18072.0x143c]
[New Thread 18072.0x32e0]
[New Thread 18072.0x3500]
[New Thread 18072.0x3bc8]
warning: HEAP[bmx NG save bitmap.debug.exe]:
warning: Invalid address specified to RtlValidateHeap( 00E70000, 0BE69A20 )

Thread 1 received signal SIGTRAP, Trace/breakpoint trap.
0x775f9c44 in ntdll!RtlCaptureStackContext () from C:\WINDOWS\SYSTEM32\ntdll.dll
(gdb) bt
#0  0x775f9c44 in ntdll!RtlCaptureStackContext () from C:\WINDOWS\SYSTEM32\ntdll.dll
#1  0x77596057 in ntdll!RtlValidateHeap () from C:\WINDOWS\SYSTEM32\ntdll.dll
#2  0x77574640 in ?? () from C:\WINDOWS\SYSTEM32\ntdll.dll
#3  0x723b64e7 in ?? () from C:\WINDOWS\SYSTEM32\AcLayers.dll
#4  0x75677409 in msvcrt!free () from C:\WINDOWS\System32\msvcrt.dll
#5  0x00e70000 in ?? ()
#6  0x00558d6d in ?? ()
#7  0xf8e483ec in ?? ()
#8  0x64084d8b in ?? ()
#9  0x0018158b in ?? ()
Backtrace stopped: Cannot access memory at address 0x8b55ff8f
(gdb)

Ashmoor

I think @Pingus is right, the crash is somewhere here

Code (blitzmax) Select

Function Img_ToBmp2:Int(img:TImage, file:TStream)

    Print "ImgToBMP start"
Local pxmp:TPixmap
Local y:Int
Local bank1:TBank

    pxmp = LockImage(img, , True, False)
If (pxmp = Null)
Return False
    EndIf
       
    file = TStream(file)
Local ptr1:Byte Ptr
ptr1 = pxmp.pixels       


bank1 = CreateStaticBank(ptr1, pxmp.pitch )

For y = 0 To 1000
        WriteBank(bank1, file, 0, pxmp.pitch )
Print " test loop "+y
Next
   
UnlockImage(img)
   
Print "imgTOBMP done "
    Return True

EndFunction


I removed this block and it didn't crash anymore.


Henri

#18
Hi,

put a Debugstop command at the start of the function and execute lines one by one and even follow the execution inside a function with jump button (next to step button). You can check your variables at the debug window and see if they are what you expect.

If there is a big loop and you don't want to iterate all items just put another Debugstop at a convenient location and you can halt the execution after loop or make it conditional like "If i = 500 Then Debugstop" ..

-Henri
- Got 01100011 problems, but the bit ain't 00000001

Derron

Quote from: Ashmoor on June 17, 2020, 00:36:43
@derron
[...]
So initiating a pixmap like this: basePM:TPixmap = LockImage(img) does not need UnlockImage(img)?

You should still use "UnlockImage(img)" after you finished modifying the "basePM" (if you do). For now the comman does nothing - but maybe after an update it would...hmm reupload the pixmap to the gpu (as texture) or emit an event or ... dunno what else it could do.

The important part of the code change above was, to avoid
basePM = newly created pixmap
basePM = some other pixmap

as the first line would create a pixmap (memory operation) just to then free it later on as another pixmap is assigned.



I had issues with "Banks" too (when I wrote some streamed audio stuff). No crashed but stuff which somehow did not work as I thought it should - but in this case it was surely my fault (doing dumb stuff :D).




bye
Ron

Brucey

#20
Hallo.

Seems to be an issue when freeing a previous TBank... The error implies the GC header has become corrupt somehow.


Thread 1 received signal SIGSEGV, Segmentation fault.
GC_free (p=0xb34d5cc) at D:/000_programming/BlitzMaxNG/mod/brl.mod/blitz.mod/bdwgc/malloc.c:588
588         sz = (size_t)hhdr->hb_sz;
(gdb) bt
#0  GC_free (p=0xb34d5cc) at D:/000_programming/BlitzMaxNG/mod/brl.mod/blitz.mod/bdwgc/malloc.c:588
#1  0x0000000000463cfa in bbMemFree (p=<optimized out>)
    at D:/000_programming/BlitzMaxNG/mod/brl.mod/blitz.mod/blitz_memory.c:26
#2  0x000000000041cd71 in _brl_bank_TBank_Delete (o=0xb2ed440)
    at D:/000_programming/BlitzMaxNG/mod/brl.mod/bank.mod/bank.bmx:41
#

Brucey

I've committed a fix to TBank which prevents the attempted freeing of static memory.

If you don't want to update to the latest, this is how Delete() currently looks:

Method Delete()
Assert Not _locked
If _capacity>=0 And Not _static MemFree _buf
End Method

Derron

#22
I think it might have the same issue in "brl.audiosample" ... deleting stuff even if created with "CreateStatic".

Edit ... strike that, there is a "capacity check" in there. But maybe brl.audiosample could learn from TBank and introduce a _static flag as it could have a valid "capacity" then.

bye
Ron

Pingus

Thanks Brucey, the fix seems working fine !

@Ashmoor
Replace the delete function in bank.bmx

\mod\brl.mod\bank.mod

And recompile the mod.


Ashmoor

Thanks guys, I updated Delete() rebuilt modules and works perfectly now.