Author Topic: Loading faster with _Loadimage?  (Read 4989 times)

0 Members and 1 Guest are viewing this topic.

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • View Profile
    • 40wattstudio
Loading faster with _Loadimage?
« on: July 16, 2021, 10:01:45 pm »
My game has a DO LOOP that loads 35 .png images for an opening animation. Each image measures 1280 x 1280 with sizes ranging from 1 to 1.5MB. So about 35 to 52 MB worth of images here.
It takes the game approximately 8-9 seconds to get them all loaded.

Are there any cool tricks with or in conjunction with _LOADIMAGE that might help in reducing load times?

I'm also a bit curious about the Wiki entry about the Mode 32 and Mode 33 options for _LOADIMAGE. For Mode 33, does hardware accelerated mean that it should load images faster? I did some experiments with Mode 33 but didn't notice any time difference.

Marked as best answer by 40wattstudio on July 19, 2021, 02:53:57 pm

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #1 on: July 18, 2021, 12:52:13 am »
File access takes some time. I think LOADIMAGE is fast. Try converting PNG to BMP and see if that makes a difference.

Offline 40wattstudio

  • Newbie
  • Posts: 82
    • View Profile
    • 40wattstudio
Re: Loading faster with _Loadimage?
« Reply #2 on: July 19, 2021, 06:53:42 pm »
I was a bit doubtful because converting everything to .bmp increased all the individual images to about 6MB . . . but I have to say it did cut the load time down to about 5-6 seconds instead of 9. I'm guessing it has to do with the fact that .png is compressed and the decompressing takes longer to process than to deal with a 6MB file (bmp) that's already decompressed.
Thanks for the suggestion!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #3 on: July 20, 2021, 01:17:27 am »
very interesting 40wattstudio

I said before that LOADIMAGE was fast and it is but since you are using BMP files then there is some code that me and bplus steve and others worked on that might be even faster than LOADIMAGE

I will try to find it.
« Last Edit: July 20, 2021, 02:14:26 am by NOVARSEG »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #4 on: July 20, 2021, 02:20:02 am »
The SUB version .  returns H = image height in pixels which can be negative or positive and W = image width in pixels
returns image handle.

The code can handle negative height BMPs too.


Code: QB64: [Select]
  1. Sub loadBMP24 (FILENAME As String, W As Long, H As Long, HANDLE As Long)
  2.  
  3.     Dim OF As _Unsigned Long
  4.     Dim tt As String * 4
  5.     Dim t As String * 3
  6.     Dim pad As Integer
  7.     Dim a As _MEM 'not defined
  8.  
  9.     N = 0
  10.  
  11.     Open FILENAME For Binary As #1
  12.     Get #1, 11, OF 'Offset to picture dat
  13.     Get #1, 15, L 'Header size
  14.     Get #1, , W 'image width
  15.     Get #1, , H 'image height
  16.     Get #1, , I 'biPlanes. Specifies the number of color planes on the target device.
  17.     Get #1, , I 'bits per pixel. Must = 24 for the program to work.
  18.     If I <> 24 Then W = 0: GoTo LL1
  19.     HANDLE = _NewImage(W, Abs(H), 32)
  20.     a = _MemImage(HANDLE)
  21.     pad = 4 - (W * 3) Mod 4
  22.     If pad = 4 Then pad = 0 'pad = multiple of 4
  23.     If H < 0 Then
  24.         For R = 0 To Abs(H) - 1
  25.             For C = 1 To W * 3 Step 3
  26.                 Get #1, R * (W * 3 + pad) + C + OF, t
  27.                 tt = t + Chr$(255)
  28.                 _MemPut a, a.OFFSET + N, tt
  29.                 N = N + 4
  30.             Next C
  31.         Next R
  32.     End If
  33.     If H > 0 Then
  34.         For R = H - 1 To 0 Step -1
  35.             For C = 1 To W * 3 Step 3
  36.                 Get #1, R * (W * 3 + pad) + C + OF, t
  37.                 tt = t + Chr$(255)
  38.                 _MemPut a, a.OFFSET + N, tt
  39.                 N = N + 4
  40.             Next C
  41.         Next R
  42.     End If
  43.     LL1:
  44.     Close

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #5 on: July 22, 2021, 03:19:34 am »
Well the above code was tested again and it is really slow.  I think it has to do with the file access. Trying to read more bytes of data from a file per file read.

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #6 on: July 22, 2021, 11:18:15 pm »
Ok

    DIM fileBuffer AS STRING * 16383
    DIM m AS _MEM
    m = _MEM(fileBuffer)

I need these 3 lines of code to work with GET.  fileBuffer is the memory block with a max size of 16383 bytes.  MEMGET must   access fileBuffer and then do some calcs and MEMPUT to the handle given by NEWIMAGE etc.

In assembler I could make a DOS function call to READFILE and it will read a file by a specified number of bytes and put those bytes in, say, fileBuffer.    GET has no such number input as it gets it's length info from string length.  Right away we gotta do some serious gymnastics to get this to work.

The objective here is to read a file by chunks of a least 16383 bytes at a time instead of 3 bytes at a time. This should seriously speed up the code.

MEM works with fixed length strings (which is good). The last file read will be a chunk either 0 bytes or less than 16383 bytes, so that looks like a variable length string is involved but MEM must work with fileBuffer which has a fixed max length of 16383.

If the last chunk is , say, 501 bytes it must be stored to fileBuffer.  In that way MEM references the same memory block.

However GET wants something like string = space$(chunksize)  but now MEM is hooped I think.

Maybe our API wizard could give us a READFILE SUB

(write a specified number of bytes to fileBuffer)



***** correction

I said "read a file by chunks of a least 16383 bytes"

should read " read a file by chunks of 16383 bytes or less"

« Last Edit: July 23, 2021, 04:07:13 pm by NOVARSEG »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #7 on: July 23, 2021, 07:14:09 pm »
@SpriggsySpriggs

I'm trying to code a fast BMP viewer /slide show.  The code is essentially complete but it is very slow due to inefficient file access.  GET statement makes it a nightmare to code this properly.  GET is so prehistoric it just don't work for what I want to do.

Can you write a READFILE sub? (API) That will make GET obsolete.   GET can be still used to support existing code. 

READFILE SUB criteria

A file is read by a specified number of bytes which is stored in a memory block named fileBuffer

fileBuffer can be  Dimensioned outside of the sub maybe like

DIM SHARED fileBuffer as STRING * 16383   (example length)

Now API might have a different way to describe fileBuffer etc ?

So all we got to do is specify the file name and bytes to read. Of course the number of bytes to read can't exceed the string length.

GET is like trying to write an OS with batch file commands.



   

« Last Edit: July 23, 2021, 07:24:41 pm by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Loading faster with _Loadimage?
« Reply #8 on: July 23, 2021, 08:13:47 pm »
There’s nothing wrong with GET.

If you want the fastest load times, just get the whole file at once and then parse it.

OPEN file$ FOR BINARY AS #1
temp$ = SPACE$(LOF(1))
GET #1, 1, temp$
CLOSE


Then parse it out in 12345 bytes at a time, until finished, if that’s what you need.



(And, since you’re one of those folks who likes to argu, “Noooo, my way is much better!!”, I just want to bring one thing to your attention in libqb.cpp:

Code: [Select]
                    if (ReadFile(f_w->file_handle,data,size2,(unsigned long*)&bytesread,NULL)){
                        data+=bytesread; f->pos+=bytesread; gfs_read_bytes_value+=bytesread;
                        if (bytesread!=size2){   
                            ZeroMemory(data,size+(size2-bytesread));//nullify remaining buffer
                            f->eof_passed=1; return -10;
                        }//eof passed
                        }else{

As you can see, QB64 is already using ReadFile internally for GET…

Which means it can’t be as obsolete as you apparently think it is.  :P
« Last Edit: July 23, 2021, 08:27:20 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #9 on: July 23, 2021, 09:37:58 pm »
 @SMcNeill

I have learned that you are usually correct and yes I love a good argument as long as it is a constructive one.

So READFILE is inside some compiled C++  code.  The thing is GET statement gets it's bytesToRead value from string length.  GET should be like this

GET handle, bytesToRead,  fileBuffer

where handle is a file handle
bytesToRead is the number of bytes to read from the file
fileBuffer is where the file bytes are stored.

Only one fileBuffer.

However you can not enter a bytesToRead value directly into GET.   GET essentially second guesses what the coder would REALLY like.  That leads to complications.

GET figures out bytesToRead from (example)

string1 = space$(bytesToRead)
GET #1,string1   etc

so string1 is a variable length string - not fixed.

The thing is MEM  works with a single memory block (fixed length) but GET works with multiple (variable) memory blocks (strings). It does not work out too well.

Quote
If you want the fastest load times, just get the whole file at once and then parse it.

I thought about that and it does work but to me that is a band aid approach.

Trust me!   if I had a READFILE API sub the BMP viewer would be a 1000 times faster.

About 50 hours has gone into the BMP viewer why stop there. We have a resident API wizard and so much absolute talent,  what other forum has that  - none.

The other thing is that a READFILE sub is almost the same as a WRITEFILE sub


Think of all the high speed file access QB64 can do with some practical API subs.  Some might think it is UNBASIC.  Well look at modern day OSes has anyone noticed that they do not resemble the OSes when BASIC was invented. 




« Last Edit: July 23, 2021, 10:11:22 pm by NOVARSEG »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #10 on: July 23, 2021, 10:27:37 pm »
*******

example subs

ReadFile handle, bytesToRead, rFileBuffer

WriteFile handle, bytesToWrite, wFileBuffer

It might be advantage to have two buffers, one for read and one for write.

« Last Edit: July 23, 2021, 10:32:11 pm by odin »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #11 on: July 24, 2021, 10:03:00 pm »
Lets look into the WIndows readfile etc


https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile

Quote
Reads data from the specified file or input/output (I/O) device. Reads occur at the position specified by the file pointer if supported by the device.

That is OK we might as well include a file pointer sub too. here is how WIndows wants the sub  (er whatever it is) to look like

BOOL ReadFile(
  HANDLE       hFile,
  LPVOID       lpBuffer,
  DWORD        nNumberOfBytesToRead,
  LPDWORD      lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);


I don't what the BOOL is . Those parameters look OK but there is LPOVERLAPPED lpOverlapped and that one i'm not familiar with.

There is only a 5 minute window to edit posts so this post and  other posts will have mistakes so keep that in mind.

Quote
lpOverlapped

A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise it can be NULL.

If hFile is opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must point to a valid and unique OVERLAPPED structure, otherwise the function can incorrectly report that the read operation is complete.

For an hFile that supports byte offsets, if you use this parameter you must specify a byte offset at which to start reading from the file or device. This offset is specified by setting the Offset and OffsetHigh members of the OVERLAPPED structure. For an hFile that does not support byte offsets, Offset and OffsetHigh are ignored.

For more information about different combinations of lpOverlapped and FILE_FLAG_OVERLAPPED, see the Remarks section and the Synchronization and File Position section.

and that is why we pay $20,000 for an expert to explain this all to us.
« Last Edit: July 24, 2021, 10:08:17 pm by NOVARSEG »

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #12 on: July 24, 2021, 10:18:26 pm »
The only way I can learn Windows API is with a tutor. I'm not gonna spend 1000s of hours trying to figure this out on my own.   

Until then I'm not gonna be able to finish the BMP viewer.  Hey BG your windows API is bullshit.


Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Loading faster with _Loadimage?
« Reply #13 on: July 24, 2021, 10:23:31 pm »
I've decided to leave the forum.  nothing more to do here. API is the last hurdle - it is not worth it.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Loading faster with _Loadimage?
« Reply #14 on: July 24, 2021, 11:03:04 pm »
I've decided to leave the forum.  nothing more to do here. API is the last hurdle - it is not worth it.

Bye.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!