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 "WebGLProgram.h"
31
32#include "WebGLContextGroup.h"
33#include "WebGLRenderingContext.h"
34
35namespace WebCore {
36
37PassRefPtr<WebGLProgram> WebGLProgram::create(WebGLRenderingContext* ctx)
38{
39    return adoptRef(new WebGLProgram(ctx));
40}
41
42WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx)
43    : WebGLSharedObject(ctx)
44    , m_linkStatus(false)
45    , m_linkCount(0)
46    , m_infoValid(true)
47{
48    setObject(ctx->graphicsContext3D()->createProgram());
49}
50
51WebGLProgram::~WebGLProgram()
52{
53    deleteObject(0);
54}
55
56void WebGLProgram::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject obj)
57{
58    context3d->deleteProgram(obj);
59    if (m_vertexShader) {
60        m_vertexShader->onDetached(context3d);
61        m_vertexShader = 0;
62    }
63    if (m_fragmentShader) {
64        m_fragmentShader->onDetached(context3d);
65        m_fragmentShader = 0;
66    }
67}
68
69unsigned WebGLProgram::numActiveAttribLocations()
70{
71    cacheInfoIfNeeded();
72    return m_activeAttribLocations.size();
73}
74
75GC3Dint WebGLProgram::getActiveAttribLocation(GC3Duint index)
76{
77    cacheInfoIfNeeded();
78    if (index >= numActiveAttribLocations())
79        return -1;
80    return m_activeAttribLocations[index];
81}
82
83bool WebGLProgram::isUsingVertexAttrib0()
84{
85    cacheInfoIfNeeded();
86    for (unsigned ii = 0; ii < numActiveAttribLocations(); ++ii) {
87        if (!getActiveAttribLocation(ii))
88            return true;
89    }
90    return false;
91}
92
93bool WebGLProgram::getLinkStatus()
94{
95    cacheInfoIfNeeded();
96    return m_linkStatus;
97}
98
99void WebGLProgram::setLinkStatus(bool status)
100{
101    cacheInfoIfNeeded();
102    m_linkStatus = status;
103}
104
105void WebGLProgram::increaseLinkCount()
106{
107    ++m_linkCount;
108    m_infoValid = false;
109}
110
111WebGLShader* WebGLProgram::getAttachedShader(GC3Denum type)
112{
113    switch (type) {
114    case GraphicsContext3D::VERTEX_SHADER:
115        return m_vertexShader.get();
116    case GraphicsContext3D::FRAGMENT_SHADER:
117        return m_fragmentShader.get();
118    default:
119        return 0;
120    }
121}
122
123bool WebGLProgram::attachShader(WebGLShader* shader)
124{
125    if (!shader || !shader->object())
126        return false;
127    switch (shader->getType()) {
128    case GraphicsContext3D::VERTEX_SHADER:
129        if (m_vertexShader)
130            return false;
131        m_vertexShader = shader;
132        return true;
133    case GraphicsContext3D::FRAGMENT_SHADER:
134        if (m_fragmentShader)
135            return false;
136        m_fragmentShader = shader;
137        return true;
138    default:
139        return false;
140    }
141}
142
143bool WebGLProgram::detachShader(WebGLShader* shader)
144{
145    if (!shader || !shader->object())
146        return false;
147    switch (shader->getType()) {
148    case GraphicsContext3D::VERTEX_SHADER:
149        if (m_vertexShader != shader)
150            return false;
151        m_vertexShader = 0;
152        return true;
153    case GraphicsContext3D::FRAGMENT_SHADER:
154        if (m_fragmentShader != shader)
155            return false;
156        m_fragmentShader = 0;
157        return true;
158    default:
159        return false;
160    }
161}
162
163void WebGLProgram::cacheActiveAttribLocations(GraphicsContext3D* context3d)
164{
165    m_activeAttribLocations.clear();
166
167    GC3Dint numAttribs = 0;
168    context3d->getProgramiv(object(), GraphicsContext3D::ACTIVE_ATTRIBUTES, &numAttribs);
169    m_activeAttribLocations.resize(static_cast<size_t>(numAttribs));
170    for (int i = 0; i < numAttribs; ++i) {
171        ActiveInfo info;
172        context3d->getActiveAttrib(object(), i, info);
173        m_activeAttribLocations[i] = context3d->getAttribLocation(object(), info.name.charactersWithNullTermination());
174    }
175}
176
177void WebGLProgram::cacheInfoIfNeeded()
178{
179    if (m_infoValid)
180        return;
181
182    if (!object())
183        return;
184
185    GraphicsContext3D* context = getAGraphicsContext3D();
186    if (!context)
187        return;
188    GC3Dint linkStatus = 0;
189    context->getProgramiv(object(), GraphicsContext3D::LINK_STATUS, &linkStatus);
190    m_linkStatus = linkStatus;
191    if (m_linkStatus)
192        cacheActiveAttribLocations(context);
193    m_infoValid = true;
194}
195
196}
197
198#endif // ENABLE(WEBGL)
199