Assertion failed in JSC::createError
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLBuffer.cpp
1 /*
2  * Copyright (C) 2009-2017 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 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 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 #include "WebGLBuffer.h"
28
29 #if ENABLE(WEBGL)
30
31 #include "WebGLContextGroup.h"
32 #include "WebGLRenderingContextBase.h"
33
34 namespace WebCore {
35
36 Ref<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContextBase& ctx)
37 {
38     return adoptRef(*new WebGLBuffer(ctx));
39 }
40
41 WebGLBuffer::WebGLBuffer(WebGLRenderingContextBase& ctx)
42     : WebGLSharedObject(ctx)
43 {
44     setObject(ctx.graphicsContext3D()->createBuffer());
45     clearCachedMaxIndices();
46 }
47
48 WebGLBuffer::~WebGLBuffer()
49 {
50     deleteObject(0);
51 }
52
53 void WebGLBuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
54 {
55     context3d->deleteBuffer(object);
56 }
57
58 bool WebGLBuffer::associateBufferDataImpl(const void* data, GC3Dsizeiptr byteLength)
59 {
60     if (byteLength < 0)
61         return false;
62
63     switch (m_target) {
64     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
65         if (byteLength > std::numeric_limits<unsigned>::max())
66             return false;
67         m_byteLength = byteLength;
68         clearCachedMaxIndices();
69         if (byteLength) {
70             m_elementArrayBuffer = ArrayBuffer::tryCreate(byteLength, 1);
71             if (!m_elementArrayBuffer) {
72                 m_byteLength = 0;
73                 return false;
74             }
75             if (data) {
76                 // We must always clone the incoming data because client-side
77                 // modifications without calling bufferData or bufferSubData
78                 // must never be able to change the validation results.
79                 memcpy(m_elementArrayBuffer->data(), data, byteLength);
80             }
81         } else
82             m_elementArrayBuffer = nullptr;
83         return true;
84     case GraphicsContext3D::ARRAY_BUFFER:
85         m_byteLength = byteLength;
86         return true;
87     default:
88 #if ENABLE(WEBGL2)
89         switch (m_target) {
90         case GraphicsContext3D::COPY_READ_BUFFER:
91         case GraphicsContext3D::COPY_WRITE_BUFFER:
92         case GraphicsContext3D::PIXEL_PACK_BUFFER:
93         case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
94         case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
95         case GraphicsContext3D::UNIFORM_BUFFER:
96             m_byteLength = byteLength;
97             return true;
98         }
99 #endif
100         return false;
101     }
102 }
103
104 bool WebGLBuffer::associateBufferData(GC3Dsizeiptr size)
105 {
106     return associateBufferDataImpl(nullptr, size);
107 }
108
109 bool WebGLBuffer::associateBufferData(ArrayBuffer* array)
110 {
111     if (!array)
112         return false;
113     return associateBufferDataImpl(array->data(), array->byteLength());
114 }
115
116 bool WebGLBuffer::associateBufferData(ArrayBufferView* array)
117 {
118     if (!array)
119         return false;
120     return associateBufferDataImpl(array->baseAddress(), array->byteLength());
121 }
122
123 bool WebGLBuffer::associateBufferSubDataImpl(GC3Dintptr offset, const void* data, GC3Dsizeiptr byteLength)
124 {
125     if (!data || offset < 0 || byteLength < 0)
126         return false;
127
128     if (byteLength) {
129         Checked<GC3Dintptr, RecordOverflow> checkedBufferOffset(offset);
130         Checked<GC3Dsizeiptr, RecordOverflow> checkedDataLength(byteLength);
131         Checked<GC3Dintptr, RecordOverflow> checkedBufferMax = checkedBufferOffset + checkedDataLength;
132         if (checkedBufferMax.hasOverflowed() || offset > m_byteLength || checkedBufferMax.unsafeGet() > 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, data, byteLength);
143         }
144         return true;
145     case GraphicsContext3D::ARRAY_BUFFER:
146         return true;
147     default:
148 #if ENABLE(WEBGL2)
149         switch (m_target) {
150         case GraphicsContext3D::COPY_READ_BUFFER:
151         case GraphicsContext3D::COPY_WRITE_BUFFER:
152         case GraphicsContext3D::PIXEL_PACK_BUFFER:
153         case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
154         case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
155         case GraphicsContext3D::UNIFORM_BUFFER:
156             return true;
157         }
158 #endif
159         return false;
160     }
161 }
162
163 bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBuffer* array)
164 {
165     if (!array)
166         return false;
167     return associateBufferSubDataImpl(offset, array->data(), array->byteLength());
168 }
169
170 bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBufferView* array)
171 {
172     if (!array)
173         return false;
174     return associateBufferSubDataImpl(offset, array->baseAddress(), array->byteLength());
175 }
176
177 bool WebGLBuffer::associateCopyBufferSubData(const WebGLBuffer& readBuffer, GC3Dintptr readOffset, GC3Dintptr writeOffset, GC3Dsizeiptr size)
178 {
179     if (readOffset < 0 || writeOffset < 0 || size < 0)
180         return false;
181
182     if (size) {
183         Checked<GC3Dintptr, RecordOverflow> checkedReadBufferOffset(readOffset);
184         Checked<GC3Dsizeiptr, RecordOverflow> checkedDataLength(size);
185         Checked<GC3Dintptr, RecordOverflow> checkedReadBufferMax = checkedReadBufferOffset + checkedDataLength;
186         if (checkedReadBufferMax.hasOverflowed() || readOffset > readBuffer.byteLength() || checkedReadBufferMax.unsafeGet() > readBuffer.byteLength())
187             return false;
188
189         Checked<GC3Dintptr, RecordOverflow> checkedWriteBufferOffset(writeOffset);
190         Checked<GC3Dintptr, RecordOverflow> checkedWriteBufferMax = checkedWriteBufferOffset + checkedDataLength;
191         if (checkedWriteBufferMax.hasOverflowed() || writeOffset > m_byteLength || checkedWriteBufferMax.unsafeGet() > m_byteLength)
192             return false;
193     }
194
195     switch (m_target) {
196     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
197         clearCachedMaxIndices();
198         if (size) {
199             if (!m_elementArrayBuffer)
200                 return false;
201             memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + writeOffset, static_cast<const unsigned char*>(readBuffer.elementArrayBuffer()->data()) + readOffset, size);
202         }
203         return true;
204     case GraphicsContext3D::ARRAY_BUFFER:
205         return true;
206     default:
207 #if ENABLE(WEBGL2)
208         switch (m_target) {
209         case GraphicsContext3D::COPY_READ_BUFFER:
210         case GraphicsContext3D::COPY_WRITE_BUFFER:
211         case GraphicsContext3D::PIXEL_PACK_BUFFER:
212         case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
213         case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
214         case GraphicsContext3D::UNIFORM_BUFFER:
215             return true;
216         }
217 #endif
218         return false;
219     }
220 }
221
222 void WebGLBuffer::disassociateBufferData()
223 {
224     m_byteLength = 0;
225     clearCachedMaxIndices();
226 }
227
228 GC3Dsizeiptr WebGLBuffer::byteLength() const
229 {
230     return m_byteLength;
231 }
232
233 Optional<unsigned> WebGLBuffer::getCachedMaxIndex(GC3Denum type)
234 {
235     for (auto& cache : m_maxIndexCache) {
236         if (cache.type == type)
237             return cache.maxIndex;
238     }
239     return WTF::nullopt;
240 }
241
242 void WebGLBuffer::setCachedMaxIndex(GC3Denum type, unsigned value)
243 {
244     for (auto& cache : m_maxIndexCache) {
245         if (cache.type == type) {
246             cache.maxIndex = value;
247             return;
248         }
249     }
250     m_maxIndexCache[m_nextAvailableCacheEntry].type = type;
251     m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value;
252     m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % WTF_ARRAY_LENGTH(m_maxIndexCache);
253 }
254
255 void WebGLBuffer::setTarget(GC3Denum target, bool forWebGL2)
256 {
257     // In WebGL, a buffer is bound to one target in its lifetime
258     if (m_target)
259         return;
260     if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
261         m_target = target;
262     else if (forWebGL2) {
263 #if ENABLE(WEBGL2)
264         switch (target) {
265         case GraphicsContext3D::COPY_READ_BUFFER:
266         case GraphicsContext3D::COPY_WRITE_BUFFER:
267         case GraphicsContext3D::PIXEL_PACK_BUFFER:
268         case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
269         case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
270         case GraphicsContext3D::UNIFORM_BUFFER:
271             m_target = target;
272         }
273 #endif
274     }
275 }
276
277 void WebGLBuffer::clearCachedMaxIndices()
278 {
279     memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
280 }
281
282 }
283
284 #endif // ENABLE(WEBGL)