• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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