From 4abfbe4a5801c907a36641102099b69397b44e2b Mon Sep 17 00:00:00 2001 From: Jerome St-Louis Date: Sat, 5 Nov 2022 15:39:00 -0400 Subject: [PATCH] ecere/gfx/drivers/GL/GLAB: Improved handling element buffers with VAO - Not modifying active element buffer when VAOs are on, except for default VAO - Not using glabCurElementBuffer with VAO except for defaultVAO, as each VAO may have a different active element buffer - Removed unecessary / wrong WebGL-specific logic - New GLABBindVertexArray() call to keep track of active VAO - NOTE: VAO usage currently expects a single context / display - butterbur: Updated to use GLABBindVertexArray() - samples/3D/CubicWorld: Updated to use GLABBindVertexArray() - samples/3D/CubicWorld: Improved readability e.g., splitting prepareMultiDraw() into multiple methods --- butterbur/src/opengl/shaders/butterbur.frag | 3 +- butterbur/src/presentation/DrawingManager.ec | 10 +- .../src/presentation/GraphicalSurface.ec | 4 +- butterbur/src/presentation/TIManager.ec | 6 +- ecere/src/gfx/drivers/OpenGLDisplayDriver.ec | 14 +- ecere/src/gfx/drivers/gl3/GLMultiDraw.ec | 20 +- ecere/src/gfx/drivers/gl3/glab.ec | 61 ++-- samples/3D/CubicWorld/cubicWorld.ec | 261 ++++++++---------- samples/3D/CubicWorld/mandelbulb.ec | 2 +- 9 files changed, 199 insertions(+), 182 deletions(-) diff --git a/butterbur/src/opengl/shaders/butterbur.frag b/butterbur/src/opengl/shaders/butterbur.frag index 2d4169714c..1b12f11239 100644 --- a/butterbur/src/opengl/shaders/butterbur.frag +++ b/butterbur/src/opengl/shaders/butterbur.frag @@ -428,7 +428,8 @@ void main(void) #if FOG_ON { - float fog = clamp(exp(fogZ), 0.0, 1.0); + float fog = clamp(exp(-fogZ * fogZ), 0.0, 1.0); + //float fog = clamp(exp(fogZ), 0.0, 1.0); c = vec4(fog * c.xyz + (1.0 - fog) * fogColor, c.w); } #endif diff --git a/butterbur/src/presentation/DrawingManager.ec b/butterbur/src/presentation/DrawingManager.ec index 43c62d9950..9142603820 100644 --- a/butterbur/src/presentation/DrawingManager.ec +++ b/butterbur/src/presentation/DrawingManager.ec @@ -134,7 +134,7 @@ public class MDManager : DrawingManager } } - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); } } @@ -227,7 +227,7 @@ class Perspective3DManager : MDManager GLFlushMatrices(); texture.bind(); - if(glCaps_vao) glBindVertexArray(md.vao); + if(glCaps_vao) GLABBindVertexArray(md.vao); for(n = 0; n < md.commandsCount; n++) { const GLDrawCommand *cmd = &md.commands[n]; @@ -251,7 +251,7 @@ class Perspective3DManager : MDManager glDisableVertexAttribArray(transform2Attribute); glDisableVertexAttribArray(transform3Attribute); }*/ - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); butterburShader.transform3D = false; } @@ -264,7 +264,7 @@ class Perspective3DManager : MDManager { PrimitiveGroup group; - if(glCaps_vao) glBindVertexArray(defaultVAO); + if(glCaps_vao) GLABBindVertexArray(defaultVAO); glDisplay.SelectMesh(mesh); for(group = mesh.groups.first; group; group = group.next) @@ -283,7 +283,7 @@ class Perspective3DManager : MDManager glDisplay.DrawPrimitives((PrimitiveSingle *)&group.type, mesh); } - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); } } } diff --git a/butterbur/src/presentation/GraphicalSurface.ec b/butterbur/src/presentation/GraphicalSurface.ec index 5cc13141f5..37174199ba 100644 --- a/butterbur/src/presentation/GraphicalSurface.ec +++ b/butterbur/src/presentation/GraphicalSurface.ec @@ -113,7 +113,7 @@ public class GraphicalSurface : MultiPresentation #endif glDisable(GL_SCISSOR_TEST); - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); glBindFramebuffer(GL_FRAMEBUFFER, texturesFramebuffer); butterburShader.activate(); butterburShader.lighting(false); @@ -268,7 +268,7 @@ public class GraphicalSurface : MultiPresentation butterburShader.textureArray(false); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); glEnable(GL_SCISSOR_TEST); - if(glCaps_vao) glBindVertexArray(defaultVAO); + if(glCaps_vao) GLABBindVertexArray(defaultVAO); DefaultShader::shader().texturing(false); DefaultShader::shader().texturing(true); DefaultShader::shader().activate(); diff --git a/butterbur/src/presentation/TIManager.ec b/butterbur/src/presentation/TIManager.ec index d20b6230c9..d2a0326e69 100644 --- a/butterbur/src/presentation/TIManager.ec +++ b/butterbur/src/presentation/TIManager.ec @@ -69,19 +69,19 @@ public class TIManager : DrawingManager float transform[2] = { originOffset.x, originOffset.y }; if(drawManager) drawManager.ready(width, height); - if(glCaps_vao) glBindVertexArray(defaultVAO); + if(glCaps_vao) GLABBindVertexArray(defaultVAO); presentation.prepareDraw(renderFlags, this, transform); } void draw() { // TODO: Proper VAO support for text & images? - if(glCaps_vao) glBindVertexArray(defaultVAO); + if(glCaps_vao) GLABBindVertexArray(defaultVAO); if(drawManager) drawManager.flushImages(); if(glCaps_shaders) glEnableVertexAttribArray(GLBufferContents::vertex); - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); } void addTextCommand(const String text, GEFont font, float opacity, Alignment2D alignment, float * transform) diff --git a/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec b/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec index 0c65b2b1fe..dc6cd4a246 100644 --- a/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec +++ b/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec @@ -398,6 +398,8 @@ Shader activeShader; static int displayWidth, displayHeight; +uint defaultVAO; // Only works with a single display / context + static bool useSingleGLContext = false; class OGLDisplay : struct { @@ -1373,8 +1375,11 @@ class OpenGLDisplayDriver : DisplayDriver #if ENABLE_GL_VAO if(oglDisplay.capabilities.vao) { + // VAOs cannot be shared across contexts, but in single context mode + // we should re-use the same VAO across displays. glGenVertexArrays(1, &oglDisplay.vao); - glBindVertexArray(oglDisplay.vao); + defaultVAO = oglDisplay.vao; // NOTE: This currently only works with a single display / context + GLABBindVertexArray(oglDisplay.vao); } #endif @@ -1413,8 +1418,7 @@ class OpenGLDisplayDriver : DisplayDriver GLDisableClientState(TANGENTS1); GLDisableClientState(TANGENTS2); #if ENABLE_GL_VAO - if(glBindVertexArray) - glBindVertexArray(0); + GLABBindVertexArray(0); #endif if(glUseProgram) glUseProgram(0); @@ -1425,7 +1429,7 @@ class OpenGLDisplayDriver : DisplayDriver #if ENABLE_GL_VAO if(glCaps_vao) - glBindVertexArray(oglDisplay.vao); + GLABBindVertexArray(oglDisplay.vao); #endif GLEnableClientState(VERTICES); @@ -2039,7 +2043,7 @@ class OpenGLDisplayDriver : DisplayDriver if(glCaps_vao) { OGLDisplay oglDisplay = display.driverData; - glBindVertexArray(oglDisplay.vao); + GLABBindVertexArray(oglDisplay.vao); } #endif GLABBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/ecere/src/gfx/drivers/gl3/GLMultiDraw.ec b/ecere/src/gfx/drivers/gl3/GLMultiDraw.ec index 134049df94..cd392e1bf5 100644 --- a/ecere/src/gfx/drivers/gl3/GLMultiDraw.ec +++ b/ecere/src/gfx/drivers/gl3/GLMultiDraw.ec @@ -639,7 +639,7 @@ public struct GLMultiDraw // TOCHECK: No attrib divisor support in ES 2 -- will it be needed? #if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) - if(glCaps_vao) glBindVertexArray(vao); + if(glCaps_vao) GLABBindVertexArray(vao); #ifndef CLIENT_MEM_COMMANDS commandsB.upload(0, commandsCount * sizeof(GLDrawCommand), commands); @@ -681,7 +681,7 @@ public struct GLMultiDraw // TOCHECK: Should this re-do all the use() here if there is no VAO support? #if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) - if(glCaps_vao) glBindVertexArray(vao); + if(glCaps_vao) GLABBindVertexArray(vao); #endif GLFlushMatrices(); @@ -696,10 +696,18 @@ public struct GLMultiDraw GLAB ab { vertexGLMB.ab.buffer }; Shader shader = activeShader; - GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexGLMB.ab.buffer); + if(!glCaps_vao) // Don't modify VAO state. + { + GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexGLMB.ab.buffer); + + glDisableVertexAttribArray((GLBufferContents)drawIDAttribute); + glDisableVertexAttribArray((GLBufferContents)posOffsetAttribute); + } + else if(vao == defaultVAO) + PrintLn("WARNING: MultiDraw with default VAO"); + else if(!glabCurVertexArray) + PrintLn("WARNING (MultiDraw): No VAO selected"); - glDisableVertexAttribArray((GLBufferContents)drawIDAttribute); - glDisableVertexAttribArray((GLBufferContents)posOffsetAttribute); for(n = 0; n < commandsCount; n++) { const GLDrawCommand *cmd = &commands[n]; @@ -783,7 +791,7 @@ public struct GLMultiDraw #endif #endif #if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) - if(glCaps_vao) glBindVertexArray(0); + if(glCaps_vao) GLABBindVertexArray(0); #endif } }; diff --git a/ecere/src/gfx/drivers/gl3/glab.ec b/ecere/src/gfx/drivers/gl3/glab.ec index 6ff480d423..bd190d4374 100644 --- a/ecere/src/gfx/drivers/gl3/glab.ec +++ b/ecere/src/gfx/drivers/gl3/glab.ec @@ -15,7 +15,7 @@ default dllexport void GLABUnbindBuffer(int target) glBindBuffer(target, 0); if(target == GL_ARRAY_BUFFER) glabCurArrayBuffer = 0; - else if(target == GL_ELEMENT_ARRAY_BUFFER) + else if(target == GL_ELEMENT_ARRAY_BUFFER && (!glCaps_vao || glabCurVertexArray == defaultVAO)) glabCurElementBuffer = 0; // NOTE: Actually ES 3.1 is required, separate define? #if !defined(_GLES) && !defined(_GLES2) && !defined(_GLES3) @@ -33,7 +33,7 @@ public void GLABBindBuffer(int target, uint buffer) glBindBuffer(target, buffer); if(target == GL_ARRAY_BUFFER) glabCurArrayBuffer = buffer; - else if(target == GL_ELEMENT_ARRAY_BUFFER) + else if(target == GL_ELEMENT_ARRAY_BUFFER && (!glCaps_vao || glabCurVertexArray == defaultVAO)) glabCurElementBuffer = buffer; // NOTE: Actually ES 3.1 is required, separate define? #if !defined(_GLES) && !defined(_GLES2) && !defined(_GLES3) @@ -43,10 +43,6 @@ public void GLABBindBuffer(int target, uint buffer) } } -#if !defined(_GLES) && !defined(_GLES2) && !defined(_GLES3) -uint glabCurDrawIndirectBuffer; -#endif - public enum GLBufferContents { vertex, normal, texCoord, color, tangent1, tangent2, lightVector, boneIndices1, boneIndices2, boneIndices3, boneWeights1, boneWeights2, boneWeights3 }; public enum GLBufferUsage { staticDraw, dynamicDraw, streamDraw }; @@ -55,7 +51,29 @@ static GLint bufferUsages[] = { GL_STATIC_DRAW, GL_DYNAMIC_DRAW, 0x88E0 /*GL_STR public define noAB = GLAB { 0 }; -uint glabCurArrayBuffer; +public void GLABBindVertexArray(uint vao) +{ +#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) + if(glCaps_vao) // && vao != glabCurVertexArray) // VAOs are not shared across contexts / displays + { +#ifdef _DEBUG + if(vao != glabCurVertexArray) + ;//PrintLn("WARNING: Redundant VAO binding"); +#endif + glBindVertexArray(vao); + glabCurVertexArray = vao; + } +#endif +} + +uint glabCurVertexArray; // Currently bound VAO. + +uint glabCurArrayBuffer; // Buffer currently bound for GL_ARRAY_BUFFER. *NOT* part of VAO state +uint glabCurElementBuffer; // Buffer currently bound for GL_ELEMENT_ARRAY_BUFFER. This *IS* part of the VAO state. With VAOs, this is for 'defaultVAO'. + +#if !defined(_GLES) && !defined(_GLES2) && !defined(_GLES3) +uint glabCurDrawIndirectBuffer; +#endif static short *shortVPBuffer = null; static uint shortVPSize = 0; @@ -508,7 +526,7 @@ public struct GLB { if(buffer == glabCurArrayBuffer) GLABBindBuffer(GL_ARRAY_BUFFER, 0); - else if(buffer == glabCurElementBuffer) + else if(buffer == glabCurElementBuffer && (!glCaps_vao || glabCurVertexArray == defaultVAO)) GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #if !defined(_GLES) && !defined(_GLES2) && !defined(_GLES3) else if(buffer == glabCurDrawIndirectBuffer) @@ -620,8 +638,6 @@ public struct GLAB : GLB } }; -uint glabCurElementBuffer; - public define noEAB = GLEAB { 0 }; public struct GLCAB : GLB @@ -657,11 +673,13 @@ public struct GLEAB : GLB #endif )) { - -#if !defined(__EMSCRIPTEN__) - if(glCaps_vertexBuffer && glabCurElementBuffer != ((this != null) ? buffer : 0)) -#endif - GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((this != null) ? buffer : 0)); + if(!glCaps_vao || glabCurVertexArray == defaultVAO) + { + if(glCaps_vertexBuffer && glabCurElementBuffer != ((this != null) ? buffer : 0)) + GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((this != null) ? buffer : 0)); + } + else if(glCaps_vao && !glabCurVertexArray) + PrintLn("WARNING (draw): No VAO selected"); if(!glCaps_intAndDouble) type = GL_UNSIGNED_SHORT; @@ -680,11 +698,14 @@ public struct GLEAB : GLB #endif )) { -#if !defined(__EMSCRIPTEN__) - if(glCaps_vertexBuffer) -#endif - if(glabCurElementBuffer != ((this != null) ? buffer : 0)) - GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((this != null) ? buffer : 0)); + if(!glCaps_vao || glabCurVertexArray == defaultVAO) + { + if(glCaps_vertexBuffer && glabCurElementBuffer != ((this != null) ? buffer : 0)) + GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((this != null) ? buffer : 0)); + } + else if(glCaps_vao && !glabCurVertexArray) + PrintLn("WARNING (draw2): No VAO selected"); + if(!glCaps_intAndDouble) type = GL_UNSIGNED_SHORT; diff --git a/samples/3D/CubicWorld/cubicWorld.ec b/samples/3D/CubicWorld/cubicWorld.ec index f7d8d9585d..0d532fd09f 100644 --- a/samples/3D/CubicWorld/cubicWorld.ec +++ b/samples/3D/CubicWorld/cubicWorld.ec @@ -10,28 +10,26 @@ import "threadedProcessing" // #define SINGLE_MANDELBULB +uint visibleChunks; +uint renderedInstances; + GLMultiDraw mdWorld { }; GLArrayTexture atTextures { }; -define CUBES_X = 64; //128; -define CUBES_Y = 64; //128; -define CUBES_Z = 64; //128; +define CUBES_X = 64; +define CUBES_Y = 64; +define CUBES_Z = 64; define CUBES_COUNT = CUBES_X * CUBES_Y * CUBES_Z; -//define fogDensity = 0.00018f; - -//define fogDensity = 0; //0.00009f; // with: float fog = clamp(exp(-fogZ * fogZ), 0.0, 1.0); in butterbur.frag:431 -define fogDensity = 0.00009f; // with: float fog = clamp(exp(-fogZ * fogZ), 0.0, 1.0); in butterbur.frag:431 - -//define fogDensity = 0.00006f; +define fogDensity = 0.00009f; Color fogColor = skyBlue; define viewDistance = 5; -define numTextures = 9; //512; +define numTextures = 9; -define maxLoadedChunks = Min(256, (uint)((1LL<<31) / (12 * CUBES_COUNT))); // 512; +define maxLoadedChunks = Min(256, (uint)((1LL<<31) / (12 * CUBES_COUNT))); CubeChunk loadedChunks[maxLoadedChunks]; FreeSpots freeChunks { }; @@ -86,7 +84,6 @@ struct CubeChunk delete materials; } -#ifdef SINGLE_MANDELBULB bool load() { Mandelbulb mandelbulb { power = 8, size = { 100, 100, 100 } }; @@ -100,50 +97,8 @@ struct CubeChunk float oz = this.oz * CUBES_Z; float scale = 1.0f / 12; - tr = transforms = new float[CUBES_COUNT * 3]; - mat = materials = new uint[CUBES_COUNT]; - j = 0; - - for(z = 0; z < CUBES_Z; z++) - for(y = 0; y < CUBES_Y; y++) - for(x = 0; x < CUBES_X; x++) - { - Vector3Df p - { - (0.5f - CUBES_X/2 - (x + ox) * scale) + 30, - (0.5f - CUBES_Y/2 - (y + oy) * scale) + 60, - (0.5f - CUBES_Z/2 - (z + oz) * scale) + 60 - }; - uint t = mandelbulb.isPointInside({ p.x, p.z, p.y }, 5); - if(t) - { - Vector3Df cp { 0.5f - CUBES_X/2 + x, 0.5f - CUBES_Y/2 + y, 0.5f - CUBES_Z/2 + z }; - - // Transform is relative to center of chunk - tr[3 * j + 0] = (float)cp.x; - tr[3 * j + 1] = (float)cp.y; - tr[3 * j + 2] = (float)cp.z; - mat[j] = (t - 1 + e) % 9; - - j++; - } - } - - count = j; - transforms = renew transforms float[count * 3]; - materials = renew materials uint[count]; - loaded = true; - return true; - } -#else - bool load() // Castles in the Sky - { - Mandelbulb mandelbulb { }; - int x, y, z; - float * tr; - uint * mat; - int i, j; - int e; +#ifndef SINGLE_MANDELBULB + // Castles in the Sky uint seed = (uint)(oz * 1024 * 1024 + oy * 1024 + ox); int sx, sy, sz; int dx, dy, dz; @@ -159,6 +114,7 @@ struct CubeChunk dz = GetRandom(-sz/4, sz/4); e = GetRandom(0, 8); randomMutex.Release(); +#endif tr = transforms = new float[CUBES_COUNT * 3]; mat = materials = new uint[CUBES_COUNT]; @@ -168,6 +124,15 @@ struct CubeChunk for(y = 0; y < CUBES_Y; y++) for(x = 0; x < CUBES_X; x++) { +#ifdef SINGLE_MANDELBULB + Vector3Df p + { + (0.5f - CUBES_X/2 - (x + ox) * scale) + 30, + (0.5f - CUBES_Y/2 - (y + oy) * scale) + 60, + (0.5f - CUBES_Z/2 - (z + oz) * scale) + 60 + }; + uint t = mandelbulb.isPointInside({ p.x, p.z, p.y }, 5); +#else Vector3Df p { 0.5f - CUBES_X/2 + x + dx, @@ -175,6 +140,7 @@ struct CubeChunk 0.5f - CUBES_Z/2 + z + dz }; uint t = mandelbulb.isPointInside(p, 6); +#endif if(t) { Vector3Df cp { 0.5f - CUBES_X/2 + x, 0.5f - CUBES_Y/2 + y, 0.5f - CUBES_Z/2 + z }; @@ -195,7 +161,6 @@ struct CubeChunk loaded = true; return true; } -#endif void unload() { @@ -242,113 +207,93 @@ struct CubeChunk return result; } - void prepareMultiDraw() + void uploadInstances() { - int vertNCoords = 3, verticesStride = 32; - uint i, j; const uint maxLoadedCubes = maxLoadedChunks * CUBES_COUNT; + int i, j; uint chunkOffset = index * CUBES_COUNT; - if(!uploaded) - { - // mdWorld.transforms = transforms.array; - if(!mdWorld.transformsAB.buffer) - mdWorld.transformsAB.allocate(maxLoadedCubes * 3 * sizeof(float), null, staticDraw); - mdWorld.transformsAB.upload(chunkOffset * 3 * sizeof(float), count * sizeof(float) * 3, transforms); - - if(!mdWorld.idsAlloced) - mdWorld.resizeIDs(maxLoadedCubes); - j = chunkOffset; - for(i = 0; i < count; i++) - mdWorld.drawIDs[j++] = materials[i]; // TOCHECK: Do we need this for non-MDEI fallbacks? - mdWorld.idsAB.upload(chunkOffset * sizeof(uint), count * sizeof(uint), materials); - - if(!mdWorld.commandsAlloced) - // We can only draw one block at a time since we need to change the view matrix in between - mdWorld.resizeCommands(1); // maxLoadedChunks); - - delete transforms; - delete materials; - - uploaded = true; - } + // mdWorld.transforms = transforms.array; // TOCHECK: Do we need this for non-MDEI fallbacks? + if(!mdWorld.transformsAB.buffer) + mdWorld.transformsAB.allocate(maxLoadedCubes * 3 * sizeof(float), null, staticDraw); + mdWorld.transformsAB.upload(chunkOffset * 3 * sizeof(float), count * sizeof(float) * 3, transforms); - mdWorld.commands[mdWorld.commandsCount] = - { - count = 36, - instanceCount = count, - firstIndex = 0, - baseVertex = 0, - baseInstance = chunkOffset - }; - mdWorld.commandsCount++; + if(!mdWorld.idsAlloced) + mdWorld.resizeIDs(maxLoadedCubes); + j = chunkOffset; + for(i = 0; i < count; i++) + mdWorld.drawIDs[j++] = materials[i]; // TOCHECK: Do we need this for non-MDEI fallbacks? + mdWorld.idsAB.upload(chunkOffset * sizeof(uint), count * sizeof(uint), materials); -#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) - if(glCaps_vao) glBindVertexArray(mdWorld.vao); -#endif + if(!mdWorld.commandsAlloced) + // We can only draw one block at a time since we need to change the view matrix in between + mdWorld.resizeCommands(1); // maxLoadedChunks); - // TOCHECK: No attrib divisor support in ES 2 -- will it be needed? -#if !defined(CLIENT_MEM_COMMANDS) && ((!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3)) - mdWorld.commandsB.upload(0, mdWorld.commandsCount * sizeof(GLDrawCommand), mdWorld.commands); -#endif + delete transforms; + delete materials; + uploaded = true; + } + + void setupVAOInstances() + { + // Per-instance transforms and IDs (array texture layers) + uint chunkOffset = index * CUBES_COUNT; + + if(!uploaded) + uploadInstances(); + + // TOCHECK: No attrib divisor support in ES 2 -- will it be needed? +#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) // Initial transform buffer setup - if(!glCaps_vao || mdWorld.lastTransformAB != mdWorld.transformsAB.buffer) + if(glCaps_shaders && (!glCaps_vao || mdWorld.lastTransformAB != mdWorld.transformsAB.buffer)) { - GLABBindBuffer(GL_ARRAY_BUFFER, mdWorld.transformsAB.buffer); - if(mdWorld.transformSize == 3) - { - glVertexAttribPointer(posOffsetAttribute, mdWorld.transformSize, GL_FLOAT, GL_FALSE, 0, 0); - glVertexAttribDivisor(posOffsetAttribute, 1); - glEnableVertexAttribArray(posOffsetAttribute); - } + mdWorld.transformsAB.use(posOffsetAttribute, 3 /*mdWorld.transformSize*/, GL_FLOAT, 0, none, null); + glEnableVertexAttribArray(posOffsetAttribute); + glVertexAttribDivisor(posOffsetAttribute, 1); mdWorld.lastTransformAB = mdWorld.transformsAB.buffer; } // Initial textureID buffer setup -#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) if(glCaps_shaders && (!glCaps_vao || mdWorld.lastIDAB != mdWorld.idsAB.buffer)) { - GLABBindBuffer(GL_ARRAY_BUFFER, mdWorld.idsAB.buffer); - glVertexAttribIPointer(drawIDAttribute, 1, GL_UNSIGNED_INT, sizeof(uint), 0); + mdWorld.idsAB.use(drawIDAttribute, 1, GL_UNSIGNED_INT, 0, integer, null); glVertexAttribDivisor(drawIDAttribute, 1); glEnableVertexAttribArray(drawIDAttribute); mdWorld.lastIDAB = mdWorld.idsAB.buffer; } #endif - if(glCaps_shaders && (!glCaps_vao || mdWorld.lastVBO != mdWorld.vertexGLMB.ab.buffer)) - { - if(vertNCoords) - { - GLAB ab { mdWorld.vertexGLMB.ab.buffer }; - glEnableVertexAttribArray(GLBufferContents::vertex); - ab.use(vertex, vertNCoords, GL_FLOAT, verticesStride, none, null); - glEnableVertexAttribArray(GLBufferContents::normal); - ab.use(normal, vertNCoords, GL_FLOAT, 32, none, (void *)(uintptr)12); - glEnableVertexAttribArray(GLBufferContents::texCoord); - ab.use(texCoord, 2, GL_FLOAT, 32, none, (void *)(uintptr)24); - - mdWorld.vertexStride = verticesStride; - } - mdWorld.lastVBO = mdWorld.vertexGLMB.ab.buffer; - } - if(glCaps_vertexBuffer && (!glCaps_vao || mdWorld.lastIBO != mdWorld.indexGLMB.ab.buffer)) + } + + void addDrawCommand() + { + uint chunkOffset = index * CUBES_COUNT; + mdWorld.commands[mdWorld.commandsCount] = { - GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mdWorld.indexGLMB.ab.buffer); - mdWorld.lastIBO = mdWorld.indexGLMB.ab.buffer; - } + count = 36, // 36 indices + instanceCount = count, // 'count' cubes + firstIndex = 0, + baseVertex = 0, + baseInstance = chunkOffset // start of chunk in transforms & IDs buffers + }; + mdWorld.commandsCount++; + + renderedInstances += count; + +#if !defined(CLIENT_MEM_COMMANDS) && ((!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3)) + mdWorld.commandsB.upload(0, mdWorld.commandsCount * sizeof(GLDrawCommand), mdWorld.commands); +#endif } void draw(Vector3D cPos) { Vector3D chunkPos { ox * CUBES_X, oy * CUBES_Y, oz * CUBES_Z }; - mdWorld.commandsCount = 0; - prepareMultiDraw(); - glmsPushMatrix(); - glmsTranslated(chunkPos.x - cPos.x, chunkPos.y - cPos.y, chunkPos.z - cPos.z); - GLFlushMatrices(); + setupVAOInstances(); + addDrawCommand(); + GLPushMatrix(); + GLTranslated(chunkPos.x - cPos.x, chunkPos.y - cPos.y, chunkPos.z - cPos.z); mdWorld.draw(); - glmsPopMatrix(); + GLPopMatrix(); } }; @@ -572,6 +517,33 @@ class CubicWorld : Window return true; } + void setupVAOVertices() + { + // Per-vertex attributes (VBO) + const int verticesStride = 32; // x,y,z + normal + u,v texture coordinates: 8 x 32-bit (4 bytes) floats + + if(glCaps_shaders && (!glCaps_vao || mdWorld.lastVBO != mdWorld.vertexGLMB.ab.buffer)) + { + GLAB ab { mdWorld.vertexGLMB.ab.buffer }; + glEnableVertexAttribArray(GLBufferContents::vertex); + ab.use(vertex, 3, GL_FLOAT, verticesStride, none, null); + glEnableVertexAttribArray(GLBufferContents::normal); + ab.use(normal, 3, GL_FLOAT, verticesStride, none, (void *)(uintptr)12); + glEnableVertexAttribArray(GLBufferContents::texCoord); + ab.use(texCoord, 2, GL_FLOAT, verticesStride, none, (void *)(uintptr)24); + + mdWorld.vertexStride = verticesStride; + mdWorld.lastVBO = mdWorld.vertexGLMB.ab.buffer; + } + + // Triangle primitives indices into VBO + if(glCaps_vertexBuffer && (!glCaps_vao || mdWorld.lastIBO != mdWorld.indexGLMB.ab.buffer)) + { + GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mdWorld.indexGLMB.ab.buffer); + mdWorld.lastIBO = mdWorld.indexGLMB.ab.buffer; + } + } + bool OnLoadGraphics() { setupGL(display); @@ -672,6 +644,8 @@ class CubicWorld : Window Vector3D cPos; int i; + PrintLn("========\nRendering:"); + setupGL(display); surface.Clear(depthBuffer); @@ -702,16 +676,25 @@ class CubicWorld : Window glEnable(GL_CULL_FACE); + GLABBindVertexArray(mdWorld.vao); + + setupVAOVertices(); + + visibleChunks = 0; + renderedInstances = 0; for(i = 0; i < maxLoadedChunks; i++) { CubeChunk * chunk = &loadedChunks[i]; if(chunk->visible && chunk->loaded) + { + mdWorld.commandsCount = 0; chunk->draw(cPos); + visibleChunks++; + } } + PrintLn(" ", visibleChunks, " chunks; ", renderedInstances, " cube instances"); -#if (!defined(_GLES) && !defined(_GLES2)) || defined(_GLES3) - if(glCaps_vao) glBindVertexArray(defaultVAO); -#endif + GLABBindVertexArray(defaultVAO); GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); DefaultShader::shader().select(); diff --git a/samples/3D/CubicWorld/mandelbulb.ec b/samples/3D/CubicWorld/mandelbulb.ec index ed24b7f57b..29c4a15e40 100644 --- a/samples/3D/CubicWorld/mandelbulb.ec +++ b/samples/3D/CubicWorld/mandelbulb.ec @@ -23,7 +23,7 @@ struct Mandelbulb { if(i > 0) { - double theta = atan2(sqrt(Z.a*Z.a + Z.b*Z.b), Z.c) * power; + double theta = atan2(1.0 / FastInvSqrtDouble(Z.a*Z.a + Z.b*Z.b), Z.c) * power; double phi = atan2(Z.b, Z.a) * power; double raised = zm*zm*zm*zm*zm*zm*zm*zm; double sinT = sin(theta);