GameEngine2D

Reply

Member

Member
Clumfest
Posts: 3
Registered: ‎19-04-2012
Message 1 of 9 (535 Views)
Accepted Solution

SpriteUV slowdown

Just wondering if I'm being far to ambitious but I am trying to draw a layer of moving tiles (1 pixel per frame) using a spriteList. Its only an experiment to see how much I can push the Vita. Unfortunately I'm only getting 18 frames per second on the Vita (60 in the simulator) .the tilesheet I'm using is a 512*512 24bit png with 32*32 tiles on it (so the tile size is 16*16 pixels).  
 
Am I doing some thing horribly wrong or am I just being insane thinking that the Vita should be well able to handle this?  
 
I've put the code below, which is just modified from the GameEngine2D HelloSprite.

 

<code>
using System.Collections;
using System.Collections.Generic;
using System;
using System.Diagnostics;

using System.Text;


using Sce.Pss.Core;
using Sce.Pss.Core.Graphics;
using Sce.Pss.Core.Input;
using Sce.Pss.Core.Imaging;
using Sce.Pss.Core.Environment;

using Sce.Pss.HighLevel.GameEngine2D;
using Sce.Pss.HighLevel.GameEngine2D.Base;

 

static class MyFirstTileSheet
{

static int TILE_SIZE = 16;
static int TILES_PER_SHEET = 32;

static int NUM_TILESX = 55;
static int NUM_TILESY = 33;

static void Main( string[] args )
{

Sce.Pss.Core.Graphics.GraphicsContext context = new Sce.Pss.Core.Graphics.GraphicsContext();

uint sprites_capacity = 500*4;

uint draw_helpers_capacity = 400*4;

Director.Initialize( sprites_capacity, draw_helpers_capacity, context );

Director.Instance.GL.Context.SetClearColor( Colors.Yellow );

// set debug flags that display rulers to debug coordinates
//Director.Instance.DebugFlags |= DebugFlags.DrawGrid;
// set the camera navigation debug flag (press left alt + mouse to navigate in 2d space)
Director.Instance.DebugFlags |= DebugFlags.Navigate;

var scene = new Scene();

scene.Camera.SetViewFromViewport();

var texture_info2 = new TextureInfo( new Texture2D("/Application/ASSETS/TILESHEETS/tileb.png", false ) );

var texture_info = new TextureInfo( new Texture2D("/Application/ASSETS/TILESHEETS/tilebd.png", false ) );
var spriteList = new SpriteList(texture_info2);
var spriteList2 = new SpriteList(texture_info);

for(int i = 0; i<NUM_TILESX;i++)
{
for(int ii = 0; ii<NUM_TILESY;ii++)
{
SpriteUV sprite = new SpriteUV();
sprite.Quad.S = texture_info.TextureSizef/TILES_PER_SHEET; 

sprite.UV.T = new Vector2((1.0f/TILES_PER_SHEET) * (float)(i%TILES_PER_SHEET), (1.0f/TILES_PER_SHEET) * (float)(ii%TILES_PER_SHEET));
sprite.UV.S = new Vector2((TILE_SIZE/texture_info.TextureSizef.X),(TILE_SIZE/texture_info.TextureSizef.Y));//0.0625f,0.0625f);

Vector2 xy = new Vector2( i*TILE_SIZE, ii*TILE_SIZE ); 

sprite.Position = scene.Camera.CalcBounds().Min + xy;
Vector2 v = scene.Camera.CalcBounds().Max;
spriteList.AddChild(sprite);
}
}



SpriteUV sprite2 = new SpriteUV();

sprite2.Quad.S = texture_info.TextureSizef/TILES_PER_SHEET;


sprite2.UV.T = new Vector2((1.0f/TILES_PER_SHEET) * (float)(1%TILES_PER_SHEET), (1.0f/TILES_PER_SHEET) * (float)(1%TILES_PER_SHEET));
sprite2.UV.S = new Vector2((TILE_SIZE/texture_info.TextureSizef.X),(TILE_SIZE/texture_info.TextureSizef.Y));//0.0625f,0.0625f);


Vector2 xyz = new Vector2( 1*16, 1*16 );


scene.AddChild( spriteList );
scene.AddChild( spriteList2 );
spriteList2.AddChild(sprite2);


Director.Instance.GL.SetBlendMode( BlendMode.Normal );
Director.Instance.RunWithScene( scene, true );

FPSCounter fps = new FPSCounter();

int frameCounter = 0;
while ( !Input2.GamePad0.Cross.Press )
{


int count = 0;
int XX = 0;
int YY = 0;
spriteList.Cleanup();
foreach (var SpriteUV in spriteList.Children) {
//Console.WriteLine(count);
XX = 0;
if(SpriteUV.Position.X+1>854){
XX = (((int)SpriteUV.Position.X - (NUM_TILESX * TILE_SIZE))+1);
}else{
XX = ((int)SpriteUV.Position.X + 1);
}

YY = 0;
if(SpriteUV.Position.Y+1>480){
YY = (((int)SpriteUV.Position.Y - (NUM_TILESY * TILE_SIZE))+1);
}else{
YY = ((int)SpriteUV.Position.Y + 1);
}


Vector2 xy = new Vector2(XX, YY);
SpriteUV.Position = xy;
count++;
}
count = 0;

Sce.Pss.Core.Environment.SystemEvents.CheckEvents();

#if EXTERNAL_INPUT

// it is not needed but you can set external input data if you want

List<TouchData> touch_data_list = Touch.GetData(0);
Input2.Touch.SetData( 0, touch_data_list );

GamePadData pad_data = GamePad.GetData(0);
Input2.GamePad.SetData( 0, pad_data );

#endif // #if EXTERNAL_INPUT

Director.Instance.Update();
Director.Instance.Render();

Director.Instance.GL.Context.SwapBuffers();
Director.Instance.PostSwap(); 

fps.printFPS(frameCounter); //To the console

}

Director.Terminate();

System.Console.WriteLine( "Bye!" );
}

static string getDebug(){
return "Wakka wakka";
}

}

 </code>

 

Please use plain text.

Re: SpriteUV slowdown

Hi Clumfest,

 

There's not too much that I have to say regarding the performance, however a contributing factor is the 1815 sprites. Although you have these organised in a SpriteList which is great, there is obviously still an overhead to having a such large number of sprites, but this approach is still better compared to having individual SpriteUVs

 

I've also noticed that you are calling spriteList.CleanUp() each frame. This will not only stop the SpriteList's actions and schedules, but it will traverse all of its children nodes and perform the same action. When you get past this point, you've now stopped the actions and schedules on all 1816 node objects. Following this, you are then traversing all 1815 node objects again, adjusting their position. So to summarise, in each frame you are looking at the nodes, twice as much as you probably should. 

 

It's not too clear why you are calling CleanUp(), as you have no actions or schedules running, so this seems a wasted operation. If you really need to call it, then in your foreach loop, you can call...

 

SpriteUV.UnscheduleAll();
SpriteUV.StopAllActions();

 

Hope this helps.

James

PlayStation®Mobile Dev Team
Please use plain text.

Level 1

Level 1
asdfADRIAN
Posts: 36
Registered: ‎15-05-2012
Message 3 of 9 (496 Views)

Re: SpriteUV slowdown

Whats the difference between SpriteUV and Sprite files? Any pros and cons? 

Come join The Freenode IRC at Channel #pss-dev!

I am merely a graphics designer who wants to program, go figure.

Please use plain text.

Member

Member
Clumfest
Posts: 3
Registered: ‎19-04-2012
Message 4 of 9 (468 Views)

Re: SpriteUV slowdown

Hi James,
Thanks for the input. I removed the CleanUp() (dont know why i was even calling it) and got a few extra frames per second. I've taken increased the tile size to 32x32 as well as switching to RawSpriteTile and have seen a massive improvement. 60 fps on the vita while displaying 3 overlaping sprite lists (each are 31X18 tiles each with a diffrent 512x512 .png for each). This should be more than enough for any game we will make. 

The code is below for anyone that is interested, but I must give cred to YstadYakuza as I used his example from another post to guide me in my code.

//AppMain.cs
using System.Collections;
using System.Collections.Generic;
using System;
using System.Diagnostics;

using System.Text;


using Sce.Pss.Core;
using Sce.Pss.Core.Graphics;
using Sce.Pss.Core.Input;
using Sce.Pss.Core.Imaging;
using Sce.Pss.Core.Environment;

using Sce.Pss.HighLevel.GameEngine2D;
using Sce.Pss.HighLevel.GameEngine2D.Base;



static class MyFirstTileSheet
{

	static int TILE_SIZE = 32;
	static int TILES_PER_SHEET = 16;
	
	static int NUM_TILESX = 31;
	static int NUM_TILESY = 18;
	
	static void Main( string[] args )
	{
		
		Sce.Pss.Core.Graphics.GraphicsContext context = new Sce.Pss.Core.Graphics.GraphicsContext();

		uint sprites_capacity = 500;

		uint draw_helpers_capacity = 400;

		Director.Initialize( sprites_capacity, draw_helpers_capacity, context );

		Director.Instance.GL.Context.SetClearColor( Colors.Yellow );

		// set debug flags that display rulers to debug coordinates
		//Director.Instance.DebugFlags |= DebugFlags.DrawGrid;
		// set the camera navigation debug flag (press left alt + mouse to navigate in 2d space)
		Director.Instance.DebugFlags |= DebugFlags.Navigate; 

		var scene = new Scene();

		scene.Camera.SetViewFromViewport();
		
		var width = Director.Instance.GL.Context.GetViewport().Width;
		var height = Director.Instance.GL.Context.GetViewport().Height;
		System.Console.WriteLine( width );
		Console.WriteLine(" ");
		System.Console.WriteLine( height );
		Console.WriteLine(" ");

		var texture_info = new TextureInfo( new Texture2D("/Application/ASSETS/TILESHEETS/tileb.png", false ),new Vector2i(TILES_PER_SHEET,TILES_PER_SHEET) );
		var texture_info2 = new TextureInfo( new Texture2D("/Application/ASSETS/TILESHEETS/tilebd.png", false ),new Vector2i(TILES_PER_SHEET,TILES_PER_SHEET) );
		var texture_info3 = new TextureInfo( new Texture2D("/Application/ASSETS/TILESHEETS/tilebe.png", false ),new Vector2i(TILES_PER_SHEET,TILES_PER_SHEET) );

		
		TileList spriteList = new TileList(texture_info, NUM_TILESX*NUM_TILESX );

		
	
		for(int i = 0; i<NUM_TILESX;i++)
		{
			for(int ii = 0; ii<NUM_TILESY;ii++)
			{
				TRS trs = new TRS(new Bounds2(new Vector2(i*TILE_SIZE,ii*TILE_SIZE),new Vector2((i*TILE_SIZE)+TILE_SIZE,(ii*TILE_SIZE)+TILE_SIZE)));
				RawSpriteTile sprite = new RawSpriteTile(trs,new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET),false, false);
				
				sprite.Quad.S = new Vector2 (TILE_SIZE,TILE_SIZE);
				sprite.TileIndex2D = new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET);
				spriteList.AddChild(sprite);
			}
		}
		
		TileList spriteList2 = new TileList(texture_info2, NUM_TILESX*NUM_TILESX );

		
	
		for(int i = 0; i<NUM_TILESX;i++)
		{
			for(int ii = 0; ii<NUM_TILESY;ii++)
			{
				TRS trs = new TRS(new Bounds2(new Vector2(i*TILE_SIZE,ii*TILE_SIZE),new Vector2((i*TILE_SIZE)+TILE_SIZE,(ii*TILE_SIZE)+TILE_SIZE)));
				RawSpriteTile sprite = new RawSpriteTile(trs,new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET),false, false);
				
				sprite.Quad.S = new Vector2 (TILE_SIZE,TILE_SIZE);//(int)(texture_info.TextureSizef/TILES_PER_SHEET),(int)(texture_info.TextureSizef/TILES_PER_SHEET)); 
				sprite.TileIndex2D = new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET);
				spriteList2.AddChild(sprite);
			}
		}
		
		TileList spriteList3 = new TileList(texture_info3, NUM_TILESX*NUM_TILESX );

		
	
		for(int i = 0; i<NUM_TILESX;i++)
		{
			for(int ii = 0; ii<NUM_TILESY;ii++)
			{
				TRS trs = new TRS(new Bounds2(new Vector2(i*TILE_SIZE,ii*TILE_SIZE),new Vector2((i*TILE_SIZE)+TILE_SIZE,(ii*TILE_SIZE)+TILE_SIZE)));
				RawSpriteTile sprite = new RawSpriteTile(trs,new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET),false, false);
				
				sprite.Quad.S = new Vector2 (TILE_SIZE,TILE_SIZE);//(int)(texture_info.TextureSizef/TILES_PER_SHEET),(int)(texture_info.TextureSizef/TILES_PER_SHEET)); 
				sprite.TileIndex2D = new Vector2i(i%TILES_PER_SHEET,ii%TILES_PER_SHEET);
				Vector2 v = scene.Camera.CalcBounds().Max;
				spriteList3.AddChild(sprite);
			}
		}
		
		
		scene.AddChild(spriteList3);
		scene.AddChild(spriteList2);
		scene.AddChild(spriteList);
		
		
		
		Director.Instance.GL.SetBlendMode( BlendMode.Normal );
		Director.Instance.RunWithScene( scene, true );
		
		FPSCounter fps = new FPSCounter();
		
		int frameCounter = 0;
		while ( !Input2.GamePad0.Cross.Press )
		{
			
			
			int count = 0;
			int XX = 0;
			int YY = 0;
			int moveSpeed = 2;
			for(int i =0;i<spriteList.Count;i++) {
				count++;
				
				TRS trs = new TRS(new Bounds2(new Vector2((spriteList.Sprites[i].Quad.T.X)+ 1,(spriteList.Sprites[i].Quad.T.Y)+ 1),new Vector2((spriteList.Sprites[i].Quad.T.X)+TILE_SIZE + 1,(spriteList.Sprites[i].Quad.T.Y)+TILE_SIZE + 1)));
				spriteList.Sprites[i].Quad = trs;//  new RawSpriteTile(trs,spriteList.Sprites[i].TileIndex2D,false, false);
				
				TRS trs2 = new TRS(new Bounds2(new Vector2((spriteList2.Sprites[i].Quad.T.X)- 1,(spriteList2.Sprites[i].Quad.T.Y)- 1),new Vector2((spriteList2.Sprites[i].Quad.T.X)+TILE_SIZE - 1,(spriteList2.Sprites[i].Quad.T.Y)+TILE_SIZE - 1)));
				spriteList2.Sprites[i].Quad = trs2;//  new RawSpriteTile(trs2,spriteList2.Sprites[i].TileIndex2D,false, false);
				
				TRS trs3 = new TRS(new Bounds2(new Vector2((spriteList3.Sprites[i].Quad.T.X)+1,(spriteList3.Sprites[i].Quad.T.Y)- 1),new Vector2((spriteList3.Sprites[i].Quad.T.X)+TILE_SIZE + 1,(spriteList3.Sprites[i].Quad.T.Y)+TILE_SIZE - 1)));
				spriteList3.Sprites[i].Quad = trs3;
			}
			
		
			Sce.Pss.Core.Environment.SystemEvents.CheckEvents();

			Director.Instance.Update();
			Director.Instance.Render();

			Director.Instance.GL.Context.SwapBuffers();
			Director.Instance.PostSwap(); 
			
			fps.printFPS(frameCounter); //To the console
			
		}
		

		Director.Terminate();

		System.Console.WriteLine( "Bye!" );
	}

}

 

//TileList.cs


using Sce.Pss.Core;
using Sce.Pss.HighLevel.GameEngine2D.Base;

namespace Sce.Pss.HighLevel.GameEngine2D
{
	public class TileList : Node
	{
		/// <summary>The list of RawSpriteTile objects to render.</summary>
		//public List< RawSpriteTile > Sprites = new List< RawSpriteTile >();
		public RawSpriteTile[] Sprites;
		public Vector4 Color = Colors.White;
		public BlendMode BlendMode = BlendMode.Normal;
		public TextureInfo TextureInfo; 
		public SpriteRenderer.ISpriteShader Shader = (SpriteRenderer.ISpriteShader)Director.Instance.SpriteRenderer.DefaultShader;
		
		public int Count = 0;

		public TileList(TextureInfo texture_info, int size)
		{
			Sprites = new RawSpriteTile[size];
			TextureInfo = texture_info;
		}

		public override void Draw()
		{
			Director.Instance.GL.SetBlendMode( BlendMode );
			Shader.SetColor( ref Color );
			Shader.SetUVTransform( ref Math.UV_TransformFlipV );
			Director.Instance.SpriteRenderer.BeginSprites( TextureInfo, Shader, Sprites.Length );

			foreach ( RawSpriteTile sprite in Sprites )
			{
				Director.Instance.SpriteRenderer.FlipU = sprite.FlipU;
				Director.Instance.SpriteRenderer.FlipV = sprite.FlipV;
				TRS copy = sprite.Quad;
				Director.Instance.SpriteRenderer.AddSprite( ref copy, sprite.TileIndex2D );
			}

			Director.Instance.SpriteRenderer.EndSprites(); 
		}
		
		public void moveSprite(RawSpriteTile rt, int index)
		{
			Sprites[index] = rt;
		}
		
		public void AddChild(RawSpriteTile rt)
		{
			Sprites[Count] = rt;
			Count++;
		}
			
		/// <summary>
		/// Based on the tile size and texture dimensions, return the corresponding size in pixels.
		/// For example you might want to do something like bob.Quad.S = bob.CalcSizeInPixels().
		/// </summary>
		public Vector2 CalcSizeInPixels()
		{
			// in the tile case, all sprites have the same pixel size
			return TextureInfo.TileSizeInPixelsf;
		}
	}
}

 

 

//FPSCounter.cs


using System;
using System.Collections.Generic;

using Sce.Pss.Core;
using Sce.Pss.Core.Graphics;
using Sce.Pss.Core.Environment;
using Sce.Pss.Core.Input;
using Sce.Pss.HighLevel.UI;

using System.Diagnostics;

public class FPSCounter
{
	
	Stopwatch stopwatch;
	int frameCounter;
	public FPSCounter ()
	{
		frameCounter = 0;
		stopwatch = Stopwatch.StartNew();
	
	}
	
	public void printFPS(int frames)
	{
		if((stopwatch.ElapsedMilliseconds/1000.0f) >= 1){
			
			Console.WriteLine(frameCounter);
			stopwatch.Reset();
			stopwatch.Start();
			frameCounter = 0;
			Console.WriteLine("");
		}else{
			frameCounter++;	
		}
	}
}

 

Please use plain text.

Member

Member
Clumfest
Posts: 3
Registered: ‎19-04-2012
Message 5 of 9 (466 Views)

Re: SpriteUV slowdown

 
Hi Adrian, 
By Sprite files you mean a single file for each sprite/animation frame in each sprite? If so, the reason that I use a lot of sprite sheets comes from making games for other platforms where you can have high seek times when reading in files. for example, if you have a tile sprite that fills a 512x512 sprite sheet and each frame is 32x32  (http://i297.photobucket.com/albums/mm238/Sevith_album/TileB.png one I found on Google) that means you have 256 individual images to load in if they are separate. if we guess an average seek time of say 15 milliseconds (cant remember the actual times we had) that means our load takes an extra  3.8 seconds. Given that our last game used around 6 to 8 of these sheets per level you can start to see how much it is costing you in extra load time. 
 
I should mention that we were basing this on reading from a disc so seek times varied a lot and I could be wrong but if your using solid state memory the seek times should be dramatically reduced. I know i could use other methods but I still use tile sheets because they were what I used when I started making games and it still works. 
 
Hope this helps,
Clumfest 
Please use plain text.

Level 2

Level 2
fr_romain1985
Posts: 16
Registered: ‎19-08-2011
Message 6 of 9 (441 Views)

Re: SpriteUV slowdown

Hi there!

 

In my own experiments,the first into tilemap, i was able to draw an entire very large  tile map (20k+ tile of 16x16 or 32/32) without any slowdown (on vita), and that's 20k+tile draw in one call. This one use one vertex buffer with an entire vertex array (coord+uv) made at initialization. But, it's deprecated now because

 

->

 

In another experiment, i have an method wich draw only the visible tile in the screen. I made a vertex array contening vertex coord + texture uv of all the map (created at initialization), and an index buffer. I refill the index buffer with the corresponding index of the visible tile (and only when needed by the scroll), then refresh the index array in the vertex buffer (vertexBuffer.setIndex(...)).

 

This one should be able to draw an infinite size tilemap (as the memory can handle, because that draw only the some visible tile in the screen in fact) always at the same speed. But the maximum size of the map is sadly the size of a ushort / 6 (each tile is made of 2 triangle). So i can have only 10922 tiles in my map (i'm looking for a better solution). Making your own tile engine is something good. In OpenGL, this rendering method can be very speedfull using instancied array.

 

As the first methode, i use only 1 draw call to draw the map. And for these 2 methods i use a large texture contening all the tile i need (so i don't bind the texturea lot of time).

 

--

 

I think the gameengine 2d is not suitable to draw and manage a large amount of sprites (but i haven't experimented so much with it, so ii can be wrong). 

Please use plain text.

Re: SpriteUV slowdown

fr_romain1985, that is some good info. I'm starting down this path am progressing slowly. Is any of your drawing code available online to look at?

Please use plain text.

Level 2

Level 2
fr_romain1985
Posts: 16
Registered: ‎19-08-2011
Message 8 of 9 (424 Views)

Re: SpriteUV slowdown

[ Edited ]

fr_romain1985, that is some good info. I'm starting down this path am progressing slowly. Is any of your drawing code available online to look at?

 

Yeah sure i will share with you! I'm progressing slowly too :smileyhappy:

You can download my actual work here (it's at an early stage, especially the tilemap, but i have a new version to upload soon, wich use index and clipping).

 

http://www.notnotme.com/misc/!!MVita.zip

 

In the new version i have removed an old sample too.

 

Ok i've put the newer tilemap code online.

 

Here is the TileMap class: http://pastebin.com/p30WUGzv

Here is the loader class : http://pastebin.com/WKrKBBUg

 

I've mad a tilemap editor in javafx 2.1 also, but i will not share this part of code. Anyway the xml structure is pretty easy to understand (but it's a pain in the ass to write the code by hand).

Basically you will see how it work (with index and clipping), but this is at an early stage of developpement..

 

* edit: it's not bug free

Please use plain text.

Member

Member
Codefused
Posts: 3
Registered: ‎30-11-2011
Message 9 of 9 (378 Views)

Re: SpriteUV slowdown

"I can have only 10922 tiles in my map"

If necessary you could get round this limit by making one big map out of lots of smaller ones. Since you are doing view culling you wouldn't have to worry about extra draw calls.
Please use plain text.
This widget could not be displayed.
Announcements

Welcome to the PlayStation Mobile Developer Forums


This is a community for the discussion of technical topics with other developers and SCE engineers. Posting ideas/requests are also appreciated. Join the discussion!

PlayStation®Mobile開発者フォーラムでは世界中の開発者の皆様と一緒に、議論や情報交換が可能です。SCEも議論に参加し、皆様の開発をサポートします。アイデアやリクエストも大歓迎です。ぜひご参加ください。

PSM Developer Registration (for free) on PSM DevPortal is required to post on the forum.
Please sign out then sign in again to the forum and PSM DevPortal after you have completed the registration.

フォーラムへ投稿をするにはPSM DevPortalへの登録(無料)が必要です。
登録後はフォーラムと PSM DevPortalを一度ログアウトし、再度ログインしてください。






Recent News