Changeset 126283 in webkit
- Timestamp:
- Aug 22, 2012 2:19:06 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r126280 r126283 1 2012-08-22 Andrey Adaikin <aandrey@chromium.org> 2 3 Web Inspector: [WebGL] Generic framework draft for tracking WebGL resources 4 https://bugs.webkit.org/show_bug.cgi?id=90597 5 6 Reviewed by Pavel Feldman. 7 8 Wrap WebGL rendering context methods and collect a trace log if we are in capturing mode. 9 Stubbed code for collecting calls contributing to a WebGL resource state so that we could replay them later. 10 11 Typical scenario: 12 - we wrap a GL context with InjectedScript.wrapWebGLContext() and return a proxy to the inspected page 13 - the proxy saves all calls necessary to do a replay later - only those that modify a resource's state 14 - when we turn on capturing mode (InjectedScript.captureFrame), we save all WebGL calls to a trace log 15 16 * inspector/InjectedScriptSource.js: 17 (.): 18 * inspector/InjectedScriptWebGLModuleSource.js: 19 (.): 20 1 21 2012-08-22 Andrey Adaikin <aandrey@chromium.org> 2 22 -
trunk/Source/WebCore/inspector/InjectedScriptSource.js
r126168 r126283 555 555 }, 556 556 557 /** 558 * @param {string} name 559 * @return {Object} 560 */ 557 561 module: function(name) 558 562 { 559 563 return this._modules[name]; 560 564 }, 561 565 566 /** 567 * @param {string} name 568 * @param {string} source 569 * @return {Object} 570 */ 562 571 injectModule: function(name, source) 563 572 { 564 573 delete this._modules[name]; 565 var module = InjectedScriptHost.evaluate("(" + source + ")"); 574 var moduleFunction = InjectedScriptHost.evaluate("(" + source + ")"); 575 if (typeof moduleFunction !== "function") { 576 inspectedWindow.console.error("Web Inspector error: A function was expected for module %s evaluation", name); 577 return null; 578 } 579 var module = moduleFunction.call(inspectedWindow, InjectedScriptHost, inspectedWindow, injectedScriptId); 566 580 this._modules[name] = module; 567 581 return module; -
trunk/Source/WebCore/inspector/InjectedScriptWebGLModuleSource.js
r120957 r126283 31 31 /** 32 32 * @param {InjectedScriptHost} InjectedScriptHost 33 * @param {Window} inspectedWindow 34 * @param {number} injectedScriptId 33 35 */ 34 36 (function (InjectedScriptHost, inspectedWindow, injectedScriptId) { … … 37 39 * @constructor 38 40 */ 39 var InjectedScript = function() 40 { 41 this._lastBoundObjectId = 0; 42 this._idToWrapperProxy = {}; 43 this._idToRealWebGLContext = {}; 44 this._capturingFrameInfo = null; 45 } 46 47 InjectedScript.prototype = { 48 wrapWebGLContext: function(glContext) 49 { 50 for (var id in this._idToRealWebGLContext) { 51 if (this._idToRealWebGLContext[id] === glContext) 52 return this._idToWrapperProxy[id]; 53 } 54 55 var proxy = {}; 56 var nameProcessed = {}; 57 nameProcessed.__proto__ = null; 58 nameProcessed.constructor = true; 59 60 function processName(name) { 61 if (nameProcessed[name]) 62 return; 63 nameProcessed[name] = true; 64 if (typeof glContext[name] === "function") 65 proxy[name] = injectedScript._wrappedFunction.bind(injectedScript, glContext, name); 66 else 67 Object.defineProperty(proxy, name, { 41 function Cache() 42 { 43 this.reset(); 44 } 45 46 Cache.prototype = { 47 /** 48 * @return {number} 49 */ 50 size: function() 51 { 52 return this._size; 53 }, 54 55 reset: function() 56 { 57 this._items = Object.create(null); 58 this._size = 0; 59 }, 60 61 /** 62 * @param {number} key 63 * @return {boolean} 64 */ 65 has: function(key) 66 { 67 return key in this._items; 68 }, 69 70 /** 71 * @param {number} key 72 * @return {Object} 73 */ 74 get: function(key) 75 { 76 return this._items[key]; 77 }, 78 79 /** 80 * @param {number} key 81 * @param {Object} item 82 */ 83 put: function(key, item) 84 { 85 if (!this.has(key)) 86 ++this._size; 87 this._items[key] = item; 88 } 89 } 90 91 /** 92 * @constructor 93 * @param {Resource|Object} thisObject 94 * @param {string} functionName 95 * @param {Array|Arguments} args 96 * @param {Resource|*} result 97 */ 98 function Call(thisObject, functionName, args, result) 99 { 100 this._thisObject = thisObject; 101 this._functionName = functionName; 102 this._args = Array.prototype.slice.call(args, 0); 103 this._result = result; 104 } 105 106 Call.prototype = { 107 /** 108 * @return {Resource} 109 */ 110 resource: function() 111 { 112 return Resource.forObject(this._thisObject); 113 }, 114 115 /** 116 * @return {string} 117 */ 118 functionName: function() 119 { 120 return this._functionName; 121 }, 122 123 /** 124 * @return {Array} 125 */ 126 args: function() 127 { 128 return this._args; 129 }, 130 131 /** 132 * @return {*} 133 */ 134 result: function() 135 { 136 return this._result; 137 } 138 } 139 140 /** 141 * @constructor 142 * @param {Object} wrappedObject 143 */ 144 function Resource(wrappedObject) 145 { 146 this._id = ++Resource._uniqueId; 147 this._resourceManager = null; 148 this.setWrappedObject(wrappedObject); 149 } 150 151 Resource._uniqueId = 0; 152 153 /** 154 * @param {Object} obj 155 * @return {Resource} 156 */ 157 Resource.forObject = function(obj) 158 { 159 if (!obj || obj instanceof Resource) 160 return obj; 161 if (typeof obj === "object") 162 return obj["__resourceObject"]; 163 return null; 164 } 165 166 Resource.prototype = { 167 /** 168 * @return {number} 169 */ 170 id: function() 171 { 172 return this._id; 173 }, 174 175 /** 176 * @return {Object} 177 */ 178 wrappedObject: function() 179 { 180 return this._wrappedObject; 181 }, 182 183 /** 184 * @param {Object} value 185 */ 186 setWrappedObject: function(value) 187 { 188 console.assert(value && !(value instanceof Resource), "Binding a Resource object to another Resource object?"); 189 this._wrappedObject = value; 190 this._bindObjectToResource(value); 191 }, 192 193 /** 194 * @return {Object} 195 */ 196 proxyObject: function() 197 { 198 // No proxy wrapping by default. 199 return this.wrappedObject(); 200 }, 201 202 /** 203 * @return {ResourceTrackingManager} 204 */ 205 manager: function() 206 { 207 return this._resourceManager; 208 }, 209 210 /** 211 * @param {ResourceTrackingManager} value 212 */ 213 setManager: function(value) 214 { 215 this._resourceManager = value; 216 }, 217 218 /** 219 * @param {Object} object 220 */ 221 _bindObjectToResource: function(object) 222 { 223 object["__resourceObject"] = this; 224 } 225 } 226 227 /** 228 * @constructor 229 * @extends {Resource} 230 * @param {WebGLRenderingContext} glContext 231 */ 232 function WebGLRenderingContextResource(glContext) 233 { 234 Resource.call(this, glContext); 235 this._proxyObject = null; 236 } 237 238 WebGLRenderingContextResource.prototype = { 239 /** 240 * @return {Object} 241 */ 242 proxyObject: function() 243 { 244 if (!this._proxyObject) 245 this._proxyObject = this._wrapObject(); 246 return this._proxyObject; 247 }, 248 249 /** 250 * @return {Object} 251 */ 252 _wrapObject: function() 253 { 254 var glContext = this.wrappedObject(); 255 var proxy = Object.create(glContext.__proto__); // In order to emulate "instanceof". 256 257 var self = this; 258 function processProperty(property) 259 { 260 if (typeof glContext[property] === "function") { 261 // FIXME: override GL calls affecting resources states here. 262 proxy[property] = self._wrapFunction(self, glContext, glContext[property], property); 263 } else if (/^[A-Z0-9_]+$/.test(property)) { 264 // Fast access to enums and constants. 265 proxy[property] = glContext[property]; 266 } else { 267 Object.defineProperty(proxy, property, { 68 268 get: function() 69 269 { 70 return glContext[ name];270 return glContext[property]; 71 271 }, 72 272 set: function(value) 73 273 { 74 glContext[ name] = value;274 glContext[property] = value; 75 275 } 76 276 }); 277 } 77 278 } 78 279 79 for (var o = glContext; o; o = o.__proto__) 80 Object.getOwnPropertyNames(o).forEach(processName); 81 82 // In order to emulate "instanceof". 83 proxy.__proto__ = glContext.__proto__; 84 proxy.constructor = glContext.constructor; 85 86 var contextId = this._generateObjectId(); 87 this._idToWrapperProxy[contextId] = proxy; 88 this._idToRealWebGLContext[contextId] = glContext; 89 InjectedScriptHost.webGLContextCreated(contextId); 280 for (var property in glContext) 281 processProperty(property); 90 282 91 283 return proxy; 92 284 }, 93 285 94 _generateObjectId: function() 95 { 96 var id = ++this._lastBoundObjectId; 97 var objectId = "{\"injectedScriptId\":" + injectedScriptId + ",\"webGLId\":" + id + "}"; 98 return objectId; 99 }, 100 101 captureFrame: function(contextId) 102 { 103 this._capturingFrameInfo = { 104 contextId: contextId, 105 capturedCallsNum: 0 286 /** 287 * @param {Resource} resource 288 * @param {WebGLRenderingContext} originalObject 289 * @param {Function} originalFunction 290 * @param {string} functionName 291 * @return {*} 292 */ 293 _wrapFunction: function(resource, originalObject, originalFunction, functionName) 294 { 295 return function() 296 { 297 var manager = resource.manager(); 298 if (!manager || !manager.capturing()) 299 return originalFunction.apply(originalObject, arguments); 300 manager.captureArguments(resource, arguments); 301 var result = originalFunction.apply(originalObject, arguments); 302 var call = new Call(resource, functionName, arguments, result); 303 manager.reportCall(call); 304 return result; 106 305 }; 107 }, 108 109 _stopCapturing: function(info) 110 { 111 if (this._capturingFrameInfo === info) 112 this._capturingFrameInfo = null; 113 }, 114 115 _wrappedFunction: function(glContext, functionName) 116 { 117 // Call real WebGL function. 118 var args = Array.prototype.slice.call(arguments, 2); 119 var result = glContext[functionName].apply(glContext, args); 120 121 if (this._capturingFrameInfo && this._idToRealWebGLContext[this._capturingFrameInfo.contextId] === glContext) { 122 var capturedCallsNum = ++this._capturingFrameInfo.capturedCallsNum; 123 if (capturedCallsNum === 1) 124 this._setZeroTimeouts(this._stopCapturing.bind(this, this._capturingFrameInfo)); 125 InjectedScriptHost.webGLReportFunctionCall(this._capturingFrameInfo.contextId, functionName, "[" + args.join(", ") + "]", result + ""); 306 } 307 } 308 309 WebGLRenderingContextResource.prototype.__proto__ = Resource.prototype; 310 311 /** 312 * @constructor 313 * @param {WebGLRenderingContext} originalObject 314 * @param {Function} originalFunction 315 * @param {string} functionName 316 * @param {Array} args 317 */ 318 WebGLRenderingContextResource.WrapFunction = function(originalObject, originalFunction, functionName, args) 319 { 320 this._originalObject = originalObject; 321 this._originalFunction = originalFunction; 322 this._functionName = functionName; 323 this._args = args; 324 this._glResource = Resource.forObject(originalObject); 325 } 326 327 WebGLRenderingContextResource.WrapFunction.prototype = { 328 /** 329 * @return {*} 330 */ 331 result: function() 332 { 333 if (!this._executed) { 334 this._executed = true; 335 this._result = this._originalFunction.apply(this._originalObject, this._args); 126 336 } 127 128 return result; 129 }, 130 337 return this._result; 338 }, 339 340 /** 341 * @return {Call} 342 */ 343 call: function() 344 { 345 if (!this._call) 346 this._call = new Call(this._glResource, this._functionName, this._args, this.result()); 347 return this._call; 348 } 349 } 350 351 /** 352 * @constructor 353 */ 354 function TraceLog() 355 { 356 this._calls = []; 357 this._resourceCache = new Cache(); 358 } 359 360 TraceLog.prototype = { 361 /** 362 * @return {number} 363 */ 364 size: function() 365 { 366 return this._calls.length; 367 }, 368 369 /** 370 * @param {Resource} resource 371 */ 372 captureResource: function(resource) 373 { 374 // FIXME: Capture current resource state to start the replay from. 375 }, 376 377 /** 378 * @param {Call} call 379 */ 380 addCall: function(call) 381 { 382 // FIXME: Clone call and push the clone. 383 this._calls.push(call); 384 } 385 } 386 387 /** 388 * @constructor 389 */ 390 function ResourceTrackingManager() 391 { 392 this._capturing = false; 393 this._stopCapturingOnFrameEnd = false; 394 this._lastTraceLog = null; 395 } 396 397 ResourceTrackingManager.prototype = { 398 /** 399 * @return {boolean} 400 */ 401 capturing: function() 402 { 403 return this._capturing; 404 }, 405 406 /** 407 * @return {TraceLog} 408 */ 409 lastTraceLog: function() 410 { 411 return this._lastTraceLog; 412 }, 413 414 /** 415 * @param {Resource} resource 416 */ 417 registerResource: function(resource) 418 { 419 resource.setManager(this); 420 }, 421 422 startCapturing: function() 423 { 424 if (!this._capturing) 425 this._lastTraceLog = new TraceLog(); 426 this._capturing = true; 427 this._stopCapturingOnFrameEnd = false; 428 }, 429 430 /** 431 * @param {TraceLog=} traceLog 432 */ 433 stopCapturing: function(traceLog) 434 { 435 if (traceLog && this._lastTraceLog !== traceLog) 436 return; 437 this._capturing = false; 438 this._stopCapturingOnFrameEnd = false; 439 }, 440 441 captureFrame: function() 442 { 443 this._lastTraceLog = new TraceLog(); 444 this._capturing = true; 445 this._stopCapturingOnFrameEnd = true; 446 }, 447 448 captureArguments: function(resource, args) 449 { 450 if (!this._capturing) 451 return; 452 this._lastTraceLog.captureResource(resource); 453 for (var i = 0, n = args.length; i < n; ++i) { 454 var res = Resource.forObject(args[i]); 455 if (res) 456 this._lastTraceLog.captureResource(res); 457 } 458 }, 459 460 /** 461 * @param {Call} call 462 */ 463 reportCall: function(call) 464 { 465 if (!this._capturing) 466 return; 467 this._lastTraceLog.addCall(call); 468 if (this._stopCapturingOnFrameEnd && this._lastTraceLog.size() === 1) { 469 this._stopCapturingOnFrameEnd = false; 470 this._setZeroTimeouts(this.stopCapturing.bind(this, this._lastTraceLog)); 471 } 472 }, 473 474 /** 475 * @param {Function} callback 476 */ 131 477 _setZeroTimeouts: function(callback) 132 478 { … … 138 484 inspectedWindow.setTimeout(callback, 0); 139 485 } 140 }; 486 } 487 488 /** 489 * @constructor 490 */ 491 var InjectedScript = function() 492 { 493 this._manager = new ResourceTrackingManager(); 494 } 495 496 InjectedScript.prototype = { 497 /** 498 * @param {WebGLRenderingContext} glContext 499 * @return {Object} 500 */ 501 wrapWebGLContext: function(glContext) 502 { 503 var resource = Resource.forObject(glContext) || new WebGLRenderingContextResource(glContext); 504 this._manager.registerResource(resource); 505 var proxy = resource.proxyObject(); 506 return proxy; 507 }, 508 509 captureFrame: function() 510 { 511 this._manager.captureFrame(); 512 } 513 } 141 514 142 515 var injectedScript = new InjectedScript(); -
trunk/Source/WebCore/inspector/compile-front-end.py
r126012 r126283 378 378 os.system(command) 379 379 os.system("rm " + inspector_path + "/" + "InjectedScriptSourceTmp.js") 380 381 print "Compiling InjectedScriptWebGLModuleSource.js..." 382 os.system("echo \"var injectedScriptWebGLModuleValue = \" > " + inspector_path + "/" + "InjectedScriptWebGLModuleSourceTmp.js") 383 os.system("cat " + inspector_path + "/" + "InjectedScriptWebGLModuleSource.js" + " >> " + inspector_path + "/" + "InjectedScriptWebGLModuleSourceTmp.js") 384 command = compiler_command 385 command += " --externs " + inspector_path + "/" + "InjectedScriptExterns.js" + " \\\n" 386 command += " --module " + jsmodule_name_prefix + "injected_script" + ":" + "1" + " \\\n" 387 command += " --js " + inspector_path + "/" + "InjectedScriptWebGLModuleSourceTmp.js" + " \\\n" 388 command += "\n" 389 os.system(command) 390 os.system("rm " + inspector_path + "/" + "InjectedScriptWebGLModuleSourceTmp.js")
Note: See TracChangeset
for help on using the changeset viewer.