diff options
Diffstat (limited to 'devtools/client/shadereditor/test')
43 files changed, 3050 insertions, 0 deletions
diff --git a/devtools/client/shadereditor/test/.eslintrc.js b/devtools/client/shadereditor/test/.eslintrc.js new file mode 100644 index 000000000..8d15a76d9 --- /dev/null +++ b/devtools/client/shadereditor/test/.eslintrc.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + // Extend from the shared list of defined globals for mochitests. + "extends": "../../../.eslintrc.mochitests.js" +}; diff --git a/devtools/client/shadereditor/test/browser.ini b/devtools/client/shadereditor/test/browser.ini new file mode 100644 index 000000000..b26bc3a74 --- /dev/null +++ b/devtools/client/shadereditor/test/browser.ini @@ -0,0 +1,47 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +support-files = + doc_blended-geometry.html + doc_multiple-contexts.html + doc_overlapping-geometry.html + doc_shader-order.html + doc_simple-canvas.html + head.js + +[browser_se_aaa_run_first_leaktest.js] +[browser_se_bfcache.js] +skip-if = true # Bug 942473, caused by Bug 940541 +[browser_se_editors-contents.js] +[browser_se_editors-error-gutter.js] +[browser_se_editors-error-tooltip.js] +[browser_se_editors-lazy-init.js] +[browser_se_first-run.js] +[browser_se_navigation.js] +[browser_se_programs-blackbox-01.js] +[browser_se_programs-blackbox-02.js] +[browser_se_programs-cache.js] +[browser_se_programs-highlight-01.js] +[browser_se_programs-highlight-02.js] +[browser_se_programs-list.js] +[browser_se_shaders-edit-01.js] +[browser_se_shaders-edit-02.js] +[browser_se_shaders-edit-03.js] +[browser_webgl-actor-test-01.js] +[browser_webgl-actor-test-02.js] +[browser_webgl-actor-test-03.js] +[browser_webgl-actor-test-04.js] +[browser_webgl-actor-test-05.js] +[browser_webgl-actor-test-06.js] +[browser_webgl-actor-test-07.js] +[browser_webgl-actor-test-08.js] +[browser_webgl-actor-test-09.js] +[browser_webgl-actor-test-10.js] +[browser_webgl-actor-test-11.js] +[browser_webgl-actor-test-12.js] +[browser_webgl-actor-test-13.js] +[browser_webgl-actor-test-14.js] +[browser_webgl-actor-test-15.js] +[browser_webgl-actor-test-16.js] +[browser_webgl-actor-test-17.js] +[browser_webgl-actor-test-18.js] diff --git a/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js b/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js new file mode 100644 index 000000000..6efe51091 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_aaa_run_first_leaktest.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the shader editor leaks on initialization and sudden destruction. + * You can also use this initialization format as a template for other tests. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + + ok(target, "Should have a target available."); + ok(panel, "Should have a panel available."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_bfcache.js b/devtools/client/shadereditor/test/browser_se_bfcache.js new file mode 100644 index 000000000..2b568e3fe --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_bfcache.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the shader editor works with bfcache. + */ +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + // Attach frame scripts if in e10s to perform + // history navigation via the content + loadFrameScripts(); + + let reloaded = reload(target); + let firstProgram = yield once(gFront, "program-linked"); + yield reloaded; + + let navigated = navigate(target, MULTIPLE_CONTEXTS_URL); + let [secondProgram, thirdProgram] = yield getPrograms(gFront, 2); + yield navigated; + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + yield navigateInHistory(target, "back", "will-navigate"); + yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED); + yield once(panel.panelWin, EVENTS.SOURCES_SHOWN); + + is($("#content").hidden, false, + "The tool's content should not be hidden."); + is(ShadersListView.itemCount, 1, + "The shaders list contains one entry after navigating back."); + is(ShadersListView.selectedIndex, 0, + "The shaders list has a correct selection after navigating back."); + + is(vsEditor.getText().indexOf("gl_Position"), 170, + "The vertex shader editor contains the correct text."); + is(fsEditor.getText().indexOf("gl_FragColor"), 97, + "The fragment shader editor contains the correct text."); + + yield navigateInHistory(target, "forward", "will-navigate"); + yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED); + yield once(panel.panelWin, EVENTS.SOURCES_SHOWN); + + is($("#content").hidden, false, + "The tool's content should not be hidden."); + is(ShadersListView.itemCount, 2, + "The shaders list contains two entries after navigating forward."); + is(ShadersListView.selectedIndex, 0, + "The shaders list has a correct selection after navigating forward."); + + is(vsEditor.getText().indexOf("gl_Position"), 100, + "The vertex shader editor contains the correct text."); + is(fsEditor.getText().indexOf("gl_FragColor"), 89, + "The fragment shader editor contains the correct text."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_editors-contents.js b/devtools/client/shadereditor/test/browser_se_editors-contents.js new file mode 100644 index 000000000..fdf2612ed --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_editors-contents.js @@ -0,0 +1,30 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the editors contain the correct text when a program + * becomes available. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, ShadersEditorsView, EVENTS } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + + is(vsEditor.getText().indexOf("gl_Position"), 170, + "The vertex shader editor contains the correct text."); + is(fsEditor.getText().indexOf("gl_FragColor"), 97, + "The fragment shader editor contains the correct text."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js b/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js new file mode 100644 index 000000000..439d6074f --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_editors-error-gutter.js @@ -0,0 +1,156 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if error indicators are shown in the editor's gutter and text area + * when there's a shader compilation error. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); + let [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(false, vertError); + info("Error marks added in the vertex shader editor."); + + vsEditor.insertText(" ", { line: 1, ch: 0 }); + yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED); + is(vsEditor.getText(1), " precision lowp float;", "Typed space."); + checkHasVertFirstError(false, vertError); + checkHasVertSecondError(false, vertError); + info("Error marks removed while typing in the vertex shader editor."); + + [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(false, vertError); + info("Error marks were re-added after recompiling the vertex shader."); + + fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); + let [, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(false, vertError); + checkHasFragError(true, fragError); + info("Error marks added in the fragment shader editor."); + + fsEditor.insertText(" ", { line: 1, ch: 0 }); + yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED); + is(fsEditor.getText(1), " precision lowp float;", "Typed space."); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(false, vertError); + checkHasFragError(false, fragError); + info("Error marks removed while typing in the fragment shader editor."); + + [, fragError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(false, vertError); + checkHasFragError(true, fragError); + info("Error marks were re-added after recompiling the fragment shader."); + + vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 }); + yield once(panel.panelWin, EVENTS.EDITOR_ERROR_MARKERS_REMOVED); + checkHasVertFirstError(false, vertError); + checkHasVertSecondError(false, vertError); + checkHasFragError(true, fragError); + info("Error marks removed while typing in the vertex shader editor again."); + + [, vertError] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + checkHasVertFirstError(true, vertError); + checkHasVertSecondError(true, vertError); + checkHasFragError(true, fragError); + info("Error marks were re-added after recompiling the fragment shader again."); + + yield teardown(panel); + finish(); + + function checkHasVertFirstError(bool, error) { + ok(error, "Vertex shader compiled with errors."); + isnot(error.link, "", "The linkage status should not be empty."); + + let line = 7; + info("Checking first vertex shader error on line " + line + "..."); + + is(vsEditor.hasMarker(line, "errors", "error"), bool, + "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); + is(vsEditor.hasLineClass(line, "error-line"), bool, + "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); + + let parsed = ShadersEditorsView._errors.vs; + is(parsed.length >= 1, bool, + "There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s)."); + + if (bool) { + is(parsed[0].line, line, + "The correct line was parsed."); + is(parsed[0].messages.length, 2, + "There are 2 parsed messages."); + ok(parsed[0].messages[0].includes("'constructor' : too many arguments"), + "The correct first message was parsed."); + ok(parsed[0].messages[1].includes("'assign' : cannot convert from"), + "The correct second message was parsed."); + } + } + + function checkHasVertSecondError(bool, error) { + ok(error, "Vertex shader compiled with errors."); + isnot(error.link, "", "The linkage status should not be empty."); + + let line = 8; + info("Checking second vertex shader error on line " + line + "..."); + + is(vsEditor.hasMarker(line, "errors", "error"), bool, + "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); + is(vsEditor.hasLineClass(line, "error-line"), bool, + "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); + + let parsed = ShadersEditorsView._errors.vs; + is(parsed.length >= 2, bool, + "There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s)."); + + if (bool) { + is(parsed[1].line, line, + "The correct line was parsed."); + is(parsed[1].messages.length, 1, + "There is 1 parsed message."); + ok(parsed[1].messages[0].includes("'assign' : cannot convert from"), + "The correct message was parsed."); + } + } + + function checkHasFragError(bool, error) { + ok(error, "Fragment shader compiled with errors."); + isnot(error.link, "", "The linkage status should not be empty."); + + let line = 5; + info("Checking first vertex shader error on line " + line + "..."); + + is(fsEditor.hasMarker(line, "errors", "error"), bool, + "Error is " + (bool ? "" : "not ") + "shown in the editor's gutter."); + is(fsEditor.hasLineClass(line, "error-line"), bool, + "Error style is " + (bool ? "" : "not ") + "applied to the faulty line."); + + let parsed = ShadersEditorsView._errors.fs; + is(parsed.length >= 1, bool, + "There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s)."); + + if (bool) { + is(parsed[0].line, line, + "The correct line was parsed."); + is(parsed[0].messages.length, 1, + "There is 1 parsed message."); + ok(parsed[0].messages[0].includes("'constructor' : too many arguments"), + "The correct message was parsed."); + } + } +} diff --git a/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js b/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js new file mode 100644 index 000000000..1ce31bebf --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_editors-error-tooltip.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if error tooltips can be opened from the editor's gutter when there's + * a shader compilation error. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); + yield once(panel.panelWin, EVENTS.SHADER_COMPILED); + + // Synthesizing 'mouseover' events doesn't work, hack around this by + // manually calling the event listener with the expected arguments. + let editorDocument = vsEditor.container.contentDocument; + let marker = editorDocument.querySelector(".error"); + let parsed = ShadersEditorsView._errors.vs[0].messages; + ShadersEditorsView._onMarkerMouseOver(7, marker, parsed); + + let tooltip = marker._markerErrorsTooltip; + ok(tooltip, "A tooltip was created successfully."); + + let content = tooltip.content; + ok(tooltip.content, + "Some tooltip's content was set."); + ok(tooltip.content.className.includes("devtools-tooltip-simple-text-container"), + "The tooltip's content container was created correctly."); + + let messages = content.childNodes; + is(messages.length, 2, + "There are two messages displayed in the tooltip."); + ok(messages[0].className.includes("devtools-tooltip-simple-text"), + "The first message was created correctly."); + ok(messages[1].className.includes("devtools-tooltip-simple-text"), + "The second message was created correctly."); + + ok(messages[0].textContent.includes("'constructor' : too many arguments"), + "The first message contains the correct text."); + ok(messages[1].textContent.includes("'assign' : cannot convert"), + "The second message contains the correct text."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js b/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js new file mode 100644 index 000000000..b2d9d888e --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_editors-lazy-init.js @@ -0,0 +1,34 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if source editors are lazily initialized. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield once(gFront, "program-linked"); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + ok(vsEditor, "A vertex shader editor was initialized."); + ok(fsEditor, "A fragment shader editor was initialized."); + + isnot(vsEditor, fsEditor, + "The vertex shader editor is distinct from the fragment shader editor."); + + let vsEditor2 = yield ShadersEditorsView._getEditor("vs"); + let fsEditor2 = yield ShadersEditorsView._getEditor("fs"); + + is(vsEditor, vsEditor2, + "The vertex shader editor instances are cached."); + is(fsEditor, fsEditor2, + "The fragment shader editor instances are cached."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_first-run.js b/devtools/client/shadereditor/test/browser_se_first-run.js new file mode 100644 index 000000000..33239bcbe --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_first-run.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the shader editor shows the appropriate UI when opened. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, $ } = panel.panelWin; + + is($("#reload-notice").hidden, false, + "The 'reload this page' notice should initially be visible."); + is($("#waiting-notice").hidden, true, + "The 'waiting for a WebGL context' notice should initially be hidden."); + is($("#content").hidden, true, + "The tool's content should initially be hidden."); + + let navigating = once(target, "will-navigate"); + let linked = once(gFront, "program-linked"); + reload(target); + + yield navigating; + + is($("#reload-notice").hidden, true, + "The 'reload this page' notice should be hidden when navigating."); + is($("#waiting-notice").hidden, false, + "The 'waiting for a WebGL context' notice should be visible when navigating."); + is($("#content").hidden, true, + "The tool's content should still be hidden."); + + yield linked; + + is($("#reload-notice").hidden, true, + "The 'reload this page' notice should be hidden after linking."); + is($("#waiting-notice").hidden, true, + "The 'waiting for a WebGL context' notice should be hidden after linking."); + is($("#content").hidden, false, + "The tool's content should not be hidden anymore."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_navigation.js b/devtools/client/shadereditor/test/browser_se_navigation.js new file mode 100644 index 000000000..f1adc3e76 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_navigation.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests target navigations are handled correctly in the UI. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + is($("#reload-notice").hidden, true, + "The 'reload this page' notice should be hidden after linking."); + is($("#waiting-notice").hidden, true, + "The 'waiting for a WebGL context' notice should be visible after linking."); + is($("#content").hidden, false, + "The tool's content should not be hidden anymore."); + + is(ShadersListView.itemCount, 1, + "The shaders list contains one entry."); + is(ShadersListView.selectedItem, ShadersListView.items[0], + "The shaders list has a correct item selected."); + is(ShadersListView.selectedIndex, 0, + "The shaders list has a correct index selected."); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + is(vsEditor.getText().indexOf("gl_Position"), 170, + "The vertex shader editor contains the correct text."); + is(fsEditor.getText().indexOf("gl_FragColor"), 97, + "The fragment shader editor contains the correct text."); + + let navigating = once(target, "will-navigate"); + let navigated = once(target, "will-navigate"); + navigate(target, "about:blank"); + + yield promise.all([navigating, once(panel.panelWin, EVENTS.UI_RESET) ]); + + is($("#reload-notice").hidden, true, + "The 'reload this page' notice should be hidden while navigating."); + is($("#waiting-notice").hidden, false, + "The 'waiting for a WebGL context' notice should be visible while navigating."); + is($("#content").hidden, true, + "The tool's content should be hidden now that there's no WebGL content."); + + is(ShadersListView.itemCount, 0, + "The shaders list should be empty."); + is(ShadersListView.selectedItem, null, + "The shaders list has no correct item."); + is(ShadersListView.selectedIndex, -1, + "The shaders list has a negative index."); + + yield navigated; + + is($("#reload-notice").hidden, true, + "The 'reload this page' notice should still be hidden after navigating."); + is($("#waiting-notice").hidden, false, + "The 'waiting for a WebGL context' notice should still be visible after navigating."); + is($("#content").hidden, true, + "The tool's content should be still hidden since there's no WebGL content."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js b/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js new file mode 100644 index 000000000..4c8199c22 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-blackbox-01.js @@ -0,0 +1,169 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if blackboxing a program works properly. + */ + +function* ifWebGLSupported() { + let { target, debuggee, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => { + ok(false, "No shaders should be publicly compiled during this test."); + }); + + reload(target); + let [[firstProgramActor, secondProgramActor]] = yield promise.all([ + getPrograms(gFront, 2), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + vsEditor.once("change", () => { + ok(false, "The vertex shader source was unexpectedly changed."); + }); + fsEditor.once("change", () => { + ok(false, "The fragment shader source was unexpectedly changed."); + }); + once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => { + ok(false, "No sources should be changed form this point onward."); + }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + + ok(!ShadersListView.selectedAttachment.isBlackBoxed, + "The first program should not be blackboxed yet."); + is(getBlackBoxCheckbox(panel, 0).checked, true, + "The first blackbox checkbox should be initially checked."); + ok(!ShadersListView.attachments[1].isBlackBoxed, + "The second program should not be blackboxed yet."); + is(getBlackBoxCheckbox(panel, 1).checked, true, + "The second blackbox checkbox should be initially checked."); + + getBlackBoxCheckbox(panel, 0).click(); + + ok(ShadersListView.selectedAttachment.isBlackBoxed, + "The first program should now be blackboxed."); + is(getBlackBoxCheckbox(panel, 0).checked, false, + "The first blackbox checkbox should now be unchecked."); + ok(!ShadersListView.attachments[1].isBlackBoxed, + "The second program should still not be blackboxed."); + is(getBlackBoxCheckbox(panel, 1).checked, true, + "The second blackbox checkbox should still be checked."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first program was correctly blackboxed."); + + getBlackBoxCheckbox(panel, 1).click(); + + ok(ShadersListView.selectedAttachment.isBlackBoxed, + "The first program should still be blackboxed."); + is(getBlackBoxCheckbox(panel, 0).checked, false, + "The first blackbox checkbox should still be unchecked."); + ok(ShadersListView.attachments[1].isBlackBoxed, + "The second program should now be blackboxed."); + is(getBlackBoxCheckbox(panel, 1).checked, false, + "The second blackbox checkbox should now be unchecked."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "The second program was correctly blackboxed."); + + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "Highlighting shouldn't work while blackboxed (1)."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) }); + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "Highlighting shouldn't work while blackboxed (2)."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "Highlighting shouldn't work while blackboxed (3)."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + ok(!ShadersListView.selectedAttachment.isBlackBoxed, + "The first program should now be unblackboxed."); + is(getBlackBoxCheckbox(panel, 0).checked, true, + "The first blackbox checkbox should now be rechecked."); + ok(!ShadersListView.attachments[1].isBlackBoxed, + "The second program should now be unblackboxed."); + is(getBlackBoxCheckbox(panel, 1).checked, true, + "The second blackbox checkbox should now be rechecked."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two programs were correctly unblackboxed."); + + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) }); + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); + ok(true, "The second program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two programs were correctly unhighlighted."); + + yield teardown(panel); + finish(); +} + +function getItemLabel(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-contents")[aIndex]; +} + +function getBlackBoxCheckbox(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-checkbox")[aIndex]; +} + +function once(aTarget, aEvent) { + let deferred = promise.defer(); + aTarget.once(aEvent, deferred.resolve); + return deferred.promise; +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js b/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js new file mode 100644 index 000000000..391a272c8 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-blackbox-02.js @@ -0,0 +1,63 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if blackboxing a program works properly in tandem with blended + * overlapping geometry. + */ + +function* ifWebGLSupported() { + let { target, debuggee, panel } = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + let [[firstProgramActor, secondProgramActor]] = yield promise.all([ + getPrograms(gFront, 2), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The canvas was correctly drawn."); + + getBlackBoxCheckbox(panel, 0).click(); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 127 }, true); + ok(true, "The first program was correctly blackboxed."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 127, g: 127, b: 127, a: 255 }, true); + ok(true, "The second program was correctly blackboxed."); + + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unblackboxed."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 255 }, true); + ok(true, "The two programs were correctly blackboxed again."); + + getBlackBoxCheckbox(panel, 0).click(); + getBlackBoxCheckbox(panel, 1).click(); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unblackboxed again."); + + yield teardown(panel); + finish(); +} + +function getBlackBoxCheckbox(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-checkbox")[aIndex]; +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-cache.js b/devtools/client/shadereditor/test/browser_se_programs-cache.js new file mode 100644 index 000000000..5e5708e44 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-cache.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that program and shader actors are cached in the frontend. + */ + +function* ifWebGLSupported() { + let { target, debuggee, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL); + let { EVENTS, gFront, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + let [[programActor]] = yield promise.all([ + getPrograms(gFront, 1), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let programItem = ShadersListView.selectedItem; + + is(programItem.attachment.programActor, programActor, + "The correct program actor is cached for the selected item."); + + is((yield programActor.getVertexShader()), + (yield programItem.attachment.vs), + "The cached vertex shader promise returns the correct actor."); + + is((yield programActor.getFragmentShader()), + (yield programItem.attachment.fs), + "The cached fragment shader promise returns the correct actor."); + + is((yield (yield programActor.getVertexShader()).getText()), + (yield (yield ShadersEditorsView._getEditor("vs")).getText()), + "The cached vertex shader promise returns the correct text."); + + is((yield (yield programActor.getFragmentShader()).getText()), + (yield (yield ShadersEditorsView._getEditor("fs")).getText()), + "The cached fragment shader promise returns the correct text."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js b/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js new file mode 100644 index 000000000..863dc2672 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-highlight-01.js @@ -0,0 +1,93 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if highlighting a program works properly. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => { + ok(false, "No shaders should be publicly compiled during this test."); + }); + + reload(target); + let [[firstProgramActor, secondProgramActor]] = yield promise.all([ + getPrograms(gFront, 2), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + vsEditor.once("change", () => { + ok(false, "The vertex shader source was unexpectedly changed."); + }); + fsEditor.once("change", () => { + ok(false, "The fragment shader source was unexpectedly changed."); + }); + once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => { + ok(false, "No sources should be changed form this point onward."); + }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) }); + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2"); + ok(true, "The second program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two programs were correctly unhighlighted."); + + ShadersListView._onProgramMouseOver({ target: getBlackBoxCheckbox(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two programs were left unchanged after hovering a blackbox checkbox."); + + ShadersListView._onProgramMouseOut({ target: getBlackBoxCheckbox(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two programs were left unchanged after unhovering a blackbox checkbox."); + + yield teardown(panel); + finish(); +} + +function getItemLabel(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-contents")[aIndex]; +} + +function getBlackBoxCheckbox(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-checkbox")[aIndex]; +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js b/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js new file mode 100644 index 000000000..c6cbd796b --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-highlight-02.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if highlighting a program works properly in tandem with blended + * overlapping geometry. + */ + +function* ifWebGLSupported() { + let { target, debuggee, panel } = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + let [[firstProgramActor, secondProgramActor]] = yield promise.all([ + getPrograms(gFront, 2), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The canvas was correctly drawn."); + + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 0) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 0, b: 32, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 0, b: 32, a: 127 }, true); + ok(true, "The first program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 0) }); + ShadersListView._onProgramMouseOver({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 255, g: 0, b: 64, a: 255 }, true); + ok(true, "The second program was correctly highlighted."); + + ShadersListView._onProgramMouseOut({ target: getItemLabel(panel, 1) }); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true); + ok(true, "The two programs were correctly unhighlighted."); + + yield teardown(panel); + finish(); +} + +function getItemLabel(aPanel, aIndex) { + return aPanel.panelWin.document.querySelectorAll( + ".side-menu-widget-item-contents")[aIndex]; +} diff --git a/devtools/client/shadereditor/test/browser_se_programs-list.js b/devtools/client/shadereditor/test/browser_se_programs-list.js new file mode 100644 index 000000000..621880886 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_programs-list.js @@ -0,0 +1,87 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the programs list contains an entry after vertex and fragment + * shaders are linked. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL); + let { gFront, EVENTS, L10N, ShadersListView, ShadersEditorsView } = panel.panelWin; + + is(ShadersListView.itemCount, 0, + "The shaders list should initially be empty."); + is(ShadersListView.selectedItem, null, + "The shaders list has no selected item."); + is(ShadersListView.selectedIndex, -1, + "The shaders list has a negative index."); + + reload(target); + + let [firstProgramActor, secondProgramActor] = yield promise.all([ + getPrograms(gFront, 2, (actors) => { + // Fired upon each actor addition, we want to check only + // after the first actor has been added so we can test state + if (actors.length === 1) + checkFirstProgram(); + if (actors.length === 2) + checkSecondProgram(); + }), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]).then(([programs, ]) => programs); + + is(ShadersListView.attachments[0].label, L10N.getFormatStr("shadersList.programLabel", 0), + "The correct first label is shown in the shaders list."); + is(ShadersListView.attachments[1].label, L10N.getFormatStr("shadersList.programLabel", 1), + "The correct second label is shown in the shaders list."); + + let vertexShader = yield firstProgramActor.getVertexShader(); + let fragmentShader = yield firstProgramActor.getFragmentShader(); + let vertSource = yield vertexShader.getText(); + let fragSource = yield fragmentShader.getText(); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + is(vertSource, vsEditor.getText(), + "The vertex shader editor contains the correct text."); + is(fragSource, fsEditor.getText(), + "The vertex shader editor contains the correct text."); + + let compiled = once(panel.panelWin, EVENTS.SHADER_COMPILED).then(() => { + ok(false, "Selecting a different program shouldn't recompile its shaders."); + }); + + let shown = once(panel.panelWin, EVENTS.SOURCES_SHOWN).then(() => { + ok(true, "The vertex and fragment sources have changed in the editors."); + }); + + EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[1].target); + yield shown; + + is(ShadersListView.selectedItem, ShadersListView.items[1], + "The shaders list has a correct item selected."); + is(ShadersListView.selectedIndex, 1, + "The shaders list has a correct index selected."); + + yield teardown(panel); + finish(); + + function checkFirstProgram() { + is(ShadersListView.itemCount, 1, + "The shaders list contains one entry."); + is(ShadersListView.selectedItem, ShadersListView.items[0], + "The shaders list has a correct item selected."); + is(ShadersListView.selectedIndex, 0, + "The shaders list has a correct index selected."); + } + function checkSecondProgram() { + is(ShadersListView.itemCount, 2, + "The shaders list contains two entries."); + is(ShadersListView.selectedItem, ShadersListView.items[0], + "The shaders list has a correct item selected."); + is(ShadersListView.selectedIndex, 0, + "The shaders list has a correct index selected."); + } +} diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js new file mode 100644 index 000000000..0cb52ac19 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-01.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if editing a vertex and a fragment shader works properly. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, $, EVENTS, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + is(vsEditor.getText().indexOf("gl_Position"), 170, + "The vertex shader editor contains the correct text."); + is(fsEditor.getText().indexOf("gl_FragColor"), 97, + "The fragment shader editor contains the correct text."); + + is($("#vs-editor-label").hasAttribute("selected"), false, + "The vertex shader editor shouldn't be initially selected."); + is($("#fs-editor-label").hasAttribute("selected"), false, + "The vertex shader editor shouldn't be initially selected."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 191, g: 64, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + + vsEditor.focus(); + + is($("#vs-editor-label").hasAttribute("selected"), true, + "The vertex shader editor should now be selected."); + is($("#fs-editor-label").hasAttribute("selected"), false, + "The vertex shader editor shouldn't still not be selected."); + + vsEditor.replaceText("2.0", { line: 7, ch: 44 }, { line: 7, ch: 47 }); + yield once(panel.panelWin, EVENTS.SHADER_COMPILED); + + ok(true, "Vertex shader was changed."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); + + ok(true, "The vertex shader was recompiled successfully."); + + fsEditor.focus(); + + is($("#vs-editor-label").hasAttribute("selected"), false, + "The vertex shader editor should now be deselected."); + is($("#fs-editor-label").hasAttribute("selected"), true, + "The vertex shader editor should now be selected."); + + fsEditor.replaceText("0.5", { line: 5, ch: 44 }, { line: 5, ch: 47 }); + yield once(panel.panelWin, EVENTS.SHADER_COMPILED); + + ok(true, "Fragment shader was changed."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true); + yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); + + ok(true, "The fragment shader was recompiled successfully."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js new file mode 100644 index 000000000..0bb72c461 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-02.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if compile or linkage errors are emitted when a shader source + * gets malformed after being edited. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(SIMPLE_CANVAS_URL); + let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin; + + reload(target); + yield promise.all([ + once(gFront, "program-linked"), + once(panel.panelWin, EVENTS.SOURCES_SHOWN) + ]); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + + vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 }); + let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + + ok(error, + "The new vertex shader source was compiled with errors."); + + // The implementation has the choice to defer all compile-time errors to link time. + let infoLog = (error.compile != "") ? error.compile : error.link; + + isnot(infoLog, "", + "The one of the compile or link info logs should not be empty."); + is(infoLog.split("ERROR").length - 1, 2, + "The info log status contains two errors."); + ok(infoLog.includes("ERROR: 0:8: 'constructor'"), + "A constructor error is contained in the info log."); + ok(infoLog.includes("ERROR: 0:8: 'assign'"), + "An assignment error is contained in the info log."); + + + fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + + ok(error, + "The new fragment shader source was compiled with errors."); + + infoLog = (error.compile != "") ? error.compile : error.link; + + isnot(infoLog, "", + "The one of the compile or link info logs should not be empty."); + is(infoLog.split("ERROR").length - 1, 1, + "The info log contains one error."); + ok(infoLog.includes("ERROR: 0:6: 'constructor'"), + "A constructor error is contained in the info log."); + + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + + vsEditor.replaceText("vec4", { line: 7, ch: 22 }, { line: 7, ch: 26 }); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + ok(!error, "The new vertex shader source was compiled successfully."); + + fsEditor.replaceText("vec3", { line: 2, ch: 14 }, { line: 2, ch: 18 }); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + ok(!error, "The new fragment shader source was compiled successfully."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js b/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js new file mode 100644 index 000000000..2c413dd72 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_se_shaders-edit-03.js @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if editing a vertex and a fragment shader would permanently store + * their new source on the backend and reshow it in the frontend when required. + */ + +function* ifWebGLSupported() { + let { target, panel } = yield initShaderEditor(MULTIPLE_CONTEXTS_URL); + let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin; + + reload(target); + + yield promise.all([ + once(gFront, "program-linked"), + once(gFront, "program-linked") + ]); + + yield once(panel.panelWin, EVENTS.SOURCES_SHOWN); + + let vsEditor = yield ShadersEditorsView._getEditor("vs"); + let fsEditor = yield ShadersEditorsView._getEditor("fs"); + + is(ShadersListView.selectedIndex, 0, + "The first program is currently selected."); + is(vsEditor.getText().indexOf("1);"), 136, + "The vertex shader editor contains the correct initial text (1)."); + is(fsEditor.getText().indexOf("1);"), 117, + "The fragment shader editor contains the correct initial text (1)."); + is(vsEditor.getText().indexOf("2.);"), -1, + "The vertex shader editor contains the correct initial text (2)."); + is(fsEditor.getText().indexOf(".0);"), -1, + "The fragment shader editor contains the correct initial text (2)."); + + vsEditor.replaceText("2.", { line: 5, ch: 44 }, { line: 5, ch: 45 }); + yield once(panel.panelWin, EVENTS.SHADER_COMPILED); + + fsEditor.replaceText(".0", { line: 5, ch: 35 }, { line: 5, ch: 37 }); + yield once(panel.panelWin, EVENTS.SHADER_COMPILED); + + ok(true, "Vertex and fragment shaders were changed."); + + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 32, y: 32 }, { r: 255, g: 255, b: 0, a: 0 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 255, g: 255, b: 0, a: 0 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 32, y: 32 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(gFront, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + + ok(true, "The vertex and fragment shaders were recompiled successfully."); + + EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[1].target); + yield once(panel.panelWin, EVENTS.SOURCES_SHOWN); + + is(ShadersListView.selectedIndex, 1, + "The second program is currently selected."); + is(vsEditor.getText().indexOf("1);"), 136, + "The vertex shader editor contains the correct text (1)."); + is(fsEditor.getText().indexOf("1);"), 117, + "The fragment shader editor contains the correct text (1)."); + is(vsEditor.getText().indexOf("2.);"), -1, + "The vertex shader editor contains the correct text (2)."); + is(fsEditor.getText().indexOf(".0);"), -1, + "The fragment shader editor contains the correct text (2)."); + + EventUtils.sendMouseEvent({ type: "mousedown" }, ShadersListView.items[0].target); + yield once(panel.panelWin, EVENTS.SOURCES_SHOWN); + + is(ShadersListView.selectedIndex, 0, + "The first program is currently selected again."); + is(vsEditor.getText().indexOf("1);"), -1, + "The vertex shader editor contains the correct text (3)."); + is(fsEditor.getText().indexOf("1);"), -1, + "The fragment shader editor contains the correct text (3)."); + is(vsEditor.getText().indexOf("2.);"), 136, + "The vertex shader editor contains the correct text (4)."); + is(fsEditor.getText().indexOf(".0);"), 116, + "The fragment shader editor contains the correct text (4)."); + + yield teardown(panel); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js new file mode 100644 index 000000000..242018a76 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-01.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if a WebGL front can be created for a remote tab target. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + + ok(target, "Should have a target available."); + ok(front, "Should have a protocol front available."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js new file mode 100644 index 000000000..addec87ca --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-02.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if notifications about WebGL programs being linked are not sent + * if the front wasn't set up first. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + + once(front, "program-linked").then(() => { + ok(false, "A 'program-linked' notification shouldn't have been sent!"); + }); + + ok(true, "Each test requires at least one pass, fail or todo so here is a pass."); + + yield reload(target); + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js new file mode 100644 index 000000000..0381973ec --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-03.js @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if notifications about WebGL programs being linked are sent + * after a target navigation. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + + let navigated = once(target, "navigate"); + let linked = once(front, "program-linked"); + + yield front.setup({ reload: true }); + ok(true, "The front was setup up successfully."); + + yield navigated; + ok(true, "Target automatically navigated when the front was set up."); + + yield linked; + ok(true, "A 'program-linked' notification was sent after reloading."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js new file mode 100644 index 000000000..4256a5329 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-04.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if a program actor is sent when WebGL programs are linked, + * and that the corresponding vertex and fragment actors can be retrieved. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + ok(programActor, + "A program actor was sent along with the 'program-linked' notification."); + + let vertexShader = yield programActor.getVertexShader(); + ok(programActor, + "A vertex shader actor was retrieved from the program actor."); + + let fragmentShader = yield programActor.getFragmentShader(); + ok(programActor, + "A fragment shader actor was retrieved from the program actor."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js new file mode 100644 index 000000000..96e445e01 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-05.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the source contents can be retrieved from the vertex and fragment + * shader actors. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + let vertSource = yield vertexShader.getText(); + ok(vertSource.includes("gl_Position"), + "The correct vertex shader source was retrieved."); + + let fragSource = yield fragmentShader.getText(); + ok(fragSource.includes("gl_FragColor"), + "The correct fragment shader source was retrieved."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js new file mode 100644 index 000000000..5cbe88a77 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-06.js @@ -0,0 +1,64 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the highlight/unhighlight and blackbox/unblackbox operations on + * program actors work as expected. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + yield checkShaderSource("The shader sources are correct before highlighting."); + ok(true, "The corner pixel colors are correct before highlighting."); + + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + yield checkShaderSource("The shader sources are preserved after highlighting."); + ok(true, "The corner pixel colors are correct after highlighting."); + + yield programActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + yield checkShaderSource("The shader sources are correct after unhighlighting."); + ok(true, "The corner pixel colors are correct after unhighlighting."); + + yield programActor.blackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield checkShaderSource("The shader sources are preserved after blackboxing."); + ok(true, "The corner pixel colors are correct after blackboxing."); + + yield programActor.unblackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + yield checkShaderSource("The shader sources are correct after unblackboxing."); + ok(true, "The corner pixel colors are correct after unblackboxing."); + + function checkShaderSource(aMessage) { + return Task.spawn(function* () { + let newVertexShader = yield programActor.getVertexShader(); + let newFragmentShader = yield programActor.getFragmentShader(); + is(vertexShader, newVertexShader, + "The same vertex shader actor was retrieved."); + is(fragmentShader, newFragmentShader, + "The same fragment shader actor was retrieved."); + + let vertSource = yield newVertexShader.getText(); + let fragSource = yield newFragmentShader.getText(); + ok(vertSource.includes("I'm special!") && + fragSource.includes("I'm also special!"), aMessage); + }); + } + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js new file mode 100644 index 000000000..a7634de44 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-07.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that vertex and fragment shader sources can be changed. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 191, g: 64, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + + let vertSource = yield vertexShader.getText(); + let fragSource = yield fragmentShader.getText(); + ok(!vertSource.includes("2.0"), + "The vertex shader source is correct before changing it."); + ok(!fragSource.includes("0.5"), + "The fragment shader source is correct before changing it."); + + let newVertSource = vertSource.replace("1.0", "2.0"); + let status = yield vertexShader.compile(newVertSource); + ok(!status, + "The new vertex shader source was compiled without errors."); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); + + vertSource = yield vertexShader.getText(); + fragSource = yield fragmentShader.getText(); + ok(vertSource.includes("2.0"), + "The vertex shader source is correct after changing it."); + ok(!fragSource.includes("0.5"), + "The fragment shader source is correct after changing the vertex shader."); + + let newFragSource = fragSource.replace("1.0", "0.5"); + status = yield fragmentShader.compile(newFragSource); + ok(!status, + "The new fragment shader source was compiled without errors."); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); + + vertSource = yield vertexShader.getText(); + fragSource = yield fragmentShader.getText(); + ok(vertSource.includes("2.0"), + "The vertex shader source is correct after changing the fragment shader."); + ok(fragSource.includes("0.5"), + "The fragment shader source is correct after changing it."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js new file mode 100644 index 000000000..8025bc703 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-08.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the rendering is updated when a varying variable is + * changed in one shader. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + let oldVertSource = yield vertexShader.getText(); + let newVertSource = oldVertSource.replace("= aVertexColor", "= vec3(0, 0, 1)"); + let status = yield vertexShader.compile(newVertSource); + ok(!status, + "The new vertex shader source was compiled without errors."); + + yield front.waitForFrame(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 0, g: 0, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true); + + let vertSource = yield vertexShader.getText(); + let fragSource = yield fragmentShader.getText(); + ok(vertSource.includes("vFragmentColor = vec3(0, 0, 1);"), + "The vertex shader source is correct after changing it."); + ok(fragSource.includes("gl_FragColor = vec4(vFragmentColor, 1.0);"), + "The fragment shader source is correct after changing the vertex shader."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js new file mode 100644 index 000000000..2054140a6 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-09.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that errors are properly handled when trying to compile a + * defective shader source. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + let oldVertSource = yield vertexShader.getText(); + let newVertSource = oldVertSource.replace("vec4", "vec3"); + + try { + yield vertexShader.compile(newVertSource); + ok(false, "Vertex shader was compiled with a defective source!"); + } catch (error) { + ok(error, + "The new vertex shader source was compiled with errors."); + + // The implementation has the choice to defer all compile-time errors to link time. + let infoLog = (error.compile != "") ? error.compile : error.link; + + isnot(infoLog, "", + "The one of the compile or link info logs should not be empty."); + is(infoLog.split("ERROR").length - 1, 2, + "The info log contains two errors."); + ok(infoLog.includes("ERROR: 0:8: 'constructor'"), + "A constructor error is contained in the info log."); + ok(infoLog.includes("ERROR: 0:8: 'assign'"), + "An assignment error is contained in the info log."); + } + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The shader was reverted to the old source."); + + let vertSource = yield vertexShader.getText(); + ok(vertSource.includes("vec4(aVertexPosition, 1.0);"), + "The previous correct vertex shader source was preserved."); + + let oldFragSource = yield fragmentShader.getText(); + let newFragSource = oldFragSource.replace("vec3", "vec4"); + + try { + yield fragmentShader.compile(newFragSource); + ok(false, "Fragment shader was compiled with a defective source!"); + } catch (error) { + ok(error, + "The new fragment shader source was compiled with errors."); + + // The implementation has the choice to defer all compile-time errors to link time. + let infoLog = (error.compile != "") ? error.compile : error.link; + + isnot(infoLog, "", + "The one of the compile or link info logs should not be empty."); + is(infoLog.split("ERROR").length - 1, 1, + "The info log contains one error."); + ok(infoLog.includes("ERROR: 0:6: 'constructor'"), + "A constructor error is contained in the info log."); + } + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The shader was reverted to the old source."); + + let fragSource = yield fragmentShader.getText(); + ok(fragSource.includes("vec3 vFragmentColor;"), + "The previous correct fragment shader source was preserved."); + + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "Highlighting worked after setting a defective fragment source."); + + yield programActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "Unhighlighting worked after setting a defective vertex source."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js new file mode 100644 index 000000000..87dfe35bf --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-10.js @@ -0,0 +1,44 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the WebGL context is correctly instrumented every time the + * target navigates. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + + front.setup({ reload: true }); + yield testHighlighting((yield once(front, "program-linked"))); + ok(true, "Canvas was correctly instrumented on the first navigation."); + + reload(target); + yield testHighlighting((yield once(front, "program-linked"))); + ok(true, "Canvas was correctly instrumented on the second navigation."); + + reload(target); + yield testHighlighting((yield once(front, "program-linked"))); + ok(true, "Canvas was correctly instrumented on the third navigation."); + + yield removeTab(target.tab); + finish(); + + function testHighlighting(programActor) { + return Task.spawn(function* () { + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); + + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); + + yield programActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); + }); + } +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js new file mode 100644 index 000000000..28663057e --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-11.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if the WebGL context is never instrumented anymore after the + * finalize method is called. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + + let linked = once(front, "program-linked"); + front.setup({ reload: true }); + yield linked; + ok(true, "Canvas was correctly instrumented on the first navigation."); + + once(front, "program-linked").then(() => { + ok(false, "A 'program-linked' notification shouldn't have been sent!"); + }); + + yield front.finalize(); + yield reload(target); + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js new file mode 100644 index 000000000..f69d5e403 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-12.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the correct vertex and fragment shader sources are retrieved + * regardless of the order in which they were compiled and attached. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SHADER_ORDER_URL); + front.setup({ reload: true }); + + let programActor = yield once(front, "program-linked"); + let vertexShader = yield programActor.getVertexShader(); + let fragmentShader = yield programActor.getFragmentShader(); + + let vertSource = yield vertexShader.getText(); + let fragSource = yield fragmentShader.getText(); + + ok(vertSource.includes("I'm a vertex shader!"), + "The correct vertex shader text was retrieved."); + ok(fragSource.includes("I'm a fragment shader!"), + "The correct fragment shader text was retrieved."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js new file mode 100644 index 000000000..f4730ba39 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-13.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if multiple WebGL contexts are correctly handled. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL); + front.setup({ reload: true }); + + let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2); + + isnot(firstProgramActor, secondProgramActor, + "Two distinct program actors were recevide from two separate contexts."); + + let firstVertexShader = yield firstProgramActor.getVertexShader(); + let firstFragmentShader = yield firstProgramActor.getFragmentShader(); + let secondVertexShader = yield secondProgramActor.getVertexShader(); + let secondFragmentShader = yield secondProgramActor.getFragmentShader(); + + isnot(firstVertexShader, secondVertexShader, + "The two programs should have distinct vertex shaders."); + isnot(firstFragmentShader, secondFragmentShader, + "The two programs should have distinct fragment shaders."); + + let firstVertSource = yield firstVertexShader.getText(); + let firstFragSource = yield firstFragmentShader.getText(); + let secondVertSource = yield secondVertexShader.getText(); + let secondFragSource = yield secondFragmentShader.getText(); + + is(firstVertSource, secondVertSource, + "The vertex shaders should have identical sources."); + is(firstFragSource, secondFragSource, + "The vertex shaders should have identical sources."); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases are correctly drawn."); + + yield firstProgramActor.highlight([1, 0, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first canvas was correctly filled after highlighting."); + + yield secondProgramActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "The second canvas was correctly filled after highlighting."); + + yield firstProgramActor.unhighlight(); + yield secondProgramActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases were correctly filled after unhighlighting."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js new file mode 100644 index 000000000..342bba382 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-14.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the rendering is updated when a uniform variable is + * changed in one shader of a page with multiple WebGL contexts. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL); + front.setup({ reload: true }); + + let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2); + + let firstFragmentShader = yield firstProgramActor.getFragmentShader(); + let secondFragmentShader = yield secondProgramActor.getFragmentShader(); + + let oldFragSource = yield firstFragmentShader.getText(); + let newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.25, 0.25, 0.25"); + let status = yield firstFragmentShader.compile(newFragSource); + ok(!status, + "The first new fragment shader source was compiled without errors."); + + yield front.waitForFrame(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first fragment shader was changed."); + + oldFragSource = yield secondFragmentShader.getText(); + newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75"); + status = yield secondFragmentShader.compile(newFragSource); + ok(!status, + "The second new fragment shader source was compiled without errors."); + + yield front.waitForFrame(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 64, g: 64, b: 64, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 191, g: 191, b: 191, a: 255 }, true, "#canvas2"); + ok(true, "The second fragment shader was changed."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js new file mode 100644 index 000000000..0a65dbe0a --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-15.js @@ -0,0 +1,133 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if program actors are cached when navigating in the bfcache. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: false }); + + // Attach frame scripts if in e10s to perform + // history navigation via the content + loadFrameScripts(); + + reload(target); + let firstProgram = yield once(front, "program-linked"); + yield checkFirstCachedPrograms(firstProgram); + yield checkHighlightingInTheFirstPage(firstProgram); + ok(true, "The cached programs behave correctly before the navigation."); + + navigate(target, MULTIPLE_CONTEXTS_URL); + let [secondProgram, thirdProgram] = yield getPrograms(front, 2); + yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]); + yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram); + ok(true, "The cached programs behave correctly after the navigation."); + + once(front, "program-linked").then(() => { + ok(false, "Shouldn't have received any more program-linked notifications."); + }); + + yield navigateInHistory(target, "back"); + yield checkFirstCachedPrograms(firstProgram); + yield checkHighlightingInTheFirstPage(firstProgram); + ok(true, "The cached programs behave correctly after navigating back."); + + yield navigateInHistory(target, "forward"); + yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]); + yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram); + ok(true, "The cached programs behave correctly after navigating forward."); + + yield navigateInHistory(target, "back"); + yield checkFirstCachedPrograms(firstProgram); + yield checkHighlightingInTheFirstPage(firstProgram); + ok(true, "The cached programs behave correctly after navigating back again."); + + yield navigateInHistory(target, "forward"); + yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]); + yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram); + ok(true, "The cached programs behave correctly after navigating forward again."); + + yield removeTab(target.tab); + finish(); + + function checkFirstCachedPrograms(programActor) { + return Task.spawn(function* () { + let programs = yield front.getPrograms(); + + is(programs.length, 1, + "There should be 1 cached program actor."); + is(programs[0], programActor, + "The cached program actor was the expected one."); + }); + } + + function checkSecondCachedPrograms(oldProgramActor, newProgramActors) { + return Task.spawn(function* () { + let programs = yield front.getPrograms(); + + is(programs.length, 2, + "There should be 2 cached program actors after the navigation."); + is(programs[0], newProgramActors[0], + "The first cached program actor was the expected one after the navigation."); + is(programs[1], newProgramActors[1], + "The second cached program actor was the expected one after the navigation."); + + isnot(newProgramActors[0], oldProgramActor, + "The old program actor is not equal to the new first program actor."); + isnot(newProgramActors[1], oldProgramActor, + "The old program actor is not equal to the new second program actor."); + }); + } + + function checkHighlightingInTheFirstPage(programActor) { + return Task.spawn(function* () { + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); + + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); + + yield programActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); + }); + } + + function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) { + return Task.spawn(function* () { + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases are correctly drawn before highlighting."); + + yield firstProgramActor.highlight([1, 0, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first canvas was correctly filled after highlighting."); + + yield secondProgramActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "The second canvas was correctly filled after highlighting."); + + yield firstProgramActor.unhighlight(); + yield secondProgramActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases were correctly filled after unhighlighting."); + }); + } +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js new file mode 100644 index 000000000..e61e73102 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-16.js @@ -0,0 +1,141 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests if program actors are invalidated from the cache when a window is + * removed from the bfcache. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(SIMPLE_CANVAS_URL); + front.setup({ reload: false }); + + // Attach frame scripts if in e10s to perform + // history navigation via the content + loadFrameScripts(); + + // 0. Perform the initial reload. + + reload(target); + let firstProgram = yield once(front, "program-linked"); + let programs = yield front.getPrograms(); + is(programs.length, 1, + "The first program should be returned by a call to getPrograms()."); + is(programs[0], firstProgram, + "The first programs was correctly retrieved from the cache."); + + let allPrograms = yield front._getAllPrograms(); + is(allPrograms.length, 1, + "Should be only one program in cache."); + + // 1. Perform a simple navigation. + + navigate(target, MULTIPLE_CONTEXTS_URL); + let [secondProgram, thirdProgram] = yield getPrograms(front, 2); + programs = yield front.getPrograms(); + is(programs.length, 2, + "The second and third programs should be returned by a call to getPrograms()."); + is(programs[0], secondProgram, + "The second programs was correctly retrieved from the cache."); + is(programs[1], thirdProgram, + "The third programs was correctly retrieved from the cache."); + + allPrograms = yield front._getAllPrograms(); + is(allPrograms.length, 3, + "Should be three programs in cache."); + + // 2. Perform a bfcache navigation. + + yield navigateInHistory(target, "back"); + let globalDestroyed = once(front, "global-created"); + let globalCreated = once(front, "global-destroyed"); + let programsLinked = once(front, "program-linked"); + reload(target); + + yield promise.all([programsLinked, globalDestroyed, globalCreated]); + allPrograms = yield front._getAllPrograms(); + is(allPrograms.length, 3, + "Should be 3 programs total in cache."); + + programs = yield front.getPrograms(); + is(programs.length, 1, + "There should be 1 cached program actor now."); + + yield checkHighlightingInTheFirstPage(programs[0]); + ok(true, "The cached programs behave correctly after navigating back and reloading."); + + // 3. Perform a bfcache navigation and a page reload. + + yield navigateInHistory(target, "forward"); + + globalDestroyed = once(front, "global-created"); + globalCreated = once(front, "global-destroyed"); + programsLinked = getPrograms(front, 2); + + reload(target); + + yield promise.all([programsLinked, globalDestroyed, globalCreated]); + allPrograms = yield front._getAllPrograms(); + is(allPrograms.length, 3, + "Should be 3 programs total in cache."); + + programs = yield front.getPrograms(); + is(programs.length, 2, + "There should be 2 cached program actors now."); + + yield checkHighlightingInTheSecondPage(programs[0], programs[1]); + ok(true, "The cached programs behave correctly after navigating forward and reloading."); + + yield removeTab(target.tab); + finish(); + + function checkHighlightingInTheFirstPage(programActor) { + return Task.spawn(function* () { + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct before highlighting."); + + yield programActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after highlighting."); + + yield programActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner pixel colors are correct after unhighlighting."); + }); + } + + function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) { + return Task.spawn(function* () { + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases are correctly drawn before highlighting."); + + yield firstProgramActor.highlight([1, 0, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The first canvas was correctly filled after highlighting."); + + yield secondProgramActor.highlight([0, 1, 0, 1]); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2"); + ok(true, "The second canvas was correctly filled after highlighting."); + + yield firstProgramActor.unhighlight(); + yield secondProgramActor.unhighlight(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1"); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); + ok(true, "The two canvases were correctly filled after unhighlighting."); + }); + } +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js new file mode 100644 index 000000000..92b940d4a --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-17.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that the blackbox/unblackbox operations work as expected with + * overlapping geometry. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(OVERLAPPING_GEOMETRY_CANVAS_URL); + front.setup({ reload: true }); + + let [firstProgramActor, secondProgramActor] = yield getPrograms(front, 2); + + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner vs. center pixel colors are correct before blackboxing."); + + yield firstProgramActor.blackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true); + ok(true, "The corner vs. center pixel colors are correct after blackboxing (1)."); + + yield firstProgramActor.unblackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner vs. center pixel colors are correct after unblackboxing (1)."); + + yield secondProgramActor.blackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 255, g: 255, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner vs. center pixel colors are correct after blackboxing (2)."); + + yield secondProgramActor.unblackbox(); + yield ensurePixelIs(front, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true); + yield ensurePixelIs(front, { x: 64, y: 64 }, { r: 0, g: 255, b: 255, a: 255 }, true); + yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true); + ok(true, "The corner vs. center pixel colors are correct after unblackboxing (2)."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js b/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js new file mode 100644 index 000000000..977b07d86 --- /dev/null +++ b/devtools/client/shadereditor/test/browser_webgl-actor-test-18.js @@ -0,0 +1,31 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests the `getPixel` actor method works across threads. + */ + +function* ifWebGLSupported() { + let { target, front } = yield initBackend(MULTIPLE_CONTEXTS_URL); + front.setup({ reload: true }); + + yield getPrograms(front, 2); + + // Wait a frame to ensure rendering + yield front.waitForFrame(); + + let pixel = yield front.getPixel({ selector: "#canvas1", position: { x: 0, y: 0 }}); + is(pixel.r, 255, "correct `r` value for first canvas."); + is(pixel.g, 255, "correct `g` value for first canvas."); + is(pixel.b, 0, "correct `b` value for first canvas."); + is(pixel.a, 255, "correct `a` value for first canvas."); + + pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }}); + is(pixel.r, 0, "correct `r` value for second canvas."); + is(pixel.g, 255, "correct `g` value for second canvas."); + is(pixel.b, 255, "correct `b` value for second canvas."); + is(pixel.a, 255, "correct `a` value for second canvas."); + + yield removeTab(target.tab); + finish(); +} diff --git a/devtools/client/shadereditor/test/doc_blended-geometry.html b/devtools/client/shadereditor/test/doc_blended-geometry.html new file mode 100644 index 000000000..75cad6dc7 --- /dev/null +++ b/devtools/client/shadereditor/test/doc_blended-geometry.html @@ -0,0 +1,136 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> + +<html> + <head> + <meta charset="utf-8"/> + <title>WebGL editor test page</title> + + <script id="shader-vs" type="x-shader/x-vertex"> + precision lowp float; + attribute vec3 aVertexPosition; + uniform float uDepth; + + void main(void) { + gl_Position = vec4(aVertexPosition, uDepth); + } + </script> + + <script id="shader-fs-0" type="x-shader/x-fragment"> + precision lowp float; + + void main(void) { + gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0); + } + </script> + + <script id="shader-fs-1" type="x-shader/x-fragment"> + precision lowp float; + + void main(void) { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + </script> + </head> + + <body> + <canvas id="canvas" width="128" height="128"></canvas> + + <script type="text/javascript;version=1.8"> + "use strict"; + + let canvas, gl; + let program = []; + let squareVerticesPositionBuffer; + let vertexPositionAttribute = []; + let depthUniform = []; + + window.onload = function() { + canvas = document.querySelector("canvas"); + gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + + initProgram(0); + initProgram(1); + initBuffers(); + drawScene(); + } + + function initProgram(i) { + let vertexShader = getShader("shader-vs"); + let fragmentShader = getShader("shader-fs-" + i); + + program[i] = gl.createProgram(); + gl.attachShader(program[i], vertexShader); + gl.attachShader(program[i], fragmentShader); + gl.linkProgram(program[i]); + + vertexPositionAttribute[i] = gl.getAttribLocation(program[i], "aVertexPosition"); + gl.enableVertexAttribArray(vertexPositionAttribute[i]); + + depthUniform[i] = gl.getUniformLocation(program[i], "uDepth"); + } + + function getShader(id) { + let script = document.getElementById(id); + let source = script.textContent; + let shader; + + if (script.type == "x-shader/x-fragment") { + shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + shader = gl.createShader(gl.VERTEX_SHADER); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + + function initBuffers() { + squareVerticesPositionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, + -1.0, -1.0, 0.0 + ]), gl.STATIC_DRAW); + } + + function drawScene() { + gl.clear(gl.COLOR_BUFFER_BIT); + + for (let i = 0; i < 2; i++) { + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.vertexAttribPointer(vertexPositionAttribute[i], 3, gl.FLOAT, false, 0, 0); + + gl.useProgram(program[i]); + gl.uniform1f(depthUniform[i], i + 1); + blend(i); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + window.requestAnimationFrame(drawScene); + } + + function blend(i) { + if (i == 0) { + gl.disable(gl.BLEND); + } + else if (i == 1) { + gl.enable(gl.BLEND); + gl.blendColor(0.5, 0, 0, 0.25); + gl.blendEquationSeparate( + gl.FUNC_REVERSE_SUBTRACT, gl.FUNC_SUBTRACT); + gl.blendFuncSeparate( + gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_COLOR, + gl.ONE_MINUS_CONSTANT_COLOR, gl.CONSTANT_COLOR); + } + } + </script> + </body> + +</html> diff --git a/devtools/client/shadereditor/test/doc_multiple-contexts.html b/devtools/client/shadereditor/test/doc_multiple-contexts.html new file mode 100644 index 000000000..039ee62d0 --- /dev/null +++ b/devtools/client/shadereditor/test/doc_multiple-contexts.html @@ -0,0 +1,112 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> + +<html> + <head> + <meta charset="utf-8"/> + <title>WebGL editor test page</title> + + <script id="shader-vs" type="x-shader/x-vertex"> + precision lowp float; + attribute vec3 aVertexPosition; + + void main(void) { + gl_Position = vec4(aVertexPosition, 1); + } + </script> + + <script id="shader-fs" type="x-shader/x-fragment"> + precision lowp float; + uniform vec3 uColor; + + void main(void) { + gl_FragColor = vec4(uColor, 1); + } + </script> + </head> + + <body> + <canvas id="canvas1" width="128" height="128"></canvas> + <canvas id="canvas2" width="128" height="128"></canvas> + + <script type="text/javascript;version=1.8"> + "use strict"; + + let canvas = [], gl = []; + let program = []; + let squareVerticesPositionBuffer = []; + let vertexPositionAttribute = []; + let colorUniform = []; + + window.onload = function() { + for (let i = 0; i < 2; i++) { + canvas[i] = document.querySelector("#canvas" + (i + 1)); + gl[i] = canvas[i].getContext("webgl", { preserveDrawingBuffer: true }); + gl[i].clearColor(0.0, 0.0, 0.0, 1.0); + + initProgram(i); + initBuffers(i); + drawScene(i); + } + } + + function initProgram(i) { + let vertexShader = getShader(gl[i], "shader-vs"); + let fragmentShader = getShader(gl[i], "shader-fs"); + + program[i] = gl[i].createProgram(); + gl[i].attachShader(program[i], vertexShader); + gl[i].attachShader(program[i], fragmentShader); + gl[i].linkProgram(program[i]); + + vertexPositionAttribute[i] = gl[i].getAttribLocation(program[i], "aVertexPosition"); + gl[i].enableVertexAttribArray(vertexPositionAttribute[i]); + + colorUniform[i] = gl[i].getUniformLocation(program[i], "uColor"); + } + + function getShader(gl, id) { + let script = document.getElementById(id); + let source = script.textContent; + let shader; + + if (script.type == "x-shader/x-fragment") { + shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + shader = gl.createShader(gl.VERTEX_SHADER); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + + function initBuffers(i) { + squareVerticesPositionBuffer[i] = gl[i].createBuffer(); + gl[i].bindBuffer(gl[i].ARRAY_BUFFER, squareVerticesPositionBuffer[i]); + gl[i].bufferData(gl[i].ARRAY_BUFFER, new Float32Array([ + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, + -1.0, -1.0, 0.0 + ]), gl[i].STATIC_DRAW); + } + + function drawScene(i) { + gl[i].clear(gl[i].COLOR_BUFFER_BIT); + + gl[i].bindBuffer(gl[i].ARRAY_BUFFER, squareVerticesPositionBuffer[i]); + gl[i].vertexAttribPointer(vertexPositionAttribute[i], 3, gl[i].FLOAT, false, 0, 0); + + gl[i].useProgram(program[i]); + gl[i].uniform3fv(colorUniform[i], i == 0 ? [1, 1, 0] : [0, 1, 1]); + gl[i].drawArrays(gl[i].TRIANGLE_STRIP, 0, 4); + + window.requestAnimationFrame(() => drawScene(i)); + } + </script> + </body> + +</html> diff --git a/devtools/client/shadereditor/test/doc_overlapping-geometry.html b/devtools/client/shadereditor/test/doc_overlapping-geometry.html new file mode 100644 index 000000000..34be8f57a --- /dev/null +++ b/devtools/client/shadereditor/test/doc_overlapping-geometry.html @@ -0,0 +1,120 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> + +<html> + <head> + <meta charset="utf-8"/> + <title>WebGL editor test page</title> + + <script id="shader-vs" type="x-shader/x-vertex"> + precision lowp float; + attribute vec3 aVertexPosition; + uniform float uDepth; + + void main(void) { + gl_Position = vec4(aVertexPosition, uDepth); + } + </script> + + <script id="shader-fs-0" type="x-shader/x-fragment"> + precision lowp float; + + void main(void) { + gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); + } + </script> + + <script id="shader-fs-1" type="x-shader/x-fragment"> + precision lowp float; + + void main(void) { + gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); + } + </script> + </head> + + <body> + <canvas id="canvas" width="128" height="128"></canvas> + + <script type="text/javascript;version=1.8"> + "use strict"; + + let canvas, gl; + let program = []; + let squareVerticesPositionBuffer; + let vertexPositionAttribute = []; + let depthUniform = []; + + window.onload = function() { + canvas = document.querySelector("canvas"); + gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + + initProgram(0); + initProgram(1); + initBuffers(); + drawScene(); + } + + function initProgram(i) { + let vertexShader = getShader("shader-vs"); + let fragmentShader = getShader("shader-fs-" + i); + + program[i] = gl.createProgram(); + gl.attachShader(program[i], vertexShader); + gl.attachShader(program[i], fragmentShader); + gl.linkProgram(program[i]); + + vertexPositionAttribute[i] = gl.getAttribLocation(program[i], "aVertexPosition"); + gl.enableVertexAttribArray(vertexPositionAttribute[i]); + + depthUniform[i] = gl.getUniformLocation(program[i], "uDepth"); + } + + function getShader(id) { + let script = document.getElementById(id); + let source = script.textContent; + let shader; + + if (script.type == "x-shader/x-fragment") { + shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + shader = gl.createShader(gl.VERTEX_SHADER); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + + function initBuffers() { + squareVerticesPositionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, + -1.0, -1.0, 0.0 + ]), gl.STATIC_DRAW); + } + + function drawScene() { + gl.clear(gl.COLOR_BUFFER_BIT); + + for (let i = 0; i < 2; i++) { + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.vertexAttribPointer(vertexPositionAttribute[i], 3, gl.FLOAT, false, 0, 0); + + gl.useProgram(program[i]); + gl.uniform1f(depthUniform[i], i + 1); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + window.requestAnimationFrame(drawScene); + } + </script> + </body> + +</html> diff --git a/devtools/client/shadereditor/test/doc_shader-order.html b/devtools/client/shadereditor/test/doc_shader-order.html new file mode 100644 index 000000000..a7cec53aa --- /dev/null +++ b/devtools/client/shadereditor/test/doc_shader-order.html @@ -0,0 +1,83 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> + +<html> + <head> + <meta charset="utf-8"/> + <title>WebGL editor test page</title> + + <script id="shader-vs" type="x-shader/x-vertex"> + precision lowp float; + + void main(void) { + gl_Position = vec4(0, 0, 0, 1); // I'm a vertex shader! + } + </script> + + <script id="shader-fs" type="x-shader/x-fragment"> + precision lowp float; + varying vec3 vFragmentColor; + + void main(void) { + gl_FragColor = vec4(1, 0, 0, 1); // I'm a fragment shader! + } + </script> + </head> + + <body> + <canvas width="512" height="512"></canvas> + + <script type="text/javascript;version=1.8"> + "use strict"; + + let canvas, gl; + + window.onload = function() { + canvas = document.querySelector("canvas"); + gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }); + + let shaderProgram = gl.createProgram(); + let vertexShader, fragmentShader; + + // Compile and attach the shaders in a random order. The test will + // ensure that the correct vertex and fragment source is retrieved + // regardless of this crazyness. + if (Math.random() > 0.5) { + vertexShader = getShader(gl, "shader-vs"); + fragmentShader = getShader(gl, "shader-fs"); + } else { + fragmentShader = getShader(gl, "shader-fs"); + vertexShader = getShader(gl, "shader-vs"); + } + if (Math.random() > 0.5) { + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + } else { + gl.attachShader(shaderProgram, fragmentShader); + gl.attachShader(shaderProgram, vertexShader); + } + + gl.linkProgram(shaderProgram); + } + + function getShader(gl, id) { + let script = document.getElementById(id); + let source = script.textContent; + let shader; + + if (script.type == "x-shader/x-fragment") { + shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + shader = gl.createShader(gl.VERTEX_SHADER); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + </script> + </body> + +</html> diff --git a/devtools/client/shadereditor/test/doc_simple-canvas.html b/devtools/client/shadereditor/test/doc_simple-canvas.html new file mode 100644 index 000000000..2a709ad8e --- /dev/null +++ b/devtools/client/shadereditor/test/doc_simple-canvas.html @@ -0,0 +1,125 @@ +<!-- Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ --> +<!doctype html> + +<html> + <head> + <meta charset="utf-8"/> + <title>WebGL editor test page</title> + + <script id="shader-vs" type="x-shader/x-vertex"> + precision lowp float; + attribute vec3 aVertexPosition; + attribute vec3 aVertexColor; + varying vec3 vFragmentColor; + + void main(void) { + gl_Position = vec4(aVertexPosition, 1.0); + vFragmentColor = aVertexColor; // I'm special! + } + </script> + + <script id="shader-fs" type="x-shader/x-fragment"> + precision lowp float; + varying vec3 vFragmentColor; + + void main(void) { + gl_FragColor = vec4(vFragmentColor, 1.0); // I'm also special! + } + </script> + </head> + + <body> + <canvas width="512" height="512"></canvas> + + <script type="text/javascript;version=1.8"> + "use strict"; + + let canvas, gl; + let program; + let squareVerticesPositionBuffer; + let squareVerticesColorBuffer; + let vertexPositionAttribute; + let vertexColorAttribute; + + window.onload = function() { + canvas = document.querySelector("canvas"); + gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }); + gl.clearColor(0.0, 0.0, 0.0, 1.0); + + initProgram(); + initBuffers(); + drawScene(); + } + + function initProgram() { + let vertexShader = getShader(gl, "shader-vs"); + let fragmentShader = getShader(gl, "shader-fs"); + + program = gl.createProgram(); + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + gl.linkProgram(program); + + vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition"); + gl.enableVertexAttribArray(vertexPositionAttribute); + + vertexColorAttribute = gl.getAttribLocation(program, "aVertexColor"); + gl.enableVertexAttribArray(vertexColorAttribute); + } + + function getShader(gl, id) { + let script = document.getElementById(id); + let source = script.textContent; + let shader; + + if (script.type == "x-shader/x-fragment") { + shader = gl.createShader(gl.FRAGMENT_SHADER); + } else if (script.type == "x-shader/x-vertex") { + shader = gl.createShader(gl.VERTEX_SHADER); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; + } + + function initBuffers() { + squareVerticesPositionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + 1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, + -1.0, -1.0, 0.0 + ]), gl.STATIC_DRAW); + + squareVerticesColorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + 1.0, 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 1.0 + ]), gl.STATIC_DRAW); + } + + function drawScene() { + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer); + gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer); + gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0); + + gl.useProgram(program); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + + window.requestAnimationFrame(drawScene); + } + </script> + </body> + +</html> diff --git a/devtools/client/shadereditor/test/head.js b/devtools/client/shadereditor/test/head.js new file mode 100644 index 000000000..754a0605d --- /dev/null +++ b/devtools/client/shadereditor/test/head.js @@ -0,0 +1,292 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); +var { Task } = require("devtools/shared/task"); + +var Services = require("Services"); +var promise = require("promise"); +var { gDevTools } = require("devtools/client/framework/devtools"); +var { DebuggerClient } = require("devtools/shared/client/main"); +var { DebuggerServer } = require("devtools/server/main"); +var { WebGLFront } = require("devtools/shared/fronts/webgl"); +var DevToolsUtils = require("devtools/shared/DevToolsUtils"); +var flags = require("devtools/shared/flags"); +var { TargetFactory } = require("devtools/client/framework/target"); +var { Toolbox } = require("devtools/client/framework/toolbox"); +var { isWebGLSupported } = require("devtools/client/shared/webgl-utils"); +var mm = null; + +const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js"; +const EXAMPLE_URL = "http://example.com/browser/devtools/client/shadereditor/test/"; +const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html"; +const SHADER_ORDER_URL = EXAMPLE_URL + "doc_shader-order.html"; +const MULTIPLE_CONTEXTS_URL = EXAMPLE_URL + "doc_multiple-contexts.html"; +const OVERLAPPING_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_overlapping-geometry.html"; +const BLENDED_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_blended-geometry.html"; + +var gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); +// To enable logging for try runs, just set the pref to true. +Services.prefs.setBoolPref("devtools.debugger.log", false); + +// All tests are asynchronous. +waitForExplicitFinish(); + +var gToolEnabled = Services.prefs.getBoolPref("devtools.shadereditor.enabled"); + +flags.testing = true; + +registerCleanupFunction(() => { + info("finish() was called, cleaning up..."); + flags.testing = false; + Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); + Services.prefs.setBoolPref("devtools.shadereditor.enabled", gToolEnabled); + + // These tests use a lot of memory due to GL contexts, so force a GC to help + // fragmentation. + info("Forcing GC after shadereditor test."); + Cu.forceGC(); +}); + +/** + * Call manually in tests that use frame script utils after initializing + * the shader editor. Must be called after initializing so we can detect + * whether or not `content` is a CPOW or not. Call after init but before navigating + * to different pages, as bfcache and thus shader caching gets really strange if + * frame script attached in the middle of the test. + */ +function loadFrameScripts() { + if (Cu.isCrossProcessWrapper(content)) { + mm = gBrowser.selectedBrowser.messageManager; + mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false); + } +} + +function addTab(aUrl, aWindow) { + info("Adding tab: " + aUrl); + + let deferred = promise.defer(); + let targetWindow = aWindow || window; + let targetBrowser = targetWindow.gBrowser; + + targetWindow.focus(); + let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl); + let linkedBrowser = tab.linkedBrowser; + + BrowserTestUtils.browserLoaded(linkedBrowser).then(function () { + info("Tab added and finished loading: " + aUrl); + deferred.resolve(tab); + }); + + return deferred.promise; +} + +function removeTab(aTab, aWindow) { + info("Removing tab."); + + let deferred = promise.defer(); + let targetWindow = aWindow || window; + let targetBrowser = targetWindow.gBrowser; + let tabContainer = targetBrowser.tabContainer; + + tabContainer.addEventListener("TabClose", function onClose(aEvent) { + tabContainer.removeEventListener("TabClose", onClose, false); + info("Tab removed and finished closing."); + deferred.resolve(); + }, false); + + targetBrowser.removeTab(aTab); + return deferred.promise; +} + +function handleError(aError) { + ok(false, "Got an error: " + aError.message + "\n" + aError.stack); + finish(); +} + +function ifWebGLSupported() { + ok(false, "You need to define a 'ifWebGLSupported' function."); + finish(); +} + +function ifWebGLUnsupported() { + todo(false, "Skipping test because WebGL isn't supported."); + finish(); +} + +function test() { + let generator = isWebGLSupported(document) ? ifWebGLSupported : ifWebGLUnsupported; + Task.spawn(generator).then(null, handleError); +} + +function createCanvas() { + return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); +} + +function once(aTarget, aEventName, aUseCapture = false) { + info("Waiting for event: '" + aEventName + "' on " + aTarget + "."); + + let deferred = promise.defer(); + + for (let [add, remove] of [ + ["on", "off"], // Use event emitter before DOM events for consistency + ["addEventListener", "removeEventListener"], + ["addListener", "removeListener"] + ]) { + if ((add in aTarget) && (remove in aTarget)) { + aTarget[add](aEventName, function onEvent(...aArgs) { + aTarget[remove](aEventName, onEvent, aUseCapture); + deferred.resolve(...aArgs); + }, aUseCapture); + break; + } + } + + return deferred.promise; +} + +// Hack around `once`, as that only resolves to a single (first) argument +// and discards the rest. `onceSpread` is similar, except resolves to an +// array of all of the arguments in the handler. These should be consolidated +// into the same function, but many tests will need to be changed. +function onceSpread(aTarget, aEvent) { + let deferred = promise.defer(); + aTarget.once(aEvent, (...args) => deferred.resolve(args)); + return deferred.promise; +} + +function observe(aNotificationName, aOwnsWeak = false) { + info("Waiting for observer notification: '" + aNotificationName + "."); + + let deferred = promise.defer(); + + Services.obs.addObserver(function onNotification(...aArgs) { + Services.obs.removeObserver(onNotification, aNotificationName); + deferred.resolve.apply(deferred, aArgs); + }, aNotificationName, aOwnsWeak); + + return deferred.promise; +} + +function isApprox(aFirst, aSecond, aMargin = 1) { + return Math.abs(aFirst - aSecond) <= aMargin; +} + +function isApproxColor(aFirst, aSecond, aMargin) { + return isApprox(aFirst.r, aSecond.r, aMargin) && + isApprox(aFirst.g, aSecond.g, aMargin) && + isApprox(aFirst.b, aSecond.b, aMargin) && + isApprox(aFirst.a, aSecond.a, aMargin); +} + +function ensurePixelIs(aFront, aPosition, aColor, aWaitFlag = false, aSelector = "canvas") { + return Task.spawn(function* () { + let pixel = yield aFront.getPixel({ selector: aSelector, position: aPosition }); + if (isApproxColor(pixel, aColor)) { + ok(true, "Expected pixel is shown at: " + aPosition.toSource()); + return; + } + + if (aWaitFlag) { + yield aFront.waitForFrame(); + return ensurePixelIs(aFront, aPosition, aColor, aWaitFlag, aSelector); + } + + ok(false, "Expected pixel was not already shown at: " + aPosition.toSource()); + throw new Error("Expected pixel was not already shown at: " + aPosition.toSource()); + }); +} + +function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") { + if (Cu.isCrossProcessWrapper(content)) { + if (!mm) { + throw new Error("`loadFrameScripts()` must be called before attempting to navigate in e10s."); + } + mm.sendAsyncMessage("devtools:test:history", { direction: aDirection }); + } + else { + executeSoon(() => content.history[aDirection]()); + } + return once(aTarget, aWaitForTargetEvent); +} + +function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { + executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); + return once(aTarget, aWaitForTargetEvent); +} + +function reload(aTarget, aWaitForTargetEvent = "navigate") { + executeSoon(() => aTarget.activeTab.reload()); + return once(aTarget, aWaitForTargetEvent); +} + +function initBackend(aUrl) { + info("Initializing a shader editor front."); + + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } + + return Task.spawn(function* () { + let tab = yield addTab(aUrl); + let target = TargetFactory.forTab(tab); + + yield target.makeRemote(); + + let front = new WebGLFront(target.client, target.form); + return { target, front }; + }); +} + +function initShaderEditor(aUrl) { + info("Initializing a shader editor pane."); + + return Task.spawn(function* () { + let tab = yield addTab(aUrl); + let target = TargetFactory.forTab(tab); + + yield target.makeRemote(); + + Services.prefs.setBoolPref("devtools.shadereditor.enabled", true); + let toolbox = yield gDevTools.showToolbox(target, "shadereditor"); + let panel = toolbox.getCurrentPanel(); + return { target, panel }; + }); +} + +function teardown(aPanel) { + info("Destroying the specified shader editor."); + + return promise.all([ + once(aPanel, "destroyed"), + removeTab(aPanel.target.tab) + ]); +} + +// Due to `program-linked` events firing synchronously, we cannot +// just yield/chain them together, as then we miss all actors after the +// first event since they're fired consecutively. This allows us to capture +// all actors and returns an array containing them. +// +// Takes a `front` object that is an event emitter, the number of +// programs that should be listened to and waited on, and an optional +// `onAdd` function that calls with the entire actors array on program link +function getPrograms(front, count, onAdd) { + let actors = []; + let deferred = promise.defer(); + front.on("program-linked", function onLink(actor) { + if (actors.length !== count) { + actors.push(actor); + if (typeof onAdd === "function") onAdd(actors); + } + if (actors.length === count) { + front.off("program-linked", onLink); + deferred.resolve(actors); + } + }); + return deferred.promise; +} |