Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (121)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  What might make Graphics2D.drawImage() slow?  (Read 1764 times)
0 Members and 1 Guest are viewing this topic.
Offline Jacob_

Junior Duke


Projects: 3



« Posted 2011-02-25 19:43:15 »

I'm developing a physics sandbox game. I can easily fill the whole screen with rotated, scaled, textured boxes without noticing any FPS drops or excessive CPU usage, and drawing the character without a rotate transformation is fast.

However, if I rotate the character image, or scale it, CPU usage goes through the roof and there is a small but noticable FPS decrease. Using a profiler, I determined that drawImage() was the problem. As far as I can tell the character and texture images are being drawn the same way... It's really confounding.

From the character:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
private VolatileImage character = Util.getGraphicsConfiguration().createCompatibleVolatileImage(200, 200, Transparency.BITMASK); //I tried using Transparency.TRANSLUCENT
[...]
    public void draw(Graphics g) throws BuildismException
    {
        updateImage(); //This line draws the appropriate sections of the player's skin in the right locations. If I remove it, the character is a white box, but drawing it is still slow!
        Vec2D pos = getPart().getPosition().worldToScreen(Main.getView());
        int w = (int) (200*(Main.getView().scaleFactor/8));
        int h = (int) (200*(Main.getView().scaleFactor/8));
        int imgX = (int) pos.getX() - w/2;
        int imgY = (int) pos.getY() - h/2;
        AffineTransform orig = ((Graphics2D)g).getTransform();
        AffineTransform rotate = AffineTransform.getRotateInstance(-Math.toRadians(getPart().getRotation()), pos.getX(), pos.getY());
        ((Graphics2D)g).setTransform(rotate);
        g.drawImage(character, imgX, imgY, w, h, null); //I tried using a scale transform here, didn't help
        ((Graphics2D)g).setTransform(orig);
    }


For textured boxes (yes, I know this code is messy and unoptimized... but it works faster than the much simpler code for drawing a character!)
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
    public void setTexture(BufferedImage t)
    {
        if(t != null)
        {
            VolatileImage i = Util.getGraphicsConfiguration().createCompatibleVolatileImage(t.getWidth(), t.getHeight(), Transparency.TRANSLUCENT);
            Graphics2D g2 = (Graphics2D) i.getGraphics();
            Composite old = g2.getComposite();
            g2.setColor(transparent);
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT));
            g2.fillRect(0, 0, t.getWidth(), t.getHeight());
            g2.setComposite(old);
            g2.drawImage(t, 0, 0, null);
            texture = i;
        }
        else
            texture = null;
    }

[...]

            Graphics2D g2 = (Graphics2D) g;
            Vec2D worldPos = new Vec2D(body.getPosition());
            Vec2D imgPos = worldPos.add(new Vec2D(-getVec2DProp("Size").getX(), getVec2DProp("Size").getY()).mul(0.5)).worldToScreen(Main.getView());
            Vec2D rotateCenter = worldPos.worldToScreen(Main.getView());
            AffineTransform original = g2.getTransform();
            AffineTransform scale = AffineTransform.getScaleInstance(scaleDimensionForScreen(texture.getWidth(), getVec2DProp("Size").getX()), scaleDimensionForScreen(texture.getHeight(), getVec2DProp("Size").getY()));
            AffineTransform rotate = AffineTransform.getRotateInstance(-body.getAngle(), rotateCenter.getX(), rotateCenter.getY());
            g2.setTransform(rotate);
            g2.transform(scale);
            g2.drawImage(texture, (int) (imgPos.getX() / ((Main.getView().scaleFactor * getVec2DProp("Size").getX())/texture.getWidth())), (int) (imgPos.getY() / ((Main.getView().scaleFactor * getVec2DProp("Size").getY())/texture.getHeight())), null); //ew
            g2.setTransform(original);


Does anyone see a problem?
Offline Jacob_

Junior Duke


Projects: 3



« Reply #1 - Posted 2011-03-20 00:19:45 »

Finally solved this yesterday! For some reason drawing a VolatileImage with bitmask transparency mode is not hardware accelerated, while drawing one with translucent transparency mode is.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2011-03-20 00:57:07 »

That was actually the first thing on my mind, when I read your original post, but I saw:
1  
createCompatibleVolatileImage(200, 200, Transparency.BITMASK); //I tried using Transparency.TRANSLUCENT

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline laxika

Junior Newbie





« Reply #3 - Posted 2011-03-31 13:31:21 »

Hy guys!

I have this problem as well. :S

I try to draw a part of an image using this code:

1  
g.drawImage(Main.getImageCache().getImage("tileset_" + Main.getMapManager().getMapData().getTileset()), xPos, yPos, xPos + 64, yPos + 32, tileXOffset(firstTileImg), tileYOffset(firstTileImg), tileXOffset(firstTileImg) + 64, tileYOffset(firstTileImg) + 32, null);


The image is a VolatileImage. It draws the image good, it's too slow, using 50% CPU all the time while drawing 60-70 images.

EDIT: Sometimes it's using 0-5% CPU, sometimes using 50%. I profiled it when it using 50%, and I figured that the drawn method makes it that bad.

I create the VolatileImage as a TRANSCULENT image.

Anyone can help pls?

(I know I'm begging for help in my first post, but I'll be online. I love this site.)

EDIT2:

Guys I tired to profile again, here is the result:

Offline aazimon
« Reply #4 - Posted 2011-04-05 14:02:16 »

I'm not an expert, but I would guess it is not hardware accelerated. Can you verify it is hardware excelerated? I saw something in the Java2d section here, about logging for the graphics, to determine if it is hardware accelerated.
Offline laxika

Junior Newbie





« Reply #5 - Posted 2011-04-05 15:34:29 »

Thanks for your answer.

I found that if the BufferStrategy's content lost before the first draw, this will happen. I did this to fix it:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
            //If at the first run the mainFrm.getBufferStrategy().contentsLost()
            //returns true then the CPU usage of the program will jump up to 50%
            //this doesn't happens on every PC and it must be a JRE Bug.
            //We just do a lame fix here, but I don't have any other idea.
            if (mainFrm.getBufferStrategy().contentsLost() && isFirstBufferCheck) {
                mainFrm.getBufferStrategy().dispose();
                mainFrm.createBufferStrategy(2);
            }

            if (isFirstBufferCheck) {
                isFirstBufferCheck = false;
            }


This really sucks, but I can't do any better right now.
Offline ra4king

JGO Kernel


Medals: 352
Projects: 3
Exp: 5 years


I'm the King!


« Reply #6 - Posted 2011-04-05 18:36:29 »

As stated in the API, there is a certain way of using BufferStrategy in your game loop:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
mainFrm.createBufferStrategy(2);
BufferStrategy strategy = mainFrm.getBufferStrategy();

while(!done) {
    //GAME CODE
   
    do{
        do{
            Graphics g = strategy.getDrawGraphics();
            //RENDERING
            g.dispose();
        }while(strategy.contentsRestored());
       
        strategy.show();
    }while(strategy.contentsLost());
}

Offline laxika

Junior Newbie





« Reply #7 - Posted 2011-04-05 19:48:05 »

Well thanks a lot, this is usefull.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

theagentd (19 views)
2014-10-25 15:46:29

Longarmx (52 views)
2014-10-17 03:59:02

Norakomi (46 views)
2014-10-16 15:22:06

Norakomi (34 views)
2014-10-16 15:20:20

lcass (39 views)
2014-10-15 16:18:58

TehJavaDev (68 views)
2014-10-14 00:39:48

TehJavaDev (68 views)
2014-10-14 00:35:47

TehJavaDev (60 views)
2014-10-14 00:32:37

BurntPizza (74 views)
2014-10-11 23:24:42

BurntPizza (45 views)
2014-10-11 23:10:45
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!