
OpenCLOpenGL Interop using VBO: SimpleGL
Posted Monday, 21 June, 2010 - 13:58 by LikeKT inCredits:
Douglas Andrade's CMSoft OpenCLOpenGL interop example as a template
nythrix for saving me hours of debuging.
Ref to existing discussion: Converting the N-Body C tutorial
http://www.opentk.com/node/1772
FYI: this is not a complete port but to evaluate how to do VBO openCLopenGL interop using OpenTK and Cloo.NET
There is room for improvement, welcome any feedback.
using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using OpenTK.Input; using Cloo; namespace CLGLInterop { class SimpleGLCloo : GameWindow { [DllImport("opengl32.dll")] extern static IntPtr wglGetCurrentDC(); #region Kernel code string source = @"__kernel void sine_wave(__global float4* pos, unsigned int width, unsigned int height, float time) { unsigned int x = get_global_id(0); unsigned int y = get_global_id(1); // calculate uv coordinates float u = x / (float) width; float v = y / (float) height; u = u*2.0f - 1.0f; v = v*2.0f - 1.0f; // calculate simple sine wave pattern float freq = 4.0f; float w = sin(u*freq + time) * cos(v*freq + time) * 0.5f; // write output vertex pos[y*width+x] = (float4)(u, w, v, 1.0f); }"; #endregion private float translationX = 0; private float translationY = 0; private float translationZ = -4; private float rotationX = 40; private float rotationY = 30; private int meshWidth = 256; private int meshHeight = 256; private float animationState = 0.0f; private long[] globalWorkSize; private bool GL_Interop = false; private bool initialized = false; private ComputeContext cxGPUContext; private ComputeCommandQueue cqCommandQueue; private ComputeKernel kernel; private ComputeBuffer<float> mVbo; private ComputeBuffer<float> mVertices; private float[] VerticeArray; private List<ComputeMemory> computeMemory; private int[] vbo= new int[1]; private IntPtr vboMemSize; private long vboSize; public SimpleGLCloo() { } /// <summary>Load resources here.</summary> /// <param name="e">Not used.</param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); VerticeArray = new float[meshWidth * meshHeight * 4]; GL.ClearColor(0.1f, 0.2f, 0.5f, 0.0f); GL.Enable(EnableCap.DepthTest); GL_Interop = true; if (GL_Interop) { #region Creating OpenGL compatible Context IntPtr curDC = wglGetCurrentDC(); OpenTK.Graphics.IGraphicsContextInternal ctx = (OpenTK.Graphics.IGraphicsContextInternal)OpenTK.Graphics.GraphicsContext.CurrentContext; IntPtr raw_context_handle = ctx.Context.Handle; ComputeContextProperty p1 = new ComputeContextProperty(ComputeContextPropertyName.CL_GL_CONTEXT_KHR, raw_context_handle); ComputeContextProperty p2 = new ComputeContextProperty(ComputeContextPropertyName.CL_WGL_HDC_KHR, curDC); ComputeContextProperty p3 = new ComputeContextProperty(ComputeContextPropertyName.Platform, ComputePlatform.Platforms[0].Handle); List<ComputeContextProperty> props = new List<ComputeContextProperty>() { p1, p2, p3 }; ComputeContextPropertyList Properties = new ComputeContextPropertyList(props); cxGPUContext = new ComputeContext(ComputeDeviceTypes.Gpu, Properties, null, IntPtr.Zero); #endregion } else { ComputeContextProperty p1 = new ComputeContextProperty(ComputeContextPropertyName.Platform, ComputePlatform.Platforms[0].Handle); List<ComputeContextProperty> props = new List<ComputeContextProperty>() { p1 }; ComputeContextPropertyList Properties = new ComputeContextPropertyList(props); cxGPUContext = new ComputeContext(ComputeDeviceTypes.Gpu, Properties, null, IntPtr.Zero); } cqCommandQueue = new ComputeCommandQueue(cxGPUContext, cxGPUContext.Devices[0], ComputeCommandQueueFlags.None); // create the program ComputeProgram program = new ComputeProgram(cxGPUContext, source); program.Build(cxGPUContext.Devices, "", null, IntPtr.Zero); // Create the kernel kernel = program.CreateKernel("sine_wave"); initVBO(); if (GL_Interop) { kernel.SetMemoryArgument(0, this.mVbo); } else { kernel.SetMemoryArgument(0, this.mVertices); } kernel.SetValueArgument<int>(1, meshWidth ); kernel.SetValueArgument<int>(2, meshHeight ); cqCommandQueue = new ComputeCommandQueue(cxGPUContext, cxGPUContext.Devices[0], ComputeCommandQueueFlags.None); initialized = true; } /** * Create the vertex buffer object (VBO) that stores the * vertex positions. */ private void initVBO() { if (vbo[0] != 0) { GL.DeleteBuffers(1, ref vbo[0]); vbo[0] = 0; } GL.GenBuffers(1, out vbo[0]); GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]); vboSize = meshWidth * meshHeight * 4 * sizeof(float); vboMemSize = Marshal.AllocHGlobal((int)vboSize); GL.BufferData(BufferTarget.ArrayBuffer, vboMemSize, IntPtr.Zero, BufferUsageHint.DynamicDraw); if (GL_Interop) { mVbo = ComputeBuffer<float>.CreateFromGLBuffer<float>(cxGPUContext, ComputeMemoryFlags.WriteOnly, vbo[0]); } else { mVertices = new ComputeBuffer<float>(cxGPUContext, ComputeMemoryFlags.WriteOnly, VerticeArray); } } protected override void OnUnload(EventArgs e) { base.OnUnload(e); GL.DeleteBuffers(1, ref vbo[0]); } protected override void OnResize(EventArgs e) { base.OnResize(e); GL.Viewport(0, 0, Width, Height); GL.MatrixMode(MatrixMode.Projection); float degreeRadian = MathHelper.DegreesToRadians(50.0f); Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(degreeRadian, Width / (float)Height, 0.1f, 100.0f); GL.LoadMatrix(ref projection); } protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); if (Keyboard[Key.Escape]) Exit(); } protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); if (!initialized) { return; } runKernel(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.MatrixMode(MatrixMode.Modelview); GL.LoadIdentity(); GL.Translate(translationX, translationY, translationZ); GL.Rotate(rotationX, 1.0f, 0.0f, 0.0f); GL.Rotate(rotationY, 0.0f, 1.0f, 0.0f); rotationY += 0.5f; GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]); GL.VertexPointer(4, VertexPointerType.Float, 0, 0); GL.EnableClientState(ArrayCap.VertexArray); GL.Color3(1.0f, 0.0f, 0.0f); GL.DrawArrays(BeginMode.Points, 00, meshWidth * meshHeight); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); GL.DisableClientState(ArrayCap.VertexArray); animationState += 0.01f; SwapBuffers(); } private void runKernel() { if (GL_Interop) { GL.Finish(); computeMemory = new List<ComputeMemory>() { this.mVbo }; cqCommandQueue.AcquireGLObjects(computeMemory, null); } kernel.SetValueArgument<float>(3, animationState); globalWorkSize = new long[2]; globalWorkSize[0] = meshWidth; globalWorkSize[1] = meshHeight; cqCommandQueue.Execute(kernel, null, globalWorkSize, null, null); if (GL_Interop) { cqCommandQueue.Finish(); cqCommandQueue.ReleaseGLObjects(computeMemory, null); } else { GL.BindBuffer(BufferTarget.ArrayBuffer, vbo[0]); IntPtr pointer = GL.MapBuffer(BufferTarget.ArrayBuffer, BufferAccess.WriteOnly); cqCommandQueue.Read<float>(this.mVertices, true, 0, meshWidth * meshHeight * 4, pointer, null); GL.UnmapBuffer(BufferTarget.ArrayBuffer); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } } [STAThread] static void Main() { using (SimpleGLCloo game = new SimpleGLCloo()) { game.Run(30.0); } } } }

