|
| 1 | +/* |
| 2 | + * Copyright LWJGL. All rights reserved. |
| 3 | + * License terms: http://lwjgl.org/license.php |
| 4 | + */ |
| 5 | +package org.lwjgl.demo.intro; |
| 6 | + |
| 7 | +import java.nio.FloatBuffer; |
| 8 | + |
| 9 | +import static org.lwjgl.glfw.GLFW.*; |
| 10 | +import static org.lwjgl.opengl.GL.*; |
| 11 | +import static org.lwjgl.opengl.GL11.*; |
| 12 | +import static org.lwjgl.opengl.GL15.*; |
| 13 | +import static org.lwjgl.system.MemoryUtil.*; |
| 14 | +import static org.lwjgl.system.MemoryStack.*; |
| 15 | + |
| 16 | +/** |
| 17 | + * In Intro2 we learnt how to allocate an off-heap memory buffer using MemoryUtil. This was done by first calling one |
| 18 | + * of the memAlloc*() methods which return a Java NIO Buffer instance representing the allocated memory region. Once |
| 19 | + * we were done with the buffer, we called the memFree() method to deallocate/free the off-heap memory represented by |
| 20 | + * the Java NIO Buffer. |
| 21 | + * <p> |
| 22 | + * This manual memory management is necessary when a buffer needs to live for an extended amount of time in our |
| 23 | + * application, meaning that the time between allocation and deallocation spans beyond one method. |
| 24 | + * <p> |
| 25 | + * In most scenarios however, the memory will be very short-living. One example was the allocation of the memory to fill |
| 26 | + * the VBO in Intro2. Memory was allocated, filled with data, given to OpenGL and then freed again. |
| 27 | + * <p> |
| 28 | + * LWJGL 3 provides a better way to handle such situations, which is by using the MemoryStack class. This class allows |
| 29 | + * to retrieve a small chunk of memory from a pre-allocated thread-local memory region of a fixed size. It is a stack |
| 30 | + * because allocations/deallocations must be issued in FIFO order, in that allocations cannot be freed randomly bust |
| 31 | + * must be freed in the reverse allocation order. This allows to avoid any heap allocation and compaction strategies. |
| 32 | + * <p> |
| 33 | + * Also note that the pre-allocated memory of the MemoryStack is per thread. That means, every thread will get its own |
| 34 | + * memory region and MemoryStack instances should not be shared among different threads. |
| 35 | + * |
| 36 | + * @author Kai Burjack |
| 37 | + */ |
| 38 | +public class Intro3 { |
| 39 | + |
| 40 | + /** |
| 41 | + * This sample is the same as Intro2, but uses the MemoryStack to allocate the short-living buffer to fill the VBO. |
| 42 | + */ |
| 43 | + public static void main(String[] args) { |
| 44 | + glfwInit(); |
| 45 | + long window = createWindow(); |
| 46 | + |
| 47 | + /* |
| 48 | + * Ask the MemoryStack to create a new "stack frame". |
| 49 | + * |
| 50 | + * This is basically for house-keeping of the current stack allocation position/pointer. Everytime we allocate |
| 51 | + * memory using the MemoryStack (see below), the stack pointer advances (towards address zero). In order to |
| 52 | + * "deallocate" memory that was previously allocated by the MemoryStack, all that needs to be done is to reset |
| 53 | + * the stack position/pointer to the previous position. This will be done by a call to stackPop(). |
| 54 | + * |
| 55 | + * So, first we need to save the current stack position/pointer using stackPush(). |
| 56 | + */ |
| 57 | + stackPush(); |
| 58 | + |
| 59 | + /* |
| 60 | + * No we reserve some space on the stack and return it as a new Java NIO Buffer using the MemoryStack's |
| 61 | + * stackMallocFloat() method. |
| 62 | + * The MemoryStack provides other stackMalloc* methods as well, which return other typed Java NIO Buffer views. |
| 63 | + */ |
| 64 | + FloatBuffer buffer = stackMallocFloat(3 * 2); |
| 65 | + |
| 66 | + /* |
| 67 | + * The following few lines of code from Intro2 are identical. This also means that code _using_ a |
| 68 | + * stack-allocated memory buffer does not differ from code using buffers allocated with other allocation |
| 69 | + * strategies. |
| 70 | + */ |
| 71 | + buffer.put(-0.5f).put(-0.5f); |
| 72 | + buffer.put(+0.5f).put(-0.5f); |
| 73 | + buffer.put(+0.0f).put(+0.5f); |
| 74 | + buffer.flip(); |
| 75 | + int vbo = glGenBuffers(); |
| 76 | + glBindBuffer(GL_ARRAY_BUFFER, vbo); |
| 77 | + glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); |
| 78 | + |
| 79 | + /* |
| 80 | + * Now, that we don't need the allocated buffer anymore, we have to pop the "stack frame". |
| 81 | + * This will reset the state of the MemoryStack (i.e. the allocation position/pointer) to where it was before |
| 82 | + * we called stackPush() above. |
| 83 | + */ |
| 84 | + stackPop(); |
| 85 | + |
| 86 | + /* |
| 87 | + * The following code is just like in Intro2. |
| 88 | + */ |
| 89 | + glEnableClientState(GL_VERTEX_ARRAY); |
| 90 | + glVertexPointer(2, GL_FLOAT, 0, 0L); |
| 91 | + while (!glfwWindowShouldClose(window)) { |
| 92 | + glfwPollEvents(); |
| 93 | + glDrawArrays(GL_TRIANGLES, 0, 3); |
| 94 | + glfwSwapBuffers(window); |
| 95 | + } |
| 96 | + glfwTerminate(); |
| 97 | + } |
| 98 | + |
| 99 | + private static long createWindow() { |
| 100 | + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); |
| 101 | + long window = glfwCreateWindow(800, 600, "Intro3", NULL, NULL); |
| 102 | + glfwMakeContextCurrent(window); |
| 103 | + createCapabilities(); |
| 104 | + return window; |
| 105 | + } |
| 106 | + |
| 107 | +} |
0 commit comments