internal OpenCLFractalEngine(OpenTK.Graphics.IGraphicsContext graphicsContext, Platform platform, Device device)
        {
            if (graphicsContext == null || !(graphicsContext is OpenTK.Graphics.IGraphicsContextInternal))
            {
                throw new ArgumentException("Invalid graphics context for OpenCLFractalEngine.", "graphicsContext");
            }

            if (platform == null)
            {
                throw new ArgumentException("Invalid platform for OpenCLFractalEngine", "platform");
            }

            if (device == null)
            {
                throw new ArgumentException("Invalid device for OpenCLFractalEngine", "device");
            }

            this.platform = platform;
            this.device   = device;

            useLowProfile = !device.ImageSupport;

            IntPtr curDC = wglGetCurrentDC();

            OpenTK.Graphics.IGraphicsContextInternal gCtx = (OpenTK.Graphics.IGraphicsContextInternal)graphicsContext;

            context = OpenCL.Context.Create(new Device[] { device },
                                            new ContextParam(ContextProperties.Platform, platform),
                                            new ContextParam(ContextProperties.GlContext, gCtx.Context.Handle),
                                            new ContextParam(ContextProperties.WglHdc, curDC));

            iterBlockCount = Util.Clamp((int)device.MaxComputeUnits * 2, 2, 64);

            string source = null;

            if (useLowProfile)
            {
                source = Kernels.KernelResources.kernels_low_cl;
            }
            else
            {
                source = Kernels.KernelResources.kernels_cl;
            }

            string opts = "";

            try{
                program = OpenCL.Program.CreateFromSource(context, new string[] { source });
                program.Build(new Device[] { device }, opts);
            }
            catch (OpenCLCallFailedException ex)
            {
                if (ex.ErrorCode == OpenCL.ErrorCode.BuildProgramFailure)
                {
                    ex.Data.Add("build_log", program.GetBuildLog(device));
                }
                throw ex;
            }

            initIteratorsKernel  = Kernel.Create(program, "init_iterators_kernel");
            resetIteratorsKernel = Kernel.Create(program, "reset_iterators_kernel");
            iterateKernel        = Kernel.Create(program, "iterate_kernel");
            updateStatsKernel    = Kernel.Create(program, "update_stats_kernel");
            resetOutputKernel    = Kernel.Create(program, "reset_output_kernel");
            updateOutputKernel   = Kernel.Create(program, "update_output_kernel");
            glOutputBufferID     = 0;

            queue = CommandQueue.Create(context, device, CommandQueueFlags.ProfilingEnable);

            fractalBuffer    = context.CreateBuffer(MemFlags.ReadOnly, Marshal.SizeOf(typeof(NativeFractal)));
            branchBuffer     = context.CreateBuffer(MemFlags.ReadOnly, Marshal.SizeOf(typeof(NativeBranch)) * NativeFractal.MaxBranches);
            variWeightBuffer = context.CreateBuffer(MemFlags.ReadOnly, 4 * NativeFractal.MaxBranches * NativeFractal.MaxVariations);

            iterPosStateBuffer   = context.CreateBuffer(MemFlags.ReadWrite, (8 * IteratorCount));
            iterColorStateBuffer = context.CreateBuffer(MemFlags.ReadWrite, (8 * IteratorCount));
            iterStatBuffer       = context.CreateBuffer(MemFlags.ReadWrite, Marshal.SizeOf(typeof(NativeIterStatEntry)) * IteratorCount);
            globalStatBuffer     = context.CreateBuffer(MemFlags.ReadWrite, Marshal.SizeOf(typeof(NativeGlobalStatEntry)));

            entropyXBuffer    = context.CreateBuffer(MemFlags.ReadWrite, (16 * IteratorCount));
            entropyCBuffer    = context.CreateBuffer(MemFlags.ReadWrite, (4 * IteratorCount));
            entropySeedBuffer = context.CreateBuffer(MemFlags.ReadWrite, (4 * IteratorCount));

            uint[] seeds = new uint[IteratorCount];
            for (int i = 0; i < IteratorCount; i++)
            {
                seeds[i] = (uint)rand.Next(65536);
            }
            entropySeedBuffer.Write(queue, seeds);

            paletteSize   = new Size(0, 0);
            paletteImage  = null;
            paletteBuffer = null;
            if (!useLowProfile)
            {
                paletteSampler = Sampler.Create(context, true, AddressingMode.ClampToEdge, FilterMode.Linear);
            }

            initIteratorsKernel.SetArgs(entropyXBuffer, entropyCBuffer, entropySeedBuffer);
            Event initEvt;

            initIteratorsKernel.EnqueueLaunch(queue, IteratorCount, IterGroupSize, null, out initEvt);
            initEvt.Wait();
            disposeAndNullify(ref initEvt);

            queue.Finish();
        }