Re: Gaussian blur in real time?
Posted: Thu Oct 17, 2019 12:39 pm
Confirm, GPU. Maybe it's just me then. Right now, I'm refactoring, I'll check that later (maybe it's the GrabSprite() part then?).
http://www.purebasic.com
http://forums.purebasic.com/english/
I dont get why you would use GrabSprite (in a loop) just to blur it - why cant you use the backbuffer directly?Joubarbe wrote:Wow man, how much do I owe you?
Impressive results.
At 800x800, your DirectionalBlur costs me 2 FPS with #Blur_Full, which is great. However, GrabSprite() is a lot more expensive than I thought. 15 FPS in that case (800x800).Code: Select all
Static sprite_tmp.i, *buffer If IsSprite(sprite_tmp) : FreeSprite(sprite_tmp) : EndIf sprite_tmp = GrabSprite(#PB_Any, 100, 100, 800, 800) StartDrawing(SpriteOutput(sprite_tmp)) *buffer = DrawingBuffer() DirectionalBlur::BlurPixelBuf32(*buffer, OutputWidth(), OutputHeight(), 10, DirectionalBlur::#Blur_Full) StopDrawing() DisplaySprite(sprite_tmp, 100, 100)
The strength option doesn't seem to cost more at 30.
I'm not sure how exactly the LineStride option works. Putting random values is fun
But yeah, again, the following is the most expensive:
I'm pretty sure that I should be doing something elseCode: Select all
Static sprite_tmp.i, *buffer If IsSprite(sprite_tmp) : FreeSprite(sprite_tmp) : EndIf sprite_tmp = GrabSprite(#PB_Any, 100, 100, 800, 800) DisplaySprite(sprite_tmp, 100, 100)
How do you mean? Am I not supposed to use a StartDrawing() block at some point? Meaning if I don't grab a sprite, I must use ScreenOutput(), and this is even slower.Once StopDrawing() has been called, the buffer is invalidated and can no more be used.
Code: Select all
CompilerIf #PB_Compiler_Debugger
If MessageRequester("debugger?", "the debugger is enabled. run anyway?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
End
EndIf
CompilerEndIf
CompilerIf Not #PB_Compiler_Thread
CompilerError "please enable threadsafe compiler option."
CompilerEndIf
EnableExplicit
#ScreenWidth = 800
#ScreenHeight = 600
;#ScreenWidth = 1024
;#ScreenHeight = 768
;#ScreenWidth = 1680
;#ScreenHeight = 1050
InitSprite()
InitKeyboard()
InitMouse()
ElapsedMilliseconds()
Structure Pixel
r.a
g.a
b.a
EndStructure
Define win, quit, mode, mode$
Define spr, i
Define sprFR, FR, FRt, FR$
Define time, timeTmp
win = OpenWindow(#PB_Any, 0, 0, #ScreenWidth, #ScreenHeight, "window")
OpenWindowedScreen(WindowID(win), 0, 0, #ScreenWidth, #ScreenHeight, 0, 0, 0, #PB_Screen_NoSynchronization)
SetFrameRate(999)
UsePNGImageDecoder()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3D/Data/PureBasic3DLogo.png") ; windows
CompilerElse
Define spr = LoadSprite(#PB_Any, #PB_Compiler_Home + "examples/3d/Data/PureBasic3DLogo.png") ; linux
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Define font = LoadFont(#PB_Any, "courier new", 10)
CompilerElse
Define font = LoadFont(#PB_Any, "monospace", 10)
CompilerEndIf
; ------------------------------------------------------------
sprFR = CreateSprite(#PB_Any, 400, 80)
mode = 5
; ------------------------------------------------------------
Procedure blur_a(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, neighborDistance)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2lef.Pixel
Protected *pixel2rig.Pixel
Protected *pixel2top.Pixel
Protected *pixel2bot.Pixel
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2lef = buffer + ((y ) * pitch) + ((x-neighborDistance) * pixelSize)
*pixel2rig = buffer + ((y ) * pitch) + ((x+neighborDistance) * pixelSize)
*pixel2top = buffer + ((y-neighborDistance) * pitch) + ((x ) * pixelSize)
*pixel2bot = buffer + ((y+neighborDistance) * pitch) + ((x ) * pixelSize)
*pixel1\r = (*pixel1\r + *pixel2lef\r + *pixel2rig\r + *pixel2top\r + *pixel2bot\r) / 5.0
*pixel1\g = (*pixel1\g + *pixel2lef\g + *pixel2rig\g + *pixel2top\g + *pixel2bot\g) / 5.0
*pixel1\b = (*pixel1\b + *pixel2lef\b + *pixel2rig\b + *pixel2top\b + *pixel2bot\b) / 5.0
Next
Next
EndProcedure
Procedure blur_b(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2_1.Pixel
Protected *pixel2_2.Pixel
Protected *pixel2_3.Pixel
Protected *pixel2_4.Pixel
Protected *pixel2_5.Pixel
Protected *pixel2_6.Pixel
Protected *pixel2_7.Pixel
Protected *pixel2_8.Pixel
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2_1 = buffer + ((y-3) * pitch) + ((x+1) * pixelSize)
*pixel2_2 = buffer + ((y-1) * pitch) + ((x+3) * pixelSize)
*pixel2_3 = buffer + ((y+1) * pitch) + ((x+3) * pixelSize)
*pixel2_4 = buffer + ((y+3) * pitch) + ((x+1) * pixelSize)
*pixel2_5 = buffer + ((y+3) * pitch) + ((x-1) * pixelSize)
*pixel2_6 = buffer + ((y+1) * pitch) + ((x-3) * pixelSize)
*pixel2_7 = buffer + ((y-1) * pitch) + ((x-3) * pixelSize)
*pixel2_8 = buffer + ((y-3) * pitch) + ((x-1) * pixelSize)
*pixel1\r = (*pixel2_1\r + *pixel2_2\r + *pixel2_3\r + *pixel2_4\r + *pixel2_5\r + *pixel2_6\r + *pixel2_7\r + *pixel2_8\r) / 8.0
*pixel1\g = (*pixel2_1\g + *pixel2_2\g + *pixel2_3\g + *pixel2_4\g + *pixel2_5\g + *pixel2_6\g + *pixel2_7\g + *pixel2_8\g) / 8.0
*pixel1\b = (*pixel2_1\b + *pixel2_2\b + *pixel2_3\b + *pixel2_4\b + *pixel2_5\b + *pixel2_6\b + *pixel2_7\b + *pixel2_8\b) / 8.0
Next
Next
EndProcedure
Procedure blur_c(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize);, buffer2)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2lef.Pixel
Protected *pixel2rig.Pixel
Protected *pixel2top.Pixel
Protected *pixel2bot.Pixel
;CopyMemory(buffer, buffer2, OutputHeight() * pitch)
Protected buffer2
buffer2 = buffer
Define n
For n = 1 To 4
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2lef = buffer2 + ((y ) * pitch) + ((x-n) * pixelSize)
*pixel2rig = buffer2 + ((y ) * pitch) + ((x+n) * pixelSize)
*pixel2top = buffer2 + ((y-n) * pitch) + ((x ) * pixelSize)
*pixel2bot = buffer2 + ((y+n) * pitch) + ((x ) * pixelSize)
*pixel1\r = (*pixel2lef\r + *pixel2rig\r + *pixel2top\r + *pixel2bot\r) / 4.0
*pixel1\g = (*pixel2lef\g + *pixel2rig\g + *pixel2top\g + *pixel2bot\g) / 4.0
*pixel1\b = (*pixel2lef\b + *pixel2rig\b + *pixel2top\b + *pixel2bot\b) / 4.0
Next
Next
Next
EndProcedure
Procedure blur_d(xStart, yStart, xEnd, yEnd, buffer, pitch, pixelSize, neighborDistance)
Protected x, y
Protected *pixel1.Pixel
Protected *pixel2lef.Pixel
Protected *pixel2rig.Pixel
For y = yStart To yEnd
For x = xStart To xEnd
*pixel1 = buffer + ((y ) * pitch) + ((x ) * pixelSize)
*pixel2lef = buffer + ((y ) * pitch) + ((x-neighborDistance) * pixelSize)
*pixel2rig = buffer + ((y ) * pitch) + ((x+neighborDistance) * pixelSize)
; *pixel1\r = (*pixel1\r + *pixel2lef\r + *pixel2rig\r) / 3.0
; *pixel1\g = (*pixel1\g + *pixel2lef\g + *pixel2rig\g) / 3.0
; *pixel1\b = (*pixel1\b + *pixel2lef\b + *pixel2rig\b) / 3.0
*pixel1\r = (*pixel2lef\r + *pixel2rig\r) / 2.0
*pixel1\g = (*pixel2lef\g + *pixel2rig\g) / 2.0
*pixel1\b = (*pixel2lef\b + *pixel2rig\b) / 2.0
Next
Next
EndProcedure
; ------------------------------------------------------------
Define buffer2
Define bufferTmp
Define yStart
Define yEnd
Define xStart
Define xEnd
; ------------------------------------------------------------
Define semaphoreThread = CreateSemaphore()
Define semaphoreMain = CreateSemaphore(1)
Enumeration #PB_Event_FirstCustomValue
#eventThreadTimeNotify
EndEnumeration
Structure s_threadInfo
buffer.i
pitch.i
pixelSize.i
yStart.i
yEnd.i
xStart.i
xEnd.i
quitThread.i
EndStructure
Procedure proc(*threadInfo.s_threadInfo)
Shared semaphoreThread
Shared semaphoreMain
Protected n
Protected nMax
Protected time
Protected dist
Protected quitThread
Repeat
WaitSemaphore(semaphoreThread) ;>
time = ElapsedMilliseconds()
If *threadInfo\buffer
; repeat
nMax = 1
For n=1 To nMax
; 4 neighbors of distance d
dist = 2
blur_a(*threadInfo\xStart, *threadInfo\yStart, *threadInfo\xEnd, *threadInfo\yEnd, *threadInfo\buffer, *threadInfo\pitch, *threadInfo\pixelSize, dist)
; 4 neighbors of distance d
;dist = 4
;blur_a(*threadInfo\xStart, *threadInfo\yStart, *threadInfo\xEnd, *threadInfo\yEnd, *threadInfo\buffer, *threadInfo\pitch, *threadInfo\pixelSize, dist)
; 8 neighbors
;blur_b(*threadInfo\xStart, *threadInfo\yStart, *threadInfo\xEnd, *threadInfo\yEnd, *threadInfo\buffer, *threadInfo\pitch, *threadInfo\pixelSize)
; 4 neighbors * multiple distance 1-4
;blur_c(*threadInfo\xStart, *threadInfo\yStart, *threadInfo\xEnd, *threadInfo\yEnd, *threadInfo\buffer, *threadInfo\pitch, *threadInfo\pixelSize)
; 2 neighbors of distance d
;dist = 3
;blur_d(*threadInfo\xStart, *threadInfo\yStart, *threadInfo\xEnd, *threadInfo\yEnd, *threadInfo\buffer, *threadInfo\pitch, *threadInfo\pixelSize, dist)
Next
EndIf
time = ElapsedMilliseconds() - time
PostEvent(#eventThreadTimeNotify, 0, 0, 0, time)
If *threadInfo\quitThread
quitThread = #True
EndIf
SignalSemaphore(semaphoreMain) ;<
Until quitThread
EndProcedure
Define threadInfo.s_threadInfo
Define thread = CreateThread(@proc(), @ threadInfo)
Define threadTime
; ------------------------------------------------------------
Repeat
ExamineMouse()
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Escape) : quit = #True : EndIf
If KeyboardPushed(#PB_Key_0) : mode = 0 : EndIf
If KeyboardPushed(#PB_Key_1) : mode = 1 : EndIf
If KeyboardPushed(#PB_Key_2) : mode = 2 : EndIf
If KeyboardPushed(#PB_Key_3) : mode = 3 : EndIf
If KeyboardPushed(#PB_Key_4) : mode = 4 : EndIf
If KeyboardPushed(#PB_Key_5) : mode = 5 : EndIf
While WindowEvent()
Select Event()
Case #PB_Event_CloseWindow
quit = #True
Case #eventThreadTimeNotify
threadTime = EventData()
EndSelect
Wend
FR + 1
If ElapsedMilliseconds() > FRt
time / FR
Select mode
Case 0 : mode$ = "no screen drawing block"
Case 1 : mode$ = "only GrabSprite()"
Case 2 : mode$ = "empty screen drawing block"
Case 3 : mode$ = "base"
Case 4 : mode$ = "base + copy"
Case 5 : mode$ = "base + copy / thread"
EndSelect
FRt = ElapsedMilliseconds() + 500
FR$ = "fps:" + Str(FR * 2)
FR = 0
StartDrawing(SpriteOutput(sprFR))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0, 0, OutputWidth(), OutputHeight(), $0)
DrawingFont(FontID(font))
DrawText(0, 0, FR$)
DrawText(0, 20, "mode: " + mode + " (" + mode$ + ")")
DrawText(0, 40, "frame time: " + time + "ms")
If mode >= 5
DrawText(0, 60, "thread time: " + threadTime + "ms")
EndIf
StopDrawing()
EndIf
ClearScreen($333333)
DisplayTransparentSprite(spr, MouseX(), MouseY())
If mode = 0
; no screen drawing block
ElseIf mode = 1
; test GrabSprite()
Define sprScreen
If sprScreen
FreeSprite(sprScreen)
sprScreen = 0
EndIf
sprScreen = GrabSprite(#PB_Any, 0, 0, #ScreenWidth, #ScreenHeight, #PB_Sprite_AlphaBlending)
;GrabSprite(0, 0, 0, #ScreenWidth, #ScreenHeight, #PB_Sprite_AlphaBlending)
ElseIf mode >= 2
; empty screen drawing block
If StartDrawing(ScreenOutput())
If mode >= 3
; base
Define buffer = DrawingBuffer()
Define pitch = DrawingBufferPitch()
Define pixelFormat = DrawingBufferPixelFormat()
Define pixelSize
; Debug pixelFormat
; Debug pixelFormat!#PB_PixelFormat_ReversedY
; Debug #PB_PixelFormat_24Bits_RGB
; Debug #PB_PixelFormat_32Bits_BGR
; End
If pixelFormat & (#PB_PixelFormat_24Bits_BGR | #PB_PixelFormat_24Bits_RGB)
pixelSize = 3
ElseIf pixelFormat & (#PB_PixelFormat_32Bits_BGR | #PB_PixelFormat_32Bits_RGB)
pixelSize = 4
Else
WaitSemaphore(semaphoreMain) ;>
threadInfo\quitThread = #True
SignalSemaphore(semaphoreThread) ;<
WaitThread(thread)
CloseScreen()
CloseWindow(win)
MessageRequester("error", "pixel format not supported")
End
EndIf
If pixelSize
;yStart = #ScreenHeight * 0.25
;yEnd = #ScreenHeight * 0.75
;xStart = #ScreenWidth * 0.25
;xEnd = #ScreenWidth * 0.75
yStart = #ScreenHeight * 0.1
yEnd = #ScreenHeight * 0.9
xStart = #ScreenWidth * 0.1
xEnd = #ScreenWidth * 0.9
DrawingMode(#PB_2DDrawing_Outlined)
Box(xStart - 20, yStart - 20, xEnd - xStart + 40, yEnd - yStart + 40, $ff00ff00)
If Not buffer2
buffer2 = AllocateMemory(pitch * OutputHeight())
EndIf
If Not bufferTmp
bufferTmp = AllocateMemory(pitch * OutputHeight())
EndIf
If mode >= 4
; copy / thread
WaitSemaphore(semaphoreMain) ;>
CopyMemory(buffer, bufferTmp, OutputHeight() * pitch)
CopyMemory(buffer2, buffer, OutputHeight() * pitch)
CopyMemory(bufferTmp, buffer2, OutputHeight() * pitch)
threadInfo\buffer = buffer2
threadInfo\pitch = pitch
threadInfo\pixelSize = pixelSize
threadInfo\yStart = yStart
threadInfo\yEnd = yEnd
threadInfo\xStart = xStart
threadInfo\xEnd = xEnd
If mode >= 5
SignalSemaphore(semaphoreThread) ;<
Else
SignalSemaphore(semaphoreMain) ;<
EndIf
;Delay(6)
EndIf
EndIf
EndIf
StopDrawing()
EndIf
EndIf
time = time + (ElapsedMilliseconds() - timeTmp)
timeTmp = ElapsedMilliseconds()
DisplaySprite(sprFR, MouseX(), MouseY() + 80)
FlipBuffers()
Until quit
WaitSemaphore(semaphoreMain) ;>
threadInfo\quitThread = #True
SignalSemaphore(semaphoreThread) ;<
WaitThread(thread)
I posted one of the functions in wilberts directional blur thread.Joubarbe wrote:Could you post your part of the code where you draw to the backbuffer? I'm not sure to follow. (Don't need the directional blur functions)
Code: Select all
StartDrawing(ScreenOutput())
DrawingBuffer()
*screen_buffer = AllocateMemory(DrawingBufferPitch() * OutputHeight())
CopyMemory(DrawingBuffer(), *screen_buffer, DrawingBufferPitch() * OutputHeight())
StopDrawing()
; ... Or just "*screen_buffer = DrawingBuffer()", I guess.
Code: Select all
Repeat
...
DirectionalBlur::BlurPixelBuf32(*screen_buffer, 200, 200, 10, DirectionalBlur::#Blur_Full)
...
FlipBuffer()
ForEver
Code: Select all
If IsSprite(sprite_tmp) : FreeSprite(sprite_tmp) : EndIf
sprite_tmp = GrabSprite(#PB_Any, 100, 100, 200, 200, #PB_Sprite_AlphaBlending)
StartDrawing(SpriteOutput(sprite_tmp))
DirectionalBlur::BlurPixelBuf32(DrawingBuffer(), OutputWidth(), OutputHeight(), 10, DirectionalBlur::#Blur_Full)
StopDrawing()
DisplayTransparentSprite(sprite_tmp, 100, 100)
Code: Select all
DirectionalBlur::BlurSurface(*screen_buffer, *screen_buffer_pitch, 0, 0, 800, 800)
Code: Select all
;...
If StartDrawing(ScreenOutput())
*pixel = DrawingBuffer()
pitch = DrawingBufferPitch()
; BlurSurface(*pixel,pitch,100,100,800,800,20)
; BlurSurface(*pixel,pitch,300,300,800,800,20)
; BlurSurface(*pixel,pitch,500,400,800,800,20)
; BlurSurface(*pixel,pitch,000,000,800,800,20)
BlurSurface(*pixel,pitch,0,0,1920,1080,10)
StopDrawing()
EndIf
;...
Code: Select all
Repeat
...
StartDrawing(ScreenOutput())
DrawingBuffer()
StopDrawing()
...
ForEver
YesJoubarbe wrote:Then I need StartDrawing(ScreenOutput())?!
No, seems like something is going wrong.Joubarbe wrote:EDIT: Yeah, well... It's extremely slow to do that, it costs me 25 FPS.