Changeset 126747 in webkit
- Timestamp:
- Aug 27, 2012 4:38:44 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r126746 r126747 1 2012-08-27 Andrey Adaikin <aandrey@chromium.org> 2 3 Web Inspector: [WebGL] Implement serializing WebGL state and replaying it later 4 https://bugs.webkit.org/show_bug.cgi?id=94933 5 6 Reviewed by Pavel Feldman. 7 8 This will allow us to save the WebGL state at any arbitrary point in order to replay a trace log later on another canvas. 9 Main points of the change: 10 - Allow every Resource and Call instances be serialized to a Replayable, and resurrected back during a replay on another canvas. 11 12 - Before executing an original WebGL call and saving it to a trace log, first serialize all the Resources that will be involved in 13 this call, if they are not yet serialized. The latter part is implemented with a Cache instance, checking that we convert a Resource 14 to a Replayable only once: the first time it was used in the trace log being collected. We do not need to serialize the subsequent 15 changes to this Resource's state (if any), since they will be saved in the trace log being collected and replayed automatically. 16 17 - Some information about the WebGL state may be requested in the runtime (e.g. with the gl.getParameter method). We use this wherever 18 possible instead of collecting Calls in a Resource log. Otherwise, we have to collect WebGL calls (like gl.texImage2D) in order to 19 replay them later. 20 21 - Later the Replayable objects hierarchy (the TraceLog) may be serialized further for cross-device transmission, for example. 22 23 24 * inspector/InjectedScriptWebGLModuleSource.js: 25 (.): 26 27 2012-08-27 Sheriff Bot <webkit.review.bot@gmail.com> 28 29 Unreviewed, rolling out r126694 and r126731. 30 http://trac.webkit.org/changeset/126694 31 http://trac.webkit.org/changeset/126731 32 https://bugs.webkit.org/show_bug.cgi?id=95069 33 34 Causes all pages to be rendered as a completely black page in 35 Qt WebKit2 (Requested by carewolf on #webkit). 36 37 * platform/graphics/GraphicsContext3D.h: 38 * platform/graphics/texmap/TextureMapperGL.cpp: 39 (SharedGLData): 40 (WebCore::TextureMapperGLData::SharedGLData::getCurrentGLContext): 41 (WebCore::TextureMapperGLData::SharedGLData::currentSharedGLData): 42 (WebCore::TextureMapperGLData::SharedGLData::SharedGLData): 43 (WebCore::TextureMapperGLData::sharedGLData): 44 (WebCore::TextureMapperGLData::TextureMapperGLData): 45 (TextureMapperGLData): 46 (WebCore::scissorClip): 47 (WebCore::TextureMapperGL::ClipStack::apply): 48 (WebCore::TextureMapperGLData::initializeStencil): 49 (WebCore::TextureMapperGL::TextureMapperGL): 50 (WebCore::TextureMapperGL::beginPainting): 51 (WebCore::TextureMapperGL::endPainting): 52 (WebCore::TextureMapperGL::drawQuad): 53 (WebCore::TextureMapperGL::drawBorder): 54 (WebCore): 55 (WebCore::TextureMapperGL::drawTextureRectangleARB): 56 (WebCore::TextureMapperGL::drawTexture): 57 (WebCore::viewportMatrix): 58 (WebCore::TextureMapperGL::drawTextureWithAntialiasing): 59 (WebCore::TextureMapperGL::drawTexturedQuadWithProgram): 60 (WebCore::BitmapTextureGL::didReset): 61 (WebCore::BitmapTextureGL::updateContents): 62 (WebCore::TextureMapperGL::drawFiltered): 63 (WebCore::BitmapTextureGL::initializeStencil): 64 (WebCore::BitmapTextureGL::clearIfNeeded): 65 (WebCore::BitmapTextureGL::createFboIfNeeded): 66 (WebCore::BitmapTextureGL::bind): 67 (WebCore::BitmapTextureGL::~BitmapTextureGL): 68 (WebCore::TextureMapperGL::bindDefaultSurface): 69 (WebCore::TextureMapperGL::beginScissorClip): 70 (WebCore::TextureMapperGL::beginClip): 71 (WebCore::TextureMapperGL::endClip): 72 (WebCore::TextureMapperGL::createTexture): 73 * platform/graphics/texmap/TextureMapperGL.h: 74 (TextureMapperGL): 75 (ClipStack): 76 (WebCore::BitmapTextureGL::textureTarget): 77 (BitmapTextureGL): 78 (WebCore::BitmapTextureGL::BitmapTextureGL): 79 * platform/graphics/texmap/TextureMapperShaderManager.cpp: 80 (WebCore): 81 (WebCore::TextureMapperShaderManager::getShaderProgram): 82 (WebCore::TextureMapperShaderProgram::TextureMapperShaderProgram): 83 (WebCore::TextureMapperShaderProgram::initializeProgram): 84 (WebCore::TextureMapperShaderProgram::getUniformLocation): 85 (WebCore::TextureMapperShaderProgram::~TextureMapperShaderProgram): 86 (WebCore::TextureMapperShaderProgramSimple::TextureMapperShaderProgramSimple): 87 (WebCore::TextureMapperShaderProgramSolidColor::TextureMapperShaderProgramSolidColor): 88 (WebCore::TextureMapperShaderProgramRectSimple::TextureMapperShaderProgramRectSimple): 89 (WebCore::TextureMapperShaderProgramOpacityAndMask::TextureMapperShaderProgramOpacityAndMask): 90 (WebCore::TextureMapperShaderProgramRectOpacityAndMask::TextureMapperShaderProgramRectOpacityAndMask): 91 (WebCore::TextureMapperShaderProgramAntialiasingNoMask::TextureMapperShaderProgramAntialiasingNoMask): 92 (WebCore::TextureMapperShaderManager::TextureMapperShaderManager): 93 (WebCore::StandardFilterProgram::~StandardFilterProgram): 94 (WebCore::StandardFilterProgram::StandardFilterProgram): 95 (WebCore::StandardFilterProgram::create): 96 (WebCore::StandardFilterProgram::prepare): 97 (WebCore::TextureMapperShaderManager::getShaderForFilter): 98 * platform/graphics/texmap/TextureMapperShaderManager.h: 99 (WebCore::TextureMapperShaderProgram::id): 100 (WebCore::TextureMapperShaderProgram::vertexAttrib): 101 (TextureMapperShaderProgram): 102 (WebCore::TextureMapperShaderProgram::matrixLocation): 103 (WebCore::TextureMapperShaderProgram::flipLocation): 104 (WebCore::TextureMapperShaderProgram::textureSizeLocation): 105 (WebCore::TextureMapperShaderProgram::sourceTextureLocation): 106 (WebCore::TextureMapperShaderProgram::maskTextureLocation): 107 (WebCore::TextureMapperShaderProgram::opacityLocation): 108 (WebCore::TextureMapperShaderProgram::isValidUniformLocation): 109 (StandardFilterProgram): 110 (WebCore::StandardFilterProgram::vertexAttrib): 111 (WebCore::StandardFilterProgram::texCoordAttrib): 112 (WebCore::StandardFilterProgram::textureUniform): 113 (WebCore::TextureMapperShaderProgramSimple::create): 114 (TextureMapperShaderProgramSimple): 115 (WebCore::TextureMapperShaderProgramRectSimple::create): 116 (WebCore::TextureMapperShaderProgramOpacityAndMask::create): 117 (WebCore::TextureMapperShaderProgramRectOpacityAndMask::create): 118 (WebCore::TextureMapperShaderProgramSolidColor::create): 119 (WebCore::TextureMapperShaderProgramSolidColor::colorLocation): 120 (TextureMapperShaderProgramSolidColor): 121 (WebCore::TextureMapperShaderProgramAntialiasingNoMask::create): 122 (WebCore::TextureMapperShaderProgramAntialiasingNoMask::expandedQuadVerticesInTextureCoordinatesLocation): 123 (WebCore::TextureMapperShaderProgramAntialiasingNoMask::expandedQuadEdgesInScreenSpaceLocation): 124 (TextureMapperShaderProgramAntialiasingNoMask): 125 1 126 2012-08-27 Ilya Tikhonovsky <loislo@chromium.org> 2 127 -
trunk/Source/WebCore/inspector/InjectedScriptWebGLModuleSource.js
r126585 r126747 246 246 this._args[i] = TypeUtils.clone(this._args[i]); 247 247 } 248 }, 249 250 /** 251 * @param {Cache} cache 252 * @return {ReplayableCall} 253 */ 254 toReplayable: function(cache) 255 { 256 this.freeze(); 257 var thisObject = /** @type {ReplayableResource} */ Resource.toReplayable(this._thisObject, cache); 258 var result = Resource.toReplayable(this._result, cache); 259 var args = this._args.map(function(obj) { 260 return Resource.toReplayable(obj, cache); 261 }); 262 return new ReplayableCall(thisObject, this._functionName, args, result); 263 }, 264 265 /** 266 * @param {ReplayableCall} replayableCall 267 * @param {Cache} cache 268 * @return {Call} 269 */ 270 replay: function(replayableCall, cache) 271 { 272 var replayObject = ReplayableResource.replay(replayableCall.resource(), cache); 273 var replayFunction = replayObject[replayableCall.functionName()]; 274 console.assert(typeof replayFunction === "function", "Expected a function to replay"); 275 var replayArgs = replayableCall.args().map(function(obj) { 276 return ReplayableResource.replay(obj, cache); 277 }); 278 var replayResult = replayFunction.apply(replayObject, replayArgs); 279 if (replayableCall.result() instanceof ReplayableResource) { 280 var resource = replayableCall.result().replay(cache); 281 if (!resource.wrappedObject()) 282 resource.setWrappedObject(replayResult); 283 } 284 285 this._thisObject = replayObject; 286 this._functionName = replayableCall.functionName(); 287 this._args = replayArgs; 288 this._result = replayResult; 289 this._freezed = true; 290 return this; 248 291 } 249 292 } … … 303 346 replay: function(cache) 304 347 { 305 // FIXME: Do the replay. 348 var call = Object.create(Call.prototype); 349 return call.replay(this, cache); 306 350 } 307 351 } … … 339 383 } 340 384 385 /** 386 * @param {Resource|*} obj 387 * @param {Cache} cache 388 * @return {ReplayableResource|*} 389 */ 390 Resource.toReplayable = function(obj, cache) 391 { 392 var resource = Resource.forObject(obj); 393 return resource ? resource.toReplayable(cache) : obj; 394 } 395 341 396 Resource.prototype = { 342 397 /** … … 401 456 402 457 /** 458 * @param {Cache} cache 459 * @return {ReplayableResource} 460 */ 461 toReplayable: function(cache) 462 { 463 var result = cache.get(this._id); 464 if (result) 465 return result; 466 var data = { 467 id: this._id 468 }; 469 result = new ReplayableResource(this, data); 470 cache.put(this._id, result); // Put into the cache early to avoid loops. 471 data.calls = this._calls.map(function(call) { 472 return call.toReplayable(cache); 473 }); 474 this._populateReplayableData(data, cache); 475 return result; 476 }, 477 478 /** 479 * @param {Object} data 480 * @param {Cache} cache 481 */ 482 _populateReplayableData: function(data, cache) 483 { 484 // Do nothing. Should be overridden by subclasses. 485 }, 486 487 /** 488 * @param {Object} data 489 * @param {Cache} cache 490 * @return {Resource} 491 */ 492 replay: function(data, cache) 493 { 494 var resource = cache.get(data.id); 495 if (resource) 496 return resource; 497 this._id = data.id; 498 this._resourceManager = null; 499 this._calls = []; 500 this._wrappedObject = null; 501 cache.put(data.id, this); // Put into the cache early to avoid loops. 502 this._doReplayCalls(data, cache); 503 console.assert(this._wrappedObject, "Resource should be reconstructed!"); 504 return this; 505 }, 506 507 /** 508 * @param {Object} data 509 * @param {Cache} cache 510 */ 511 _doReplayCalls: function(data, cache) 512 { 513 for (var i = 0, n = data.calls.length; i < n; ++i) 514 this._calls.push(data.calls[i].replay(cache)); 515 }, 516 517 /** 403 518 * @param {Call} call 404 519 */ … … 425 540 function ReplayableResource(originalResource, data) 426 541 { 542 this._proto = originalResource.__proto__; 543 this._data = data; 427 544 } 428 545 … … 434 551 replay: function(cache) 435 552 { 436 // FIXME: Do the replay. 437 } 553 var result = Object.create(this._proto); 554 result = result.replay(this._data, cache) 555 console.assert(result.__proto__ === this._proto, "Wrong type of a replay result"); 556 return result; 557 } 558 } 559 560 /** 561 * @param {ReplayableResource|*} obj 562 * @param {Cache} cache 563 * @return {*} 564 */ 565 ReplayableResource.replay = function(obj, cache) 566 { 567 return (obj instanceof ReplayableResource) ? obj.replay(cache).wrappedObject() : obj; 438 568 } 439 569 … … 449 579 450 580 WebGLBoundResource.prototype = { 581 /** 582 * @override 583 * @param {Object} data 584 * @param {Cache} cache 585 */ 586 _populateReplayableData: function(data, cache) 587 { 588 var state = this._state; 589 data.state = {}; 590 Object.keys(state).forEach(function(parameter) { 591 data.state[parameter] = Resource.toReplayable(state[parameter], cache); 592 }); 593 }, 594 595 /** 596 * @override 597 * @param {Object} data 598 * @param {Cache} cache 599 */ 600 _doReplayCalls: function(data, cache) 601 { 602 var state = {}; 603 Object.keys(data.state).forEach(function(parameter) { 604 state[parameter] = ReplayableResource.replay(data.state[parameter], cache); 605 }); 606 this._state = state; 607 608 var gl = this._replayContextResource(data, cache).wrappedObject(); 609 610 var bindingsData = { 611 TEXTURE_2D: ["bindTexture", "TEXTURE_BINDING_2D"], 612 TEXTURE_CUBE_MAP: ["bindTexture", "TEXTURE_BINDING_CUBE_MAP"], 613 ARRAY_BUFFER: ["bindBuffer", "ARRAY_BUFFER_BINDING"], 614 ELEMENT_ARRAY_BUFFER: ["bindBuffer", "ELEMENT_ARRAY_BUFFER_BINDING"], 615 FRAMEBUFFER: ["bindFramebuffer", "FRAMEBUFFER_BINDING"], 616 RENDERBUFFER: ["bindRenderbuffer", "RENDERBUFFER_BINDING"] 617 }; 618 var originalBindings = {}; 619 Object.keys(bindingsData).forEach(function(bindingTarget) { 620 var bindingParameter = bindingsData[bindingTarget][1]; 621 originalBindings[bindingTarget] = gl.getParameter(gl[bindingParameter]); 622 }); 623 624 Resource.prototype._doReplayCalls.call(this, data, cache); 625 626 Object.keys(bindingsData).forEach(function(bindingTarget) { 627 var bindMethodName = bindingsData[bindingTarget][0]; 628 gl[bindMethodName].call(gl, gl[bindingTarget], originalBindings[bindingTarget]); 629 }); 630 }, 631 632 _replayContextResource: function(data, cache) 633 { 634 var calls = data.calls; 635 for (var i = 0, n = calls.length; i < n; ++i) { 636 var resource = ReplayableResource.replay(calls[i].resource(), cache); 637 var contextResource = WebGLRenderingContextResource.forObject(resource); 638 if (contextResource) 639 return contextResource; 640 } 641 return null; 642 }, 643 451 644 /** 452 645 * @param {number} target … … 474 667 475 668 WebGLTextureResource.prototype = { 476 /** @inheritDoc */ 669 /** 670 * @override 671 * @param {Object} data 672 * @param {Cache} cache 673 */ 674 _doReplayCalls: function(data, cache) 675 { 676 var gl = this._replayContextResource(data, cache).wrappedObject(); 677 678 var state = {}; 679 WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) { 680 state[parameter] = gl.getParameter(gl[parameter]); 681 }); 682 683 WebGLBoundResource.prototype._doReplayCalls.call(this, data, cache); 684 685 WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) { 686 gl.pixelStorei(gl[parameter], state[parameter]); 687 }); 688 }, 689 690 /** 691 * @override 692 * @param {Call} call 693 */ 477 694 pushCall: function(call) 478 695 { … … 537 754 } 538 755 756 /** 757 * @type {Object.<number,string>} 758 */ 759 WebGLProgramResource.UniformMethodNames = null; 760 539 761 WebGLProgramResource.prototype = { 540 /** @inheritDoc */ 762 /** 763 * @override 764 * @param {Object} data 765 * @param {Cache} cache 766 */ 767 _populateReplayableData: function(data, cache) 768 { 769 var gl = WebGLRenderingContextResource.forObject(this).wrappedObject(); 770 var program = this.wrappedObject(); 771 772 var uniforms = []; 773 var uniformsCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); 774 for (var i = 0; i < uniformsCount; ++i) { 775 var activeInfo = gl.getActiveUniform(program, i); 776 if (!activeInfo) 777 continue; 778 var uniformLocation = gl.getUniformLocation(program, activeInfo.name); 779 if (!uniformLocation) 780 continue; 781 var value = gl.getUniform(program, uniformLocation); 782 uniforms.push({ 783 name: activeInfo.name, 784 type: activeInfo.type, 785 value: value 786 }); 787 } 788 data.uniforms = uniforms; 789 }, 790 791 /** 792 * @override 793 * @param {Object} data 794 * @param {Cache} cache 795 */ 796 _doReplayCalls: function(data, cache) 797 { 798 Resource.prototype._doReplayCalls.call(this, data, cache); 799 var gl = WebGLRenderingContextResource.forObject(this).wrappedObject(); 800 var program = this.wrappedObject(); 801 802 var originalProgram = gl.getParameter(gl.CURRENT_PROGRAM); 803 var currentProgram = originalProgram; 804 805 data.uniforms.forEach(function(uniform) { 806 var uniformLocation = gl.getUniformLocation(program, uniform.name); 807 if (!uniformLocation) 808 return; 809 if (currentProgram !== program) { 810 currentProgram = program; 811 gl.useProgram(program); 812 } 813 var methodName = this._uniformMethodNameByType(gl, uniform.type); 814 if (methodName.indexOf("Matrix") === -1) 815 gl[methodName].call(gl, uniformLocation, uniform.value); 816 else 817 gl[methodName].call(gl, uniformLocation, false, uniform.value); 818 }.bind(this)); 819 820 if (currentProgram !== originalProgram) 821 gl.useProgram(originalProgram); 822 }, 823 824 /** 825 * @param {WebGLRenderingContext} gl 826 * @param {number} type 827 * @return {string} 828 */ 829 _uniformMethodNameByType: function(gl, type) 830 { 831 var uniformMethodNames = WebGLProgramResource.UniformMethodNames; 832 if (!uniformMethodNames) { 833 uniformMethodNames = {}; 834 uniformMethodNames[gl.FLOAT] = "uniform1f"; 835 uniformMethodNames[gl.FLOAT_VEC2] = "uniform2fv"; 836 uniformMethodNames[gl.FLOAT_VEC3] = "uniform3fv"; 837 uniformMethodNames[gl.FLOAT_VEC4] = "uniform4fv"; 838 uniformMethodNames[gl.INT] = "uniform1i"; 839 uniformMethodNames[gl.BOOL] = "uniform1i"; 840 uniformMethodNames[gl.SAMPLER_2D] = "uniform1i"; 841 uniformMethodNames[gl.SAMPLER_CUBE] = "uniform1i"; 842 uniformMethodNames[gl.INT_VEC2] = "uniform2iv"; 843 uniformMethodNames[gl.BOOL_VEC2] = "uniform2iv"; 844 uniformMethodNames[gl.INT_VEC3] = "uniform3iv"; 845 uniformMethodNames[gl.BOOL_VEC3] = "uniform3iv"; 846 uniformMethodNames[gl.INT_VEC4] = "uniform4iv"; 847 uniformMethodNames[gl.BOOL_VEC4] = "uniform4iv"; 848 uniformMethodNames[gl.FLOAT_MAT2] = "uniformMatrix2fv"; 849 uniformMethodNames[gl.FLOAT_MAT3] = "uniformMatrix3fv"; 850 uniformMethodNames[gl.FLOAT_MAT4] = "uniformMatrix4fv"; 851 WebGLProgramResource.UniformMethodNames = uniformMethodNames; 852 } 853 console.assert(uniformMethodNames[type], "Unknown uniform type " + type); 854 return uniformMethodNames[type]; 855 }, 856 857 /** 858 * @override 859 * @param {Call} call 860 */ 541 861 pushCall: function(call) 542 862 { … … 559 879 560 880 WebGLShaderResource.prototype = { 561 /** @inheritDoc */ 881 /** 882 * @override 883 * @param {Call} call 884 */ 562 885 pushCall: function(call) 563 886 { … … 580 903 581 904 WebGLBufferResource.prototype = { 582 /** @inheritDoc */ 905 /** 906 * @override 907 * @param {Call} call 908 */ 583 909 pushCall: function(call) 584 910 { … … 601 927 602 928 WebGLFramebufferResource.prototype = { 603 /** @inheritDoc */ 929 /** 930 * @override 931 * @param {Call} call 932 */ 604 933 pushCall: function(call) 605 934 { … … 621 950 622 951 WebGLRenderbufferResource.prototype = { 623 /** @inheritDoc */ 952 /** 953 * @override 954 * @param {Call} call 955 */ 624 956 pushCall: function(call) 625 957 { … … 635 967 * @extends {Resource} 636 968 * @param {WebGLRenderingContext} glContext 637 */ 638 function WebGLRenderingContextResource(glContext) 969 * @param {Function} replayContextCallback 970 */ 971 function WebGLRenderingContextResource(glContext, replayContextCallback) 639 972 { 640 973 Resource.call(this, glContext); 641 974 this._proxyObject = null; 642 } 975 this._replayContextCallback = replayContextCallback; 976 } 977 978 /** 979 * @const 980 * @type {Array.<string>} 981 */ 982 WebGLRenderingContextResource.GLCapabilities = [ 983 "BLEND", 984 "CULL_FACE", 985 "DEPTH_TEST", 986 "DITHER", 987 "POLYGON_OFFSET_FILL", 988 "SAMPLE_ALPHA_TO_COVERAGE", 989 "SAMPLE_COVERAGE", 990 "SCISSOR_TEST", 991 "STENCIL_TEST" 992 ]; 643 993 644 994 /** … … 652 1002 "UNPACK_FLIP_Y_WEBGL", 653 1003 "UNPACK_PREMULTIPLY_ALPHA_WEBGL" 1004 ]; 1005 1006 /** 1007 * @const 1008 * @type {Array.<string>} 1009 */ 1010 WebGLRenderingContextResource.StateParameters = [ 1011 "ACTIVE_TEXTURE", 1012 "ARRAY_BUFFER_BINDING", 1013 "BLEND_COLOR", 1014 "BLEND_DST_ALPHA", 1015 "BLEND_DST_RGB", 1016 "BLEND_EQUATION_ALPHA", 1017 "BLEND_EQUATION_RGB", 1018 "BLEND_SRC_ALPHA", 1019 "BLEND_SRC_RGB", 1020 "COLOR_CLEAR_VALUE", 1021 "COLOR_WRITEMASK", 1022 "CULL_FACE_MODE", 1023 "CURRENT_PROGRAM", 1024 "DEPTH_CLEAR_VALUE", 1025 "DEPTH_FUNC", 1026 "DEPTH_RANGE", 1027 "DEPTH_WRITEMASK", 1028 "ELEMENT_ARRAY_BUFFER_BINDING", 1029 "FRAMEBUFFER_BINDING", 1030 "FRONT_FACE", 1031 "GENERATE_MIPMAP_HINT", 1032 "LINE_WIDTH", 1033 "PACK_ALIGNMENT", 1034 "POLYGON_OFFSET_FACTOR", 1035 "POLYGON_OFFSET_UNITS", 1036 "RENDERBUFFER_BINDING", 1037 "SAMPLE_COVERAGE_INVERT", 1038 "SAMPLE_COVERAGE_VALUE", 1039 "SCISSOR_BOX", 1040 "STENCIL_BACK_FAIL", 1041 "STENCIL_BACK_FUNC", 1042 "STENCIL_BACK_PASS_DEPTH_FAIL", 1043 "STENCIL_BACK_PASS_DEPTH_PASS", 1044 "STENCIL_BACK_REF", 1045 "STENCIL_BACK_VALUE_MASK", 1046 "STENCIL_BACK_WRITEMASK", 1047 "STENCIL_CLEAR_VALUE", 1048 "STENCIL_FAIL", 1049 "STENCIL_FUNC", 1050 "STENCIL_PASS_DEPTH_FAIL", 1051 "STENCIL_PASS_DEPTH_PASS", 1052 "STENCIL_REF", 1053 "STENCIL_VALUE_MASK", 1054 "STENCIL_WRITEMASK", 1055 "UNPACK_ALIGNMENT", 1056 "UNPACK_COLORSPACE_CONVERSION_WEBGL", 1057 "UNPACK_FLIP_Y_WEBGL", 1058 "UNPACK_PREMULTIPLY_ALPHA_WEBGL", 1059 "VIEWPORT" 654 1060 ]; 655 1061 … … 682 1088 683 1089 /** 1090 * @override 1091 * @param {Object} data 1092 * @param {Cache} cache 1093 */ 1094 _populateReplayableData: function(data, cache) 1095 { 1096 var gl = this.wrappedObject(); 1097 data.replayContextCallback = this._replayContextCallback; 1098 1099 // FIXME: Save the getError() status and restore it after taking the GL state snapshot. 1100 1101 // Take a full GL state snapshot. 1102 var glState = {}; 1103 WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) { 1104 glState[parameter] = gl.isEnabled(gl[parameter]); 1105 }); 1106 WebGLRenderingContextResource.StateParameters.forEach(function(parameter) { 1107 glState[parameter] = Resource.toReplayable(gl.getParameter(gl[parameter]), cache); 1108 // FIXME: Call while(gl.getError() != gl.NO_ERROR) {...} to check if a particular parameter is supported. 1109 }); 1110 1111 // VERTEX_ATTRIB_ARRAYS 1112 var maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 1113 var vertexAttribParameters = ["VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", "VERTEX_ATTRIB_ARRAY_ENABLED", "VERTEX_ATTRIB_ARRAY_SIZE", "VERTEX_ATTRIB_ARRAY_STRIDE", "VERTEX_ATTRIB_ARRAY_TYPE", "VERTEX_ATTRIB_ARRAY_NORMALIZED", "CURRENT_VERTEX_ATTRIB"]; 1114 var vertexAttribStates = []; 1115 for (var i = 0; i < maxVertexAttribs; ++i) { 1116 var state = {}; 1117 vertexAttribParameters.forEach(function(attribParameter) { 1118 state[attribParameter] = Resource.toReplayable(gl.getVertexAttrib(i, gl[attribParameter]), cache); 1119 }); 1120 state.VERTEX_ATTRIB_ARRAY_POINTER = gl.getVertexAttribOffset(i, gl.VERTEX_ATTRIB_ARRAY_POINTER); 1121 vertexAttribStates.push(state); 1122 } 1123 glState.vertexAttribStates = vertexAttribStates; 1124 1125 // TEXTURES 1126 var currentTextureBinding = gl.getParameter(gl.ACTIVE_TEXTURE); 1127 var maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); 1128 var textureBindings = []; 1129 for (var i = 0; i < maxTextureImageUnits; ++i) { 1130 gl.activeTexture(gl.TEXTURE0 + i); 1131 var state = { 1132 TEXTURE_2D: Resource.toReplayable(gl.getParameter(gl.TEXTURE_BINDING_2D), cache), 1133 TEXTURE_CUBE_MAP: Resource.toReplayable(gl.getParameter(gl.TEXTURE_BINDING_CUBE_MAP), cache) 1134 }; 1135 textureBindings.push(state); 1136 } 1137 glState.textureBindings = textureBindings; 1138 gl.activeTexture(currentTextureBinding); 1139 1140 data.glState = glState; 1141 }, 1142 1143 /** 1144 * @override 1145 * @param {Object} data 1146 * @param {Cache} cache 1147 */ 1148 _doReplayCalls: function(data, cache) 1149 { 1150 this._proxyObject = null; 1151 this._replayContextCallback = data.replayContextCallback; 1152 1153 var context = this._replayContextCallback(); 1154 var contextResource = Resource.forObject(context); 1155 var gl = contextResource ? contextResource.wrappedObject() : context; 1156 this.setWrappedObject(gl); 1157 1158 var glState = data.glState; 1159 gl.bindFramebuffer(gl.FRAMEBUFFER, ReplayableResource.replay(glState.FRAMEBUFFER_BINDING, cache)); 1160 gl.bindRenderbuffer(gl.RENDERBUFFER, ReplayableResource.replay(glState.RENDERBUFFER_BINDING, cache)); 1161 1162 // Enable or disable server-side GL capabilities. 1163 WebGLRenderingContextResource.GLCapabilities.forEach(function(parameter) { 1164 console.assert(parameter in glState); 1165 if (glState[parameter]) 1166 gl.enable(gl[parameter]); 1167 else 1168 gl.disable(gl[parameter]); 1169 }); 1170 1171 gl.blendColor(glState.BLEND_COLOR[0], glState.BLEND_COLOR[1], glState.BLEND_COLOR[2], glState.BLEND_COLOR[3]); 1172 gl.blendEquationSeparate(glState.BLEND_EQUATION_RGB, glState.BLEND_EQUATION_ALPHA); 1173 gl.blendFuncSeparate(glState.BLEND_SRC_RGB, glState.BLEND_DST_RGB, glState.BLEND_SRC_ALPHA, glState.BLEND_DST_ALPHA); 1174 gl.clearColor(glState.COLOR_CLEAR_VALUE[0], glState.COLOR_CLEAR_VALUE[1], glState.COLOR_CLEAR_VALUE[2], glState.COLOR_CLEAR_VALUE[3]); 1175 gl.clearDepth(glState.DEPTH_CLEAR_VALUE); 1176 gl.clearStencil(glState.STENCIL_CLEAR_VALUE); 1177 gl.colorMask(glState.COLOR_WRITEMASK[0], glState.COLOR_WRITEMASK[1], glState.COLOR_WRITEMASK[2], glState.COLOR_WRITEMASK[3]); 1178 gl.cullFace(glState.CULL_FACE_MODE); 1179 gl.depthFunc(glState.DEPTH_FUNC); 1180 gl.depthMask(glState.DEPTH_WRITEMASK); 1181 gl.depthRange(glState.DEPTH_RANGE[0], glState.DEPTH_RANGE[1]); 1182 gl.frontFace(glState.FRONT_FACE); 1183 gl.hint(gl.GENERATE_MIPMAP_HINT, glState.GENERATE_MIPMAP_HINT); 1184 gl.lineWidth(glState.LINE_WIDTH); 1185 1186 WebGLRenderingContextResource.PixelStoreParameters.forEach(function(parameter) { 1187 gl.pixelStorei(gl[parameter], glState[parameter]); 1188 }); 1189 1190 gl.polygonOffset(glState.POLYGON_OFFSET_FACTOR, glState.POLYGON_OFFSET_UNITS); 1191 gl.sampleCoverage(glState.SAMPLE_COVERAGE_VALUE, glState.SAMPLE_COVERAGE_INVERT); 1192 gl.stencilFuncSeparate(gl.FRONT, glState.STENCIL_FUNC, glState.STENCIL_REF, glState.STENCIL_VALUE_MASK); 1193 gl.stencilFuncSeparate(gl.BACK, glState.STENCIL_BACK_FUNC, glState.STENCIL_BACK_REF, glState.STENCIL_BACK_VALUE_MASK); 1194 gl.stencilOpSeparate(gl.FRONT, glState.STENCIL_FAIL, glState.STENCIL_PASS_DEPTH_FAIL, glState.STENCIL_PASS_DEPTH_PASS); 1195 gl.stencilOpSeparate(gl.BACK, glState.STENCIL_BACK_FAIL, glState.STENCIL_BACK_PASS_DEPTH_FAIL, glState.STENCIL_BACK_PASS_DEPTH_PASS); 1196 gl.stencilMaskSeparate(gl.FRONT, glState.STENCIL_WRITEMASK); 1197 gl.stencilMaskSeparate(gl.BACK, glState.STENCIL_BACK_WRITEMASK); 1198 1199 gl.scissor(glState.SCISSOR_BOX[0], glState.SCISSOR_BOX[1], glState.SCISSOR_BOX[2], glState.SCISSOR_BOX[3]); 1200 gl.viewport(glState.VIEWPORT[0], glState.VIEWPORT[1], glState.VIEWPORT[2], glState.VIEWPORT[3]); 1201 1202 gl.useProgram(ReplayableResource.replay(glState.CURRENT_PROGRAM, cache)); 1203 1204 // VERTEX_ATTRIB_ARRAYS 1205 var maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 1206 for (var i = 0; i < maxVertexAttribs; ++i) { 1207 var state = glState.vertexAttribStates[i] || {}; 1208 if (state.VERTEX_ATTRIB_ARRAY_ENABLED) 1209 gl.enableVertexAttribArray(i); 1210 else 1211 gl.disableVertexAttribArray(i); 1212 if (state.CURRENT_VERTEX_ATTRIB) 1213 gl.vertexAttrib4fv(i, state.CURRENT_VERTEX_ATTRIB); 1214 var buffer = ReplayableResource.replay(state.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, cache); 1215 if (buffer) { 1216 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 1217 gl.vertexAttribPointer(i, state.VERTEX_ATTRIB_ARRAY_SIZE, state.VERTEX_ATTRIB_ARRAY_TYPE, state.VERTEX_ATTRIB_ARRAY_NORMALIZED, state.VERTEX_ATTRIB_ARRAY_STRIDE, state.VERTEX_ATTRIB_ARRAY_POINTER); 1218 } 1219 } 1220 gl.bindBuffer(gl.ARRAY_BUFFER, ReplayableResource.replay(glState.ARRAY_BUFFER_BINDING, cache)); 1221 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ReplayableResource.replay(glState.ELEMENT_ARRAY_BUFFER_BINDING, cache)); 1222 1223 // TEXTURES 1224 var maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); 1225 for (var i = 0; i < maxTextureImageUnits; ++i) { 1226 gl.activeTexture(gl.TEXTURE0 + i); 1227 var state = glState.textureBindings[i] || {}; 1228 gl.bindTexture(gl.TEXTURE_2D, ReplayableResource.replay(state.TEXTURE_2D, cache)); 1229 gl.bindTexture(gl.TEXTURE_CUBE_MAP, ReplayableResource.replay(state.TEXTURE_CUBE_MAP, cache)); 1230 } 1231 gl.activeTexture(glState.ACTIVE_TEXTURE); 1232 1233 return Resource.prototype._doReplayCalls.call(this, data, cache); 1234 }, 1235 1236 /** 684 1237 * @param {Object|number} target 685 1238 * @return {Resource} … … 694 1247 var bindMethodName; 695 1248 switch (target) { 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 1249 case gl.ARRAY_BUFFER: 1250 bindingTarget = gl.ARRAY_BUFFER_BINDING; 1251 bindMethodName = "bindBuffer"; 1252 break; 1253 case gl.ELEMENT_ARRAY_BUFFER: 1254 bindingTarget = gl.ELEMENT_ARRAY_BUFFER_BINDING; 1255 bindMethodName = "bindBuffer"; 1256 break; 1257 case gl.TEXTURE_2D: 1258 bindingTarget = gl.TEXTURE_BINDING_2D; 1259 bindMethodName = "bindTexture"; 1260 break; 1261 case gl.TEXTURE_CUBE_MAP: 1262 case gl.TEXTURE_CUBE_MAP_POSITIVE_X: 1263 case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: 1264 case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: 1265 case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: 1266 case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: 1267 case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: 1268 bindingTarget = gl.TEXTURE_BINDING_CUBE_MAP; 1269 bindMethodName = "bindTexture"; 1270 break; 1271 case gl.FRAMEBUFFER: 1272 bindingTarget = gl.FRAMEBUFFER_BINDING; 1273 bindMethodName = "bindFramebuffer"; 1274 break; 1275 case gl.RENDERBUFFER: 1276 bindingTarget = gl.RENDERBUFFER_BINDING; 1277 bindMethodName = "bindRenderbuffer"; 1278 break; 1279 default: 1280 console.error("ASSERT_NOT_REACHED: unknown binding target " + target); 1281 return null; 729 1282 } 730 1283 resource = Resource.forObject(gl.getParameter(bindingTarget)); … … 966 1519 captureResource: function(resource) 967 1520 { 968 // FIXME: Capture current resource state to start the replay from.1521 resource.toReplayable(this._replayablesCache); 969 1522 }, 970 1523 … … 974 1527 addCall: function(call) 975 1528 { 976 // FIXME: Convert the call to a ReplayableCall and push it. 1529 var res = Resource.forObject(call.result()); 1530 if (res) 1531 this.captureResource(res); 1532 var size = this._replayablesCache.size(); 1533 this._replayableCalls.push(call.toReplayable(this._replayablesCache)); 1534 console.assert(this._replayablesCache.size() === size, "Internal error: We should have captured all the resources already by this time."); 977 1535 } 978 1536 } … … 1163 1721 wrapWebGLContext: function(glContext) 1164 1722 { 1165 var resource = Resource.forObject(glContext) || new WebGLRenderingContextResource(glContext );1723 var resource = Resource.forObject(glContext) || new WebGLRenderingContextResource(glContext, this._constructReplayContext.bind(this, glContext)); 1166 1724 this._manager.registerResource(resource); 1167 1725 var proxy = resource.proxyObject(); … … 1228 1786 } 1229 1787 // Return current screenshot. 1788 // FIXME: Support replaying several canvases simultaneously. 1230 1789 return this._replayContext.canvas.toDataURL(); 1231 1790 }, … … 1237 1796 { 1238 1797 return "{\"injectedScriptId\":" + injectedScriptId + ",\"traceLogId\":" + (++this._lastTraceLogId) + "}"; 1798 }, 1799 1800 /** 1801 * @param {WebGLRenderingContext} originalGlContext 1802 * @return {WebGLRenderingContext} 1803 */ 1804 _constructReplayContext: function(originalGlContext) 1805 { 1806 var replayContext = originalGlContext["__replayContext"]; 1807 if (!replayContext) { 1808 var canvas = originalGlContext.canvas.cloneNode(true); 1809 // FIXME: Pass original context id instead of "experimental-webgl". 1810 // FIXME: Pass original ContextAttributes to the getContext() method. 1811 replayContext = canvas.getContext("experimental-webgl"); 1812 originalGlContext["__replayContext"] = replayContext; 1813 this._replayContext = replayContext; 1814 } else { 1815 // FIXME: Reset the replay GL state and clear the canvas. 1816 } 1817 return replayContext; 1239 1818 } 1240 1819 }
Note: See TracChangeset
for help on using the changeset viewer.