Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Loading an Image cause game lag


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 09 November 2013 - 10:06 AM

There seems to be a laggy with my game. Character movement and attack animations and enemy movement animation starts to slow down in the game.

 

This issue started when I decided to load an image with a width of 3392 pixels and draw that image to the game. I am using this image as a background for my game.

 

My game screen width is 660.

 

The laggy issue stops when I decided to use a different image with a width of 768 pixels.

 

Why is this happening exactly? Memory issue? Image issue?

 

Do larger image use more memory than smaller image?

 

It is certainly an interesting issue.

 

 



Sponsor:

#2 Samith   Members   -  Reputation: 2323

Like
0Likes
Like

Posted 09 November 2013 - 12:16 PM

Does your 3392 pixel image have mip maps? If not, then trying to render that image into a screen that is only 660 pixels wide is going to cause a lot of trouble for the texture caches on your GPU since every texture fetch is going to be looking up texels very far away from the texels requried for neighboring pixels. Having mipmaps for your giant background texture will mitigate this problem as the GPU will use a lower resolution mip and texel fetches will be much more local. But this raises the obvious question: why are you using a 3392 pixel background when your screen is only 660 pixels? The memory requirements are much higher, and with mip mapping the higher mips will never be used, so it is just wasted memory.



#3 Samith   Members   -  Reputation: 2323

Like
0Likes
Like

Posted 09 November 2013 - 12:19 PM


Do larger image use more memory than smaller image?

 

Missed this part originally. The answer is yes, larger images use much more memory than smaller images. In an RGBA image (an image with a red, green, blue and alpha channel) with 8 bits per channel, each pixel is 4 bytes. If an image is 512x512, then you have 512 * 512 pixels, each of which is 4 bytes. This is 1048576 bytes (1mb). Now, imaging your image is 1024x1024 with 4 bytes per pixel. This image has 1024*1024 pixels, each of which is 4 bytes. That ends up being 4194304 bytes (4mb)! So, merely doubling the width and height of the image resulted in the memory requirements quadrupling. 



#4 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 09 November 2013 - 04:11 PM

Does your 3392 pixel image have mip maps? If not, then trying to render that image into a screen that is only 660 pixels wide is going to cause a lot of trouble for the texture caches on your GPU since every texture fetch is going to be looking up texels very far away from the texels requried for neighboring pixels. Having mipmaps for your giant background texture will mitigate this problem as the GPU will use a lower resolution mip and texel fetches will be much more local. But this raises the obvious question: why are you using a 3392 pixel background when your screen is only 660 pixels? The memory requirements are much higher, and with mip mapping the higher mips will never be used, so it is just wasted memory.

Ah I see. Larger image means larger memory usage. Thanks for the information!

 

The image is not using mip maps.

 

That is a pretty cool technique though now that I think about it...Calculating beforehand for optimal performance. I will research more about this and apply it to my game! Thanks!


Edited by warnexus, 09 November 2013 - 04:13 PM.


#5 Chris_J_H   Members   -  Reputation: 256

Like
0Likes
Like

Posted 11 November 2013 - 07:39 AM

Also - I understand that performance is generally better if your image/texture is sized on each dimension as 2^n (so here 512/1024/2048/4096).... and pre-processed mip-maps obviously... (all your mip-maps will be powers of 2 also)



#6 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 12 November 2013 - 01:30 PM

Also - I understand that performance is generally better if your image/texture is sized on each dimension as 2^n (so here 512/1024/2048/4096).... and pre-processed mip-maps obviously... (all your mip-maps will be powers of 2 also)


Why does performance works better when the image has those dimensions of 2 to the n?

#7 frob   Moderators   -  Reputation: 22770

Like
0Likes
Like

Posted 12 November 2013 - 02:19 PM


Why does performance works better when the image has those dimensions of 2 to the n?

It has to do with math and the way graphics texturing hardware works.

 

Having power of two (POT) lengths allows you to make many optimizations because computers are based on POT hardware. When you have non power of two (NPOT) textures you lose those optimizations. 

 

If you go back a few years all the major graphics engines required textures to have a POT length on each edge. So a texture could be 64x2048, or 256x256, or any other size as long as both edges were a POT length.  One of the many reasons for this is generating mip-maps; it is easy to generate an image that is half as big, and another image that is half as big, and another image that is half as big, as small as needed. Another is some of the nice mathematical properties involved, such that you can always double the dimensions and store all the lower resolutions in that space, and that if you use any convolution kernels on the image it is guaranteed to work at every detail level. There are filters built in to the major graphics APIs, and they are usually box filters, using a 4x4 box filter works wonderful on POT images, but produce edge effects if the image is not a proper multiple(some NPOT sizes can still be proper multiples of the filter, but it is no longer guaranteed in all NPOT cases). Texture coordinate calculations and texture wrapping modes (floor/ceiling) mathematics is much simpler and can be done with bit shifts rather than multiplication and division. Another is that you can guarantee memory alignment.  Etc., etc., etc.

 

For almost ten years now, newer graphics libraries require that implementations support NPOT textures.

 

Having NPOT has many indirect effects. Some of these include mipmap generation handling edges differently, texture compression may require encoding of blank space, wrapping and border functionality gets more complex, LOD filtering gets more complex, and there is a loss of compatibility with various algorithms that are optimized for POT sizes.

 

 

 

But getting back to your point, it is going to do with your specific algorithm and your specific implementation details in your code.  

 

You would need to share a lot more details. If you are allowing the video card to do everything and you have a small number of sprites, the video card can easily handle a few hundred sprites, even a 4000-pixel wide background sprite is easy for the card. If instead you are running everything on the CPU then you could easily be trashing your CPU cache with your graphics data, or consuming all your memory bandwidth by moving images back and forth into memory, or having memory access patterns that are cache unfriendly.  


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#8 Nana111   Members   -  Reputation: 106

Like
0Likes
Like

Posted 12 November 2013 - 08:36 PM

HI there

I am new here ,and i am not so fimiliar with gamedev.You said that the issue started when you decided to load an image with a width of 3392 pixels.I have encountered the same question.I just want to know that if there is any powerful program which supports to do that.Thanks for any suggestion



#9 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 12 November 2013 - 08:41 PM


You would need to share a lot more details. If you are allowing the video card to do everything and you have a small number of sprites, the video card can easily handle a few hundred sprites, even a 4000-pixel wide background sprite is easy for the card. If instead you are running everything on the CPU then you could easily be trashing your CPU cache with your graphics data, or consuming all your memory bandwidth by moving images back and forth into memory, or having memory access patterns that are cache unfriendly.
 

 

I am happy to share code. Here is the code of my 2D image in my 2D Java game.

I have comments that explains the code.

 

I am doing my painting and I am drawing this background image to Java double buffered graphics canvas

 

Note: The game is not full screen and the code does not use the GraphicsConfiguration Object in Java.

 

I am not sure if the game is using the video card or the CPU because I never use any code that

tells the game to take over either of the two.

package com.nicholaskong.SpaceShoot.characterSprites;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import com.nicholaskong.SpaceShoot.Game;
import com.nicholaskong.SpaceShoot.Main;
import com.nicholaskong.SpaceShoot.Sprite;
import com.nicholaskong.SpaceShoot.Vector2D;

public class MountainStage extends Sprite implements KeyListener{

    private ArrayList<Image> stage;
    private BufferedImage image;
    private double speed = 5;
    
    public MountainStage(Vector2D position,Spiderman spiderman)
    {
        this(position.getX(),position.getY());
    }
    public MountainStage(double x, double y) {
        
        position = new Vector2D(x,y);
        velocity = new Vector2D();
        
        stage = new ArrayList<>();
        try {
            image = ImageIO.read(new File("src/stage/stage.png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
            stage.add(image);
            // mountain stage can now listen for key events
            Game.getInstance().addKeyListener(this);
            
        
    }
    public void draw(Graphics g)
    {
        // draw the mountain stage to Java graphics canvas
        g.drawImage(stage.get(0), getX(), getY(),getWidth(),getHeight(),null);
    }
    
    public void update(long milliseconds)
    {
        // mountain stage gets updated with a time-based motion
        position = position.add(velocity.multiply(milliseconds / 16.667));

    }
    
    public int getWidth()
    {
        return image.getWidth();
    }
    
    public int getHeight()
    {
        return image.getHeight();
    }
    public int getX()
    {
        return (int) position.getX();
    }
    
    public int getY()
    {
        return (int) position.getY();
    }
    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        
        // while the character Spiderman is alive
        if(Spiderman.alive)
        {
            
            if(e.getKeyCode() == KeyEvent.VK_LEFT)
            {
                /*
                * use -5 instead of say 0 because
                * if I use 0, otherwise the image won;t
                * cover the default black screen of the canvas
                * when moving the mountain stage image
                */
                int lowXThreshold = -5;
                if(position.getX() > lowXThreshold)
                {
                    // lock the image at a particular point
                    position.setX(lowXThreshold);
                
                
                }
                
                // moves the mountain stage background
                position.setX(position.getX() + speed );
            
            }
            else if(e.getKeyCode() == KeyEvent.VK_RIGHT)
            {
               /* As the player moves farther right,
                * this makes the mountain stage background
                * image move farther left to achieve the
                * illusion that the player is actually
                * moving in this background that makes
                * up the world.
                *  
                * You will notice the top left corner that represents the
                * image coordinate x position will be at a negative x value
                * when the player moves farther right.
                *
                * subtract off the image width from the game screen's width
                * the difference of this calculation is the distance of the image
                * the player does not see in the game but is merely outside
                * the game window in view.
                *
                * NOTE: when the player sees the game, the player
                * only see a part of an actual image
                *
                * The user will see the rest as the player
                * moves father right in the game
                */
                
                /* the calculation logic to enable the player to scroll
                *  through the entire image.
                *  The logic scales well so it works with any image
                *  of any width size.
                */
                if(-position.getX() > image.getWidth() - Main.getWidth())
                {
                    
                    
                    // locks the image at a particular point
                    position.setX(-(image.getWidth() - Main.getWidth()));
                    
                    
                }
                
                // moves the mountain stage background
                position.setX(position.getX() - speed);
            }
        }
    }
    @Override
    public void keyReleased(KeyEvent arg0) {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void keyTyped(KeyEvent arg0) {
        // TODO Auto-generated method stub
        
    }
}
 

Edited by warnexus, 12 November 2013 - 10:43 PM.


#10 AticAtac   Members   -  Reputation: 334

Like
0Likes
Like

Posted 13 November 2013 - 03:37 AM

Why does performance works better when the image has those dimensions of 2 to the n?

 

 

I would also like to add:

Multiplying and dividng with texture-width values of power of 2 (which happens a lot) is a matter of of shifting bits to left / right, and shift-operations are very fast!

E.g. to multiply x with 256 you just need to shift bits in x 8 times. ( x = x<<8 )



#11 frob   Moderators   -  Reputation: 22770

Like
0Likes
Like

Posted 13 November 2013 - 11:36 AM

Yeah, that is going to be slow.

 

The code is using the CPU to copy all the images and not using any hardware acceleration.  You have a memory buffer with images in it writing to other memory buffers with images in them.

 

When you do all that processing everything must go through the CPU. That means the data must be loaded into the CPU cache replacing other things that are there -- like your program's data. The CPU needs to churn through all the rendering code, with the images sizes you are mentioning it sounds like it is processing about 30MB worth of data. Note that 3GHz@60fps = 50 million cycles per frame, so even in an ideal world you have burnt over half your compute cycles by manually copying images.  Then the updated image gets transferred out to the video card for display.  Contrast this with using the GPU for all of that copying, your program stays running in the CPU all the time and there are no significant image processing going on. The GPU is designed to handle a hundred million pixels per 60fps frame easily. 

 

 

Assuming you are on a PC and not an Android device (they are also written with Java) look up JOGL, the Java OpenGL interface.  Everything you need is under javax.media.opengl.*.

 

There are many JOGL tutorials on the web, they cover it pretty well.


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#12 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 13 November 2013 - 05:57 PM


Assuming you are on a PC and not an Android device (they are also written with Java) look up JOGL, the Java OpenGL interface. Everything you need is under javax.media.opengl.*.

 

So from what I am understanding, it uses the CPU by default for loading image and running the game unless I make it explicitly I want to use hardware acceleration from standard pure Java?

 

I see. Would I be at a disadvantage if I do not have any knowledge on OpenGL? Is that really true?

 

This source says "This allows computer graphics programmers to use the object-oriented tools for Java with hardware-accellerated 2D and 3D graphics while leveraging their existing knowledge of OpenGL."

 

Source: http://www.cs.umd.edu/~meesh/kmconroy/JOGLTutorial/


Edited by warnexus, 13 November 2013 - 05:59 PM.


#13 frob   Moderators   -  Reputation: 22770

Like
0Likes
Like

Posted 13 November 2013 - 07:01 PM

It might use hardware acceleration, or it might not,  The problem is that the decision often seems random and it can change mid-execution, and you have no way to detect or control the situation. Sometimes you get lucky, sometimes you get unlucky, and it is extremely difficult for the program to know until it is too late. 
 
Some of the java graphics parts will take advantage of 2D hardware acceleration. Unfortunately they are tricky to get correct and they don't document which operations prevent the acceleration. That's why the general advice is to use JOGL or another library that ensures hardware acceleration.
 
Sometimes it decides to use OpenGL or DirectDraw graphics operations to accelerate it, sometimes it uses a very slow CPU processing to do the exact same operation. Sometimes one operation is accelerated but another is not, perhaps on one machine drawImage() is not hardware accelerated but copyArea() is accelerated. Then on the next machine drawImage() may be accelerated but copyArea is not. You never know what you are going to get.
 
 
JOGL is a wrapper for OpenGL. Using JOGL or one of the other similar libraries give much better results because you are no longer at the undocumented whims of the system. If you rely on Java's BufferedImage you get some of the benefits like streaming support, but it comes at a cost that it may be high performance or low performance at the system's whim, sometimes changing performance characteristics mid-use when an operation like GetRGB() is used. Contrast this with an OpenGL texture where you know it is a texture, and it has all the performance characteristics that come with it.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#14 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 13 November 2013 - 08:10 PM

It might use hardware acceleration, or it might not,  The problem is that the decision often seems random and it can change mid-execution, and you have no way to detect or control the situation. Sometimes you get lucky, sometimes you get unlucky, and it is extremely difficult for the program to know until it is too late. 
 
Some of the java graphics parts will take advantage of 2D hardware acceleration. Unfortunately they are tricky to get correct and they don't document which operations prevent the acceleration. That's why the general advice is to use JOGL or another library that ensures hardware acceleration.
 
Sometimes it decides to use OpenGL or DirectDraw graphics operations to accelerate it, sometimes it uses a very slow CPU processing to do the exact same operation. Sometimes one operation is accelerated but another is not, perhaps on one machine drawImage() is not hardware accelerated but copyArea() is accelerated. Then on the next machine drawImage() may be accelerated but copyArea is not. You never know what you are going to get.
 
 
JOGL is a wrapper for OpenGL. Using JOGL or one of the other similar libraries give much better results because you are no longer at the undocumented whims of the system. If you rely on Java's BufferedImage you get some of the benefits like streaming support, but it comes at a cost that it may be high performance or low performance at the system's whim, sometimes changing performance characteristics mid-use when an operation like GetRGB() is used. Contrast this with an OpenGL texture where you know it is a texture, and it has all the performance characteristics that come with it.

Wow so even using JOGL can produce randomness in the methods?

 

I never knew I was at the hands of the system for using all parts of Java. I thought that only happens when I needed to use Java's paintComponent method.

 

So I am still at the mercy of the operating system even though I am doing my own painting. Things just got even more interesting.



#15 frob   Moderators   -  Reputation: 22770

Like
1Likes
Like

Posted 14 November 2013 - 12:42 AM

 

It might use hardware acceleration, or it might not,  The problem is that the decision often seems random and it can change mid-execution, and you have no way to detect or control the situation. Sometimes you get lucky, sometimes you get unlucky, and it is extremely difficult for the program to know until it is too late. 

Wow so even using JOGL can produce randomness in the methods?

 

I never knew I was at the hands of the system for using all parts of Java. I thought that only happens when I needed to use Java's paintComponent method.

 

So I am still at the mercy of the operating system even though I am doing my own painting. Things just got even more interesting.

 

 

Sorry for being unclear on that.

 

The "it" in the quotation was referring to Java draw calls. When you use Java's drawing system everything is handled by the Java implementation. They have a history of erratic performance. There is no way for the program to force the implementation to do anything. The erratic and sometimes painfully slow performance of the built in drawing libraries is one of many reasons that games will usually use a library that is written with performance in mind. As mentioned in the link, sometimes just resizing a window or moving it between monitors on a multi-monitor system can cause the built in functions like drawImage to dramatically change behavior.

 

When you use a library like JOGL, you are relying on the behavior of the library instead of the behavior of the Java implementation. The key difference is that JOGL and similar libraries have a focus of hardware acceleration. The built-in awt graphics package is designed for portability on any system, with or without acceleration.

 

Back when I learned Java (it was 1.1 back then) the graphics performance was so horrible you couldn't do anything useful with it. Yes it could run on many devices and platforms, but usually the results were so horrible you weren't going to use it for anything but web applets. Phone programmers used the MIDP LCDUI libraries for anything that required image processing.  Not that you could do much on a 66MHz phone with 240x400 or similar size screen. When you have less than 100,000 pixels there isn't much to draw. :-)

 

At any rate, games written in Java have nearly always relied on hardware-accelerated libraries rather than the general purpose drawing commands. 

 

 

As for being at the mercy of the operating system, that is always true. The operating system, the drivers, and other running programs all can make a difference.


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#16 warnexus   Prime Members   -  Reputation: 1504

Like
0Likes
Like

Posted 14 November 2013 - 08:53 AM

It might use hardware acceleration, or it might not,  The problem is that the decision often seems random and it can change mid-execution, and you have no way to detect or control the situation. Sometimes you get lucky, sometimes you get unlucky, and it is extremely difficult for the program to know until it is too late.

Wow so even using JOGL can produce randomness in the methods?
 
I never knew I was at the hands of the system for using all parts of Java. I thought that only happens when I needed to use Java's paintComponent method.
 
So I am still at the mercy of the operating system even though I am doing my own painting. Things just got even more interesting.
 
Sorry for being unclear on that.
 
The "it" in the quotation was referring to Java draw calls. When you use Java's drawing system everything is handled by the Java implementation. They have a history of erratic performance. There is no way for the program to force the implementation to do anything. The erratic and sometimes painfully slow performance of the built in drawing libraries is one of many reasons that games will usually use a library that is written with performance in mind. As mentioned in the link, sometimes just resizing a window or moving it between monitors on a multi-monitor system can cause the built in functions like drawImage to dramatically change behavior.
 
When you use a library like JOGL, you are relying on the behavior of the library instead of the behavior of the Java implementation. The key difference is that JOGL and similar libraries have a focus of hardware acceleration. The built-in awt graphics package is designed for portability on any system, with or without acceleration.
 
Back when I learned Java (it was 1.1 back then) the graphics performance was so horrible you couldn't do anything useful with it. Yes it could run on many devices and platforms, but usually the results were so horrible you weren't going to use it for anything but web applets. Phone programmers used the MIDP LCDUI libraries for anything that required image processing.  Not that you could do much on a 66MHz phone with 240x400 or similar size screen. When you have less than 100,000 pixels there isn't much to draw. :-)
 
At any rate, games written in Java have nearly always relied on hardware-accelerated libraries rather than the general purpose drawing commands. 
 
 
As for being at the mercy of the operating system, that is always true. The operating system, the drivers, and other running programs all can make a difference.

Wow thanks for information! JOGL would be a great learning experience too!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS