Home | History | Annotate | Download | only in canvas
      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(3D_CANVAS)
     29 
     30 #include "WebGLBuffer.h"
     31 #include "WebGLRenderingContext.h"
     32 
     33 namespace WebCore {
     34 
     35 PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx)
     36 {
     37     return adoptRef(new WebGLBuffer(ctx));
     38 }
     39 
     40 PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx, Platform3DObject obj)
     41 {
     42     return adoptRef(new WebGLBuffer(ctx, obj));
     43 }
     44 
     45 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
     46     : CanvasObject(ctx)
     47     , m_elementArrayBufferByteLength(0)
     48     , m_arrayBufferByteLength(0)
     49     , m_nextAvailableCacheEntry(0)
     50 {
     51     setObject(context()->graphicsContext3D()->createBuffer());
     52     clearCachedMaxIndices();
     53 }
     54 
     55 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx, Platform3DObject obj)
     56     : CanvasObject(ctx)
     57     , m_nextAvailableCacheEntry(0)
     58 {
     59     setObject(obj, false);
     60     clearCachedMaxIndices();
     61 }
     62 
     63 void WebGLBuffer::_deleteObject(Platform3DObject object)
     64 {
     65     context()->graphicsContext3D()->deleteBuffer(object);
     66 }
     67 
     68 bool WebGLBuffer::associateBufferData(unsigned long target, int size)
     69 {
     70     if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
     71         m_elementArrayBufferByteLength = size;
     72         return true;
     73     }
     74 
     75     if (target == GraphicsContext3D::ARRAY_BUFFER) {
     76         m_arrayBufferByteLength = size;
     77         return true;
     78     }
     79 
     80     return false;
     81 }
     82 
     83 bool WebGLBuffer::associateBufferData(unsigned long target, WebGLArray* array)
     84 {
     85     if (!array)
     86         return false;
     87 
     88     if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
     89         clearCachedMaxIndices();
     90         m_elementArrayBufferByteLength = array->byteLength();
     91         // We must always clone the incoming data because client-side
     92         // modifications without calling bufferData or bufferSubData
     93         // must never be able to change the validation results.
     94         m_elementArrayBuffer = WebGLArrayBuffer::create(array->buffer().get());
     95         return true;
     96     }
     97 
     98     if (target == GraphicsContext3D::ARRAY_BUFFER) {
     99         m_arrayBufferByteLength = array->byteLength();
    100         return true;
    101     }
    102 
    103     return false;
    104 }
    105 
    106 bool WebGLBuffer::associateBufferSubData(unsigned long target, long offset, WebGLArray* array)
    107 {
    108     if (!array)
    109         return false;
    110 
    111     if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
    112         clearCachedMaxIndices();
    113 
    114         // We need to protect against integer overflow with these tests
    115         if (offset < 0)
    116             return false;
    117 
    118         unsigned long uoffset = static_cast<unsigned long>(offset);
    119         if (uoffset > m_elementArrayBufferByteLength || array->byteLength() > m_elementArrayBufferByteLength - uoffset)
    120             return false;
    121 
    122         memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + offset, array->baseAddress(), array->byteLength());
    123         return true;
    124     }
    125 
    126     if (target == GraphicsContext3D::ARRAY_BUFFER)
    127         return array->byteLength() + offset <= m_arrayBufferByteLength;
    128 
    129     return false;
    130 }
    131 
    132 unsigned WebGLBuffer::byteLength(unsigned long target) const
    133 {
    134     return (target == GraphicsContext3D::ARRAY_BUFFER) ? m_arrayBufferByteLength : m_elementArrayBufferByteLength;
    135 }
    136 
    137 long WebGLBuffer::getCachedMaxIndex(unsigned long type)
    138 {
    139     size_t numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry);
    140     for (size_t i = 0; i < numEntries; i++)
    141         if (m_maxIndexCache[i].type == type)
    142             return m_maxIndexCache[i].maxIndex;
    143     return -1;
    144 }
    145 
    146 void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value)
    147 {
    148     int numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry);
    149     for (int i = 0; i < numEntries; i++)
    150         if (m_maxIndexCache[i].type == type) {
    151             m_maxIndexCache[i].maxIndex = value;
    152             return;
    153         }
    154     m_maxIndexCache[m_nextAvailableCacheEntry].type = type;
    155     m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value;
    156     m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries;
    157 }
    158 
    159 void WebGLBuffer::clearCachedMaxIndices()
    160 {
    161     memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
    162 }
    163 
    164 }
    165 
    166 #endif // ENABLE(3D_CANVAS)
    167