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

Preserve depth buffer between fill-extrusion layers + optimize render order #5101

Merged
merged 3 commits into from
Aug 30, 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
4 changes: 2 additions & 2 deletions src/render/draw_background.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Style
const image = layer.paint['background-pattern'];
const opacity = layer.paint['background-opacity'];

const isOpaque = !image && color[3] === 1 && opacity === 1;
if (painter.isOpaquePass !== isOpaque) return;
const pass = (!image && color[3] === 1 && opacity === 1) ? 'opaque' : 'translucent';
if (painter.renderPass !== pass) return;

gl.disable(gl.STENCIL_TEST);

Expand Down
2 changes: 1 addition & 1 deletion src/render/draw_circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type TileCoord from '../source/tile_coord';
module.exports = drawCircles;

function drawCircles(painter: Painter, sourceCache: SourceCache, layer: CircleStyleLayer, coords: Array<TileCoord>) {
if (painter.isOpaquePass) return;
if (painter.renderPass !== 'translucent') return;

const gl = painter.gl;

Expand Down
9 changes: 4 additions & 5 deletions src/render/draw_fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@ function drawFill(painter: Painter, sourceCache: SourceCache, layer: FillStyleLa
const gl = painter.gl;
gl.enable(gl.STENCIL_TEST);

const isOpaque =
!layer.paint['fill-pattern'] &&
const pass = (!layer.paint['fill-pattern'] &&
layer.isPaintValueFeatureConstant('fill-color') &&
layer.isPaintValueFeatureConstant('fill-opacity') &&
layer.paint['fill-color'][3] === 1 &&
layer.paint['fill-opacity'] === 1;
layer.paint['fill-opacity'] === 1) ? 'opaque' : 'translucent';

// Draw fill
if (painter.isOpaquePass === isOpaque) {
if (painter.renderPass === pass) {
// Once we switch to earcut drawing we can pull most of the WebGL setup
// outside of this coords loop.
painter.setDepthSublayer(1);
drawFillTiles(painter, sourceCache, layer, coords, drawFillTile);
}

// Draw stroke
if (!painter.isOpaquePass && layer.paint['fill-antialias']) {
if (painter.renderPass === 'translucent' && layer.paint['fill-antialias']) {
painter.lineWidth(2);
painter.depthMask(false);

Expand Down
95 changes: 24 additions & 71 deletions src/render/draw_fill_extrusion.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// @flow

const glMatrix = require('@mapbox/gl-matrix');
const VertexBuffer = require('../gl/vertex_buffer');
const VertexArrayObject = require('./vertex_array_object');
const PosArray = require('../data/pos_array');
const pattern = require('./pattern');
const mat3 = glMatrix.mat3;
const mat4 = glMatrix.mat4;
Expand All @@ -18,95 +15,51 @@ import type TileCoord from '../source/tile_coord';
module.exports = draw;

function draw(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: Array<TileCoord>) {
if (painter.isOpaquePass) return;
if (layer.paint['fill-extrusion-opacity'] === 0) return;
if (painter.renderPass === '3d') {
const gl = painter.gl;

const gl = painter.gl;
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
painter.depthMask(true);

// Create a new texture to which to render the extrusion layer. This approach
// allows us to adjust opacity on a per-layer basis (eliminating the interior
// walls per-feature opacity problem)
const texture = renderToTexture(gl, painter);
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);

gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
painter.clearColor();
painter.depthMask(true);

for (let i = 0; i < coords.length; i++) {
drawExtrusion(painter, source, layer, coords[i]);
for (let i = 0; i < coords.length; i++) {
drawExtrusion(painter, source, layer, coords[i]);
}
} else if (painter.renderPass === 'translucent') {
drawExtrusionTexture(painter, layer);
}

// Unbind the framebuffer as a render target and render it to the map
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
renderTextureToMap(gl, painter, layer, texture);
}

function renderToTexture(gl, painter) {
gl.activeTexture(gl.TEXTURE1);

let texture = painter.viewportTexture;
if (!texture) {
texture = 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);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, painter.width, painter.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
painter.viewportTexture = texture;
} else {
gl.bindTexture(gl.TEXTURE_2D, texture);
}
function drawExtrusionTexture(painter, layer) {
const renderedTexture = painter.prerenderedFrames[layer.id];
if (!renderedTexture) return;

let fbo = painter.viewportFbo;
if (!fbo) {
fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
const depthRenderBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRenderBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, painter.width, painter.height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRenderBuffer);
painter.viewportFbo = fbo;
} else {
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
}

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

return texture;
}

function renderTextureToMap(gl, painter, layer, texture) {
const gl = painter.gl;
const program = painter.useProgram('extrusionTexture');

gl.disable(gl.STENCIL_TEST);
gl.disable(gl.DEPTH_TEST);

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.bindTexture(gl.TEXTURE_2D, renderedTexture.texture);

gl.uniform1f(program.uniforms.u_opacity, layer.paint['fill-extrusion-opacity']);
gl.uniform1i(program.uniforms.u_image, 1);
gl.uniform1i(program.uniforms.u_image, 0);

const matrix = mat4.create();
mat4.ortho(matrix, 0, painter.width, painter.height, 0, 0, 1);
gl.uniformMatrix4fv(program.uniforms.u_matrix, false, matrix);

gl.disable(gl.DEPTH_TEST);

gl.uniform2f(program.uniforms.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight);

const array = new PosArray();
array.emplaceBack(0, 0);
array.emplaceBack(1, 0);
array.emplaceBack(0, 1);
array.emplaceBack(1, 1);
const buffer = new VertexBuffer(gl, array);

const vao = new VertexArrayObject();
vao.bind(gl, program, buffer);
renderedTexture.vao.bind(gl, program, renderedTexture.buffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

gl.enable(gl.DEPTH_TEST);
// Since this texture has been rendered, make it available for reuse in the next frame.
painter.viewportFrames.push(renderedTexture);
delete painter.prerenderedFrames[layer.id];
}

function drawExtrusion(painter, source, layer, coord) {
Expand Down
2 changes: 1 addition & 1 deletion src/render/draw_line.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type LineBucket from '../data/bucket/line_bucket';
import type TileCoord from '../source/tile_coord';

module.exports = function drawLine(painter: Painter, sourceCache: SourceCache, layer: LineStyleLayer, coords: Array<TileCoord>) {
if (painter.isOpaquePass) return;
if (painter.renderPass !== 'translucent') return;
painter.setDepthSublayer(0);
painter.depthMask(false);

Expand Down
2 changes: 1 addition & 1 deletion src/render/draw_raster.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type TileCoord from '../source/tile_coord';
module.exports = drawRaster;

function drawRaster(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<TileCoord>) {
if (painter.isOpaquePass) return;
if (painter.renderPass !== 'translucent') return;

const gl = painter.gl;
const source = sourceCache.getSource();
Expand Down
2 changes: 1 addition & 1 deletion src/render/draw_symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type TileCoord from '../source/tile_coord';
module.exports = drawSymbols;

function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolStyleLayer, coords: Array<TileCoord>) {
if (painter.isOpaquePass) return;
if (painter.renderPass !== 'translucent') return;

const drawAcrossEdges =
!layer.layout['text-allow-overlap'] &&
Expand Down
Loading