Stupid_2D's picture

GL.ReadPixels eats CPU

Hello everyone,

im currently implementing picking into my little game i am working on.
It works, but it eats all my CPU.

	struct Byte4
        {
            public byte R, G, B, A;
 
            public Byte4(byte[] input)
            {
                R = input[0];
                G = input[1];
                B = input[2];
                A = input[3];
            }
        }
		public static Byte4 Pixel;
...
                public static void RendeFrame(FrameEventArgs e)
		{
			GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
			GL.MatrixMode(MatrixMode.Projection);
			GL.LoadIdentity();
 
			GL.Disable(EnableCap.Texture2D);
				VertexBuffer.Selection();
				GL.ReadPixels(Mouse_X, Context_H - Mouse_Y,1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, ref Pixel);
			GL.Enable(EnableCap.Texture2D);
 
			GL.Clear(ClearBufferMask.ColorBufferBit| ClearBufferMask.DepthBufferBit);
 
			ParticleSystem.Draw();
			VertexBuffer.Draw();
		}

The CPU usage drops dramatically when i comment the ReadPixel or increase the Area from 1x1 to 2x2 Pixel.
VertexBuffer.Selection() draws my VBOs without textures but with unique colors instead (Currently everysthing is (255 255 255 255) for testing purposes.

You may think SwapBuffers is missing, its implemented in the GameWindow.cs.

		public static void Selection()
		{
			foreach(VBO _vbo in vbos)
			{
				if (_vbo.VertexBufferID != 0)
				{
					GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo.VertexBufferID);
					GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, IntPtr.Zero);
					GL.EnableClientState(ArrayCap.VertexArray);
				} 
				GL.BindBuffer(BufferTarget.ArrayBuffer, WhiteBufferID);
				GL.ColorPointer(4, ColorPointerType.Float, Vector4.SizeInBytes, IntPtr.Zero);
				GL.EnableClientState(ArrayCap.ColorArray);	
				if (_vbo.IndicesBufferID != 0)
				{
					GL.BindBuffer(BufferTarget.ElementArrayBuffer, _vbo.IndicesBufferID);
					GL.DrawElements(_vbo.Mode, _vbo.IndicesData.Length,
				                DrawElementsType.UnsignedInt, IntPtr.Zero);
				}
			}
 
		}

So can you please tell me what I am doing wrong?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Stupid_2D's picture

I figured out that its completely random. Sometimes it runs great, sometimes with 100% Cpu. -.-

the Fiddler's picture

Video card, drivers, OS?

GL.ReadPixels() is always slow but I don't think it should consume 100% CPU randomly.

Stupid_2D's picture

Hey thank you for your reply.
My specs are:

Win7 Professional 64 bit.
Nvidia Geforce 8700M (latest driver)
Intel Core 2Duo T9300 2.5 GHZ

At the moment I am using a workarround by only picking every 5 frames but I am no fan of workarrounds -.-

I tested disabling almost every systemrpocess there is (Virusscan and so on) nothing helped so far.

Probably its my bad coding.

Ill try what happens when I try picking without VBOs but simple Quads.

Still no change using following code:

What I noticed is that after roughly 2 minutes the cpu usage drops down to 5-10% and stays there. Also the Ram keeps growing till that point, starting at 13Mb going up to about 32 then dropping to a steady 24

 
                        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
			GL.MatrixMode(MatrixMode.Projection);
			GL.LoadIdentity();
                                // "Picking Color"
				GL.Color3(1,0.5,1);
				GL.Begin(BeginMode.Quads);
				GL.Vertex2(0,0);
				GL.Vertex2(5,0);
				GL.Vertex2(5,5);
				GL.Vertex2(0,5);				
				GL.End();	
 
				GL.ReadPixels(Mouse_X, Mouse_Y,1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, ref Pixel);
 
				GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
				GL.Color3(1,1,1);
 
				GL.Begin(BeginMode.Quads);
				GL.Vertex2(0,0);
				GL.Vertex2(5,0);
				GL.Vertex2(5,5);
				GL.Vertex2(0,5);				
				GL.End();
 
                                 this.SwapBuffers();
the Fiddler's picture

Hm, this doesn't really ring a bell. Try moving the GL.ReadPixels call after SwapBuffers to see if it helps. (This should be faster, especially when vsync is enabled).

Additionally, check GL.GetErrors() to see if it returns anything. (CPU usage can often skyrocket once an error occurs).

Using something like gDEBugger, glslDevil or BuGLe might also give a clue.

If nothing helps, try posting at http://opengl.org. Someone might have encountered this before (and driver developers tend to read the posts and comment on driver bugs, which is pretty useful).

Stupid_2D's picture

Thank you for your reply again.

Well nothing worked so far. GL.Error returns no error

changing the position of GL.ReadPixels() doesnt help either.

How do i use
gDEBugger, glslDevil or BuGLe??

tksuoran's picture

Does it do anything different if you add Finish() right before ReadPixels()? What if you only have Finish() but no ReadPixels()?

Stupid_2D's picture

Thank you for your reply

Commenting out ReadPixels alone lets my CPU drop to almost nothing.
Finish doesnt seem to make a change, tried it at different positions (same with flush) :(

The OpenTK ExampleBrowser Picking example gives me full CPU Load too.

Stupid_2D's picture

I dont know why i was playing arround with it, but this fixed the High CPU usage:

A second SwapBuffers Call.

// ======================= FIX ======================
Context.SwapBuffers(); 
// ======================= FIX ======================
 
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
GL.MatrixMode(MatrixMode.Modelview);		
if(SelectionStep == 0)
{					
	GL.Disable(EnableCap.Blend);
	GL.Disable(EnableCap.Texture2D);				
	VBOHelper.RenderSelection();				
	GL.ReadPixels<Byte4>(Mouse_X,Mouse_Y,1, 1, PixelFormat.Rgba, PixelType.UnsignedByte,ref Pixel);				
	VBOHelper.Select(Pixel,clickstate);			
	clickstate = false;				
	SelectionStep = SelectionSkip;				
} else SelectionStep--;
 
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend);		
VBOHelper.RenderScene();
 
Context.SwapBuffers();