GPUStats
Statsの丸パク
インスタンスはひとつしか作らないと信じて。
GPUStats.vramに割り当てた/破棄したバイト数を加算/減算する(自分で!)
GPUStats.setTRI()でdrawTrianglesした△数を毎フレームセットする(自分で!)
一気に複数パス分セットするときは第二引数にその回数を入れる
ついでに自分用メモ
Stage3Dのssの撮り方
private var sc:BitmapData=new BitmapData(465,465,false);
Wonderfl.disable_capture();
addChild(new Bitmap(sc));
context3D.drawToBitmapData(sc);
/**
* Copyright 9balls ( http://wonderfl.net/user/9balls )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hI8YM
*/
// forked from 9balls's Stage3Dで花火
package {
import com.adobe.utils.AGALMiniAssembler;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.textures.Texture;
import flash.display3D.VertexBuffer3D;
import flash.events.ContextMenuEvent;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.text.TextField;
import flash.ui.ContextMenu;
import flash.ui.ContextMenuItem;
import flash.utils.ByteArray;
import frocessing.color.ColorHSV;
import net.hires.debug.Stats;
/**
* ...
* @author
*/
public class Main extends Sprite {
private var driverText:TextField;
private var stats:GPUStats;
private var isShowDriver:Boolean = false;
private var isShowStats:Boolean = true;
//
private var size:Number = 1;
private var maxNum:uint = 3000;
private var num:uint = 0;
private var count:uint = 0;
private var next:uint = 0;
//
private var stage3D:Stage3D;
private var context3D:Context3D;
//
private var program1:Program3D;
private var program2:Program3D;
private var program3:Program3D;
private var program4:Program3D;
private var indexBuffer:IndexBuffer3D;
private var vertexBuffer:VertexBuffer3D;
private var texture:Texture;
private var screen:Texture;
private var screenIndexBuffer:IndexBuffer3D;
private var screenVertexBuffer:VertexBuffer3D;
private var waterIndexBuffer:IndexBuffer3D;
private var waterVertexBuffer:VertexBuffer3D;
private var vertices:Vector.<Number>;
private var particles:Vector.<Particle>;
private var particlesFree:Vector.<Particle>;
private var mtx:Matrix3D;
private var waterMtx:Matrix3D;
private var testTexture:Texture;
//
public function Main():void {
//Wonderfl.disable_capture();
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stats = new GPUStats();
addChild(stats);
stage.frameRate = 60;
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//
particles = new Vector.<Particle>();
particlesFree = new Vector.<Particle>(maxNum);
for (var i:int = 0; i < maxNum; i++){
particlesFree[i] = new Particle();
}
//
stage3D = stage.stage3Ds[0];
stage3D.x = 0;
stage3D.y = 0;
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
stage3D.requestContext3D(Context3DRenderMode.AUTO);
}
private function onContextCreate(e:Event):void {
context3D = stage3D.context3D;
//context3D.enableErrorChecking = true;
context3D.configureBackBuffer(466, 466, 0, false);
//text
driverText = new TextField();
driverText.textColor = 0xffffff;
driverText.wordWrap = true;
driverText.width = 400;
driverText.text = context3D.driverInfo;
driverText.y = 440;
var item1:ContextMenuItem = new ContextMenuItem("show driverInfo", false);
item1.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, showDriver);
var item2:ContextMenuItem = new ContextMenuItem("hide Stats", false);
item2.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, showStats);
var contextMenu:ContextMenu = new ContextMenu();
contextMenu.customItems = [item1, item2]; // カスタムメニューに登録
this.contextMenu = contextMenu;
//create
createShaders();
setConstant();
setBuffer();
texture = context3D.createTexture(32, 32, Context3DTextureFormat.BGRA, true);
screen = context3D.createTexture(512, 512, Context3DTextureFormat.BGRA, true);
GPUStats.vram += (32*32+512*512)*4;
testTexture = context3D.createTexture(32, 32, Context3DTextureFormat.BGRA, false);
testTexture.uploadFromBitmapData(new BitmapData(32, 32, false, 0xff0000));
//run
addEventListener(Event.ENTER_FRAME, onEnter);
}
private function showDriver(e:ContextMenuEvent):void {
if (isShowDriver){
removeChild(driverText);
(e.currentTarget as ContextMenuItem).caption = "show driverInfo";
} else {
addChild(driverText);
(e.currentTarget as ContextMenuItem).caption = "hide driverInfo";
}
isShowDriver = !isShowDriver;
}
private function showStats(e:ContextMenuEvent):void {
if (isShowStats){
removeChild(stats);
(e.currentTarget as ContextMenuItem).caption = "show Stats";
} else {
addChild(stats);
(e.currentTarget as ContextMenuItem).caption = "hide Stats";
}
isShowStats = !isShowStats;
}
private function onEnter(e:Event):void {
if (count == next){
createFire((Math.random() - 0.5) * 500, Math.random() * 100 + 150, 6 + 10 * Math.random(), 1000);
count = 0;
next = 50 + 30 * Math.random() >> 0;
}
count++;
var par:Particle;
var n:uint;
for (var i:int = 0; i < num; i++){
par = particles[i];
n = 15 * i;
if (par.life == par.death){
particlesFree.push(particles.splice(i, 1)[0]);
i--;
num--;
vertices.splice(n, 15);
continue;
}
var posX:Number = par.x;
var posY:Number = par.y;
vertices[n] = posX - size;
vertices[uint(n + 1)] = posY - size;
vertices[uint(n + 5)] = posX - size;
vertices[uint(n + 6)] = posY + size;
vertices[uint(n + 10)] = posX + size;
vertices[uint(n + 11)] = posY - size;
//
par.update();
}
//
vertexBuffer.uploadFromVector(vertices, 0, 3 * num);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mtx, false);
context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(1, vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_3);
context3D.setProgram(program1);
context3D.setRenderToTexture(screen);
context3D.clear(0, 0, 0, 1);
context3D.drawTriangles(indexBuffer, 0, num);
GPUStats.setTRI(num);
//
context3D.setVertexBufferAt(0, screenVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(1, screenVertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
context3D.setProgram(program2);
context3D.setRenderToTexture(texture);
context3D.setTextureAt(0, screen);
context3D.clear(0, 0, 0, 1);
context3D.drawTriangles(screenIndexBuffer);
GPUStats.setTRI(2);
//
context3D.setProgram(program3);
context3D.setRenderToBackBuffer();
context3D.setTextureAt(0, screen);
context3D.setTextureAt(1, texture);
context3D.clear(0, 0, 0, 1);
context3D.drawTriangles(screenIndexBuffer);
GPUStats.setTRI(2);
//
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, waterMtx, true);
context3D.setVertexBufferAt(0, waterVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(1, waterVertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
context3D.setProgram(program4);
context3D.setTextureAt(0, texture);
context3D.setTextureAt(1, null);
context3D.drawTriangles(screenIndexBuffer);
GPUStats.setTRI(2);
//
context3D.present();
//
context3D.setTextureAt(0, null);
}
private function createShaders():void {
//create shaders
var agalAssembler:AGALMiniAssembler = new AGALMiniAssembler();
//
//vertex
var vertexShaderOpMtx:ByteArray = agalAssembler.assemble(Context3DProgramType.VERTEX, "m44 op, va0, vc0 \n" + "mov v0, va1\n");
var vertexShaderOpNone:ByteArray = agalAssembler.assemble(Context3DProgramType.VERTEX, "mov op, va0\n" + "mov v0, va1\n");
//
//fragment
var code:String = "";
code += "mov ft0 v0\n";
code += "mov oc, ft0\n";
var fragmentShader:ByteArray = agalAssembler.assemble(Context3DProgramType.FRAGMENT, code);
program1 = context3D.createProgram();
program1.upload(vertexShaderOpMtx, fragmentShader);
GPUStats.vram += vertexShaderOpMtx.length + fragmentShader.length;
//
code = "";
code += "mov ft0 v0\n";
code += "tex ft0, ft0, fs0<2d,repeat,linear>\n";
code += "mov oc, ft0\n";
fragmentShader = agalAssembler.assemble(Context3DProgramType.FRAGMENT, code);
program2 = context3D.createProgram();
program2.upload(vertexShaderOpNone, fragmentShader);
GPUStats.vram += vertexShaderOpNone.length + fragmentShader.length;
//
program4 = context3D.createProgram();
program4.upload(vertexShaderOpMtx, fragmentShader);
GPUStats.vram += vertexShaderOpMtx.length + fragmentShader.length;
//
code = "";
code += "mov ft0 v0\n";
code += "tex ft1, ft0, fs0<2d,repeat,linear>\n";
code += "tex ft0, ft0, fs1<2d,repeat,linear>\n";
code += "add ft0, ft0, ft1\n";
code += "mov oc, ft0\n";
fragmentShader = agalAssembler.assemble(Context3DProgramType.FRAGMENT, code);
program3 = context3D.createProgram();
program3.upload(vertexShaderOpNone, fragmentShader);
GPUStats.vram += vertexShaderOpNone.length + fragmentShader.length;
}
private function setConstant():void {
//vc
mtx = new Matrix3D();
mtx.appendScale(1 / 256, 1 / 256, 1);
waterMtx = new Matrix3D();
waterMtx.appendTranslation(0, 2.5, 0);
waterMtx.appendScale(1, -0.3, 1);
}
private function setBuffer():void {
//particle
var length:uint = 3 * maxNum;
var length2:uint = 15 * maxNum;
//vertex buffer
vertices = new Vector.<Number>(length2);
for (var i:int = 0; i < length2; i++){
vertices[i] = 0;
}
vertexBuffer = context3D.createVertexBuffer(length, 5);
GPUStats.vram += length * 5 * 4;
vertexBuffer.uploadFromVector(vertices, 0, length);
//index buffer
var indices:Vector.<uint> = new Vector.<uint>(length);
for (i = 0; i < length; i++){
indices[i] = i;
}
indexBuffer = context3D.createIndexBuffer(length);
GPUStats.vram += length * 4;
indexBuffer.uploadFromVector(indices, 0, length);
//
//water
//vertex buffer
waterVertexBuffer = context3D.createVertexBuffer(4, 5);
GPUStats.vram += 4 * 5 *4;
waterVertexBuffer.uploadFromVector(Vector.<Number>([-1, -1, 0, 0, 1, -1, 1, 0, 0, 0, 1, -1, 0, 1, 1, 1, 1, 0, 1, 0]), 0, 4);
//index buffer
waterIndexBuffer = context3D.createIndexBuffer(6);
GPUStats.vram += 6 * 4;
waterIndexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 1, 2, 3]), 0, 6);
//
//screen
//vertex buffer
screenVertexBuffer = context3D.createVertexBuffer(4, 4);
GPUStats.vram += 4 * 4 *4;
screenVertexBuffer.uploadFromVector(Vector.<Number>([-1, -1, 0, 1, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]), 0, 4);
//index buffer
screenIndexBuffer = context3D.createIndexBuffer(6);
GPUStats.vram += 6 * 4;
screenIndexBuffer.uploadFromVector(Vector.<uint>([0, 1, 2, 1, 2, 3]), 0, 6);
}
private function createFire(xPos:Number, yPos:Number, radius:Number, numP:uint):void {
var r:Number;
var g:Number;
var b:Number;
var buf:Vector.<Number> = new Vector.<Number>(numP * 15);
var par:Vector.<Particle> = particlesFree.splice(0, numP);
var n:uint;
var color:ColorHSV = new ColorHSV(360 * Math.random());
for (var i:int = 0; i < numP; i++){
par[i].init(xPos, yPos, Math.random() * radius + 0.5, Math.random() * 2 * Math.PI)
color.s = 0.2 + Math.random() * 0.8;
color.v = 0.2 + Math.random() * 0.8;
r = color.r / 255;
g = color.g / 255;
b = color.b / 255;
n = i * 15;
buf[uint(n + 2)] = r;
buf[uint(n + 3)] = g;
buf[uint(n + 4)] = b;
buf[uint(n + 7)] = r;
buf[uint(n + 8)] = g;
buf[uint(n + 9)] = b;
buf[uint(n + 12)] = r;
buf[uint(n + 13)] = g;
buf[uint(n + 14)] = b;
}
particles = particles.concat(par);
vertices = vertices.concat(buf);
num += numP;
}
}
}
class Particle extends Object {
public var life:uint;
public var death:uint;
public var x:Number;
public var y:Number;
public var vx:Number;
public var vy:Number;
public function Particle():void {
}
public function init(xPos:Number, yPos:Number, r:Number, theta:Number):void {
x = xPos;
y = yPos;
vx = r * Math.cos(theta);
vy = r * Math.sin(theta) - 0.1;
death = (Math.random() * 60 >> 0) + 30;
life = 0;
}
public function update():void {
x += vx;
y += vy;
vx *= 0.92;
vy -= 0.1;
vy *= 0.92;
life++;
}
}
//////////////////////////////////////////////////
// GPUStats
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.system.System;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.utils.getTimer;
class GPUStats extends Sprite {
protected const WIDTH:uint = 70;
protected const HEIGHT:uint = 80;
//
protected var xml:XML;
protected var text:TextField;
protected var style:StyleSheet;
//
protected var timer:uint;
protected var fps:uint;
protected var ms:uint;
protected var ms_prev:uint;
protected var mem:Number;
protected var mem_max:Number = 0;
//
public static var vram:uint = 0;
public static var drw:uint = 0;
public static var tri:uint = 0;
//
protected var theme:Object = {bg: 0x000033, fps: 0xffff00, ms: 0x00ff00, mem: 0x00ffff, memmax: 0xff0070, vram: 0xffffff, drw: 0xffffff, tri: 0xffffff};
public function GPUStats(theme:Object = null):void {
if (!theme)
theme = this.theme;
//
xml = <xml><fps></fps><ms></ms><mem></mem><memMax></memMax><vram></vram><drw></drw><tri></tri></xml>;
style = new StyleSheet();
style.setStyle('xml', {fontSize: '9px', fontFamily: '_sans', leading: '-2px'});
for (var name:String in theme){
style.setStyle(name, {color: "#" + theme[name].toString(16)});
}
//
text = new TextField();
text.width = WIDTH;
text.height = HEIGHT;
text.styleSheet = style;
text.condenseWhite = true;
text.selectable = false;
text.mouseEnabled = false;
//
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
addEventListener(Event.REMOVED_FROM_STAGE, destroy, false, 0, true);
}
protected function init(e:Event):void {
graphics.beginFill(theme.bg);
graphics.drawRect(0, 0, WIDTH, HEIGHT);
graphics.endFill();
addChild(text);
addEventListener(MouseEvent.CLICK, onClick);
addEventListener(Event.ENTER_FRAME, update);
}
protected function destroy(e:Event):void {
graphics.clear();
removeChildren();
removeEventListener(MouseEvent.CLICK, onClick);
removeEventListener(Event.ENTER_FRAME, update);
}
protected function update(e:Event):void {
timer = getTimer();
if (timer - 1000 > ms_prev){
ms_prev = timer;
mem = Number((System.totalMemory * 0.000000954).toFixed(3));
mem_max = mem_max > mem ? mem_max : mem;
//
xml.fps = "FPS: " + fps + " / " + stage.frameRate;
xml.mem = "MEM: " + mem;
xml.memMax = "MAX: " + mem_max;
xml.vram = "VRAM: " + (vram * 0.000000954).toFixed(3)
xml.drw = "DRW: " + drw;
xml.tri = "TRI: " + tri;
//
fps = 0;
}
fps++;
xml.ms = "MS: " + (timer - ms);
ms = timer;
text.htmlText = xml;
drw = 0;
tri = 0;
}
protected function onClick(e:MouseEvent):void {
mouseY / height > .5 ? stage.frameRate-- : stage.frameRate++;
xml.fps = "FPS: " + fps + " / " + stage.frameRate;
text.htmlText = xml;
}
public static function setTRI(numTriangles:uint, drwCount:uint = 1):void {
tri += numTriangles;
drw += drwCount;
}
}