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