src/renderers/WebGlCommon.js
function setViewport(gl, layer, rect, viewportMatrix) {
  if (rect.x === 0 && rect.width === 1 && rect.y === 0 && rect.height === 1) {
    // Fast path for full rect.
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
    mat4.identity(viewportMatrix);
    return;
  }

  var offsetX = rect.x;
  var clampedOffsetX = clamp(offsetX, 0, 1);
  var leftExcess = clampedOffsetX - offsetX;
  var maxClampedWidth = 1 - clampedOffsetX;
  var clampedWidth = clamp(rect.width - leftExcess, 0, maxClampedWidth);
  var rightExcess = rect.width - clampedWidth;

  var offsetY = 1 - rect.height - rect.y;
  var clampedOffsetY = clamp(offsetY, 0, 1);
  var bottomExcess = clampedOffsetY - offsetY;
  var maxClampedHeight = 1 - clampedOffsetY;
  var clampedHeight = clamp(rect.height - bottomExcess, 0, maxClampedHeight);
  var topExcess = rect.height - clampedHeight;

  vec3.set(
    scaleVector,
    rect.width / clampedWidth,
    rect.height / clampedHeight,
    1);

  vec3.set(
    translateVector,
    (rightExcess - leftExcess) / clampedWidth,
    (topExcess - bottomExcess) / clampedHeight,
    0);

  mat4.identity(viewportMatrix);
  mat4.translate(viewportMatrix, viewportMatrix, translateVector);
  mat4.scale(viewportMatrix, viewportMatrix, scaleVector);

  gl.viewport(gl.drawingBufferWidth * clampedOffsetX,
              gl.drawingBufferHeight * clampedOffsetY,
              gl.drawingBufferWidth * clampedWidth,
              gl.drawingBufferHeight * clampedHeight);
}
function setViewport(gl, layer, rect, viewportMatrix) {
  if (rect.x === 0 && rect.width === 1 && rect.y === 0 && rect.height === 1) {
    // Fast path for full rect.
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
    mat4.identity(viewportMatrix);
    return;
  }

  var offsetX = rect.x;
  var clampedOffsetX = clamp(offsetX, 0, 1);
  var leftExcess = clampedOffsetX - offsetX;
  var maxClampedWidth = 1 - clampedOffsetX;
  var clampedWidth = clamp(rect.width - leftExcess, 0, maxClampedWidth);
  var rightExcess = rect.width - clampedWidth;

  var offsetY = 1 - rect.height - rect.y;
  var clampedOffsetY = clamp(offsetY, 0, 1);
  var bottomExcess = clampedOffsetY - offsetY;
  var maxClampedHeight = 1 - clampedOffsetY;
  var clampedHeight = clamp(rect.height - bottomExcess, 0, maxClampedHeight);
  var topExcess = rect.height - clampedHeight;

  vec3.set(
    scaleVector,
    rect.width / clampedWidth,
    rect.height / clampedHeight,
    1);

  vec3.set(
    translateVector,
    (rightExcess - leftExcess) / clampedWidth,
    (topExcess - bottomExcess) / clampedHeight,
    0);

  mat4.identity(viewportMatrix);
  mat4.translate(viewportMatrix, viewportMatrix, translateVector);
  mat4.scale(viewportMatrix, viewportMatrix, scaleVector);

  gl.viewport(gl.drawingBufferWidth * clampedOffsetX,
              gl.drawingBufferHeight * clampedOffsetY,
              gl.drawingBufferWidth * clampedWidth,
              gl.drawingBufferHeight * clampedHeight);
}
function setViewport ( gl , layer , rect , viewportMatrix ) { if ( rect . x === 0 && rect . width === 1 && rect . y === 0 && rect . height === 1 ) { // Fast path for full rect. gl . viewport ( 0 , 0 , gl . drawingBufferWidth , gl . drawingBufferHeight ) ; mat4 . identity ( viewportMatrix ) ; return ; } var offsetX = rect . x ; var clampedOffsetX = clamp ( offsetX , 0 , 1 ) ; var leftExcess = clampedOffsetX - offsetX ; var maxClampedWidth = 1 - clampedOffsetX ; var clampedWidth = clamp ( rect . width - leftExcess , 0 , maxClampedWidth ) ; var rightExcess = rect . width - clampedWidth ; var offsetY = 1 - rect . height - rect . y ; var clampedOffsetY = clamp ( offsetY , 0 , 1 ) ; var bottomExcess = clampedOffsetY - offsetY ; var maxClampedHeight = 1 - clampedOffsetY ; var clampedHeight = clamp ( rect . height - bottomExcess , 0 , maxClampedHeight ) ; var topExcess = rect . height - clampedHeight ; vec3 . set ( scaleVector , rect . width / clampedWidth , rect . height / clampedHeight , 1 ) ; vec3 . set ( translateVector , ( rightExcess - leftExcess ) / clampedWidth , ( topExcess - bottomExcess ) / clampedHeight , 0 ) ; mat4 . identity ( viewportMatrix ) ; mat4 . translate ( viewportMatrix , viewportMatrix , translateVector ) ; mat4 . scale ( viewportMatrix , viewportMatrix , scaleVector ) ; gl . viewport ( gl . drawingBufferWidth * clampedOffsetX , gl . drawingBufferHeight * clampedOffsetY , gl . drawingBufferWidth * clampedWidth , gl . drawingBufferHeight * clampedHeight ) ; }
Sets the WebGL viewport and returns a viewport clamping compensation matrix.  Negative viewport origin coordinates cause rendering issues. Letting the viewport dimensions extend beyond the visible area do not seem to cause rendering issues, but they may still have an impact on performance. Therefore, when the scene's rect is not fully contained in the rendering area, we clamp the viewport to the rendering area, and return a compensation matrix to scale and translate vertices accordingly.
Sets the WebGL viewport and returns a viewport clamping compensation matrix . Negative viewport origin coordinates cause rendering issues . Letting the viewport dimensions extend beyond the visible area do not seem to cause rendering issues but they may still have an impact on performance . Therefore when the scene s rect is not fully contained in the rendering area we clamp the viewport to the rendering area and return a compensation matrix to scale and translate vertices accordingly .