Skip to content

Commit 76d2509

Browse files
committed
Minimal example of filters on GPU
1 parent 14b9e12 commit 76d2509

File tree

7 files changed

+152
-4
lines changed

7 files changed

+152
-4
lines changed

paket.dependencies

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ nuget altcover ~> 8.2.825
1010
nuget Packaging.Targets 0.1.208
1111

1212
nuget SixLabors.ImageSharp
13+
nuget Brahma.FSharp
1314
// [ FAKE GROUP ]
1415
group Build
1516
storage: none

paket.lock

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,45 @@ NUGET
55
Argu (6.1.1)
66
FSharp.Core (>= 4.3.2) - restriction: >= netstandard2.0
77
System.Configuration.ConfigurationManager (>= 4.4) - restriction: >= netstandard2.0
8+
Brahma.FSharp (2.0.1)
9+
Brahma.FSharp.OpenCL.Printer (>= 2.0.1) - restriction: >= net5.0
10+
Brahma.FSharp.OpenCL.Shared (>= 2.0.1) - restriction: >= net5.0
11+
Brahma.FSharp.OpenCL.Translator (>= 2.0.1) - restriction: >= net5.0
12+
FSharp.Core (>= 5.0.1) - restriction: >= net5.0
13+
FSharp.Quotations.Evaluator (>= 2.1) - restriction: >= net5.0
14+
YC.OpenCL.NET (>= 2.0.1) - restriction: >= net5.0
15+
Brahma.FSharp.OpenCL.AST (2.0.1) - restriction: >= net5.0
16+
FSharp.Core (>= 5.0.1) - restriction: >= net5.0
17+
Brahma.FSharp.OpenCL.Printer (2.0.1) - restriction: >= net5.0
18+
Brahma.FSharp.OpenCL.AST (>= 2.0.1) - restriction: >= net5.0
19+
Brahma.FSharp.OpenCL.Translator (>= 2.0.1) - restriction: >= net5.0
20+
FSharp.Core (>= 5.0.1) - restriction: >= net5.0
21+
FSharpx.Collections (>= 2.1.3) - restriction: >= net5.0
22+
FSharpx.Text.StructuredFormat (>= 3.0) - restriction: >= net5.0
23+
Brahma.FSharp.OpenCL.Shared (2.0.3) - restriction: >= net5.0
24+
YC.OpenCL.NET (>= 2.0.3) - restriction: >= net7.0
25+
Brahma.FSharp.OpenCL.Translator (2.0.1) - restriction: >= net5.0
26+
Brahma.FSharp.OpenCL.AST (>= 2.0.1) - restriction: >= net5.0
27+
Brahma.FSharp.OpenCL.Shared (>= 2.0.1) - restriction: >= net5.0
28+
FSharp.Core (>= 5.0.1) - restriction: >= net5.0
29+
FSharp.Quotations.Evaluator (>= 2.1) - restriction: >= net5.0
30+
FSharpx.Collections (>= 2.1.3) - restriction: >= net5.0
831
Expecto (9.0.4)
932
FSharp.Core (>= 4.6) - restriction: || (>= net461) (>= netstandard2.0)
1033
Mono.Cecil (>= 0.11.3) - restriction: || (>= net461) (>= netstandard2.0)
34+
ExtraConstraints.Fody (1.14) - restriction: >= net7.0
35+
Fody (>= 6.0) - restriction: || (>= net452) (>= netstandard1.4)
36+
NETStandard.Library (>= 1.6.1) - restriction: && (< net452) (>= netstandard1.4)
37+
Fody (6.6.4) - restriction: >= net7.0
1138
FSharp.Core (6.0)
39+
FSharp.Quotations.Evaluator (2.1) - restriction: >= net5.0
40+
FSharp.Core (>= 4.3.1) - restriction: >= netstandard2.0
41+
FSharpx.Collections (3.1) - restriction: >= net5.0
42+
FSharp.Core (>= 4.3.4) - restriction: >= netstandard2.0
43+
FSharpx.Text.StructuredFormat (3.1) - restriction: >= net5.0
44+
FSharp.Core (>= 4.6.2) - restriction: || (>= net452) (>= netstandard2.0)
45+
Microsoft.Build.Framework (16.10) - restriction: >= net7.0
46+
System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0)
1247
Microsoft.CodeCoverage (17.5.0-preview-20221221-03) - restriction: || (>= net45) (>= netcoreapp1.0)
1348
Microsoft.CSharp (4.7) - restriction: || (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard2.0) (>= uap10.0))
1449
Microsoft.NET.Test.Sdk (17.1.0-preview-20211109-03)
@@ -32,7 +67,7 @@ NUGET
3267
System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)
3368
Microsoft.Win32.SystemEvents (7.0) - restriction: >= net6.0
3469
Mono.Cecil (0.11.4) - restriction: || (>= net461) (>= netstandard2.0)
35-
NETStandard.Library (2.0.3) - restriction: || (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard2.0) (>= uap10.0))
70+
NETStandard.Library (2.0.3) - restriction: || (>= net7.0) (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard2.0) (>= uap10.0))
3671
Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (>= net45) (< netstandard1.3)) (&& (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< net45) (>= netstandard2.0)) (&& (>= net46) (< netstandard1.4)) (>= net461) (>= netcoreapp2.0) (&& (>= netstandard1.0) (< portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= portable-net45+win8) (< win8)) (&& (< netstandard1.0) (< portable-net45+win8) (>= portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard1.3) (< win8) (>= wpa81)) (&& (< netstandard1.5) (>= uap10.0)) (>= uap10.1) (>= wp8)
3772
Microsoft.Win32.Primitives (>= 4.3) - restriction: || (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (>= net46) (< netstandard1.4)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1))
3873
System.AppContext (>= 4.3) - restriction: || (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (>= net46) (< netstandard1.4)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1))
@@ -127,6 +162,7 @@ NUGET
127162
System.AppContext (4.3) - restriction: || (&& (>= net46) (< netstandard1.4) (>= uap10.0)) (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard1.4) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.5) (< netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) (&& (< netstandard1.5) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.6) (< netstandard2.0) (>= uap10.0) (< win8) (< wpa81))
128163
System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.6)) (&& (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos))
129164
System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (< netstandard1.1) (>= netstandard2.1)) (&& (< monoandroid) (>= netstandard2.1)) (&& (>= monotouch) (>= netstandard2.1)) (&& (>= net45) (>= netstandard2.1)) (&& (>= net46) (< netstandard1.4) (>= uap10.0)) (&& (>= net461) (>= netstandard2.1)) (&& (< netcoreapp2.0) (>= netstandard2.1)) (&& (< netcoreapp2.1) (>= netstandard2.1)) (&& (< netcoreapp2.1) (>= xamarinios)) (&& (< netcoreapp2.1) (>= xamarinmac)) (&& (< netstandard1.1) (>= netstandard2.1) (>= win8)) (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard1.4) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.5) (< netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) (&& (< netstandard1.5) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (>= netstandard2.0) (&& (>= netstandard2.1) (>= wpa81))
165+
System.CodeDom (7.0) - restriction: >= net7.0
130166
System.Collections (4.3) - restriction: || (&& (< netstandard1.2) (>= uap10.0) (< win8)) (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard1.4) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.5) (< netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) (&& (< netstandard1.5) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard2.0) (>= uap10.0)) (&& (< portable-net45+win8+wpa81) (>= uap10.0))
131167
System.Collections.Concurrent (4.3) - restriction: || (&& (< netstandard1.2) (>= uap10.0) (< win8)) (&& (< netstandard1.3) (>= uap10.0)) (&& (< netstandard1.4) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.5) (< netstandard1.6) (>= uap10.0) (< win8) (< wpa81)) (&& (< netstandard1.5) (>= uap10.0) (< uap10.1)) (&& (< netstandard1.5) (>= uap10.0) (< win8) (< wpa81)) (&& (>= netstandard1.6) (< netstandard2.0) (>= uap10.0) (< win8) (< wpa81))
132168
System.Collections.Immutable (7.0) - restriction: >= netcoreapp2.1
@@ -284,6 +320,10 @@ NUGET
284320
System.Text.Encoding (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)
285321
System.Threading (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)
286322
System.Xml.ReaderWriter (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)
323+
YC.OpenCL.NET (2.0.3) - restriction: >= net5.0
324+
ExtraConstraints.Fody (1.14) - restriction: >= net7.0
325+
Microsoft.Build.Framework (16.10) - restriction: >= net7.0
326+
System.CodeDom (>= 7.0) - restriction: >= net7.0
287327
YoloDev.Expecto.TestSdk (0.12.12)
288328
Expecto (>= 9.0 < 10.0) - restriction: >= netcoreapp2.1
289329
FSharp.Core (>= 4.6) - restriction: >= netcoreapp2.1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
2+
<ExtraConstraints />
3+
</Weavers>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3+
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
4+
<xs:element name="Weavers">
5+
<xs:complexType>
6+
<xs:all>
7+
<xs:element name="ExtraConstraints" minOccurs="0" maxOccurs="1" type="xs:anyType" />
8+
</xs:all>
9+
<xs:attribute name="VerifyAssembly" type="xs:boolean">
10+
<xs:annotation>
11+
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
12+
</xs:annotation>
13+
</xs:attribute>
14+
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
15+
<xs:annotation>
16+
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
17+
</xs:annotation>
18+
</xs:attribute>
19+
<xs:attribute name="GenerateXsd" type="xs:boolean">
20+
<xs:annotation>
21+
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
22+
</xs:annotation>
23+
</xs:attribute>
24+
</xs:complexType>
25+
</xs:element>
26+
</xs:schema>

src/ImageProcessing/ImageProcessing.fs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module ImageProcessing.ImageProcessing
22

3+
open Brahma.FSharp
34
open SixLabors.ImageSharp
45
open SixLabors.ImageSharp.PixelFormats
56

@@ -64,3 +65,70 @@ let applyFilter (filter: float32[][]) (img: byte[,]) =
6465
Array.fold2 (fun s x y -> s + x * y) 0.0f filter dataToHandle
6566

6667
Array2D.mapi (fun x y _ -> byte (processPixel x y)) img
68+
69+
70+
let applyFilterGPUKernel (clContext: ClContext) localWorkSize =
71+
72+
let kernel =
73+
<@
74+
fun (r:Range1D) (img:ClArray<_>) imgW imgH (filter:ClArray<_>) filterD (result:ClArray<_>) ->
75+
let p = r.GlobalID0
76+
let pw = p % imgW
77+
let ph = p / imgW
78+
79+
let mutable res = 0.0f
80+
81+
for i in ph - filterD .. ph + filterD do
82+
for j in pw - filterD .. pw + filterD do
83+
let mutable d = 0uy
84+
if i < 0 || i >= imgH || j < 0 || j >= imgW
85+
then d <- img.[p]
86+
else d <- img.[i * imgW + j]
87+
let f = filter.[(i - ph + filterD) * (2 * filterD + 1) + (j - pw + filterD)]
88+
res <- res + (float32 d) * f
89+
result.[p] <- byte (int res)
90+
@>
91+
92+
let kernel = clContext.Compile kernel
93+
94+
fun (commandQueue: MailboxProcessor<_>) (filter: ClArray<float32>) filterD (img: ClArray<byte>) imgH imgW ->
95+
96+
let result = clContext.CreateClArray(img.Length, allocationMode = AllocationMode.Default)
97+
98+
let ndRange = Range1D.CreateValid(imgH * imgW, localWorkSize)
99+
100+
let kernel = kernel.GetKernel()
101+
commandQueue.Post(
102+
Msg.MsgSetArguments
103+
(fun () -> kernel.KernelFunc ndRange img imgW imgH filter filterD result)
104+
)
105+
commandQueue.Post(Msg.CreateRunMsg<_, _> kernel)
106+
result
107+
108+
let applyFiltersGPU (clContext: ClContext) localWorkSize =
109+
let kernel = applyFilterGPUKernel clContext localWorkSize
110+
let queue = clContext.QueueProvider.CreateQueue()
111+
fun (filters: list<float32[][]>) (img: byte[,]) ->
112+
let imgH = img.GetLength 0
113+
let imgW = img.GetLength 1
114+
let img =
115+
[| for x in 0 .. Array2D.length1 img - 1 do
116+
yield! [| for y in 0 .. Array2D.length2 img - 1 -> img.[x, y] |]
117+
|]
118+
let clImage = clContext.CreateClArray<_> img
119+
120+
let mutable res = Unchecked.defaultof<_>
121+
122+
for filter in filters do
123+
let filter = Array.concat filter
124+
let filterD = (Array.length filter) / 2
125+
let clFilter = clContext.CreateClArray<_> filter
126+
res <- kernel queue clFilter filterD clImage imgH imgW
127+
queue.Post(Msg.CreateFreeMsg clFilter)
128+
129+
let result' = Array.zeroCreate (imgH * imgW)
130+
let result' = queue.PostAndReply(fun ch -> Msg.CreateToHostMsg(res, result', ch))
131+
let result = Array2D.zeroCreate imgH imgW
132+
Array.Parallel.iteri (fun x v -> result.[x / imgW, x % imgW] <- v) result'
133+
clImage.Dispose()
134+
result

src/ImageProcessing/Main.fs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
namespace ImageProcessing
22

3+
open Brahma.FSharp
4+
35
module Main =
46
let pathToExamples = "/home/gsv/Projects/TestProj2020/src/ImgProcessing/Examples"
57
let inputFolder = System.IO.Path.Combine(pathToExamples,"input")
68
let demoFile = System.IO.Path.Combine(inputFolder, "armin-djuhic-ohc29QXbS-s-unsplash.jpg")
79
[<EntryPoint>]
810
let main (argv: string array) =
11+
let device = ClDevice.GetFirstAppropriateDevice()
12+
printfn $"Device: %A{device.Name}"
13+
14+
let context = ClContext(device)
15+
let applyFiltersGPU = ImageProcessing.applyFiltersGPU context 32
16+
917
let grayscaleImage = ImageProcessing.loadAs2DArray demoFile
10-
let blur = ImageProcessing.applyFilter ImageProcessing.gaussianBlurKernel grayscaleImage
11-
let edges = ImageProcessing.applyFilter ImageProcessing.edgesKernel blur
18+
//let blur = ImageProcessing.applyFilter ImageProcessing.gaussianBlurKernel grayscaleImage
19+
//let edges = ImageProcessing.applyFilter ImageProcessing.edgesKernel blur
20+
let edges = applyFiltersGPU [ImageProcessing.gaussianBlurKernel; ImageProcessing.edgesKernel] grayscaleImage
1221
ImageProcessing.save2DByteArrayAsImage edges "../../../../../out/demo_grayscale.jpg"
1322
0
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
FSharp.Core
22
Argu
33
Packaging.Targets
4-
SixLabors.ImageSharp
4+
SixLabors.ImageSharp
5+
Brahma.FSharp

0 commit comments

Comments
 (0)