Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Framebuffer refactor #5793

Merged
merged 7 commits into from
Dec 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
35 changes: 35 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 @@ -87,6 +88,10 @@ class Context {
pixelStoreUnpack: State<number>;
pixelStoreUnpackPremultiplyAlpha: State<boolean>;

extTextureFilterAnisotropic: any;
extTextureFilterAnisotropicMax: any;
extTextureHalfFloat: any;

constructor(gl: WebGLRenderingContext) {
this.gl = gl;
this.extVertexArrayObject = this.gl.getExtension('OES_vertex_array_object');
Expand Down Expand Up @@ -118,6 +123,21 @@ class Context {
this.bindVertexArrayOES = this.extVertexArrayObject && new State(new BindVertexArrayOES(this));
this.pixelStoreUnpack = new State(new PixelStoreUnpack(this));
this.pixelStoreUnpackPremultiplyAlpha = new State(new PixelStoreUnpackPremultiplyAlpha(this));

this.extTextureFilterAnisotropic = (
gl.getExtension('EXT_texture_filter_anisotropic') ||
gl.getExtension('MOZ_EXT_texture_filter_anisotropic') ||
gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic')
);
if (this.extTextureFilterAnisotropic) {
this.extTextureFilterAnisotropicMax = gl.getParameter(this.extTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
}

this.extTextureHalfFloat = gl.getExtension('OES_texture_half_float');
if (this.extTextureHalfFloat) {
gl.getExtension('OES_texture_half_float_linear');
}

}

createIndexBuffer(array: TriangleIndexArray | LineIndexArray, dynamicDraw?: boolean) {
Expand All @@ -128,6 +148,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(width: number, height: number) {
return new Framebuffer(this, width, height);
}

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

import type Context from './context';

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

constructor(context: Context, width: number, height: number) {
this.context = context;
this.width = width;
this.height = height;
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));
}

destroy() {
const gl = this.context.gl;

const texture = this.colorAttachment.get();
if (texture) gl.deleteTexture(texture);

const renderbuffer = this.depthAttachment.get();
if (renderbuffer) gl.deleteRenderbuffer(renderbuffer);

gl.deleteFramebuffer(this.framebuffer);
}
}

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;
49 changes: 48 additions & 1 deletion src/gl/value.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type {
ViewportType,
} from './types';


export interface Value<T> {
context: Context;
static default(context?: Context): T;
Expand Down Expand Up @@ -324,6 +323,51 @@ class PixelStoreUnpackPremultiplyAlpha extends ContextValue implements Value<boo
}
}

/**
* Framebuffer values
*/
class FramebufferValue extends ContextValue {
context: Context;
parent: WebGLFramebuffer;

constructor(context: Context, parent: WebGLFramebuffer) {
super(context);
this.parent = parent;
}
}

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

set(v: ?WebGLTexture): void {
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 FramebufferValue implements Value<?WebGLRenderbuffer> {
static default() { return null; }

set(v: ?WebGLRenderbuffer): void {
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 +396,7 @@ module.exports = {
BindVertexArrayOES,
PixelStoreUnpack,
PixelStoreUnpackPremultiplyAlpha,

ColorAttachment,
DepthAttachment,
};
48 changes: 38 additions & 10 deletions src/render/draw_fill_extrusion.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const glMatrix = require('@mapbox/gl-matrix');
const pattern = require('./pattern');
const Texture = require('./texture');
const Color = require('../style-spec/util/color');
const mat3 = glMatrix.mat3;
const mat4 = glMatrix.mat4;
Expand All @@ -20,14 +21,8 @@ function draw(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLa
return;
}

if (painter.renderPass === '3d') {
const context = painter.context;

context.stencilTest.set(false);
context.depthTest.set(true);

context.clear({ color: Color.transparent });
context.depthMask.set(true);
if (painter.renderPass === 'offscreen') {
drawToExtrusionFramebuffer(painter, layer);

for (let i = 0; i < coords.length; i++) {
drawExtrusion(painter, source, layer, coords[i]);
Expand All @@ -37,6 +32,39 @@ function draw(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLa
}
}

function drawToExtrusionFramebuffer(painter, layer) {
const context = painter.context;
const gl = context.gl;

let renderTarget = layer.viewportFrame;

if (painter.depthRboNeedsClear) {
painter.setupOffscreenDepthRenderbuffer();
}

if (!renderTarget) {
const texture = new Texture(context, {width: painter.width, height: painter.height, data: null}, gl.RGBA);
texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);

renderTarget = layer.viewportFrame = context.createFramebuffer(painter.width, painter.height);
renderTarget.colorAttachment.set(texture.texture);
}

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

if (painter.depthRboNeedsClear) {
context.clear({ depth: 1 });
painter.depthRboNeedsClear = false;
}

context.stencilTest.set(false);
context.depthTest.set(true);

context.clear({ color: Color.transparent });
context.depthMask.set(true);
}

function drawExtrusionTexture(painter, layer) {
const renderedTexture = layer.viewportFrame;
if (!renderedTexture) return;
Expand All @@ -48,8 +76,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
Loading