|
-
Sep 24th, 2002, 10:28 AM
#1
Thread Starter
I wonder how many charact
DirectDraw draws slower than LineTo API
Here's some code that creates a file of 500,000 lines, saves it to disk, loads it, then draws it. For some reason, it takes twice as long to draw then the LineTo Api method... go figure...
To use the code below you have to:
put the code in a module
set startup properties of the project to Sub Main
add a Form (Form1) to your project
Check 'DirectX 7 for Visual Basic Type Library' under References
VB Code:
Option Explicit
'determines performance of execution for testing purposes only
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
Private Type mapLineType
XPosStart As Single
YPosStart As Single
XPosEnd As Single
YPosEnd As Single
Colour As Long
Thickness As Single
End Type
Private mapLine(500000) As mapLineType
'below type is needed for LineTo and MoveEx API functions
Private Type POINTAPI
x As Long
y As Long
End Type
Private DX7 As New DirectX7
Private DD7 As DirectDraw7
Private Primary As DirectDrawSurface7
Private Back As DirectDrawSurface7
Public Display As Form1
Private Sub InitialiseDirectX()
Dim ddsd As DDSURFACEDESC2, Size As RECT
Dim Clip As DirectDrawClipper
'Instantiate the main DX DirectDraw
Set DD7 = DX7.DirectDrawCreate("")
'Negotiate a normal windowed display
DD7.SetCooperativeLevel Display.hWnd, DDSCL_NORMAL
'Create the primary surface used to display completed images
ddsd.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE
Set Primary = DD7.CreateSurface(ddsd)
'Create and attach a Clipper to the Primary surface
Set Clip = DD7.CreateClipper(0)
Clip.SetHWnd Display.hWnd
Primary.SetClipper Clip
'Create a back surface used to compose images before display
ddsd.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsd.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT
ddsd.lWidth = Display.ScaleWidth
ddsd.lHeight = Display.ScaleHeight
Set Back = DD7.CreateSurface(ddsd)
End Sub
Public Sub cleanup()
'Reset the display back to the original windows
DD7.RestoreDisplayMode
'Release objects
Set DX7 = Nothing
Set DD7 = Nothing
Set Back = Nothing
Set Primary = Nothing
Unload Form1
Set Form1 = Nothing
End Sub
Public Sub main()
Dim mypointapi As POINTAPI
Dim EmptyRect As RECT, DestRect As RECT
Dim i As Long
'needed for conversion from twips to pixels with API functions
Dim picture1width As Long
Dim picture1height As Long
'performance measuring variable
Dim start As Long
Set Display = New Form1
Display.ScaleMode = vbPixels
'Setup and initialise the DX environment and the Vectoid population
InitialiseDirectX
Form1.Show
picture1width = (Form1.Width / Screen.TwipsPerPixelX)
picture1height = (Form1.Height / Screen.TwipsPerPixelY)
'make some RANDOM DATA
For i = 1 To 500000
mapLine(i).XPosStart = Int(picture1width * Rnd)
mapLine(i).YPosStart = Int(picture1height * Rnd)
mapLine(i).XPosEnd = Int(picture1width * Rnd)
mapLine(i).YPosEnd = Int(picture1height * Rnd)
mapLine(i).Colour = Int(10000 * Rnd + 1)
mapLine(i).Thickness = Int(1 * Rnd + 1)
Next
Open ("C:\testfile.tst") For Binary As #1
Put #1, 1, mapLine
Close #1
'Begin load and draw
start = GetTickCount
Open ("C:\testfile.tst") For Binary As #1
Get #1, 1, mapLine
Close #1
Debug.Print "loaded in : " & (GetTickCount - start) / 1000 & " seconds"
start = GetTickCount
'clear the back surface
Back.BltColorFill EmptyRect, vbBlack
'draw the lines to the back surface
For i = 1 To 500000
Back.SetForeColor mapLine(i).Colour
Back.DrawLine mapLine(i).XPosStart, mapLine(i).YPosStart, mapLine(i).XPosEnd, mapLine(i).YPosEnd
Next
'Get the latest size and position of destination window
DX7.GetWindowRect Display.hWnd, DestRect
'Blt the back surface to the primary surface
Primary.Blt DestRect, Back, EmptyRect, DDBLT_WAIT
Debug.Print "Drawn in :" & (GetTickCount - start) / 1000 & " seconds"
End Sub
-
Sep 27th, 2002, 05:13 AM
#2
Addicted Member
i have about 50 filled circles moving in a dx project, and a regular Circle method vb project, and the vb is faster. Tried this on a friend's system that doesn't have a video card, and the speed difference was even greater
-
Sep 27th, 2002, 08:50 AM
#3
Thread Starter
I wonder how many charact
I can only assume then, that for 2D graphics, its best to stick to API or native VB functions...
-
Sep 29th, 2002, 02:29 PM
#4
Fanatic Member
Lock the bufffer first and then use the LineTo api to draw the line as many times as you want then UnLock the buffer.
The problem is that each time you call that DrawLine function, it will Lock and UnLock. These Locks take time.
-
Sep 29th, 2002, 03:15 PM
#5
Thread Starter
I wonder how many charact
How would i Lock a buffer? I'm new to DirectX, and really only wanted to learn this much to accomplish a needed task. Any help from a knowledgable directX programmer would be appreciated.
-
Sep 29th, 2002, 03:54 PM
#6
Fanatic Member
Back.Lock or something; look in the help file that came with directx sdk
-
Sep 30th, 2002, 01:39 PM
#7
Anyway, there isn't any way VB native functions could be faster than DX, no matter what, unless you have some hidden blocker in there (like MoMad said, Lock/Unlock)
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Sep 30th, 2002, 02:02 PM
#8
Fanatic Member
No, LineTo is not vb, its API and it is what directdraw uses. But if you just call the drawline method, it will do this:
VB Code:
Function DrawLine (bla)
Buffer.Lock
Buffer.MoveTo (x,y)
Buffer.LineTo (x,y)
Buffer.Unlock
End Function
The lock takes a while because it was designed for 16bit windows. It waits for the "vertical scanline" or something to do with the monitor and refresh rate and not being used,... so if each lock takes 100ms, imagine what 50000 locks will take?
Lock the buffer your self and moveto/lineto yourself!!
-
Sep 30th, 2002, 02:36 PM
#9
No, the lock wasn't designed for 16-bit. It's a necessity because normaly the video card may move blocks of memory around it's memory at will. Lock will tell it not to do this for a while because we want to access the memory, and it would be bad if it was moved away at that time.
The inner DirectDraw actually doesn't have a LineTo API. This function is part of the DX wrapper for VB.
In pure DD you usually have to write your own functions for this.
Of course there is a reason for this: a VB implementation of a rasterizing algorithm would probably simply be too slow.
But you're right, locks are synchronized to the vertical retrace, so you can have at best as many locks per second as your monitor refresh rate. E.g. 80 locks/second on an 80Hz screen.
Probably less if any calculation takes up more than 1/80 of a second (which means you're missing a chance to lock/unlock).
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Sep 30th, 2002, 03:00 PM
#10
Fanatic Member
Yeah, and i forgot one other thing, it has to do with COM aggregation and multithreading (being threadsafe and all)... or some shznick like that! heh, like i care anyways, just know this, do as little locks as possible, not only you, the functions you call also... blt, fastblt, bitblt, *blt all have locking mechanisms inside them.
[EDIT]
Lock was originally designed for 16bits, there are better ways to be threadsafe now, and btw, the dx lock is a mutex which explains why its of 16bit originality.
-
Sep 30th, 2002, 03:12 PM
#11
Basically if you have to lock do it once. Then call all functions that should do something. Then unlock. The most efficient way.
Actually BitBlts don't really lock the surface as they are a more or less atomic operation. A surface must not be locked when calling the DD-Blitter, so I suppose it has some internal mechanism similar to but faster than locking. Else DD would expose a blitter that accepts pointers to locked mem regions.
Another reason why the VB wrapper has it's own functions for simple geometry is that VB code has no way to dereference a pointer
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Sep 30th, 2002, 03:29 PM
#12
Fanatic Member
-
Sep 30th, 2002, 03:41 PM
#13
Thread Starter
I wonder how many charact
You know this is all well and dandy, but the fact remains, if you aren't supposed to use DrawLine in the DirectX library, how else do you put a line on the screen? I imagine someone would have enough DirectX programming to show me how else it could be acheived using the code above.
-
Sep 30th, 2002, 03:53 PM
#14
Fanatic Member
Havent you read my above post? Do a Lock and this will give you some kind of dc that you can draw on. Then use the API functions MoveToEx and LineTo to draw your lines as much as you like. Then Unlock!
-
Sep 30th, 2002, 04:00 PM
#15
Thread Starter
I wonder how many charact
Does a LineTo call work on a DirectX Surface? And if so, how do I get a handle to it (the DX surface)?
-
Oct 1st, 2002, 06:12 AM
#16
For the third time: by calling Lock
You get the surface by creating it - unless you just threw the object away, in which case you should be punished.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Oct 1st, 2002, 07:40 AM
#17
Thread Starter
I wonder how many charact
Alright lol, sorry, wasn't getting that part through my head yesterday I guess...
Anyway, I'm gettin a Type Mismatch on the lock line...2nd parameter, i don't understand why I would have to pass the surface (2nd parameter), if Lock is obviously a member of the surface class... so I must be missing something here...
VB Code:
start = GetTickCount
'clear the back surface
Back.BltColorFill EmptyRect, vbBlack
'lock the surface, retrieve handle from lock
[b]mysurfaceHandle = Back.Lock(EmptyREct, Back, DDLOCK_WAIT, 0)[/b]
'draw the lines to the back surface
For i = 1 To 500000
Back.SetForeColor mapLine(i).Colour
MoveToEx mysurfaceHandle, mapLine(i).XPosStart, mapLine(i).YPosStart
LineTo mysurfaceHandle, mapLine(i).XPosEnd, mapLine(i).YPosEnd
Next
Back.Unlock 0
'Get the latest size and position of destination window
DX7.GetWindowRect Display.hWnd, DestRect
'Blt the back surface to the primary surface
Primary.Blt DestRect, Back, EmptyRect, DDBLT_WAIT
-
Oct 1st, 2002, 09:04 AM
#18
Don't you have a reference to look that up? What's the function prototype?
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Oct 1st, 2002, 10:18 AM
#19
Thread Starter
I wonder how many charact
This is the prototype:
VB Code:
Lock (r as RECT, desc as DDSURFACEDESC2, flags As CONST_DDLOCKFLAGS, hwnd As Long)
-
Oct 1st, 2002, 01:32 PM
#20
Fanatic Member
For crying out loud, here:
VB Code:
[b]Dim ddsd As DDSURFACEDESC2 ' <-------------- this is not a surface[/b]
start = GetTickCount
'clear the back surface
Back.BltColorFill EmptyRect, vbBlack
'lock the surface, retrieve handle from lock
[b]mysurfaceHandle = Back.Lock(EmptyREct, ddsd, DDLOCK_WAIT, 0)[/b]
' =======================
' NOW ddsd contains anything you need to know about Back surface!!!
' though I dont kno if Lock returns the dc, you might have to
' get that from ddsd (not sure), check the directX doc (vb).
' =============================
'draw the lines to the back surface
For i = 1 To 500000
Back.SetForeColor mapLine(i).Colour
MoveToEx mysurfaceHandle, mapLine(i).XPosStart, mapLine(i).YPosStart
LineTo mysurfaceHandle, mapLine(i).XPosEnd, mapLine(i).YPosEnd
Next
Back.Unlock 0
'Get the latest size and position of destination window
DX7.GetWindowRect Display.hWnd, DestRect
'Blt the back surface to the primary surface
Primary.Blt DestRect, Back, EmptyRect, DDBLT_WAIT
-
Oct 1st, 2002, 03:03 PM
#21
Thread Starter
I wonder how many charact
Thanks for the tip... like I said, I only have time to learn enough DirectX to accomplish this 1 task..
The code steps through properly, but still, I cannot get anything to display in the Picturebox. Not sure why, but if you throw this code in a new project, with a picturebox1 and a command1, you can see what may be or may not be happening...
VB Code:
Option Explicit
'determines performance of execution for testing purposes only
Private Type POINTAPI
x As Long
y As Long
End Type
Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
Private Declare Function LineTo Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function MoveToEx Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Type mapLineType
XPosStart As Single
YPosStart As Single
XPosEnd As Single
YPosEnd As Single
Colour As Long
Thickness As Single
End Type
Private mapLine(500000) As mapLineType
Private DX7 As New DirectX7
Private DD7 As DirectDraw7
Private Primary As DirectDrawSurface7
Private Back As DirectDrawSurface7
Public Display As Form1
Private Sub InitialiseDirectX()
Dim ddsd As DDSURFACEDESC2, Size As RECT
Dim Clip As DirectDrawClipper
'Instantiate the main DX DirectDraw
Set DD7 = DX7.DirectDrawCreate("")
'Negotiate a normal windowed display
DD7.SetCooperativeLevel Display.hWnd, DDSCL_NORMAL
'Create the primary surface used to display completed images
ddsd.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE
Set Primary = DD7.CreateSurface(ddsd)
'Create and attach a Clipper to the Primary surface
Set Clip = DD7.CreateClipper(0)
Clip.SetHWnd Display.hWnd
Primary.SetClipper Clip
'Create a back surface used to compose images before display
ddsd.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsd.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT
ddsd.lWidth = Display.ScaleWidth
ddsd.lHeight = Display.ScaleHeight
Set Back = DD7.CreateSurface(ddsd)
End Sub
Public Sub Cleanup()
'Reset the display back to the original windows
DD7.RestoreDisplayMode
'Release objects
Set DX7 = Nothing
Set DD7 = Nothing
Set Back = Nothing
Set Primary = Nothing
Unload Form1
Set Form1 = Nothing
End Sub
Public Sub main()
Dim mypointapi As POINTAPI
Dim EmptyRect As RECT, DestRect As RECT
Dim i As Long
'needed for conversion from twips to pixels with API functions
Dim picture1width As Long
Dim picture1height As Long
Dim mysurface As Long
'performance measuring variable
Dim start As Long
Set Display = New Form1
Display.ScaleMode = vbPixels
'Setup and initialise the DX environment
InitialiseDirectX
Dim ddsd As DDSURFACEDESC2
Form1.Show
picture1width = (Form1.Width / Screen.TwipsPerPixelX)
picture1height = (Form1.Height / Screen.TwipsPerPixelY)
'make some RANDOM DATA
For i = 1 To 500000
mapLine(i).XPosStart = Int(picture1width * Rnd)
mapLine(i).YPosStart = Int(picture1height * Rnd)
mapLine(i).XPosEnd = Int(picture1width * Rnd)
mapLine(i).YPosEnd = Int(picture1height * Rnd)
mapLine(i).Colour = Int(10000 * Rnd + 1)
mapLine(i).Thickness = Int(1 * Rnd + 1)
Next
Open ("C:\testfile.tst") For Binary As #1
Put #1, 1, mapLine
Close #1
'Begin load and draw
start = GetTickCount
Open ("C:\testfile.tst") For Binary As #1
Get #1, 1, mapLine
Close #1
Debug.Print "loaded in : " & (GetTickCount - start) / 1000 & " seconds"
start = GetTickCount
'clear the back surface
Back.BltColorFill EmptyRect, vbBlack
Back.Lock EmptyRect, ddsd, DDLOCK_WAIT, 0
mysurface = Back.GetDC
'draw the lines to the back surface
For i = 1 To 500000
Back.SetForeColor mapLine(i).Colour
MoveToEx mysurface, mapLine(i).XPosStart, mapLine(i).YPosStart, mypointapi
LineTo mysurface, mapLine(i).XPosEnd, mapLine(i).YPosEnd
Next
Back.ReleaseDC (mysurface)
'Get the latest size and position of destination window
DX7.GetWindowRect Display.hWnd, DestRect
'Blt the back surface to the primary surface
Primary.Blt DestRect, Back, EmptyRect, DDBLT_WAIT
Debug.Print "Drawn in :" & (GetTickCount - start) / 1000 & " seconds"
End Sub
Private Sub Command1_Click()
Call main
End Sub
Private Sub Form_Unload(Cancel As Integer)
Cleanup
End Sub
-
Oct 2nd, 2002, 03:57 AM
#22
Well, it seems you don't need to lock when you call GetDC (that's the way it is in C++). Do you get any errors or does simply nothing happen?
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Oct 2nd, 2002, 03:58 AM
#23
Or you just forgot to Unlock! Then the blt call would fail!
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Oct 2nd, 2002, 08:22 AM
#24
Thread Starter
I wonder how many charact
There are no errors, the code steps through properly. It simply fails to blit the back surface to the picturebox. If I include an unlock statement, I get an Automation Error on the unlock line:
The entire code is posted above, a simply copy/paste and add a reference to Directx 7 type library...
-
Oct 2nd, 2002, 08:45 AM
#25
Thread Starter
I wonder how many charact
I checked the return values of the MoveToEx and LineTo functions, and they were all nonzero (1 actually), which by definition of the function, means it was sucessful.
-
Oct 2nd, 2002, 09:08 AM
#26
Thread Starter
I wonder how many charact
Well, at first it appeared this emerging code was drawing faster than the purely LineTO API method (straight to Picturebox)... but after resizing the picturebox to the size I had with the LineTO method, IT IS NOT ANY FASTER, its not noticably slower, but it IS NOT FASTER.
Thanks for all your help...
-
Oct 2nd, 2002, 04:17 PM
#27
Fanatic Member
Sorry, use GetDC like you did (it has its own lock method and release dc will unlock it), make sure your surface is associated with the picturebox or whatever it is you are drawing on, also, you cant say Back.SetForeColor, you have to use CreateSolidBrush, and SelectObject api calls.
I see that all throughout your code you are refering to Display, what is display? If you are drawing on picture1, use picture1 not display.
When you draw on picture1, put a DoEvents in your loop so you can quit at anytime during the drawing loop.
Also, you are using display and form1 interchangably.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|