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 | |
8 | namespace 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 | |