Проблема с производительностью Flash MouseMove

Мой тестовый пример - нарисовать два треугольника, а затем подождать шесть миллисекунд. При этом фпс 60.

Если машу мышкой на сцене, то фпс не стабильный. Неактивное время будет увеличиваться, и у меня нет возможности уменьшить неактивное время. Почему это происходит.

Ниже несколько скриншотов.

Снимок экрана разведчика: http://i.stack.imgur.com/xK0xV.png

Граф GPUView fps: http://i.stack.imgur.com/XO0HQ.png

И код приложения

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;
            }
        }

    }
}

person niluzhou1984    schedule 15.12.2012    source источник
comment
Есть ли причина, по которой вы не используете Starling, чтобы облегчить себе жизнь с помощью Stage3D?   -  person antman    schedule 19.12.2012
comment
это тестовый пример для демонстрации проблемы   -  person niluzhou1984    schedule 22.12.2012
comment
Кстати, Старлинг для 2D... может быть, он хочет делать что-то в 3D? Кроме того, Starling не без ограничений. На момент написания у них до сих пор нет собственных команд для moveTo, lineTo, beginFill и т. д. Существуют расширения и сторонние библиотеки, которые добавляют это... но это просто показывает, насколько молод скворец. .   -  person jordancpaul    schedule 19.01.2013
comment
У меня такая же проблема в отладочных сборках на Mac. Не знаю в чем причина, возможно это баг. Я наткнулся на аналогичный вопрос на форумах Adobe, но ответа тоже нет. Однако в релизных сборках под релизным плеером, в том числе и под iOS, все нормально.   -  person skozin    schedule 25.01.2013


Ответы (1)


Я предполагаю, что вы родом из C или какого-то другого языка с собственной поддержкой потоковой передачи. В однопоточных языках, таких как Actionscript и Javascript, циклы занятости, такие как в вашей функции onRender, являются большим запретом:

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

Период кадра для 60 Гц составляет 16 мс. Потратив 6 мс на цикл, вы оставили себе 10 мс на рендеринг и его завершение до следующего вызова onRender. Что еще хуже, AS3 имеет довольно плохое разрешение таймера. Ознакомьтесь с этой записью в блоге Тиника Уро ( Флэш-инженер) о таймере - суть в том, что не используйте getTimer() или stage.frameRate для любой синхронизации.

Все это приводит к тому, что между циклами рендеринга вспышка никогда не останавливается. Он просто сидит и крутится в этой петле. Способ, которым AS3 справляется с однопоточностью, заключается в использовании времени простоя для обслуживания асинхронных событий (таких как ваши события mousemove). Поместив цикл занятости в функцию onRender, вы фактически гарантируете, что теперь есть время простоя для обслуживания событий mousemove, что приводит к неустойчивой частоте кадров при возникновении событий mousemove.

person jordancpaul    schedule 19.01.2013