Results 1 to 6 of 6

Thread: Drawing pixels

  1. #1
    Peasant
    Join Date
    May 2008
    Location
    Norway
    Posts
    5

    Question Drawing pixels

    Hi. I'm using ClanLib 0.8 on a linux machine, and I'm wondering;
    What is the fastest way to draw lots of pixels to a surface?
    Do I:
    - draw_pixel on a pixelbuffer, then use surface.set_pixelbuffer
    - get a canvas for the surface, get the graphic context by canvas.get_gc(), call graphicContext->draw_pixel (This is what I'm currently doing, but it seems slow.)
    - get a canvas for the surface, draw on a pixelbuffer, use canvas.set_pixelbuffer
    - something else?

  2. #2
    Peasant
    Join Date
    May 2008
    Location
    Norway
    Posts
    5

    Default

    Looks like I'll be having a monologue here...

    I tested my three suggestions, and they all ran at the same speed.
    (~4.7 fps, drawing 512x512 pixels)
    Commenting out just the line with draw_pixel gives 23 fps.
    Commenting out most of the non-graphics code gives 5.5 fps.
    For fun I tried drawing 512x512 one-pixel sprites, resulting in 3.6 fps.

    Is there a way to draw several pixels at once? (I imagine that would be faster, as there is probably some overhead costs for each draw_pixel)
    If there isn't, would you be interested if I made it?

    Is there any point in writing the pixel array to memory manually and constructing a pixelbuffer using a pointer to the data? I'd rather not do that, though...

  3. #3
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    I depends how many pixels you are going to draw. For my game, i write 320*256 pixels to a pixel buffer, which is nice and fast

    See http://methane.sourceforge.net
    Code:
    CL_PixelBuffer pixel_screen(SCR_WIDTH, SCR_HEIGHT, SCR_WIDTH*4, CL_PixelFormat::rgba8888);
    
    CL_Surface game_screen(pixel_screen);
    CL_Canvas game_canvas(game_screen);
    
    pixel_screen.lock();
    Game.MainLoop(pixel_screen.get_data()
    pixel_screen.unlock();
    game_screen.set_pixeldata(pixel_screen);
    
    CL_Rect rect(0,0,(int)CL_Display::get_width(), (int)CL_Display::get_height());
    game_screen.draw(rect);

  4. #4
    Peasant
    Join Date
    May 2008
    Location
    Norway
    Posts
    5

    Default

    Quote Originally Posted by rombust View Post
    I depends how many pixels you are going to draw. For my game, i write 320*256 pixels to a pixel buffer, which is nice and fast

    See http://methane.sourceforge.net
    I took a look at the source code of your game, and if I read it correctly this is what you do (roughly) :
    - lock the pixelbuffer and get a pointer to the data from pixel_screen.get_data()
    - draw stuff directly to memory using your own routines.
    - unlock the buffer, update stuff and show it on screen.

    It also looks like you are using 8 bit pixels, which means there is only 1/4 as much data to move around. (I'm using 32bit pixels)

    Whereas I'm using ClanLibs own routines, calling draw_pixel() once per pixel I draw.
    Your way is obviously more effective, but I'd rather not have to manipulate memory directly myself.

    When I get some time, I think I will try to add some functionality to CL_PixelBuffer to let me draw many pixels at once. If it works out I'll post the results here.
    If I don't find a good way to do it, I guess I'll do what you do.

  5. #5
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    I am using 32 bit pixels, see CL_PixelFormat::rgba8888 (8 + 8 +8 + 8 = 32). Internally the game uses only 32 colours iirc.

    Have a look at ClanLib 0.9 - Maybe it will be better to use opengl, and write your own pixel shader (using opengl shader language - via CL_ProgramObject)?

  6. #6
    Peasant
    Join Date
    May 2008
    Location
    Norway
    Posts
    5

    Default

    In case anyone's interested, I made this;
    Code:
    void CL_PixelBuffer::draw_pixels(int *x, int *y, const CL_Color *color, int pixelcount)
    {
    	lock();
    
    	cl_uint8* buf = static_cast<cl_uint8*>(impl->get_data());
    	CL_PixelFormat format = get_format();
    
    	if (format.get_type() == pixelformat_index)
    	{
    		throw CL_Error("Direct settings of CL_Colors pixels in paletted mode is not supported.");
    	}
    	else if (format.get_type() == pixelformat_rgba)
    	{
    		int i;
    		int depth = format.get_depth ();
    		int bytes_per_pixel = (depth + 7)/8;
    		cl_uint8 *pos;
    
    		int red_shift = format.get_mask_shift(format.get_red_mask()),
    			green_shift = format.get_mask_shift(format.get_green_mask()),
    			blue_shift = format.get_mask_shift(format.get_blue_mask()),
    			alpha_shift = format.get_mask_shift(format.get_alpha_mask());
    
    		switch (bytes_per_pixel)
    		{
    		case 4:
    		case 3:
    			{
    				for(i=0;i<pixelcount;i++) 
    				{
    					pos = &buf[y[i] * impl->pitch + x[i] * bytes_per_pixel]
    					cl_uint32 c = (color[i].get_red() << red_shift) | (color[i].get_green() << green_shift) | (color[i].get_blue() << blue_shift) | (color[i].get_alpha() << alpha_shift);
    					memcpy (pos, &c, bytes_per_pixel);
    				}
    			}
    			break;
    
    		case 2:
    			{
    				for(i=0;i<pixelcount;i++) 
    				{
    					pos = &buf[y[i] * impl->pitch + x[i] * bytes_per_pixel]
    					cl_uint16 c = (color[i].get_red() << red_shift) | (color[i].get_green() << green_shift) | (color[i].get_blue() << blue_shift) | (color[i].get_alpha() << alpha_shift);
    					memcpy (pos, &c, bytes_per_pixel);
    				}
    			}
    			break;
    
    		case 1:
    			{
    				for(i=0;i<pixelcount;i++) 
    				{
    					pos = &buf[y[i] * impl->pitch + x[i] * bytes_per_pixel]
    					cl_uint8 c = (color[i].get_red() << red_shift) | (color[i].get_green() << green_shift) | (color[i].get_blue() << blue_shift) | (color[i].get_alpha() << alpha_shift);
    					*pos = c;
    				}
    			}
    			break;
    
    		default:
    			throw CL_Error("Unsuported pixel format depth for draw_pixels.");
    		}
    
    	}
    	unlock();
    }
    which draws an array of pixels of arbitrary positions and colors. ( Note: There was some amount of CRTL-C from CL_PixelBuffer::draw_pixel )
    It does expect pixelcount to be set to the correct value and will behave strangely if it is too large.
    Using this roughly doubles my fps.

    Getting a pointer to the memory used by the pixelbuffer and writing stuff directly to memory is slightly(~20-30%) faster than this, but needs to be redone for each particular use.

    I haven't looked into using a pixel shader. If someone does, and compares it to draw_pixel, please make a post about it.

Similar Threads

  1. Drawing primitives in ClanLib 0.8
    By LonelyStar in forum Official ClanLib SDK Forums
    Replies: 1
    Last Post: 05-12-2008, 09:36 PM
  2. problem of drawing an image
    By newhand in forum Official ClanLib SDK Forums
    Replies: 4
    Last Post: 04-17-2008, 02:33 AM
  3. Redirect GUI drawing?
    By madmark in forum Official ClanLib SDK Forums
    Replies: 0
    Last Post: 10-06-2007, 04:25 AM
  4. Resolution Independent Drawing
    By glorified_ameba in forum Official ClanLib SDK Forums
    Replies: 4
    Last Post: 03-28-2007, 05:33 PM
  5. Drawing/displaying problem
    By shade37337 in forum Official ClanLib SDK Forums
    Replies: 4
    Last Post: 10-21-2006, 05:11 PM

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •