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/webgl_rendering_context_base.h"
18 #include "context/webgl2_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;
TexImage2D_(const TexImageArg & imgArg,WebGLTexture * texture,const void * pixels,bool changeUnpackAlignment)27 void WebGLRenderingContextBaseImpl::TexImage2D_(
28     const TexImageArg& imgArg, WebGLTexture* texture, const void* pixels, bool changeUnpackAlignment)
29 {
30     if (changeUnpackAlignment) {
31         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
32     }
33     glTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, imgArg.border,
34         imgArg.format, imgArg.type, pixels);
35     texture->SetTextureLevel(imgArg);
36 
37     if (changeUnpackAlignment) {
38         glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment_);
39     }
40     LOGD("WebGL TexImage2D_ target %{public}u result %{public}u", imgArg.target, GetError_());
41 }
42 
TexImage2D(napi_env env,const TexImageArg & imgArg,napi_value pixels,GLuint srcOffset)43 napi_value WebGLRenderingContextBaseImpl::TexImage2D(
44     napi_env env, const TexImageArg& imgArg, napi_value pixels, GLuint srcOffset)
45 {
46     imgArg.Dump("WebGL texImage2D");
47     LOGD("WebGL texImage2D srcOffset %{public}u", srcOffset);
48     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
49     if (!texture) {
50         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "texture is nullptr");
51         return NVal::CreateNull(env).val_;
52     }
53     GLenum error = CheckTexImage(env, imgArg, texture);
54     if (error != WebGLRenderingContextBase::NO_ERROR) {
55         SET_ERROR_WITH_LOG(error, "CheckTexImage failed");
56         return NVal::CreateNull(env).val_;
57     }
58     if (texture->CheckImmutable()) {
59         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "CheckImmutable failed");
60         return NVal::CreateNull(env).val_;
61     }
62     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
63         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "CheckNPOT failed");
64         return NVal::CreateNull(env).val_;
65     }
66 
67     GLvoid* data = nullptr;
68     WebGLImageSource imageSource(env, version_, unpackFlipY_, unpackPremultiplyAlpha_);
69     bool changeUnpackAlignment = false;
70     if (!NVal(env, pixels).IsNull()) {
71         error =imageSource.GenImageSource(
72             { imgArg.format, imgArg.type, imgArg.width, imgArg.height }, pixels, srcOffset);
73         if (error) {
74             SET_ERROR_WITH_LOG(error, "texSubImage2D invalid pixels");
75             return NVal::CreateNull(env).val_;
76         }
77         changeUnpackAlignment = unpackFlipY_ || unpackPremultiplyAlpha_;
78         data = imageSource.GetImageSourceData();
79     }
80     TexImage2D_(imgArg, texture, data, changeUnpackAlignment);
81     LOGD("WebGL texImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
82     return NVal::CreateNull(env).val_;
83 }
84 
TexImage2D(napi_env env,const TexImageArg & info,napi_value source)85 napi_value WebGLRenderingContextBaseImpl::TexImage2D(napi_env env, const TexImageArg& info, napi_value source)
86 {
87     TexImageArg imgArg(info);
88     GLvoid* data = nullptr;
89     WebGLImageSource imageSource(env, version_, unpackFlipY_, unpackPremultiplyAlpha_);
90     if (!NVal(env, source).IsNull()) {
91         GLenum error = imageSource.GenImageSource({ imgArg.format, imgArg.type, imgArg.width, imgArg.height }, source);
92         if (error) {
93             SET_ERROR_WITH_LOG(error, "texImage2D Image source invalid");
94             return NVal::CreateNull(env).val_;
95         }
96         data = imageSource.GetImageSourceData();
97         imgArg.width = imageSource.GetWidth();
98         imgArg.height = imageSource.GetHeight();
99     }
100     imgArg.Dump("WebGL texImage2D");
101 
102     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
103     if (!texture) {
104         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "Can not find texture");
105         return NVal::CreateNull(env).val_;
106     }
107     GLenum error = CheckTexImage(env, imgArg, texture);
108     if (error != WebGLRenderingContextBase::NO_ERROR) {
109         SET_ERROR_WITH_LOG(error, "WebGL texImage2D checkTexImage failed");
110         return NVal::CreateNull(env).val_;
111     }
112     if (texture->CheckImmutable()) {
113         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "WebGL texImage2D checkImmutable failed");
114         return NVal::CreateNull(env).val_;
115     }
116     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
117         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL texImage2D checkNPOT failed");
118         return NVal::CreateNull(env).val_;
119     }
120     if (imgArg.type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
121         // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
122         imgArg.type = GL_FLOAT;
123     }
124 
125     TexImage2D_(imgArg, texture, data, unpackAlignment_ != 1);
126     LOGD("WebGL texImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
127     return NVal::CreateNull(env).val_;
128 }
129 
TexImage2D(napi_env env,const TexImageArg & imgArg,GLintptr pbOffset)130 napi_value WebGLRenderingContextBaseImpl::TexImage2D(napi_env env, const TexImageArg& imgArg, GLintptr pbOffset)
131 {
132     imgArg.Dump("WebGL texImage2D");
133     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
134     if (!texture) {
135         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "Can not find texture");
136         return NVal::CreateNull(env).val_;
137     }
138     GLenum error = CheckTexImage(env, imgArg, texture);
139     if (error != WebGLRenderingContextBase::NO_ERROR) {
140         SET_ERROR_WITH_LOG(error, "WebGL texImage2D error");
141         return NVal::CreateNull(env).val_;
142     }
143     if (texture->CheckImmutable()) {
144         SET_ERROR(WebGLRenderingContextBase::INVALID_OPERATION);
145         return NVal::CreateNull(env).val_;
146     }
147     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
148         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
149         return NVal::CreateNull(env).val_;
150     }
151     glTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, imgArg.border,
152         imgArg.format, imgArg.type, reinterpret_cast<GLvoid*>(pbOffset));
153     LOGD("WebGL texImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
154     return NVal::CreateNull(env).val_;
155 }
156 
TexSubImage2D_(const TexSubImage2DArg & imgArg,WebGLTexture * texture,const void * pixels,bool changeUnpackAlignment)157 void WebGLRenderingContextBaseImpl::TexSubImage2D_(
158     const TexSubImage2DArg& imgArg, WebGLTexture* texture, const void* pixels, bool changeUnpackAlignment)
159 {
160     if (changeUnpackAlignment) {
161         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
162     }
163     glTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
164         imgArg.format, imgArg.type, pixels);
165     if (changeUnpackAlignment) {
166         glPixelStorei(GL_UNPACK_ALIGNMENT, unpackAlignment_);
167     }
168 }
169 
TexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,GLintptr pbOffset)170 napi_value WebGLRenderingContextBaseImpl::TexSubImage2D(napi_env env, const TexSubImage2DArg& imgArg, GLintptr pbOffset)
171 {
172     imgArg.Dump("WebGL texSubImage2D");
173     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
174     if (!texture) {
175         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "texture is nullptr");
176         return NVal::CreateNull(env).val_;
177     }
178     GLenum error = CheckTexImage(env, imgArg, texture);
179     if (error != WebGLRenderingContextBase::NO_ERROR) {
180         SET_ERROR_WITH_LOG(error, "CheckTexImage failed");
181         return NVal::CreateNull(env).val_;
182     }
183     glTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
184         imgArg.format, imgArg.type, reinterpret_cast<void *>(pbOffset));
185     LOGD("WebGL texSubImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
186     return NVal::CreateNull(env).val_;
187 }
188 
TexSubImage2D(napi_env env,const TexSubImage2DArg & info,napi_value pixels,GLuint srcOffset)189 napi_value WebGLRenderingContextBaseImpl::TexSubImage2D(
190     napi_env env, const TexSubImage2DArg& info, napi_value pixels, GLuint srcOffset)
191 {
192     TexSubImage2DArg& imgArg = const_cast<TexSubImage2DArg&>(info);
193     imgArg.Dump("WebGL texSubImage2D");
194     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
195     if (!texture) {
196         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "texture is nullptr");
197         return NVal::CreateNull(env).val_;
198     }
199     GLenum error = CheckTexImage(env, imgArg, texture);
200     if (error != WebGLRenderingContextBase::NO_ERROR) {
201         SET_ERROR_WITH_LOG(error, "WebGL texSubImage2D error");
202         return NVal::CreateNull(env).val_;
203     }
204 
205     if (!texture->CheckValid(imgArg.target, imgArg.level)) {
206         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, " invalid texture level");
207         return NVal::CreateNull(env).val_;
208     }
209 
210     GLvoid* data = nullptr;
211     WebGLImageSource imageSource(env, version_, unpackFlipY_, unpackPremultiplyAlpha_);
212     bool changeUnpackAlignment = false;
213     if (!NVal(env, pixels).IsNull()) {
214         error = imageSource.GenImageSource(
215             { imgArg.format, imgArg.type, imgArg.width, imgArg.height }, pixels, srcOffset);
216         if (error) {
217             SET_ERROR_WITH_LOG(error, "texSubImage2D invalid pixels");
218             return NVal::CreateNull(env).val_;
219         }
220         changeUnpackAlignment = unpackFlipY_ || unpackPremultiplyAlpha_;
221         data = imageSource.GetImageSourceData();
222         imgArg.width = imageSource.GetWidth();
223         imgArg.height = imageSource.GetHeight();
224     }
225 
226     error = CheckTexSubImage2D(env, imgArg, texture);
227     if (error != WebGLRenderingContextBase::NO_ERROR) {
228         SET_ERROR_WITH_LOG(error, "WebGL texSubImage2D error");
229         return NVal::CreateNull(env).val_;
230     }
231 
232     if (imgArg.type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
233         // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
234         imgArg.type = GL_FLOAT;
235     }
236     TexSubImage2D_(imgArg, texture, data, changeUnpackAlignment);
237     LOGD("WebGL texSubImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
238     return NVal::CreateNull(env).val_;
239 }
240 
TexSubImage2D(napi_env env,const TexSubImage2DArg & info,napi_value imageData)241 napi_value WebGLRenderingContextBaseImpl::TexSubImage2D(
242     napi_env env, const TexSubImage2DArg& info, napi_value imageData)
243 {
244     TexSubImage2DArg imgArg(info);
245     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
246     if (!texture) {
247         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "Can not find texture");
248         return NVal::CreateNull(env).val_;
249     }
250     GLvoid* data = nullptr;
251     GLenum error = 0;
252     WebGLImageSource imageSource(env, version_, unpackFlipY_, unpackPremultiplyAlpha_);
253     if (!NVal(env, imageData).IsNull()) {
254         error = imageSource.GenImageSource({ imgArg.format, imgArg.type, imgArg.width, imgArg.height }, imageData);
255         if (error) {
256             SET_ERROR_WITH_LOG(error, "texSubImage2D Image source invalid");
257             return NVal::CreateNull(env).val_;
258         }
259         data = imageSource.GetImageSourceData();
260         imgArg.width = imageSource.GetWidth();
261         imgArg.height = imageSource.GetHeight();
262     }
263     imgArg.Dump("WebGL texSubImage2D");
264     error = CheckTexImage(env, imgArg, texture);
265     if (error != WebGLRenderingContextBase::NO_ERROR) {
266         SET_ERROR_WITH_LOG(error, "WebGL texSubImage2D CheckTexImage failed");
267         return NVal::CreateNull(env).val_;
268     }
269     error = CheckTexSubImage2D(env, imgArg, texture);
270     if (error != WebGLRenderingContextBase::NO_ERROR) {
271         SET_ERROR_WITH_LOG(error, "WebGL texSubImage2D CheckTexSubImage2D failed");
272         return NVal::CreateNull(env).val_;
273     }
274     TexSubImage2D_(imgArg, texture, data, unpackAlignment_);
275     LOGD("WebGL texSubImage2D target %{public}u result %{public}u", imgArg.target, GetError_());
276     return NVal::CreateNull(env).val_;
277 }
278 
DrawElements(napi_env env,GLenum mode,GLsizei count,GLenum type,GLintptr offset)279 napi_value WebGLRenderingContextBaseImpl::DrawElements(
280     napi_env env, GLenum mode, GLsizei count, GLenum type, GLintptr offset)
281 {
282     LOGD("WebGL drawElements mode %{public}u %{public}d %{public}u", mode, count, type);
283     GLenum result = CheckDrawElements(env, mode, count, type, static_cast<int64_t>(offset));
284     if (result != WebGLRenderingContextBase::NO_ERROR) {
285         SET_ERROR_WITH_LOG(result, "WebGL drawElements failed");
286         return NVal::CreateNull(env).val_;
287     }
288     glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(offset));
289     return NVal::CreateNull(env).val_;
290 }
291 
DrawArrays(napi_env env,GLenum mode,GLint first,GLsizei count)292 napi_value WebGLRenderingContextBaseImpl::DrawArrays(napi_env env, GLenum mode, GLint first, GLsizei count)
293 {
294     LOGD("WebGL drawArrays mode %{public}u %{public}d %{public}d error %{public}u", mode, first, count, GetError_());
295     GLenum result = CheckDrawArrays(env, mode, first, count);
296     if (result != WebGLRenderingContextBase::NO_ERROR) {
297         SET_ERROR(result);
298         return NVal::CreateNull(env).val_;
299     }
300     glDrawArrays(mode, first, count);
301     LOGD("WebGL drawArrays result %{public}u", GetError_());
302     return NVal::CreateNull(env).val_;
303 }
304 
ReadPixels(napi_env env,const PixelsArg & arg,GLintptr offset)305 napi_value WebGLRenderingContextBaseImpl::ReadPixels(napi_env env, const PixelsArg& arg, GLintptr offset)
306 {
307     arg.Dump("WebGL readPixels");
308     if (!IsHighWebGL()) {
309         return NVal::CreateNull(env).val_;
310     }
311 
312     WebGLBuffer* buffer = GetBoundBuffer(env, WebGL2RenderingContextBase::PIXEL_PACK_BUFFER);
313     if (buffer == nullptr || buffer->GetBufferSize() == 0) {
314         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
315             "buffer is nullptr or GetBufferSize failed");
316         return NVal::CreateNull(env).val_;
317     }
318     uint64_t size = static_cast<uint64_t>(buffer->GetBufferSize());
319     if (size < static_cast<uint64_t>(offset)) {
320         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
321         return NVal::CreateNull(env).val_;
322     }
323     size = size - static_cast<uint64_t>(offset);
324     GLenum result = CheckReadPixelsArg(env, arg, size);
325     if (!result) {
326         SET_ERROR(result);
327         return NVal::CreateNull(env).val_;
328     }
329     glReadPixels(arg.x, arg.y, arg.width, arg.height, arg.format, arg.type, reinterpret_cast<void*>(offset));
330     LOGD("WebGL readPixels result %{public}u", GetError_());
331     return NVal::CreateNull(env).val_;
332 }
333 
ReadPixels(napi_env env,const PixelsArg & arg,napi_value buffer,GLuint dstOffset)334 napi_value WebGLRenderingContextBaseImpl::ReadPixels(
335     napi_env env, const PixelsArg& arg, napi_value buffer, GLuint dstOffset)
336 {
337     arg.Dump("WebGL readPixels");
338     WebGLReadBufferArg bufferData(env);
339     napi_status status = bufferData.GenBufferData(buffer);
340     if (status != 0) {
341         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
342         return NVal::CreateNull(env).val_;
343     }
344 
345     GLenum result = CheckReadPixelsArg(env, arg, static_cast<int64_t>(bufferData.GetBufferLength()));
346     if (result != WebGLRenderingContextBase::NO_ERROR) {
347         SET_ERROR(result);
348         return NVal::CreateNull(env).val_;
349     }
350 
351     glReadPixels(arg.x, arg.y, arg.width, arg.height, arg.format, arg.type,
352         static_cast<void*>(bufferData.GetBuffer() + dstOffset));
353     bufferData.DumpBuffer(bufferData.GetBufferDataType());
354     LOGD("WebGL readPixels pixels %{public}u result %{public}u", dstOffset, GetError_());
355     return NVal::CreateNull(env).val_;
356 }
357 
BufferData_(napi_env env,GLenum target,GLsizeiptr size,GLenum usage,const uint8_t * bufferData)358 napi_value WebGLRenderingContextBaseImpl::BufferData_(
359     napi_env env, GLenum target, GLsizeiptr size, GLenum usage, const uint8_t* bufferData)
360 {
361     LOGD("WebGL bufferData target %{public}u, usage %{public}u", target, usage);
362     uint32_t index = 0;
363     if (!CheckBufferTarget(env, target, index)) {
364         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckBufferTarget failed");
365         return NVal::CreateNull(env).val_;
366     }
367     WebGLBuffer* webGLBuffer = GetObjectInstance<WebGLBuffer>(env, boundBufferIds_[index]);
368     if (webGLBuffer == nullptr) {
369         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "webGLBuffer is nullptr");
370         return NVal::CreateNull(env).val_;
371     }
372     if (!CheckBufferDataUsage(env, usage)) {
373         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckBufferDataUsage failed");
374         return NVal::CreateNull(env).val_;
375     }
376 
377     if (webGLBuffer->GetTarget() != target) {
378         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
379             "webGLBuffer->GetTarget %{public}u target %{public}u", webGLBuffer->GetTarget(), target);
380         return NVal::CreateNull(env).val_;
381     }
382     webGLBuffer->SetBuffer(size, nullptr);
383     if (bufferData != nullptr) {
384         webGLBuffer->SetBuffer(size, bufferData);
385         glBufferData(target, size, bufferData, usage);
386     } else {
387         glBufferData(target, size, nullptr, usage);
388     }
389     webGLBuffer->SetTarget(target);
390     return NVal::CreateNull(env).val_;
391 }
392 
BufferData(napi_env env,GLenum target,int64_t size,GLenum usage)393 napi_value WebGLRenderingContextBaseImpl::BufferData(napi_env env, GLenum target, int64_t size, GLenum usage)
394 {
395     LOGD("WebGL bufferData target %{public}u, usage %{public}u size %{public}" PRIi64, target, usage, size);
396     BufferData_(env, target, static_cast<GLsizeiptr>(size), usage, nullptr);
397     return NVal::CreateNull(env).val_;
398 }
399 
BufferData(napi_env env,GLenum target,napi_value data,GLenum usage,const BufferExt & ext)400 napi_value WebGLRenderingContextBaseImpl::BufferData(
401     napi_env env, GLenum target, napi_value data, GLenum usage, const BufferExt& ext)
402 {
403     WebGLReadBufferArg bufferData(env);
404     if (NVal(env, data).IsNull()) {
405         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "data is nullptr");
406         return NVal::CreateNull(env).val_;
407     }
408     bool succ = bufferData.GenBufferData(data, BUFFER_DATA_FLOAT_32) == napi_ok;
409     if (!succ || bufferData.GetBufferType() == BUFFER_ARRAY) {
410         SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
411         return NVal::CreateNull(env).val_;
412     }
413     // change
414     GLuint srcOffset = static_cast<GLuint>(ext.offset * bufferData.GetBufferDataSize());
415     GLsizeiptr length = (ext.length == 0) ? static_cast<GLsizeiptr>(bufferData.GetBufferLength())
416                         : static_cast<GLsizeiptr>(ext.length * bufferData.GetBufferDataSize());
417     BufferData_(env, target, length, usage, bufferData.GetBuffer() + srcOffset);
418     LOGD("WebGL bufferData buffer usage %{public}u size %{public}zu target %{public}u, result %{public}u ",
419         usage, bufferData.GetBufferLength(), target, GetError_());
420     return NVal::CreateNull(env).val_;
421 }
422 
BufferSubData(napi_env env,GLenum target,GLintptr offset,napi_value buffer,const BufferExt & ext)423 napi_value WebGLRenderingContextBaseImpl::BufferSubData(
424     napi_env env, GLenum target, GLintptr offset, napi_value buffer, const BufferExt& ext)
425 {
426     WebGLBuffer* webGLBuffer = GetObjectInstance<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::ARRAY_BUFFER]);
427     if (webGLBuffer == nullptr || webGLBuffer->GetBufferSize() == 0) {
428         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION, "bufferSubData Can not find bound buffer");
429         return NVal::CreateNull(env).val_;
430     }
431 
432     WebGLReadBufferArg bufferData(env);
433     napi_status status = bufferData.GenBufferData(buffer);
434     if (status != 0) {
435         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "WebGL bufferSubData invalid buffer data");
436         return NVal::CreateNull(env).val_;
437     }
438     // check sub buffer
439     if ((static_cast<size_t>(offset) + bufferData.GetBufferLength()) > webGLBuffer->GetBufferSize()) {
440         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
441             "WebGL bufferSubData invalid buffer size %{public}zu offset %{public}zu ",
442             bufferData.GetBufferLength(), webGLBuffer->GetBufferSize());
443         return NVal::CreateNull(env).val_;
444     }
445 
446     bufferData.DumpBuffer(bufferData.GetBufferDataType());
447     glBufferSubData(target, offset, static_cast<GLsizeiptr>(bufferData.GetBufferLength()),
448         static_cast<uint8_t*>(bufferData.GetBuffer()));
449     LOGD("WebGL bufferSubData offset %{public}u target %{public}u size %{public}zu result %{public}u ",
450          static_cast<unsigned int>(offset), static_cast<unsigned int>(target),
451          bufferData.GetBufferLength(), static_cast<unsigned int>(GetError_()));
452     return NVal::CreateNull(env).val_;
453 }
454 
PixelStorei(napi_env env,GLenum pname,GLint param)455 napi_value WebGLRenderingContextBaseImpl::PixelStorei(napi_env env, GLenum pname, GLint param)
456 {
457     switch (pname) {
458         case WebGLRenderingContextBase::UNPACK_FLIP_Y_WEBGL:
459             unpackFlipY_ = (param == 1);
460             return NVal::CreateNull(env).val_;
461         case WebGLRenderingContextBase::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
462             unpackPremultiplyAlpha_ = (param == 1);
463             return NVal::CreateNull(env).val_;
464         case WebGLRenderingContextBase::PACK_ALIGNMENT:
465         case WebGLRenderingContextBase::UNPACK_ALIGNMENT: {
466             if (param == 1 || param == 2 || param == 4 || param == 8) { // 2,4,8 ALIGNMENT
467                 if (pname == WebGLRenderingContextBase::PACK_ALIGNMENT) {
468                     packAlignment_ = param;
469                     webGLRenderingContext_->SetPackAlignment(param);
470                 } else {
471                     unpackAlignment_ = param;
472                 }
473             } else {
474                 SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
475                 return NVal::CreateNull(env).val_;
476             }
477             break;
478         }
479         case WebGLRenderingContextBase::UNPACK_COLORSPACE_CONVERSION_WEBGL: {
480             if (static_cast<GLenum>(param) == WebGLRenderingContextBase::BROWSER_DEFAULT_WEBGL || param == GL_NONE) {
481                 unpackColorspaceConversion_ = static_cast<GLenum>(param);
482             } else {
483                 SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
484                     "WebGL pixelStorei invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL %{public}u", pname);
485                 return NVal::CreateNull(env).val_;
486             }
487             break;
488         }
489         default:
490             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
491                 "WebGL pixelStorei invalid pname  %{public}u", pname);
492             return NVal::CreateNull(env).val_;
493     }
494     glPixelStorei(pname, param);
495     LOGD("WebGL pixelStorei pname %{public}u param %{public}d result %{public}u ", pname, param, GetError_());
496     return NVal::CreateNull(env).val_;
497 }
498 
CheckCompressedTexImage2D(napi_env env,const TexImageArg & imgArg,size_t imageSize)499 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexImage2D(
500     napi_env env, const TexImageArg& imgArg, size_t imageSize)
501 {
502     if (imgArg.border) {
503         return WebGLRenderingContextBase::INVALID_VALUE;
504     }
505     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
506     if (result != WebGLRenderingContextBase::NO_ERROR) {
507         LOGE("Invalid target or level target %{public}u %{public}d", imgArg.target, imgArg.level);
508         return result;
509     }
510     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
511     if (texture == nullptr || texture->CheckImmutable()) {
512         LOGE("Invalid texture target %{public}u ", imgArg.target);
513         return WebGLRenderingContextBase::INVALID_OPERATION;
514     }
515     if (!CheckTexImageInternalFormat(env, imgArg.func, imgArg.internalFormat)) {
516         LOGE("Invalid internalFormat target %{public}u %{public}u", imgArg.target, imgArg.internalFormat);
517         return WebGLRenderingContextBase::INVALID_ENUM;
518     }
519     result = CheckCompressedTexDimensions(imgArg);
520     if (result != WebGLRenderingContextBase::NO_ERROR) {
521         LOGE("Invalid internalFormat %{public}u ", imgArg.internalFormat);
522         return result;
523     }
524 
525     result = CheckCompressedTexData(imgArg, imageSize);
526     if (result != WebGLRenderingContextBase::NO_ERROR) {
527         LOGE("Invalid tex data %{public}u ", result);
528         return result;
529     }
530 
531     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
532         return WebGLRenderingContextBase::INVALID_VALUE;
533     }
534     return WebGLRenderingContextBase::NO_ERROR;
535 }
536 
CompressedTexImage2D(napi_env env,const TexImageArg & imgArg,GLsizei imageSize,GLintptr offset)537 napi_value WebGLRenderingContextBaseImpl::CompressedTexImage2D(
538     napi_env env, const TexImageArg& imgArg, GLsizei imageSize, GLintptr offset)
539 {
540     imgArg.Dump("WebGL compressedTexImage2D");
541     GLenum result = CheckCompressedTexImage2D(env, imgArg, static_cast<size_t>(imageSize));
542     if (result != WebGLRenderingContextBase::NO_ERROR) {
543         SET_ERROR(result);
544         return NVal::CreateNull(env).val_;
545     }
546 
547     glCompressedTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height,
548         imgArg.border, imageSize, reinterpret_cast<void*>(offset));
549     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
550     if (texture != nullptr) {
551         texture->SetTextureLevel(
552             { imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, 1, GL_UNSIGNED_BYTE });
553     }
554     LOGD("WebGL compressedTexImage2D %{public}u", GetError_());
555     return NVal::CreateNull(env).val_;
556 }
557 
CompressedTexImage2D(napi_env env,const TexImageArg & info,napi_value srcData,GLuint srcOffset,GLuint srcLengthOverride)558 napi_value WebGLRenderingContextBaseImpl::CompressedTexImage2D(
559     napi_env env, const TexImageArg& info, napi_value srcData, GLuint srcOffset, GLuint srcLengthOverride)
560 {
561     TexImageArg& imgArg = const_cast<TexImageArg&>(info);
562     imgArg.Dump("WebGL compressedTexImage2D");
563 
564     WebGLReadBufferArg bufferData(env);
565     bool succ = bufferData.GenBufferData(srcData, BUFFER_DATA_FLOAT_32) == napi_ok;
566     if (!succ) {
567         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GenBufferData failed");
568         return NVal::CreateNull(env).val_;
569     }
570     bufferData.DumpBuffer(bufferData.GetBufferDataType());
571 
572     GLvoid* data = reinterpret_cast<GLvoid*>(bufferData.GetBuffer());
573     size_t length = bufferData.GetBufferLength();
574     if (srcOffset != 0) {
575         data = reinterpret_cast<GLvoid*>(bufferData.GetBuffer() + srcOffset * bufferData.GetBufferDataSize());
576     }
577     if (srcLengthOverride != 0) {
578         length = srcLengthOverride;
579     }
580 
581     GLenum result = CheckCompressedTexImage2D(env, imgArg, length);
582     if (result != WebGLRenderingContextBase::NO_ERROR) {
583         SET_ERROR_WITH_LOG(result, "CheckCompressedTexImage2D failed");
584         return NVal::CreateNull(env).val_;
585     }
586     glCompressedTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height,
587         imgArg.border, static_cast<GLsizei>(length), data);
588 
589     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
590     if (texture != nullptr) {
591         texture->SetTextureLevel(
592             { imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, 1, GL_UNSIGNED_BYTE });
593     }
594     LOGD("WebGL compressedTexImage2D %{public}u", GetError_());
595     return NVal::CreateNull(env).val_;
596 }
597 
CheckCompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,size_t imageSize)598 bool WebGLRenderingContextBaseImpl::CheckCompressedTexSubImage2D(
599     napi_env env, const TexSubImage2DArg& imgArg, size_t imageSize)
600 {
601     if (imgArg.border) {
602         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.border %{public}d", imgArg.border);
603         return false;
604     }
605     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
606     if (result != WebGLRenderingContextBase::NO_ERROR) {
607         SET_ERROR_WITH_LOG(result, "CheckTextureLevel failed");
608         return false;
609     }
610     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
611     if (texture == nullptr || texture->CheckImmutable()) {
612         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
613             "texture is nullptr or CheckImmutable failed");
614         return false;
615     }
616     if (!CheckTexImageInternalFormat(env, imgArg.func, imgArg.format)) {
617         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckTexImageInternalFormat failed");
618         return false;
619     }
620     result = CheckCompressedTexData(imgArg, imageSize);
621     if (result != WebGLRenderingContextBase::NO_ERROR) {
622         SET_ERROR_WITH_LOG(result, "CheckCompressedTexData failed");
623         return false;
624     }
625     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
626         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.level %{public}d", imgArg.level);
627         return false;
628     }
629     result = CheckCompressedTexSubDimensions(imgArg, texture);
630     if (result != WebGLRenderingContextBase::NO_ERROR) {
631         SET_ERROR_WITH_LOG(result, "CheckCompressedTexSubDimensions failed");
632         return false;
633     }
634     return true;
635 }
636 
CompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,napi_value srcData,GLuint srcOffset,GLuint srcLengthOverride)637 napi_value WebGLRenderingContextBaseImpl::CompressedTexSubImage2D(
638     napi_env env, const TexSubImage2DArg& imgArg, napi_value srcData, GLuint srcOffset, GLuint srcLengthOverride)
639 {
640     imgArg.Dump("WebGL compressedTexSubImage2D");
641     WebGLReadBufferArg bufferData(env);
642     GLvoid* data = nullptr;
643     GLsizei length = 0;
644     if (!NVal(env, srcData).IsNull()) {
645         bool succ = bufferData.GenBufferData(srcData, BUFFER_DATA_FLOAT_32) == napi_ok;
646         if (!succ) {
647             return NVal::CreateNull(env).val_;
648         }
649         bufferData.DumpBuffer(bufferData.GetBufferDataType());
650         data = reinterpret_cast<void*>(bufferData.GetBuffer() + srcOffset * bufferData.GetBufferDataSize());
651         length = srcLengthOverride == 0 ?
652             static_cast<GLsizei>(bufferData.GetBufferLength()) : static_cast<GLsizei>(srcLengthOverride);
653     }
654     bool succ = CheckCompressedTexSubImage2D(env, imgArg, length);
655     if (!succ) {
656         return NVal::CreateNull(env).val_;
657     }
658     glCompressedTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
659         imgArg.format, length, data);
660     LOGD("WebGL compressedTexSubImage2D result: %{public}u", GetError_());
661     return NVal::CreateNull(env).val_;
662 }
663 
CompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,GLsizei imageSize,GLintptr offset)664 napi_value WebGLRenderingContextBaseImpl::CompressedTexSubImage2D(
665     napi_env env, const TexSubImage2DArg& imgArg, GLsizei imageSize, GLintptr offset)
666 {
667     imgArg.Dump("WebGL compressedTexSubImage2D");
668     bool succ = CheckCompressedTexSubImage2D(env, imgArg, imageSize);
669     if (!succ) {
670         return NVal::CreateNull(env).val_;
671     }
672     glCompressedTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
673         imgArg.format, imageSize, reinterpret_cast<void*>(offset));
674     LOGD("WebGL compressedTexSubImage2D result %{public}u", GetError_());
675     return NVal::CreateNull(env).val_;
676 }
677 
CopyTexImage2D(napi_env env,const CopyTexImage2DArg & imgArg)678 napi_value WebGLRenderingContextBaseImpl::CopyTexImage2D(napi_env env, const CopyTexImage2DArg& imgArg)
679 {
680     if (imgArg.border) {
681         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.border %{public}d", imgArg.border);
682         return NVal::CreateNull(env).val_;
683     }
684     imgArg.Dump("WebGL copyTexImage2D");
685     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
686     if (result != WebGLRenderingContextBase::NO_ERROR) {
687         SET_ERROR_WITH_LOG(result, "CheckTextureLevel failed");
688         return NVal::CreateNull(env).val_;
689     }
690     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
691     if (!texture || texture->CheckImmutable()) {
692         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
693             "texture is nullptr or CheckImmutable failed");
694         return NVal::CreateNull(env).val_;
695     }
696     result = CheckTextureFormatAndType(env,
697         imgArg.internalFormat, imgArg.internalFormat, GL_UNSIGNED_BYTE, imgArg.level);
698     if (result != WebGLRenderingContextBase::NO_ERROR) {
699         SET_ERROR_WITH_LOG(result, "CheckTextureFormatAndType failed");
700         return NVal::CreateNull(env).val_;
701     }
702     result = CheckTexFuncDimensions(imgArg);
703     if (result != WebGLRenderingContextBase::NO_ERROR) {
704         SET_ERROR_WITH_LOG(result, "CheckTexFuncDimensions failed");
705         return NVal::CreateNull(env).val_;
706     }
707     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
708         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
709             "imgArg.level %{public}d %{public}d", imgArg.level, IsHighWebGL());
710         return NVal::CreateNull(env).val_;
711     }
712     GLuint frameBufferId = 0;
713     result = CheckReadBufferAndGetInfo(env, &frameBufferId, nullptr, nullptr);
714     if (result != WebGLRenderingContextBase::NO_ERROR) {
715         SET_ERROR_WITH_LOG(result, "CheckReadBufferAndGetInfo failed");
716         return NVal::CreateNull(env).val_;
717     }
718 
719     glCopyTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.x, imgArg.y, imgArg.width,
720         imgArg.height, imgArg.border);
721 
722     texture->SetTextureLevel({ imgArg.target, imgArg.level, imgArg.internalFormat,
723         imgArg.width, imgArg.height, 1, 1 });
724     return NVal::CreateNull(env).val_;
725 }
726 
CopyTexSubImage2D(napi_env env,const CopyTexSubImageArg & imgArg)727 napi_value WebGLRenderingContextBaseImpl::CopyTexSubImage2D(napi_env env, const CopyTexSubImageArg& imgArg)
728 {
729     imgArg.Dump("WebGL copyTexSubImage2D");
730     GLenum result = CheckCopyTexSubImage(env, imgArg);
731     if (result != WebGLRenderingContextBase::NO_ERROR) {
732         SET_ERROR_WITH_LOG(result, "CheckCopyTexSubImage failed");
733         return NVal::CreateNull(env).val_;
734     }
735 
736     GLuint frameBufferId = 0;
737     result = CheckReadBufferAndGetInfo(env, &frameBufferId, nullptr, nullptr);
738     if (result != WebGLRenderingContextBase::NO_ERROR) {
739         SET_ERROR_WITH_LOG(result, "CheckReadBufferAndGetInfo failed");
740         return NVal::CreateNull(env).val_;
741     }
742     glCopyTexSubImage2D(
743         imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.x, imgArg.y, imgArg.width, imgArg.height);
744     return NVal::CreateNull(env).val_;
745 }
746 
CheckTextureLevel(GLenum target,GLint level)747 GLenum WebGLRenderingContextBaseImpl::CheckTextureLevel(GLenum target, GLint level)
748 {
749     GLint max = WebGLTexture::GetMaxTextureLevelForTarget(target, IsHighWebGL());
750     if (max <= 0) {
751         return WebGLRenderingContextBase::INVALID_ENUM;
752     }
753     if ((level < 0) || level > max) {
754         return WebGLRenderingContextBase::INVALID_VALUE;
755     }
756     return WebGLRenderingContextBase::NO_ERROR;
757 }
758 
CheckTexImage(napi_env env,const TexImageArg & imgArg,WebGLTexture * texture)759 GLenum WebGLRenderingContextBaseImpl::CheckTexImage(napi_env env, const TexImageArg& imgArg, WebGLTexture* texture)
760 {
761     if (imgArg.border) {
762         return WebGLRenderingContextBase::INVALID_VALUE;
763     }
764     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
765     if (result != WebGLRenderingContextBase::NO_ERROR) {
766         return result;
767     }
768     GLenum internalFormat = imgArg.internalFormat;
769     if (imgArg.internalFormat == 0) {
770         internalFormat = texture->GetInternalFormat(imgArg.target, imgArg.level);
771     }
772     if (internalFormat == 0) {
773         LOGE("Invalid internalFormat %{public}u", internalFormat);
774         return WebGLRenderingContextBase::INVALID_OPERATION;
775     }
776     result = CheckTextureFormatAndType(env, internalFormat, imgArg.format, imgArg.type, imgArg.level);
777     if (result != WebGLRenderingContextBase::NO_ERROR) {
778         return result;
779     }
780     result = CheckTexFuncDimensions(imgArg);
781     if (result != WebGLRenderingContextBase::NO_ERROR) {
782         LOGE("Invalid texture dimension or type %{public}u", result);
783         return result;
784     }
785     return WebGLRenderingContextBase::NO_ERROR;
786 }
787 
CheckTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,WebGLTexture * texture)788 GLenum WebGLRenderingContextBaseImpl::CheckTexSubImage2D(
789     napi_env env, const TexSubImage2DArg& imgArg, WebGLTexture* texture)
790 {
791     if (imgArg.xOffset < 0 || imgArg.yOffset < 0) {
792         LOGE("WebGL CheckTexSubImage2D invalid xOffset %{public}d", imgArg.xOffset);
793         return WebGLRenderingContextBase::INVALID_VALUE;
794     }
795 
796     // Before checking if it is in the range, check if overflow happens first.
797     if (imgArg.xOffset + imgArg.width < 0 || imgArg.yOffset + imgArg.height < 0) {
798         return WebGLRenderingContextBase::INVALID_VALUE;
799     }
800     if ((imgArg.xOffset + imgArg.width) > texture->GetWidth(imgArg.target, imgArg.level) ||
801         (imgArg.yOffset + imgArg.height) > texture->GetHeight(imgArg.target, imgArg.level)) {
802         LOGE("WebGL invalid CheckTexSubImage2D GetWidth %{public}u, GetHeight %{public}d",
803             texture->GetWidth(imgArg.target, imgArg.level), texture->GetHeight(imgArg.target, imgArg.level));
804         return WebGLRenderingContextBase::INVALID_VALUE;
805     }
806     if (!IsHighWebGL() && texture->GetType(imgArg.target, imgArg.level) != imgArg.type) {
807         LOGE("WebGL invalid CheckTexSubImage2D type %{public}d", imgArg.type);
808         return WebGLRenderingContextBase::INVALID_OPERATION;
809     }
810     return WebGLRenderingContextBase::NO_ERROR;
811 }
812 
CheckTexImageInternalFormat(napi_env env,int32_t func,GLenum internalFormat)813 bool WebGLRenderingContextBaseImpl::CheckTexImageInternalFormat(napi_env env, int32_t func, GLenum internalFormat)
814 {
815     return CheckInList(internalFormat, WebGLRenderingContextBaseImpl::GetTexImageInternalFormat());
816 }
817 
CheckTexFuncDimensions(const TexImageArg & imgArg)818 GLenum WebGLRenderingContextBaseImpl::CheckTexFuncDimensions(const TexImageArg& imgArg)
819 {
820     if (imgArg.width < 0 || imgArg.height < 0) {
821         LOGE("Invalid offset or size ");
822         return WebGLRenderingContextBase::INVALID_VALUE;
823     }
824     switch (imgArg.target) {
825         case GL_TEXTURE_2D:
826             if (static_cast<GLuint>(imgArg.width) > (static_cast<GLuint>(maxTextureSize_) >> imgArg.level) ||
827                 static_cast<GLuint>(imgArg.height) > (static_cast<GLuint>(maxTextureSize_) >> imgArg.level)) {
828                 return WebGLRenderingContextBase::INVALID_VALUE;
829             }
830             break;
831         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
832         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
833         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
834         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
835         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
836         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
837             if (imgArg.func != IMAGE_TEX_SUB_IMAGE_2D && imgArg.width != imgArg.height) {
838                 return WebGLRenderingContextBase::INVALID_VALUE;
839             }
840             if (static_cast<uint32_t>(imgArg.width) > (static_cast<uint32_t>(maxCubeMapTextureSize_) >>
841                 static_cast<uint32_t>(imgArg.level))) {
842                 return WebGLRenderingContextBase::INVALID_VALUE;
843             }
844             break;
845         default:
846             return WebGLRenderingContextBase::INVALID_ENUM;
847     }
848     return WebGLRenderingContextBase::NO_ERROR;
849 }
850 
CheckCompressedTexDimensions(const TexImageArg & imgArg)851 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexDimensions(const TexImageArg& imgArg)
852 {
853     GLenum result = CheckTexFuncDimensions(imgArg);
854     if (result != WebGLRenderingContextBase::NO_ERROR) {
855         LOGE("Invalid tex dimensions %{public}u %{public}d", imgArg.target, imgArg.level);
856         return result;
857     }
858     if (CheckInList(imgArg.internalFormat, GetExtentionAstcTexImageInternal())) {
859         return WebGLRenderingContextBase::NO_ERROR;
860     }
861     bool widthValid = true;
862     bool heightValid = true;
863     switch (imgArg.internalFormat) {
864 #ifdef GC3D_COMPRESSED_ATC_RGB_AMD
865         case GC3D_COMPRESSED_ATC_RGB_AMD:
866         case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
867         case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
868 #endif
869         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
870         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
871         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
872         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
873             widthValid = (imgArg.level && imgArg.width == 1) || (imgArg.level && imgArg.width == 2) ||
874                 !(imgArg.width % 4); // 1 2 4 ALIGNMENT
875             heightValid = (imgArg.level && imgArg.height == 1) || (imgArg.level && imgArg.height == 2) ||
876                 !(imgArg.height % 4); // 1 2 4 ALIGNMENT
877             break;
878         }
879         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
880         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
881         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
882         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
883             widthValid = (static_cast<uint32_t>(imgArg.width) & static_cast<uint32_t>(imgArg.width - 1)) == 0;
884             heightValid = (static_cast<uint32_t>(imgArg.height) & static_cast<uint32_t>(imgArg.height - 1)) == 0;
885             break;
886         }
887         default:
888             return WebGLRenderingContextBase::NO_ERROR;
889     }
890 
891     if (!widthValid || !heightValid) {
892         return WebGLRenderingContextBase::INVALID_OPERATION;
893     }
894     return WebGLRenderingContextBase::NO_ERROR;
895 }
896 
CheckCompressedTexData(const TexImageArg & imgArg,size_t dataLen)897 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexData(const TexImageArg& imgArg, size_t dataLen)
898 {
899     size_t bytesRequired = 0;
900     switch (imgArg.internalFormat) {
901         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
902         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: {
903             const int32_t kBlockWidth = 4;
904             const int32_t kBlockHeight = 4;
905             const int32_t kBlockSize = 8;
906             int32_t numBlocksAcross = (imgArg.width + kBlockWidth - 1) / kBlockWidth;
907             int32_t numBlocksDown = (imgArg.height + kBlockHeight - 1) / kBlockHeight;
908             int32_t numBlocks = numBlocksAcross * numBlocksDown;
909             bytesRequired = static_cast<size_t>(numBlocks * kBlockSize);
910             break;
911         }
912         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
913         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
914             const int32_t kBlockWidth = 4;
915             const int32_t kBlockHeight = 4;
916             const int32_t kBlockSize = 16;
917             int32_t numBlocksAcross = (imgArg.width + kBlockWidth - 1) / kBlockWidth;
918             int32_t numBlocksDown = (imgArg.height + kBlockHeight - 1) / kBlockHeight;
919             int32_t numBlocks = numBlocksAcross * numBlocksDown;
920             bytesRequired = static_cast<size_t>(numBlocks * kBlockSize);
921             break;
922         }
923         case GL_ETC1_RGB8_OES: { // 3 kBlockWidth -1, 4 kBlockWidth, 8 kBlockSize
924             bytesRequired = floor(static_cast<double>((imgArg.width + 3) / 4)) *
925                 floor(static_cast<double>((imgArg.height + 3) / 4)) * 8;
926             break;
927         }
928         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
929         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: { // 4 4BPPV1, 7 kBlockWidth -1, 8 kBlockWidth, 8 kBlockSize
930             bytesRequired = (max(imgArg.width, 8) * max(imgArg.height, 8) * 4 + 7) / 8;
931             break;
932         }
933         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
934         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { // 2 2BPPV1, 7 kBlockWidth - 1, 16 kBlockWidth, 8 kBlockSize
935             bytesRequired = (max(imgArg.width, 16) * max(imgArg.height, 8) * 2 + 7) / 8;
936             break;
937         }
938         default:
939             return WebGLRenderingContextBase::INVALID_ENUM;
940     }
941     LOGD("CheckCompressedTexData bytesRequired %{public}zu", bytesRequired);
942     if (dataLen != bytesRequired) {
943         return WebGLRenderingContextBase::INVALID_VALUE;
944     }
945     return WebGLRenderingContextBase::NO_ERROR;
946 }
947 
CheckCompressedTexSubDimensions(const TexSubImage2DArg & imgArg,WebGLTexture * texture)948 bool WebGLRenderingContextBaseImpl::CheckCompressedTexSubDimensions(
949     const TexSubImage2DArg& imgArg, WebGLTexture* texture)
950 {
951     if (imgArg.xOffset < 0 || imgArg.yOffset < 0) {
952         return WebGLRenderingContextBase::INVALID_VALUE;
953     }
954 
955     switch (imgArg.format) {
956         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
957         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
958         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
959         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
960             const int32_t kBlockWidth = 4;
961             const int32_t kBlockHeight = 4;
962             if ((imgArg.xOffset % kBlockWidth) || (imgArg.yOffset % kBlockHeight)) {
963                 return WebGLRenderingContextBase::INVALID_OPERATION;
964             }
965             if (WebGLArg::CheckOverflow<GLint, GLint>(imgArg.xOffset, imgArg.width) ||
966                 WebGLArg::CheckOverflow<GLint, GLint>(imgArg.yOffset, imgArg.height)) {
967                 return WebGLRenderingContextBase::INVALID_VALUE;
968             }
969 
970             if ((imgArg.xOffset + imgArg.width) > texture->GetWidth(imgArg.target, imgArg.level) ||
971                 (imgArg.yOffset + imgArg.height) > texture->GetHeight(imgArg.target, imgArg.level)) {
972                 return WebGLRenderingContextBase::INVALID_VALUE;
973             }
974             return CheckCompressedTexDimensions(imgArg);
975         }
976         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
977         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
978         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
979         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
980             if ((imgArg.xOffset != 0) || (imgArg.yOffset != 0)) {
981                 return WebGLRenderingContextBase::INVALID_OPERATION;
982             }
983             if (imgArg.width != texture->GetWidth(imgArg.target, imgArg.level) ||
984                 imgArg.height != texture->GetHeight(imgArg.target, imgArg.level)) {
985                 return WebGLRenderingContextBase::INVALID_OPERATION;
986             }
987             return CheckCompressedTexDimensions(imgArg);
988         }
989         case GL_ETC1_RGB8_OES: {
990             return WebGLRenderingContextBase::INVALID_OPERATION;
991         }
992         default:
993             return WebGLRenderingContextBase::INVALID_ENUM;
994     }
995     return WebGLRenderingContextBase::NO_ERROR;
996 }
997 
CheckTextureDataBuffer(const TexImageArg & arg,const WebGLReadBufferArg * bufferData)998 GLenum WebGLRenderingContextBaseImpl::CheckTextureDataBuffer(
999     const TexImageArg& arg, const WebGLReadBufferArg* bufferData)
1000 {
1001     if (!bufferData) {
1002         return WebGLRenderingContextBase::INVALID_VALUE;
1003     }
1004     if (WebGLTexture::ChangeToBufferDataType(arg.type) != bufferData->GetBufferDataType()) {
1005         return WebGLRenderingContextBase::INVALID_OPERATION;
1006     }
1007     return WebGLRenderingContextBase::NO_ERROR;
1008 }
1009 
CheckCopyTexSubImage(napi_env env,const CopyTexSubImageArg & arg)1010 GLenum WebGLRenderingContextBaseImpl::CheckCopyTexSubImage(napi_env env, const CopyTexSubImageArg& arg)
1011 {
1012     GLenum result = CheckTextureLevel(arg.target, arg.level);
1013     if (result != WebGLRenderingContextBase::NO_ERROR) {
1014         return result;
1015     }
1016 
1017     WebGLTexture* texture = GetBoundTexture(env, arg.target, false);
1018     if (texture == nullptr) {
1019         return WebGLRenderingContextBase::INVALID_OPERATION;
1020     }
1021 
1022     if (!WebGLTexture::CheckTextureSize(arg.xOffset, arg.width, texture->GetWidth(arg.target, arg.level)) ||
1023         !WebGLTexture::CheckTextureSize(arg.yOffset, arg.height, texture->GetHeight(arg.target, arg.level))) {
1024         return WebGLRenderingContextBase::INVALID_VALUE;
1025     }
1026     if (arg.func == IMAGE_COPY_TEX_SUB_IMAGE_3D) {
1027         const CopyTexSubImage3DArg* img3D = reinterpret_cast<const CopyTexSubImage3DArg*>(&arg);
1028         if (!WebGLTexture::CheckTextureSize(img3D->zOffset, img3D->depth, texture->GetDepth(arg.target, arg.level))) {
1029             return WebGLRenderingContextBase::INVALID_VALUE;
1030         }
1031     }
1032     return WebGLRenderingContextBase::NO_ERROR;
1033 }
1034 
CheckDrawArrays(napi_env env,GLenum mode,GLint first,GLsizei count)1035 GLenum WebGLRenderingContextBaseImpl::CheckDrawArrays(napi_env env, GLenum mode, GLint first, GLsizei count)
1036 {
1037     if (!CheckDrawMode(env, mode)) {
1038         return WebGLRenderingContextBase::INVALID_ENUM;
1039     }
1040     if (!CheckStencil(env)) {
1041         return WebGLRenderingContextBase::INVALID_OPERATION;
1042     }
1043 
1044     if (first < 0 || count < 0) {
1045         return WebGLRenderingContextBase::INVALID_VALUE;
1046     }
1047 
1048     if (!currentProgramId_) {
1049         LOGE("WebGL drawArrays no valid shader program in use");
1050         return WebGLRenderingContextBase::INVALID_OPERATION;
1051     }
1052 
1053     return CheckFrameBufferBoundComplete(env);
1054 }
1055 
CheckDrawElements(napi_env env,GLenum mode,GLsizei count,GLenum type,int64_t offset)1056 GLenum WebGLRenderingContextBaseImpl::CheckDrawElements(
1057     napi_env env, GLenum mode, GLsizei count, GLenum type, int64_t offset)
1058 {
1059     if (!CheckDrawMode(env, mode)) {
1060         return WebGLRenderingContextBase::INVALID_ENUM;
1061     }
1062     if (!CheckStencil(env)) {
1063         return WebGLRenderingContextBase::INVALID_OPERATION;
1064     }
1065 
1066     uint32_t size = 1;
1067     switch (type) {
1068         case WebGLRenderingContextBase::UNSIGNED_BYTE:
1069             break;
1070         case WebGLRenderingContextBase::UNSIGNED_SHORT:
1071             size = sizeof(short);
1072             break;
1073         case WebGLRenderingContextBase::UNSIGNED_INT: {
1074             size = sizeof(int);
1075             if (IsHighWebGL()) {
1076                 break;
1077             }
1078             [[fallthrough]];
1079         }
1080         default:
1081             return WebGLRenderingContextBase::INVALID_ENUM;
1082     }
1083     if (count < 0 || offset < 0) {
1084         return WebGLRenderingContextBase::INVALID_VALUE;
1085     }
1086     if ((offset % static_cast<int64_t>(size)) != 0) {
1087         return WebGLRenderingContextBase::INVALID_VALUE;
1088     }
1089     WebGLBuffer* webGLBuffer =
1090         GetObjectInstance<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::ELEMENT_ARRAY_BUFFER]);
1091     if (webGLBuffer == nullptr || webGLBuffer->GetBufferSize() == 0) {
1092         return WebGLRenderingContextBase::INVALID_OPERATION;
1093     }
1094 
1095     // check count
1096     if (size * static_cast<uint32_t>(count) > static_cast<uint32_t>(webGLBuffer->GetBufferSize())) {
1097         LOGE("WebGL drawElements Insufficient buffer size %{public}d", count);
1098         return WebGLRenderingContextBase::INVALID_OPERATION;
1099     }
1100     if (static_cast<size_t>(offset) >= webGLBuffer->GetBufferSize()) {
1101         LOGE("WebGL drawElements invalid offset %{public}" PRIi64, offset);
1102         return WebGLRenderingContextBase::INVALID_VALUE;
1103     }
1104 
1105     if (!currentProgramId_) {
1106         LOGE("WebGL drawArrays no valid shader program in use");
1107         return WebGLRenderingContextBase::INVALID_OPERATION;
1108     }
1109 
1110     return CheckFrameBufferBoundComplete(env);
1111 }
1112 
CheckReadBufferAndGetInfo(napi_env env,GLuint * frameBufferId,GLenum * format,GLenum * type)1113 GLenum WebGLRenderingContextBaseImpl::CheckReadBufferAndGetInfo(
1114     napi_env env, GLuint* frameBufferId, GLenum* format, GLenum* type)
1115 {
1116     GLenum target = IsHighWebGL() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
1117     WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, target);
1118     if (frameBuffer) {
1119         LOGD("CheckReadBufferAndGetInfo frameBuffer %{public}u", frameBuffer->GetFramebuffer());
1120         if (frameBuffer->CheckStatus(env, this) != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
1121             LOGE("CheckStatus not FRAMEBUFFER_COMPLETE");
1122             return WebGLRenderingContextBase::INVALID_FRAMEBUFFER_OPERATION;
1123         }
1124         if (!GetReadBufferFormatAndType(env, frameBuffer, format, type)) {
1125             return WebGLRenderingContextBase::INVALID_OPERATION;
1126         }
1127         *frameBufferId = frameBuffer->GetFramebuffer();
1128     } else {
1129         if (defaultReadBufferMode_ == GL_NONE) {
1130             LOGE("defaultReadBufferMode_ %{public}u", defaultReadBufferMode_);
1131             return WebGLRenderingContextBase::INVALID_OPERATION;
1132         }
1133         if (format) {
1134             *format = GL_RGBA;
1135         }
1136         if (type) {
1137             *type = GL_UNSIGNED_BYTE;
1138         }
1139     }
1140     return WebGLRenderingContextBase::NO_ERROR;
1141 }
1142 
GetReadBufferFormatAndType(napi_env env,const WebGLFramebuffer * frameBuffer,GLenum * format,GLenum * type)1143 bool WebGLRenderingContextBaseImpl::GetReadBufferFormatAndType(
1144     napi_env env, const WebGLFramebuffer* frameBuffer, GLenum* format, GLenum* type)
1145 {
1146     GLenum mode = frameBuffer->GetReadBufferMode();
1147     LOGD("GetReadBufferFormatAndType mode %{public}u", mode);
1148     if (mode == GL_NONE) {
1149         return false;
1150     }
1151     WebGLAttachment* attachedObject = frameBuffer->GetAttachment(mode);
1152     if (!attachedObject) {
1153         LOGE("GetReadBufferFormatAndType no attachment %{public}u", mode);
1154         return false;
1155     }
1156     WebGLAttachmentInfo info = {};
1157     if (!frameBuffer->GetWebGLAttachmentInfo(env, this, attachedObject, info)) {
1158         LOGE("GetReadBufferFormatAndType no attachment info %{public}u", mode);
1159         return false;
1160     }
1161     if (format) {
1162         *format = info.format;
1163     }
1164     if (type) {
1165         *type = info.type;
1166     }
1167     return true;
1168 }
1169 
CheckTextureFormatAndType(napi_env env,GLenum internalFormat,GLenum format,GLenum type,GLint level)1170 GLenum WebGLRenderingContextBaseImpl::CheckTextureFormatAndType(
1171     napi_env env, GLenum internalFormat, GLenum format, GLenum type, GLint level)
1172 {
1173     LOGD("internalFormat %{public}u format %{public}u type %{public}u %{public}d",
1174         internalFormat, format, type, level);
1175     if (!CheckInList(internalFormat, WebGLTexture::GetSupportedInternalFormats())) {
1176         LOGE("Invalid internalFormat %{public}u ", internalFormat);
1177         return GL_INVALID_ENUM;
1178     }
1179     if (!CheckInList(format, WebGLTexture::GetSupportedFormats())) {
1180         LOGE("Invalid format %{public}u ", format);
1181         return GL_INVALID_ENUM;
1182     }
1183     if (!CheckInList(type, WebGLTexture::GetSupportedTypes())) {
1184         LOGE("Invalid type %{public}u ", type);
1185         return GL_INVALID_ENUM;
1186     }
1187 
1188     TextureFormatTypeMap map = { internalFormat, format, type };
1189     if (WebGLTexture::GetSupportedFormatTypeMaps().find(map) == WebGLTexture::GetSupportedFormatTypeMaps().end()) {
1190         LOGE("Invalid format type ");
1191         return GL_INVALID_OPERATION;
1192     }
1193 
1194     if ((format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_OES) && level > 0 && !IsHighWebGL()) {
1195         return GL_INVALID_OPERATION;
1196     }
1197     return 0;
1198 }
1199 } // namespace Impl
1200 } // namespace Rosen
1201 } // namespace OHOS
1202