• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 
28 #if ENABLE(WEBGL)
29 
30 #include "WebGLBuffer.h"
31 
32 #include "ArrayBufferView.h"
33 #include "CheckedInt.h"
34 #include "WebGLRenderingContext.h"
35 
36 namespace WebCore {
37 
create(WebGLRenderingContext * ctx)38 PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx)
39 {
40     return adoptRef(new WebGLBuffer(ctx));
41 }
42 
WebGLBuffer(WebGLRenderingContext * ctx)43 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
44     : WebGLObject(ctx)
45     , m_target(0)
46     , m_byteLength(0)
47     , m_nextAvailableCacheEntry(0)
48 {
49     setObject(context()->graphicsContext3D()->createBuffer());
50     clearCachedMaxIndices();
51 }
52 
deleteObjectImpl(Platform3DObject object)53 void WebGLBuffer::deleteObjectImpl(Platform3DObject object)
54 {
55     context()->graphicsContext3D()->deleteBuffer(object);
56 }
57 
associateBufferDataImpl(ArrayBuffer * array,GC3Dintptr byteOffset,GC3Dsizeiptr byteLength)58 bool WebGLBuffer::associateBufferDataImpl(ArrayBuffer* array, GC3Dintptr byteOffset, GC3Dsizeiptr byteLength)
59 {
60     if (byteLength < 0 || byteOffset < 0)
61         return false;
62 
63     if (array && byteLength) {
64         CheckedInt<GC3Dintptr> checkedOffset(byteOffset);
65         CheckedInt<GC3Dsizeiptr> checkedLength(byteLength);
66         CheckedInt<GC3Dintptr> checkedMax = checkedOffset + checkedLength;
67         if (!checkedMax.valid() || checkedMax.value() > static_cast<int32_t>(array->byteLength()))
68             return false;
69     }
70 
71     switch (m_target) {
72     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
73         m_byteLength = byteLength;
74         clearCachedMaxIndices();
75         if (byteLength) {
76             m_elementArrayBuffer = ArrayBuffer::create(byteLength, 1);
77             if (!m_elementArrayBuffer) {
78                 m_byteLength = 0;
79                 return false;
80             }
81             if (array) {
82                 // We must always clone the incoming data because client-side
83                 // modifications without calling bufferData or bufferSubData
84                 // must never be able to change the validation results.
85                 memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()),
86                        static_cast<unsigned char*>(array->data()) + byteOffset,
87                        byteLength);
88             }
89         } else
90             m_elementArrayBuffer = 0;
91         return true;
92     case GraphicsContext3D::ARRAY_BUFFER:
93         m_byteLength = byteLength;
94         return true;
95     default:
96         return false;
97     }
98 }
99 
associateBufferData(GC3Dsizeiptr size)100 bool WebGLBuffer::associateBufferData(GC3Dsizeiptr size)
101 {
102     if (size < 0)
103         return false;
104     return associateBufferDataImpl(0, 0, size);
105 }
106 
associateBufferData(ArrayBuffer * array)107 bool WebGLBuffer::associateBufferData(ArrayBuffer* array)
108 {
109     if (!array)
110         return false;
111     return associateBufferDataImpl(array, 0, array->byteLength());
112 }
113 
associateBufferData(ArrayBufferView * array)114 bool WebGLBuffer::associateBufferData(ArrayBufferView* array)
115 {
116     if (!array)
117         return false;
118     return associateBufferDataImpl(array->buffer().get(), array->byteOffset(), array->byteLength());
119 }
120 
associateBufferSubDataImpl(GC3Dintptr offset,ArrayBuffer * array,GC3Dintptr arrayByteOffset,GC3Dsizeiptr byteLength)121 bool WebGLBuffer::associateBufferSubDataImpl(GC3Dintptr offset, ArrayBuffer* array, GC3Dintptr arrayByteOffset, GC3Dsizeiptr byteLength)
122 {
123     if (!array || offset < 0 || arrayByteOffset < 0 || byteLength < 0)
124         return false;
125 
126     if (byteLength) {
127         CheckedInt<GC3Dintptr> checkedBufferOffset(offset);
128         CheckedInt<GC3Dintptr> checkedArrayOffset(arrayByteOffset);
129         CheckedInt<GC3Dsizeiptr> checkedLength(byteLength);
130         CheckedInt<GC3Dintptr> checkedArrayMax = checkedArrayOffset + checkedLength;
131         CheckedInt<GC3Dintptr> checkedBufferMax = checkedBufferOffset + checkedLength;
132         if (!checkedArrayMax.valid() || checkedArrayMax.value() > static_cast<int32_t>(array->byteLength()) || !checkedBufferMax.valid() || checkedBufferMax.value() > m_byteLength)
133             return false;
134     }
135 
136     switch (m_target) {
137     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
138         clearCachedMaxIndices();
139         if (byteLength) {
140             if (!m_elementArrayBuffer)
141                 return false;
142             memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + offset,
143                    static_cast<unsigned char*>(array->data()) + arrayByteOffset,
144                    byteLength);
145         }
146         return true;
147     case GraphicsContext3D::ARRAY_BUFFER:
148         return true;
149     default:
150         return false;
151     }
152 }
153 
associateBufferSubData(GC3Dintptr offset,ArrayBuffer * array)154 bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBuffer* array)
155 {
156     if (!array)
157         return false;
158     return associateBufferSubDataImpl(offset, array, 0, array->byteLength());
159 }
160 
associateBufferSubData(GC3Dintptr offset,ArrayBufferView * array)161 bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBufferView* array)
162 {
163     if (!array)
164         return false;
165     return associateBufferSubDataImpl(offset, array->buffer().get(), array->byteOffset(), array->byteLength());
166 }
167 
byteLength() const168 GC3Dsizeiptr WebGLBuffer::byteLength() const
169 {
170     return m_byteLength;
171 }
172 
getCachedMaxIndex(GC3Denum type)173 int WebGLBuffer::getCachedMaxIndex(GC3Denum type)
174 {
175     for (size_t i = 0; i < WTF_ARRAY_LENGTH(m_maxIndexCache); ++i)
176         if (m_maxIndexCache[i].type == type)
177             return m_maxIndexCache[i].maxIndex;
178     return -1;
179 }
180 
setCachedMaxIndex(GC3Denum type,int value)181 void WebGLBuffer::setCachedMaxIndex(GC3Denum type, int value)
182 {
183     size_t numEntries = WTF_ARRAY_LENGTH(m_maxIndexCache);
184     for (size_t i = 0; i < numEntries; ++i)
185         if (m_maxIndexCache[i].type == type) {
186             m_maxIndexCache[i].maxIndex = value;
187             return;
188         }
189     m_maxIndexCache[m_nextAvailableCacheEntry].type = type;
190     m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value;
191     m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries;
192 }
193 
setTarget(GC3Denum target)194 void WebGLBuffer::setTarget(GC3Denum target)
195 {
196     // In WebGL, a buffer is bound to one target in its lifetime
197     if (m_target)
198         return;
199     if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
200         m_target = target;
201 }
202 
clearCachedMaxIndices()203 void WebGLBuffer::clearCachedMaxIndices()
204 {
205     memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
206 }
207 
208 }
209 
210 #endif // ENABLE(WEBGL)
211