Author Topic: _CopyImage crashing my program after a while, can somebody please help?  (Read 6801 times)

0 Members and 1 Guest are viewing this topic.

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
sorry  Ok the whole code

Quote
Do Until a& = m.SIZE - 4
                       
        c~& = _MemGet(m, m.OFFSET + a&, _Unsigned Long)
               
        If c~& = oldcolor~& Then
            _MemPut m, m.OFFSET + a&, newcolor~&
       
End If

a& = a& + 4
    Loop

also try

DIM a AS _Unsigned Long



Quote
Do Until a = m.SIZE - 4
                       
        c~& = _MemGet(m, m.OFFSET + a, _Unsigned Long)
               
        If c~& = oldcolor~& Then
            _MemPut m, m.OFFSET + a, newcolor~&
       
End If

a = a + 4
    Loop

« Last Edit: May 17, 2021, 11:22:48 pm by NOVARSEG »

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
sorry  Ok the whole code
also try
DIM a AS _Unsigned Long

My reply didn't post for some reason. I finally got it to stop crashing with a combination of suggestions - thanks for your help guys!

However seeing this latest message I will have some followup questions tomorrow...

Thanks again
« Last Edit: May 18, 2021, 12:25:47 am by madscijr »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Sorry again. Lets say m.size = 8 (bytes)

the first 4 bytes are memgetted . byte 0, 1, 2, 3

then

 a = a +4  and right away the condition

DO Until a = m.SIZE - 4 

a = (8 - 4) and that exits the DO  LOOP

but bytes 4, 5, 6, 7 don't get memgetted

so

Quote
DO

    c~& = _MemGet(m, m.OFFSET + a, _Unsigned Long)

    IF c~& = oldcolor~& THEN
       _MemPut m, m.OFFSET + a, newcolor~&

    END IF

    a = a + 4
    IF a = m.size THEN EXIT DO
LOOP

which is one of the weaknesses of DO UNTIL etc

Always use EXIT DO

Do Until a = m.SIZE would work, but  there is no sense in LOOPing an extra time if you don't have to.





« Last Edit: May 18, 2021, 01:46:25 am by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Yes, it is doing that. The value retrieved from the function in line 105:
Code: QB64: [Select]
  1.     ColorSprite& = swapcolor&(UniversalSprite&, cBlack&, TileColor&)

is freed in line 113:
Code: QB64: [Select]
  1.     _FREEIMAGE ColorSprite&

Is it possible that swapcolor& is causing a memory leak just by being a function?
Would it be better to instead make it a sub and return the value in a parameter?

The thing is, it seems to me as if there's 3 different areas inside your code where you're calling swapcolor.  Line 2416, 2476, 2586.

Each of these calls to swapcolor is making a duplicate image of your screen (that's what _COPYIMAGE does), and yet there's no call to _FREEIMAGE those images.  Each and every one of these routines need to FREEIMAGE the image when you're finished with it.  Doing it in just one place won't handle the issue.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
One option, at least in this case, would be to store and free the images in swapcolor itself, like so:

Code: [Select]
FUNCTION swapcolor& (handle&, oldcolor~&, newcolor~&)
    DIM m AS _MEM
    DIM a&
    DIM c AS _UNSIGNED LONG


    STATIC perma_handle AS LONG 'save  the handle between function calls
    IF perma_handle < -1 THEN _FREEIMAGE perma_handle 'if you've used this swapcolor before, then free the old screen
    perma_handle = _COPYIMAGE(handle&, 32) 'get a copy of the screen
    swapcolor& = perma_handle 'and assign it to the FUNCTION so we can return it back for use elsewhere

    m = _MEMIMAGE(swapcolor&)
    DO
        IF _MEMGET(m, m.OFFSET + a&, _UNSIGNED LONG) = oldcolor~& THEN _MEMPUT m, m.OFFSET + a&, newcolor~&
        a& = a& + 4
    LOOP UNTIL a& = m.SIZE
    _MEMFREE m

END FUNCTION ' swapcolor&
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
Thanks for your reply.

The thing is, it seems to me as if there's 3 different areas inside your code where you're calling swapcolor.  Line 2416, 2476, 2586.

Are you looking at the original code? That's why I added
Code: QB64: [Select]
  1.  _FREEIMAGE ColorSprite&
a few lines below each call to swapcolor.

Each of these calls to swapcolor is making a duplicate image of your screen (that's what _COPYIMAGE does), and yet there's no call to _FREEIMAGE those images. 

I am not sending an image of the screen to swapcolor, just a single tile-sized image.

Each and every one of these routines need to FREEIMAGE the image when you're finished with it. 
Doing it in just one place won't handle the issue.

That is a question I had, which is, if a function returns a value directly, like
Code: QB64: [Select]
  1. swapcolor& = _CopyImage(handle&, 32)
you can free the value returned to the calling code outside the function,
but how do you free the function's copy?

One option, at least in this case, would be to store and free the images in swapcolor itself, like so:
Code: [Select]
FUNCTION swapcolor& (handle&, oldcolor~&, newcolor~&)
    STATIC perma_handle AS LONG 'save  the handle between function calls

So wait a minute, if we have a function that sends an image handle back as its return value, it's not enough to do a freeimage on the returned handle in the calling code?

Did you see NOVARSEG's responses regarding the memcopy and the loops inside swapcolor?
It sounds like the swapcolor routine needs some work - although it seems to be working for me after changing the variable types:
Code: QB64: [Select]
  1.     Dim m As _MEM
  2.     DIM a As _OFFSET
  3.  

Thanks again!
« Last Edit: May 18, 2021, 08:57:03 am by madscijr »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
trying out some tests with m.size
keep getting "cannot convert _OFFSET type to other types" error

I have never been able to get m.size to work. In DO LOOPs FOR NEXT LOOPS it just don't work for me.  Maybe the version Im using is outdated?

It looks like m.size is a pointer (_OFFSET)  why?

Like b = m.size is impossible

Another thing,   m.size is redundant, you can get the same value with

_WIDTH * _HEIGHT  * 4

The only thing I got to work is PRINT m.size

but this crashes

  FOR T = 0 TO m.size - 1 STEP 4
« Last Edit: May 18, 2021, 07:11:05 pm by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
M.size is a pointer, as it points to an offset of memory.  In 32-bit QB64, it’s only 4-bytes in size.  In 64-bit QB64, it’s 8-bytes.

Make your variables _OFFSETs when working with M.SIZE and you won’t have any issues.  Or convert your offset to a suitable integer value as below:


DIM x AS INTEGER
DIM m AS _MEM
m = _MEM(x)
PRINT m.OFFSET
PRINT ConvertOffset(m.OFFSET)


FUNCTION ConvertOffset&& (value AS _OFFSET)
$CHECKING:OFF
DIM m AS _MEM 'Define a memblock
m = _MEM(value) 'Point it to use value
$IF 64BIT THEN
    'On 64 bit OSes, an OFFSET is 8 bytes in size.  We can put it directly into an Integer64
    _MEMGET m, m.OFFSET, ConvertOffset&& 'Get the contents of the memblock and put the values there directly into ConvertOffset&&
$ELSE
    'However, on 32 bit OSes, an OFFSET is only 4 bytes.  We need to put it into a LONG variable first
    _MEMGET m, m.OFFSET, temp& 'Like this
    ConvertOffset&& = temp& 'And then assign that long value to ConvertOffset&&
$END IF
_MEMFREE m 'Free the memblock
$CHECKING:ON
END FUNCTION
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
PRINT m.OFFSET
PRINT ConvertOffset(m.OFFSET)

did you mean m.size ?

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
PRINT m.OFFSET
PRINT ConvertOffset(m.OFFSET)

did you mean m.size ?

Sure.  M.OFFSET is an offset.  M.SIZE is an offset.  M.ELEMENTSIZE is an offset.  You can convert any of those with the above.  (Or any other offset.)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
i DIMensioned T as _OFFSET but

   
Quote
'FOR T = 0 TO 800 * 600 * 4 - 1 STEP 4
        FOR T = 0 TO m.size - 1 STEP 4
            B = _MEMGET(m, m.OFFSET + T, _UNSIGNED _BYTE)
            G = _MEMGET(m, m.OFFSET + T + 1, _UNSIGNED _BYTE)
            R = _MEMGET(m, m.OFFSET + T + 2, _UNSIGNED _BYTE)
            IF B > 1 THEN B = B - 1
            'IF B = 1 THEN B = 0
            IF G > 1 THEN G = G - 1
            ' IF G = 1 THEN G = 0
            IF R > 1 THEN R = R - 1
            'IF R = 1 THEN R = 0
            _MEMPUT m, m.OFFSET + T, B
            _MEMPUT m, m.OFFSET + T + 1, G
            _MEMPUT m, m.OFFSET + T + 2, R
        NEXT T

still crashes

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
ok  this works

   
Quote
DIM Z AS _UNSIGNED LONG
    DIM W AS _MEM
    W = _MEM(m.SIZE)
    _MEMGET W, W.OFFSET, Z



    'FOR T = 0 TO 800 * 600 * 4 - 1 STEP 4
    FOR T = 0 TO Z - 1 STEP 4
        'PRINT T
        B = _MEMGET(m, m.OFFSET + T, _UNSIGNED _BYTE)
        G = _MEMGET(m, m.OFFSET + T + 1, _UNSIGNED _BYTE)
        R = _MEMGET(m, m.OFFSET + T + 2, _UNSIGNED _BYTE)
        IF B > 1 THEN B = B - 1
        'IF B = 1 THEN B = 0
        IF G > 1 THEN G = G - 1
        ' IF G = 1 THEN G = 0
        IF R > 1 THEN R = R - 1
        'IF R = 1 THEN R = 0
        _MEMPUT m, m.OFFSET + T, B
        _MEMPUT m, m.OFFSET + T + 1, G
        _MEMPUT m, m.OFFSET + T + 2, R
    NEXT T

_MEMGET W, W.OFFSET, Z is just the plain _MEMGET. It works a bit different  than the _MEMGET function

 the _MEMGET function

Z = _MEMGET(W, W.OFFSET, _UNSIGNED LONG)

Ok i gonna show that method too
Quote

    DIM Z AS _UNSIGNED LONG
    DIM W AS _MEM
    W = _MEM(m.SIZE)
    Z = _MEMGET(W, W.OFFSET, _UNSIGNED LONG)
   

    'FOR T = 0 TO 800 * 600 * 4 - 1 STEP 4
    FOR T = 0 TO Z - 1 STEP 4
        'PRINT T
        B = _MEMGET(m, m.OFFSET + T, _UNSIGNED _BYTE)
        G = _MEMGET(m, m.OFFSET + T + 1, _UNSIGNED _BYTE)
        R = _MEMGET(m, m.OFFSET + T + 2, _UNSIGNED _BYTE)
        IF B > 1 THEN B = B - 1
        'IF B = 1 THEN B = 0
        IF G > 1 THEN G = G - 1
        ' IF G = 1 THEN G = 0
        IF R > 1 THEN R = R - 1
        'IF R = 1 THEN R = 0
        _MEMPUT m, m.OFFSET + T, B
        _MEMPUT m, m.OFFSET + T + 1, G
        _MEMPUT m, m.OFFSET + T + 2, R
    NEXT T

works the same.

the whole program to see it work. Mess with m.size until it crashes

Code: QB64: [Select]
  1.  
  2. DIM SHARED screenx%, screeny%, tx1%, ty1%, tx2%, ty2%, x1%, y1%, x2%, y2%, d%, handle2&
  3.  
  4. 'DIM T AS _OFFSET
  5. DIM handle AS LONG
  6. screenx% = 800
  7. screeny% = 600
  8.  
  9. handle = _NEWIMAGE(screenx%, screeny%, 32)
  10.  
  11. m = _MEMIMAGE(handle)
  12.  
  13. SCREEN handle
  14.  
  15.  
  16. ' create new black image with alpha channel
  17. 'handle2& = _NEWIMAGE(screenx%, screeny%, 32)
  18. '_DEST handle2&
  19. 'LINE (0, 0)-(screenx%, screeny%), _RGBA(0, 0, 0, 255), BF
  20. '_DEST 0
  21.  
  22. tx1% = screenx% * RND
  23. ty1% = screeny% * RND
  24. tx2% = screenx% * RND
  25. ty2% = screeny% * RND
  26. x1% = screenx% * RND
  27. y1% = screeny% * RND
  28. x2% = screenx% * RND
  29. y2% = screeny% * RND
  30. d% = 3
  31.  
  32.     COLOR _RGB(256 * RND, 256 * RND, 256 * RND)
  33.     ' smearfx
  34.  
  35.     DIM W AS _MEM
  36.     W = _MEM(m.SIZE)
  37.     Z = _MEMGET(W, W.OFFSET, _UNSIGNED LONG)
  38.    
  39.  
  40.     'FOR T = 0 TO 800 * 600 * 4 - 1 STEP 4
  41.     FOR T = 0 TO Z - 1 STEP 4
  42.         'PRINT T
  43.         B = _MEMGET(m, m.OFFSET + T, _UNSIGNED _BYTE)
  44.         G = _MEMGET(m, m.OFFSET + T + 1, _UNSIGNED _BYTE)
  45.         R = _MEMGET(m, m.OFFSET + T + 2, _UNSIGNED _BYTE)
  46.         IF B > 1 THEN B = B - 1
  47.         'IF B = 1 THEN B = 0
  48.         IF G > 1 THEN G = G - 1
  49.         ' IF G = 1 THEN G = 0
  50.         IF R > 1 THEN R = R - 1
  51.         'IF R = 1 THEN R = 0
  52.         _MEMPUT m, m.OFFSET + T, B
  53.         _MEMPUT m, m.OFFSET + T + 1, G
  54.         _MEMPUT m, m.OFFSET + T + 2, R
  55.     NEXT T
  56.  
  57.     IF x1% < tx1% THEN
  58.         x1% = x1% + d%
  59.     ELSE
  60.         x1% = x1% - d%
  61.     END IF
  62.     IF ABS(x1% - tx1%) < d% THEN
  63.         tx1% = screenx% * RND
  64.     END IF
  65.  
  66.     IF y1% < ty1% THEN
  67.         y1% = y1% + d%
  68.     ELSE
  69.         y1% = y1% - d%
  70.     END IF
  71.     IF ABS(y1% - ty1%) < d% THEN
  72.         ty1% = screeny% * RND
  73.     END IF
  74.  
  75.     IF x2% < tx2% THEN
  76.         x2% = x2% + d%
  77.     ELSE
  78.         x2% = x2% - d%
  79.     END IF
  80.     IF ABS(x2% - tx2%) < d% THEN
  81.         tx2% = screenx% * RND
  82.     END IF
  83.  
  84.     IF y2% < ty2% THEN
  85.         y2% = y2% + d%
  86.     ELSE
  87.         y2% = y2% - d%
  88.     END IF
  89.     IF ABS(y2% - ty2%) < d% THEN
  90.         ty2% = screeny% * RND
  91.     END IF
  92.  
  93.     LINE (x1%, y1%)-(x2%, y2%)
  94.  
  95. SUB smearfx ()
  96.     _LIMIT 50
  97.     LINE (0, 0)-(screenx%, screeny%), _RGBA(0, 0, 0, 1), BF
  98.     _PUTIMAGE (0, 0), handle2&, 0
  99.     LINE (x1%, y1%)-(x2%, y2%)
  100.     _DISPLAY
  101.  




« Last Edit: May 18, 2021, 11:44:39 pm by NOVARSEG »