1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsGLHardwareBuffer.h"
4#include "BsGLHardwareBufferManager.h"
5#include "Error/BsException.h"
6#include "BsGLCommandBuffer.h"
7
8namespace bs { namespace ct
9{
10 GLHardwareBuffer::GLHardwareBuffer(GLenum target, UINT32 size, GpuBufferUsage usage)
11 : HardwareBuffer(size, usage, GDF_DEFAULT), mTarget(target)
12 {
13 glGenBuffers(1, &mBufferId);
14 BS_CHECK_GL_ERROR();
15
16 if (!mBufferId)
17 BS_EXCEPT(InternalErrorException, "Cannot create GL buffer");
18
19 glBindBuffer(target, mBufferId);
20 BS_CHECK_GL_ERROR();
21
22 glBufferData(target, size, nullptr, GLHardwareBufferManager::getGLUsage(usage));
23 BS_CHECK_GL_ERROR();
24 }
25
26 GLHardwareBuffer::~GLHardwareBuffer()
27 {
28 if (mBufferId != 0)
29 {
30 glDeleteBuffers(1, &mBufferId);
31 BS_CHECK_GL_ERROR();
32 }
33 }
34
35 void* GLHardwareBuffer::map(UINT32 offset, UINT32 length, GpuLockOptions options, UINT32 deviceIdx, UINT32 queueIdx)
36 {
37 // If no buffer ID it's assumed this type of buffer is unsupported and we silently fail (it's up to the creator
38 // if the buffer to check for support and potentially print a warning)
39 if(mBufferId == 0)
40 return nullptr;
41
42 GLenum access = 0;
43
44 glBindBuffer(mTarget, mBufferId);
45 BS_CHECK_GL_ERROR();
46
47 if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))
48 {
49 access = GL_MAP_WRITE_BIT;
50
51 if (options == GBL_WRITE_ONLY_DISCARD)
52 access |= GL_MAP_INVALIDATE_BUFFER_BIT;
53 else if (options == GBL_WRITE_ONLY_NO_OVERWRITE)
54 access |= GL_MAP_UNSYNCHRONIZED_BIT;
55 }
56 else if (options == GBL_READ_ONLY)
57 access = GL_MAP_READ_BIT;
58 else
59 access = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
60
61 void* buffer = nullptr;
62
63 if (length > 0)
64 {
65 buffer = glMapBufferRange(mTarget, offset, length, access);
66 BS_CHECK_GL_ERROR();
67
68 if (buffer == nullptr)
69 BS_EXCEPT(InternalErrorException, "Cannot map OpenGL buffer.");
70
71 mZeroLocked = false;
72 }
73 else
74 mZeroLocked = true;
75
76 return static_cast<void*>(static_cast<unsigned char*>(buffer));
77 }
78
79 void GLHardwareBuffer::unmap()
80 {
81 if(mBufferId == 0)
82 return;
83
84 glBindBuffer(mTarget, mBufferId);
85 BS_CHECK_GL_ERROR();
86
87 if (!mZeroLocked)
88 {
89 if (!glUnmapBuffer(mTarget))
90 {
91 BS_CHECK_GL_ERROR();
92 BS_EXCEPT(InternalErrorException, "Buffer data corrupted, please reload.");
93 }
94 }
95 }
96
97 void GLHardwareBuffer::readData(UINT32 offset, UINT32 length, void* dest, UINT32 deviceIdx, UINT32 queueIdx)
98 {
99 if(mBufferId == 0)
100 return;
101
102 void* bufferData = lock(offset, length, GBL_READ_ONLY, deviceIdx, queueIdx);
103 memcpy(dest, bufferData, length);
104 unlock();
105 }
106
107 void GLHardwareBuffer::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags, UINT32 queueIdx)
108 {
109 if(mBufferId == 0)
110 return;
111
112 GpuLockOptions lockOption = GBL_WRITE_ONLY;
113 if (writeFlags == BWT_DISCARD)
114 lockOption = GBL_WRITE_ONLY_DISCARD;
115 else if (writeFlags == BTW_NO_OVERWRITE)
116 lockOption = GBL_WRITE_ONLY_NO_OVERWRITE;
117
118 void* bufferData = lock(offset, length, lockOption, 0, queueIdx);
119 memcpy(bufferData, source, length);
120 unlock();
121 }
122
123 void GLHardwareBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, UINT32 length,
124 bool discardWholeBuffer, const SPtr<ct::CommandBuffer>& commandBuffer)
125 {
126 if(mBufferId == 0)
127 return;
128
129 auto executeRef = [this](HardwareBuffer& srcBuffer, UINT32 srcOffset, UINT32 dstOffset, UINT32 length)
130 {
131 GLHardwareBuffer& glSrcBuffer = static_cast<GLHardwareBuffer&>(srcBuffer);
132
133 glBindBuffer(GL_COPY_READ_BUFFER, glSrcBuffer.getGLBufferId());
134 BS_CHECK_GL_ERROR();
135
136 glBindBuffer(GL_COPY_WRITE_BUFFER, mBufferId);
137 BS_CHECK_GL_ERROR();
138
139 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, dstOffset, length);
140 BS_CHECK_GL_ERROR();
141 };
142
143 if (commandBuffer == nullptr)
144 executeRef(srcBuffer, srcOffset, dstOffset, length);
145 else
146 {
147 auto execute = [&]() { executeRef(srcBuffer, srcOffset, dstOffset, length); };
148
149 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
150 cb->queueCommand(execute);
151 }
152
153 }
154}}
155