サブプロジェクトAI004
Revisión | 679a34d178685030bf585b599a25acf12986c3e9 (tree) |
---|---|
Tiempo | 2014-01-25 12:54:19 |
Autor | hikarupsp <hikarupsp@user...> |
Commiter | hikarupsp |
webcpuの高速化と描画処理の実装変更(直接bmpに描画するようになった。)
@@ -1,12 +1,144 @@ | ||
1 | +function BitmapCanvas(){ | |
2 | + this.canvasDOMObject = null; | |
3 | + this.canvasContext = null; | |
4 | + this.bufferImageData = null; | |
5 | + this.bmp = null; | |
6 | + this.width = undefined; | |
7 | + this.height = undefined; | |
8 | +} | |
9 | +BitmapCanvas.prototype = { | |
10 | + setCanvas: function(canvasDOMObject){ | |
11 | + this.canvasDOMObject = canvasDOMObject; | |
12 | + if(canvasDOMObject){ | |
13 | + this.canvasContext = this.canvasDOMObject.getContext("2d"); | |
14 | + this.width = this.canvasDOMObject.width; | |
15 | + this.height = this.canvasDOMObject.height; | |
16 | + this.bufferImageData = this.canvasContext.getImageData(0, 0, this.width, this.height); | |
17 | + this.bmp = this.bufferImageData.data; | |
18 | + console.log(this.bufferImageData); | |
19 | + // | |
20 | + /* | |
21 | + for(var i = 0; i < 100; i += 2){ | |
22 | + this.drawLine(0, i, 100, i, 0xffffff, 0); | |
23 | + } | |
24 | + var x0 = 10; | |
25 | + var y0 = 10; | |
26 | + var x1 = 60; | |
27 | + var y1 = 11; | |
28 | + this.drawLine(x0, y0, x1, y1, 0xff0000, 0); | |
29 | + this.drawLine(x1, y1, x0, y0, 0x00ff00, 1); | |
30 | + */ | |
31 | + this.flush(); | |
32 | + } else{ | |
33 | + this.bmp = null; | |
34 | + this.canvasContext = null; | |
35 | + this.bufferImageData = null; | |
36 | + this.width = undefined; | |
37 | + this.height = undefined; | |
38 | + } | |
39 | + }, | |
40 | + drawPoint: function(x, y, color, mode){ | |
41 | + if(this.bmp){ | |
42 | + if(mode === undefined){ | |
43 | + mode = 0; | |
44 | + } else{ | |
45 | + mode &= 0x03; | |
46 | + } | |
47 | + x += 0.5; | |
48 | + x |= 0; | |
49 | + y += 0.5; | |
50 | + y |= 0; | |
51 | + //RGBARGBA... | |
52 | + if(mode == 0){ | |
53 | + //PSET | |
54 | + this.bmp[4 * (y * this.width + x) + 0] = (color >> 16) & 0xFF; | |
55 | + this.bmp[4 * (y * this.width + x) + 1] = (color >> 8) & 0xFF; | |
56 | + this.bmp[4 * (y * this.width + x) + 2] = color & 0xFF; | |
57 | + } else if(mode == 1){ | |
58 | + //OR | |
59 | + this.bmp[4 * (y * this.width + x) + 0] |= (color >> 16) & 0xFF; | |
60 | + this.bmp[4 * (y * this.width + x) + 1] |= (color >> 8) & 0xFF; | |
61 | + this.bmp[4 * (y * this.width + x) + 2] |= color & 0xFF; | |
62 | + } else if(mode == 2){ | |
63 | + //XOR | |
64 | + this.bmp[4 * (y * this.width + x) + 0] ^= (color >> 16) & 0xFF; | |
65 | + this.bmp[4 * (y * this.width + x) + 1] ^= (color >> 8) & 0xFF; | |
66 | + this.bmp[4 * (y * this.width + x) + 2] ^= color & 0xFF; | |
67 | + } else if(mode == 3){ | |
68 | + //AND | |
69 | + this.bmp[4 * (y * this.width + x) + 0] &= (color >> 16) & 0xFF; | |
70 | + this.bmp[4 * (y * this.width + x) + 1] &= (color >> 8) & 0xFF; | |
71 | + this.bmp[4 * (y * this.width + x) + 2] &= color & 0xFF; | |
72 | + } | |
73 | + } | |
74 | + }, | |
75 | + drawLine: function(x0, y0, x1, y1, color, mode){ | |
76 | + //整数座標のみ対応。 | |
77 | + x0 |= 0; | |
78 | + y0 |= 0; | |
79 | + x1 |= 0; | |
80 | + y1 |= 0; | |
81 | + var dx = x1 - x0; | |
82 | + var dy = y1 - y0; | |
83 | + var dxa = dx; | |
84 | + var dya = dy; | |
85 | + var l; | |
86 | + | |
87 | + if(dxa < 0){ | |
88 | + dxa = -dxa; | |
89 | + } | |
90 | + if(dya < 0){ | |
91 | + dya = -dya; | |
92 | + } | |
93 | + | |
94 | + if(dxa > dya){ | |
95 | + //x軸基準 | |
96 | + l = dxa + 1; | |
97 | + if(x0 > x1){ | |
98 | + dx = -1; | |
99 | + } else{ | |
100 | + dx = 1; | |
101 | + } | |
102 | + dy /= l; | |
103 | + } else{ | |
104 | + //y軸基準 | |
105 | + l = dya + 1; | |
106 | + if(y0 > y1){ | |
107 | + dy = -1; | |
108 | + } else{ | |
109 | + dy = 1; | |
110 | + } | |
111 | + dx /= l; | |
112 | + } | |
113 | + | |
114 | + for(var i = 0; i < l; i++){ | |
115 | + this.drawPoint(x0 + dx * i, y0 + dy * i, color, mode); | |
116 | + } | |
117 | + }, | |
118 | + fillRect: function(xSize, ySize, x0, y0, col, mode){ | |
119 | + | |
120 | + }, | |
121 | + fillOval: function(xSize, ySize, x0, y0, col, mode){ | |
122 | + | |
123 | + }, | |
124 | + flush: function(){ | |
125 | + if(this.bufferImageData){ | |
126 | + this.canvasContext.putImageData(this.bufferImageData, 0, 0); | |
127 | + } | |
128 | + }, | |
129 | +} | |
130 | + | |
1 | 131 | function WebCPU_API(){ |
2 | 132 | this.mainWindowCanvas = null; |
3 | 133 | this.mainWindowContext = null; |
4 | - this.mainWindowBufferCanvas = document.createElement('canvas'); | |
5 | - this.mainWindowBufferContext = this.mainWindowBufferCanvas.getContext("2d"); | |
134 | + //this.mainWindowBufferCanvas = document.createElement('canvas'); | |
135 | + //this.mainWindowBufferContext = this.mainWindowBufferCanvas.getContext("2d"); | |
136 | + // | |
137 | + this.bitmapCanvas = new BitmapCanvas(); | |
6 | 138 | // |
7 | - this.mainWindowBufferCanvas.width = 640; | |
8 | - this.mainWindowBufferCanvas.height = 480; | |
9 | - this.initCanvas(this.mainWindowBufferCanvas); | |
139 | + //this.mainWindowBufferCanvas.width = 640; | |
140 | + //this.mainWindowBufferCanvas.height = 480; | |
141 | + //this.initCanvas(this.mainWindowBufferCanvas); | |
10 | 142 | } |
11 | 143 | WebCPU_API.prototype = { |
12 | 144 | executeAPI: function(env){ |
@@ -57,6 +189,8 @@ WebCPU_API.prototype = { | ||
57 | 189 | if(this.mainWindowCanvas){ |
58 | 190 | this.mainWindowContext = this.mainWindowCanvas.getContext('2d') |
59 | 191 | this.initCanvas(this.mainWindowCanvas); |
192 | + // | |
193 | + this.bitmapCanvas.setCanvas(this.mainWindowCanvas); | |
60 | 194 | } else{ |
61 | 195 | this.mainWindowContext = null; |
62 | 196 | } |
@@ -74,20 +208,24 @@ WebCPU_API.prototype = { | ||
74 | 208 | env.message("junkApi_openWin();\n", 20); |
75 | 209 | this.mainWindowCanvas.width = xSize; |
76 | 210 | this.mainWindowCanvas.height = ySize; |
77 | - this.mainWindowBufferCanvas.width = xSize; | |
78 | - this.mainWindowBufferCanvas.height = ySize; | |
211 | + //this.mainWindowBufferCanvas.width = xSize; | |
212 | + //this.mainWindowBufferCanvas.height = ySize; | |
213 | + this.initCanvas(this.mainWindowCanvas); | |
214 | + this.bitmapCanvas.setCanvas(this.mainWindowCanvas); | |
79 | 215 | }, |
80 | 216 | API_flushWin: function(env, xSize, ySize, x0, y0){ |
81 | 217 | env.message("junkApi_flushWin();\n", 20); |
82 | - this.mainWindowContext.drawImage(this.mainWindowBufferCanvas, x0, y0, xSize, ySize, 0, 0, xSize, ySize); | |
218 | + //this.mainWindowContext.drawImage(this.mainWindowBufferCanvas, x0, y0, xSize, ySize, 0, 0, xSize, ySize); | |
219 | + this.bitmapCanvas.flush(); | |
83 | 220 | }, |
84 | 221 | API_drawPoint: function(env, mode, x, y, col){ |
85 | 222 | env.message("junkApi_drawPoint();\n", 20); |
86 | 223 | if((mode & 0x04) != 0){ |
87 | 224 | col = this.colorTable[col]; |
88 | 225 | } |
89 | - this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase(); | |
90 | - this.mainWindowBufferContext.fillRect(x, y, 1, 1); | |
226 | + //this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase(); | |
227 | + //this.mainWindowBufferContext.fillRect(x, y, 1, 1); | |
228 | + this.bitmapCanvas.drawPoint(x, y, col, mode); | |
91 | 229 | }, |
92 | 230 | API_drawLine: function(env, mode, x0, y0, x1, y1, col){ |
93 | 231 | env.message("junkApi_drawLine();\n", 20); |
@@ -95,13 +233,15 @@ WebCPU_API.prototype = { | ||
95 | 233 | if((mode & 0x04) != 0){ |
96 | 234 | col = this.colorTable[col]; |
97 | 235 | } |
98 | - | |
236 | + /* | |
99 | 237 | this.mainWindowBufferContext.strokeStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase(); |
100 | 238 | this.mainWindowBufferContext.beginPath(); |
101 | 239 | this.mainWindowBufferContext.moveTo(x0, y0); |
102 | 240 | this.mainWindowBufferContext.lineTo(x1, y1); |
103 | 241 | this.mainWindowBufferContext.closePath(); |
104 | 242 | this.mainWindowBufferContext.stroke(); |
243 | + */ | |
244 | + this.bitmapCanvas.drawLine(x0, y0, x1, y1, col, mode); | |
105 | 245 | }, |
106 | 246 | API_fillRect: function(env, mode, xSize, ySize, x0, y0, col){ |
107 | 247 | env.message("junkApi_fillRect();\n", 20); |
@@ -109,9 +249,10 @@ WebCPU_API.prototype = { | ||
109 | 249 | if((mode & 0x04) != 0){ |
110 | 250 | col = this.colorTable[col]; |
111 | 251 | } |
112 | - | |
252 | + /* | |
113 | 253 | this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase(); |
114 | 254 | this.mainWindowBufferContext.fillRect(x0, y0, xSize, ySize); |
255 | + */ | |
115 | 256 | }, |
116 | 257 | API_fillOval: function(env, mode, xSize, ySize, x0, y0, col){ |
117 | 258 | env.message("junkApi_fillRect();\n", 20); |
@@ -119,8 +260,9 @@ WebCPU_API.prototype = { | ||
119 | 260 | if((mode & 0x04) != 0){ |
120 | 261 | col = this.colorTable[col]; |
121 | 262 | } |
122 | - | |
263 | + /* | |
123 | 264 | this.mainWindowBufferContext.fillStyle = "#" + ("000000" + col.toString(16)).slice(-6).toUpperCase(); |
124 | 265 | this.mainWindowBufferContext.fillEllipse(x0, y0, xSize, ySize); |
266 | + */ | |
125 | 267 | }, |
126 | 268 | } |
@@ -67,14 +67,20 @@ function disableDebugMode(){ | ||
67 | 67 | } |
68 | 68 | |
69 | 69 | var stepInTimer = null; |
70 | +var autoStepInCount = 0; | |
70 | 71 | |
71 | 72 | function stepInMs(){ |
72 | 73 | stepInTimer = window.setInterval(stepInMs_Tick, 1); |
73 | 74 | } |
74 | 75 | |
75 | 76 | function stepInMs_Tick(){ |
76 | - if(mainCPU.executeStepIn() != 0){ | |
77 | + if(mainCPU.executeStepIn_Internal(false) != 0){ | |
77 | 78 | window.clearTimeout(stepInTimer); |
79 | + } else{ | |
80 | + autoStepInCount++; | |
81 | + if((autoStepInCount & 0xff) == 0){ | |
82 | + mainCPU.API.API_flushWin(mainCPU, mainCPU.API.mainWindowCanvas.width, mainCPU.API.mainWindowCanvas.height, 0, 0); | |
83 | + } | |
78 | 84 | } |
79 | 85 | } |
80 | 86 |
@@ -19,11 +19,11 @@ WebCPU_Instruction.prototype = { | ||
19 | 19 | }, |
20 | 20 | execute: function(env){ |
21 | 21 | //printXXXはデバッグ用 |
22 | - if(this.printSourceRegister){ | |
22 | + if(this.isEnabledPrintSourceRegister && this.printSourceRegister){ | |
23 | 23 | this.printSourceRegister(env); |
24 | 24 | } |
25 | 25 | this.instruction(env); |
26 | - if(this.printDestinationRegister){ | |
26 | + if(this.isEnabledPrintDestinationRegister && this.printDestinationRegister){ | |
27 | 27 | this.printDestinationRegister(env); |
28 | 28 | } |
29 | 29 | }, |
@@ -72,6 +72,8 @@ WebCPU_Instruction.prototype = { | ||
72 | 72 | return parseSignedInt32(argBinStr.substr(baseIndex + offset * 2, bytes * 2), 16); |
73 | 73 | }, |
74 | 74 | // |
75 | + isEnabledPrintSourceRegister: true, | |
76 | + isEnabledPrintDestinationRegister: true, | |
75 | 77 | printSourceRegister: null, |
76 | 78 | printDestinationRegister: null, |
77 | 79 | } |
@@ -0,0 +1,37 @@ | ||
1 | +*WebCPU-VM | |
2 | +By hikarupsp 2013-2014 for OSECPU-VM | |
3 | + | |
4 | +**これは何? | |
5 | +OSECPU-VMのJavaScript実装です。 | |
6 | +JavaScriptは、ほとんどの場合ウェブブラウザさえあれば実行できる言語なので、より多くの環境でOSECPUコードを実行させることができます。 | |
7 | +また、HTML5技術(Canvas)と連携することで、ウェブページに直接OSECPUコードを埋め込むこともできるようになるでしょう。 | |
8 | +これは、テキストを直接転送しているHTMLにとって、データの転送量を削減することにもつながります。 | |
9 | + | |
10 | +**動作環境 | |
11 | +動作を確認している環境は以下の通りです。(app0023フロントエンドコードテキストのStepInMs実行にて確認。) | |
12 | +-Chrome (Mac OSX, Windows) | |
13 | +-Safari (Mac OSX, iOS) | |
14 | +-Browser (Android) | |
15 | +-InternetExplorer9 (Windows) | |
16 | + | |
17 | +**現在の状況は? | |
18 | +-アプリケーションバイナリのフロントエンドコードHex文字列を実行し、その結果を表示することができます。 | |
19 | +-実行バイナリをドラッグ&ドロップで直接読み込ませ、実行させることができます(HTML5FileAPI対応ブラウザに限ります)。 | |
20 | +-バックエンド命令はほとんどが実装されていますが、APIおよびメモリ関連の一部の命令は未実装です。 | |
21 | + | |
22 | +**使い方は? | |
23 | +組み込んで使用する方は、index.htmlのサンプルコードを見ていただければ、だいたいはわかると思います。 | |
24 | +***テストページの操作方法 | |
25 | ++binaryCodeのところに、バイナリをHex文字列化したものを打ち込む | |
26 | +--もしくは実行バイナリファイルを直接読み込ませることもできます。 | |
27 | ++コードをLoadする | |
28 | +Loadボタンを押すことで、バイナリコードが解釈されてWebCPUで実行可能な状態になります。フロントエンドコードの場合、環境によってはデコードに少し時間がかかるかもしれません。 | |
29 | ++実行する | |
30 | +実行するときにはいくつかの方法があります。 | |
31 | +++StepIn:ステップ実行します。 | |
32 | +++StepInMs:1ミリ秒ごとに区切って実行します。デバッグ表示をしている間は最速で実行する方法です。 | |
33 | +++StepIn100:100ステップ実行します。 | |
34 | +++Execute:最速で実行します(デバッグモード有効時は使用しない方がよいです) | |
35 | +-デバッグモードについて | |
36 | +デバッグモード時は、実行中のレジスタ情報と現在実行中の命令について詳細を確認しながら実行できます。 | |
37 | +負荷のかかるアプリケーションを実行する際は、デバッグモードを無効にするのがよいでしょう。 |
@@ -1,3 +1,5 @@ | ||
1 | +//WebCPUは、このディレクトリにあるファイルで完結している。 | |
2 | + | |
1 | 3 | function WebCPU_Exception(errno, infoArray){ |
2 | 4 | this.errno = errno; |
3 | 5 | this.infoArray = infoArray; |
@@ -265,27 +267,29 @@ WebCPU.prototype = { | ||
265 | 267 | executeStepIn: function(){ |
266 | 268 | //ステップ実行する。 |
267 | 269 | //一回実行するたびに再描画する。 |
268 | - var retv = this.executeStepIn_Internal(); | |
269 | - this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0); | |
270 | + var retv = this.executeStepIn_Internal(true); | |
271 | + this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0); | |
270 | 272 | return retv; |
271 | 273 | }, |
272 | - executeStepIn_Internal: function(){ | |
274 | + executeStepIn_Internal: function(isManualStepIn){ | |
273 | 275 | //ステップ実行の内部部分。 |
274 | 276 | //終端到達時は1を、まだ後続命令がある場合は0を返す。 |
275 | 277 | //終了時にのみ再描画を行う |
276 | 278 | if(this.stopFlag){ |
277 | 279 | this.message(">stepIn:Break.\n", 2); |
278 | 280 | this.stopFlag = false; |
279 | - this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0); | |
281 | + this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0); | |
280 | 282 | return 2; |
281 | 283 | } |
282 | 284 | var instr = this.fetchMemoryNext(); |
283 | 285 | if(instr === undefined){ |
284 | 286 | this.message(">stepIn:control reached end of binary.\n", 2); |
285 | - this.API.API_flushWin(this, this.API.mainWindowBufferCanvas.width, this.API.mainWindowBufferCanvas.height, 0, 0); | |
287 | + this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0); | |
286 | 288 | return 1; |
287 | 289 | } |
288 | - this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20); | |
290 | + if(isManualStepIn){ | |
291 | + this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20); | |
292 | + } | |
289 | 293 | instr.execute(this); |
290 | 294 | //これ以降this.memoryInstructionCounterが今実行した命令を指すとは限らない。(JMP系命令のため) |
291 | 295 | /* |
@@ -300,7 +304,7 @@ WebCPU.prototype = { | ||
300 | 304 | execute: function(){ |
301 | 305 | //最速で実行する |
302 | 306 | for(;;){ |
303 | - if(this.executeStepIn_Internal() != 0){ | |
307 | + if(this.executeStepIn_Internal(false) != 0){ | |
304 | 308 | return; |
305 | 309 | } |
306 | 310 | } |
@@ -356,10 +360,14 @@ WebCPU.prototype = { | ||
356 | 360 | //すべて無効だったらタイマーの動作自体を止める |
357 | 361 | window.clearTimeout(this.messageTimer); |
358 | 362 | this.messageTimer = null; |
363 | + WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = false; | |
364 | + WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = false; | |
359 | 365 | } else if(!this.messageTimer){ |
360 | 366 | //どれかが有効でかつタイマーが止まっていたらスタートさせる |
361 | 367 | var that = this; |
362 | 368 | this.messageTimer = window.setInterval(function(){that.debugShowTick();}, 50); |
369 | + WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = true; | |
370 | + WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = true; | |
363 | 371 | } |
364 | 372 | }, |
365 | 373 | debugShowTick: function(){ |