/// <summary>
        /// Initialize specified OpenCL device
        /// </summary>
        /// <param name="device">Device</param>
        private static void InitializeDevice(OpenCLDevice device)
        {
            if (device.Context != null)
            {
                return;
            }

            Context      context      = null;
            CommandQueue commandQueue = null;

            try {
                context = Context.Create(device.InnerDevice);

#if ENABLE_PROFILING
                commandQueue = context.CreateCommandQueue(device.InnerDevice, CommandQueueProperties.ProfilingEnable);
#else
                commandQueue = context.CreateCommandQueue(device.InnerDevice, 0);
#endif
            } catch (Exception ex) {
                if (commandQueue != null)
                {
                    commandQueue.Dispose();
                }

                if (context != null)
                {
                    context.Dispose();
                }

                throw new OpenCLException("Device is not available (" + ex.Message + ").", ex);
            }

            device.Context      = context;
            device.CommandQueue = commandQueue;
        }
        /// <summary>
        /// Compiles specified OpenCL program on specified device
        /// </summary>
        /// <param name="device">OpenCL device</param>
        /// <param name="programName">Program name</param>
        /// <param name="programReceiveCallback">Callback to receive program sources; or null to use default storage</param>
        /// <returns>Kernel set for program</returns>
        public OpenCLKernelSet Compile(OpenCLDevice device, string programName, Func <string, string> programReceiveCallback = null)
        {
            const string buildOptions = "-cl-fast-relaxed-math -cl-mad-enable -cl-no-signed-zeros";

            InitializeDevice(device);

            OpenCLKernelSet kernelSet;

            if (device.CachedKernels == null)
            {
                device.CachedKernels = new Dictionary <string, OpenCLKernelSet>();
            }
            else
            {
                if (device.CachedKernels.TryGetValue(programName, out kernelSet))
                {
                    return(kernelSet);
                }
            }

            string programSource;

            if (programReceiveCallback != null)
            {
                programSource = programReceiveCallback(programName);
            }
            else
            {
                programSource = LoadSourceFromResources(programName);
            }

            Program program = device.Context.CreateProgramWithSource(programSource);

            program.Build(UseRelaxedMath ? buildOptions : null);

#if ENABLE_PROFILING
            Console.WriteLine("Using kernel {0}...", programName);
            Console.WriteLine("OpenCL Build log: " + program.GetBuildLog(device.InnerDevice));
#endif

            kernelSet = new OpenCLKernelSet {
                Program     = program,
                Kernels     = new Dictionary <string, NOpenCL.Kernel>(),
                OwnerDevice = device
            };

            device.CachedKernels[programName] = kernelSet;
            return(kernelSet);
        }
        /// <summary>
        /// Creates buffer on target device from memory
        /// </summary>
        /// <param name="device">Target device</param>
        /// <param name="ptr">Pointer to memory</param>
        /// <param name="size">Size of memory</param>
        /// <param name="readOnly">Bind as read-only</param>
        /// <returns>Buffer</returns>
        public unsafe OpenCLBuffer CreateBuffer(OpenCLDevice device, void *ptr, int size, bool readOnly)
        {
            try {
                NOpenCL.Buffer buffer = device.Context.CreateBuffer(
                    MemoryFlags.UseHostPointer | (readOnly ? MemoryFlags.ReadOnly : MemoryFlags.ReadWrite),
                    size,
                    new IntPtr(ptr));

                return(new OpenCLBuffer {
                    Ptr = new IntPtr(ptr),
                    Buffer = buffer,
                    OwnerDevice = device,
                    HasOwnership = true
                });
            } catch (Exception ex) {
                throw new OpenCLException("Cannot create buffer. Buffer size is probably too high.", ex);
            }
        }