1

My Test Case is to draw Two triangles and then wait six millseconds. When doing this,it's fps is at 60.

If I wave the mouse on the stage, then the fps is not stable. The Inactive time will increase and I have no way to decrease the inactive time. Why is this hapening.

Below are several screenshots.

Screen capture of scout: https://i.stack.imgur.com/xK0xV.png

GPUView fps Graph: https://i.stack.imgur.com/XO0HQ.png

And the code of the application

package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DCompareMode;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix3D;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.utils.getTimer;


[SWF(width="1000",height="600", backgroundColor = 0x000000, frameRate="60")]
public class SingleThreadRender extends Sprite
{
    [Embed( source = "RockSmooth.jpg" )]
    protected const TextureBitmap:Class;

    protected var context3D:Context3D;

    protected var vertexbuffer:VertexBuffer3D;
    protected var indexBuffer:IndexBuffer3D; 
    protected var program:Program3D;
    protected var texture:Texture;
    protected var projectionTransform:PerspectiveMatrix3D;

    private   var dataReady :Boolean = false;


    private   var text      :TextField = null;

    public function SingleThreadRender()
    {
        text = new TextField();
        text.text = "gogo";
        addChild(text);
        stage.mouseChildren = false;

        startRenderThread();
    }


    private function startRenderThread() :void {
        stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, initMolehill );
        stage.stage3Ds[0].requestContext3D();
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;  
        stage.stageHeight = 600
        stage.stageWidth = 800;
        addEventListener(Event.ENTER_FRAME, onRender);
        stage.addEventListener(MouseEvent.RIGHT_CLICK,rightClickHandler);
    }

    protected function initMolehill(e:Event):void
    {
        context3D = stage.stage3Ds[0].context3D;            
        context3D.configureBackBuffer(1000, 600, 1, true);

        var vertices:Vector.<Number> = Vector.<Number>([
            -3,-3, 0,0, 0, // x, y, z, u, v
            -3, 3, 0, 0, 1,
            3, -3, 0, 1, 1,
            3, 3, 0, 1, 0]);
        vertexbuffer = context3D.createVertexBuffer(4, 5);
        vertexbuffer.uploadFromVector(vertices, 0, 4);
        indexBuffer = context3D.createIndexBuffer(6);           
        indexBuffer.uploadFromVector (Vector.<uint>([0, 1, 2, 2, 3, 0]), 0, 6);

        var bitmap:Bitmap = new TextureBitmap();

        texture = context3D.createTexture(bitmap.bitmapData.width, bitmap.bitmapData.height, Context3DTextureFormat.BGRA, false);
        texture.uploadFromBitmapData(bitmap.bitmapData);

        var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
        vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
            "m44 op, va0, vc0\n" + // pos to clipspace
            "mov v0, va1" // copy uv
        );
        var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler();
        fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
            "tex ft1, v0, fs0 <2d,linear,nomip>\n" +
            "mov oc, ft1"
        );

        program = context3D.createProgram();
        program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);

        projectionTransform = new PerspectiveMatrix3D();
        var aspect:Number = 4/3;
        var zNear:Number = 0.1;
        var zFar:Number = 1000;
        var fov:Number = 45*Math.PI/180;
        projectionTransform.perspectiveFieldOfViewLH(fov, aspect, zNear, zFar);
    }

    private function rightClickHandler(event :MouseEvent) :void {
        stage.removeEventListener(MouseEvent.RIGHT_CLICK,rightClickHandler);
        stage.fullScreenSourceRect = new Rectangle( 0,0,stage.fullScreenWidth,stage.fullScreenHeight);
        stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
    }

    private var firstTime :Boolean = true;
    protected function onRender(e:Event):void
    {
        if(stage.frameRate != 60) {
            stage.frameRate = 60;
        }
        if ( !context3D ) 
            return;
        var start :int = flash.utils.getTimer();
        var now :int = 0;
        while(true) {
            now = flash.utils.getTimer();
            if((now - start) > 6) {
                break;
            }
        }

        context3D.clear ( 1,1, 1, 1 );

        context3D.setDepthTest( true, Context3DCompareMode.LESS_EQUAL);
        context3D.setVertexBufferAt (0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
        context3D.setVertexBufferAt(1, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
        context3D.setTextureAt(0, texture);         
        context3D.setProgram(program);
        var m:Matrix3D = new Matrix3D();
        m.appendTranslation(0, 0, 2);
        m.append(projectionTransform);

        context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, m, true);

        var i:int = 2;
        while(i--)
            context3D.drawTriangles(indexBuffer,0,2);
        context3D.present();

        while(true) {
            now = flash.utils.getTimer();
            if((now - start) > 6) {
                break;
            }
        }

    }
}
Nallath
  • 2,100
  • 20
  • 37
  • Is there a reason you're not using Starling to make life easier for yourself with the Stage3D of it all? – antman Dec 19 '12 at 19:32
  • this is a test case to demonstrate the problem – niluzhou1984 Dec 22 '12 at 06:30
  • BTW, starling is for 2D...maybe he wants to do stuff in 3D? Also, Starling is not without it's limitations. As of writing, they _still_ do not have native commands for moveTo, lineTo, beginFill, etc. There are extensions and third party libraries which add this...but it just goes to show how young starling is. – jordancpaul Jan 19 '13 at 10:13
  • I have the same problem in debug builds on Mac. I don't know what's the reason, probably it's a bug. I came across a similar question on Adobe forums, but there's no answer as well. Howewer, everything is fine in release builds under release player, including release builds running under iOS. – skozin Jan 24 '13 at 20:44

1 Answers1

0

I'm assuming you come from a C background or some other language with native threading support. In single threaded languages such as Actionscript and Javascript, busy loops such as the one in your onRender function are a big no-no:

while(true) {
    now = flash.utils.getTimer();
    if((now - start) > 6) {
        break;
    }
}

The frame period for 60 hz is 16ms. By wasting 6ms in a loop, you've left yourself 10ms to do the rendering and complete before the next onRender call. To make matters even worse, AS3 has pretty bad timer resolution. Check out this blog post by Tinic Uro (Flash engineer) about the timer - bottom line, don't use getTimer() or stage.frameRate for any kind of synchronization.

What this all adds up to is that between your render cycles, the flash never stops. It's just sitting there spinning in that loop. The way AS3 deals with it's single-threadedness is by using idle time to service asynchronous events (such as your mousemove events). By putting a busy loop in your onRender function you have effectively guaranteed that there is now downtime to service the mousemove events - thus causing erratic frame rates when mousemove events occur.

jordancpaul
  • 2,954
  • 1
  • 18
  • 27