Skip to content

Commit

Permalink
Create Framebuffer class, remove RenderTexture
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauren Budorick committed Dec 2, 2017
1 parent 722ae7c commit a541fae
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 107 deletions.
3 changes: 2 additions & 1 deletion flow-typed/window.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ declare interface Window extends EventTarget, IDBEnvironment {
Image: typeof Image;
ImageData: typeof ImageData;
URL: typeof URL;
webkitURL: typeof URL;
URLSearchParams: typeof URLSearchParams;
WebGLFramebuffer: typeof WebGLFramebuffer;
webkitURL: typeof URL;
WheelEvent: typeof WheelEvent;
Worker: typeof Worker;
XMLHttpRequest: typeof XMLHttpRequest;
Expand Down
16 changes: 16 additions & 0 deletions src/gl/context.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
const IndexBuffer = require('./index_buffer');
const VertexBuffer = require('./vertex_buffer');
const Framebuffer = require('./framebuffer');
const State = require('./state');
const {
ClearColor,
Expand Down Expand Up @@ -128,6 +129,21 @@ class Context {
return new VertexBuffer(this, array, dynamicDraw);
}

createRenderbuffer(storageFormat: number, width: number, height: number) {
const gl = this.gl;

const rbo = gl.createRenderbuffer();
this.bindRenderbuffer.set(rbo);
gl.renderbufferStorage(gl.RENDERBUFFER, storageFormat, width, height);
this.bindRenderbuffer.set(null);

return rbo;
}

createFramebuffer() {
return new Framebuffer(this);
}

clear({color, depth}: ClearArgs) {
const gl = this.gl;
let mask = 0;
Expand Down
23 changes: 23 additions & 0 deletions src/gl/framebuffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// @flow
const State = require('./state');
const { ColorAttachment, DepthAttachment } = require('./value');

import type Context from './context';

class Framebuffer {
context: Context;
framebuffer: WebGLFramebuffer;
colorAttachment: State<?WebGLTexture>;
depthAttachment: State<?WebGLRenderbuffer>;

constructor(context: Context) {
this.context = context;
const gl = context.gl;
const fbo = this.framebuffer = gl.createFramebuffer();

this.colorAttachment = new State(new ColorAttachment(context, fbo));
this.depthAttachment = new State(new DepthAttachment(context, fbo));
}
}

module.exports = Framebuffer;
10 changes: 9 additions & 1 deletion src/gl/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ class State<T> {
}

set(t: T) {
if (!this.value.constructor.equal(this.current, t)) {
if (this.dirty || !this.value.constructor.equal(this.current, t)) {
this.current = t;
this.value.set(t);
}
}

isDirty(): boolean {
return this.dirty;
}

setDirty(): void {
this.dirty = true;
}
}

module.exports = State;
52 changes: 50 additions & 2 deletions src/gl/value.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// @flow
const assert = require('assert');

const Color = require('../style-spec/util/color');
const util = require('../util/util');
const window = require('../util/window');

import type Context from './context';
import type {
Expand All @@ -15,7 +17,6 @@ import type {
ViewportType,
} from './types';


export interface Value<T> {
context: Context;
static default(context?: Context): T;
Expand All @@ -25,9 +26,13 @@ export interface Value<T> {

class ContextValue {
context: Context;
parent: ?any;

constructor(context: Context) {
constructor(context: Context, parent: ?any) {
this.context = context;
if (parent) {
this.parent = parent;
}
}

static equal(a, b): boolean {
Expand Down Expand Up @@ -324,6 +329,46 @@ class PixelStoreUnpackPremultiplyAlpha extends ContextValue implements Value<boo
}
}

/**
* Framebuffer values
*/

class ColorAttachment extends ContextValue implements Value<?WebGLTexture> {
static default() { return null; }

set(v: ?WebGLTexture): void {
assert(this.parent && this.parent instanceof window.WebGLFramebuffer);

const gl = this.context.gl;
this.context.bindFramebuffer.set(this.parent);
// note: it's possible to attach a renderbuffer to the color
// attachment point, but thus far MBGL only uses textures for color
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, v, 0);
}

static equal(a, b): boolean {
return a === b;
}
}

class DepthAttachment extends ContextValue implements Value<?WebGLRenderbuffer> {
static default() { return null; }

set(v: ?WebGLRenderbuffer): void {
assert(this.parent && this.parent instanceof window.WebGLFramebuffer);

const gl = this.context.gl;
this.context.bindFramebuffer.set(this.parent);
// note: it's possible to attach a texture to the depth attachment
// point, but thus far MBGL only uses renderbuffers for depth
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, v);
}

static equal(a, b): boolean {
return a === b;
}
}

module.exports = {
ClearColor,
ClearDepth,
Expand Down Expand Up @@ -352,4 +397,7 @@ module.exports = {
BindVertexArrayOES,
PixelStoreUnpack,
PixelStoreUnpackPremultiplyAlpha,

ColorAttachment,
DepthAttachment,
};
4 changes: 2 additions & 2 deletions src/render/draw_fill_extrusion.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ function drawExtrusionTexture(painter, layer) {
context.stencilTest.set(false);
context.depthTest.set(false);

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, renderedTexture.texture);
context.activeTexture.set(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, renderedTexture.colorAttachment.get());

gl.uniform1f(program.uniforms.u_opacity, layer.paint.get('fill-extrusion-opacity'));
gl.uniform1i(program.uniforms.u_image, 0);
Expand Down
10 changes: 5 additions & 5 deletions src/render/draw_heatmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,21 @@ function renderToTexture(context, painter, layer) {
let texture = layer.heatmapTexture;
let fbo = layer.heatmapFbo;

if (!texture) {
if (!texture || !fbo) {
texture = layer.heatmapTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

fbo = layer.heatmapFbo = gl.createFramebuffer();
fbo = layer.heatmapFbo = context.createFramebuffer();

bindTextureFramebuffer(context, painter, texture, fbo);

} else {
gl.bindTexture(gl.TEXTURE_2D, texture);
context.bindFramebuffer.set(fbo);
context.bindFramebuffer.set(fbo.framebuffer);
}
}

Expand All @@ -106,12 +106,12 @@ function bindTextureFramebuffer(context, painter, texture, fbo) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, painter.width / 4, painter.height / 4, 0, gl.RGBA,
painter.extTextureHalfFloat ? painter.extTextureHalfFloat.HALF_FLOAT_OES : gl.UNSIGNED_BYTE, null);

context.bindFramebuffer.set(fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
fbo.colorAttachment.set(texture);

// If using half-float texture as a render target is not supported, fall back to a low precision texture
if (painter.extTextureHalfFloat && gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
painter.extTextureHalfFloat = null;
fbo.colorAttachment.setDirty();
bindTextureFramebuffer(context, painter, texture, fbo);
}
}
Expand Down
18 changes: 11 additions & 7 deletions src/render/draw_hillshade.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// @flow
const TileCoord = require('../source/tile_coord');
const Texture = require('./texture');
const RenderTexture = require('./render_texture');
const EXTENT = require('../data/extent');
const mat4 = require('@mapbox/gl-matrix').mat4;

Expand Down Expand Up @@ -29,6 +28,8 @@ function drawHillshade(painter: Painter, sourceCache: SourceCache, layer: Hillsh
}
}

context.viewport.set([0, 0, painter.width, painter.height]);
context.bindFramebuffer.set(null);
}

function setLight(program, painter, layer) {
Expand Down Expand Up @@ -56,7 +57,8 @@ function renderHillshade(painter, tile, layer) {
// for scaling the magnitude of a points slope by its latitude
const latRange = getTileLatRange(painter, tile.coord);
context.activeTexture.set(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tile.texture.texture);

gl.bindTexture(gl.TEXTURE_2D, tile.texture.colorAttachment.get());

gl.uniformMatrix4fv(program.uniforms.u_matrix, false, posMatrix);
gl.uniform2fv(program.uniforms.u_latrange, latRange);
Expand Down Expand Up @@ -124,10 +126,14 @@ function prepareHillshade(painter, tile) {

context.activeTexture.set(gl.TEXTURE0);
if (!tile.texture) {
tile.texture = new RenderTexture(painter, tileSize, tileSize);
} else {
tile.texture.bindFbo();
const _texture = new Texture(context, {width: tileSize, height: tileSize, data: null}, gl.RGBA);
_texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);

tile.texture = context.createFramebuffer();
tile.texture.colorAttachment.set(_texture.texture);
}

context.bindFramebuffer.set(tile.texture.framebuffer);
context.viewport.set([0, 0, tileSize, tileSize]);

const matrix = mat4.create();
Expand All @@ -148,8 +154,6 @@ function prepareHillshade(painter, tile) {
vao.bind(context, program, buffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, buffer.length);

tile.texture.unbind();
context.viewport.set([0, 0, painter.width, painter.height]);
tile.needsHillshadePrepare = false;
}
}
40 changes: 20 additions & 20 deletions src/render/painter.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const CrossTileSymbolIndex = require('../symbol/cross_tile_symbol_index');
const shaders = require('../shaders');
const Program = require('./program');
const Context = require('../gl/context');
const RenderTexture = require('./render_texture');
const Texture = require('./texture');
const updateTileMasks = require('./tile_mask');
const Color = require('../style-spec/util/color');

Expand All @@ -37,7 +37,6 @@ import type TileCoord from '../source/tile_coord';
import type Style from '../style/style';
import type StyleLayer from '../style/style_layer';
import type LineAtlas from './line_atlas';
import type Texture from './texture';
import type ImageManager from './image_manager';
import type GlyphManager from './glyph_manager';
import type VertexBuffer from '../gl/vertex_buffer';
Expand Down Expand Up @@ -69,7 +68,6 @@ class Painter {
width: number;
height: number;
depthRbo: WebGLRenderbuffer;
depthRboAttached: boolean;
tileExtentBuffer: VertexBuffer;
tileExtentVAO: VertexArrayObject;
tileExtentPatternVAO: VertexArrayObject;
Expand Down Expand Up @@ -292,7 +290,7 @@ class Painter {
this.imageManager = style.imageManager;
this.glyphManager = style.glyphManager;

const context = this.context;
const gl = this.context.gl;

for (const id in style.sourceCaches) {
const sourceCache = this.style.sourceCaches[id];
Expand Down Expand Up @@ -351,19 +349,28 @@ class Painter {

this._setup3DRenderbuffer();

const renderTarget = layer.viewportFrame || new RenderTexture(this);
layer.viewportFrame = renderTarget;
renderTarget.bindWithDepth(this.depthRbo);
let renderTarget = layer.viewportFrame;
if (!renderTarget) {
const texture = new Texture(this.context, {width: this.width, height: this.height, data: null}, gl.RGBA);
texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);

renderTarget = this.context.createFramebuffer();
renderTarget.colorAttachment.set(texture.texture);
layer.viewportFrame = renderTarget;
}

this.context.bindFramebuffer.set(renderTarget.framebuffer);
renderTarget.depthAttachment.set(this.depthRbo);

if (first) {
context.clear({ depth: 1 });
this.context.clear({ depth: 1 });
first = false;
}

this.renderLayer(this, (sourceCache: any), layer, coords);

renderTarget.unbind();
}

this.context.bindFramebuffer.set(null);
}


Expand Down Expand Up @@ -397,7 +404,7 @@ class Painter {


// Clear buffers in preparation for drawing to the main framebuffer
context.clear({ color: Color.transparent, depth: 1 });
this.context.clear({ color: Color.transparent, depth: 1 });

this.showOverdrawInspector(options.showOverdrawInspector);

Expand Down Expand Up @@ -477,19 +484,12 @@ class Painter {
}
}

_setup3DRenderbuffer() {
_setup3DRenderbuffer(): void {
const context = this.context;
// All of the 3D textures will use the same depth renderbuffer.
if (!this.depthRbo) {
const gl = this.context.gl;
this.depthRbo = gl.createRenderbuffer();

context.bindRenderbuffer.set(this.depthRbo);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.width, this.height);
context.bindRenderbuffer.set(null);
this.depthRbo = context.createRenderbuffer(context.gl.DEPTH_COMPONENT16, this.width, this.height);
}

this.depthRboAttached = true;
}

renderLayer(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<TileCoord>) {
Expand Down
Loading

0 comments on commit a541fae

Please sign in to comment.