Latest strange image drawing bugs killed

This commit is contained in:
djes
2017-06-15 15:15:02 +02:00
parent 55bbe10378
commit e67076802b

254
PBMap.pb
View File

@@ -298,7 +298,6 @@ Module PBMap
MemoryCacheAccessNB.i ; Count the access to the memory cache. =0 no access ; >0 download threads ; -1 cleaning MemoryCacheAccessNB.i ; Count the access to the memory cache. =0 no access ; >0 download threads ; -1 cleaning
MemoryCacheAccessNBMutex.i ; Memorycache access variable mutual exclusion MemoryCacheAccessNBMutex.i ; Memorycache access variable mutual exclusion
DownloadSlots.i ; Actual nb of used download slots DownloadSlots.i ; Actual nb of used download slots
DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var
List TracksList.Tracks() ; To display a GPX track List TracksList.Tracks() ; To display a GPX track
List Markers.Marker() ; To diplay marker List Markers.Marker() ; To diplay marker
@@ -1053,72 +1052,50 @@ Module PBMap
EndProcedure EndProcedure
;-*** ;-***
; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack)
Procedure MemoryCacheManagement() Procedure MemoryCacheManagement()
; MemoryCache access management LockMutex(PBMap\MemoryCacheAccessNBMutex) ; Prevents thread to start or finish
LockMutex(PBMap\MemoryCacheAccessNBMutex) Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA)
; If MemoryCache is not being used by any download thread Protected CacheLimit = PBMap\Options\MaxMemCache * 1024
If PBMap\MemoryCacheAccessNB = 0 MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5)
PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous If CacheSize > CacheLimit
;UnlockMutex(PBMap\MemoryCacheAccessNBMutex) MyDebug(" Cache full. Trying cache cleaning", 5)
; If cache size exceeds limit, try to delete the oldest tiles used (first in the time stack) ResetList(PBMap\MemCache\ImagesTimeStack())
Protected CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) ; Try to free half the cache memory (one pass)
Protected CacheLimit = PBMap\Options\MaxMemCache * 1024 While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half
MyDebug("Cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey
If CacheSize > CacheLimit ; Is the loading over
MyDebug(" Cache full. Trying cache cleaning", 5) If PBMap\MemCache\Images(CacheMapKey)\Tile <= 0 ;TODO Should not verify this var directly
ResetList(PBMap\MemCache\ImagesTimeStack()) MyDebug(" Delete " + CacheMapKey, 5)
; Try to free half the cache memory (one pass) If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage)
While NextElement(PBMap\MemCache\ImagesTimeStack()) And CacheSize > (CacheLimit / 2) ; /2 = half FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage)
Protected CacheMapKey.s = PBMap\MemCache\ImagesTimeStack()\MapKey MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5)
;Protected Image = PBMap\MemCache\Images(CacheMapKey)\nImage PBMap\MemCache\Images(CacheMapKey)\nImage = 0
; Is the loading over
If PBMap\MemCache\Images(CacheMapKey)\Tile = -1
MyDebug(" Delete " + CacheMapKey, 5)
If PBMap\MemCache\Images(CacheMapKey)\nImage;IsImage(PBMap\MemCache\Images(CacheMapKey)\nImage)
FreeImage(PBMap\MemCache\Images(CacheMapKey)\nImage)
MyDebug(" and free image nb " + Str(PBMap\MemCache\Images(CacheMapKey)\nImage), 5)
PBMap\MemCache\Images(CacheMapKey)\nImage = 0
EndIf
DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey)
DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1)
ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0
MyDebug(" Delete " + CacheMapKey, 5)
DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey)
DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1)
ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0
; If the thread is running, try to abort the download
If PBMap\MemCache\Images(CacheMapKey)\Tile\Download
AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download)
EndIf
EndIf EndIf
CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA) DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey)
Wend DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1)
MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5) ; ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile = 0
If CacheSize > CacheLimit ; MyDebug(" Delete " + CacheMapKey, 5)
MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5) ; DeleteMapElement(PBMap\MemCache\Images(), CacheMapKey)
; DeleteElement(PBMap\MemCache\ImagesTimeStack(), 1)
; ElseIf PBMap\MemCache\Images(CacheMapKey)\Tile > 0
; ; If the thread is running, try to abort the download
; If PBMap\MemCache\Images(CacheMapKey)\Tile\Download
; AbortHTTP(PBMap\MemCache\Images(CacheMapKey)\Tile\Download) ; Could lead to error
; EndIf
EndIf EndIf
CacheSize = MapSize(PBMap\MemCache\Images()) * Pow(PBMap\TileSize, 2) * 4 ; Size of a tile = TileSize * TileSize * 4 bytes (RGBA)
Wend
MyDebug(" New cache size : " + Str(CacheSize/1024) + " / CacheLimit : " + Str(CacheLimit/1024), 5)
If CacheSize > CacheLimit
MyDebug(" Cache cleaning unsuccessfull, can't add new tiles.", 5)
EndIf EndIf
; We're no more accessing MemoryCache
;LockMutex(PBMap\MemoryCacheAccessNBMutex)
PBMap\MemoryCacheAccessNB = 0 ; Not really useful as the download thread are now blocked
EndIf EndIf
UnlockMutex(PBMap\MemoryCacheAccessNBMutex) UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
EndProcedure EndProcedure
Procedure.i GetTileFromHDD(CacheFile.s) Procedure.i GetTileFromHDD(CacheFile.s)
Protected nImage.i, LifeTime.i, MaxLifeTime.i Protected nImage.i, LifeTime.i, MaxLifeTime.i
MaxLifeTime.i = PBMap\Options\TileLifetime
If FileSize(CacheFile) > 0 ; <> -1
; Manage tile file lifetime
If MaxLifeTime <> -1
LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created
If LifeTime > MaxLifeTime
MyDebug(" Deleting too old (" + StrU(LifeTime) + " secs) " + CacheFile, 3)
DeleteFile(CacheFile)
ProcedureReturn #False
EndIf
EndIf
; Everything is OK, loads the file ; Everything is OK, loads the file
nImage = LoadImage(#PB_Any, CacheFile) nImage = LoadImage(#PB_Any, CacheFile)
If nImage If nImage
@@ -1132,9 +1109,6 @@ Module PBMap
MyDebug(" Can't delete faulty image file " + CacheFile, 3) MyDebug(" Can't delete faulty image file " + CacheFile, 3)
EndIf EndIf
EndIf EndIf
Else
MyDebug(" Failed loading " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3)
EndIf
ProcedureReturn #False ProcedureReturn #False
EndProcedure EndProcedure
@@ -1167,49 +1141,21 @@ Module PBMap
Threaded Progress = 0, Quit = #False Threaded Progress = 0, Quit = #False
Procedure GetImageThread(*Tile.Tile) Procedure GetImageThread(*Tile.Tile)
MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5)
LockMutex(PBMap\DownloadSlotsMutex)
; Is there's no free download slot, abort
If PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because no free download slot.", 5)
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
UnlockMutex(PBMap\DownloadSlotsMutex)
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
ProcedureReturn
EndIf
PBMap\DownloadSlots + 1
UnlockMutex(PBMap\DownloadSlotsMutex)
; *** Waits for a free download slot
; LockMutex(PBMap\DownloadSlotsMutex)
; While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots
; UnlockMutex(PBMap\DownloadSlotsMutex)
; If ElapsedMilliseconds() - *Tile\Time > 10000
; *Tile\Size = 0 ; \Size = 0 signals that the download has failed
; MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5)
; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
; ProcedureReturn #False
; EndIf
; MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5)
; Delay(20)
; LockMutex(PBMap\DownloadSlotsMutex)
; Wend
; PBMap\DownloadSlots + 1
; UnlockMutex(PBMap\DownloadSlotsMutex)
; ***
; MemoryCache access management
LockMutex(PBMap\MemoryCacheAccessNBMutex) LockMutex(PBMap\MemoryCacheAccessNBMutex)
MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5)
; If MemoryCache is currently being cleaned, abort ; If MemoryCache is currently being cleaned, abort
If PBMap\MemoryCacheAccessNB = -1 ; If PBMap\MemoryCacheAccessNB = -1
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5) ; MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5)
*Tile\Size = 0 ; \Size = 0 signals that the download has failed ; *Tile\Size = 0 ; \Size = 0 signals that the download has failed
UnlockMutex(PBMap\MemoryCacheAccessNBMutex) ; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread ; UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
ProcedureReturn ; ProcedureReturn
EndIf ; EndIf
; We're accessing MemoryCache ; We're accessing MemoryCache
PBMap\MemoryCacheAccessNB + 1 PBMap\MemoryCacheAccessNB + 1
UnlockMutex(PBMap\MemoryCacheAccessNBMutex) UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
*Tile\Size = 0
*Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous) *Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous)
If *Tile\Download If *Tile\Download
Repeat Repeat
@@ -1242,12 +1188,8 @@ Module PBMap
; End of the memory cache access ; End of the memory cache access
LockMutex(PBMap\MemoryCacheAccessNBMutex) LockMutex(PBMap\MemoryCacheAccessNBMutex)
PBMap\MemoryCacheAccessNB - 1 PBMap\MemoryCacheAccessNB - 1
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
; Frees a download slot
LockMutex(PBMap\DownloadSlotsMutex)
PBMap\DownloadSlots - 1
UnlockMutex(PBMap\DownloadSlotsMutex)
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
EndProcedure EndProcedure
;-*** ;-***
@@ -1298,41 +1240,58 @@ Module PBMap
MyDebug("Key : " + key + " added in memory cache", 4) MyDebug("Key : " + key + " added in memory cache", 4)
EndIf EndIf
; If there's no active download thread for this tile ; If there's no active download thread for this tile
If *timg\Tile <= 0 If *timg\Tile <= 0
; Try To load it from HD ; Manage tile file lifetime, delete if too old
*timg\nImage = GetTileFromHDD(CacheFile.s) If PBMap\Options\TileLifetime <> -1
If Date() - GetFileDate(CacheFile, #PB_Date_Modified) > PBMap\Options\TileLifetime ; If Lifetime > MaxLifeTime ; There's a bug with #PB_Date_Created
MyDebug(" Deleting too old " + CacheFile, 3)
DeleteFile(CacheFile)
EndIf
EndIf
; Try To load it from HD
*timg\nImage = 0
*timg\Size = FileSize(CacheFile)
If *timg\Size > 0
*timg\nImage = GetTileFromHDD(CacheFile.s)
Else
MyDebug(" Failed loading from HDD " + CacheFile + " -> Filesize = " + FileSize(CacheFile), 3)
EndIf
If *timg\nImage If *timg\nImage
; Image found and loaded from HDD ; Image found and loaded from HDD
*timg\Alpha = 0 *timg\Alpha = 0
UnlockMutex(PBMap\MemoryCacheAccessNBMutex) UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
ProcedureReturn *timg ProcedureReturn *timg
EndIf Else
; If GetTileFromHDD failed, will load it (again?) from the web (see below) ; If GetTileFromHDD failed, will load it (again?) from the web
If *timg\nImage = 0 If PBMap\ThreadsNB < PBMap\Options\MaxThreads
; Launch a new web loading thread If PBMap\DownloadSlots < PBMap\Options\MaxDownloadSlots
If PBMap\ThreadsNB < PBMap\Options\MaxThreads ; Launch a new web loading thread
Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile)) PBMap\DownloadSlots + 1
If *NewTile Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile))
With *NewTile If *NewTile
; New tile parameters With *NewTile
\key = key ; New tile parameters
\URL = URL \key = key
\CacheFile = CacheFile \URL = URL
\nImage = 0 \CacheFile = CacheFile
\Time = ElapsedMilliseconds() \nImage = 0
\GetImageThread = CreateThread(@GetImageThread(), *NewTile) \Time = ElapsedMilliseconds()
If \GetImageThread \GetImageThread = CreateThread(@GetImageThread(), *NewTile)
*timg\Tile = *NewTile ; There's now a loading thread If \GetImageThread
*timg\Alpha = 0 *timg\Tile = *NewTile ; There's now a loading thread
MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3) *timg\Alpha = 0
PBMap\ThreadsNB + 1 MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3)
Else PBMap\ThreadsNB + 1
MyDebug(" Can't create get image thread to get " + CacheFile, 3) Else
FreeMemory(*NewTile) MyDebug(" Can't create get image thread to get " + CacheFile, 3)
EndIf FreeMemory(*NewTile)
EndWith EndIf
Else EndWith
MyDebug(" Error, can't allocate memory for a new tile loading thread", 3) Else
MyDebug(" Error, can't allocate memory for a new tile loading thread", 3)
EndIf
Else
MyDebug(" Thread needed " + key + " for image " + CacheFile + " canceled because no free download slot.", 5)
EndIf EndIf
Else Else
MyDebug(" Error, maximum threads nb reached", 3) MyDebug(" Error, maximum threads nb reached", 3)
@@ -2505,16 +2464,18 @@ Module PBMap
*Tile = EventData() *Tile = EventData()
key = *Tile\key key = *Tile\key
*Tile\Download = 0 *Tile\Download = 0
PBMap\MemCache\Images(key)\Tile = *Tile\Size If FindMapElement(PBMap\MemCache\Images(), key) <> 0
If *Tile\Size ; <> 0 ; If the map element has not been deleted during the thread lifetime (should not occur)
; Web loading thread has finished successfully PBMap\MemCache\Images(key)\Tile = *Tile\Size
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) If *Tile\Size
PBMap\MemCache\Images(key)\Tile = -1 PBMap\MemCache\Images(key)\Tile = -1 ; Web loading thread has finished successfully
Else Else
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile) PBMap\MemCache\Images(key)\Tile = 0
PBMap\MemCache\Images(key)\Tile = 0 EndIf
EndIf EndIf
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile)
PBMap\ThreadsNB - 1 PBMap\ThreadsNB - 1
PBMap\DownloadSlots - 1
PBMap\Redraw = #True PBMap\Redraw = #True
EndSelect EndSelect
EndProcedure EndProcedure
@@ -2585,11 +2546,6 @@ Module PBMap
\Window = Window \Window = Window
\Timer = 1 \Timer = 1
\Mode = #MODE_DEFAULT \Mode = #MODE_DEFAULT
\DownloadSlotsMutex = CreateMutex()
If \DownloadSlotsMutex = #False
MyDebug("Cannot create a mutex", 0)
End
EndIf
\MemoryCacheAccessNB = 0 \MemoryCacheAccessNB = 0
\MemoryCacheAccessNBMutex = CreateMutex() \MemoryCacheAccessNBMutex = CreateMutex()
If \MemoryCacheAccessNBMutex = #False If \MemoryCacheAccessNBMutex = #False
@@ -2913,10 +2869,10 @@ CompilerIf #PB_Compiler_IsMainFile
CompilerEndIf CompilerEndIf
; IDE Options = PureBasic 5.60 (Windows - x64) ; IDE Options = PureBasic 5.60 (Windows - x64)
; CursorPosition = 1181 ; CursorPosition = 1066
; FirstLine = 1156 ; FirstLine = 1384
; Folding = ------------------- ; Folding = -------------------
; EnableThread ; EnableThread
; EnableXP ; EnableXP
; CompileSourceDirectory ; CompileSourceDirectory
; Watchlist = PBMap::PBMap\DownloadSlots ; DisablePurifier = 1,1,1,1