Skip to content

Commit

Permalink
Minimize image/video/canvas texture updates
Browse files Browse the repository at this point in the history
Static image sources were getting the image texture uploaded on every frame, as were paused canvas and video sources.
  • Loading branch information
jfirebaugh committed Dec 14, 2017
1 parent 0ed0460 commit 1d86f68
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 25 deletions.
3 changes: 1 addition & 2 deletions debug/canvas.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@
[-122.51467645168304, 37.56410183312965],
[-122.51309394836426, 37.563391708549425],
[-122.51423120498657, 37.56161849366671]
],
"contextType": '2d'
]
}
},
"layers": [{
Expand Down
6 changes: 4 additions & 2 deletions src/render/texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const {HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, ImageData} = requi

import type Context from '../gl/context';
import type {RGBAImage, AlphaImage} from '../util/image';
import type {ImageTextureSource} from '../source/image_source';

export type TextureFormat =
| $PropertyType<WebGLRenderingContext, 'RGBA'>
Expand All @@ -27,7 +26,10 @@ type EmptyImage = {
export type TextureImage =
| RGBAImage
| AlphaImage
| ImageTextureSource
| HTMLImageElement
| HTMLCanvasElement
| HTMLVideoElement
| ImageData
| EmptyImage;

class Texture {
Expand Down
31 changes: 30 additions & 1 deletion src/source/canvas_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

const ImageSource = require('./image_source');
const window = require('../util/window');
const VertexArrayObject = require('../render/vertex_array_object');
const Texture = require('../render/texture');

import type Map from '../ui/map';
import type Dispatcher from '../util/dispatcher';
Expand Down Expand Up @@ -134,7 +136,34 @@ class CanvasSource extends ImageSource {

if (Object.keys(this.tiles).length === 0) return; // not enough data for current position

this._prepareImage(this.map.painter.context, this.canvas, resize);
const context = this.map.painter.context;
const gl = context.gl;

if (!this.boundsBuffer) {
this.boundsBuffer = context.createVertexBuffer(this._boundsArray);
}

if (!this.boundsVAO) {
this.boundsVAO = new VertexArrayObject();
}

if (!this.texture) {
this.texture = new Texture(context, this.canvas, gl.RGBA);
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
} else if (resize) {
this.texture.update(this.canvas);
} else if (this._playing) {
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
}

for (const w in this.tiles) {
const tile = this.tiles[w];
if (tile.state !== 'loaded') {
tile.state = 'loaded';
tile.texture = this.texture;
}
}
}

serialize(): Object {
Expand Down
24 changes: 6 additions & 18 deletions src/source/image_source.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// @flow

const util = require('../util/util');
const window = require('../util/window');
const {CanonicalTileID} = require('./tile_id');
const LngLat = require('../geo/lng_lat');
const Point = require('@mapbox/point-geometry');
Expand All @@ -19,15 +18,8 @@ import type Dispatcher from '../util/dispatcher';
import type Tile from './tile';
import type Coordinate from '../geo/coordinate';
import type {Callback} from '../types/callback';
import type Context from '../gl/context';
import type VertexBuffer from '../gl/vertex_buffer';

export type ImageTextureSource =
ImageData |
HTMLImageElement |
HTMLCanvasElement |
HTMLVideoElement;

/**
* A data source containing an image.
* (See the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#sources-image) for detailed documentation of options.)
Expand Down Expand Up @@ -185,12 +177,13 @@ class ImageSource extends Evented implements Source {
}

prepare() {
if (Object.keys(this.tiles).length === 0 || !this.image) return;
this._prepareImage(this.map.painter.context, this.image);
}
if (Object.keys(this.tiles).length === 0 || !this.image) {
return;
}

_prepareImage(context: Context, image: ImageTextureSource, resize?: boolean) {
const context = this.map.painter.context;
const gl = context.gl;

if (!this.boundsBuffer) {
this.boundsBuffer = context.createVertexBuffer(this._boundsArray);
}
Expand All @@ -200,13 +193,8 @@ class ImageSource extends Evented implements Source {
}

if (!this.texture) {
this.texture = new Texture(context, image, gl.RGBA);
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
} else if (resize) {
this.texture.update(image);
} else if (image instanceof window.HTMLVideoElement || image instanceof window.ImageData || image instanceof window.HTMLCanvasElement) {
this.texture = new Texture(context, this.image, gl.RGBA);
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
}

for (const w in this.tiles) {
Expand Down
34 changes: 32 additions & 2 deletions src/source/video_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

const ajax = require('../util/ajax');
const ImageSource = require('./image_source');
const VertexArrayObject = require('../render/vertex_array_object');
const Texture = require('../render/texture');

import type Map from '../ui/map';
import type Dispatcher from '../util/dispatcher';
Expand Down Expand Up @@ -112,8 +114,36 @@ class VideoSource extends ImageSource {
// setCoordinates inherited from ImageSource

prepare() {
if (Object.keys(this.tiles).length === 0 || this.video.readyState < 2) return; // not enough data for current position
this._prepareImage(this.map.painter.context, this.video);
if (Object.keys(this.tiles).length === 0 || this.video.readyState < 2) {
return; // not enough data for current position
}

const context = this.map.painter.context;
const gl = context.gl;

if (!this.boundsBuffer) {
this.boundsBuffer = context.createVertexBuffer(this._boundsArray);
}

if (!this.boundsVAO) {
this.boundsVAO = new VertexArrayObject();
}

if (!this.texture) {
this.texture = new Texture(context, this.video, gl.RGBA);
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
} else if (!this.video.paused) {
this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.video);
}

for (const w in this.tiles) {
const tile = this.tiles[w];
if (tile.state !== 'loaded') {
tile.state = 'loaded';
tile.texture = this.texture;
}
}
}

serialize() {
Expand Down

0 comments on commit 1d86f68

Please sign in to comment.