Skip to content

Commit f79ca11

Browse files
committed
Implement staging buffer and use it for material system
Adds `GLStagingBuffer` and `GLBufferCopy()`. `GLStagingBuffer` allows setting buffer storage and map flags to 0 on the destination buffers, which pretty much guarantees that they will go into VRAM. The data is uploaded through mapping `stagingBuffer` and doing a copy of the data on the GPU.
1 parent 0fa128f commit f79ca11

File tree

8 files changed

+290
-58
lines changed

8 files changed

+290
-58
lines changed

src.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ set(RENDERERLIST
9797
${ENGINE_DIR}/renderer/GeometryCache.h
9898
${ENGINE_DIR}/renderer/GeometryOptimiser.cpp
9999
${ENGINE_DIR}/renderer/GeometryOptimiser.h
100+
${ENGINE_DIR}/renderer/GLMemory.cpp
101+
${ENGINE_DIR}/renderer/GLMemory.h
100102
${ENGINE_DIR}/renderer/InternalImage.cpp
101103
${ENGINE_DIR}/renderer/InternalImage.h
102104
${ENGINE_DIR}/renderer/Material.cpp

src/engine/renderer/BufferBind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace BufferBind {
5858

5959
COMMAND_COUNTERS_STORAGE = 9,
6060
TEX_DATA_STORAGE = 11,
61+
STAGING = 12,
6162

6263
DEBUG = 10,
6364

src/engine/renderer/GLMemory.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2025 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
// GLMemory.cpp
35+
36+
#include "common/Common.h"
37+
38+
#include "GLMemory.h"
39+
40+
// 128 MB, should be enough to fit anything in BAR without going overboard
41+
const GLsizeiptr GLStagingBuffer::SIZE = 128 * 1024 * 1024 / sizeof( uint32_t );
42+
43+
GLStagingBuffer stagingBuffer;
44+
45+
void GLBufferCopy( GLBuffer* src, GLBuffer* dst, GLintptr srcOffset, GLintptr dstOffset, GLsizeiptr size ) {
46+
glCopyNamedBufferSubData( src->id, dst->id,
47+
srcOffset * sizeof( uint32_t ), dstOffset * sizeof( uint32_t ), size * sizeof( uint32_t ) );
48+
}
49+
50+
uint32_t* GLStagingBuffer::MapBuffer( const GLsizeiptr size ) {
51+
if ( size > SIZE ) {
52+
Sys::Drop( "Couldn't map GL staging buffer: size too large (%u/%u)", size, SIZE );
53+
}
54+
55+
if ( pointer + size > SIZE ) {
56+
FlushAll();
57+
58+
GLsync sync = glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
59+
60+
constexpr GLuint64 SYNC_TIMEOUT = 10000000000; // 10 seconds
61+
if ( glClientWaitSync( sync, GL_SYNC_FLUSH_COMMANDS_BIT, SYNC_TIMEOUT ) == GL_TIMEOUT_EXPIRED ) {
62+
Sys::Drop( "Failed GL staging buffer copy sync" );
63+
}
64+
glDeleteSync( sync );
65+
66+
pointer = 0;
67+
current = 0;
68+
last = 0;
69+
}
70+
71+
uint32_t* ret = buffer.GetData() + pointer;
72+
last = pointer;
73+
pointer += size;
74+
75+
return ret;
76+
}
77+
78+
void GLStagingBuffer::FlushBuffer() {
79+
buffer.FlushRange( current, pointer - current );
80+
81+
GL_CheckErrors();
82+
83+
current = pointer;
84+
}
85+
86+
void GLStagingBuffer::QueueStagingCopy( GLBuffer* dst, const GLsizeiptr dstOffset ) {
87+
copyQueue[currentCopy].dst = dst;
88+
copyQueue[currentCopy].dstOffset = dstOffset;
89+
copyQueue[currentCopy].stagingOffset = last;
90+
copyQueue[currentCopy].size = pointer - last;
91+
92+
currentCopy++;
93+
94+
if ( currentCopy == MAX_COPIES ) {
95+
FlushStagingCopyQueue();
96+
}
97+
}
98+
99+
void GLStagingBuffer::FlushStagingCopyQueue() {
100+
for ( GLStagingCopy& copy : copyQueue ) {
101+
if ( copy.dst ) {
102+
GLBufferCopy( &buffer, copy.dst, copy.stagingOffset, copy.dstOffset, copy.size );
103+
copy.dst = nullptr;
104+
}
105+
}
106+
107+
currentCopy = 0;
108+
109+
GL_CheckErrors();
110+
}
111+
112+
void GLStagingBuffer::FlushAll() {
113+
FlushBuffer();
114+
FlushStagingCopyQueue();
115+
}
116+
117+
void GLStagingBuffer::InitGLBuffer() {
118+
buffer.GenBuffer();
119+
120+
buffer.BufferStorage( SIZE, 1, nullptr );
121+
buffer.MapAll();
122+
123+
GL_CheckErrors();
124+
}
125+
126+
void GLStagingBuffer::FreeGLBuffer() {
127+
buffer.DelBuffer();
128+
}

src/engine/renderer/GLMemory.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
===========================================================================
3+
4+
Daemon BSD Source Code
5+
Copyright (c) 2025 Daemon Developers
6+
All rights reserved.
7+
8+
This file is part of the Daemon BSD Source Code (Daemon Source Code).
9+
10+
Redistribution and use in source and binary forms, with or without
11+
modification, are permitted provided that the following conditions are met:
12+
* Redistributions of source code must retain the above copyright
13+
notice, this list of conditions and the following disclaimer.
14+
* Redistributions in binary form must reproduce the above copyright
15+
notice, this list of conditions and the following disclaimer in the
16+
documentation and/or other materials provided with the distribution.
17+
* Neither the name of the Daemon developers nor the
18+
names of its contributors may be used to endorse or promote products
19+
derived from this software without specific prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
25+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
===========================================================================
33+
*/
34+
// GLMemory.h
35+
36+
#ifndef GLMEMORY_H
37+
#define GLMEMORY_H
38+
39+
#include "gl_shader.h"
40+
41+
void GLBufferCopy( GLBuffer* src, GLBuffer* dst, GLintptr srcOffset, GLintptr dstOffset, GLsizeiptr size );
42+
43+
struct GLStagingCopy {
44+
GLBuffer* dst;
45+
GLsizeiptr stagingOffset;
46+
GLsizeiptr dstOffset;
47+
GLsizeiptr size;
48+
};
49+
50+
class GLStagingBuffer {
51+
public:
52+
uint32_t* MapBuffer( const GLsizeiptr size );
53+
void FlushBuffer();
54+
void QueueStagingCopy( GLBuffer* dst, const GLsizeiptr dstOffset );
55+
void FlushStagingCopyQueue();
56+
void FlushAll();
57+
58+
void InitGLBuffer();
59+
void FreeGLBuffer();
60+
61+
private:
62+
static const GLsizeiptr SIZE;
63+
64+
GLsizeiptr pointer = 0;
65+
GLsizeiptr current = 0;
66+
GLsizeiptr last = 0;
67+
68+
static const uint32_t MAX_COPIES = 16;
69+
GLStagingCopy copyQueue[MAX_COPIES];
70+
uint32_t currentCopy = 0;
71+
72+
GLBuffer buffer = GLBuffer( "staging", BufferBind::STAGING, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT,
73+
GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT );
74+
};
75+
76+
extern GLStagingBuffer stagingBuffer;
77+
78+
#endif // GLMEMORY_H

0 commit comments

Comments
 (0)