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