1 //
2 // Copyright (c) 2002-2014 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 // Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or
8 // index data. Implements GL buffer objects and related functionality.
9 // [OpenGL ES 2.0.24] section 2.9 page 21.
10 
11 #include "libANGLE/Buffer.h"
12 
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/BufferImpl.h"
15 #include "libANGLE/renderer/GLImplFactory.h"
16 
17 namespace gl
18 {
19 
BufferState()20 BufferState::BufferState()
21     : mLabel(),
22       mUsage(BufferUsage::StaticDraw),
23       mSize(0),
24       mAccessFlags(0),
25       mAccess(GL_WRITE_ONLY_OES),
26       mMapped(GL_FALSE),
27       mMapPointer(nullptr),
28       mMapOffset(0),
29       mMapLength(0)
30 {
31 }
32 
~BufferState()33 BufferState::~BufferState()
34 {
35 }
36 
Buffer(rx::GLImplFactory * factory,GLuint id)37 Buffer::Buffer(rx::GLImplFactory *factory, GLuint id)
38     : RefCountObject(id), mImpl(factory->createBuffer(mState))
39 {
40 }
41 
~Buffer()42 Buffer::~Buffer()
43 {
44     SafeDelete(mImpl);
45 }
46 
onDestroy(const Context * context)47 Error Buffer::onDestroy(const Context *context)
48 {
49     // In tests, mImpl might be null.
50     if (mImpl)
51         mImpl->destroy(context);
52     return NoError();
53 }
54 
setLabel(const std::string & label)55 void Buffer::setLabel(const std::string &label)
56 {
57     mState.mLabel = label;
58 }
59 
getLabel() const60 const std::string &Buffer::getLabel() const
61 {
62     return mState.mLabel;
63 }
64 
bufferData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage)65 Error Buffer::bufferData(const Context *context,
66                          BufferBinding target,
67                          const void *data,
68                          GLsizeiptr size,
69                          BufferUsage usage)
70 {
71     const void *dataForImpl = data;
72 
73     // If we are using robust resource init, make sure the buffer starts cleared.
74     // Note: the Context is checked for nullptr because of some testing code.
75     // TODO(jmadill): Investigate lazier clearing.
76     if (context && context->getGLState().isRobustResourceInitEnabled() && !data && size > 0)
77     {
78         angle::MemoryBuffer *scratchBuffer = nullptr;
79         ANGLE_TRY(context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
80         dataForImpl = scratchBuffer->data();
81     }
82 
83     ANGLE_TRY(mImpl->setData(context, target, dataForImpl, size, usage));
84 
85     mIndexRangeCache.clear();
86     mState.mUsage = usage;
87     mState.mSize  = size;
88 
89     return NoError();
90 }
91 
bufferSubData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,GLintptr offset)92 Error Buffer::bufferSubData(const Context *context,
93                             BufferBinding target,
94                             const void *data,
95                             GLsizeiptr size,
96                             GLintptr offset)
97 {
98     ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
99 
100     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(size));
101 
102     return NoError();
103 }
104 
copyBufferSubData(const Context * context,Buffer * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)105 Error Buffer::copyBufferSubData(const Context *context,
106                                 Buffer *source,
107                                 GLintptr sourceOffset,
108                                 GLintptr destOffset,
109                                 GLsizeiptr size)
110 {
111     ANGLE_TRY(
112         mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
113 
114     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset), static_cast<unsigned int>(size));
115 
116     return NoError();
117 }
118 
map(const Context * context,GLenum access)119 Error Buffer::map(const Context *context, GLenum access)
120 {
121     ASSERT(!mState.mMapped);
122 
123     mState.mMapPointer = nullptr;
124     ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
125 
126     ASSERT(access == GL_WRITE_ONLY_OES);
127 
128     mState.mMapped      = GL_TRUE;
129     mState.mMapOffset   = 0;
130     mState.mMapLength   = mState.mSize;
131     mState.mAccess      = access;
132     mState.mAccessFlags = GL_MAP_WRITE_BIT;
133     mIndexRangeCache.clear();
134 
135     return NoError();
136 }
137 
mapRange(const Context * context,GLintptr offset,GLsizeiptr length,GLbitfield access)138 Error Buffer::mapRange(const Context *context,
139                        GLintptr offset,
140                        GLsizeiptr length,
141                        GLbitfield access)
142 {
143     ASSERT(!mState.mMapped);
144     ASSERT(offset + length <= mState.mSize);
145 
146     mState.mMapPointer = nullptr;
147     ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
148 
149     mState.mMapped      = GL_TRUE;
150     mState.mMapOffset   = static_cast<GLint64>(offset);
151     mState.mMapLength   = static_cast<GLint64>(length);
152     mState.mAccess      = GL_WRITE_ONLY_OES;
153     mState.mAccessFlags = access;
154 
155     // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
156     // value for GL_BUFFER_ACCESS_OES because it was written against ES2.  Since there is
157     // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
158     // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
159 
160     if ((access & GL_MAP_WRITE_BIT) > 0)
161     {
162         mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset), static_cast<unsigned int>(length));
163     }
164 
165     return NoError();
166 }
167 
unmap(const Context * context,GLboolean * result)168 Error Buffer::unmap(const Context *context, GLboolean *result)
169 {
170     ASSERT(mState.mMapped);
171 
172     *result = GL_FALSE;
173     ANGLE_TRY(mImpl->unmap(context, result));
174 
175     mState.mMapped      = GL_FALSE;
176     mState.mMapPointer  = nullptr;
177     mState.mMapOffset   = 0;
178     mState.mMapLength   = 0;
179     mState.mAccess      = GL_WRITE_ONLY_OES;
180     mState.mAccessFlags = 0;
181 
182     return NoError();
183 }
184 
onTransformFeedback()185 void Buffer::onTransformFeedback()
186 {
187     mIndexRangeCache.clear();
188 }
189 
onPixelUnpack()190 void Buffer::onPixelUnpack()
191 {
192     mIndexRangeCache.clear();
193 }
194 
getIndexRange(const gl::Context * context,GLenum type,size_t offset,size_t count,bool primitiveRestartEnabled,IndexRange * outRange) const195 Error Buffer::getIndexRange(const gl::Context *context,
196                             GLenum type,
197                             size_t offset,
198                             size_t count,
199                             bool primitiveRestartEnabled,
200                             IndexRange *outRange) const
201 {
202     if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
203     {
204         return NoError();
205     }
206 
207     ANGLE_TRY(
208         mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
209 
210     mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
211 
212     return NoError();
213 }
214 
215 }  // namespace gl
216