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-2013 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 "OgreGLES2HardwareBufferManager.h"
30 
31 #if OGRE_NO_GLES3_SUPPORT == 0
32 #include "OgreGLES2HardwareUniformBuffer.h"
33 #include "OgreRoot.h"
34 #include "OgreGLES2RenderSystem.h"
35 
36 namespace Ogre {
GLES2HardwareUniformBuffer(HardwareBufferManagerBase * mgr,size_t bufferSize,HardwareBuffer::Usage usage,bool useShadowBuffer,const String & name)37     GLES2HardwareUniformBuffer::GLES2HardwareUniformBuffer(HardwareBufferManagerBase* mgr,
38                                                                size_t bufferSize,
39                                                                HardwareBuffer::Usage usage,
40                                                                bool useShadowBuffer, const String& name)
41     : HardwareUniformBuffer(mgr, bufferSize, usage, useShadowBuffer, name)
42     {
43         OGRE_CHECK_GL_ERROR(glGenBuffers(1, &mBufferId));
44 
45         if (!mBufferId)
46         {
47             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
48                         "Cannot create GL uniform buffer",
49                         "GLES2HardwareUniformBuffer::GLES2HardwareUniformBuffer");
50         }
51 
52         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
53         OGRE_CHECK_GL_ERROR(glBufferData(GL_UNIFORM_BUFFER, mSizeInBytes, NULL,
54                                          GLES2HardwareBufferManager::getGLUsage(usage)));
55 
56 //        std::cerr << "creating uniform buffer = " << mBufferId << std::endl;
57     }
58 
~GLES2HardwareUniformBuffer()59     GLES2HardwareUniformBuffer::~GLES2HardwareUniformBuffer()
60     {
61         OGRE_CHECK_GL_ERROR(glDeleteBuffers(1, &mBufferId));
62     }
63 
setGLBufferBinding(GLint binding)64     void GLES2HardwareUniformBuffer::setGLBufferBinding(GLint binding)
65     {
66         mBinding = binding;
67 
68         // Attach the buffer to the UBO binding
69         OGRE_CHECK_GL_ERROR(glBindBufferBase(GL_UNIFORM_BUFFER, mBinding, mBufferId));
70     }
71 
lockImpl(size_t offset,size_t length,LockOptions options)72     void* GLES2HardwareUniformBuffer::lockImpl(size_t offset,
73                                                  size_t length,
74                                                  LockOptions options)
75     {
76         if (mIsLocked)
77         {
78             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
79                         "Invalid attempt to lock a uniform buffer that has already been locked",
80                         "GLES2HardwareUniformBuffer::lock");
81         }
82 
83         GLenum access = 0;
84         void* retPtr = 0;
85 
86         // Use glMapBuffer
87         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
88 
89         if (mUsage & HBU_WRITE_ONLY)
90         {
91             access |= GL_MAP_WRITE_BIT;
92             access |= GL_MAP_FLUSH_EXPLICIT_BIT;
93             if(options == HBL_DISCARD)
94             {
95                 // Discard the buffer
96                 access |= GL_MAP_INVALIDATE_RANGE_BIT;
97             }
98         }
99         else if (options == HBL_READ_ONLY)
100             access |= GL_MAP_READ_BIT;
101         else
102             access |= GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
103 
104         access |= GL_MAP_UNSYNCHRONIZED_BIT;
105 
106         void* pBuffer;
107         OGRE_CHECK_GL_ERROR(pBuffer = glMapBufferRange(GL_UNIFORM_BUFFER, offset, length, access));
108 
109         if(pBuffer == 0)
110         {
111             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
112                         "Uniform Buffer: Out of memory",
113                         "GLES2HardwareUniformBuffer::lock");
114         }
115 
116         // return offsetted
117         retPtr = static_cast<void*>(static_cast<unsigned char*>(pBuffer) + offset);
118 
119 		mIsLocked = true;
120         return retPtr;
121     }
122 
unlockImpl(void)123     void GLES2HardwareUniformBuffer::unlockImpl(void)
124     {
125         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
126 
127         if (mUsage & HBU_WRITE_ONLY)
128         {
129             OGRE_CHECK_GL_ERROR(glFlushMappedBufferRange(GL_UNIFORM_BUFFER, mLockStart, mLockSize));
130         }
131 
132         GLboolean mapped;
133         OGRE_CHECK_GL_ERROR(mapped = glUnmapBuffer(GL_UNIFORM_BUFFER));
134         if(!mapped)
135         {
136             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
137                         "Buffer data corrupted, please reload",
138                         "GLES2HardwareUniformBuffer::unlock");
139         }
140         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, 0));
141 
142         mIsLocked = false;
143     }
144 
readData(size_t offset,size_t length,void * pDest)145     void GLES2HardwareUniformBuffer::readData(size_t offset, size_t length, void* pDest)
146     {
147         // Get data from the real buffer
148         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
149 
150 		OGRE_CHECK_GL_ERROR(glGetBufferPointerv(GL_UNIFORM_BUFFER, GL_BUFFER_MAP_POINTER, &pDest));
151     }
152 
writeData(size_t offset,size_t length,const void * pSource,bool discardWholeBuffer)153     void GLES2HardwareUniformBuffer::writeData(size_t offset,
154                                                  size_t length,
155                                                  const void* pSource,
156                                                  bool discardWholeBuffer)
157     {
158         OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
159 
160         if (offset == 0 && length == mSizeInBytes)
161         {
162             OGRE_CHECK_GL_ERROR(glBufferData(GL_UNIFORM_BUFFER, mSizeInBytes, pSource,
163                                              GLES2HardwareBufferManager::getGLUsage(mUsage)));
164         }
165         else
166         {
167             if(discardWholeBuffer)
168             {
169                 OGRE_CHECK_GL_ERROR(glBufferData(GL_UNIFORM_BUFFER, mSizeInBytes, NULL,
170                                                  GLES2HardwareBufferManager::getGLUsage(mUsage)));
171             }
172 
173             OGRE_CHECK_GL_ERROR(glBufferSubData(GL_UNIFORM_BUFFER, offset, length, pSource));
174         }
175     }
176 
copyData(HardwareBuffer & srcBuffer,size_t srcOffset,size_t dstOffset,size_t length,bool discardWholeBuffer)177     void GLES2HardwareUniformBuffer::copyData(HardwareBuffer& srcBuffer, size_t srcOffset,
178                                                 size_t dstOffset, size_t length, bool discardWholeBuffer)
179     {
180         // If the buffer is not in system memory we can use ARB_copy_buffers to do an optimised copy.
181         if (srcBuffer.isSystemMemory())
182         {
183 			HardwareBuffer::copyData(srcBuffer, srcOffset, dstOffset, length, discardWholeBuffer);
184         }
185         else
186         {
187             // Unbind the current buffer
188             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, 0));
189 
190             // Zero out this(destination) buffer
191             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, mBufferId));
192             OGRE_CHECK_GL_ERROR(glBufferData(GL_UNIFORM_BUFFER, length, 0, GLES2HardwareBufferManager::getGLUsage(mUsage)));
193             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, 0));
194 
195             // Do it the fast way.
196             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_READ_BUFFER, static_cast<GLES2HardwareUniformBuffer &>(srcBuffer).getGLBufferId()));
197             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_WRITE_BUFFER, mBufferId));
198 
199             OGRE_CHECK_GL_ERROR(glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, dstOffset, length));
200 
201             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_READ_BUFFER, 0));
202             OGRE_CHECK_GL_ERROR(glBindBuffer(GL_COPY_WRITE_BUFFER, 0));
203         }
204     }
205 }
206 #endif
207