aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/makamys/lodmod/renderer/GPUMemoryManager.java
blob: 72f22a2a63551270d67186d8a299e3f4cd84ec11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package makamys.lodmod.renderer;

import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glBufferSubData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import makamys.lodmod.renderer.Mesh.GPUStatus;

public class GPUMemoryManager {
    
    private static int BUFFER_SIZE = 1024 * 1024 * 1024;
    
    public int VBO;
    
    private int nextTri;
    private int nextMeshOffset;
    private int nextMesh;
    
    private List<Mesh> sentMeshes = new ArrayList<>();
    
    public GPUMemoryManager() {
        VBO = glGenBuffers();
        
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        
        glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE, GL_STATIC_DRAW);
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    
    public void runGC() {
        nextMeshOffset = 0;
        nextTri = 0;
        
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
            
        int deletedNum = 0;
        int deletedRAM = 0;
        
        long t0 = System.nanoTime();
        
        for(Iterator<Mesh> it = sentMeshes.iterator(); it.hasNext(); ) {
            Mesh mesh = it.next();
            if(mesh.gpuStatus == GPUStatus.SENT) {
                if(mesh.offset != nextMeshOffset) {
                    glBufferSubData(GL_ARRAY_BUFFER, nextMeshOffset, mesh.buffer);
                }
                mesh.iFirst = nextTri;
                mesh.offset = nextMeshOffset;
                
                nextMeshOffset += mesh.bufferSize();
                nextTri += mesh.quadCount * 6;
            } else if(mesh.gpuStatus == GPUStatus.PENDING_DELETE) {
                mesh.iFirst = mesh.offset = -1;
                mesh.visible = false;
                mesh.gpuStatus = GPUStatus.UNSENT;
                mesh.destroyBuffer();
                
                it.remove();
                deletedNum++;
                deletedRAM += mesh.bufferSize();
            }
        }
        
        long t1 = System.nanoTime();
        
        System.out.println("Deleted " + deletedNum + " meshes in " + ((t1 - t0) / 1_000_000.0) + " ms, freeing up " + (deletedRAM / 1024 / 1024) + "MB of VRAM");
        
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    
    public void sendMeshToGPU(Mesh mesh) {
        if(mesh == null) {
            return;
        }
        if(mesh.gpuStatus == GPUStatus.UNSENT) {
            mesh.prepareBuffer();
            
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            
            glBufferSubData(GL_ARRAY_BUFFER, nextMeshOffset, mesh.buffer);
            mesh.iFirst = nextTri;
            mesh.iCount = mesh.quadCount * 6;
            mesh.offset = nextMeshOffset;
            
            nextTri += mesh.quadCount * 6;
            nextMeshOffset += mesh.buffer.limit();
            sentMeshes.add(mesh);
            
            glBindBuffer(GL_ARRAY_BUFFER, 0);
        }
        
        mesh.gpuStatus = GPUStatus.SENT;
    }
    
    public void deleteMeshFromGPU(Mesh mesh) {
        if(mesh == null || mesh.gpuStatus == GPUStatus.UNSENT) {
            return;
        }
        mesh.gpuStatus = GPUStatus.PENDING_DELETE;
    }

    public void destroy() {
        glDeleteBuffers(VBO);
    }

    public List<String> getDebugText() {
        return Arrays.asList("VRAM: " + (nextMeshOffset / 1024 / 1024) + "MB / " + (BUFFER_SIZE / 1024 / 1024) + "MB");
    }
    
}