YaccConstructor / Brahma.FSharp

F# quotation to OpenCL translator and respective runtime to utilize GPGPUs in F# applications.
http://yaccconstructor.github.io/Brahma.FSharp
Eclipse Public License 1.0
74 stars 17 forks source link

Unexpected behavior with float32 argument in kernel #157

Closed PolinaSavelyeva closed 4 months ago

PolinaSavelyeva commented 1 year ago

Describe the bug Unexpected behavior when value of type float32 is provided as an argument to the kernel

Unhandled exception. System.Exception: Unexpected argument: 0.4102564156f
   at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1448.Invoke(String message)
   at Microsoft.FSharp.Core.PrintfModule.gprintf[a,TState,TResidue,TResult,TPrinter](FSharpFunc`2 envf, PrintfFormat`4 format) in D:\a\_work\1\s\src\FSharp.Core\printf.fs:line 1398
   at Brahma.FSharp.ClProgram`2.setupArgument(Kernel kernel, Int32 index, Object arg)
   at lambda_method3(Closure, Kernel, Int32, Object)
   at Microsoft.FSharp.Collections.ArrayModule.IterateIndexed[T](FSharpFunc`2 action, T[] array) in D:\a\_work\1\s\src\FSharp.Core\array.fs:line 437
   at lambda_method4(Closure, FSharpFunc`2, Object[])
   at FSharp.Quotations.Evaluator.Tools.Invoke@137-19DD.Invoke(l l, m m)
   at GPUKernels.resize@170-1.Invoke(Unit unitVar0) in /Users/svmena/Documents/GPUImageProcessing/src/GPUImageProcessing/GPUKernels.fs:line 170
   at <StartupCode$Brahma-FSharp-OpenCL-Core>.$CommandQueueProvider.loop@148-6.Invoke(Unit unitVar)
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in D:\a\_work\1\s\src\FSharp.Core\async.fs:line 510
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in D:\a\_work\1\s\src\FSharp.Core\async.fs:line 112
--- End of stack trace from previous location ---
   at Microsoft.FSharp.Control.AsyncPrimitives.Start@1174-1.Invoke(ExceptionDispatchInfo edi) in D:\a\_work\1\s\src\FSharp.Core\async.fs:line 1174
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in D:\a\_work\1\s\src\FSharp.Core\async.fs:line 112
   at <StartupCode$FSharp-Core>.$Async.clo@193-15.Invoke(Object o) in D:\a\_work\1\s\src\FSharp.Core\async.fs:line 195
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
   at System.Threading.Thread.StartCallback()

To Reproduce

  1. Kernel
 let resizeKernel (clContext: ClContext) localWorkSize =

    let kernel =
        <@
            fun (range: Range1D) (image: ClArray<byte>) imageWidth imageHeight newWidth newHeight (scaleX: float32) (scaleY: float32) (result: ClArray<byte>) ->
                let p = range.GlobalID0
                let py = p / newWidth
                let px = p % newWidth

                let positionY = float32 py * scaleY
                let yLower = int positionY

                let positionX = float32 px * scaleX
                let xLower = int positionX

                if py < newHeight
                   && xLower < imageWidth
                   && yLower < imageHeight
                   && xLower >= 0
                   && yLower >= 0 then

                        let originalIndex = yLower * imageWidth + xLower

                        if originalIndex < imageWidth * imageHeight then

                            result[p] <- image[originalIndex]
        @>

    let kernel = clContext.Compile kernel

    fun (commandQueue: MailboxProcessor<Msg>) (image: ClArray<byte>) imageWidth imageHeight newWidth newHeight scaleX scaleY (result: ClArray<byte>) ->

        let ndRange = Range1D.CreateValid(newWidth * newHeight, localWorkSize)
        let kernel = kernel.GetKernel()

        commandQueue.Post(Msg.MsgSetArguments(fun () -> kernel.KernelFunc ndRange image imageWidth imageHeight newWidth newHeight scaleX scaleY result))
        commandQueue.Post(Msg.CreateRunMsg<INDRange, obj> kernel)

        result
  1. Kernel execution
let resize (clContext: ClContext) (localWorkSize: int) =

    let resizeKernel = resizeKernel clContext localWorkSize
    let queue = clContext.QueueProvider.CreateQueue()

    fun (newWidth: int) (newHeight: int) (imageWidth: int) (imageHeight: int) (image: array<byte>) ->

        if newWidth <= 0 || newHeight <= 0 then
            failwith $"Expected positive new sides, but given newWidth = %A{newWidth} and newHeight = %A{newHeight}. "

        let input =
            clContext.CreateClArray<byte>(image, HostAccessMode.NotAccessible, DeviceAccessMode.ReadOnly)

        let output =
            clContext.CreateClArray(newWidth * newHeight, HostAccessMode.NotAccessible, DeviceAccessMode.WriteOnly)

        let result = Array.zeroCreate (newWidth * newHeight)

        let scaleX = float32 imageWidth / float32 newWidth
        let scaleY = float32 imageHeight / float32 newHeight

        let result =
            queue.PostAndReply(fun ch -> Msg.CreateToHostMsg(resizeKernel queue input imageWidth imageHeight newWidth newHeight scaleX scaleY output, result, ch))

        queue.Post(Msg.CreateFreeMsg input)
        queue.Post(Msg.CreateFreeMsg output)

Expected behavior float32 should be a valid input type to the kernel

Workaround Provide ClCell<float32> argument instead

Additional context Brahma.FSharp: 2.0.5

gsvgit commented 4 months ago

Fixed in this commit