1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "context/webgl_rendering_context_base_impl.h"
16 
17 #include "context/webgl2_rendering_context_base.h"
18 #include "context/webgl_rendering_context_base.h"
19 #include "napi/n_class.h"
20 #include "util/log.h"
21 #include "util/util.h"
22 
23 namespace OHOS {
24 namespace Rosen {
25 namespace Impl {
26 using namespace std;
~WebGLRenderingContextBaseImpl()27 WebGLRenderingContextBaseImpl::~WebGLRenderingContextBaseImpl() {}
28 
Init()29 void WebGLRenderingContextBaseImpl::Init()
30 {
31     if (maxTextureImageUnits_ != 0) {
32         return;
33     }
34 
35     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits_);
36     boundTexture_[BoundTextureType::TEXTURE_3D].resize(maxTextureImageUnits_);
37     boundTexture_[BoundTextureType::TEXTURE_2D_ARRAY].resize(maxTextureImageUnits_);
38 
39     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_);
40     boundTexture_[BoundTextureType::TEXTURE_2D].resize(maxTextureSize_);
41 
42     glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeMapTextureSize_);
43     boundTexture_[BoundTextureType::TEXTURE_CUBE_MAP].resize(maxCubeMapTextureSize_);
44 
45     glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderBufferSize_);
46 
47     unpackColorspaceConversion_ = WebGLRenderingContextBase::BROWSER_DEFAULT_WEBGL;
48 
49     GLint max = 0;
50     glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max);
51     maxVertexAttribs_ = static_cast<GLuint>(max);
52     arrayVertexAttribs_.resize(maxVertexAttribs_);
53 
54     stencilMask_[0] = 0xffffffff; // 0xffffffff: stencilMask_ max value
55     stencilMask_[1] = 0xffffffff; // 0xffffffff: stencilMask_ max value
56     stencilFuncMask_[0] = 0xffffffff; // 0xffffffff: stencilFuncMask_ max value
57     stencilFuncMask_[1] = 0xffffffff; // 0xffffffff: stencilFuncMask_ max value
58     stencilFuncRef_[0] = 0;
59     stencilFuncRef_[1] = 0;
60 
61     clearColor_[0] = 0; // 0: r
62     clearColor_[1] = 0; // 1: g
63     clearColor_[2] = 0; // 2: b
64     clearColor_[3] = 0; // 3: a
65 
66     colorMask_[0] = false; // 0: r
67     colorMask_[1] = false; // 1: g
68     colorMask_[2] = false; // 2: b
69     colorMask_[3] = false; // 3: a
70 
71     LOGD("WebGL Init maxTextureImageUnits %{public}d, maxTextureSize %{public}d, maxCubeMapTextureSize %{public}d, "
72         "maxRenderBufferSize %{public}d, maxVertexAttribs %{public}d", maxTextureImageUnits_,
73         maxTextureSize_, maxCubeMapTextureSize_, maxRenderBufferSize_, maxVertexAttribs_);
74 }
75 
GetContextAttributes(napi_env env)76 napi_value WebGLRenderingContextBaseImpl::GetContextAttributes(napi_env env)
77 {
78     auto webGlContextAttributes = webGLRenderingContext_->CreateWebGlContextAttributes();
79     if (webGlContextAttributes == nullptr) {
80         return NVal::CreateNull(env).val_;
81     }
82     NVal res = NVal::CreateObject(env);
83     napi_value alpha = NVal::CreateBool(env, webGlContextAttributes->alpha_).val_;
84     napi_value antialias = NVal::CreateBool(env, webGlContextAttributes->antialias_).val_;
85     napi_value depth = NVal::CreateBool(env, webGlContextAttributes->depth_).val_;
86     napi_value failIfMajorPerformanceCaveat =
87         NVal::CreateBool(env, webGlContextAttributes->failIfMajorPerformanceCaveat_).val_;
88     napi_value desynchronized = NVal::CreateBool(env, webGlContextAttributes->desynchronized_).val_;
89     napi_value premultipliedAlpha = NVal::CreateBool(env, webGlContextAttributes->premultipliedAlpha_).val_;
90     napi_value preserveDrawingBuffer = NVal::CreateBool(env, webGlContextAttributes->preserveDrawingBuffer_).val_;
91     napi_value stencil = NVal::CreateBool(env, webGlContextAttributes->stencil_).val_;
92     napi_value powerPreference = NVal::CreateUTF8String(env, webGlContextAttributes->powerPreference_).val_;
93     res.AddProp("alpha", alpha);
94     res.AddProp("antialias", antialias);
95     res.AddProp("depth", depth);
96     res.AddProp("failIfMajorPerformanceCaveat", failIfMajorPerformanceCaveat);
97     res.AddProp("desynchronized", desynchronized);
98     res.AddProp("premultipliedAlpha", premultipliedAlpha);
99     res.AddProp("preserveDrawingBuffer", preserveDrawingBuffer);
100     res.AddProp("stencil", stencil);
101     res.AddProp("powerPreference", powerPreference);
102     return res.val_;
103 }
104 
CreateTextureObject(napi_env env)105 napi_value WebGLRenderingContextBaseImpl::CreateTextureObject(napi_env env)
106 {
107     WebGLTexture* webGlTexture = nullptr;
108     napi_value objTexture = WebGLTexture::CreateObjectInstance(env, &webGlTexture).val_;
109     if (!webGlTexture) {
110         return NVal::CreateNull(env).val_;
111     }
112     GLuint textureId = 0;
113     glGenTextures(1, &textureId);
114     webGlTexture->SetTexture(textureId);
115     LOGD("WebGL createTexture textureId %{public}u", textureId);
116     AddObject<WebGLTexture>(env, textureId, objTexture);
117     return objTexture;
118 }
119 
ActiveTexture(napi_env env,GLenum texture)120 napi_value WebGLRenderingContextBaseImpl::ActiveTexture(napi_env env, GLenum texture)
121 {
122     if (texture < GL_TEXTURE0 || static_cast<GLint>(texture - GL_TEXTURE0) >= maxTextureImageUnits_) {
123         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
124             "WebGL activeTexture texture unit out of range %{public}u", texture);
125         return NVal::CreateNull(env).val_;
126     }
127     activeTextureIndex_ = texture - GL_TEXTURE0;
128     glActiveTexture(texture);
129     return NVal::CreateNull(env).val_;
130 }
131 
BindTexture(napi_env env,GLenum target,napi_value textureRef)132 napi_value WebGLRenderingContextBaseImpl::BindTexture(napi_env env, GLenum target, napi_value textureRef)
133 {
134     uint32_t texture = WebGLTexture::DEFAULT_TEXTURE;
135     WebGLTexture* webGlTexture = WebGLTexture::GetObjectInstance(env, textureRef);
136     if (webGlTexture != nullptr) {
137         texture = webGlTexture->GetTexture();
138         if (webGlTexture->GetTarget() && webGlTexture->GetTarget() != target) {
139             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
140                 "WebGL bindTexture textureId %{public}u has been bound", texture);
141             return NVal::CreateNull(env).val_;
142         }
143     }
144 
145     uint32_t index = 0;
146     if (!WebGLRenderingContextBaseImpl::CheckTextureTarget(env, target, index)) {
147         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
148         return NVal::CreateNull(env).val_;
149     }
150     if (activeTextureIndex_ >= boundTexture_[index].size()) {
151         SET_ERROR(WebGLRenderingContextBase::INVALID_OPERATION);
152         return NVal::CreateNull(env).val_;
153     }
154     if (boundTexture_[index][activeTextureIndex_] && boundTexture_[index][activeTextureIndex_] !=
155         static_cast<uint32_t>(texture)) {
156         LOGD("WebGL bindTexture has been bound to textureId %{public}u", boundTexture_[index][activeTextureIndex_]);
157     }
158     boundTexture_[index][activeTextureIndex_] = texture;
159 
160     glBindTexture(target, texture);
161     if (webGlTexture) {
162         webGlTexture->SetTarget(target);
163     }
164     LOGD("WebGL bindTexture target %{public}u textureId %{public}u activeTextureIndex %{public}u result %{public}u ",
165         target, texture, activeTextureIndex_, GetError_());
166     return NVal::CreateNull(env).val_;
167 }
168 
IsBuffer(napi_env env,napi_value object)169 napi_value WebGLRenderingContextBaseImpl::IsBuffer(napi_env env, napi_value object)
170 {
171     WebGLBuffer* webGlBuffer = GetValidBuffer(env, object);
172     if (webGlBuffer == nullptr) {
173         return NVal::CreateBool(env, false).val_;
174     }
175     uint32_t buffer = webGlBuffer->GetBufferId();
176     bool result = static_cast<bool>(glIsBuffer(static_cast<GLuint>(buffer)));
177     LOGD("WebGL isBuffer %{public}u res %{public}d", buffer, result);
178     return NVal::CreateBool(env, result).val_;
179 }
180 
BindBuffer(napi_env env,GLenum target,napi_value object)181 napi_value WebGLRenderingContextBaseImpl::BindBuffer(napi_env env, GLenum target, napi_value object)
182 {
183     // support default value
184     uint32_t bufferId = WebGLBuffer::DEFAULT_BUFFER;
185     WebGLBuffer* webGlBuffer = GetValidBuffer(env, object);
186     if (webGlBuffer != nullptr) {
187         bufferId = webGlBuffer->GetBufferId();
188     }
189     LOGD("WebGL bindBuffer target %{public}u bufferId %{public}u", target, bufferId);
190     uint32_t index = BoundBufferType::ARRAY_BUFFER;
191     if (!CheckBufferTarget(env, target, index)) {
192         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
193         return NVal::CreateNull(env).val_;
194     }
195     if (webGlBuffer && webGlBuffer->GetTarget() && webGlBuffer->GetTarget() != target) {
196         SET_ERROR(WebGLRenderingContextBase::INVALID_OPERATION);
197         return NVal::CreateNull(env).val_;
198     }
199     if (boundBufferIds_[index] && boundBufferIds_[index] != bufferId) {
200         LOGD("WebGL bindBuffer has been bound bufferId %{public}u", boundBufferIds_[index]);
201     }
202     boundBufferIds_[index] = bufferId;
203 
204     glBindBuffer(target, static_cast<GLuint>(bufferId));
205     if (webGlBuffer) {
206         webGlBuffer->SetTarget(target);
207     }
208     LOGD("WebGL bindBuffer bufferId %{public}u result %{public}u", bufferId, GetError_());
209     return NVal::CreateNull(env).val_;
210 }
211 
IsFrameBuffer(napi_env env,napi_value object)212 napi_value WebGLRenderingContextBaseImpl::IsFrameBuffer(napi_env env, napi_value object)
213 {
214     GLuint frameBufferId = WebGLFramebuffer::DEFAULT_FRAME_BUFFER;
215     WebGLFramebuffer* webGlFramebuffer = GetValidFrameBuffer(env, object);
216     if (webGlFramebuffer == nullptr) {
217         return NVal::CreateBool(env, false).val_;
218     }
219     frameBufferId = webGlFramebuffer->GetFramebuffer();
220     bool res = static_cast<bool>(glIsFramebuffer(frameBufferId));
221     LOGD("WebGL isFramebuffer framebuffer %{public}u result %{public}d", frameBufferId, res);
222     return NVal::CreateBool(env, res).val_;
223 }
224 
BindFrameBuffer(napi_env env,GLenum target,napi_value object)225 napi_value WebGLRenderingContextBaseImpl::BindFrameBuffer(napi_env env, GLenum target, napi_value object)
226 {
227     uint32_t index = 0;
228     if (!CheckFrameBufferTarget(env, target, index)) {
229         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "BindFrameBuffer Invalid target");
230         return NVal::CreateNull(env).val_;
231     }
232 
233     GLuint frameBufferId = WebGLFramebuffer::DEFAULT_FRAME_BUFFER;
234     WebGLFramebuffer* webGlFramebuffer = GetValidFrameBuffer(env, object);
235     if (webGlFramebuffer == nullptr) {
236         glBindFramebuffer(target, 0);
237         return NVal::CreateNull(env).val_;
238     }
239 
240     frameBufferId = webGlFramebuffer->GetFramebuffer();
241     if (boundFrameBufferIds_[index] && boundFrameBufferIds_[index] != frameBufferId) {
242         LOGD("WebGL bindFramebuffer has been bound %{public}u", boundFrameBufferIds_[index]);
243     }
244     glBindFramebuffer(target, frameBufferId);
245     boundFrameBufferIds_[index] = frameBufferId;
246     if (IsHighWebGL()) {
247         if (target == GL_FRAMEBUFFER || target == GL_READ_FRAMEBUFFER) {
248             boundFrameBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER] = frameBufferId;
249         }
250     }
251     if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) {
252         boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER] = frameBufferId;
253     }
254 
255     if (webGlFramebuffer) {
256         webGlFramebuffer->SetTarget(target);
257     }
258     LOGD("WebGL bindFramebuffer target %{public}u frameBufferId %{public}u result %{public}u",
259         target, frameBufferId, GetError_());
260     return NVal::CreateNull(env).val_;
261 }
262 
BindRenderBuffer(napi_env env,GLenum target,napi_value object)263 napi_value WebGLRenderingContextBaseImpl::BindRenderBuffer(napi_env env, GLenum target, napi_value object)
264 {
265     uint32_t index = 0;
266     if (!CheckRenderBufferTarget(env, target, index)) {
267         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "BindRenderBuffer Invalid target");
268         return NVal::CreateNull(env).val_;
269     }
270 
271     GLuint renderBufferId = WebGLRenderbuffer::DEFAULT_RENDER_BUFFER;
272     WebGLRenderbuffer* renderBuffer = GetValidRenderBuffer(env, object);
273     if (renderBuffer != nullptr) {
274         renderBufferId = renderBuffer->GetRenderbuffer();
275     }
276 
277     glBindRenderbuffer(target, renderBufferId);
278 
279     // record render buffer
280     if (boundRenderBufferIds_[index] && boundRenderBufferIds_[index] != renderBufferId) {
281         LOGD("WebGL bindRenderbuffer has been bound %{public}u", boundRenderBufferIds_[index]);
282     }
283     boundRenderBufferIds_[index] = renderBufferId;
284 
285     if (renderBuffer) {
286         renderBuffer->SetTarget(target);
287     }
288     LOGD("WebGL bindRenderbuffer target %{public}u %{public}u", target, GetError_());
289     return NVal::CreateNull(env).val_;
290 }
291 
CreateBuffer(napi_env env)292 napi_value WebGLRenderingContextBaseImpl::CreateBuffer(napi_env env)
293 {
294     WebGLBuffer* webGlBuffer = nullptr;
295     napi_value objBuffer = WebGLBuffer::CreateObjectInstance(env, &webGlBuffer).val_;
296     if (webGlBuffer == nullptr) {
297         return NVal::CreateNull(env).val_;
298     }
299     uint32_t bufferId = 0;
300     glGenBuffers(1, &bufferId);
301     webGlBuffer->SetBufferId(bufferId);
302     bool ret = AddObject<WebGLBuffer>(env, bufferId, objBuffer);
303     LOGD("WebGL createBuffer bufferId %{public}u %{public}d", bufferId, ret);
304     return objBuffer;
305 }
306 
CreateFrameBuffer(napi_env env)307 napi_value WebGLRenderingContextBaseImpl::CreateFrameBuffer(napi_env env)
308 {
309     WebGLFramebuffer* webGlFramebuffer = nullptr;
310     napi_value objFramebuffer = WebGLFramebuffer::CreateObjectInstance(env, &webGlFramebuffer).val_;
311     if (!webGlFramebuffer) {
312         return NVal::CreateNull(env).val_;
313     }
314     uint32_t framebufferId = 0;
315     glGenFramebuffers(1, &framebufferId);
316     webGlFramebuffer->SetFramebuffer(framebufferId);
317     (void)AddObject<WebGLFramebuffer>(env, framebufferId, objFramebuffer);
318     LOGD("WebGL createFramebuffer framebufferId %{public}u", framebufferId);
319     return objFramebuffer;
320 }
321 
CreateProgram(napi_env env)322 napi_value WebGLRenderingContextBaseImpl::CreateProgram(napi_env env)
323 {
324     WebGLProgram* webGlProgram = nullptr;
325     napi_value objProgram = WebGLProgram::CreateObjectInstance(env, &webGlProgram).val_;
326     if (webGlProgram == nullptr) {
327         return NVal::CreateNull(env).val_;
328     }
329     GLuint programId = glCreateProgram();
330     if (programId == 0) {
331         LOGE("WebGL createProgram fail programId %{public}u", programId);
332         return NVal::CreateNull(env).val_;
333     }
334     webGlProgram->SetProgramId(programId);
335 
336     (void)AddObject<WebGLProgram>(env, programId, objProgram);
337     LOGD("WebGL createProgram programId %{public}u result %{public}u", programId, GetError_());
338     return objProgram;
339 }
340 
CreateRenderBuffer(napi_env env)341 napi_value WebGLRenderingContextBaseImpl::CreateRenderBuffer(napi_env env)
342 {
343     WebGLRenderbuffer* webGlRenderbuffer = nullptr;
344     napi_value objRenderbuffer = WebGLRenderbuffer::CreateObjectInstance(env, &webGlRenderbuffer).val_;
345     if (!webGlRenderbuffer) {
346         return NVal::CreateNull(env).val_;
347     }
348     GLuint renderbufferId = 0;
349     glGenRenderbuffers(1, &renderbufferId);
350     webGlRenderbuffer->SetRenderbuffer(renderbufferId);
351     (void)AddObject<WebGLRenderbuffer>(env, renderbufferId, objRenderbuffer);
352     LOGD("WebGL createRenderbuffer renderbufferId %{public}u result %{public}p", renderbufferId, objRenderbuffer);
353     return objRenderbuffer;
354 }
355 
CreateShader(napi_env env,GLenum type)356 napi_value WebGLRenderingContextBaseImpl::CreateShader(napi_env env, GLenum type)
357 {
358     if (type != WebGLRenderingContextBase::VERTEX_SHADER && type != WebGLRenderingContextBase::FRAGMENT_SHADER) {
359         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "createShader Invalid type");
360         return NVal::CreateNull(env).val_;
361     }
362     WebGLShader* webGlShader = nullptr;
363     napi_value objShader = WebGLShader::CreateObjectInstance(env, &webGlShader).val_;
364     if (!webGlShader) {
365         return NVal::CreateNull(env).val_;
366     }
367     GLuint shaderId = glCreateShader(type);
368     webGlShader->SetShaderId(shaderId);
369     LOGD("WebGL createShader shaderId = %{public}u type %{public}u", shaderId, type);
370     if (shaderId == 0) {
371         LOGE("WebGL create shader failed. type %{public}x", type);
372         return NVal::CreateNull(env).val_;
373     }
374     (void)AddObject<WebGLShader>(env, shaderId, objShader);
375     webGlShader->SetShaderType(type);
376     return objShader;
377 }
378 
AttachShader(napi_env env,napi_value programObj,napi_value shaderObj)379 napi_value WebGLRenderingContextBaseImpl::AttachShader(napi_env env, napi_value programObj, napi_value shaderObj)
380 {
381     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, programObj);
382     if (webGLProgram == nullptr) {
383         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL attach shader invalid program");
384         return NVal::CreateNull(env).val_;
385     }
386     WebGLShader* webGlShader = WebGLShader::GetObjectInstance(env, shaderObj);
387     if (webGlShader == nullptr) {
388         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL attach shader invalid shader");
389         return NVal::CreateNull(env).val_;
390     }
391     uint32_t shaderId = webGlShader->GetShaderId();
392     uint32_t programId = webGLProgram->GetProgramId();
393     LOGD("WebGL attach shader programId %{public}u, shaderId %{public}u", programId, shaderId);
394     uint32_t index = 0;
395     if (!CheckShaderType(env, webGlShader->GetShaderType(), index) || !webGLProgram->AttachShader(index, shaderId)) {
396         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "WebGL attach shader invalid shader");
397         return NVal::CreateNull(env).val_;
398     }
399     glAttachShader(static_cast<GLuint>(programId), static_cast<GLuint>(shaderId));
400     return NVal::CreateNull(env).val_;
401 }
402 
DetachShader(napi_env env,napi_value programObj,napi_value shaderObj)403 napi_value WebGLRenderingContextBaseImpl::DetachShader(napi_env env, napi_value programObj, napi_value shaderObj)
404 {
405     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, programObj);
406     if (webGLProgram == nullptr) {
407         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "webGLProgram is nullptr.");
408         return NVal::CreateNull(env).val_;
409     }
410     WebGLShader* webGlShader = WebGLShader::GetObjectInstance(env, shaderObj);
411     if (webGlShader == nullptr) {
412         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "webGlShader is nullptr.");
413         return NVal::CreateNull(env).val_;
414     }
415     uint32_t shaderId = webGlShader->GetShaderId();
416     uint32_t programId = webGLProgram->GetProgramId();
417     LOGD("WebGL detach shader programId %{public}u, shaderId %{public}u", programId, shaderId);
418     uint32_t index = 0;
419     if (!CheckShaderType(env, webGlShader->GetShaderType(), index) || !webGLProgram->DetachShader(index, shaderId)) {
420         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "Invalid shader");
421         return NVal::CreateNull(env).val_;
422     }
423     glDetachShader(static_cast<GLuint>(programId), static_cast<GLuint>(shaderId));
424     return NVal::CreateNull(env).val_;
425 }
426 
CompileShader(napi_env env,napi_value object)427 napi_value WebGLRenderingContextBaseImpl::CompileShader(napi_env env, napi_value object)
428 {
429     WebGLShader* webGlShader = WebGLShader::GetObjectInstance(env, object);
430     if (webGlShader == nullptr) {
431         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
432         return NVal::CreateNull(env).val_;
433     }
434     uint32_t shaderId = webGlShader->GetShaderId();
435     glCompileShader(static_cast<GLuint>(shaderId));
436     LOGD("WebGL compile shader shaderId %{public}u result %{public}u", shaderId, GetError_());
437     return NVal::CreateNull(env).val_;
438 }
439 
ShaderSource(napi_env env,napi_value object,const std::string & source)440 napi_value WebGLRenderingContextBaseImpl::ShaderSource(napi_env env, napi_value object, const std::string& source)
441 {
442     WebGLShader* webGlShader = WebGLShader::GetObjectInstance(env, object);
443     if (webGlShader == nullptr) {
444         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "webGlShader is nullptr.");
445         return NVal::CreateNull(env).val_;
446     }
447     uint32_t shaderId = webGlShader->GetShaderId();
448     if (!WebGLArg::CheckString(source)) {
449         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "checkString failed.");
450         return NVal::CreateNull(env).val_;
451     }
452     GLint length = static_cast<GLint>(source.size());
453     GLchar* str = const_cast<GLchar*>(source.c_str());
454     glShaderSource(static_cast<GLuint>(shaderId), 1, &str, &length);
455     webGlShader->SetShaderRes(source);
456     LOGD("WebGL shaderSource shaderId %{public}u source: '%{public}s' result %{public}u",
457         shaderId, source.c_str(), GetError_());
458     return NVal::CreateNull(env).val_;
459 }
460 
DeleteBuffer(napi_env env,napi_value object)461 napi_value WebGLRenderingContextBaseImpl::DeleteBuffer(napi_env env, napi_value object)
462 {
463     LOGD("WebGL deleteBuffer ");
464     WebGLBuffer* webGlBuffer = GetValidBuffer(env, object);
465     if (webGlBuffer == nullptr) {
466         return NVal::CreateNull(env).val_;
467     }
468     GLuint buffer = webGlBuffer->GetBufferId();
469     DoObjectDelete(WebGLBuffer::objectType, webGlBuffer);
470     DeleteObject<WebGLBuffer>(env, buffer);
471     glDeleteBuffers(1, &buffer);
472     LOGD("WebGL deleteBuffer bufferId %{public}u %{public}p result %{public}u", buffer, webGlBuffer, GetError_());
473     for (uint32_t i = 0; i < BoundBufferType::BUFFER_MAX; i++) {
474         if (boundBufferIds_[i] == buffer) {
475             boundBufferIds_[i] = 0;
476         }
477     }
478     return NVal::CreateNull(env).val_;
479 }
480 
DeleteFrameBuffer(napi_env env,napi_value object)481 napi_value WebGLRenderingContextBaseImpl::DeleteFrameBuffer(napi_env env, napi_value object)
482 {
483     WebGLFramebuffer* webGlFramebuffer = WebGLObject::GetObjectInstance<WebGLFramebuffer>(env, object);
484     if (webGlFramebuffer == nullptr) {
485         return NVal::CreateNull(env).val_;
486     }
487     GLuint frameBufferId = webGlFramebuffer->GetFramebuffer();
488     DeleteObject<WebGLFramebuffer>(env, frameBufferId);
489     glDeleteFramebuffers(1, &frameBufferId);
490     GLenum target = 0;
491     if (!IsHighWebGL()) {
492         if (boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER] == frameBufferId) {
493             boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER] = 0;
494         }
495         target = webGlFramebuffer->GetTarget();
496     } else {
497         if (frameBufferId == boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER]) {
498             if (frameBufferId == boundFrameBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER]) {
499                 target = GL_FRAMEBUFFER;
500                 boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER] = 0;
501                 boundFrameBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER] = 0;
502             } else {
503                 target = GL_DRAW_FRAMEBUFFER;
504                 boundFrameBufferIds_[BoundFrameBufferType::FRAMEBUFFER] = 0;
505             }
506         } else if (frameBufferId == boundFrameBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER]) {
507             target = GL_READ_FRAMEBUFFER;
508             boundFrameBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER] = 0;
509         }
510     }
511     if (target) {
512         glBindFramebuffer(target, 0);
513     }
514     LOGD("WebGL deleteFramebuffer target %{public}u framebufferId %{public}u result %{public}u",
515         target, frameBufferId, GetError_());
516     return NVal::CreateNull(env).val_;
517 }
518 
GetBufferParameter(napi_env env,GLenum target,GLenum pname)519 napi_value WebGLRenderingContextBaseImpl::GetBufferParameter(napi_env env, GLenum target, GLenum pname)
520 {
521     LOGD("WebGL getBufferParameter target %{public}u %{public}u", target, pname);
522     uint32_t index = 0;
523     if (!CheckBufferTarget(env, target, index)) {
524         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckBufferTarget failed.");
525         return NVal::CreateNull(env).val_;
526     }
527     switch (pname) {
528         case WebGLRenderingContextBase::BUFFER_USAGE:
529         case WebGLRenderingContextBase::BUFFER_SIZE: {
530             GLint value = 0;
531             glGetBufferParameteriv(target, pname, &value);
532             return NVal::CreateInt64(env, value).val_;
533         }
534         default:
535             SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
536             return NVal::CreateNull(env).val_;
537     }
538 }
539 
DeleteProgram(napi_env env,napi_value object)540 napi_value WebGLRenderingContextBaseImpl::DeleteProgram(napi_env env, napi_value object)
541 {
542     WebGLProgram* webGlProgram = WebGLObject::GetObjectInstance<WebGLProgram>(env, object);
543     if (webGlProgram == nullptr) {
544         return NVal::CreateNull(env).val_;
545     }
546     uint32_t programId = webGlProgram->GetProgramId();
547     DeleteObject<WebGLProgram>(env, programId);
548     glDeleteProgram(static_cast<GLuint>(programId));
549     if (currentProgramId_ == programId) {
550         currentProgramId_ = 0;
551     } else if (currentProgramId_ != 0) {
552         LOGD("WebGL deleteProgram current programId %{public}u", currentProgramId_);
553     }
554     LOGD("WebGL deleteProgram programId %{public}u result %{public}u", programId, GetError_());
555     return NVal::CreateNull(env).val_;
556 }
557 
DeleteRenderBuffer(napi_env env,napi_value object)558 napi_value WebGLRenderingContextBaseImpl::DeleteRenderBuffer(napi_env env, napi_value object)
559 {
560     WebGLRenderbuffer* webGlRenderbuffer = WebGLObject::GetObjectInstance<WebGLRenderbuffer>(env, object);
561     if (webGlRenderbuffer == nullptr) {
562         return NVal::CreateNull(env).val_;
563     }
564 
565     uint32_t renderbuffer = webGlRenderbuffer->GetRenderbuffer();
566     WebGLFramebuffer* framebufferBinding = GetBoundFrameBuffer(env, WebGLRenderingContextBase::FRAMEBUFFER);
567     if (framebufferBinding) {
568         framebufferBinding->RemoveAttachment(GL_FRAMEBUFFER, renderbuffer, AttachmentType::RENDER_BUFFER);
569     }
570     framebufferBinding = GetBoundFrameBuffer(env, WebGL2RenderingContextBase::READ_FRAMEBUFFER);
571     if (framebufferBinding != nullptr) {
572         framebufferBinding->RemoveAttachment(GL_READ_FRAMEBUFFER, renderbuffer, AttachmentType::RENDER_BUFFER);
573     }
574     DeleteObject<WebGLRenderbuffer>(env, renderbuffer);
575     glDeleteRenderbuffers(1, &renderbuffer);
576     LOGD("WebGL deleteRenderbuffer renderbuffer %{public}u", renderbuffer);
577     uint32_t index = 0;
578     if (!CheckRenderBufferTarget(env, webGlRenderbuffer->GetTarget(), index)) {
579         return NVal::CreateNull(env).val_;
580     }
581     boundRenderBufferIds_[index] = 0;
582     return NVal::CreateNull(env).val_;
583 }
584 
GetRenderBufferParameter(napi_env env,GLenum target,GLenum pname)585 napi_value WebGLRenderingContextBaseImpl::GetRenderBufferParameter(napi_env env, GLenum target, GLenum pname)
586 {
587     uint32_t index = 0;
588     LOGD("WebGL getRenderbufferParameter target %{public}u %{public}u", target, pname);
589     if (!CheckRenderBufferTarget(env, target, index)) {
590         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckRenderBufferTarget failed.");
591         return NVal::CreateNull(env).val_;
592     }
593     WebGLRenderbuffer* renderBuffer = GetObjectInstance<WebGLRenderbuffer>(env, boundRenderBufferIds_[index]);
594     if (renderBuffer == nullptr) {
595         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
596             "WebGL getRenderbufferParameter can not get bound render buffer Id %{public}u",
597             boundRenderBufferIds_[index]);
598         return NVal::CreateNull(env).val_;
599     }
600 
601     GLint params = 0;
602     switch (pname) {
603         case WebGL2RenderingContextBase::RENDERBUFFER_SAMPLES: {
604             if (!IsHighWebGL()) {
605                 SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
606                 return NVal::CreateNull(env).val_;
607             }
608             [[fallthrough]];
609         }
610         case WebGLRenderingContextBase::RENDERBUFFER_WIDTH:
611         case WebGLRenderingContextBase::RENDERBUFFER_HEIGHT:
612         case WebGLRenderingContextBase::RENDERBUFFER_RED_SIZE:
613         case WebGLRenderingContextBase::RENDERBUFFER_GREEN_SIZE:
614         case WebGLRenderingContextBase::RENDERBUFFER_BLUE_SIZE:
615         case WebGLRenderingContextBase::RENDERBUFFER_ALPHA_SIZE:
616         case WebGLRenderingContextBase::RENDERBUFFER_DEPTH_SIZE:
617         case WebGLRenderingContextBase::RENDERBUFFER_STENCIL_SIZE: {
618             glGetRenderbufferParameteriv(target, pname, &params);
619             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
620         }
621         case WebGLRenderingContextBase::RENDERBUFFER_INTERNAL_FORMAT:
622             return NVal::CreateInt64(env, static_cast<int64_t>(renderBuffer->GetInternalFormat())).val_;
623         default: {
624             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "invalud pname %{public}u", pname);
625             return NVal::CreateNull(env).val_;
626         }
627     }
628 }
629 
DeleteShader(napi_env env,napi_value object)630 napi_value WebGLRenderingContextBaseImpl::DeleteShader(napi_env env, napi_value object)
631 {
632     uint32_t shaderId = WebGLShader::DEFAULT_SHADER_ID;
633     WebGLShader* webGlShader = WebGLObject::GetObjectInstance<WebGLShader>(env, object);
634     if (webGlShader == nullptr) {
635         return NVal::CreateNull(env).val_;
636     }
637     shaderId = webGlShader->GetShaderId();
638     DeleteObject<WebGLShader>(env, shaderId);
639     glDeleteShader(static_cast<GLuint>(shaderId));
640     LOGD("WebGL deleteShader shaderId %{public}u", shaderId);
641     return NVal::CreateNull(env).val_;
642 }
643 
GetShaderParameter(napi_env env,napi_value object,GLenum pname)644 napi_value WebGLRenderingContextBaseImpl::GetShaderParameter(napi_env env, napi_value object, GLenum pname)
645 {
646     WebGLShader* webGlShader = WebGLShader::GetObjectInstance(env, object);
647     if (webGlShader == nullptr) {
648         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
649         return NVal::CreateNull(env).val_;
650     }
651     uint32_t shaderId = webGlShader->GetShaderId();
652     LOGD("WebGL getShaderParameter shaderId %{public}u", shaderId);
653 
654     GLint params = 0;
655     switch (pname) {
656         case WebGLRenderingContextBase::SHADER_TYPE: {
657             glGetShaderiv(static_cast<GLuint>(shaderId), pname, &params);
658             int64_t res = static_cast<int64_t>(params);
659             return NVal::CreateInt64(env, res).val_;
660         }
661         case WebGLRenderingContextBase::DELETE_STATUS:
662         case WebGLRenderingContextBase::COMPILE_STATUS: {
663             glGetShaderiv(static_cast<GLuint>(shaderId), pname, &params);
664             bool res = (params == GL_FALSE) ? false : true;
665             return NVal::CreateBool(env, res).val_;
666         }
667         default:
668             break;
669     }
670     SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
671     return NVal::CreateNull(env).val_;
672 }
673 
GetShaderPrecisionFormat(napi_env env,GLenum shaderType,GLenum precisionType)674 napi_value WebGLRenderingContextBaseImpl::GetShaderPrecisionFormat(
675     napi_env env, GLenum shaderType, GLenum precisionType)
676 {
677     LOGD("WebGL getShaderPrecisionFormat shaderType %{public}u precisionType %{public}u", shaderType, precisionType);
678     uint32_t index = 0;
679     if (!CheckShaderType(env, shaderType, index)) {
680         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckShaderType failed.");
681         return NVal::CreateNull(env).val_;
682     }
683     if (!CheckGLenum(precisionType,
684             { WebGLRenderingContextBase::LOW_FLOAT, WebGLRenderingContextBase::MEDIUM_FLOAT,
685             WebGLRenderingContextBase::HIGH_FLOAT, WebGLRenderingContextBase::LOW_INT,
686             WebGLRenderingContextBase::MEDIUM_INT, WebGLRenderingContextBase::HIGH_INT }, {})) {
687         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckGLenum failed.");
688         return NVal::CreateNull(env).val_;
689     }
690     WebGLShaderPrecisionFormat* webGLShaderPrecisionFormat = nullptr;
691     napi_value objShaderPrecisionFormat =
692         WebGLShaderPrecisionFormat::CreateObjectInstance(env, &webGLShaderPrecisionFormat).val_;
693     if (webGLShaderPrecisionFormat == nullptr) {
694         LOGE("WebGL getShaderPrecisionFormat fail oshaderType %{public}u", shaderType);
695         return NVal::CreateNull(env).val_;
696     }
697 
698     GLint range[2] = { 0 }; // 2 is glGetShaderPrecisionFormat default range array pointer.
699     GLint precision = 0;
700     glGetShaderPrecisionFormat(shaderType, precisionType, range, &precision);
701     LOGD("WebGL getShaderPrecisionFormat [%{public}d %{public}d] precision %{public}d", range[0], range[1], precision);
702     webGLShaderPrecisionFormat->SetShaderPrecisionFormatRangeMin(range[0]);
703     webGLShaderPrecisionFormat->SetShaderPrecisionFormatRangeMax(range[1]);
704     webGLShaderPrecisionFormat->SetShaderPrecisionFormatPrecision(precision);
705     return objShaderPrecisionFormat;
706 }
707 
DeleteTexture(napi_env env,napi_value object)708 napi_value WebGLRenderingContextBaseImpl::DeleteTexture(napi_env env, napi_value object)
709 {
710     WebGLTexture* webGlTexture = WebGLObject::GetObjectInstance<WebGLTexture>(env, object);
711     if (webGlTexture == nullptr) {
712         return NVal::CreateNull(env).val_;
713     }
714     uint32_t texture = webGlTexture->GetTexture();
715     LOGD("WebGL deleteTexture textureId %{public}u", texture);
716     WebGLFramebuffer* framebufferBinding = GetBoundFrameBuffer(env, WebGLRenderingContextBase::FRAMEBUFFER);
717     if (framebufferBinding) {
718         framebufferBinding->RemoveAttachment(GL_FRAMEBUFFER, texture, AttachmentType::TEXTURE);
719     }
720     framebufferBinding = GetBoundFrameBuffer(env, WebGL2RenderingContextBase::READ_FRAMEBUFFER);
721     if (framebufferBinding != nullptr) {
722         framebufferBinding->RemoveAttachment(GL_READ_FRAMEBUFFER, texture, AttachmentType::TEXTURE);
723     }
724     uint32_t index = 0;
725     if (webGlTexture->GetTarget() &&
726         !WebGLRenderingContextBaseImpl::CheckTextureTarget(env, webGlTexture->GetTarget(), index)) {
727         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
728         return NVal::CreateNull(env).val_;
729     }
730     for (size_t i = 0; i < boundTexture_[index].size(); i++) {
731         if (boundTexture_[index][i] == texture) {
732             boundTexture_[index][i] = 0;
733         }
734     }
735     DeleteObject<WebGLTexture>(env, texture);
736     glDeleteTextures(1, &texture);
737     return NVal::CreateNull(env).val_;
738 }
739 
HandleFrameBufferAttachmentPname(napi_env env,GLenum target,GLenum attachment,GLenum pname,GLint type)740 napi_value WebGLRenderingContextBaseImpl::HandleFrameBufferAttachmentPname(
741     napi_env env, GLenum target, GLenum attachment, GLenum pname, GLint type)
742 {
743     GLint params = 0;
744     switch (pname) {
745         case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
746             return NVal::CreateInt64(env, static_cast<int64_t>(type)).val_;
747         case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: {
748             glGetFramebufferAttachmentParameteriv(target, attachment, pname, &params);
749             LOGD("WebGL getFramebufferAttachmentParameter objectId %{public}d", params);
750             return (type == WebGLRenderingContextBase::RENDERBUFFER) ? GetObject<WebGLRenderbuffer>(env, params) :
751                 GetObject<WebGLTexture>(env, params);
752         }
753         case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: {
754             if (!IsHighWebGL()) {
755                 break;
756             }
757             [[fallthrough]];
758         }
759         case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
760         case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
761             if (type == WebGLRenderingContextBase::RENDERBUFFER) {
762                 break;
763             }
764             glGetFramebufferAttachmentParameteriv(target, attachment, pname, &params);
765             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
766         }
767         case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
768             if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
769                 SET_ERROR(WebGLRenderingContextBase::INVALID_OPERATION);
770                 return NVal::CreateNull(env).val_;
771             }
772             [[fallthrough]];
773         }
774         case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
775         case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
776         case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
777         case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
778         case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
779         case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
780         case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: {
781             if (!IsHighWebGL()) {
782                 break;
783             }
784             glGetFramebufferAttachmentParameteriv(target, attachment, pname, &params);
785             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
786         }
787         default:
788             break;
789     }
790     SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
791     LOGE("WebGL getFramebufferAttachmentParameter : no image is attached pname %{public}u %{public}d", pname, type);
792     return NVal::CreateNull(env).val_;
793 }
794 
GetFrameBufferAttachmentParameter(napi_env env,GLenum target,GLenum attachment,GLenum pname)795 napi_value WebGLRenderingContextBaseImpl::GetFrameBufferAttachmentParameter(
796     napi_env env, GLenum target, GLenum attachment, GLenum pname)
797 {
798     uint32_t index = 0;
799     if (!CheckFrameBufferTarget(env, target, index)) {
800         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "getFramebufferAttachmentParameter Invalid target");
801         return NVal::CreateNull(env).val_;
802     }
803     if (!CheckAttachment(env, attachment)) {
804         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckAttachment failed.");
805         return NVal::CreateNull(env).val_;
806     }
807 
808     WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, WebGLRenderingContextBase::FRAMEBUFFER);
809     if (frameBuffer == nullptr) {
810         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "frameBuffer is nullptr");
811         return NVal::CreateNull(env).val_;
812     }
813     GLint type = 0;
814     glGetFramebufferAttachmentParameteriv(target, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
815     LOGD("WebGL getFramebufferAttachmentParameter target %{public}u %{public}u %{public}u %{public}d",
816         target, attachment, pname, type);
817     if ((type != WebGLRenderingContextBase::RENDERBUFFER) && (type != WebGLRenderingContextBase::TEXTURE)) {
818         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
819         return NVal::CreateNull(env).val_;
820     }
821 
822     return HandleFrameBufferAttachmentPname(env, target, attachment, pname, type);
823 }
824 
FrameBufferRenderBuffer(napi_env env,GLenum target,GLenum attachment,GLenum renderBufferTarget,napi_value object)825 napi_value WebGLRenderingContextBaseImpl::FrameBufferRenderBuffer(
826     napi_env env, GLenum target, GLenum attachment, GLenum renderBufferTarget, napi_value object)
827 {
828     LOGD("WebGL framebufferRenderbuffer target %{public}u %{public}u %{public}u",
829         target, attachment, renderBufferTarget);
830     uint32_t frameBufferTargetIdx = 0;
831     if (!CheckFrameBufferTarget(env, target, frameBufferTargetIdx)) {
832         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
833             "WebGL framebufferRenderbuffer invalid target %{public}u", target);
834         return NVal::CreateNull(env).val_;
835     }
836     if (!CheckAttachment(env, attachment)) {
837         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
838             "WebGL framebufferRenderbuffer invalid attachment %{public}u", attachment);
839         return NVal::CreateNull(env).val_;
840     }
841     uint32_t renderBufferTargetIdx = 0;
842     if (!CheckRenderBufferTarget(env, renderBufferTarget, renderBufferTargetIdx)) {
843         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
844             "WebGL framebufferRenderbuffer invalid renderBufferTarget %{public}u", renderBufferTarget);
845         return NVal::CreateNull(env).val_;
846     }
847     WebGLFramebuffer* frameBuffer =
848         GetObjectInstance<WebGLFramebuffer>(env, boundFrameBufferIds_[frameBufferTargetIdx]);
849     if (frameBuffer == nullptr) {
850         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
851             "WebGL framebufferRenderbuffer can not find bind frame buffer");
852         return NVal::CreateNull(env).val_;
853     }
854 
855     GLuint renderbuffer = WebGLRenderbuffer::DEFAULT_RENDER_BUFFER;
856     WebGLRenderbuffer* webGlRenderbuffer = GetValidRenderBuffer(env, object);
857     if (webGlRenderbuffer != nullptr) {
858         renderbuffer = webGlRenderbuffer->GetRenderbuffer();
859     }
860 
861     if (attachment == WebGLRenderingContextBase::DEPTH_STENCIL_ATTACHMENT) {
862         if (IsHighWebGL()) {
863             frameBuffer->AddAttachment(target, WebGLRenderingContextBase::DEPTH_ATTACHMENT, renderbuffer);
864             frameBuffer->AddAttachment(target, WebGLRenderingContextBase::STENCIL_ATTACHMENT, renderbuffer);
865         } else {
866             frameBuffer->AddAttachment(target, attachment, renderbuffer);
867         }
868         glFramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderBufferTarget, renderbuffer);
869         glFramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderBufferTarget, renderbuffer);
870     } else {
871         frameBuffer->AddAttachment(target, attachment, renderbuffer);
872         glFramebufferRenderbuffer(target, attachment, renderBufferTarget, renderbuffer);
873     }
874     LOGD("WebGL framebufferRenderbuffer renderbuffer %{public}u error %{public}u", renderbuffer, GetError_());
875     return NVal::CreateNull(env).val_;
876 }
877 
FrameBufferTexture2D(napi_env env,GLenum target,GLenum attachment,GLenum textureTarget,napi_value texture,GLint level)878 napi_value WebGLRenderingContextBaseImpl::FrameBufferTexture2D(
879     napi_env env, GLenum target, GLenum attachment, GLenum textureTarget, napi_value texture, GLint level)
880 {
881     LOGD("WebGL framebufferTexture2D target %{public}u %{public}u %{public}u", target, attachment, textureTarget);
882     if (!CheckAttachment(env, attachment)) {
883         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "invalid attachment");
884         return NVal::CreateNull(env).val_;
885     }
886     if (IsHighWebGL()) {
887         if (CheckTextureLevel(textureTarget, level)) {
888             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "Invalid texture level");
889             return NVal::CreateNull(env).val_;
890         }
891     } else if (level) {
892         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "Invalid texture level");
893         return NVal::CreateNull(env).val_;
894     }
895     if (!CheckTexture2DTarget(env, textureTarget)) {
896         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "invalid textureTarget");
897         return NVal::CreateNull(env).val_;
898     }
899     WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, target);
900     if (frameBuffer == nullptr) {
901         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "can not find bind frame buffer");
902         return NVal::CreateNull(env).val_;
903     }
904 
905     int32_t textureId = WebGLTexture::DEFAULT_TEXTURE;
906     WebGLTexture* webGlTexture = WebGLTexture::GetObjectInstance(env, texture);
907     if (webGlTexture != nullptr) {
908         textureId = static_cast<int32_t>(webGlTexture->GetTexture());
909     }
910     frameBuffer->AddAttachment(target, attachment, static_cast<GLuint>(textureId), textureTarget, level);
911 
912     if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
913         glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textureTarget, static_cast<GLuint>(textureId), level);
914         glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textureTarget, static_cast<GLuint>(textureId), level);
915     } else {
916         glFramebufferTexture2D(target, attachment, textureTarget, static_cast<GLuint>(textureId), level);
917     }
918     LOGD("WebGL framebufferTexture2D texture %{public}u result %{public}u", textureId, GetError_());
919     return NVal::CreateNull(env).val_;
920 }
921 
GetProgramParameter(napi_env env,napi_value object,GLenum pname)922 napi_value WebGLRenderingContextBaseImpl::GetProgramParameter(napi_env env, napi_value object, GLenum pname)
923 {
924     uint32_t programId = WebGLProgram::DEFAULT_PROGRAM_ID;
925     WebGLProgram* webGlProgram = WebGLObject::GetObjectInstance<WebGLProgram>(env, object);
926     if (webGlProgram == nullptr) {
927         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
928         return NVal::CreateNull(env).val_;
929     }
930     programId = webGlProgram->GetProgramId();
931     LOGD("WebGL getProgramParameter programId %{public}u pname %{public}u", programId, pname);
932     switch (pname) {
933         case WebGLRenderingContextBase::DELETE_STATUS:
934         case WebGLRenderingContextBase::LINK_STATUS:
935         case WebGLRenderingContextBase::VALIDATE_STATUS: {
936             GLint params = 0;
937             glGetProgramiv(static_cast<GLuint>(programId), pname, &params);
938             LOGD("WebGL getProgramParameter params %{public}d", params);
939             return NVal::CreateBool(env, params ? true : false).val_;
940         }
941         case WebGLRenderingContextBase::ATTACHED_SHADERS:
942         case WebGLRenderingContextBase::ACTIVE_ATTRIBUTES:
943         case WebGLRenderingContextBase::ACTIVE_UNIFORMS: {
944             GLint params = 0;
945             glGetProgramiv(static_cast<GLuint>(programId), pname, &params);
946             LOGD("WebGL getProgramParameter params %{public}d", params);
947             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
948         }
949         case WebGL2RenderingContextBase::ACTIVE_UNIFORM_BLOCKS:
950         case WebGL2RenderingContextBase::TRANSFORM_FEEDBACK_VARYINGS:
951         case WebGL2RenderingContextBase::TRANSFORM_FEEDBACK_BUFFER_MODE: {
952             if (!IsHighWebGL()) {
953                 SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
954                 return NVal::CreateNull(env).val_;
955             }
956             GLint params = 0;
957             glGetProgramiv(static_cast<GLuint>(programId), pname, &params);
958             LOGD("WebGL getProgramParameter params %{public}d", params);
959             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
960         }
961         default:
962             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "invalid pname %{public}u", pname);
963             break;
964     }
965     return NVal::CreateNull(env).val_;
966 }
967 
GetAttachedShaders(napi_env env,napi_value object)968 napi_value WebGLRenderingContextBaseImpl::GetAttachedShaders(napi_env env, napi_value object)
969 {
970     uint32_t programId = WebGLProgram::DEFAULT_PROGRAM_ID;
971     WebGLProgram* webGlProgram = WebGLObject::GetObjectInstance<WebGLProgram>(env, object);
972     if (webGlProgram != nullptr) {
973         programId = webGlProgram->GetProgramId();
974     }
975 
976     GLsizei count = 1;
977     std::vector<GLuint> shaderId(MAX_COUNT_ATTACHED_SHADER);
978     glGetAttachedShaders(
979         static_cast<GLuint>(programId), MAX_COUNT_ATTACHED_SHADER, &count, static_cast<GLuint*>(shaderId.data()));
980     LOGD("WebGL getAttachedShaders programId %{public}u count %{public}d", programId, count);
981     napi_value shaderArr = nullptr;
982     napi_create_array(env, &shaderArr);
983     for (GLsizei i = 0; i < count; i++) {
984         napi_value objShader = GetObject<WebGLShader>(env, shaderId[i]);
985         (void)napi_set_element(env, shaderArr, i, objShader);
986     }
987     return shaderArr;
988 }
989 
GetUniformLocation(napi_env env,napi_value object,const std::string & name)990 napi_value WebGLRenderingContextBaseImpl::GetUniformLocation(napi_env env, napi_value object, const std::string& name)
991 {
992     WebGLProgram* webGlProgram = WebGLObject::GetObjectInstance<WebGLProgram>(env, object);
993     if (webGlProgram == nullptr) {
994         return NVal::CreateNull(env).val_;
995     }
996     GLuint programId = webGlProgram->GetProgramId();
997     if (!CheckLocationName(name)) {
998         return NVal::CreateNull(env).val_;
999     }
1000 
1001     GLint locationId = glGetUniformLocation(programId, name.c_str());
1002     LOGD("WebGL getUniformLocation locationId programId %{public}u name '%{public}s' %{public}d",
1003         programId, name.c_str(), locationId);
1004     if (locationId == -1) {
1005         return NVal::CreateNull(env).val_;
1006     }
1007     // check if exit
1008     WebGLUniformLocation* webGLUniformLocation = GetObjectInstance<WebGLUniformLocation>(env, locationId);
1009     napi_value objUniformLocation = GetNapiValue<WebGLUniformLocation>(env, locationId);
1010     if (webGLUniformLocation == nullptr) { // create new
1011         objUniformLocation = WebGLUniformLocation::CreateObjectInstance(env, &webGLUniformLocation).val_;
1012         if (webGLUniformLocation == nullptr) {
1013             return NVal::CreateNull(env).val_;
1014         }
1015         webGLUniformLocation->SetUniformLocationId(locationId);
1016         AddObject<WebGLUniformLocation>(env, locationId, objUniformLocation);
1017     } else {
1018         webGLUniformLocation->SetUniformLocationName(name);
1019     }
1020     return objUniformLocation;
1021 }
1022 
GetAttribLocation(napi_env env,napi_value object,const std::string & name)1023 napi_value WebGLRenderingContextBaseImpl::GetAttribLocation(napi_env env, napi_value object, const std::string& name)
1024 {
1025     WebGLProgram* webGlProgram = WebGLObject::GetObjectInstance<WebGLProgram>(env, object);
1026     if (webGlProgram == nullptr) {
1027         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "webGlProgram is nullptr.");
1028         return NVal::CreateInt64(env, -1).val_;
1029     }
1030 
1031     if (!CheckLocationName(name)) {
1032         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "CheckLocationName failed.");
1033         return NVal::CreateInt64(env, -1).val_;
1034     }
1035 
1036     if (!CheckProgramLinkStatus(webGlProgram)) {
1037         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "CheckProgramLinkStatus failed.");
1038         return NVal::CreateInt64(env, -1).val_;
1039     }
1040     GLuint programId = webGlProgram->GetProgramId();
1041     GLint returnValue = glGetAttribLocation(programId, const_cast<char*>(name.c_str()));
1042     LOGD("WebGL getAttribLocation programId %{public}u name %{public}s, location %{public}d",
1043         programId, name.c_str(), returnValue);
1044     return NVal::CreateInt64(env, static_cast<int64_t>(returnValue)).val_;
1045 }
1046 
GetVertexAttrib(napi_env env,GLenum pname,GLuint index,VertexAttribInfo * info)1047 napi_value WebGLRenderingContextBaseImpl::GetVertexAttrib(napi_env env, GLenum pname, GLuint index,
1048     VertexAttribInfo* info)
1049 {
1050     if (info == nullptr) {
1051         return NVal::CreateNull(env).val_;
1052     }
1053     WebGLWriteBufferArg writeBuffer(env);
1054     void* result = reinterpret_cast<void*>(writeBuffer.AllocBuffer(4 * sizeof(GLfloat))); // 4 args
1055     if (result == nullptr) {
1056         return NVal::CreateNull(env).val_;
1057     }
1058     switch (info->type) {
1059         case BUFFER_DATA_FLOAT_32:
1060             glGetVertexAttribfv(index, pname, reinterpret_cast<GLfloat*>(result));
1061             return writeBuffer.ToNormalArray(BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32);
1062         case BUFFER_DATA_INT_32:
1063             glGetVertexAttribIuiv(index, pname, reinterpret_cast<GLuint*>(result));
1064             return writeBuffer.ToNormalArray(BUFFER_DATA_INT_32, BUFFER_DATA_INT_32);
1065         case BUFFER_DATA_UINT_32:
1066             glGetVertexAttribIuiv(index, pname, reinterpret_cast<GLuint*>(result));
1067             return writeBuffer.ToNormalArray(BUFFER_DATA_UINT_32, BUFFER_DATA_UINT_32);
1068         default:
1069             break;
1070     }
1071     return NVal::CreateNull(env).val_;
1072 }
1073 
GetVertexAttrib(napi_env env,GLenum pname,GLuint index)1074 napi_value WebGLRenderingContextBaseImpl::GetVertexAttrib(napi_env env, GLenum pname, GLuint index)
1075 {
1076     LOGD("WebGL getVertexAttrib index %{public}u %{public}u", index, pname);
1077     VertexAttribInfo* info = GetVertexAttribInfo(index);
1078     if (info == nullptr) {
1079         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
1080         return NVal::CreateNull(env).val_;
1081     }
1082     int32_t params = -1;
1083     switch (pname) {
1084         case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
1085             glGetVertexAttribiv(index, pname, &params);
1086             LOGD("WebGL getVertexAttrib %{public}d", params);
1087             return GetObject<WebGLBuffer>(env, params);
1088         }
1089         case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1090         case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1091         case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1092             glGetVertexAttribiv(index, pname, &params);
1093             return NVal::CreateBool(env, static_cast<bool>(params)).val_;
1094         case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1095         case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1096         case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
1097         case GL_VERTEX_ATTRIB_ARRAY_TYPE: {
1098             glGetVertexAttribiv(index, pname, &params);
1099             LOGD("WebGL getVertexAttrib %{public}d", params);
1100             return NVal::CreateInt64(env, params).val_;
1101         }
1102         case GL_CURRENT_VERTEX_ATTRIB:
1103             break;
1104         default:
1105             glGetVertexAttribiv(index, pname, &params);
1106             LOGD("WebGL getVertexAttrib getVertexAttrib end");
1107             return NVal::CreateNull(env).val_;
1108     }
1109     return GetVertexAttrib(env, pname, index, info);
1110 }
1111 
GetExtensionsParameter(napi_env env,GLenum pname)1112 static napi_value GetExtensionsParameter(napi_env env, GLenum pname)
1113 {
1114     const unsigned char* extensions = glGetString(pname);
1115     if (extensions == nullptr) {
1116         return NVal::CreateNull(env).val_;
1117     }
1118     std::string str = const_cast<char*>(reinterpret_cast<const char*>(extensions));
1119     vector<std::string> vec {};
1120     Util::SplitString(str, vec, " ");
1121     LOGD("WebGL GetExtensionsParameter  %{public}s %{public}s %{public}zu", extensions, str.c_str(), vec.size());
1122     napi_value result = nullptr;
1123     napi_create_array_with_length(env, vec.size(), &result);
1124     for (vector<std::string>::size_type i = 0; i != vec.size(); ++i) {
1125         napi_set_element(env, result, i, NVal::CreateUTF8String(env, vec[i]).val_);
1126     }
1127     return result;
1128 }
1129 
1130 template<class T>
GetObjectParameter(napi_env env,GLenum pname)1131 napi_value WebGLRenderingContextBaseImpl::GetObjectParameter(napi_env env, GLenum pname)
1132 {
1133     GLint params = 0;
1134     glGetIntegerv(pname, &params);
1135     LOGD("WebGL getParameter %{public}s params %{public}d", T::className.c_str(), params);
1136     return GetObject<T>(env, params);
1137 }
1138 
1139 template<class T>
GetIntegerVectorParameter(napi_env env,GLenum pname,GLuint count,BufferDataType dstDataType)1140 napi_value WebGLRenderingContextBaseImpl::GetIntegerVectorParameter(
1141     napi_env env, GLenum pname, GLuint count, BufferDataType dstDataType)
1142 {
1143     LOGD("get integer parameter pname %{public}u count %{public}u", pname, count);
1144     WebGLWriteBufferArg writeBuffer(env);
1145     T* params = reinterpret_cast<T*>(writeBuffer.AllocBuffer(count * sizeof(T))); // 2 args
1146     if (params == nullptr) {
1147         return writeBuffer.ToExternalArray(dstDataType);
1148     }
1149     glGetIntegerv(pname, params);
1150     return writeBuffer.ToExternalArray(dstDataType);
1151 }
1152 
GetFloatVectorParameter(napi_env env,GLenum pname,GLuint count,BufferDataType dstDataType)1153 napi_value WebGLRenderingContextBaseImpl::GetFloatVectorParameter(
1154     napi_env env, GLenum pname, GLuint count, BufferDataType dstDataType)
1155 {
1156     LOGD("get float parameter pname %{public}u count %{public}u", pname, count);
1157     WebGLWriteBufferArg writeBuffer(env);
1158     GLfloat* params = reinterpret_cast<GLfloat*>(writeBuffer.AllocBuffer(count * sizeof(GLfloat)));
1159     if (params == nullptr) {
1160         return writeBuffer.ToExternalArray(dstDataType);
1161     }
1162     glGetFloatv(pname, params);
1163     return writeBuffer.ToExternalArray(dstDataType);
1164 }
1165 
GetBoolVectorParameter(napi_env env,GLenum pname,GLuint count,BufferDataType dstDataType)1166 napi_value WebGLRenderingContextBaseImpl::GetBoolVectorParameter(
1167     napi_env env, GLenum pname, GLuint count, BufferDataType dstDataType)
1168 {
1169     WebGLWriteBufferArg writeBuffer(env);
1170     GLboolean* params = reinterpret_cast<GLboolean*>(writeBuffer.AllocBuffer(count * sizeof(GLboolean)));
1171     if (params == nullptr) {
1172         return writeBuffer.ToExternalArray(dstDataType);
1173     }
1174     glGetBooleanv(pname, static_cast<GLboolean*>(params));
1175     return writeBuffer.ToNormalArray(BUFFER_DATA_BOOLEAN, dstDataType);
1176 }
1177 
GetParameter(napi_env env,GLenum pname)1178 napi_value WebGLRenderingContextBaseImpl::GetParameter(napi_env env, GLenum pname)
1179 {
1180     LOGD("WebGL getParameter pname %{public}u", pname);
1181     switch (pname) {
1182         case GL_DEPTH_CLEAR_VALUE:
1183         case GL_LINE_WIDTH:
1184         case GL_POLYGON_OFFSET_FACTOR:
1185         case GL_POLYGON_OFFSET_UNITS:
1186         case GL_SAMPLE_COVERAGE_VALUE:
1187             return WebGLArg::GetFloatParameter(env, pname);
1188         case GL_TEXTURE_BINDING_2D:
1189         case GL_TEXTURE_BINDING_CUBE_MAP:
1190             return GetObjectParameter<WebGLTexture>(env, pname);
1191         case GL_RENDERER:
1192         case GL_SHADING_LANGUAGE_VERSION:
1193         case GL_VENDOR:
1194         case GL_VERSION:
1195             return GetExtensionsParameter(env, pname);
1196         case GL_ARRAY_BUFFER_BINDING:
1197         case GL_ELEMENT_ARRAY_BUFFER_BINDING:
1198             return GetObjectParameter<WebGLBuffer>(env, pname);
1199         case GL_FRAMEBUFFER_BINDING:
1200             return GetObjectParameter<WebGLFramebuffer>(env, pname);
1201         case GL_CURRENT_PROGRAM:
1202             return GetObjectParameter<WebGLProgram>(env, pname);
1203         case GL_RENDERBUFFER_BINDING:
1204             return GetObjectParameter<WebGLRenderbuffer>(env, pname);
1205         case GL_ALIASED_LINE_WIDTH_RANGE:
1206         case GL_ALIASED_POINT_SIZE_RANGE:
1207         case GL_DEPTH_RANGE:
1208             return GetFloatVectorParameter(env, pname, 2, BUFFER_DATA_FLOAT_32); //  2 args
1209         case GL_COLOR_CLEAR_VALUE:
1210         case GL_BLEND_COLOR:
1211             return GetFloatVectorParameter(env, pname, 4, BUFFER_DATA_FLOAT_32); //  4 args
1212         case GL_COMPRESSED_TEXTURE_FORMATS: {
1213             GLint count = 0;
1214             glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &count);
1215             return GetIntegerVectorParameter<GLint>(env, pname, count, BUFFER_DATA_INT_32);
1216         }
1217         case GL_MAX_VIEWPORT_DIMS:
1218             return GetIntegerVectorParameter<GLint>(env, pname, 2, BUFFER_DATA_INT_32); // 2 args
1219         case GL_SCISSOR_BOX:
1220         case WebGLRenderingContextBase::VIEWPORT:
1221             return GetIntegerVectorParameter<GLint>(env, pname, 4, BUFFER_DATA_INT_32); // 4 args
1222         case GL_COLOR_WRITEMASK:
1223             return GetBoolVectorParameter(env, pname, 4, BUFFER_DATA_BOOLEAN); // 4 args
1224         case WebGLRenderingContextBase::UNPACK_COLORSPACE_CONVERSION_WEBGL:
1225             return NVal::CreateInt64(env, unpackColorspaceConversion_).val_;
1226         case WebGLRenderingContextBase::UNPACK_FLIP_Y_WEBGL:
1227             return NVal::CreateBool(env, unpackFlipY_).val_;
1228         case WebGLRenderingContextBase::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
1229             return NVal::CreateBool(env, unpackPremultiplyAlpha_).val_;
1230         default: {
1231             if (CheckInList(pname, GetBoolParaName())) {
1232                 return WebGLArg::GetBoolParameter(env, pname);
1233             }
1234             if (CheckInList(pname, GetIntegerParaName())) {
1235                 return WebGLArg::GetInt32Parameter(env, pname);
1236             }
1237             break;
1238         }
1239     }
1240     SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "WebGL getParameter invalid pname %{public}u", pname);
1241     return NVal::CreateNull(env).val_;
1242 }
1243 
ClearColor(napi_env env,GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha)1244 napi_value WebGLRenderingContextBaseImpl::ClearColor(
1245     napi_env env, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
1246 {
1247     LOGD("WebGL clearColor [%{public}f, %{public}f, %{public}f, %{public}f]", red, green, blue, alpha);
1248     clearColor_[0] = red; // 0:red
1249     clearColor_[1] = green; // 1:green
1250     clearColor_[2] = blue; // 2:blue
1251     clearColor_[3] = alpha; // 3:alpha
1252     glClearColor(red, green, blue, alpha);
1253     return NVal::CreateNull(env).val_;
1254 }
1255 
ColorMask(napi_env env,GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)1256 napi_value WebGLRenderingContextBaseImpl::ColorMask(
1257     napi_env env, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
1258 {
1259     colorMask_[0] = red; // 0:red
1260     colorMask_[1] = green; // 1:green
1261     colorMask_[2] = blue; // 2:blue
1262     colorMask_[3] = alpha; // 3:alpha
1263     glColorMask(static_cast<GLboolean>(red), static_cast<GLboolean>(green), static_cast<GLboolean>(blue),
1264         static_cast<GLboolean>(alpha));
1265     return NVal::CreateNull(env).val_;
1266 }
1267 
Clear(napi_env env,GLbitfield mask)1268 napi_value WebGLRenderingContextBaseImpl::Clear(napi_env env, GLbitfield mask)
1269 {
1270     if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
1271         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1272             "WebGL clear mask %{public}x failed.", mask);
1273         return NVal::CreateNull(env).val_;
1274     }
1275     GLenum result = CheckFrameBufferBoundComplete(env);
1276     if (result) {
1277         SET_ERROR_WITH_LOG(result, "WebGL clear mask %{public}x CheckFrameBufferBoundComplete failed.", mask);
1278         return NVal::CreateNull(env).val_;
1279     }
1280     glClear(mask);
1281     LOGD("WebGL clear mask %{public}x result %{public}u", mask, GetError_());
1282     return NVal::CreateNull(env).val_;
1283 }
1284 
ClearDepth(napi_env env,GLclampf depth)1285 napi_value WebGLRenderingContextBaseImpl::ClearDepth(napi_env env, GLclampf depth)
1286 {
1287     LOGD("WebGL clearDepth %{public}f", depth);
1288     clearDepth_ = depth;
1289     glClearDepthf(depth);
1290     return NVal::CreateNull(env).val_;
1291 }
1292 
ClearStencil(napi_env env,GLint s)1293 napi_value WebGLRenderingContextBaseImpl::ClearStencil(napi_env env, GLint s)
1294 {
1295     LOGD("WebGL clearStencil s %{public}d", s);
1296     clearStencil_ = static_cast<GLint>(s);
1297     glClearStencil(static_cast<GLint>(s));
1298     return NVal::CreateNull(env).val_;
1299 }
1300 
UseProgram(napi_env env,napi_value object)1301 napi_value WebGLRenderingContextBaseImpl::UseProgram(napi_env env, napi_value object)
1302 {
1303     uint32_t program = WebGLProgram::DEFAULT_PROGRAM_ID;
1304     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, object);
1305     if (webGLProgram != nullptr) {
1306         program = webGLProgram->GetProgramId();
1307     }
1308     if ((currentProgramId_ != program) && (currentProgramId_ != 0)) {
1309         glUseProgram(static_cast<GLuint>(0));
1310     }
1311     currentProgramId_ = program;
1312     glUseProgram(static_cast<GLuint>(program));
1313     LOGD("WebGL useProgram programId %{public}u %{public}u result %{public}u",
1314         program, currentProgramId_, GetError_());
1315     return NVal::CreateNull(env).val_;
1316 }
1317 
ValidateProgram(napi_env env,napi_value object)1318 napi_value WebGLRenderingContextBaseImpl::ValidateProgram(napi_env env, napi_value object)
1319 {
1320     uint32_t program = WebGLProgram::DEFAULT_PROGRAM_ID;
1321     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, object);
1322     if (webGLProgram != nullptr) {
1323         program = webGLProgram->GetProgramId();
1324     }
1325     LOGD("WebGL validateProgram program %{public}u", program);
1326     glValidateProgram(static_cast<GLuint>(program));
1327     return NVal::CreateNull(env).val_;
1328 }
1329 
LinkProgram(napi_env env,napi_value object)1330 napi_value WebGLRenderingContextBaseImpl::LinkProgram(napi_env env, napi_value object)
1331 {
1332     uint32_t program = WebGLProgram::DEFAULT_PROGRAM_ID;
1333     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, object);
1334     if (webGLProgram != nullptr) {
1335         program = webGLProgram->GetProgramId();
1336     }
1337     glLinkProgram(static_cast<GLuint>(program));
1338     LOGD("WebGL linkProgram program %{public}u result %{public}u", program, GetError_());
1339     return NVal::CreateNull(env).val_;
1340 }
1341 
RenderBufferStorage(napi_env env,const TexStorageArg & arg)1342 napi_value WebGLRenderingContextBaseImpl::RenderBufferStorage(napi_env env, const TexStorageArg& arg)
1343 {
1344     LOGD("WebGL renderbufferStorage target %{public}u %{public}u %{public}d %{public}d",
1345         arg.target, arg.internalFormat, arg.width, arg.height);
1346     WebGLRenderbuffer* renderBuffer = CheckRenderBufferStorage(env, arg);
1347     if (renderBuffer == nullptr) {
1348         return NVal::CreateNull(env).val_;
1349     }
1350 
1351     switch (arg.internalFormat) {
1352         case WebGLRenderingContextBase::DEPTH_COMPONENT16:
1353         case WebGLRenderingContextBase::RGBA4:
1354         case WebGLRenderingContextBase::RGB5_A1:
1355         case WebGLRenderingContextBase::RGB565:
1356         case WebGLRenderingContextBase::STENCIL_INDEX8: {
1357             glRenderbufferStorage(arg.target, arg.internalFormat, arg.width, arg.height);
1358             renderBuffer->SetInternalFormat(arg.internalFormat);
1359             renderBuffer->SetSize(arg.width, arg.height);
1360             break;
1361         }
1362         case WebGLRenderingContextBase::DEPTH_STENCIL: {
1363             glRenderbufferStorage(arg.target, GL_DEPTH_COMPONENT16, arg.width, arg.height);
1364             glRenderbufferStorage(arg.target, GL_STENCIL_INDEX8, arg.width, arg.height);
1365             renderBuffer->SetInternalFormat(arg.internalFormat);
1366             renderBuffer->SetSize(arg.width, arg.height);
1367             break;
1368         }
1369         default:
1370             SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1371             return NVal::CreateNull(env).val_;
1372     }
1373     LOGD("WebGL renderbufferStorage result %{public}u", GetError_());
1374     return NVal::CreateNull(env).val_;
1375 }
1376 
VertexAttribPointer(napi_env env,const VertexAttribArg & vertexInfo)1377 napi_value WebGLRenderingContextBaseImpl::VertexAttribPointer(napi_env env, const VertexAttribArg& vertexInfo)
1378 {
1379     vertexInfo.Dump("WebGL vertexAttribPointer");
1380     if (!CheckGLenum(vertexInfo.type, { GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT }, {})) {
1381         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1382             "WebGL vertexAttribPointer invalid type %{public}u", vertexInfo.type);
1383     }
1384     GLenum result = CheckVertexAttribPointer(env, vertexInfo);
1385     if (result) {
1386         SET_ERROR(result);
1387         return NVal::CreateNull(env).val_;
1388     }
1389     glVertexAttribPointer(vertexInfo.index, vertexInfo.size, vertexInfo.type, vertexInfo.normalized,
1390         vertexInfo.stride, reinterpret_cast<GLvoid*>(vertexInfo.offset));
1391     LOGD("WebGL vertexAttribPointer index %{public}u result %{public}u", vertexInfo.index, GetError_());
1392     return NVal::CreateNull(env).val_;
1393 }
1394 
GetVertexAttribOffset(napi_env env,GLuint index,GLenum pname)1395 napi_value WebGLRenderingContextBaseImpl::GetVertexAttribOffset(napi_env env, GLuint index, GLenum pname)
1396 {
1397     LOGD("WebGL getVertexAttribOffset index %{public}u %{public}u", index, pname);
1398     if (pname != WebGLRenderingContextBase::VERTEX_ATTRIB_ARRAY_POINTER) {
1399         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1400         return NVal::CreateInt64(env, 0).val_;
1401     }
1402     GLvoid* point = nullptr;
1403     glGetVertexAttribPointerv(index, pname, &point);
1404     return NVal::CreateInt64(env, reinterpret_cast<int64_t>(point)).val_;
1405 }
1406 
EnableVertexAttribArray(napi_env env,int64_t index)1407 napi_value WebGLRenderingContextBaseImpl::EnableVertexAttribArray(napi_env env, int64_t index)
1408 {
1409     if (index < 0 || index >= GetMaxVertexAttribs()) {
1410         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1411             "WebGL enableVertexAttribArray invalid index %{public}" PRIi64, index);
1412         return NVal::CreateNull(env).val_;
1413     }
1414     LOGD("WebGL enableVertexAttribArray index %{public}" PRIi64, index);
1415     glEnableVertexAttribArray(static_cast<GLuint>(index));
1416     return NVal::CreateNull(env).val_;
1417 }
1418 
DisableVertexAttribArray(napi_env env,int64_t index)1419 napi_value WebGLRenderingContextBaseImpl::DisableVertexAttribArray(napi_env env, int64_t index)
1420 {
1421     if (index < 0 || index >= GetMaxVertexAttribs()) {
1422         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1423             "WebGL disableVertexAttribArray invalid index %{public}" PRIi64, index);
1424         return NVal::CreateNull(env).val_;
1425     }
1426     LOGD("WebGL disableVertexAttribArray index %{public}" PRIi64, index);
1427     glDisableVertexAttribArray(index);
1428     return NVal::CreateNull(env).val_;
1429 }
1430 
IsEnabled(napi_env env,GLenum cap)1431 napi_value WebGLRenderingContextBaseImpl::IsEnabled(napi_env env, GLenum cap)
1432 {
1433     bool result = false;
1434     if (!CheckCap(env, cap)) {
1435         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1436         return NVal::CreateBool(env, result).val_;
1437     }
1438     result = static_cast<bool>(glIsEnabled(cap));
1439     LOGD("WebGL isEnabled cap %{public}u result %{public}d", cap, result);
1440     return NVal::CreateBool(env, result).val_;
1441 }
1442 
Disable(napi_env env,GLenum cap)1443 napi_value WebGLRenderingContextBaseImpl::Disable(napi_env env, GLenum cap)
1444 {
1445     LOGD("WebGL disable cap %{public}u", cap);
1446     if (!CheckCap(env, cap)) {
1447         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1448         return NVal::CreateNull(env).val_;
1449     }
1450     glDisable(cap);
1451     return NVal::CreateNull(env).val_;
1452 }
1453 
Enable(napi_env env,GLenum cap)1454 napi_value WebGLRenderingContextBaseImpl::Enable(napi_env env, GLenum cap)
1455 {
1456     LOGD("WebGL enable cap %{public}u", cap);
1457     if (!CheckCap(env, cap)) {
1458         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1459         return NVal::CreateNull(env).val_;
1460     }
1461     if (cap == WebGLRenderingContextBase::STENCIL_TEST) {
1462         stencilEnabled_ = true;
1463     }
1464     if (cap == WebGLRenderingContextBase::SCISSOR_TEST) {
1465         scissorEnabled_ = true;
1466     }
1467     glEnable(cap);
1468     return NVal::CreateNull(env).val_;
1469 }
1470 
BindAttribLocation(napi_env env,napi_value program,GLuint index,const std::string & name)1471 napi_value WebGLRenderingContextBaseImpl::BindAttribLocation(
1472     napi_env env, napi_value program, GLuint index, const std::string& name)
1473 {
1474     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, program);
1475     if (webGLProgram == nullptr) {
1476         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL bindAttribLocation invalid object");
1477         return NVal::CreateNull(env).val_;
1478     }
1479     GLuint programId = webGLProgram->GetProgramId();
1480 
1481     if (index >= GetMaxVertexAttribs()) {
1482         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1483             "WebGL bindAttribLocation invalid index %{public}u", index);
1484         return NVal::CreateNull(env).val_;
1485     }
1486 
1487     if (!CheckLocationName(name)) {
1488         return NVal::CreateNull(env).val_;
1489     }
1490     LOGD("WebGL bindAttribLocation programId %{public}u index %{public}u name %{public}s",
1491         programId, index, name.c_str());
1492     glBindAttribLocation(programId, index, const_cast<char*>(name.c_str()));
1493     return NVal::CreateNull(env).val_;
1494 }
1495 
GenerateMipmap(napi_env env,GLenum target)1496 napi_value WebGLRenderingContextBaseImpl::GenerateMipmap(napi_env env, GLenum target)
1497 {
1498     if (!CheckGLenum(target,
1499         { WebGLRenderingContextBase::TEXTURE_2D, WebGLRenderingContextBase::TEXTURE_CUBE_MAP },
1500         { WebGL2RenderingContextBase::TEXTURE_3D, WebGL2RenderingContextBase::TEXTURE_2D_ARRAY })) {
1501         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1502         return NVal::CreateNull(env).val_;
1503     }
1504 
1505     WebGLTexture* webGLTexture = GetBoundTexture(env, target, false);
1506     if (webGLTexture == nullptr) {
1507         SET_ERROR(WebGLRenderingContextBase::INVALID_OPERATION);
1508         return NVal::CreateNull(env).val_;
1509     }
1510     glGenerateMipmap(target);
1511     LOGD("WebGL generateMipmap target %{public}u %{public}u", target, GetError_());
1512     return NVal::CreateNull(env).val_;
1513 }
1514 
GetError_()1515 GLenum WebGLRenderingContextBaseImpl::GetError_()
1516 {
1517     GLenum err = glGetError();
1518     if (err != GL_NO_ERROR) {
1519         lastError_ = err;
1520     }
1521     return lastError_;
1522 }
1523 
GetError(napi_env env)1524 napi_value WebGLRenderingContextBaseImpl::GetError(napi_env env)
1525 {
1526     GLenum err = GetError_();
1527     LOGD("getError result %{public}u", err);
1528     lastError_ = GL_NO_ERROR;
1529     return NVal::CreateInt64(env, static_cast<int64_t>(err)).val_;
1530 }
1531 
UniformF(napi_env env,napi_value locationObj,uint32_t count,const GLfloat * data)1532 napi_value WebGLRenderingContextBaseImpl::UniformF(
1533     napi_env env, napi_value locationObj, uint32_t count, const GLfloat* data)
1534 {
1535     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1536     if (webGLUniformLocation == nullptr) {
1537         LOGE("WebGL uniform_f can not find uniform");
1538         return NVal::CreateNull(env).val_;
1539     }
1540     GLint location = webGLUniformLocation->GetUniformLocationId();
1541 
1542     // 0,1,2,3 index for data
1543     LOGD("WebGL uniform location %{public}d [%{public}f %{public}f %{public}f %{public}f]",
1544         location, data[0], data[1], data[2], data[3]);
1545     switch (count) {
1546         case PARAMETERS_NUM_1:
1547             glUniform1f(location, data[0]);
1548             break;
1549         case PARAMETERS_NUM_2:
1550             glUniform2f(location, data[0], data[1]);
1551             break;
1552         case PARAMETERS_NUM_3:
1553             glUniform3f(location, data[0], data[1], data[2]); // 0,1,2,3 index for data
1554             break;
1555         case PARAMETERS_NUM_4:
1556             glUniform4f(location, data[0], data[1], data[2], data[3]); // 0,1,2,3 index for data
1557             break;
1558         default:
1559             break;;
1560     }
1561     return NVal::CreateNull(env).val_;
1562 }
1563 
UniformI(napi_env env,napi_value locationObj,uint32_t count,const GLint * data)1564 napi_value WebGLRenderingContextBaseImpl::UniformI(
1565     napi_env env, napi_value locationObj, uint32_t count, const GLint* data)
1566 {
1567     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1568     if (webGLUniformLocation == nullptr) {
1569         LOGE("WebGL uniform_i can not find uniform");
1570         return NVal::CreateNull(env).val_;
1571     }
1572     GLint location = webGLUniformLocation->GetUniformLocationId();
1573     // 0,1,2,3 index for data
1574     LOGD("WebGL uniform location %{public}d [%{public}d %{public}d %{public}d %{public}d]",
1575         location, data[0], data[1], data[2], data[3]);
1576     switch (count) {
1577         case PARAMETERS_NUM_1:
1578             glUniform1i(location, data[0]);
1579             break;
1580         case PARAMETERS_NUM_2:
1581             glUniform2i(location, data[0], data[1]);
1582             break;
1583         case PARAMETERS_NUM_3:
1584             glUniform3i(location, data[0], data[1], data[2]); // 0, 1, 2 are array index
1585             break;
1586         case PARAMETERS_NUM_4:
1587             glUniform4i(location, data[0], data[1], data[2], data[3]); // 0, 1, 2, 3 are array index
1588             break;
1589         default:
1590             break;
1591     }
1592     return NVal::CreateNull(env).val_;
1593 }
1594 
UniformUi(napi_env env,napi_value locationObj,uint32_t count,const GLuint * data)1595 napi_value WebGLRenderingContextBaseImpl::UniformUi(
1596     napi_env env, napi_value locationObj, uint32_t count, const GLuint* data)
1597 {
1598     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1599     if (webGLUniformLocation == nullptr) {
1600         LOGE("WebGL uniform_ui can not find uniform");
1601         return NVal::CreateNull(env).val_;
1602     }
1603     GLint location = webGLUniformLocation->GetUniformLocationId();
1604     LOGD("WebGL uniformXui location %{public}d [%{public}u %{public}u %{public}u %{public}u]",
1605         location, data[0], data[1], data[2], data[3]); // 0,1,2,3 index for data
1606     switch (count) {
1607         case PARAMETERS_NUM_1:
1608             glUniform1ui(location, data[0]);
1609             break;
1610         case PARAMETERS_NUM_2:
1611             glUniform2ui(location, data[0], data[1]);
1612             break;
1613         case PARAMETERS_NUM_3:
1614             glUniform3ui(location, data[0], data[1], data[2]); // 0, 1, 2 are array index
1615             break;
1616         case PARAMETERS_NUM_4:
1617             glUniform4ui(location, data[0], data[1], data[2], data[3]); // 0, 1, 2, 3 are array index
1618             break;
1619         default:
1620             break;
1621     }
1622     LOGD("WebGL uniformXui result %{public}u", GetError_());
1623     return NVal::CreateNull(env).val_;
1624 }
1625 
1626 template<class T>
CheckUniformDataInfo(bool isHighWebGL,const WebGLReadBufferArg & readData,const UniformExtInfo * info)1627 static std::tuple<GLenum, GLsizei, T*> CheckUniformDataInfo(
1628     bool isHighWebGL, const WebGLReadBufferArg& readData, const UniformExtInfo* info)
1629 {
1630     GLuint count = static_cast<GLuint>(readData.GetBufferLength() / sizeof(T));
1631     T* srcData = reinterpret_cast<T*>(readData.GetBuffer());
1632     LOGD("WebGL CheckUniformDataInfo count %{public}u length %{public}zu %{public}zu Offset %{public}zu %{public}zu",
1633          static_cast<unsigned int>(count), static_cast<size_t>(readData.GetBufferLength()),
1634          static_cast<size_t>(info->elemCount), static_cast<size_t>(info->srcOffset),
1635          static_cast<size_t>(info->srcLength));
1636     if (isHighWebGL) {
1637         if (count <= info->srcOffset || count < info->srcLength) {
1638             return make_tuple(WebGLRenderingContextBase::INVALID_VALUE, 0, nullptr);
1639         }
1640         count = info->srcLength != 0 ? info->srcLength : count - info->srcOffset;
1641         srcData = srcData + info->srcOffset;
1642     }
1643     if (count % info->elemCount) {
1644         return make_tuple(WebGLRenderingContextBase::INVALID_VALUE, 0, nullptr);
1645     }
1646     if (count != info->elemCount) {
1647         return make_tuple(WebGLRenderingContextBase::INVALID_OPERATION, 0, nullptr);
1648     }
1649     return make_tuple(WebGLRenderingContextBase::NO_ERROR, count, srcData);
1650 }
1651 
UniformFv(napi_env env,napi_value locationObj,napi_value data,const UniformExtInfo * info)1652 napi_value WebGLRenderingContextBaseImpl::UniformFv(
1653     napi_env env, napi_value locationObj, napi_value data, const UniformExtInfo* info)
1654 {
1655     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1656     if (webGLUniformLocation == nullptr) {
1657         LOGE("WebGL uniform_fv can not find uniform");
1658         return NVal::CreateNull(env).val_;
1659     }
1660     GLint location = webGLUniformLocation->GetUniformLocationId();
1661 
1662     WebGLReadBufferArg readData(env);
1663     napi_status status = readData.GenBufferData(data, BUFFER_DATA_FLOAT_32);
1664     if (status != napi_ok) {
1665         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GenBufferData failed.");
1666         return NVal::CreateNull(env).val_;
1667     }
1668     readData.DumpBuffer(readData.GetBufferDataType());
1669     if (readData.GetBufferDataType() != BUFFER_DATA_FLOAT_32) {
1670         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GetBufferDataType failed. %{public}d",
1671             readData.GetBufferDataType());
1672         return NVal::CreateNull(env).val_;
1673     }
1674     GLenum result = 0;
1675     GLsizei count = 0;
1676     GLfloat* srcData = nullptr;
1677     std::tie(result, count, srcData) = CheckUniformDataInfo<GLfloat>(IsHighWebGL(), readData, info);
1678     if (result) {
1679         SET_ERROR(result);
1680         return NVal::CreateNull(env).val_;
1681     }
1682 
1683     switch (info->dimension) {
1684         case PARAMETERS_NUM_1:
1685             glUniform1fv(location, 1, srcData);
1686             break;
1687         case PARAMETERS_NUM_2:
1688             glUniform2fv(location, count / 2, srcData); // 2 array size
1689             break;
1690         case PARAMETERS_NUM_3:
1691             glUniform3fv(location, count / 3, srcData); // 3 array size
1692             break;
1693         case PARAMETERS_NUM_4:
1694             glUniform4fv(location, count / 4, srcData); // 4 array size
1695             break;
1696         default:
1697             break;
1698     }
1699     return NVal::CreateNull(env).val_;
1700 }
1701 
UniformIv(napi_env env,napi_value locationObj,napi_value data,const UniformExtInfo * info)1702 napi_value WebGLRenderingContextBaseImpl::UniformIv(
1703     napi_env env, napi_value locationObj, napi_value data, const UniformExtInfo* info)
1704 {
1705     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1706     if (webGLUniformLocation == nullptr) {
1707         LOGE("WebGL UniformIv can not find uniform");
1708         return NVal::CreateNull(env).val_;
1709     }
1710     GLint location = webGLUniformLocation->GetUniformLocationId();
1711 
1712     WebGLReadBufferArg readData(env);
1713     napi_status status = readData.GenBufferData(data, BUFFER_DATA_INT_32);
1714     if (status != napi_ok) {
1715         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL UniformIv failed to getbuffer data");
1716         return NVal::CreateNull(env).val_;
1717     }
1718     readData.DumpBuffer(readData.GetBufferDataType());
1719     if (readData.GetBufferDataType() != BUFFER_DATA_INT_32) {
1720         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1721             "WebGL UniformIv not support data type %{public}d", readData.GetBufferDataType());
1722         return NVal::CreateNull(env).val_;
1723     }
1724     GLenum result = 0;
1725     GLsizei count = 0;
1726     GLint* srcData = nullptr;
1727     std::tie(result, count, srcData) = CheckUniformDataInfo<GLint>(IsHighWebGL(), readData, info);
1728     if (result) {
1729         SET_ERROR(result);
1730         return NVal::CreateNull(env).val_;
1731     }
1732     switch (info->dimension) {
1733         case PARAMETERS_NUM_1:
1734             glUniform1iv(location, 1, srcData);
1735             break;
1736         case PARAMETERS_NUM_2:
1737             glUniform2iv(location, count / 2, srcData); // 2 array size
1738             break;
1739         case PARAMETERS_NUM_3:
1740             glUniform3iv(location, count / 3, srcData); // 3 array size
1741             break;
1742         case PARAMETERS_NUM_4:
1743             glUniform4iv(location, count / 4, srcData); // 4 array size
1744             break;
1745         default:
1746             break;
1747     }
1748     return NVal::CreateNull(env).val_;
1749 }
1750 
UniformUiv(napi_env env,napi_value locationObj,napi_value dataObj,const UniformExtInfo * info)1751 napi_value WebGLRenderingContextBaseImpl::UniformUiv(
1752     napi_env env, napi_value locationObj, napi_value dataObj, const UniformExtInfo* info)
1753 {
1754     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1755     if (webGLUniformLocation == nullptr) {
1756         LOGE("WebGL uniform_uiv can not find uniform");
1757         return NVal::CreateNull(env).val_;
1758     }
1759     GLint location = webGLUniformLocation->GetUniformLocationId();
1760 
1761     WebGLReadBufferArg readData(env);
1762     napi_status status = readData.GenBufferData(dataObj, BUFFER_DATA_UINT_32);
1763     if (status != napi_ok) {
1764         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GenBufferData failed.");
1765         return NVal::CreateNull(env).val_;
1766     }
1767     readData.DumpBuffer(readData.GetBufferDataType());
1768     if (readData.GetBufferDataType() != BUFFER_DATA_UINT_32) {
1769         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GetBufferDataType failed. %{public}d",
1770             readData.GetBufferDataType());
1771         return NVal::CreateNull(env).val_;
1772     }
1773     GLenum result = 0;
1774     GLsizei count = 0;
1775     GLuint* srcData = nullptr;
1776     std::tie(result, count, srcData) = CheckUniformDataInfo<GLuint>(IsHighWebGL(), readData, info);
1777     if (result) {
1778         SET_ERROR(result);
1779         return NVal::CreateNull(env).val_;
1780     }
1781     switch (info->dimension) {
1782         case PARAMETERS_NUM_1:
1783             glUniform1uiv(location, 1, srcData);
1784             break;
1785         case PARAMETERS_NUM_2:
1786             glUniform2uiv(location, count / PARAMETERS_NUM_2, srcData);
1787             break;;
1788         case PARAMETERS_NUM_3:
1789             glUniform3uiv(location, count / PARAMETERS_NUM_3, srcData);
1790             break;
1791         case PARAMETERS_NUM_4:
1792             glUniform4uiv(location, count / PARAMETERS_NUM_4, srcData);
1793             break;
1794         default:
1795             break;
1796     }
1797     return NVal::CreateNull(env).val_;
1798 }
1799 
HandleUniformMatrixInfo(GLboolean transpose,const UniformExtInfo * info,GLint location,GLsizei count,GLfloat * srcData)1800 void WebGLRenderingContextBaseImpl::HandleUniformMatrixInfo(
1801     GLboolean transpose, const UniformExtInfo* info, GLint location, GLsizei count, GLfloat* srcData)
1802 {
1803     switch (info->dimension) {
1804         case WebGLArg::MATRIX_2X2_REQUIRE_MIN_SIZE:
1805             glUniformMatrix2fv(location, count / 4, transpose, srcData); // 4 is 2x2
1806             break;
1807         case WebGLArg::MATRIX_3X3_REQUIRE_MIN_SIZE:
1808             glUniformMatrix3fv(location, count / 8, transpose, srcData); // 8 is 2x2x2
1809             break;
1810         case WebGLArg::MATRIX_4X4_REQUIRE_MIN_SIZE:
1811             glUniformMatrix4fv(location, count / 16, transpose, srcData); // 16 is 2x2x2x2
1812             break;
1813         case WebGLArg::MATRIX_3X2_REQUIRE_MIN_SIZE:
1814             glUniformMatrix3x2fv(location, count / 6, transpose, srcData); // 6 matrix
1815             break;
1816         case WebGLArg::MATRIX_4X2_REQUIRE_MIN_SIZE:
1817             glUniformMatrix4x2fv(location, count / 8, transpose, srcData); // 8 matrix
1818             break;
1819         case WebGLArg::MATRIX_2X3_REQUIRE_MIN_SIZE:
1820             glUniformMatrix2x3fv(location, count / 6, transpose, srcData); // 6 matrix
1821             break;
1822         case WebGLArg::MATRIX_4X3_REQUIRE_MIN_SIZE:
1823             glUniformMatrix4x3fv(location, count / 12, transpose, srcData); // 12 matrix
1824             break;
1825         case WebGLArg::MATRIX_2X4_REQUIRE_MIN_SIZE:
1826             glUniformMatrix2x4fv(location, count / 8, transpose, srcData); // 8 matrix
1827             break;
1828         case WebGLArg::MATRIX_3X4_REQUIRE_MIN_SIZE:
1829             glUniformMatrix3x4fv(location, count / 12, transpose, srcData); // 12 matrix
1830             break;
1831         default:
1832             break;
1833     }
1834 }
1835 
UniformMatrixFv(napi_env env,napi_value locationObj,napi_value data,GLboolean transpose,const UniformExtInfo * info)1836 napi_value WebGLRenderingContextBaseImpl::UniformMatrixFv(
1837     napi_env env, napi_value locationObj, napi_value data, GLboolean transpose, const UniformExtInfo* info)
1838 {
1839     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, locationObj);
1840     if (webGLUniformLocation == nullptr) {
1841         LOGE("WebGL uniformMatrix_fv can not find uniform");
1842         return NVal::CreateNull(env).val_;
1843     }
1844     GLint location = webGLUniformLocation->GetUniformLocationId();
1845 
1846     WebGLReadBufferArg readData(env);
1847     napi_status status = readData.GenBufferData(data, BUFFER_DATA_FLOAT_32);
1848     if (status != napi_ok) {
1849         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1850             "WebGL uniformMatrix_fv failed to getbuffer data");
1851         return NVal::CreateNull(env).val_;
1852     }
1853     readData.DumpBuffer(readData.GetBufferDataType());
1854 
1855     if (readData.GetBufferDataType() != BUFFER_DATA_FLOAT_32) {
1856         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
1857             "WebGL uniformMatrix_fv not support data type %{public}d", readData.GetBufferDataType());
1858         return NVal::CreateNull(env).val_;
1859     }
1860     GLenum result = 0;
1861     GLsizei count = 0;
1862     GLfloat* srcData = nullptr;
1863     std::tie(result, count, srcData) = CheckUniformDataInfo<GLfloat>(IsHighWebGL(), readData, info);
1864     if (result) {
1865         SET_ERROR(result);
1866         return NVal::CreateNull(env).val_;
1867     }
1868     HandleUniformMatrixInfo(transpose, info, location, count, srcData);
1869     LOGD("WebGL uniformMatrix_fv location %{public}d result %{public}u", location, GetError_());
1870     return NVal::CreateNull(env).val_;
1871 }
1872 
CheckFrameBufferStatus(napi_env env,GLenum target)1873 napi_value WebGLRenderingContextBaseImpl::CheckFrameBufferStatus(napi_env env, GLenum target)
1874 {
1875     uint32_t index = 0;
1876     if (!CheckFrameBufferTarget(env, target, index)) {
1877         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1878         return NVal::CreateInt64(env, 0).val_;
1879     }
1880     WebGLFramebuffer* framebufferBinding = GetBoundFrameBuffer(env, target);
1881     if (!framebufferBinding) {
1882         return NVal::CreateInt64(env, WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE).val_;
1883     }
1884     GLenum result = framebufferBinding->CheckStatus(env, this);
1885     if (result != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
1886         return NVal::CreateInt64(env, static_cast<int64_t>(result)).val_;
1887     }
1888     result = glCheckFramebufferStatus(target);
1889     LOGD("WebGL checkFramebufferStatus target %{public}u result %{public}u", target, result);
1890     return NVal::CreateInt64(env, static_cast<int64_t>(result)).val_;
1891 }
1892 
DepthMask(napi_env env,bool flag)1893 napi_value WebGLRenderingContextBaseImpl::DepthMask(napi_env env, bool flag)
1894 {
1895     LOGD("WebGL depthMask flag %{public}d", flag);
1896     depthMask_ = flag;
1897     glDepthMask(static_cast<GLboolean>(flag));
1898     return NVal::CreateNull(env).val_;
1899 }
1900 
StencilMask(napi_env env,GLuint mask)1901 napi_value WebGLRenderingContextBaseImpl::StencilMask(napi_env env, GLuint mask)
1902 {
1903     LOGD("WebGL stencilMask mask %{public}u", mask);
1904     stencilMask_[0] = mask;
1905     stencilMask_[1] = mask;
1906     glStencilMask(mask);
1907     return NVal::CreateNull(env).val_;
1908 }
1909 
StencilMaskSeparate(napi_env env,GLenum face,GLuint mask)1910 napi_value WebGLRenderingContextBaseImpl::StencilMaskSeparate(napi_env env, GLenum face, GLuint mask)
1911 {
1912     LOGD("WebGL stencilMaskSeparate face %{public}u mask %{public}u", face, mask);
1913     switch (face) {
1914         case WebGLRenderingContextBase::FRONT_AND_BACK: {
1915             stencilMask_[0] = mask;
1916             stencilMask_[1] = mask;
1917             break;
1918         }
1919         case WebGLRenderingContextBase::FRONT:
1920             stencilMask_[0] = mask;
1921             break;
1922         case WebGLRenderingContextBase::BACK:
1923             stencilMask_[1] = mask;
1924             break;
1925         default:
1926             SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1927             return NVal::CreateNull(env).val_;
1928     }
1929     glStencilMaskSeparate(face, mask);
1930     return NVal::CreateNull(env).val_;
1931 }
1932 
StencilFunc(napi_env env,GLenum func,GLint ref,GLuint mask)1933 napi_value WebGLRenderingContextBaseImpl::StencilFunc(napi_env env, GLenum func, GLint ref, GLuint mask)
1934 {
1935     LOGD("WebGL stencilFunc func %{public}u %{public}d %{public}u", func, ref, mask);
1936     if (!CheckGLenum(func,
1937         { WebGLRenderingContextBase::NEVER, WebGLRenderingContextBase::LESS, WebGLRenderingContextBase::EQUAL,
1938             WebGLRenderingContextBase::LEQUAL, WebGLRenderingContextBase::GREATER,
1939             WebGLRenderingContextBase::NOTEQUAL, WebGLRenderingContextBase::GEQUAL,
1940             WebGLRenderingContextBase::ALWAYS }, {})) {
1941         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1942         return NVal::CreateNull(env).val_;
1943     }
1944     stencilFuncRef_[0] = ref;
1945     stencilFuncRef_[1] = ref;
1946     stencilFuncMask_[0] = mask;
1947     stencilFuncMask_[1] = mask;
1948     glStencilFunc(func, ref, mask);
1949     return NVal::CreateNull(env).val_;
1950 }
1951 
StencilFuncSeparate(napi_env env,GLenum face,GLenum func,GLint ref,GLuint mask)1952 napi_value WebGLRenderingContextBaseImpl::StencilFuncSeparate(
1953     napi_env env, GLenum face, GLenum func, GLint ref, GLuint mask)
1954 {
1955     LOGD("WebGL stencilFuncSeparate face %{public}u func %{public}u %{public}d %{public}u", face, func, ref, mask);
1956     switch (face) {
1957         case WebGLRenderingContextBase::FRONT_AND_BACK: {
1958             stencilFuncRef_[0] = ref;
1959             stencilFuncRef_[1] = ref;
1960             stencilFuncMask_[0] = mask;
1961             stencilFuncMask_[1] = mask;
1962             break;
1963         }
1964         case WebGLRenderingContextBase::FRONT: {
1965             stencilFuncRef_[0] = ref;
1966             stencilFuncMask_[0] = mask;
1967             break;
1968         }
1969         case WebGLRenderingContextBase::BACK: {
1970             stencilFuncRef_[1] = ref;
1971             stencilFuncMask_[1] = mask;
1972             break;
1973         }
1974         default:
1975             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "invalid face %{public}u", face);
1976             return NVal::CreateNull(env).val_;
1977     }
1978     if (!CheckGLenum(func,
1979         { WebGLRenderingContextBase::NEVER, WebGLRenderingContextBase::LESS, WebGLRenderingContextBase::EQUAL,
1980             WebGLRenderingContextBase::LEQUAL, WebGLRenderingContextBase::GREATER,
1981             WebGLRenderingContextBase::NOTEQUAL, WebGLRenderingContextBase::GEQUAL,
1982             WebGLRenderingContextBase::ALWAYS }, {})) {
1983         SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
1984         return NVal::CreateNull(env).val_;
1985     }
1986     glStencilFuncSeparate(face, func, ref, mask);
1987     return NVal::CreateNull(env).val_;
1988 }
1989 
1990 template<class T>
CheckTexParameter(napi_env env,GLenum target,GLenum pname,T param,bool isFloat)1991 GLenum WebGLRenderingContextBaseImpl::CheckTexParameter(
1992     napi_env env, GLenum target, GLenum pname, T param, bool isFloat)
1993 {
1994     WebGLTexture* textuer = GetBoundTexture(env, target, false);
1995     if (textuer == nullptr) {
1996         return WebGLRenderingContextBase::INVALID_VALUE;
1997     }
1998 
1999     switch (pname) {
2000         case WebGLRenderingContextBase::TEXTURE_MIN_FILTER:
2001         case WebGLRenderingContextBase::TEXTURE_MAG_FILTER:
2002             break;
2003         case WebGL2RenderingContextBase::TEXTURE_WRAP_R: {
2004             if (!IsHighWebGL()) {
2005                 return WebGLRenderingContextBase::INVALID_ENUM;
2006             }
2007             [[fallthrough]];
2008         }
2009         case WebGLRenderingContextBase::TEXTURE_WRAP_S:
2010         case WebGLRenderingContextBase::TEXTURE_WRAP_T: {
2011             if (param == WebGLRenderingContextBase::CLAMP_TO_EDGE ||
2012                 param == WebGLRenderingContextBase::MIRRORED_REPEAT || param == WebGLRenderingContextBase::REPEAT) {
2013                 break;
2014             }
2015             return WebGLRenderingContextBase::INVALID_ENUM;
2016         }
2017         case WebGL2RenderingContextBase::TEXTURE_COMPARE_FUNC:
2018         case WebGL2RenderingContextBase::TEXTURE_COMPARE_MODE:
2019         case WebGL2RenderingContextBase::TEXTURE_BASE_LEVEL:
2020         case WebGL2RenderingContextBase::TEXTURE_MAX_LEVEL:
2021         case WebGL2RenderingContextBase::TEXTURE_MAX_LOD:
2022         case WebGL2RenderingContextBase::TEXTURE_MIN_LOD: {
2023             if (!IsHighWebGL()) {
2024                 return WebGLRenderingContextBase::INVALID_ENUM;
2025             }
2026             break;
2027         }
2028         default:
2029             return WebGLRenderingContextBase::INVALID_ENUM;
2030     }
2031     return WebGLRenderingContextBase::NO_ERROR;
2032 }
2033 
TexParameteri(napi_env env,GLenum target,GLenum pname,GLint param)2034 napi_value WebGLRenderingContextBaseImpl::TexParameteri(napi_env env, GLenum target, GLenum pname, GLint param)
2035 {
2036     GLenum result = CheckTexParameter<GLint>(env, target, pname, param, false);
2037     if (result != WebGLRenderingContextBase::NO_ERROR) {
2038         SET_ERROR(result);
2039         return NVal::CreateNull(env).val_;
2040     }
2041     glTexParameteri(target, pname, static_cast<GLint>(param));
2042     LOGD("WebGL texParameteri target %{public}u %{public}u %{public}d result %{public}u ",
2043         target, pname, param, GetError_());
2044     return NVal::CreateNull(env).val_;
2045 }
2046 
TexParameterf(napi_env env,GLenum target,GLenum pname,GLfloat param)2047 napi_value WebGLRenderingContextBaseImpl::TexParameterf(napi_env env, GLenum target, GLenum pname, GLfloat param)
2048 {
2049     GLenum result = CheckTexParameter<GLfloat>(env, target, pname, param, false);
2050     if (result != WebGLRenderingContextBase::NO_ERROR) {
2051         SET_ERROR(result);
2052         return NVal::CreateNull(env).val_;
2053     }
2054     glTexParameterf(target, pname, static_cast<GLfloat>(param));
2055     LOGD("WebGL texParameterf target %{public}u %{public}u %{public}f result %{public}u ",
2056         target, pname, param, GetError_());
2057     return NVal::CreateNull(env).val_;
2058 }
2059 
GetTexParameter(napi_env env,GLenum target,GLenum pname)2060 napi_value WebGLRenderingContextBaseImpl::GetTexParameter(napi_env env, GLenum target, GLenum pname)
2061 {
2062     WebGLTexture* texture = GetBoundTexture(env, target, false);
2063     if (!texture) {
2064         return NVal::CreateNull(env).val_;
2065     }
2066     if (IsHighWebGL()) {
2067         switch (pname) {
2068             case GL_TEXTURE_WRAP_R:
2069             case GL_TEXTURE_COMPARE_FUNC:
2070             case GL_TEXTURE_COMPARE_MODE:
2071             case GL_TEXTURE_BASE_LEVEL:
2072             case GL_TEXTURE_MAX_LEVEL:
2073             case GL_TEXTURE_IMMUTABLE_LEVELS: {
2074                 GLint params = 0;
2075                 glGetTexParameteriv(target, pname, &params);
2076                 return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
2077             }
2078             case GL_TEXTURE_IMMUTABLE_FORMAT: {
2079                 GLint params = 0;
2080                 glGetTexParameteriv(target, pname, &params);
2081                 return NVal::CreateBool(env, params == 1).val_;
2082             }
2083             case GL_TEXTURE_MAX_LOD:
2084             case GL_TEXTURE_MIN_LOD: {
2085                 GLfloat params = 0.f;
2086                 glGetTexParameterfv(target, pname, &params);
2087                 return NVal::CreateDouble(env, static_cast<double>(params)).val_;
2088             }
2089             default:
2090                 break;
2091         }
2092     }
2093 
2094     switch (pname) {
2095         case WebGLRenderingContextBase::TEXTURE_MAG_FILTER:
2096         case WebGLRenderingContextBase::TEXTURE_MIN_FILTER:
2097         case WebGLRenderingContextBase::TEXTURE_WRAP_S:
2098         case WebGLRenderingContextBase::TEXTURE_WRAP_T: {
2099             GLint params = 0;
2100             glGetTexParameteriv(target, pname, &params);
2101             LOGD("WebGL getTexParameter params %{public}d", params);
2102             return NVal::CreateInt64(env, static_cast<int64_t>(params)).val_;
2103         }
2104         default:
2105             SET_ERROR(WebGLRenderingContextBase::INVALID_ENUM);
2106             return NVal::CreateNull(env).val_;
2107     }
2108 }
2109 
VertexAttribfv(napi_env env,GLuint index,int32_t count,napi_value dataObj)2110 napi_value WebGLRenderingContextBaseImpl::VertexAttribfv(napi_env env, GLuint index, int32_t count, napi_value dataObj)
2111 {
2112     LOGD("WebGL vertexAttribfv index %{public}u %{public}d", index, count);
2113     WebGLReadBufferArg bufferData(env);
2114     napi_status status = bufferData.GenBufferData(dataObj, BUFFER_DATA_FLOAT_32);
2115     if (status != 0) {
2116         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL vertexAttribfv failed to getbuffer data");
2117         return NVal::CreateNull(env).val_;
2118     }
2119     bufferData.DumpBuffer(bufferData.GetBufferDataType());
2120     if (bufferData.GetBufferDataType() != BUFFER_DATA_FLOAT_32) {
2121         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
2122             "WebGL :vertexAttribfv invalid buffer data type = %{public}d",
2123             static_cast<uint32_t>(bufferData.GetBufferDataType()));
2124         return NVal::CreateNull(env).val_;
2125     }
2126 
2127     if (static_cast<int32_t>(bufferData.GetBufferLength() / sizeof(float)) < count) {
2128         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
2129             "WebGL vertexAttribfv invalid data length %{public}zu", bufferData.GetBufferLength());
2130         return NVal::CreateNull(env).val_;
2131     }
2132     VertexAttribInfo* info = GetVertexAttribInfo(index);
2133     if (info == nullptr) {
2134         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
2135         return NVal::CreateNull(env).val_;
2136     }
2137 
2138     switch (count) {
2139         case PARAMETERS_NUM_1:
2140             glVertexAttrib1fv(index, reinterpret_cast<GLfloat*>(bufferData.GetBuffer()));
2141             break;
2142         case PARAMETERS_NUM_2:
2143             glVertexAttrib2fv(index, reinterpret_cast<GLfloat*>(bufferData.GetBuffer()));
2144             break;
2145         case PARAMETERS_NUM_3:
2146             glVertexAttrib3fv(index, reinterpret_cast<GLfloat*>(bufferData.GetBuffer()));
2147             break;
2148         case PARAMETERS_NUM_4:
2149             glVertexAttrib4fv(index, reinterpret_cast<GLfloat*>(bufferData.GetBuffer()));
2150             break;
2151         default:
2152             break;
2153     }
2154     info->type = BUFFER_DATA_FLOAT_32;
2155     return NVal::CreateNull(env).val_;
2156 }
2157 
VertexAttribf(napi_env env,GLuint index,int32_t count,GLfloat * data)2158 napi_value WebGLRenderingContextBaseImpl::VertexAttribf(napi_env env, GLuint index, int32_t count, GLfloat* data)
2159 {
2160     VertexAttribInfo* info = GetVertexAttribInfo(index);
2161     if (info == nullptr) {
2162         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
2163         return NVal::CreateNull(env).val_;
2164     }
2165     // In GL, we skip setting vertexAttrib0 values.
2166     switch (count) {
2167         case PARAMETERS_NUM_1:
2168             glVertexAttrib1f(index, data[0]);
2169             break;
2170         case PARAMETERS_NUM_2:
2171             glVertexAttrib2f(index, data[0], data[1]);
2172             break;
2173         case PARAMETERS_NUM_3:
2174             glVertexAttrib3f(index, data[0], data[1], data[2]); // 1, 2 index
2175             break;
2176         case PARAMETERS_NUM_4:
2177             glVertexAttrib4f(index, data[0], data[1], data[2], data[3]); // 1, 2, 3 index
2178             break;
2179         default:
2180             break;
2181     }
2182     LOGD("WebGL vertexAttribf index %{public}u count %{public}d result %{public}u", index, count, GetError_());
2183     info->type = BUFFER_DATA_FLOAT_32;
2184     return NVal::CreateNull(env).val_;
2185 }
2186 
GetUniformType(napi_env env,GLuint programId,GLint locationId)2187 GLenum WebGLRenderingContextBaseImpl::GetUniformType(napi_env env, GLuint programId, GLint locationId)
2188 {
2189     GLint maxNameLength = -1;
2190     glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
2191     if (maxNameLength <= 0) {
2192         return 0;
2193     }
2194 
2195     GLint activeUniforms = 0;
2196     glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &activeUniforms);
2197     LOGD("WebGL getUniform maxNameLength %{public}d activeUniforms %{public}d", maxNameLength, activeUniforms);
2198     if (locationId >= activeUniforms) {
2199         return 0;
2200     }
2201     GLenum type = 0;
2202     std::vector<GLchar> name(maxNameLength + 1);
2203     name[maxNameLength] = '\0';
2204     for (int32_t i = 0; i < activeUniforms; i++) {
2205         GLsizei nameLength = 0;
2206         GLint size = -1;
2207         glGetActiveUniform(programId, i, maxNameLength, &nameLength, &size, &type, name.data());
2208         LOGD("WebGL getUniform index %{public}d type 0x%{public}x name %{public}s ", i, type, name.data());
2209         if (locationId == i) {
2210             break;
2211         }
2212     }
2213     return type;
2214 }
2215 
GetUniform(napi_env env,napi_value programObj,napi_value uniformObj)2216 napi_value WebGLRenderingContextBaseImpl::GetUniform(napi_env env, napi_value programObj, napi_value uniformObj)
2217 {
2218     WebGLProgram* webGLProgram = WebGLProgram::GetObjectInstance(env, programObj);
2219     WebGLUniformLocation* webGLUniformLocation = WebGLUniformLocation::GetObjectInstance(env, uniformObj);
2220     if (webGLUniformLocation == nullptr || webGLProgram == nullptr) {
2221         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
2222             "webGLUniformLocation or webGLProgram is nullptr.");
2223         return NVal::CreateNull(env).val_;
2224     }
2225     GLuint programId = webGLProgram->GetProgramId();
2226     GLint locationId = webGLUniformLocation->GetUniformLocationId();
2227     const UniformTypeMap* typeMap = GetUniformTypeMap(GetUniformType(env, programId, locationId));
2228     if (typeMap == nullptr) {
2229         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "typeMap is nullptr.");
2230         return NVal::CreateNull(env).val_;
2231     }
2232     WebGLWriteBufferArg writeBuffer(env);
2233     GLint* data = reinterpret_cast<GLint*>(writeBuffer.AllocBuffer(typeMap->length * sizeof(GLfloat)));
2234     if (data == nullptr) {
2235         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "data is nullptr.");
2236         return NVal::CreateNull(env).val_;
2237     }
2238     switch (typeMap->baseType) {
2239         case GL_FLOAT: {
2240             GLfloat* params = reinterpret_cast<GLfloat*>(data);
2241             glGetUniformfv(programId, locationId, params);
2242             if (typeMap->length == 1) {
2243                 return NVal::CreateDouble(env, params[0]).val_;
2244             }
2245             break;
2246         }
2247         case GL_INT: {
2248             glGetUniformiv(programId, locationId, data);
2249             if (typeMap->length == 1) {
2250                 return NVal::CreateInt64(env, data[0]).val_;
2251             }
2252             break;
2253         }
2254         case GL_BOOL: {
2255             glGetUniformiv(programId, locationId, data);
2256             if (typeMap->length == 1) {
2257                 return NVal::CreateBool(env, data[0]).val_;
2258             }
2259             break;
2260         }
2261         case GL_UNSIGNED_INT: {
2262             GLuint* params = reinterpret_cast<GLuint*>(data);
2263             glGetUniformuiv(programId, locationId, params);
2264             if (typeMap->length == 1) {
2265                 return NVal::CreateInt64(env, params[0]).val_;
2266             }
2267             break;
2268         }
2269         default:
2270             break;
2271     }
2272     writeBuffer.DumpBuffer(typeMap->dstType);
2273     return writeBuffer.ToNormalArray(typeMap->srcType, typeMap->dstType);
2274 }
2275 
CheckGLenum(GLenum type,const std::vector<GLenum> & glSupport,const std::vector<GLenum> & g2Support)2276 bool WebGLRenderingContextBaseImpl::CheckGLenum(
2277     GLenum type, const std::vector<GLenum>& glSupport, const std::vector<GLenum>& g2Support)
2278 {
2279     auto it = std::find(glSupport.begin(), glSupport.end(), type);
2280     if (it != glSupport.end()) {
2281         return true;
2282     }
2283     if (!IsHighWebGL()) {
2284         return false;
2285     }
2286     auto it2 = std::find(g2Support.begin(), g2Support.end(), type);
2287     if (it2 != g2Support.end()) {
2288         return true;
2289     }
2290     return false;
2291 }
2292 
CheckInList(GLenum type,const std::vector<GLenum> & glSupport)2293 bool WebGLRenderingContextBaseImpl::CheckInList(GLenum type, const std::vector<GLenum>& glSupport)
2294 {
2295     auto it = std::find(glSupport.begin(), glSupport.end(), type);
2296     if (it != glSupport.end()) {
2297         return true;
2298     }
2299     return false;
2300 }
2301 
CheckCap(napi_env env,GLenum cap)2302 bool WebGLRenderingContextBaseImpl::CheckCap(napi_env env, GLenum cap)
2303 {
2304     return CheckGLenum(cap,
2305         { WebGLRenderingContextBase::BLEND, WebGLRenderingContextBase::CULL_FACE, WebGLRenderingContextBase::DEPTH_TEST,
2306             WebGLRenderingContextBase::DITHER, WebGLRenderingContextBase::POLYGON_OFFSET_FILL,
2307             WebGLRenderingContextBase::SAMPLE_ALPHA_TO_COVERAGE, WebGLRenderingContextBase::SAMPLE_COVERAGE,
2308             WebGLRenderingContextBase::SCISSOR_TEST, WebGLRenderingContextBase::STENCIL_TEST },
2309         { WebGL2RenderingContextBase::RASTERIZER_DISCARD });
2310 }
2311 
CheckInternalFormat(napi_env env,GLenum internalFormat)2312 bool WebGLRenderingContextBaseImpl::CheckInternalFormat(napi_env env, GLenum internalFormat)
2313 {
2314     static const std::vector<GLenum> glSupport = { WebGLRenderingContextBase::RGBA4, WebGLRenderingContextBase::RGB565,
2315         WebGLRenderingContextBase::RGB5_A1, WebGLRenderingContextBase::DEPTH_COMPONENT16,
2316         WebGLRenderingContextBase::STENCIL_INDEX8, WebGLRenderingContextBase::DEPTH_STENCIL };
2317     static const std::vector<GLenum> gl2Support = { WebGL2RenderingContextBase::R8, WebGL2RenderingContextBase::R8UI,
2318         WebGL2RenderingContextBase::R8I, WebGL2RenderingContextBase::R16UI, WebGL2RenderingContextBase::R16I,
2319         WebGL2RenderingContextBase::R32UI, WebGL2RenderingContextBase::R32I,
2320 
2321         WebGL2RenderingContextBase::RG8, WebGL2RenderingContextBase::RG8UI, WebGL2RenderingContextBase::RG8I,
2322         WebGL2RenderingContextBase::RG16UI, WebGL2RenderingContextBase::RG16I, WebGL2RenderingContextBase::RG32UI,
2323         WebGL2RenderingContextBase::RG32I,
2324 
2325         WebGL2RenderingContextBase::RGB8, WebGL2RenderingContextBase::RGBA8, WebGL2RenderingContextBase::SRGB8_ALPHA8,
2326         WebGL2RenderingContextBase::RGB10_A2, WebGL2RenderingContextBase::RGBA8UI, WebGL2RenderingContextBase::RGBA8I,
2327         WebGL2RenderingContextBase::RGB10_A2UI,
2328 
2329         WebGL2RenderingContextBase::RGBA16UI, WebGL2RenderingContextBase::RGBA16I, WebGL2RenderingContextBase::RGBA32I,
2330         WebGL2RenderingContextBase::RGBA32UI, WebGL2RenderingContextBase::DEPTH_COMPONENT24,
2331         WebGL2RenderingContextBase::DEPTH_COMPONENT32F, WebGL2RenderingContextBase::DEPTH24_STENCIL8,
2332         WebGL2RenderingContextBase::DEPTH32F_STENCIL8 };
2333     return CheckGLenum(internalFormat, glSupport, gl2Support);
2334 }
2335 
CheckAttachment(napi_env env,GLenum attachment)2336 bool WebGLRenderingContextBaseImpl::CheckAttachment(napi_env env, GLenum attachment)
2337 {
2338     static const std::vector<GLenum> glSupport = { WebGLRenderingContextBase::COLOR_ATTACHMENT0,
2339         WebGLRenderingContextBase::DEPTH_ATTACHMENT, WebGLRenderingContextBase::STENCIL_ATTACHMENT,
2340         WebGLRenderingContextBase::DEPTH_STENCIL_ATTACHMENT };
2341 
2342     if (!CheckGLenum(attachment, glSupport, {})) {
2343         if (IsHighWebGL()) {
2344             if (attachment < WebGLRenderingContextBase::COLOR_ATTACHMENT0 ||
2345                 attachment > WebGLRenderingContextBase::COLOR_ATTACHMENT0 +
2346                 static_cast<GLenum>(GetMaxColorAttachments())) {
2347                 return false;
2348             }
2349         }
2350     }
2351     return true;
2352 }
2353 
GetBoundTexture(napi_env env,GLenum target,bool cubeMapExt)2354 WebGLTexture* WebGLRenderingContextBaseImpl::GetBoundTexture(napi_env env, GLenum target, bool cubeMapExt)
2355 {
2356     uint32_t index = 0;
2357     switch (target) {
2358         case WebGLRenderingContextBase::TEXTURE_2D:
2359             index = BoundTextureType::TEXTURE_2D;
2360             break;
2361         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_X:
2362         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_X:
2363         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_Y:
2364         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_Y:
2365         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_Z:
2366         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_Z: {
2367             if (!cubeMapExt) {
2368                 return nullptr;
2369             }
2370             index = BoundTextureType::TEXTURE_CUBE_MAP;
2371             break;
2372         }
2373         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP: {
2374             if (cubeMapExt) {
2375                 return nullptr;
2376             }
2377             index = BoundTextureType::TEXTURE_CUBE_MAP;
2378             break;
2379         }
2380         case WebGL2RenderingContextBase::TEXTURE_2D_ARRAY: {
2381             if (!IsHighWebGL()) {
2382                 return nullptr;
2383             }
2384             index = BoundTextureType::TEXTURE_2D_ARRAY;
2385             break;
2386         }
2387         case WebGL2RenderingContextBase::TEXTURE_3D: {
2388             if (!IsHighWebGL()) {
2389                 return nullptr;
2390             }
2391             index = BoundTextureType::TEXTURE_3D;
2392             break;
2393         }
2394         default:
2395             return nullptr;
2396     }
2397     if (activeTextureIndex_ >= boundTexture_[index].size()) {
2398         return nullptr;
2399     }
2400 
2401     return GetObjectInstance<WebGLTexture>(env, boundTexture_[index][activeTextureIndex_]);
2402 }
2403 
GetBoundFrameBuffer(napi_env env,GLenum target)2404 WebGLFramebuffer* WebGLRenderingContextBaseImpl::GetBoundFrameBuffer(napi_env env, GLenum target)
2405 {
2406     uint32_t index = 0;
2407     if (!CheckFrameBufferTarget(env, target, index)) {
2408         return nullptr;
2409     }
2410     LOGD("Get bound Frame buffer target %{public}u id %{public}u ", target, boundFrameBufferIds_[index]);
2411     return GetObjectInstance<WebGLFramebuffer>(env, boundFrameBufferIds_[index]);
2412 }
2413 
GetBoundRenderBuffer(napi_env env,GLenum target)2414 WebGLRenderbuffer* WebGLRenderingContextBaseImpl::GetBoundRenderBuffer(napi_env env, GLenum target)
2415 {
2416     uint32_t index = 0;
2417     if (!CheckRenderBufferTarget(env, target, index)) {
2418         return nullptr;
2419     }
2420     LOGD("Get bound render buffer target %{public}u id %{public}u ", target, boundRenderBufferIds_[index]);
2421     return GetObjectInstance<WebGLRenderbuffer>(env, boundRenderBufferIds_[index]);
2422 }
2423 
GetBoundBuffer(napi_env env,GLenum target)2424 WebGLBuffer* WebGLRenderingContextBaseImpl::GetBoundBuffer(napi_env env, GLenum target)
2425 {
2426     uint32_t index = BoundBufferType::ARRAY_BUFFER;
2427     if (!CheckBufferTarget(env, target, index)) {
2428         return nullptr;
2429     }
2430     LOGD("Get bound buffer target %{public}u id %{public}u ", target, boundBufferIds_[index]);
2431     return GetObjectInstance<WebGLBuffer>(env, boundBufferIds_[index]);
2432 }
2433 
CheckDrawMode(napi_env env,GLenum mode)2434 bool WebGLRenderingContextBaseImpl::CheckDrawMode(napi_env env, GLenum mode)
2435 {
2436     return CheckGLenum(mode,
2437         {
2438             WebGLRenderingContextBase::POINTS,
2439             WebGLRenderingContextBase::LINE_STRIP,
2440             WebGLRenderingContextBase::LINE_LOOP,
2441             WebGLRenderingContextBase::LINES,
2442             WebGLRenderingContextBase::TRIANGLE_STRIP,
2443             WebGLRenderingContextBase::TRIANGLE_FAN,
2444             WebGLRenderingContextBase::TRIANGLES
2445         },
2446         {});
2447 }
2448 
CheckFrameBufferTarget(napi_env env,GLenum target,uint32_t & index)2449 bool WebGLRenderingContextBaseImpl::CheckFrameBufferTarget(napi_env env, GLenum target, uint32_t& index)
2450 {
2451     switch (target) {
2452         case WebGLRenderingContextBase::FRAMEBUFFER:
2453             index = BoundFrameBufferType::FRAMEBUFFER;
2454             return true;
2455         default:
2456             break;
2457     }
2458     if (!IsHighWebGL()) {
2459         return false;
2460     }
2461     switch (target) {
2462         case WebGL2RenderingContextBase::DRAW_FRAMEBUFFER:
2463             index = BoundFrameBufferType::DRAW_FRAMEBUFFER;
2464             return true;
2465         case WebGL2RenderingContextBase::READ_FRAMEBUFFER:
2466             index = BoundFrameBufferType::READ_FRAMEBUFFER;
2467             return true;
2468         default:
2469             break;
2470     }
2471     return false;
2472 }
2473 
CheckRenderBufferTarget(napi_env env,GLenum target,uint32_t & index)2474 bool WebGLRenderingContextBaseImpl::CheckRenderBufferTarget(napi_env env, GLenum target, uint32_t& index)
2475 {
2476     switch (target) {
2477         case WebGLRenderingContextBase::RENDERBUFFER:
2478             index = BoundRenderBufferType::RENDERBUFFER;
2479             return true;
2480         default:
2481             break;
2482     }
2483     return false;
2484 }
2485 
CheckTextureTarget(napi_env env,GLenum target,uint32_t & index)2486 bool WebGLRenderingContextBaseImpl::CheckTextureTarget(napi_env env, GLenum target, uint32_t& index)
2487 {
2488     switch (target) {
2489         case WebGLRenderingContextBase::TEXTURE_2D:
2490             index = BoundTextureType::TEXTURE_2D;
2491             break;
2492         case WebGLRenderingContextBase::TEXTURE_CUBE_MAP:
2493             index = BoundTextureType::TEXTURE_CUBE_MAP;
2494             break;
2495         case WebGL2RenderingContextBase::TEXTURE_3D:
2496             index = BoundTextureType::TEXTURE_3D;
2497             break;
2498         case WebGL2RenderingContextBase::TEXTURE_2D_ARRAY:
2499             index = BoundTextureType::TEXTURE_2D_ARRAY;
2500             break;
2501         default:
2502             if (IsHighWebGL()) {
2503                 break;
2504             }
2505             return false;
2506     }
2507     return true;
2508 }
2509 
CheckShaderType(napi_env env,GLenum type,uint32_t & index)2510 bool WebGLRenderingContextBaseImpl::CheckShaderType(napi_env env, GLenum type, uint32_t& index)
2511 {
2512     switch (type) {
2513         case WebGLRenderingContextBase::VERTEX_SHADER:
2514             index = BoundShaderType::VERTEX_SHADER;
2515             break;
2516         case WebGLRenderingContextBase::FRAGMENT_SHADER:
2517             index = BoundShaderType::FRAGMENT_SHADER;
2518             break;
2519         default:
2520             return false;
2521     }
2522     return true;
2523 }
2524 
CheckTexture2DTarget(napi_env env,GLenum target)2525 bool WebGLRenderingContextBaseImpl::CheckTexture2DTarget(napi_env env, GLenum target)
2526 {
2527     return CheckGLenum(target,
2528         { WebGLRenderingContextBase::TEXTURE_2D, WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_X,
2529             WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_X,
2530             WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_Y,
2531             WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_Y,
2532             WebGLRenderingContextBase::TEXTURE_CUBE_MAP_POSITIVE_Z,
2533             WebGLRenderingContextBase::TEXTURE_CUBE_MAP_NEGATIVE_Z },
2534         {});
2535 }
2536 
CheckBufferTarget(napi_env env,GLenum target,uint32_t & index)2537 bool WebGLRenderingContextBaseImpl::CheckBufferTarget(napi_env env, GLenum target, uint32_t& index)
2538 {
2539     switch (target) {
2540         case WebGLRenderingContextBase::ARRAY_BUFFER:
2541             index = BoundBufferType::ARRAY_BUFFER;
2542             break;
2543         case WebGLRenderingContextBase::ELEMENT_ARRAY_BUFFER:
2544             index = BoundBufferType::ELEMENT_ARRAY_BUFFER;
2545             break;
2546         case WebGL2RenderingContextBase::COPY_READ_BUFFER:
2547             index = BoundBufferType::COPY_READ_BUFFER;
2548             break;
2549         case WebGL2RenderingContextBase::COPY_WRITE_BUFFER:
2550             index = BoundBufferType::COPY_WRITE_BUFFER;
2551             break;
2552         case WebGL2RenderingContextBase::TRANSFORM_FEEDBACK_BUFFER:
2553             index = BoundBufferType::TRANSFORM_FEEDBACK_BUFFER;
2554             break;
2555         case WebGL2RenderingContextBase::UNIFORM_BUFFER:
2556             index = BoundBufferType::UNIFORM_BUFFER;
2557             break;
2558         case WebGL2RenderingContextBase::PIXEL_PACK_BUFFER:
2559             index = BoundBufferType::PIXEL_PACK_BUFFER;
2560             break;
2561         case WebGL2RenderingContextBase::PIXEL_UNPACK_BUFFER:
2562             index = BoundBufferType::PIXEL_UNPACK_BUFFER;
2563             break;
2564         default:
2565             if (IsHighWebGL()) {
2566                 break;
2567             }
2568             return false;
2569     }
2570     return true;
2571 }
2572 
CheckBufferDataUsage(napi_env env,GLenum usage)2573 bool WebGLRenderingContextBaseImpl::CheckBufferDataUsage(napi_env env, GLenum usage)
2574 {
2575     return CheckGLenum(usage, { GL_STREAM_DRAW, GL_STATIC_DRAW, GL_DYNAMIC_DRAW },
2576         { GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_READ, GL_DYNAMIC_COPY });
2577 }
2578 
CheckPixelsFormat(napi_env env,GLenum format)2579 bool WebGLRenderingContextBaseImpl::CheckPixelsFormat(napi_env env, GLenum format)
2580 {
2581     return CheckGLenum(format, { GL_ALPHA, GL_RGB, GL_RGBA },
2582         {
2583             GL_RED,
2584             GL_RED_INTEGER,
2585             GL_RG,
2586             GL_RG_INTEGER,
2587             GL_RGBA,
2588             GL_RGBA_INTEGER,
2589             GL_LUMINANCE_ALPHA,
2590             GL_LUMINANCE,
2591             GL_ALPHA,
2592             GL_RGB,
2593             GL_RGB_INTEGER,
2594         });
2595 }
2596 
CheckPixelsType(napi_env env,GLenum type)2597 bool WebGLRenderingContextBaseImpl::CheckPixelsType(napi_env env, GLenum type)
2598 {
2599     return CheckGLenum(type,
2600         { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1, GL_FLOAT,
2601             GL_HALF_FLOAT_OES },
2602         { GL_UNSIGNED_BYTE, GL_BYTE, GL_HALF_FLOAT, GL_FLOAT, GL_UNSIGNED_SHORT, GL_UNSIGNED_SHORT_5_6_5,
2603             GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1, GL_SHORT, GL_UNSIGNED_INT,
2604             GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV, GL_INT
2605         });
2606 }
2607 
CheckStencil(napi_env env)2608 bool WebGLRenderingContextBaseImpl::CheckStencil(napi_env env)
2609 {
2610     if (stencilMask_[0] != stencilMask_[1] || stencilFuncRef_[0] != stencilFuncRef_[1] ||
2611         stencilFuncMask_[0] != stencilFuncMask_[1]) {
2612         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
2613             "front and back stencils settings do not match");
2614         return false;
2615     }
2616     return true;
2617 }
2618 
CheckLocationName(const std::string & name)2619 bool WebGLRenderingContextBaseImpl::CheckLocationName(const std::string& name)
2620 {
2621     if (name.size() > MAX_LOCATION_LENGTH) {
2622         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "check name size failed.%{public}zu",
2623             name.size());
2624         return false;
2625     }
2626     if (!WebGLArg::CheckString(name)) {
2627         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "CheckString failed.");
2628         return false;
2629     }
2630     if (WebGLArg::CheckReservedPrefix(name)) {
2631         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "CheckReservedPrefix failed.");
2632         return false;
2633     }
2634     return true;
2635 }
2636 
CheckRenderBufferStorage(napi_env env,const TexStorageArg & arg)2637 WebGLRenderbuffer* WebGLRenderingContextBaseImpl::CheckRenderBufferStorage(napi_env env, const TexStorageArg& arg)
2638 {
2639     uint32_t index = 0;
2640     if (!CheckRenderBufferTarget(env, arg.target, index)) {
2641         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
2642             "WebGL renderbufferStorage invalid target %{public}u", arg.target);
2643         return nullptr;
2644     }
2645     if (!CheckInternalFormat(env, arg.internalFormat)) {
2646         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
2647             "WebGL renderbufferStorage invalid internalFormat %{public}u", arg.internalFormat);
2648         return nullptr;
2649     }
2650     if (arg.width < 0 || arg.height < 0) {
2651         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
2652             "WebGL renderbufferStorage invalid size %{public}d %{public}d", arg.width, arg.height);
2653         return nullptr;
2654     }
2655     WebGLRenderbuffer* renderBuffer = GetObjectInstance<WebGLRenderbuffer>(env, boundRenderBufferIds_[index]);
2656     if (renderBuffer == nullptr) {
2657         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
2658             "WebGL renderbufferStorage can not get bound render buffer Id %{public}u", boundRenderBufferIds_[index]);
2659         return nullptr;
2660     }
2661     return renderBuffer;
2662 }
2663 
CheckProgramLinkStatus(WebGLProgram * program)2664 bool WebGLRenderingContextBaseImpl::CheckProgramLinkStatus(WebGLProgram* program)
2665 {
2666     if (program == nullptr) {
2667         return false;
2668     }
2669     GLint params = 0;
2670     glGetProgramiv(static_cast<GLuint>(program->GetProgramId()), WebGLRenderingContextBase::LINK_STATUS, &params);
2671     if (params) {
2672         return true;
2673     }
2674     return false;
2675 }
2676 
GetUniformTypeMap(GLenum type)2677 const UniformTypeMap* WebGLRenderingContextBaseImpl::GetUniformTypeMap(GLenum type)
2678 {
2679     const static UniformTypeMap baseTypeMap[] = {
2680         { GL_FLOAT, GL_FLOAT, 1, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2681         { GL_FLOAT_VEC2, GL_FLOAT, 2, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2682         { GL_FLOAT_VEC3, GL_FLOAT, 3, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2683         { GL_FLOAT_VEC4, GL_FLOAT, 4, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2684         { GL_FLOAT_MAT2, GL_FLOAT, 4, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2685         { GL_FLOAT_MAT3, GL_FLOAT, 9, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2686         { GL_FLOAT_MAT4, GL_FLOAT, 16, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2687 
2688         { GL_INT, GL_INT, 1, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2689         { GL_INT_VEC2, GL_INT, 2, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2690         { GL_INT_VEC3, GL_INT, 3, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2691         { GL_INT_VEC4, GL_INT, 4, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2692 
2693         { GL_BOOL, GL_BOOL, 1, BUFFER_DATA_INT_32, BUFFER_DATA_BOOLEAN },
2694         { GL_BOOL_VEC2, GL_BOOL, 2, BUFFER_DATA_INT_32, BUFFER_DATA_BOOLEAN },
2695         { GL_BOOL_VEC3, GL_BOOL, 3, BUFFER_DATA_INT_32, BUFFER_DATA_BOOLEAN },
2696         { GL_BOOL_VEC4, GL_BOOL, 4, BUFFER_DATA_INT_32, BUFFER_DATA_BOOLEAN },
2697 
2698         { GL_SAMPLER_2D, GL_INT, 1, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2699         { GL_SAMPLER_CUBE, GL_INT, 1, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2700     };
2701 
2702     const static UniformTypeMap webgl2BaseTypeMap[] = {
2703         { GL_UNSIGNED_INT, GL_UNSIGNED_INT, 1, BUFFER_DATA_UINT_32, BUFFER_DATA_UINT_32 },
2704         { GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT, 2, BUFFER_DATA_UINT_32, BUFFER_DATA_UINT_32 },
2705         { GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT, 3, BUFFER_DATA_UINT_32, BUFFER_DATA_UINT_32 },
2706         { GL_UNSIGNED_INT_VEC4, GL_UNSIGNED_INT, 4, BUFFER_DATA_UINT_32, BUFFER_DATA_UINT_32 },
2707 
2708         { GL_FLOAT_MAT2x3, GL_FLOAT, 6, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2709         { GL_FLOAT_MAT2x4, GL_FLOAT, 8, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2710         { GL_FLOAT_MAT3x2, GL_FLOAT, 6, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2711         { GL_FLOAT_MAT3x4, GL_FLOAT, 12, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2712         { GL_FLOAT_MAT4x2, GL_FLOAT, 8, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2713         { GL_FLOAT_MAT4x3, GL_FLOAT, 12, BUFFER_DATA_FLOAT_32, BUFFER_DATA_FLOAT_32 },
2714 
2715         { GL_SAMPLER_3D, GL_INT, 1, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2716         { GL_SAMPLER_2D_ARRAY, GL_INT, 1, BUFFER_DATA_INT_32, BUFFER_DATA_INT_32 },
2717     };
2718     for (size_t i = 0; i < sizeof(baseTypeMap) / sizeof(baseTypeMap[0]); i++) {
2719         if (baseTypeMap[i].type == type) {
2720             return &baseTypeMap[i];
2721         }
2722     }
2723     if (!IsHighWebGL()) {
2724         return nullptr;
2725     }
2726     for (size_t i = 0; i < sizeof(webgl2BaseTypeMap) / sizeof(webgl2BaseTypeMap[0]); i++) {
2727         if (webgl2BaseTypeMap[i].type == type) {
2728             return &webgl2BaseTypeMap[i];
2729         }
2730     }
2731     return nullptr;
2732 }
2733 
CheckFrameBufferBoundComplete(napi_env env)2734 GLenum WebGLRenderingContextBaseImpl::CheckFrameBufferBoundComplete(napi_env env)
2735 {
2736     WebGLFramebuffer* framebufferBinding = GetBoundFrameBuffer(env, WebGLRenderingContextBase::FRAMEBUFFER);
2737     if (framebufferBinding &&
2738         framebufferBinding->CheckStatus(env, this) != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
2739         return WebGLRenderingContextBase::INVALID_FRAMEBUFFER_OPERATION;
2740     }
2741     GLenum complete = glCheckFramebufferStatus(WebGLRenderingContextBase::FRAMEBUFFER);
2742     LOGD("CheckFrameBufferBoundComplete complete %{public}u", complete);
2743     if (complete != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
2744         return WebGLRenderingContextBase::INVALID_FRAMEBUFFER_OPERATION;
2745     }
2746     return WebGLRenderingContextBase::NO_ERROR;
2747 }
2748 
CheckReadPixelsArg(napi_env env,const PixelsArg & arg,uint64_t bufferSize)2749 GLenum WebGLRenderingContextBaseImpl::CheckReadPixelsArg(napi_env env, const PixelsArg& arg, uint64_t bufferSize)
2750 {
2751     if (!CheckPixelsFormat(env, arg.format) || !CheckPixelsType(env, arg.type)) {
2752         return WebGLRenderingContextBase::INVALID_ENUM;
2753     }
2754     return 0;
2755 }
2756 
CheckVertexAttribPointer(napi_env env,const VertexAttribArg & vertexInfo)2757 GLenum WebGLRenderingContextBaseImpl::CheckVertexAttribPointer(napi_env env, const VertexAttribArg& vertexInfo)
2758 {
2759     if (vertexInfo.index >= GetMaxVertexAttribs()) {
2760         LOGE("WebGL vertexAttribPointer invalid index %{public}u", vertexInfo.index);
2761         return WebGLRenderingContextBase::INVALID_VALUE;
2762     }
2763     // check size,  4 is max vertexInfo size, 255 is max vertexInfo stride
2764     if (vertexInfo.size < 1 || vertexInfo.size > 4 || vertexInfo.stride < 0 || vertexInfo.stride > 255) {
2765         LOGE("WebGL vertexAttribPointer invalid size %{public}d %{public}d", vertexInfo.size, vertexInfo.stride);
2766         return WebGLRenderingContextBase::INVALID_VALUE;
2767     }
2768     // check offset
2769     WebGLBuffer* webGLBuffer = GetBoundBuffer(env, WebGLRenderingContextBase::ARRAY_BUFFER);
2770     if (webGLBuffer == nullptr || webGLBuffer->GetBufferSize() == 0) {
2771         LOGE("WebGL vertexAttribPointer can not bind buffer");
2772         return WebGLRenderingContextBase::INVALID_OPERATION;
2773     }
2774 
2775     // check offset
2776     if (vertexInfo.offset >= static_cast<GLintptr>(webGLBuffer->GetBufferSize())) {
2777         LOGE("WebGL vertexAttribPointer invalid offset %{public}u", static_cast<unsigned int>(vertexInfo.offset));
2778         return WebGLRenderingContextBase::INVALID_VALUE;
2779     }
2780 
2781     uint32_t typeSize = WebGLArg::GetWebGLDataSize(vertexInfo.type);
2782     if ((static_cast<uint32_t>(vertexInfo.stride) & static_cast<uint32_t>(typeSize - 1)) ||
2783         (static_cast<uint32_t>(vertexInfo.offset) & static_cast<uint32_t>(typeSize - 1))) {
2784         return WebGLRenderingContextBase::INVALID_OPERATION;
2785     }
2786     return WebGLRenderingContextBase::NO_ERROR;
2787 }
2788 
GetBoundFrameBufferColorFormat(napi_env env)2789 GLenum WebGLRenderingContextBaseImpl::GetBoundFrameBufferColorFormat(napi_env env)
2790 {
2791     WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, WebGLRenderingContextBase::FRAMEBUFFER);
2792     if (frameBuffer != nullptr) {
2793         WebGLAttachmentInfo info = {};
2794         if (frameBuffer->GetWebGLAttachmentInfo(env, this, frameBuffer->GetAttachment(GL_COLOR_ATTACHMENT0), info)) {
2795             return info.format;
2796         }
2797     }
2798     auto webGlContextAttributes = webGLRenderingContext_->CreateWebGlContextAttributes();
2799     if (webGlContextAttributes != nullptr && webGlContextAttributes->alpha_) {
2800         return GL_RGBA;
2801     }
2802     return GL_RGB;
2803 }
2804 
GetVertexAttribInfo(GLint index)2805 VertexAttribInfo* WebGLRenderingContextBaseImpl::GetVertexAttribInfo(GLint index)
2806 {
2807     if (index < 0 || index >= static_cast<GLint>(arrayVertexAttribs_.size())) {
2808         LOGE("Invalid index for VertexAttrib %{public}d, max %{public}zu",
2809             index, arrayVertexAttribs_.size());
2810         return nullptr;
2811     }
2812     return &arrayVertexAttribs_[index];
2813 }
2814 
CheckReadBufferMode(GLenum mode)2815 bool WebGLRenderingContextBaseImpl::CheckReadBufferMode(GLenum mode)
2816 {
2817     switch (mode) {
2818         case WebGLRenderingContextBase::BACK:
2819         case WebGLRenderingContextBase::NONE:
2820         case WebGLRenderingContextBase::COLOR_ATTACHMENT0:
2821             return true;
2822         default: {
2823             if (mode < WebGLRenderingContextBase::COLOR_ATTACHMENT0) {
2824                 return false;
2825             }
2826             if (mode > static_cast<GLenum>(WebGLRenderingContextBase::COLOR_ATTACHMENT0 + GetMaxColorAttachments())) {
2827                 return false;
2828             }
2829             break;
2830         }
2831     }
2832     return true;
2833 }
2834 
GetMaxColorAttachments()2835 GLint WebGLRenderingContextBaseImpl::GetMaxColorAttachments()
2836 {
2837     if (!maxColorAttachments_) {
2838         glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments_);
2839     }
2840     LOGD("maxColorAttachments %{public}d", maxColorAttachments_);
2841     return maxColorAttachments_;
2842 }
2843 
GetValidFrameBuffer(napi_env env,napi_value object)2844 WebGLFramebuffer* WebGLRenderingContextBaseImpl::GetValidFrameBuffer(napi_env env, napi_value object)
2845 {
2846     WebGLFramebuffer* webGlFramebuffer = WebGLObject::GetObjectInstance<WebGLFramebuffer>(env, object);
2847     if (webGlFramebuffer == nullptr) {
2848         return nullptr;
2849     }
2850     return GetObjectInstance<WebGLFramebuffer>(env, webGlFramebuffer->GetFramebuffer());
2851 }
2852 
GetValidBuffer(napi_env env,napi_value object)2853 WebGLBuffer* WebGLRenderingContextBaseImpl::GetValidBuffer(napi_env env, napi_value object)
2854 {
2855     WebGLBuffer* buffer = WebGLObject::GetObjectInstance<WebGLBuffer>(env, object);
2856     if (buffer == nullptr) {
2857         return nullptr;
2858     }
2859     return GetObjectInstance<WebGLBuffer>(env, buffer->GetBufferId());
2860 }
2861 
GetValidRenderBuffer(napi_env env,napi_value object)2862 WebGLRenderbuffer* WebGLRenderingContextBaseImpl::GetValidRenderBuffer(napi_env env, napi_value object)
2863 {
2864     WebGLRenderbuffer* renderBuffer = WebGLObject::GetObjectInstance<WebGLRenderbuffer>(env, object);
2865     if (renderBuffer == nullptr) {
2866         return nullptr;
2867     }
2868     return GetObjectInstance<WebGLRenderbuffer>(env, renderBuffer->GetRenderbuffer());
2869 }
2870 } // namespace Impl
2871 } // namespace Rosen
2872 } // namespace OHOS
2873