public override void Allocate(int xRes, int yRes)
        {
            queue.Finish();

            Deallocate();
            this.xRes = xRes;
            this.yRes = yRes;

            accumBuffer = context.CreateBuffer(MemFlags.ReadWrite, SubPixelByteSize * AALevel * AALevel * xRes * yRes);

            GL.GenBuffers(1, out glOutputBufferID);
            GL.BindBuffer(BufferTarget.PixelUnpackBuffer, glOutputBufferID);
            GL.BufferData(BufferTarget.PixelUnpackBuffer, (IntPtr)(4 * xRes * yRes), IntPtr.Zero, BufferUsageHint.StreamCopy);
            GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);

            outputBuffer = OpenCL.Buffer.CreateFromGLBuffer(context, MemFlags.ReadWrite, glOutputBufferID);

            glOutputTexID = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, glOutputTexID);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Clamp);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Clamp);
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
                          xRes, yRes, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
            GL.BindTexture(TextureTarget.Texture2D, 0);
        }
        public override void ApplyPalette(Palette palette)
        {
            queue.Finish();

            if (palette.Width <= 0 || palette.Height <= 0)
            {
                throw new ArgumentException("palette may not be empty.");
            }

            disposeAndNullify(ref paletteImage);
            disposeAndNullify(ref paletteBuffer);

            paletteSize = new Size(palette.Width, palette.Height);

            if (useLowProfile)
            {
                paletteBuffer = context.CreateBuffer(MemFlags.ReadOnly, 4 * palette.Width * palette.Height);
                uint[] pixels = new uint[palette.Height * palette.Width];
                Color  col;
                int    i = 0;
                for (int y = 0; y < palette.Height; y++)
                {
                    for (int x = 0; x < palette.Width; x++)
                    {
                        col       = palette.GetPixel(x, y);
                        pixels[i] = (0xFF000000 | (uint)col.B << 16 | (uint)col.G << 8 | (uint)col.R);
                        i++;
                    }
                }
                paletteBuffer.Write(queue, pixels);
            }
            else
            {
                paletteImage = context.CreateImage2D(MemFlags.ReadOnly, new ImageFormat(ChannelOrder.Rgba, ChannelType.UnormInt8), palette.Width, palette.Height);

                uint[,] pixels = new uint[palette.Height, palette.Width];
                Color col;
                for (int y = 0; y < palette.Height; y++)
                {
                    for (int x = 0; x < palette.Width; x++)
                    {
                        col          = palette.GetPixel(x, y);
                        pixels[y, x] = (0xFF000000 | (uint)col.B << 16 | (uint)col.G << 8 | (uint)col.R);
                    }
                }

                paletteImage.Write(queue, pixels);
            }
        }
        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();
        }