1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 
29 #include "OgreGLES2HardwareBuffer.h"
30 #include "OgreRoot.h"
31 #include "OgreGLES2RenderSystem.h"
32 #include "OgreGLES2StateCacheManager.h"
33 
34 namespace Ogre {
GLES2HardwareBuffer(GLenum target,size_t sizeInBytes,GLenum usage)35     GLES2HardwareBuffer::GLES2HardwareBuffer(GLenum target, size_t sizeInBytes, GLenum usage)
36         : mTarget(target), mSizeInBytes(sizeInBytes), mUsage(usage)
37     {
38         mRenderSystem = static_cast<GLES2RenderSystem*>(Root::getSingleton().getRenderSystem());
39         createBuffer();
40     }
41 
~GLES2HardwareBuffer()42     GLES2HardwareBuffer::~GLES2HardwareBuffer()
43     {
44         destroyBuffer();
45     }
46 
createBuffer()47     void GLES2HardwareBuffer::createBuffer()
48     {
49         OGRE_CHECK_GL_ERROR(glGenBuffers(1, &mBufferId));
50 
51         if (!mBufferId)
52         {
53             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
54                         "Cannot create GL ES buffer",
55                         "GLES2HardwareBuffer::createBuffer");
56         }
57 
58         mRenderSystem->_getStateCacheManager()->bindGLBuffer(mTarget, mBufferId);
59 
60         if(mRenderSystem->getCapabilities()->hasCapability(RSC_DEBUG))
61         {
62             OGRE_CHECK_GL_ERROR(glLabelObjectEXT(GL_BUFFER_OBJECT_EXT, mBufferId, 0, ("Buffer #" + StringConverter::toString(mBufferId)).c_str()));
63         }
64 
65         OGRE_CHECK_GL_ERROR(glBufferData(mTarget, mSizeInBytes, NULL, getGLUsage(mUsage)));
66     }
67 
destroyBuffer()68     void GLES2HardwareBuffer::destroyBuffer()
69     {
70         // Delete the cached value
71         if(GLES2StateCacheManager* stateCacheManager = mRenderSystem->_getStateCacheManager())
72             stateCacheManager->deleteGLBuffer(mTarget, mBufferId);
73     }
74 
lockImpl(size_t offset,size_t length,HardwareBuffer::LockOptions options)75     void* GLES2HardwareBuffer::lockImpl(size_t offset, size_t length,
76                                         HardwareBuffer::LockOptions options)
77     {
78         GLenum access = 0;
79 
80         // Use glMapBuffer
81         mRenderSystem->_getStateCacheManager()->bindGLBuffer(mTarget, mBufferId);
82 
83         bool writeOnly =
84             options == HardwareBuffer::HBL_WRITE_ONLY ||
85             ((mUsage & HardwareBuffer::HBU_WRITE_ONLY) &&
86              options != HardwareBuffer::HBL_READ_ONLY && options != HardwareBuffer::HBL_NORMAL);
87 
88         void* pBuffer = NULL;
89         if(mRenderSystem->getCapabilities()->hasCapability(RSC_MAPBUFFER))
90         {
91             if (writeOnly)
92             {
93                 access = GL_MAP_WRITE_BIT_EXT;
94                 if (options == HardwareBuffer::HBL_DISCARD ||
95                     options == HardwareBuffer::HBL_NO_OVERWRITE)
96                 {
97                     // Discard the buffer
98                     access |= GL_MAP_INVALIDATE_RANGE_BIT_EXT;
99                 }
100             }
101             else if (options == HardwareBuffer::HBL_READ_ONLY)
102                 access = GL_MAP_READ_BIT_EXT;
103             else
104                 access = GL_MAP_READ_BIT_EXT | GL_MAP_WRITE_BIT_EXT;
105 
106             OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRangeEXT(mTarget, offset, length, access));
107         }
108 
109         if (!pBuffer)
110         {
111             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer: Out of memory",
112                         "GLES2HardwareBuffer::lock");
113         }
114 
115         // pBuffer is already offsetted in glMapBufferRange
116         return static_cast<uint8*>(pBuffer);
117     }
118 
unlockImpl()119     void GLES2HardwareBuffer::unlockImpl()
120     {
121         mRenderSystem->_getStateCacheManager()->bindGLBuffer(mTarget, mBufferId);
122 
123         if(mRenderSystem->getCapabilities()->hasCapability(RSC_MAPBUFFER)) {
124             GLboolean mapped;
125             OGRE_CHECK_GL_ERROR(mapped = glUnmapBufferOES(mTarget));
126             if(!mapped)
127             {
128                 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer data corrupted, please reload",
129                             "GLES2HardwareBuffer::unlock");
130             }
131         }
132     }
133 
readData(size_t offset,size_t length,void * pDest)134     void GLES2HardwareBuffer::readData(size_t offset, size_t length, void* pDest)
135     {
136         if(!OGRE_NO_GLES3_SUPPORT || mRenderSystem->checkExtension("GL_EXT_map_buffer_range"))
137         {
138             // Map the buffer range then copy out of it into our destination buffer
139             void* srcData;
140             OGRE_CHECK_GL_ERROR(srcData = glMapBufferRangeEXT(mTarget, offset, length, GL_MAP_READ_BIT_EXT));
141             memcpy(pDest, srcData, length);
142 
143             // Unmap the buffer since we are done.
144             GLboolean mapped;
145             OGRE_CHECK_GL_ERROR(mapped = glUnmapBufferOES(mTarget));
146             if(!mapped)
147             {
148                 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Buffer data corrupted, please reload",
149                             "GLES2HardwareBuffer::readData");
150             }
151         }
152         else
153         {
154             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Read hardware buffer is not supported",
155                         "GLES2HardwareBuffer::readData");
156         }
157     }
158 
writeData(size_t offset,size_t length,const void * pSource,bool discardWholeBuffer)159     void GLES2HardwareBuffer::writeData(size_t offset, size_t length, const void* pSource,
160                                         bool discardWholeBuffer)
161     {
162         mRenderSystem->_getStateCacheManager()->bindGLBuffer(mTarget, mBufferId);
163 
164         if (offset == 0 && length == mSizeInBytes)
165         {
166             OGRE_CHECK_GL_ERROR(glBufferData(mTarget, mSizeInBytes, pSource, getGLUsage(mUsage)));
167         }
168         else
169         {
170             if(discardWholeBuffer)
171             {
172                 OGRE_CHECK_GL_ERROR(glBufferData(mTarget, mSizeInBytes, NULL, getGLUsage(mUsage)));
173             }
174 
175             OGRE_CHECK_GL_ERROR(glBufferSubData(mTarget, offset, length, pSource));
176         }
177     }
178 
copyData(GLuint srcBufferId,size_t srcOffset,size_t dstOffset,size_t length,bool discardWholeBuffer)179     void GLES2HardwareBuffer::copyData(GLuint srcBufferId, size_t srcOffset, size_t dstOffset,
180                                        size_t length, bool discardWholeBuffer)
181     {
182 #if OGRE_NO_GLES3_SUPPORT == 0
183         // Zero out this(destination) buffer
184         OGRE_CHECK_GL_ERROR(glBindBuffer(mTarget, mBufferId));
185         OGRE_CHECK_GL_ERROR(glBufferData(mTarget, length, 0, getGLUsage(mUsage)));
186         OGRE_CHECK_GL_ERROR(glBindBuffer(mTarget, 0));
187 
188         // Do it the fast way.
189         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_READ_BUFFER, srcBufferId));
190         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_WRITE_BUFFER, mBufferId));
191 
192         OGRE_CHECK_GL_ERROR(glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, dstOffset, length));
193 
194         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_READ_BUFFER, 0));
195         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_WRITE_BUFFER, 0));
196 #else
197         OgreAssert(false, "GLES3 needed");
198 #endif
199     }
200 
getGLUsage(unsigned int usage)201     GLenum GLES2HardwareBuffer::getGLUsage(unsigned int usage)
202     {
203         return  (usage & HardwareBuffer::HBU_DISCARDABLE) ? GL_STREAM_DRAW :
204                 (usage & HardwareBuffer::HBU_STATIC) ? GL_STATIC_DRAW :
205                 GL_DYNAMIC_DRAW;
206     }
207 }
208