Hi.
I have tried using SetDIBits but it doesn't work as expected. I didn't give much effort trying to make it work but I read somewhere it has a bug. Does anyone have a working example, GDI and GDI+ set/get pixel functions are too slow, I need to use SetDIBits for plotting pixels manually.
Preferably an example where you create a DIB color array and then plot a few pixels, then use SetDIBits to plot it to a bitmap and then to screen.
I could use GDI+ lockbits, but unfortunately I am working on a hBitmap not a GpBitmap they are not compatible.
Hi zemtex,
Can't say as I have ever used SetDIBits but as a suggestion if you are using a DIB anyway why not convert it to 32bpp and write directly to the DIB's memory. That is the approach I used in graphics.lib, its much faster than the two tiered approach of writing to memory then copying to a different location (GetObject will give a pointer to the DIB btis). Ofcourse I don't know if your particular application can use this method but it did work well for me. You would (possibly) need the ConvertToDIB32 and SetDIBPixel functions modified to suit your needs but they are fairly straightforward functions and should be easy to adapt to whatever you require. As usual, they are free to use and modify for any purpose whatever (including commercial software) with or without acknowledgement.
Edgar
Quote from: zemtex on December 13, 2011, 10:26:07 AM
I could use GDI+ lockbits, but unfortunately I am working on a hBitmap not a GpBitmap they are not compatible.
For DIBs you can use:
invoke GdipCreateBitmapFromHBITMAP,hBitmap,0,ADDR image
I posted an example here (http://www.masm32.com/board/index.php?topic=17168.msg144509#msg144509) that uses a DIB as a drawing surface for a fast set-pixel routine, and SetDIBits to copy the bitmap bits from the DIB to a DDB for display.
These pixel routines are extremely fast :U
I made my own routine, I didn't copy yours it was only after that I noticed mine had one less instruction, if it matters, you can copy mine if you want. Register dependencies goes in the toilet
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
align 4
PlotPixel PROC x:DWORD, y:DWORD, farge:DWORD
mov eax, [esp+8]
mov ecx, 1920
mul ecx
mov edx, bitdataptr
mov ecx, [esp+4]
add eax, ecx
mov ecx, [esp+12]
mov [edx+eax*4], ecx
ret 12
PlotPixel ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
Here is another routine for plotting pixels by using registers for coordinates and stack for color. set ecx to x value and eax to y value, and push color on stack.
Like this:
mov ecx, 1024-1
mov eax, 768-1
INVOKE PlotPixelR, 0FF00FF00h
-----------------------------------------------------------------------
; ecx = x eax = y
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
align 4
PlotPixelR PROC color:DWORD
mov edx, 1920
mul edx
add eax, ecx
mov edx, bitdataptr
mov ecx, [esp+4]
mov [edx+eax*4], ecx
ret 4
PlotPixelR ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
I made a quick macro for clearing the screen, avvoiding function calls.
ClrDib MACRO BitDataPtr:REQ, Farge:REQ, FreeReg:REQ
mov FreeReg, edi
mov ecx, 1920*1200
mov eax, Farge
mov edi, BitDataPtr
rep stosd
mov edi, FreeReg
ENDM
Btw, I experience a bit of a flicker from time to time. I never get flickering usually when dealing with memDC and ScreenDC using DDB's. But when I use a DIB section I experience flicker from time to time. Is this structure "OK" ?
(http://i.imgur.com/M5Zdm.png)
It is very rare I might add. I think I know what the problem is, I added some test drawing code in a WM_TIMER just for a quick look at the results, the timer might be overlapping WM_PAINT, I added a critical section and it seems to be solved. The code is not supposed to be in a WM_TIMER but it was just for testing purposes.
Here is an example of pixel throughput using the register variant of PlotPixelR. 100,000 pixels on WM_MOUSEMOVE, remember to move your mouse very slowly as the resolution of your mouse is much higher than the potential framerate.
I forgot to modify the 1920 constant, so you have to change that to your own screen resolution hehe. Search and replace, lol.
If your resolution is not 1920x1200 don't run the program. :toothy
It could be accelerated a little bit :wink
(Hint: it's not MasmBasic that speeds it up - but Antariy could tell you where to search...)
Intel(R) Celeron(R) M CPU 420 @ 1.60GHz (SSE3)
145775 cycles for Masm32
69828 cycles for MasmBasic
145032 cycles for Masm32
69398 cycles for MasmBasic
Quote from: zemtex on December 14, 2011, 11:09:20 AM
Btw, I experience a bit of a flicker from time to time. I never get flickering usually when dealing with memDC and ScreenDC using DDB's. But when I use a DIB section I experience flicker from time to time. Is this structure "OK" ?
My DIB code has no flicker that I can see. For it the DIB consists of a BITMAPINFO structure and a buffer for the DIB bits, both in allocated memory. The DIB is not selected into anything and there is no BitBlt operation. For each frame FastSetPixel is used to update the DIB bits and then SetDIBits is used to copy them to the DDB, then an InvalidateRect and the WM_PAINT handler does the rest.
jjl2007, I am sure there is a whole lot of things that can be optimized in there, but do tell because I need to learn this.
MichaelW, the flicker is totally gone, It was because I put the code in a WM_TIMER during a quick test I did, once I removed it the flicker was gone. :U
Quote from: zemtex on December 15, 2011, 06:35:57 AM
jjl2007, I am sure there is a whole lot of things that can be optimized in there, but do tell because I need to learn this.
Ok, the point is that MasmBasic's Rand() is about twice as fast as nrandom. If you use none of them, your code will be a factor 14 faster than the original - it's the random generator that is slow... :bg
That's ok, it is only temporary. I have created another putpixel routine which uses registers only. I fixed a few tearing problems that occurs when there are excessive WM_PAINT messages in the middle of pixel computations. I put computations in a separate thread and added a critical section to synchronize between them. Screen resolution can now be set in the constant field. No longer need to use mouse movement to update screen. If you have a faster random routine, I can implement it if you have the code somewhere. I have the mersenne twister algorithm here somewhere too.
I measure it to 100 million pixels in 218 ms without using random function (clean mode). 458 pixels per microsecond. With that speed I can fill 43 screens of 1920x1200 in the same amount of time. I can fill exactly 200 full screens at 1920x1200 in a second by plotting pixels clean. It is more than acceptable, in most situations you would never do that anyway. But the main problem is not frame rate, the main problem is the remaining time and processing power left over for other functions. There should be a maximum cpu idle time leftover for other functions, that is why faster is always better of course.
I dont know but OpenGL and DX7 is faster on this pixel function, but OpenGL copy pixel is very slow. I never know that copying from VRAM is slower on Windows, On syslinux it was fast, you can use it directly using the pointer provided by VESA or using Hardware Port.