The MASM Forum Archive 2004 to 2012

General Forums => The Laboratory => Topic started by: Jimg on February 26, 2009, 11:06:12 PM

Title: Graphics again.
Post by: Jimg on February 26, 2009, 11:06:12 PM
I'm working on a blink comparator, it switches between two images at a set interval for comparison.
The problem is - I'm not able blit the full image fast enough.
The attached program doesn't use actual images, it just blinks between two colors by bliting from one memory dc or the other, one gray, one orange.
    .elseif eax==WM_PAINT

        inv BeginPaint,hWnd,ADDR ps
        mov hdc,eax
        neg toggle
        .if sign?
            inv BitBlt,hdc,0,0,mwidth,mheight,mdc,0,0,SRCCOPY
        .else
            inv BitBlt,hdc,0,0,mwidth,mheight,mdc2,0,0,SRCCOPY
        .endif
        inv EndPaint,hWnd,ADDR ps

I've tried all the limited number of things I can find to do with no success.
If you run the program, you will probably be able to see where the vertical retrace occurs.  I added Michaels vertical blanking routine.  To active it, press a key, to deactivate, press a key again.  Activating the retrace code makes the problem stand still on the screen, but it is still there.
What is the proper way to avoid this problem?
.nolist
include \masm32\include\masm32rt.inc
.list
.data?
hInst dd ?
.code
.data
ClassName       DB "StdWindow",0
szAppName       DB "test",0
align 4
wc WNDCLASS <CS_HREDRAW or CS_VREDRAW,WndProc,0,0,0,0,0,0,0,ClassName>

.data?
message MSG <>
hwindow dd ?
hMenu   dd ?
SWidth  dd ?    ; screen width
SHeight dd ?    ; screen height
.code
inv equ invoke
Program:
    inv InitCommonControls
    inv GetModuleHandle,0
    mov hInst,eax
    mov wc.hInstance,eax   ; save for later
    inv LoadIcon, 0, IDI_APPLICATION
    mov wc.hIcon,eax
    inv LoadCursor, 0, IDC_ARROW
    mov wc.hCursor,eax
    inv RegisterClass, addr wc
    ;inv LoadMenu, hInst, MNU
    mov hMenu,0;eax
    call GetScreenSetup   
    inv CreateWindowEx,WS_EX_CLIENTEDGE,addr ClassName,addr szAppName,WS_OVERLAPPEDWINDOW,
           0,0,SWidth,SHeight,0,hMenu,hInst,0
    mov hwindow,eax
    inv ShowWindow, hwindow, SW_SHOWNORMAL
    inv UpdateWindow, hwindow
    .repeat
        inv GetMessage,addr message,0,0,0
        .break .if !eax
        inv TranslateMessage,addr message
        inv DispatchMessage,addr message
    .until 0
    inv ExitProcess,message.wParam

GetScreenSetup proc
    inv GetSystemMetrics,SM_CXSCREEN  ; screen width
    mov SWidth,eax
    inv GetSystemMetrics,SM_CYSCREEN
    mov SHeight,eax
ret
GetScreenSetup endp

.data?
hWin dd ?   ; dialog handle
hdc  dd ?   ; temp dc of dialog
mdc  dd ?   ; memory dc of hidden buffer
mdc2 dd ?   ; scratch for loading images

hbm1 dd ?   ; bitmap for hidden buffer mdc
hbm2 dd ?   ; mdc2

crect RECT <>
mwidth  equ crect.right  ; total width of client rectangle in pixels
mheight equ crect.bottom ; total height in pixels

hbrush1 dd ?
hbrush2 dd ?
usevert dd ?
.data
toggle dd 1
.code
TimerProc proc hwnd,imsg,tid,ctime  ; timer callback routine.
    inv InvalidateRect,hWin,0,0
ret
TimerProc endp

WndProc Proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    local ps:PAINTSTRUCT

    mov eax,uMsg
    .if eax==WM_COMMAND
    .elseif eax==WM_ERASEBKGND
        mov eax,1
        jmp WndRet
    .elseif eax==WM_LBUTTONDOWN
        inv InvalidateRect,hWin,0,0
    .elseif eax==WM_PAINT

        inv BeginPaint,hWnd,ADDR ps
        mov hdc,eax
        .if usevert
        .if VblankOk
                call WaitForVerticalBlank
        .endif
        .endif
        neg toggle
        .if sign?
            inv BitBlt,hdc,0,0,mwidth,mheight,mdc,0,0,SRCCOPY
        .else
            inv BitBlt,hdc,0,0,mwidth,mheight,mdc2,0,0,SRCCOPY
        .endif
        inv EndPaint,hWnd,ADDR ps
       
    .elseif eax==WM_SIZE
        .if mdc==0
            inv GetClientRect,hWin,addr crect    ; get the size needed for the bitmap
            inv GetDC,hWin  ; get dc's
            mov hdc,eax
       
            inv CreateCompatibleDC,hdc      ; create dc for hidden buffer
            mov mdc,eax
            inv SetBkMode,mdc,TRANSPARENT
            inv CreateCompatibleBitmap,hdc, mwidth, mheight ; make a hidden buffer of the appropriate size
            mov hbm1,eax
            inv SelectObject, mdc,hbm1
            inv DeleteObject,eax        ; delete old bitmap
            inv CreateSolidBrush,002492ffh
            mov hbrush1,eax
            inv SelectObject,mdc,eax
       
            inv CreateCompatibleDC,hdc      ; create dc for hidden buffer
            mov mdc2,eax
            inv SetBkMode,mdc2,TRANSPARENT
            inv CreateCompatibleBitmap,hdc, mwidth, mheight ; make a hidden buffer of the appropriate size
            mov hbm2,eax
            inv SelectObject, mdc2, hbm2
            inv DeleteObject,eax        ; delete old bitmap
            inv CreateSolidBrush,00818181h
            mov hbrush2,eax
            inv SelectObject,mdc2,eax
       
            inv FillRect,mdc,addr crect,hbrush1
            inv FillRect,mdc2,addr crect,hbrush2
       
            inv ReleaseDC,hWin,hdc
            inv SetTimer,hWin,999,150,addr TimerProc
        .endif

    .elseif eax==WM_KEYDOWN
        not usevert
    .elseif eax==WM_CREATE

        m2m hWin,hWnd
        call StartDD    ; set up for vertical blanking
       
    .elseif eax==WM_DESTROY

        inv PostQuitMessage,0
        mov eax,wParam
        jmp WndRet

    .endif
LpExit:
    inv DefWindowProc, hWnd, uMsg, wParam, lParam
WndRet:
ret
WndProc endp

;-----code to get vertical blanking to prevent flicker from MichaelW------------
uselib ddraw ; to find vertical blanking to prevent flicker

DDO_GetScanLine EQU 64
DDERR_VERTICALBLANKINPROGRESS EQU ((1 shl 31)or(876h shl 16)or(537))

.data
lpdd_1   dd 0
scanLine dd 0
VblankOk dd 0 ; flag that it is ok to wait for vertical blanking
.code

StartDD proc
    invoke DirectDrawCreate,0,ADDR lpdd_1,0 ; Create a default DirectDraw object.
    or eax,eax
    jnz DDNoGood
    call DDGetScanLine ; Make sure DDGetScanLine doesn't have any obvious problems.
    or eax,eax
    jnz DDNoGood
mov VblankOk,1 ; ok to use
DDNoGood:   
ret
StartDD EndP

DDGetScanLine proc
    push offset scanLine
    push lpdd_1
    mov  eax, lpdd_1
    mov  eax, [eax]
    call DWORD PTR[eax+DDO_GetScanLine]
    ret
DDGetScanLine endp

WaitForVerticalBlank proc
    .repeat
        call DDGetScanLine
    .until eax != DDERR_VERTICALBLANKINPROGRESS
    .repeat
        call DDGetScanLine
    .until eax == DDERR_VERTICALBLANKINPROGRESS   
    ret
WaitForVerticalBlank endp

end Program

[attachment deleted by admin]
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 12:45:27 AM
Usually, after I post something like this, a dozen different things occur to me to try.  This time, the only thing I can think of is to do true video double buffering like the old days.  Perhaps junk gdi entirely and do it in DirectX.  Unfortunately, I haven't found any directx double buffering code I could make enough sense of to convert it to masm.  How do I set up two actual video buffers and then tell the hardware to just switch, when I want, from one to the other rather then copying all those bits each time?

If I stick with GDI, is there some way to tell a window to use this DC or that DC without blitting?

Perhaps I could make two full windows, and make one or the other visible or not?

Any other ideas?
Title: Re: Graphics again.
Post by: NightWare on February 27, 2009, 01:52:25 AM
old ways, are generally better  :wink

http://www.masm32.com/board/index.php?topic=10624.0, it's easy to understand (maybe you should transform the calls to standard, for an easier understanding). use SetDIBitsToDevice instead of BitBlt, plus here i use double buffer only for the case where you read data of the current screen (fliker effect here), otherwise with SetDIBitsToDevice there is no flicker effect, so no need of double buffer... AND IT'S FAST !
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 02:15:53 AM
It's beyond me how SetDIBitsToDevice could possibly be faster than a simple bitblt, but I'll try it.  I have to say I'm a little overwhelmed by your code however.  Thanks.
Title: Re: Graphics again.
Post by: gwapo on February 27, 2009, 02:48:37 AM
Hi Jim,

I've made a simple gradient example before:
http://www.masm32.com/board/index.php?topic=5944.0 (http://www.masm32.com/board/index.php?topic=5944.0)

I think it has a simple double buffering in there. Hopefully, it may help you.

Cheers,

-chris
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 02:50:40 AM
Thanks gwapo, I'll give it a look.
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 03:26:12 PM
Okay, I've look the two over.

I don't see how Chris's program helps at all.  Now if you could switch between the two screens without tearing, that would help.

NightWare's program is just too much for my old brain to follow at the moment.

I'm going to try SetDIBits from scratch, but if anyone else has suggestions, I'd appreciate it.
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 03:52:04 PM
According to Microsoft http://msdn.microsoft.com/en-us/library/dd183562(VS.85).aspx,
QuoteTo repeatedly redraw a bitmap in a window, however, the application should use the BitBlt function. For example, a multimedia application that combines animated graphics with sound would benefit from calling the BitBlt function because it executes faster than SetDIBitsToDevice.
Title: Re: Graphics again.
Post by: jj2007 on February 27, 2009, 05:22:11 PM
Quote from: Jimg on February 27, 2009, 03:52:04 PM
According to Microsoft http://msdn.microsoft.com/en-us/library/dd183562(VS.85).aspx,
QuoteTo repeatedly redraw a bitmap in a window, however, the application should use the BitBlt function. For example, a multimedia application that combines animated graphics with sound would benefit from calling the BitBlt function because it executes faster than SetDIBitsToDevice.

The accent is on repeatedly - for drawing the same unchanged bitmap, BitBlt is probably faster. But if I remember well, you wanted to change the bits, right?
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 06:24:38 PM
Well, yes, I want to change All the bits repeatedly rather than a small band or rectangle.

I found a post http://www.asmcommunity.net/board/index.php?topic=28403.0
I made a little comparing tool which compares some blit operations, results are:

BitBlt            900
SetDIBitsToDevice 6000
StretchBlt        9000
DrawDIB           50000
Title: Re: Graphics again.
Post by: Jimg on February 27, 2009, 07:35:11 PM
Does someone have a SIMPLE example of showing a graphic image in a standard (resizable, movable, titlebar,etc.) window using DirectDraw?
By Simple I mean something less than say 2000 lines of code counting all non-masm32 include files?
If this isn't going to work with standard GDI, I'd better get started learning DirectDraw, but initially, I'm overwhelmed.
I found something that looked promising on Japeth's site (http://www.japheth.de/Download/ShowBmp.zip), but was totally unable to get it to assemble (I don't seem to have dxguid.lib or be able to find it anywhere).
Title: Re: Graphics again.
Post by: Jimg on March 03, 2009, 03:22:56 AM
It's been several days and probably 30 hours of searching the web, trying to assemble and run examples, and general frustration.  Just as there is something about C that just won't click in my brain, there's something that just won't click about DirectDraw either.

I looked at OpenGL which makes a small bit more sense to me, but I don't see how to flip back and forth between two buffers. 

Both are just way, way too much code to accomplish anything in my opinion, and they are just rubbing me the wrong way to the point of needing to scream and pull out my hair.

So I need to decide which one can do what I want and just learn one.

Rather than blitting the whole image each time which doesn't seem to be able to happen before the vertical retrace puts an obvious tear in the picture, at least with GDI, which one is better for creating two images, just flipping back and forth between the two by telling the system just display this one or that one?  I wish I could have tested both to see, but I can't get either to work so far.

Just so you know, I'm not trying to hide anything.  I agreed to do this simple app for a set amount of money.  I was totally surprised that GDI couldn't do something so simple.  So I'm going to end up making about $2.00/hour before this is done, and any code or examples or suggestions have to be unencumbered by anti-commercial licensing agreements, a problem with virtually all example OpenGL or Directdraw code I've found.

After I finish this, I'm going to be doing some plotting.  Which one is better suited for this, or should I just drop back to GDI?

I really need to pick one.  Any suggestions will be greatly appreciated.
Title: Re: Graphics again.
Post by: NightWare on March 03, 2009, 03:53:11 AM
 :bg last attempt, jimg, severals things...

1. for SetDIBitsToDevice you send a memory area (pixels) + infos (not a DC) to the display (a DC), so you can use your own functions.
for BitBlt you copy a src DC to another DC ! but if you have a DC as src, you MUST use microsoft's APIs (and gdi is well known to be very fast  ::) ...) to alterate the content. it's a question a choice.

2. i've no idea of how you DO your speed tests, but here the algos DON'T do the same thing, i even suspect that BitBlt simply swap pointers here, after some test... (so yes it can be fast here, except that you have to use gdi's functions to set/alterate the content, before  :lol), plus without infos on the alignment your results are inconsistant.
and i don't speak of the branch/variables that could affect the results...

3. if you want to test speed, mesure the result in FPS (the reality, and for the same visual result, not a black/background screen). note : the fps is NOT the number of screen seen (your gfx board simply can't), but the number of screen you have calculated/made and sent to the display.

4. direct draw also use DC (originally based on gdi), but it's more a rectangular face texturing than a screen draw... and here again, you will be the slave of the dedicated functions.

Quote from: Jimg on February 27, 2009, 07:35:11 PM
By Simple I mean something less than say 2000 lines of code counting all non-masm32 include files
it's the problem ? then why don't you see that as API (temporary) ? when you use gdi functions do you look/examine the algos used ?
Title: Re: Graphics again.
Post by: jj2007 on March 03, 2009, 07:13:30 AM
Quote from: Jimg on February 26, 2009, 11:06:12 PM
I'm working on a blink comparator
Let me try to understand: A blink comparator is used in astrology for finding moving stars, right? If I remember well, it takes two bitmaps, and they must be drawn on the DC in a given interval. That sounds like a straightforward case for BitBlt... either with two source DCs, or one source DC with two bitmaps selected in alternatively.
So what does make your code so slow? A huge screen resolution?
Title: Re: Graphics again.
Post by: MichaelW on March 03, 2009, 07:31:38 AM
Regarding the vertical retrace putting a tear in the picture, if you are updating the screen from top to bottom, by starting the update at the correct time, you can have almost two vertical frames to complete the update. As far as I know, that was the purpose of providing GetScanLine. I have never worked this out completely, but I think that by comparing the vertical refresh rate to the update rate you can determine which scan line to start on. If the update moves slower than the vertical scan, then you start the update when the scan reaches the second line from the top. If the update moves faster than the vertical scan, then you start the update somewhere close to the end of vertical blank.
Title: Re: Graphics again.
Post by: japheth on March 03, 2009, 08:43:49 AM
Quote from: Jimg on February 27, 2009, 07:35:11 PM
Does someone have a SIMPLE example of showing a graphic image in a standard (resizable, movable, titlebar,etc.) window using DirectDraw?
By Simple I mean something less than say 2000 lines of code counting all non-masm32 include files?
If this isn't going to work with standard GDI, I'd better get started learning DirectDraw, but initially, I'm overwhelmed.
I found something that looked promising on Japeth's site (http://www.japheth.de/Download/ShowBmp.zip), but was totally unable to get it to assemble (I don't seem to have dxguid.lib or be able to find it anywhere).

dxguid.lib is part of the platform SDK, but you'll find in in Open Watcom as well. However, what's used from this lib is just the DirectDraw2 IID - you can define it on your own in the source and so skip any need for dxguid.lib:

IID_IDirectDraw2 GUID <0B3A6F3E0h,2B43h,11CFh,<0A2h,0DEh,00h,0AAh,00h,0B9h,33h,56h>>

Quote
Just so you know, I'm not trying to hide anything.  I agreed to do this simple app for a set amount of money.  I was totally surprised that GDI couldn't do something so simple.  So I'm going to end up making about $2.00/hour before this is done, and any code or examples or suggestions have to be unencumbered by anti-commercial licensing agreements, a problem with virtually all example OpenGL or Directdraw code I've found.

Don't worry, this DD sample is Public Domain  :toothy
Title: Re: Graphics again.
Post by: Jimg on March 03, 2009, 03:00:17 PM
Michael-
QuoteRegarding the vertical retrace putting a tear in the picture, if you are updating the screen from top to bottom, by starting the update at the correct time, you can have almost two vertical frames to complete the update. As far as I know, that was the purpose of providing GetScanLine. I have never worked this out completely, but I think that by comparing the vertical refresh rate to the update rate you can determine which scan line to start on. If the update moves slower than the vertical scan, then you start the update when the scan reaches the second line from the top. If the update moves faster than the vertical scan, then you start the update somewhere close to the end of vertical blank.
I am using a 1680 x 1050 screen for my test.  With the blit synced to scanline 750, I just start to see a second break at the top of the picture.  These two move down the screen as I increase the scanline I sync on, until the bottom one rolls off the bottom (line 1050) at which point there is only one break.  Of course, I can't determine the appropriate number in the program since every screen/video card is different.
Ok, re-reading, I see what you are saying about starting from the bottom, but I don't immediately know how to do that with bitblt, and my brain tells me that would cut the available time down to 1/2 frame as me drawing from the bottom collided with the screen refreshing from the top and we met in the middle.  I'll have to think a little more about it.

JJ-
QuoteLet me try to understand: A blink comparator is used in astrology for finding moving stars, right? If I remember well, it takes two bitmaps, and they must be drawn on the DC in a given interval. That sounds like a straightforward case for BitBlt... either with two source DCs, or one source DC with two bitmaps selected in alternatively.
So what does make your code so slow? A huge screen resolution?
You are correct. In the initial case, it will be two 1024 x 1024 technical bitmaps, not of stars however, but will be used for many other things as well.  Did you try the code I posted above?  Do you not get the tearing effect?  Is it only my computer that has this problem?  How do you load two bitmaps into one DC and switch between them?  I missed that API somehow.

Japeth-
Quotedxguid.lib is part of the platform SDK, but you'll find in in Open Watcom as well. However, what's used from this lib is just the DirectDraw2 IID - you can define it on your own in the source and so skip any need for dxguid.lib:

IID_IDirectDraw2 GUID <0B3A6F3E0h,2B43h,11CFh,<0A2h,0DEh,00h,0AAh,00h,0B9h,33h,56h>>
Thank you.  I feel much better having that rather than an unknown library from an unknown source.  And it actually works!  I'll look at it some more when I have more time.  Vielen Dank.

NightWare-
Quotewhen you use gdi functions do you look/examine the algos used ?
Actally I did try to trace them.  But Microsoft is the only one I have to accept.  Everything else I scrutinize mercilessly until I understand it and know exactly what is happening.  Which is probably why it takes me so long to do anything.
I'm going to try again in a full implementation and let you know the results.  I certainly hope you are right.  Basically I only care that it is not obvious visually.  And Thank You also for your undeserved patience.

Title: Re: Graphics again.
Post by: jj2007 on March 03, 2009, 03:27:54 PM
Quote from: Jimg on March 03, 2009, 03:00:17 PM
JJ-
...
Do you not get the tearing effect?  Is it only my computer that has this problem?

I see an orange and a grey screen alternating about 4 times a second. Not sure what you mean with "tearing" - the screens look ok, there is a scan line that may be visible for some milliseconds at about 2/3 of the screen, but it might as well be my eyes that produce this effect.

I am a bit surprised why this is so slow: 4 times per second is very slow compared to what you browser has to perform when updating a page.

Quote
  How do you load two bitmaps into one DC and switch between them?  I missed that API somehow.

Not simultaneously, but you switch your selection: inv SelectObject, mdc2, hbm2
I doubt, though, that it's any faster than using two separate DCs.
Title: Re: Graphics again.
Post by: Jimg on March 03, 2009, 03:48:34 PM
That's about right, it's set in the timer-
inv SetTimer,hWin,999,150,addr TimerProc
to 150 ms.  Just for this test, it's adjustable in the real program.   Set it to 15 ms and the problem should be more visible when not synced to the retrace.
To me, it's really obvious that I'm seeing the top 1/4 in orange and the bottom 3/4's in grey, and on the next paint, it's the top 1/4 in gray and bottom 3/4's in orange.
Windows is doing the screen refresh when the blit has transfered only part of the pixels.  By selecting the scan line to sync on, I can get about the top 1/8th in orange, the middle 6/8's in gray and the bottom 1/8th in orange, and just the opposite on the next paint.  Very disturbing when your'e trying to detect or compare fine details.
I'll put in the time if necessary to learn directdraw or opengl if I can get assurances one of them is necessary and sufficient.  But I'd much prefer to use gdi if I can.  I'm going to try NightWare's method next and hope for the best.
Title: Re: Graphics again.
Post by: jj2007 on March 03, 2009, 05:01:02 PM
OK, I got it. On my screen, the tear is at about 8% from the top, and pretty constant.

Here is a post saying Tearing-free drawing with GDI (http://www.codeproject.com/KB/GDI/tearingfreedrawing.aspx) can be done by exact timing; on the other hand, MSDN says (http://msdn.microsoft.com/en-us/library/aa911354.aspx)

QuoteIn a preemptive multithreaded environment, it is unlikely that the IDirectDraw::WaitForVerticalBlank method can synchronize with the vertical-blank interval. Instead, use appropriate wait flags to time blits and flips

GetVerticalBlankStatus is sometimes mentioned, too. The general idea seems to do the blitting some microseconds before the vertical blank occurs, i.e. to use QPC etc to finetune the start of the BitBlt...

Good luck :thumbu
Title: Re: Graphics again.
Post by: Jimg on March 03, 2009, 05:06:31 PM
Thanks.  Like I mentioned above, I've tried syncing everywhere throughout the frame, and some places I see two breaks, so there doesn't exist a place where the whole frame can be blitted and displayed using what I doing now.
Title: Re: Graphics again.
Post by: MichaelW on March 03, 2009, 08:23:37 PM
If the update takes more than two vertical frames, I can't see any way to eliminate the tearing.
Title: Re: Graphics again.
Post by: jj2007 on March 03, 2009, 09:36:52 PM
Jim, good news: I have tested it on my other puter now, and there is no tear at all. Tell your clients they need a recent model :bg
Title: Re: Graphics again.
Post by: NightWare on March 04, 2009, 12:51:37 AM
15 ms it's too low for me (and my puter is only 1 year old...), with 17 or + it's ok...

1000/17=58,82 fps... not enough for your need ?
Title: Re: Graphics again.
Post by: Jimg on March 04, 2009, 01:00:08 AM
Mine can't handle it at any speed, it always tears.

Okay, I created a couple of  dibsections and drew on them, in this case, I just filled them with color ---

.data?
hWin dd ?   ; window handle

hdc    dd ? ; temp dc of dialog
dib1   dd ? ; dibs
dib2   dd ?
mbits1 dd 0 ; address of bits
mbits2 dd 0 

crect RECT <>
mwidth  equ crect.right  ; total width of client rectangle in pixels
mheight equ crect.bottom ; total height in pixels

.data

bih BITMAPINFOHEADER <sizeof BITMAPINFOHEADER, \
  0,        \;biWidth
  0,        \;biHeight
  1,        \;biPlanes WORD
  32,       \;biBitCount WORD
  BI_RGB,   \;biCompression
  0,        \;biSizeImage
  0,        \;biXPelsPerMeter
  0,        \;biYPelsPerMeter
  0,        \;biClrUsed
  0 >       ;biClrImportant

.code
SetupDibs proc
    pusha

    inv GetClientRect,hWin,addr crect    ; get the size needed for the bitmap
    inv GetDC,hWin  ; get dc's
    mov hdc,eax
    m2m bih.biWidth,mwidth  ; set width and height in bitmapinfoheader
    mov eax,mheight
    neg eax
    mov bih.biHeight,eax
    inv CreateDIBSection,hdc,addr bih,DIB_RGB_COLORS,addr mbits1,0,0
    mov dib1,eax
    inv CreateDIBSection,hdc,addr bih,DIB_RGB_COLORS,addr mbits2,0,0
    mov dib2,eax
    inv ReleaseDC,hWin,hdc

    mov eax,mwidth
    imul eax,mheight    ; get total number of bits

    push eax            ; save
    mov ecx,eax
    mov edi,mbits1
    mov eax,002492ffh   ; fill with color
    rep stosd

    pop ecx             ; get back total number of bits
    mov edi,mbits2
    mov eax,00818181h   ; fill with color
    rep stosd

    inv GdiFlush
sdret:
    popa       
ret
SetupDibs endp


Now to do the SetDIBitsToDevice, I need a BitmapInfo structure.
            inv SetDIBitsToDevice,dib1,0,0,mwidth,mheight,0,0,0,mheight,
                    mbits2,addr bi ,DIB_RGB_COLORS


I can't find how to create a BitmapInfo structure from the DibSection I already have, or alternately, tell SetDIBitsToDevice to just use the section and header.
I'm really struggling over this array of RGBQUAD structure that the system should already know about.   What's the best way to get over this next step?
Title: Re: Graphics again.
Post by: NightWare on March 04, 2009, 01:53:58 AM
the rgbquad structures are not always exist... it depends if the bitmap use a palette of colors or directly use the colors as pixels.

if you have loaded a bmp file, in BITMAPINFOHEADER.biSize you have SIZEOF BITMAPCOREHEADER if the bmp use a BITMAPINFOHEADER structure, otherwise it use a BITMAPCOREHEADER structure. you just need to get width and height and put them in your BITMAPINFOHEADER to create the appropriate dib.

once you have the width/heidht, you allocate the corresponding mem area (aligned 16, if possible). here you have your pixels area.

once you've made all your manipulation, just send the area to the DC of the display SetDIBitsToDevice,HDC,...
(GetDC from the handler obtained by CreateWindowEx), and use your bih for the bitmapinfo structure, coz here you have defined 32 bits, there is no palette here, so the BITMAPINFO structure it's just a BITMAPINFOHEADER structure, no RGBQUADs

note : keep the HDC you have defined, you define it at the beginnig of the app, and delete it at the end, just before ExitProcess

note2 : why have you created dib sections ? just allocate the memory area for your 2 pixels area, all the infos needed after that are in bih.

note3: no need of GetClientRect, GdiFlush,etc ... coz SetDIBitsToDevice do the FINAL transformation to the DC of the display (including format conversion, if needed...) so you don't need ANY other gdi functions...
Title: Re: Graphics again.
Post by: Jimg on March 04, 2009, 02:20:46 AM
Excellent, thanks.

So I got it working, the tearing seems about the same or possibly slightly better, it's hard to tell.


After further testing, I'd say it's about twice as fast.  Maybe even fast enough, if I can just figure out which line to sync on for all cases programatically.

edit: removed test, better one below.

Title: Re: Graphics again.
Post by: NightWare on March 04, 2009, 02:28:51 AM
haven't tested it yet (i need to make few change to make it work with masm32 v8), but you don't need vertical blanks
Title: Re: Graphics again.
Post by: Jimg on March 04, 2009, 03:25:46 AM
I'm still getting significant tearing until I get up to about scan line 300, so I'll need to check the vertical blanking.  I have an idea for optimizing it, I'll have to check it out.
Title: Re: Graphics again.
Post by: Jimg on March 04, 2009, 04:42:04 AM
Here's an update to the test.  It prints out in the title bar of the window, the starting scan line, the ending scanline, and the number of scan lines that it takes to do the SetDIBitsToDevice for each paint.
It increments the starting scan line by 5 for each paint so I can see where the vertical retrace shows up on the screen based on starting scan line.  On my computer, it takes about 550 scan lines to do the update, on a 1680 x 1050 screen.
I lowered the delay between paints to 50 ms. to make the progression happen faster.


NightWare-

You have may sincerest apologies for doubting you, and my thanks for your patience.  Every test I ran said SetDIBitsToDevice was slower except the one that actually mattered, how it worked on the screen.

[attachment deleted by admin]
Title: Re: Graphics again.
Post by: MichaelW on March 04, 2009, 05:11:40 AM
On my system, with a 1024x768 screen, it takes only about 30 scan lines to do the update, the tearing starts when the starting scan line reaches about 740, and ends somewhere around 0.

I probably should have added that one reason for the low number of scan lines per update, beyond the lower number of pixels per row, is my 60Hz refresh rate.
Title: Re: Graphics again.
Post by: jj2007 on March 04, 2009, 06:28:27 AM
796/180, needed 616 (on my fast machine).
The exe hangs apparently, I have to kill it manually.
Title: Re: Graphics again.
Post by: Mark Jones on March 04, 2009, 04:17:19 PM
A tear line slowly meanders down the screen on my AMD x64 4000+/XP SP3/1280x1024 with a GeForce 8600GTS. This rig should easily be able to do 100FPS. Is WaitForScanline not working as expected?
Title: Re: Graphics again.
Post by: Jimg on March 04, 2009, 05:42:03 PM
Hi Mark-

No, that is what it is supposed to do.  In the title bar, it show what scan line it waited for before starting the setdibitstodevice. 
It is incremented each time by 5 scanlines, so you can see what is the optimum scan line to start the drawing operation (when the tear disappears).
Also it shows how many scanlines it took to complete the operation (as long as it doesn't exceed the a full page, it's very crude).
Title: Re: Graphics again.
Post by: NightWare on March 04, 2009, 10:29:08 PM
Quote from: Jimg on March 04, 2009, 04:42:04 AM
You have may sincerest apologies for doubting you
:lol not needed, plus it's essential to not blindly trust someone else, especially in asm  :wink