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/angletypes.h"
14 #include "libANGLE/formatutils.h"
15 #include "libANGLE/renderer/gl/FunctionsGL.h"
16 #include "libANGLE/renderer/gl/StateManagerGL.h"
17 #include "libANGLE/renderer/gl/renderergl_utils.h"
18
19 namespace rx
20 {
21
22 // Use the GL_COPY_READ_BUFFER binding when two buffers need to be bound simultaneously.
23 // GL_ELEMENT_ARRAY_BUFFER is supported on more versions but can modify the state of the currently
24 // bound VAO. Two simultaneous buffer bindings are only needed for glCopyBufferSubData which also
25 // adds the GL_COPY_READ_BUFFER binding.
26 static const GLenum SourceBufferOperationTarget = GL_COPY_READ_BUFFER;
27
28 // Use the GL_ELEMENT_ARRAY_BUFFER binding for most operations since it's available on all
29 // supported GL versions and doesn't affect any current state when it changes.
30 static const GLenum DestBufferOperationTarget = GL_ARRAY_BUFFER;
31
BufferGL(const gl::BufferState & state,const FunctionsGL * functions,StateManagerGL * stateManager)32 BufferGL::BufferGL(const gl::BufferState &state,
33 const FunctionsGL *functions,
34 StateManagerGL *stateManager)
35 : BufferImpl(state),
36 mIsMapped(false),
37 mMapOffset(0),
38 mMapSize(0),
39 mShadowBufferData(!CanMapBufferForRead(functions)),
40 mShadowCopy(),
41 mBufferSize(0),
42 mFunctions(functions),
43 mStateManager(stateManager),
44 mBufferID(0)
45 {
46 ASSERT(mFunctions);
47 ASSERT(mStateManager);
48
49 mFunctions->genBuffers(1, &mBufferID);
50 }
51
~BufferGL()52 BufferGL::~BufferGL()
53 {
54 mStateManager->deleteBuffer(mBufferID);
55 mBufferID = 0;
56 }
57
setData(GLenum,const void * data,size_t size,GLenum usage)58 gl::Error BufferGL::setData(GLenum /*target*/, const void *data, size_t size, GLenum usage)
59 {
60 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
61 mFunctions->bufferData(DestBufferOperationTarget, size, data, usage);
62
63 if (mShadowBufferData)
64 {
65 if (!mShadowCopy.resize(size))
66 {
67 return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize buffer data shadow copy.");
68 }
69
70 if (size > 0 && data != nullptr)
71 {
72 memcpy(mShadowCopy.data(), data, size);
73 }
74 }
75
76 mBufferSize = size;
77
78 return gl::Error(GL_NO_ERROR);
79 }
80
setSubData(GLenum,const void * data,size_t size,size_t offset)81 gl::Error BufferGL::setSubData(GLenum /*target*/, const void *data, size_t size, size_t offset)
82 {
83 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
84 mFunctions->bufferSubData(DestBufferOperationTarget, offset, size, data);
85
86 if (mShadowBufferData && size > 0)
87 {
88 memcpy(mShadowCopy.data() + offset, data, size);
89 }
90
91 return gl::Error(GL_NO_ERROR);
92 }
93
copySubData(BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)94 gl::Error BufferGL::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size)
95 {
96 BufferGL *sourceGL = GetAs<BufferGL>(source);
97
98 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
99 mStateManager->bindBuffer(SourceBufferOperationTarget, sourceGL->getBufferID());
100
101 mFunctions->copyBufferSubData(SourceBufferOperationTarget, DestBufferOperationTarget, sourceOffset, destOffset, size);
102
103 if (mShadowBufferData && size > 0)
104 {
105 ASSERT(sourceGL->mShadowBufferData);
106 memcpy(mShadowCopy.data() + destOffset, sourceGL->mShadowCopy.data() + sourceOffset, size);
107 }
108
109 return gl::Error(GL_NO_ERROR);
110 }
111
map(GLenum access,GLvoid ** mapPtr)112 gl::Error BufferGL::map(GLenum access, GLvoid **mapPtr)
113 {
114 if (mShadowBufferData)
115 {
116 *mapPtr = mShadowCopy.data();
117 }
118 else
119 {
120 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
121 *mapPtr = mFunctions->mapBuffer(DestBufferOperationTarget, access);
122 }
123
124 mIsMapped = true;
125 mMapOffset = 0;
126 mMapSize = mBufferSize;
127
128 return gl::Error(GL_NO_ERROR);
129 }
130
mapRange(size_t offset,size_t length,GLbitfield access,GLvoid ** mapPtr)131 gl::Error BufferGL::mapRange(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr)
132 {
133 if (mShadowBufferData)
134 {
135 *mapPtr = mShadowCopy.data() + offset;
136 }
137 else
138 {
139 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
140 *mapPtr = mFunctions->mapBufferRange(DestBufferOperationTarget, offset, length, access);
141 }
142
143 mIsMapped = true;
144 mMapOffset = offset;
145 mMapSize = length;
146
147 return gl::Error(GL_NO_ERROR);
148 }
149
unmap(GLboolean * result)150 gl::Error BufferGL::unmap(GLboolean *result)
151 {
152 ASSERT(result);
153 ASSERT(mIsMapped);
154
155 if (mShadowBufferData)
156 {
157 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
158 mFunctions->bufferSubData(DestBufferOperationTarget, mMapOffset, mMapSize,
159 mShadowCopy.data() + mMapOffset);
160 *result = GL_TRUE;
161 }
162 else
163 {
164 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
165 *result = mFunctions->unmapBuffer(DestBufferOperationTarget);
166 }
167
168 mIsMapped = false;
169 return gl::Error(GL_NO_ERROR);
170 }
171
getIndexRange(GLenum type,size_t offset,size_t count,bool primitiveRestartEnabled,gl::IndexRange * outRange)172 gl::Error BufferGL::getIndexRange(GLenum type,
173 size_t offset,
174 size_t count,
175 bool primitiveRestartEnabled,
176 gl::IndexRange *outRange)
177 {
178 ASSERT(!mIsMapped);
179
180 if (mShadowBufferData)
181 {
182 *outRange = gl::ComputeIndexRange(type, mShadowCopy.data() + offset, count,
183 primitiveRestartEnabled);
184 }
185 else
186 {
187 mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
188
189 const gl::Type &typeInfo = gl::GetTypeInfo(type);
190 const uint8_t *bufferData = MapBufferRangeWithFallback(
191 mFunctions, DestBufferOperationTarget, offset, count * typeInfo.bytes, GL_MAP_READ_BIT);
192 *outRange = gl::ComputeIndexRange(type, bufferData, count, primitiveRestartEnabled);
193 mFunctions->unmapBuffer(DestBufferOperationTarget);
194 }
195
196 return gl::Error(GL_NO_ERROR);
197 }
198
getBufferID() const199 GLuint BufferGL::getBufferID() const
200 {
201 return mBufferID;
202 }
203
204 }
205