mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 14:46:10 +03:00
Add functional test for problems with WebGL and fall back to canvas if needed
This commit is contained in:
parent
e1e0ec6b24
commit
fb374fc286
@ -3905,7 +3905,7 @@ function drawWorld( viewer ) {
|
||||
viewer.world.draw();
|
||||
|
||||
/**
|
||||
* <em>- Needs documentation -</em>
|
||||
* This event is raised any time the viewer has rendered a new frame.
|
||||
*
|
||||
* @event update-viewport
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
|
@ -36,7 +36,7 @@
|
||||
(function( $ ){
|
||||
|
||||
const OpenSeadragon = $; // alias for JSDoc
|
||||
|
||||
let testing = false;
|
||||
/**
|
||||
* @class OpenSeadragon.WebGLDrawer
|
||||
* @classdesc Default implementation of WebGLDrawer for an {@link OpenSeadragon.Viewer}. The WebGLDrawer
|
||||
@ -110,7 +110,9 @@
|
||||
|
||||
this.context = this._outputContext; // API required by tests
|
||||
|
||||
}
|
||||
this._requiresCanvasDrawerFallback = false;
|
||||
this._doRenderingTest();
|
||||
}
|
||||
|
||||
// Public API required by all Drawer implementations
|
||||
/**
|
||||
@ -281,7 +283,7 @@
|
||||
//iterate over tiled images and draw each one using a two-pass rendering pipeline if needed
|
||||
tiledImages.forEach( (tiledImage, tiledImageIndex) => {
|
||||
|
||||
if(tiledImage.isTainted()){
|
||||
if(tiledImage.isTainted() || this._requiresCanvasDrawerFallback ){
|
||||
// first, draw any data left in the rendering buffer onto the output canvas
|
||||
if(renderingBufferHasImageData){
|
||||
this._outputContext.drawImage(this._renderingCanvas, 0, 0);
|
||||
@ -1325,6 +1327,79 @@
|
||||
return shaderProgram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test webgl rendering in the current browser by drawing a small image
|
||||
* in a new viewer. If all pixel data is 0, rendering failed, and fallback
|
||||
* to the CanvasDrawer is required for all tiled images.
|
||||
* @private
|
||||
* @returns
|
||||
*/
|
||||
_doRenderingTest(){
|
||||
// Avoid infinite call stack by only testing once
|
||||
if( testing ){
|
||||
this._isTestingViewer = true;
|
||||
return;
|
||||
}
|
||||
// Set the testing flag to true until the test viewer has been created
|
||||
testing = true;
|
||||
|
||||
// A dataUrl with non-zero pixels to use
|
||||
const dataUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAASgAwAEAAAAAQAAAAQAAAAANlaTAQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGV7hBwAAAElJREFUCB1jZACCa5uWJr/78JHVhkNkNuPpmhy/b5+Z1/74/vPzr2/3y1junTr5QYf1NAsDI4Pg1ivin0E6GLbnMDhsTmHwArEBM20b4j0ge4MAAAAASUVORK5CYII=";
|
||||
|
||||
// Create a small element for the test viewer and append it to our viewer's element
|
||||
const div = document.createElement('div');
|
||||
div.setAttribute('id', 'osd_internal_test');
|
||||
div.style.width = '4px';
|
||||
div.style.height = '4px';
|
||||
div.style.position = 'fixed';
|
||||
div.style.top = 0;
|
||||
div.style.left = 0;
|
||||
this.viewer.element.appendChild( div );
|
||||
|
||||
// create the test viewer
|
||||
const testViewer = $( { element: div, drawer: 'webgl', navigator: false } );
|
||||
|
||||
// reset testing flag to false so additional viewers can be tested
|
||||
testing = false;
|
||||
|
||||
// Once a frame is drawn, check the pixel values in the output canvas
|
||||
testViewer.addOnceHandler('update-viewport', () => {
|
||||
const numNonZeroValues = testViewer.drawer._outputContext.getImageData(0, 0, 4, 4).data.filter( pixel => pixel > 0).length;
|
||||
// If all values are zero, rendering failed. Set a flag and issue a warning.
|
||||
this._requiresCanvasDrawerFallback = ( numNonZeroValues === 0);
|
||||
if( this._requiresCanvasDrawerFallback ){
|
||||
$.console.warn('A problem was detected with webgl rendering. Falling back to CanvasDrawer.');
|
||||
|
||||
// Raise an event so applications can handle this more gracefully if needed
|
||||
/**
|
||||
* This event is fired if a WebGLDrawer detects a problem with rendering and
|
||||
* requires fallback to CanvasDrawer. This fallback happens automatically,
|
||||
* but some applications may not desire this and would wish to explicitly handle
|
||||
* the error in a different way, for example by removing and/or re-creating the viewer with
|
||||
* different settings.
|
||||
*
|
||||
* @event webgl-error
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
|
||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||
*/
|
||||
this.viewer.raiseEvent('webgl-error', { });
|
||||
}
|
||||
|
||||
// Clean up the test viewer
|
||||
setTimeout( () => testViewer.destroy(), 0);
|
||||
this.viewer.element.removeChild(div);
|
||||
});
|
||||
|
||||
// Open the test image using the dataUrl from above
|
||||
const testSource = {
|
||||
url: dataUrl,
|
||||
type: 'image'
|
||||
};
|
||||
testViewer.open( testSource );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user