From ef8f75e774040a4c7a330467ba453650a9d25ebc Mon Sep 17 00:00:00 2001 From: Steven Dwy Date: Sat, 17 Oct 2015 17:32:31 -0700 Subject: [PATCH] Use instancing to further enhnace rendering efficiency --- dub.json | 8 ++--- res/shader.fs | 10 +++--- res/shader.vs | 17 ++++++++- src/pacman/gl/renderer.d | 75 +++++++++++++++++++++++++++++++--------- src/pacman/main.d | 7 +--- src/pacman/package.d | 1 + 6 files changed, 85 insertions(+), 33 deletions(-) diff --git a/dub.json b/dub.json index 75ee935..e39968a 100644 --- a/dub.json +++ b/dub.json @@ -4,9 +4,9 @@ "copyright": "Copyright © 2015, Steven", "authors": ["Steven"], "dependencies": { - "gfm:logger": "~>3.0.5", - "gfm:sdl2": "~>3.0.5", - "gfm:math": "~>3.0.5", - "gfm:opengl": "~>3.0.5", + "gfm:logger": "~>3.0.6", + "gfm:sdl2": "~>3.0.6", + "gfm:math": "~>3.0.6", + "gfm:opengl": "~>3.0.6", }, } diff --git a/res/shader.fs b/res/shader.fs index f711e56..2c9211c 100644 --- a/res/shader.fs +++ b/res/shader.fs @@ -2,26 +2,26 @@ #define TEXTURE_SIZE 32u in vec2 fragmentTextureCoordinate; +flat in uint fragmentTextureIndex; +in vec3 fragmentColorMask; out vec4 outColor; uniform uint atlasSizePixels; //size of the atlas in pixels uniform uint atlasSizeTiles; //size of the atlas in TEXTURE_SIZE tiles uniform float atlasTileSizeFloating; //size of a tile on the atlas in floating coords -uniform uint index; //index into the atlas for the tile to use uniform sampler2D activeTexture; -uniform vec3 colorMask; void main() { uvec2 tileCoords = uvec2( - index % atlasSizeTiles, - index / atlasSizeTiles + fragmentTextureIndex % atlasSizeTiles, + fragmentTextureIndex / atlasSizeTiles ); uvec2 pixelCoords = tileCoords * TEXTURE_SIZE; vec2 floatingCoords = pixelCoords / float(atlasSizePixels); vec2 flippedCoords = vec2(fragmentTextureCoordinate.x, 1 -fragmentTextureCoordinate.y); vec2 finalCoords = floatingCoords + flippedCoords * atlasTileSizeFloating; - outColor = vec4(colorMask, 1.0) * texture(activeTexture, finalCoords); + outColor = vec4(fragmentColorMask, 1.0) * texture(activeTexture, finalCoords); } diff --git a/res/shader.vs b/res/shader.vs index d2cc111..c7ca2dd 100644 --- a/res/shader.vs +++ b/res/shader.vs @@ -2,16 +2,31 @@ in vec2 coordinate; in vec2 textureCoordinate; +in vec4 maskAndIndex; //color mask and texture index in single vector to work around gfm limitations +//model matrix unpacked as four vec4s, again working around gfm limitations +in vec4 modelColumn1; +in vec4 modelColumn2; +in vec4 modelColumn3; +in vec4 modelColumn4; out vec2 fragmentTextureCoordinate; +flat out uint fragmentTextureIndex; +out vec3 fragmentColorMask; uniform mat4 projection; uniform mat4 view; -uniform mat4 model; void main() { + mat4 model = mat4( + modelColumn1, + modelColumn2, + modelColumn3, + modelColumn4 + ); fragmentTextureCoordinate = textureCoordinate; + fragmentTextureIndex = uint(maskAndIndex.w); + fragmentColorMask = maskAndIndex.rgb; vec4 coordinate4 = vec4(coordinate, 0.0, 1.0); gl_Position = projection * view * model * coordinate4; } diff --git a/src/pacman/gl/renderer.d b/src/pacman/gl/renderer.d index 322edef..692b9ca 100644 --- a/src/pacman/gl/renderer.d +++ b/src/pacman/gl/renderer.d @@ -1,5 +1,6 @@ module pacman.gl.renderer; +import std.array; import std.experimental.logger; import std.file; import std.string; @@ -11,20 +12,34 @@ import pacman.gl.texture; import pacman.globals; import pacman; -struct Vertex +private struct Vertex { vec2f coordinate; vec2f textureCoordinate; } +private struct Instance +{ + vec4f maskAndIndex; //color mask and texture index in single vector to work around gfm limitations + //model matrix unpacked as four vec4s, again working around gfm limitations + vec4f modelColumn1; + vec4f modelColumn2; + vec4f modelColumn3; + vec4f modelColumn4; +} + class Renderer { private GLProgram _program; - private GLBuffer buffer; - private VertexSpecification!Vertex specification; + private GLBuffer shapeBuffer; + private GLBuffer instanceBuffer; + private VertexSpecification!Vertex shapeSpecification; + private VertexSpecification!Instance instanceSpecification; + private GLsizei shapeVertexCount; private bool firstUpdate = true; private mat4 view; private mat4 projection; + private Appender!(Instance[]) instances; this() { @@ -79,11 +94,18 @@ class Renderer vec2f(uvMin, uvMin) ), ]; - buffer = new GLBuffer(opengl, GL_ARRAY_BUFFER, GL_STATIC_DRAW, shape.dup); - specification = new VertexSpecification!Vertex(_program); + shapeBuffer = new GLBuffer(opengl, GL_ARRAY_BUFFER, GL_STATIC_DRAW, shape.dup); + shapeSpecification = new VertexSpecification!Vertex(_program); + shapeVertexCount = cast(GLsizei)(shapeBuffer.size / shapeSpecification.vertexSize); + + shapeBuffer.bind; + shapeSpecification.use; + + instanceBuffer = new GLBuffer(opengl, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, null); + instanceSpecification = new VertexSpecification!Instance(_program); - buffer.bind; - specification.use; + instanceBuffer.bind; + instanceSpecification.use(1); } projection = mat4.orthographic( @@ -92,6 +114,7 @@ class Renderer 0.0, 5.0, ); + _program.uniform("activeTexture").set(0); _program.uniform("projection").set(projection); _program.uniform("view").set(view); } @@ -104,7 +127,8 @@ class Renderer void close() { _program.destroy; - buffer.destroy; + shapeBuffer.destroy; + instanceBuffer.destroy; } void update() @@ -133,17 +157,34 @@ class Renderer void copy(TextureData data, int x, int y, real rotation = 0, vec3f color = vec3f(1, 1, 1)) { enum halfSize = TEXTURE_SIZE / 2f; + mat4 model = + mat4.translation(vec3f(cast(float)x + halfSize, cast(float)y + halfSize, 0)) * + mat4.rotation(rotation.radians, vec3f(0, 0, 1)) + ; - program.uniform("model").set( - mat4.translation(vec3f(cast(float)x, cast(float)y, 0)) * - mat4.translation(vec3f(halfSize, halfSize, 0)) * - mat4.rotation(rotation.radians, vec3f(0, 0, 1)) * - mat4.translation(vec3f(-halfSize, -halfSize, 0)) * - mat4.scaling(vec3f(TEXTURE_SIZE, TEXTURE_SIZE, 0)) + model.translate(vec3f(-halfSize, -halfSize, 0)); + model.scale(vec3f(TEXTURE_SIZE, TEXTURE_SIZE, 0)); + instances.put( + Instance( + vec4f(color, cast(float)data.index), + model.column(0), + model.column(1), + model.column(2), + model.column(3), + ) + ); + } + + void flush() + { + instanceBuffer.setData(instances.data); + glDrawArraysInstanced( + GL_TRIANGLES, + 0, + shapeVertexCount, + instances.data.length, ); - program.uniform("colorMask").set(color); - program.uniform("index").set(data.index); - glDrawArrays(GL_TRIANGLES, 0, cast(int)(buffer.size / specification.vertexSize)); + instances.clear; } } diff --git a/src/pacman/main.d b/src/pacman/main.d index 5923ba7..16176be 100644 --- a/src/pacman/main.d +++ b/src/pacman/main.d @@ -78,11 +78,6 @@ void main() stitch_textures; regenerate_level; - renderer.program.uniform("model").set( - mat4.translation(vec3f(15, 15, 0)) * - mat4.scaling(vec3f(200, 200, 1)) - ); - renderer.program.uniform("activeTexture").set(0); while(true) { @@ -150,7 +145,7 @@ void main() player.update; player.render; - //renderer.draw; + renderer.flush; window.swapBuffers; } diff --git a/src/pacman/package.d b/src/pacman/package.d index 26f9c40..259e499 100644 --- a/src/pacman/package.d +++ b/src/pacman/package.d @@ -8,3 +8,4 @@ alias vec3i = gfm.math.vec3!int; alias mat4 = gfm.math.mat4!float; alias vec2f = gfm.math.vec2!float; alias vec3f = gfm.math.vec3!float; +alias vec4f = gfm.math.vec4!float;