1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // BufferGL.cpp: Implements the class methods for BufferGL.
8
9 #include "libANGLE/renderer/gl/BufferGL.h"
10
11 #include "common/debug.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/angletypes.h"
15 #include "libANGLE/formatutils.h"
16 #include "libANGLE/renderer/gl/ContextGL.h"
17 #include "libANGLE/renderer/gl/FunctionsGL.h"
18 #include "libANGLE/renderer/gl/StateManagerGL.h"
19 #include "libANGLE/renderer/gl/renderergl_utils.h"
20
21 namespace rx
22 {
23
24 // Use the GL_COPY_READ_BUFFER binding when two buffers need to be bound simultaneously.
25 // GL_ELEMENT_ARRAY_BUFFER is supported on more versions but can modify the state of the currently
26 // bound VAO. Two simultaneous buffer bindings are only needed for glCopyBufferSubData which also
27 // adds the GL_COPY_READ_BUFFER binding.
28 static constexpr gl::BufferBinding SourceBufferOperationTarget = gl::BufferBinding::CopyRead;
29
30 // Use the GL_ELEMENT_ARRAY_BUFFER binding for most operations since it's available on all
31 // supported GL versions and doesn't affect any current state when it changes.
32 static constexpr gl::BufferBinding DestBufferOperationTarget = gl::BufferBinding::Array;
33
BufferGL(const gl::BufferState & state,const FunctionsGL * functions,StateManagerGL * stateManager)34 BufferGL::BufferGL(const gl::BufferState &state,
35 const FunctionsGL *functions,
36 StateManagerGL *stateManager)
37 : BufferImpl(state),
38 mIsMapped(false),
39 mMapOffset(0),
40 mMapSize(0),
41 mShadowBufferData(!CanMapBufferForRead(functions)),
42 mShadowCopy(),
43 mBufferSize(0),
44 mFunctions(functions),
45 mStateManager(stateManager),
46 mBufferID(0)
47 {
48 ASSERT(mFunctions);
49 ASSERT(mStateManager);
50
51 mFunctions->genBuffers(1, &mBufferID);
52 }
53
~BufferGL()54 BufferGL::~BufferGL()
55 {
56 mStateManager->deleteBuffer(mBufferID);
57 mBufferID = 0;
58 }
59
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage usage)60 angle::Result BufferGL::setData(const gl::Context *context,
61 gl::BufferBinding target,
62 const void *data,
63 size_t size,
64 gl::BufferUsage usage)
65 {
66 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
67 mFunctions->bufferData(gl::ToGLenum(DestBufferOperationTarget), size, data, ToGLenum(usage));
68
69 if (mShadowBufferData)
70 {
71 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextGL>(context), mShadowCopy.resize(size));
72
73 if (size > 0 && data != nullptr)
74 {
75 memcpy(mShadowCopy.data(), data, size);
76 }
77 }
78
79 mBufferSize = size;
80
81 return angle::Result::Continue;
82 }
83
setSubData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,size_t offset)84 angle::Result BufferGL::setSubData(const gl::Context *context,
85 gl::BufferBinding target,
86 const void *data,
87 size_t size,
88 size_t offset)
89 {
90 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
91 mFunctions->bufferSubData(gl::ToGLenum(DestBufferOperationTarget), offset, size, data);
92
93 if (mShadowBufferData && size > 0)
94 {
95 memcpy(mShadowCopy.data() + offset, data, size);
96 }
97
98 return angle::Result::Continue;
99 }
100
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)101 angle::Result BufferGL::copySubData(const gl::Context *context,
102 BufferImpl *source,
103 GLintptr sourceOffset,
104 GLintptr destOffset,
105 GLsizeiptr size)
106 {
107 BufferGL *sourceGL = GetAs<BufferGL>(source);
108
109 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
110 mStateManager->bindBuffer(SourceBufferOperationTarget, sourceGL->getBufferID());
111
112 mFunctions->copyBufferSubData(gl::ToGLenum(SourceBufferOperationTarget),
113 gl::ToGLenum(DestBufferOperationTarget), sourceOffset, destOffset,
114 size);
115
116 if (mShadowBufferData && size > 0)
117 {
118 ASSERT(sourceGL->mShadowBufferData);
119 memcpy(mShadowCopy.data() + destOffset, sourceGL->mShadowCopy.data() + sourceOffset, size);
120 }
121
122 return angle::Result::Continue;
123 }
124
map(const gl::Context * context,GLenum access,void ** mapPtr)125 angle::Result BufferGL::map(const gl::Context *context, GLenum access, void **mapPtr)
126 {
127 if (mShadowBufferData)
128 {
129 *mapPtr = mShadowCopy.data();
130 }
131 else if (mFunctions->mapBuffer)
132 {
133 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
134 *mapPtr = mFunctions->mapBuffer(gl::ToGLenum(DestBufferOperationTarget), access);
135 }
136 else
137 {
138 ASSERT(mFunctions->mapBufferRange && access == GL_WRITE_ONLY_OES);
139 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
140 *mapPtr = mFunctions->mapBufferRange(gl::ToGLenum(DestBufferOperationTarget), 0,
141 mBufferSize, GL_MAP_WRITE_BIT);
142 }
143
144 mIsMapped = true;
145 mMapOffset = 0;
146 mMapSize = mBufferSize;
147
148 return angle::Result::Continue;
149 }
150
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)151 angle::Result BufferGL::mapRange(const gl::Context *context,
152 size_t offset,
153 size_t length,
154 GLbitfield access,
155 void **mapPtr)
156 {
157 if (mShadowBufferData)
158 {
159 *mapPtr = mShadowCopy.data() + offset;
160 }
161 else
162 {
163 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
164 *mapPtr = mFunctions->mapBufferRange(gl::ToGLenum(DestBufferOperationTarget), offset,
165 length, access);
166 }
167
168 mIsMapped = true;
169 mMapOffset = offset;
170 mMapSize = length;
171
172 return angle::Result::Continue;
173 }
174
unmap(const gl::Context * context,GLboolean * result)175 angle::Result BufferGL::unmap(const gl::Context *context, GLboolean *result)
176 {
177 ASSERT(result);
178 ASSERT(mIsMapped);
179
180 if (mShadowBufferData)
181 {
182 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
183 mFunctions->bufferSubData(gl::ToGLenum(DestBufferOperationTarget), mMapOffset, mMapSize,
184 mShadowCopy.data() + mMapOffset);
185 *result = GL_TRUE;
186 }
187 else
188 {
189 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
190 *result = mFunctions->unmapBuffer(gl::ToGLenum(DestBufferOperationTarget));
191 }
192
193 mIsMapped = false;
194 return angle::Result::Continue;
195 }
196
getIndexRange(const gl::Context * context,gl::DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,gl::IndexRange * outRange)197 angle::Result BufferGL::getIndexRange(const gl::Context *context,
198 gl::DrawElementsType type,
199 size_t offset,
200 size_t count,
201 bool primitiveRestartEnabled,
202 gl::IndexRange *outRange)
203 {
204 ASSERT(!mIsMapped);
205
206 if (mShadowBufferData)
207 {
208 *outRange = gl::ComputeIndexRange(type, mShadowCopy.data() + offset, count,
209 primitiveRestartEnabled);
210 }
211 else
212 {
213 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
214
215 const GLuint typeBytes = gl::GetDrawElementsTypeSize(type);
216 const uint8_t *bufferData =
217 MapBufferRangeWithFallback(mFunctions, gl::ToGLenum(DestBufferOperationTarget), offset,
218 count * typeBytes, GL_MAP_READ_BIT);
219 if (bufferData)
220 {
221 *outRange = gl::ComputeIndexRange(type, bufferData, count, primitiveRestartEnabled);
222 mFunctions->unmapBuffer(gl::ToGLenum(DestBufferOperationTarget));
223 }
224 else
225 {
226 // Workaround the null driver not having map support.
227 *outRange = gl::IndexRange(0, 0, 1);
228 }
229 }
230
231 return angle::Result::Continue;
232 }
233
getBufferID() const234 GLuint BufferGL::getBufferID() const
235 {
236 return mBufferID;
237 }
238 } // namespace rx
239