packages feed

cuda-0.2: examples/src/simpleTexture/SimpleTexture.hs

{-# LANGUAGE ParallelListComp #-}
--------------------------------------------------------------------------------
--
-- Module    : SimpleTexture
-- Copyright : (c) 2009 Trevor L. McDonell
-- License   : BSD
--
-- Demonstrates texture references. Takes an input PGM file and generates an
-- output that has been rotated. The kernel performs a simple 2D transformation
-- on the texture coordinates (u,v).
--
--------------------------------------------------------------------------------

module Main where

import Data.Array.Unboxed
import Graphics.Pgm
import qualified Foreign.CUDA                 as CUDA
import qualified Foreign.CUDA.Runtime.Texture as CUDA


imageFile, outputFile, referenceFile :: FilePath
imageFile     = "data/lena_bw.pgm"
outputFile    = "data/lena_bw_out.pgm"
referenceFile = "data/ref_rotated.pgm"

rotation :: Float
rotation = 0.5          -- radians


main :: IO ()
main = do
  img <- either (error . show) head `fmap` pgmsFromFile imageFile
  ref <- either (error . show) head `fmap` pgmsFromFile referenceFile
  runTest img ref


runTest :: UArray (Int,Int) Int -> UArray (Int,Int) Int -> IO ()
runTest img ref' = do
  rotated <- transform (amap (\x-> fromIntegral x/255) img)
  arrayToFile outputFile (amap (\x -> round (x*255)) rotated)
  if verify (elems ref) (elems rotated)
     then putStrLn "PASSED"
     else putStrLn "FAILED!"

  where
    ref          = amap (\x -> fromIntegral x / 255) ref'
    verify xs ys = all (< epsilon) [abs ((x-y)/(x+y+epsilon)) | x <- xs | y <- ys]
    epsilon      = 0.05


transform :: UArray (Int,Int) Float -> IO (UArray (Int,Int) Float)
transform pgm =
  let bnds@((x0,y0),(x1,y1)) = bounds pgm
      width   = x1-x0+1
      height  = y1-y0+1
      desc    = CUDA.FormatDesc (32,0,0,0) CUDA.Float
      texture = CUDA.Texture True CUDA.Linear (CUDA.Wrap,CUDA.Wrap,CUDA.Wrap) desc
  in
  CUDA.allocaArray (width * height) $ \d_out ->
  CUDA.withListArray (elems pgm)    $ \d_tex -> do
    CUDA.bind2D "tex" texture d_tex (width,height) (fromIntegral $ height * 4)
    CUDA.setConfig (width `div` 8,height `div` 8) (8,8,1) 0 Nothing
    CUDA.setParams [CUDA.VArg d_out, CUDA.IArg width, CUDA.IArg height, CUDA.FArg rotation]
    CUDA.launch "transformKernel"

    listArray bnds `fmap` CUDA.peekListArray (width*height) d_out