OSDN Git Service

webcpuの高速化と描画処理の実装変更(直接bmpに描画するようになった。)
authorhikarupsp <hikarupsp@users.sourceforge.jp>
Sat, 25 Jan 2014 03:54:19 +0000 (12:54 +0900)
committerhikarupsp <hikarupsp@users.sourceforge.jp>
Sat, 25 Jan 2014 03:54:19 +0000 (12:54 +0900)
webcpu/api.js
webcpu/index.html
webcpu/instrbas.js
webcpu/readme.txt [new file with mode: 0644]
webcpu/webcpu.js

index e1f1a6c..8510adb 100644 (file)
+function BitmapCanvas(){
+       this.canvasDOMObject = null;
+       this.canvasContext = null;
+       this.bufferImageData = null;
+       this.bmp = null;
+       this.width = undefined;
+       this.height = undefined;
+}
+BitmapCanvas.prototype = {
+       setCanvas: function(canvasDOMObject){
+               this.canvasDOMObject = canvasDOMObject;
+               if(canvasDOMObject){
+                       this.canvasContext = this.canvasDOMObject.getContext("2d");
+                       this.width = this.canvasDOMObject.width;
+                       this.height = this.canvasDOMObject.height;
+                       this.bufferImageData = this.canvasContext.getImageData(0, 0, this.width, this.height);
+                       this.bmp = this.bufferImageData.data;
+                       console.log(this.bufferImageData);
+                       //
+                       /*
+                       for(var i = 0; i < 100; i += 2){
+                               this.drawLine(0, i, 100, i, 0xffffff, 0);
+                       }
+                       var x0 = 10;
+                       var y0 = 10;
+                       var x1 = 60;
+                       var y1 = 11;
+                       this.drawLine(x0, y0, x1, y1, 0xff0000, 0);
+                       this.drawLine(x1, y1, x0, y0, 0x00ff00, 1);
+                       */
+                       this.flush();
+               } else{
+                       this.bmp = null;
+                       this.canvasContext = null;
+                       this.bufferImageData = null;
+                       this.width = undefined;
+                       this.height = undefined;
+               }
+       },
+       drawPoint: function(x, y, color, mode){
+               if(this.bmp){
+                       if(mode === undefined){
+                               mode = 0;
+                       } else{
+                               mode &= 0x03;
+                       }
+                       x += 0.5;
+                       x |= 0;
+                       y += 0.5;
+                       y |= 0;
+                       //RGBARGBA...
+                       if(mode == 0){
+                               //PSET
+                               this.bmp[4 * (y * this.width + x) + 0] = (color >> 16) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 1] = (color >> 8) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 2] = color & 0xFF;
+                       } else if(mode == 1){
+                               //OR
+                               this.bmp[4 * (y * this.width + x) + 0] |= (color >> 16) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 1] |= (color >> 8) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 2] |= color & 0xFF;
+                       } else if(mode == 2){
+                               //XOR
+                               this.bmp[4 * (y * this.width + x) + 0] ^= (color >> 16) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 1] ^= (color >> 8) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 2] ^= color & 0xFF;
+                       } else if(mode == 3){
+                               //AND
+                               this.bmp[4 * (y * this.width + x) + 0] &= (color >> 16) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 1] &= (color >> 8) & 0xFF;
+                               this.bmp[4 * (y * this.width + x) + 2] &= color & 0xFF;
+                       }
+               }
+       },
+       drawLine: function(x0, y0, x1, y1, color, mode){
+               //整数座標のみ対応。
+               x0 |= 0;
+               y0 |= 0;
+               x1 |= 0;
+               y1 |= 0;
+               var dx = x1 - x0;
+               var dy = y1 - y0;
+               var dxa = dx;
+               var dya = dy;
+               var l;
+               
+               if(dxa < 0){
+                       dxa = -dxa;
+               }
+               if(dya < 0){
+                       dya = -dya;
+               }
+               
+               if(dxa > dya){
+                       //x軸基準
+                       l = dxa + 1;
+                       if(x0 > x1){
+                               dx = -1;
+                       } else{
+                               dx = 1;
+                       }
+                       dy /= l;
+               } else{
+                       //y軸基準
+                       l = dya + 1;
+                       if(y0 > y1){
+                               dy = -1;
+                       } else{
+                               dy = 1;
+                       }
+                       dx /= l;
+               }
+               
+               for(var i = 0; i < l; i++){
+                       this.drawPoint(x0 + dx * i, y0 + dy * i, color, mode);
+               }
+       },
+       fillRect: function(xSize, ySize, x0, y0, col, mode){
+       
+       },
+       fillOval: function(xSize, ySize, x0, y0, col, mode){
+       
+       },
+       flush: function(){
+               if(this.bufferImageData){
+                       this.canvasContext.putImageData(this.bufferImageData, 0, 0);
+               }
+       },
+}
+
 function WebCPU_API(){
        this.mainWindowCanvas = null;
        this.mainWindowContext = null;
-       this.mainWindowBufferCanvas = document.createElement('canvas');
-       this.mainWindowBufferContext = this.mainWindowBufferCanvas.getContext("2d");
+       //this.mainWindowBufferCanvas = document.createElement('canvas');
+       //this.mainWindowBufferContext = this.mainWindowBufferCanvas.getContext("2d");
+       //
+       this.bitmapCanvas = new BitmapCanvas();
        //
-       this.mainWindowBufferCanvas.width = 640;
-       this.mainWindowBufferCanvas.height = 480;
-       this.initCanvas(this.mainWindowBufferCanvas);
+       //this.mainWindowBufferCanvas.width = 640;
+       //this.mainWindowBufferCanvas.height = 480;
+       //this.initCanvas(this.mainWindowBufferCanvas);
 }
 WebCPU_API.prototype = {
        executeAPI: function(env){
@@ -57,6 +189,8 @@ WebCPU_API.prototype = {
                if(this.mainWindowCanvas){
                        this.mainWindowContext = this.mainWindowCanvas.getContext('2d')
                        this.initCanvas(this.mainWindowCanvas);
+                       //
+                       this.bitmapCanvas.setCanvas(this.mainWindowCanvas);
                } else{
                        this.mainWindowContext = null;
                }
@@ -74,20 +208,24 @@ WebCPU_API.prototype = {
                env.message("junkApi_openWin();\n", 20);
                this.mainWindowCanvas.width = xSize;
                this.mainWindowCanvas.height = ySize;
-               this.mainWindowBufferCanvas.width = xSize;
-               this.mainWindowBufferCanvas.height = ySize;
+               //this.mainWindowBufferCanvas.width = xSize;
+               //this.mainWindowBufferCanvas.height = ySize;
+               this.initCanvas(this.mainWindowCanvas);
+               this.bitmapCanvas.setCanvas(this.mainWindowCanvas);
        },
        API_flushWin: function(env, xSize, ySize, x0, y0){
                env.message("junkApi_flushWin();\n", 20);
-               this.mainWindowContext.drawImage(this.mainWindowBufferCanvas, x0, y0, xSize, ySize, 0, 0, xSize, ySize);
+               //this.mainWindowContext.drawImage(this.mainWindowBufferCanvas, x0, y0, xSize, ySize, 0, 0, xSize, ySize);
+               this.bitmapCanvas.flush();
        },
        API_drawPoint: function(env, mode, x, y, col){
                env.message("junkApi_drawPoint();\n", 20);
                if((mode & 0x04) != 0){
                        col = this.colorTable[col];
                }
-               this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase();
-               this.mainWindowBufferContext.fillRect(x, y, 1, 1);
+               //this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase();
+               //this.mainWindowBufferContext.fillRect(x, y, 1, 1);
+               this.bitmapCanvas.drawPoint(x, y, col, mode);
        },
        API_drawLine: function(env, mode, x0, y0, x1, y1, col){
                env.message("junkApi_drawLine();\n", 20);
@@ -95,13 +233,15 @@ WebCPU_API.prototype = {
                if((mode & 0x04) != 0){
                        col = this.colorTable[col];
                }
-               
+               /*
                this.mainWindowBufferContext.strokeStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase();
                this.mainWindowBufferContext.beginPath();
                this.mainWindowBufferContext.moveTo(x0, y0);
                this.mainWindowBufferContext.lineTo(x1, y1);
                this.mainWindowBufferContext.closePath();
                this.mainWindowBufferContext.stroke();
+               */
+               this.bitmapCanvas.drawLine(x0, y0, x1, y1, col, mode);
        },
        API_fillRect: function(env, mode, xSize, ySize, x0, y0, col){
                env.message("junkApi_fillRect();\n", 20);
@@ -109,9 +249,10 @@ WebCPU_API.prototype = {
                if((mode & 0x04) != 0){
                        col = this.colorTable[col];
                }
-               
+               /*
                this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase();
                this.mainWindowBufferContext.fillRect(x0, y0, xSize, ySize);
+               */
        },
        API_fillOval: function(env, mode, xSize, ySize, x0, y0, col){
                env.message("junkApi_fillRect();\n", 20);
@@ -119,8 +260,9 @@ WebCPU_API.prototype = {
                if((mode & 0x04) != 0){
                        col = this.colorTable[col];
                }
-               
+               /*
                this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase();
                this.mainWindowBufferContext.fillEllipse(x0, y0, xSize, ySize);
+               */
        },
 }
index 0970880..2a28cfc 100755 (executable)
@@ -67,14 +67,20 @@ function disableDebugMode(){
 }
 
 var stepInTimer = null;
+var autoStepInCount = 0;
 
 function stepInMs(){
        stepInTimer = window.setInterval(stepInMs_Tick, 1);
 }
 
 function stepInMs_Tick(){
-       if(mainCPU.executeStepIn() != 0){
+       if(mainCPU.executeStepIn_Internal(false) != 0){
                window.clearTimeout(stepInTimer);
+       } else{
+               autoStepInCount++;
+               if((autoStepInCount & 0xff) == 0){
+                       mainCPU.API.API_flushWin(mainCPU, mainCPU.API.mainWindowCanvas.width, mainCPU.API.mainWindowCanvas.height, 0, 0);
+               }
        }
 }
 
index ccd51c2..ebf62f6 100644 (file)
@@ -19,11 +19,11 @@ WebCPU_Instruction.prototype = {
        },
        execute: function(env){
                //printXXXはデバッグ用
-               if(this.printSourceRegister){
+               if(this.isEnabledPrintSourceRegister && this.printSourceRegister){
                        this.printSourceRegister(env);
                }
                this.instruction(env);
-               if(this.printDestinationRegister){
+               if(this.isEnabledPrintDestinationRegister && this.printDestinationRegister){
                        this.printDestinationRegister(env);
                }
        },
@@ -72,6 +72,8 @@ WebCPU_Instruction.prototype = {
                return parseSignedInt32(argBinStr.substr(baseIndex + offset * 2, bytes * 2), 16);
        },
        //
+       isEnabledPrintSourceRegister: true,
+       isEnabledPrintDestinationRegister: true,
        printSourceRegister: null,
        printDestinationRegister: null,
 }
diff --git a/webcpu/readme.txt b/webcpu/readme.txt
new file mode 100644 (file)
index 0000000..a23a2cd
--- /dev/null
@@ -0,0 +1,37 @@
+*WebCPU-VM
+By hikarupsp 2013-2014 for OSECPU-VM
+
+**これは何?
+OSECPU-VMのJavaScript実装です。
+JavaScriptは、ほとんどの場合ウェブブラウザさえあれば実行できる言語なので、より多くの環境でOSECPUコードを実行させることができます。
+また、HTML5技術(Canvas)と連携することで、ウェブページに直接OSECPUコードを埋め込むこともできるようになるでしょう。
+これは、テキストを直接転送しているHTMLにとって、データの転送量を削減することにもつながります。
+
+**動作環境
+動作を確認している環境は以下の通りです。(app0023フロントエンドコードテキストのStepInMs実行にて確認。)
+-Chrome (Mac OSX, Windows)
+-Safari (Mac OSX, iOS)
+-Browser (Android)
+-InternetExplorer9 (Windows)
+
+**現在の状況は?
+-アプリケーションバイナリのフロントエンドコードHex文字列を実行し、その結果を表示することができます。
+-実行バイナリをドラッグ&ドロップで直接読み込ませ、実行させることができます(HTML5FileAPI対応ブラウザに限ります)。
+-バックエンド命令はほとんどが実装されていますが、APIおよびメモリ関連の一部の命令は未実装です。
+
+**使い方は?
+組み込んで使用する方は、index.htmlのサンプルコードを見ていただければ、だいたいはわかると思います。
+***テストページの操作方法
++binaryCodeのところに、バイナリをHex文字列化したものを打ち込む
+--もしくは実行バイナリファイルを直接読み込ませることもできます。
++コードをLoadする
+Loadボタンを押すことで、バイナリコードが解釈されてWebCPUで実行可能な状態になります。フロントエンドコードの場合、環境によってはデコードに少し時間がかかるかもしれません。
++実行する
+実行するときにはいくつかの方法があります。
+++StepIn:ステップ実行します。
+++StepInMs:1ミリ秒ごとに区切って実行します。デバッグ表示をしている間は最速で実行する方法です。
+++StepIn100:100ステップ実行します。
+++Execute:最速で実行します(デバッグモード有効時は使用しない方がよいです)
+-デバッグモードについて
+デバッグモード時は、実行中のレジスタ情報と現在実行中の命令について詳細を確認しながら実行できます。
+負荷のかかるアプリケーションを実行する際は、デバッグモードを無効にするのがよいでしょう。
index 45f0b6e..ed3d54a 100755 (executable)
@@ -1,3 +1,5 @@
+//WebCPUは、このディレクトリにあるファイルで完結している。
+
 function WebCPU_Exception(errno, infoArray){
        this.errno = errno;
        this.infoArray = infoArray;
@@ -265,27 +267,29 @@ WebCPU.prototype = {
        executeStepIn: function(){
                //ステップ実行する。
                //一回実行するたびに再描画する。
-               var retv = this.executeStepIn_Internal();
-               this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
+               var retv = this.executeStepIn_Internal(true);
+               this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
                return retv;
        },
-       executeStepIn_Internal: function(){
+       executeStepIn_Internal: function(isManualStepIn){
                //ステップ実行の内部部分。
                //終端到達時は1を、まだ後続命令がある場合は0を返す。
                //終了時にのみ再描画を行う
                if(this.stopFlag){
                        this.message(">stepIn:Break.\n", 2);
                        this.stopFlag = false;
-                       this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
+                       this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
                        return 2;
                }
                var instr = this.fetchMemoryNext();
                if(instr === undefined){
                        this.message(">stepIn:control reached end of binary.\n", 2);
-                       this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0);
+                       this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
                        return 1;
                }
-               this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20);
+               if(isManualStepIn){
+                       this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20);
+               }
                instr.execute(this);
                //これ以降this.memoryInstructionCounterが今実行した命令を指すとは限らない。(JMP系命令のため)
                /*
@@ -300,7 +304,7 @@ WebCPU.prototype = {
        execute: function(){
                //最速で実行する
                for(;;){
-                       if(this.executeStepIn_Internal() != 0){
+                       if(this.executeStepIn_Internal(false) != 0){
                                return;
                        }
                }
@@ -356,10 +360,14 @@ WebCPU.prototype = {
                        //すべて無効だったらタイマーの動作自体を止める
                        window.clearTimeout(this.messageTimer);
                        this.messageTimer = null;
+                       WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = false;
+                       WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = false;
                } else if(!this.messageTimer){
                        //どれかが有効でかつタイマーが止まっていたらスタートさせる
                        var that = this;
                        this.messageTimer = window.setInterval(function(){that.debugShowTick();}, 50);
+                       WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = true;
+                       WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = true;
                }
        },
        debugShowTick: function(){