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