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 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 28#if ENABLE(WEBGL) 29 30#include "WebGLBuffer.h" 31 32#include "WebGLContextGroup.h" 33#include "WebGLRenderingContext.h" 34 35namespace WebCore { 36 37PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx) 38{ 39 return adoptRef(new WebGLBuffer(ctx)); 40} 41 42WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx) 43 : WebGLSharedObject(ctx) 44 , m_target(0) 45 , m_byteLength(0) 46 , m_nextAvailableCacheEntry(0) 47{ 48 setObject(ctx->graphicsContext3D()->createBuffer()); 49 clearCachedMaxIndices(); 50} 51 52WebGLBuffer::~WebGLBuffer() 53{ 54 deleteObject(0); 55} 56 57void WebGLBuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object) 58{ 59 context3d->deleteBuffer(object); 60} 61 62bool WebGLBuffer::associateBufferDataImpl(const void* data, GC3Dsizeiptr byteLength) 63{ 64 if (byteLength < 0) 65 return false; 66 67 switch (m_target) { 68 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER: 69 m_byteLength = byteLength; 70 clearCachedMaxIndices(); 71 if (byteLength) { 72 m_elementArrayBuffer = ArrayBuffer::create(byteLength, 1); 73 if (!m_elementArrayBuffer) { 74 m_byteLength = 0; 75 return false; 76 } 77 if (data) { 78 // We must always clone the incoming data because client-side 79 // modifications without calling bufferData or bufferSubData 80 // must never be able to change the validation results. 81 memcpy(m_elementArrayBuffer->data(), data, byteLength); 82 } 83 } else 84 m_elementArrayBuffer = nullptr; 85 return true; 86 case GraphicsContext3D::ARRAY_BUFFER: 87 m_byteLength = byteLength; 88 return true; 89 default: 90 return false; 91 } 92} 93 94bool WebGLBuffer::associateBufferData(GC3Dsizeiptr size) 95{ 96 return associateBufferDataImpl(0, size); 97} 98 99bool WebGLBuffer::associateBufferData(ArrayBuffer* array) 100{ 101 if (!array) 102 return false; 103 return associateBufferDataImpl(array->data(), array->byteLength()); 104} 105 106bool WebGLBuffer::associateBufferData(ArrayBufferView* array) 107{ 108 if (!array) 109 return false; 110 return associateBufferDataImpl(array->baseAddress(), array->byteLength()); 111} 112 113bool WebGLBuffer::associateBufferSubDataImpl(GC3Dintptr offset, const void* data, GC3Dsizeiptr byteLength) 114{ 115 if (!data || offset < 0 || byteLength < 0) 116 return false; 117 118 if (byteLength) { 119 Checked<GC3Dintptr, RecordOverflow> checkedBufferOffset(offset); 120 Checked<GC3Dsizeiptr, RecordOverflow> checkedDataLength(byteLength); 121 Checked<GC3Dintptr, RecordOverflow> checkedBufferMax = checkedBufferOffset + checkedDataLength; 122 if (checkedBufferMax.hasOverflowed() || offset > m_byteLength || checkedBufferMax.unsafeGet() > m_byteLength) 123 return false; 124 } 125 126 switch (m_target) { 127 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER: 128 clearCachedMaxIndices(); 129 if (byteLength) { 130 if (!m_elementArrayBuffer) 131 return false; 132 memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + offset, data, byteLength); 133 } 134 return true; 135 case GraphicsContext3D::ARRAY_BUFFER: 136 return true; 137 default: 138 return false; 139 } 140} 141 142bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBuffer* array) 143{ 144 if (!array) 145 return false; 146 return associateBufferSubDataImpl(offset, array->data(), array->byteLength()); 147} 148 149bool WebGLBuffer::associateBufferSubData(GC3Dintptr offset, ArrayBufferView* array) 150{ 151 if (!array) 152 return false; 153 return associateBufferSubDataImpl(offset, array->baseAddress(), array->byteLength()); 154} 155 156void WebGLBuffer::disassociateBufferData() 157{ 158 m_byteLength = 0; 159 clearCachedMaxIndices(); 160} 161 162GC3Dsizeiptr WebGLBuffer::byteLength() const 163{ 164 return m_byteLength; 165} 166 167int WebGLBuffer::getCachedMaxIndex(GC3Denum type) 168{ 169 for (size_t i = 0; i < WTF_ARRAY_LENGTH(m_maxIndexCache); ++i) 170 if (m_maxIndexCache[i].type == type) 171 return m_maxIndexCache[i].maxIndex; 172 return -1; 173} 174 175void WebGLBuffer::setCachedMaxIndex(GC3Denum type, int value) 176{ 177 size_t numEntries = WTF_ARRAY_LENGTH(m_maxIndexCache); 178 for (size_t i = 0; i < numEntries; ++i) 179 if (m_maxIndexCache[i].type == type) { 180 m_maxIndexCache[i].maxIndex = value; 181 return; 182 } 183 m_maxIndexCache[m_nextAvailableCacheEntry].type = type; 184 m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value; 185 m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries; 186} 187 188void WebGLBuffer::setTarget(GC3Denum target) 189{ 190 // In WebGL, a buffer is bound to one target in its lifetime 191 if (m_target) 192 return; 193 if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) 194 m_target = target; 195} 196 197void WebGLBuffer::clearCachedMaxIndices() 198{ 199 memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache)); 200} 201 202} 203 204#endif // ENABLE(WEBGL) 205