-- ----------------------------------------------------------------------------- -- This file is part of Haskell-Opencl. -- Haskell-Opencl is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- Haskell-Opencl is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- You should have received a copy of the GNU General Public License -- along with Haskell-Opencl. If not, see . -- ----------------------------------------------------------------------------- {-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-} module System.GPU.OpenCL.Context( -- * Types CLContext, -- * Context Functions clCreateContext, clCreateContextFromType, clRetainContext, clReleaseContext, clGetContextReferenceCount, clGetContextDevices ) where -- ----------------------------------------------------------------------------- import Foreign( Ptr, FunPtr, nullPtr, castPtr, alloca, allocaArray, peek, peekArray, pokeArray ) import Foreign.C.Types( CSize ) import Foreign.C.String( CString, peekCString ) import Foreign.Storable( sizeOf ) import System.GPU.OpenCL.Types( CLuint, CLint, CLDeviceType_, CLContextInfo_, CLContextProperty_, CLDeviceID, CLContext, CLDeviceType, CLError(..), bitmaskFromFlags, getCLValue, getEnumCL, wrapCheckSuccess, wrapPError, wrapGetInfo ) #include -- ----------------------------------------------------------------------------- type ContextCallback = CString -> Ptr () -> CSize -> Ptr () -> IO () foreign import ccall "wrapper" wrapContextCallback :: ContextCallback -> IO (FunPtr ContextCallback) foreign import ccall "clCreateContext" raw_clCreateContext :: Ptr CLContextProperty_ -> CLuint -> Ptr CLDeviceID -> FunPtr ContextCallback -> Ptr () -> Ptr CLint -> IO CLContext foreign import ccall "clCreateContextFromType" raw_clCreateContextFromType :: Ptr CLContextProperty_ -> CLDeviceType_ -> FunPtr ContextCallback -> Ptr () -> Ptr CLint -> IO CLContext foreign import ccall "clRetainContext" raw_clRetainContext :: CLContext -> IO CLint foreign import ccall "clReleaseContext" raw_clReleaseContext :: CLContext -> IO CLint foreign import ccall "clGetContextInfo" raw_clGetContextInfo :: CLContext -> CLContextInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint -- ----------------------------------------------------------------------------- mkContextCallback :: (String -> IO ()) -> ContextCallback mkContextCallback f msg _ _ _ = peekCString msg >>= f -- | Creates an OpenCL context. -- An OpenCL context is created with one or more devices. Contexts are used by -- the OpenCL runtime for managing objects such as command-queues, memory, -- program and kernel objects and for executing kernels on one or more devices -- specified in the context. clCreateContext :: [CLDeviceID] -> (String -> IO ()) -> IO (Either CLError CLContext) clCreateContext devs f = allocaArray ndevs $ \pdevs -> do pokeArray pdevs devs wrapPError $ \perr -> do fptr <- wrapContextCallback $ mkContextCallback f raw_clCreateContext nullPtr cndevs pdevs fptr nullPtr perr where ndevs = length devs cndevs = fromIntegral ndevs -- | Create an OpenCL context from a device type that identifies the specific -- device(s) to use. clCreateContextFromType :: [CLDeviceType] -> (String -> IO ()) -> IO (Either CLError CLContext) clCreateContextFromType xs f = wrapPError $ \perr -> do fptr <- wrapContextCallback $ mkContextCallback f raw_clCreateContextFromType nullPtr types fptr nullPtr perr where types = bitmaskFromFlags xs -- | Increment the context reference count. -- 'clCreateContext' and 'clCreateContextFromType' perform an implicit retain. -- This is very helpful for 3rd party libraries, which typically get a context -- passed to them by the application. However, it is possible that the -- application may delete the context without informing the library. Allowing -- functions to attach to (i.e. retain) and release a context solves the -- problem of a context being used by a library no longer being valid. -- Returns 'True' if the function is executed successfully, or 'False' if -- context is not a valid OpenCL context. clRetainContext :: CLContext -> IO Bool clRetainContext ctx = wrapCheckSuccess $ raw_clRetainContext ctx -- | Decrement the context reference count. -- After the context reference count becomes zero and all the objects attached -- to context (such as memory objects, command-queues) are released, the -- context is deleted. -- Returns 'True' if the function is executed successfully, or 'False' if -- context is not a valid OpenCL context. clReleaseContext :: CLContext -> IO Bool clReleaseContext ctx = wrapCheckSuccess $ raw_clReleaseContext ctx getContextInfoSize :: CLContext -> CLContextInfo_ -> IO (Either CLError CSize) getContextInfoSize ctx infoid = alloca $ \(value_size :: Ptr CSize) -> do errcode <- raw_clGetContextInfo ctx infoid 0 nullPtr value_size if errcode == getCLValue CL_SUCCESS then fmap Right $ peek value_size else return . Left . getEnumCL $ errcode #c enum CLContextInfo { cL_CONTEXT_REFERENCE_COUNT=CL_CONTEXT_REFERENCE_COUNT, cL_CONTEXT_DEVICES=CL_CONTEXT_DEVICES, cL_CONTEXT_PROPERTIES=CL_CONTEXT_PROPERTIES }; #endc {#enum CLContextInfo {upcaseFirstLetter} #} -- | Return the context reference count. The reference count returned should be -- considered immediately stale. It is unsuitable for general use in -- applications. This feature is provided for identifying memory leaks. clGetContextReferenceCount :: CLContext -> IO (Either CLError CLuint) clGetContextReferenceCount ctx = wrapGetInfo (\(dat :: Ptr CLuint) -> raw_clGetContextInfo ctx infoid size (castPtr dat)) id where infoid = getCLValue CL_CONTEXT_REFERENCE_COUNT size = fromIntegral $ sizeOf (0::CLuint) -- | Return the list of devices in context. clGetContextDevices :: CLContext -> IO (Either CLError [CLDeviceID]) clGetContextDevices ctx = do val <- getContextInfoSize ctx infoid case val of Left err -> return . Left $ err Right size -> let n = (fromIntegral size) `div` elemSize in allocaArray n $ \(buff :: Ptr CLDeviceID) -> do errcode <- raw_clGetContextInfo ctx infoid size (castPtr buff) nullPtr if errcode == getCLValue CL_SUCCESS then fmap Right $ peekArray n buff else return . Left . getEnumCL $ errcode where infoid = getCLValue CL_CONTEXT_DEVICES elemSize = sizeOf (nullPtr :: CLDeviceID) -- -----------------------------------------------------------------------------