• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         offset, target,  bufferData.GetBufferLength(), GetError_());
451     return NVal::CreateNull(env).val_;
452 }
453 
PixelStorei(napi_env env,GLenum pname,GLint param)454 napi_value WebGLRenderingContextBaseImpl::PixelStorei(napi_env env, GLenum pname, GLint param)
455 {
456     switch (pname) {
457         case WebGLRenderingContextBase::UNPACK_FLIP_Y_WEBGL:
458             unpackFlipY_ = (param == 1);
459             return NVal::CreateNull(env).val_;
460         case WebGLRenderingContextBase::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
461             unpackPremultiplyAlpha_ = (param == 1);
462             return NVal::CreateNull(env).val_;
463         case WebGLRenderingContextBase::PACK_ALIGNMENT:
464         case WebGLRenderingContextBase::UNPACK_ALIGNMENT: {
465             if (param == 1 || param == 2 || param == 4 || param == 8) { // 2,4,8 ALIGNMENT
466                 if (pname == WebGLRenderingContextBase::PACK_ALIGNMENT) {
467                     packAlignment_ = param;
468                     webGLRenderingContext_->SetPackAlignment(param);
469                 } else {
470                     unpackAlignment_ = param;
471                 }
472             } else {
473                 SET_ERROR(WebGLRenderingContextBase::INVALID_VALUE);
474                 return NVal::CreateNull(env).val_;
475             }
476             break;
477         }
478         case WebGLRenderingContextBase::UNPACK_COLORSPACE_CONVERSION_WEBGL: {
479             if (static_cast<GLenum>(param) == WebGLRenderingContextBase::BROWSER_DEFAULT_WEBGL || param == GL_NONE) {
480                 unpackColorspaceConversion_ = static_cast<GLenum>(param);
481             } else {
482                 SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
483                     "WebGL pixelStorei invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL %{public}u", pname);
484                 return NVal::CreateNull(env).val_;
485             }
486             break;
487         }
488         default:
489             SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM,
490                 "WebGL pixelStorei invalid pname  %{public}u", pname);
491             return NVal::CreateNull(env).val_;
492     }
493     glPixelStorei(pname, param);
494     LOGD("WebGL pixelStorei pname %{public}u param %{public}d result %{public}u ", pname, param, GetError_());
495     return NVal::CreateNull(env).val_;
496 }
497 
CheckCompressedTexImage2D(napi_env env,const TexImageArg & imgArg,size_t imageSize)498 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexImage2D(
499     napi_env env, const TexImageArg& imgArg, size_t imageSize)
500 {
501     if (imgArg.border) {
502         return WebGLRenderingContextBase::INVALID_VALUE;
503     }
504     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
505     if (result != WebGLRenderingContextBase::NO_ERROR) {
506         LOGE("Invalid target or level target %{public}u %{public}d", imgArg.target, imgArg.level);
507         return result;
508     }
509     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
510     if (texture == nullptr || texture->CheckImmutable()) {
511         LOGE("Invalid texture target %{public}u ", imgArg.target);
512         return WebGLRenderingContextBase::INVALID_OPERATION;
513     }
514     if (!CheckTexImageInternalFormat(env, imgArg.func, imgArg.internalFormat)) {
515         LOGE("Invalid internalFormat target %{public}u %{public}u", imgArg.target, imgArg.internalFormat);
516         return WebGLRenderingContextBase::INVALID_ENUM;
517     }
518     result = CheckCompressedTexDimensions(imgArg);
519     if (result != WebGLRenderingContextBase::NO_ERROR) {
520         LOGE("Invalid internalFormat %{public}u ", imgArg.internalFormat);
521         return result;
522     }
523 
524     result = CheckCompressedTexData(imgArg, imageSize);
525     if (result != WebGLRenderingContextBase::NO_ERROR) {
526         LOGE("Invalid tex data %{public}u ", result);
527         return result;
528     }
529 
530     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
531         return WebGLRenderingContextBase::INVALID_VALUE;
532     }
533     return WebGLRenderingContextBase::NO_ERROR;
534 }
535 
CompressedTexImage2D(napi_env env,const TexImageArg & imgArg,GLsizei imageSize,GLintptr offset)536 napi_value WebGLRenderingContextBaseImpl::CompressedTexImage2D(
537     napi_env env, const TexImageArg& imgArg, GLsizei imageSize, GLintptr offset)
538 {
539     imgArg.Dump("WebGL compressedTexImage2D");
540     GLenum result = CheckCompressedTexImage2D(env, imgArg, static_cast<size_t>(imageSize));
541     if (result != WebGLRenderingContextBase::NO_ERROR) {
542         SET_ERROR(result);
543         return NVal::CreateNull(env).val_;
544     }
545 
546     glCompressedTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height,
547         imgArg.border, imageSize, reinterpret_cast<void*>(offset));
548     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
549     if (texture != nullptr) {
550         texture->SetTextureLevel(
551             { imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, 1, GL_UNSIGNED_BYTE });
552     }
553     LOGD("WebGL compressedTexImage2D %{public}u", GetError_());
554     return NVal::CreateNull(env).val_;
555 }
556 
CompressedTexImage2D(napi_env env,const TexImageArg & info,napi_value srcData,GLuint srcOffset,GLuint srcLengthOverride)557 napi_value WebGLRenderingContextBaseImpl::CompressedTexImage2D(
558     napi_env env, const TexImageArg& info, napi_value srcData, GLuint srcOffset, GLuint srcLengthOverride)
559 {
560     TexImageArg& imgArg = const_cast<TexImageArg&>(info);
561     imgArg.Dump("WebGL compressedTexImage2D");
562 
563     WebGLReadBufferArg bufferData(env);
564     bool succ = bufferData.GenBufferData(srcData, BUFFER_DATA_FLOAT_32) == napi_ok;
565     if (!succ) {
566         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "GenBufferData failed");
567         return NVal::CreateNull(env).val_;
568     }
569     bufferData.DumpBuffer(bufferData.GetBufferDataType());
570 
571     GLvoid* data = reinterpret_cast<GLvoid*>(bufferData.GetBuffer());
572     size_t length = bufferData.GetBufferLength();
573     if (srcOffset != 0) {
574         data = reinterpret_cast<GLvoid*>(bufferData.GetBuffer() + srcOffset * bufferData.GetBufferDataSize());
575     }
576     if (srcLengthOverride != 0) {
577         length = srcLengthOverride;
578     }
579 
580     GLenum result = CheckCompressedTexImage2D(env, imgArg, length);
581     if (result != WebGLRenderingContextBase::NO_ERROR) {
582         SET_ERROR_WITH_LOG(result, "CheckCompressedTexImage2D failed");
583         return NVal::CreateNull(env).val_;
584     }
585     glCompressedTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height,
586         imgArg.border, static_cast<GLsizei>(length), data);
587 
588     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
589     if (texture != nullptr) {
590         texture->SetTextureLevel(
591             { imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.width, imgArg.height, 1, GL_UNSIGNED_BYTE });
592     }
593     LOGD("WebGL compressedTexImage2D %{public}u", GetError_());
594     return NVal::CreateNull(env).val_;
595 }
596 
CheckCompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,size_t imageSize)597 bool WebGLRenderingContextBaseImpl::CheckCompressedTexSubImage2D(
598     napi_env env, const TexSubImage2DArg& imgArg, size_t imageSize)
599 {
600     if (imgArg.border) {
601         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.border %{public}d", imgArg.border);
602         return false;
603     }
604     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
605     if (result != WebGLRenderingContextBase::NO_ERROR) {
606         SET_ERROR_WITH_LOG(result, "CheckTextureLevel failed");
607         return false;
608     }
609     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
610     if (texture == nullptr || texture->CheckImmutable()) {
611         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
612             "texture is nullptr or CheckImmutable failed");
613         return false;
614     }
615     if (!CheckTexImageInternalFormat(env, imgArg.func, imgArg.format)) {
616         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_ENUM, "CheckTexImageInternalFormat failed");
617         return false;
618     }
619     result = CheckCompressedTexData(imgArg, imageSize);
620     if (result != WebGLRenderingContextBase::NO_ERROR) {
621         SET_ERROR_WITH_LOG(result, "CheckCompressedTexData failed");
622         return false;
623     }
624     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
625         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.level %{public}d", imgArg.level);
626         return false;
627     }
628     result = CheckCompressedTexSubDimensions(imgArg, texture);
629     if (result != WebGLRenderingContextBase::NO_ERROR) {
630         SET_ERROR_WITH_LOG(result, "CheckCompressedTexSubDimensions failed");
631         return false;
632     }
633     return true;
634 }
635 
CompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,napi_value srcData,GLuint srcOffset,GLuint srcLengthOverride)636 napi_value WebGLRenderingContextBaseImpl::CompressedTexSubImage2D(
637     napi_env env, const TexSubImage2DArg& imgArg, napi_value srcData, GLuint srcOffset, GLuint srcLengthOverride)
638 {
639     imgArg.Dump("WebGL compressedTexSubImage2D");
640     WebGLReadBufferArg bufferData(env);
641     GLvoid* data = nullptr;
642     GLsizei length = 0;
643     if (!NVal(env, srcData).IsNull()) {
644         bool succ = bufferData.GenBufferData(srcData, BUFFER_DATA_FLOAT_32) == napi_ok;
645         if (!succ) {
646             return NVal::CreateNull(env).val_;
647         }
648         bufferData.DumpBuffer(bufferData.GetBufferDataType());
649         data = reinterpret_cast<void*>(bufferData.GetBuffer() + srcOffset * bufferData.GetBufferDataSize());
650         length = srcLengthOverride == 0 ?
651             static_cast<GLsizei>(bufferData.GetBufferLength()) : static_cast<GLsizei>(srcLengthOverride);
652     }
653     bool succ = CheckCompressedTexSubImage2D(env, imgArg, length);
654     if (!succ) {
655         return NVal::CreateNull(env).val_;
656     }
657     glCompressedTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
658         imgArg.format, length, data);
659     LOGD("WebGL compressedTexSubImage2D result: %{public}u", GetError_());
660     return NVal::CreateNull(env).val_;
661 }
662 
CompressedTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,GLsizei imageSize,GLintptr offset)663 napi_value WebGLRenderingContextBaseImpl::CompressedTexSubImage2D(
664     napi_env env, const TexSubImage2DArg& imgArg, GLsizei imageSize, GLintptr offset)
665 {
666     imgArg.Dump("WebGL compressedTexSubImage2D");
667     bool succ = CheckCompressedTexSubImage2D(env, imgArg, imageSize);
668     if (!succ) {
669         return NVal::CreateNull(env).val_;
670     }
671     glCompressedTexSubImage2D(imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.width, imgArg.height,
672         imgArg.format, imageSize, reinterpret_cast<void*>(offset));
673     LOGD("WebGL compressedTexSubImage2D result %{public}u", GetError_());
674     return NVal::CreateNull(env).val_;
675 }
676 
CopyTexImage2D(napi_env env,const CopyTexImage2DArg & imgArg)677 napi_value WebGLRenderingContextBaseImpl::CopyTexImage2D(napi_env env, const CopyTexImage2DArg& imgArg)
678 {
679     if (imgArg.border) {
680         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE, "imgArg.border %{public}d", imgArg.border);
681         return NVal::CreateNull(env).val_;
682     }
683     imgArg.Dump("WebGL copyTexImage2D");
684     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
685     if (result != WebGLRenderingContextBase::NO_ERROR) {
686         SET_ERROR_WITH_LOG(result, "CheckTextureLevel failed");
687         return NVal::CreateNull(env).val_;
688     }
689     WebGLTexture* texture = GetBoundTexture(env, imgArg.target, true);
690     if (!texture || texture->CheckImmutable()) {
691         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_OPERATION,
692             "texture is nullptr or CheckImmutable failed");
693         return NVal::CreateNull(env).val_;
694     }
695     result = CheckTextureFormatAndType(env,
696         imgArg.internalFormat, imgArg.internalFormat, GL_UNSIGNED_BYTE, imgArg.level);
697     if (result != WebGLRenderingContextBase::NO_ERROR) {
698         SET_ERROR_WITH_LOG(result, "CheckTextureFormatAndType failed");
699         return NVal::CreateNull(env).val_;
700     }
701     result = CheckTexFuncDimensions(imgArg);
702     if (result != WebGLRenderingContextBase::NO_ERROR) {
703         SET_ERROR_WITH_LOG(result, "CheckTexFuncDimensions failed");
704         return NVal::CreateNull(env).val_;
705     }
706     if (!IsHighWebGL() && imgArg.level && WebGLTexture::CheckNPOT(imgArg.width, imgArg.height)) {
707         SET_ERROR_WITH_LOG(WebGLRenderingContextBase::INVALID_VALUE,
708             "imgArg.level %{public}d %{public}d", imgArg.level, IsHighWebGL());
709         return NVal::CreateNull(env).val_;
710     }
711     GLuint frameBufferId = 0;
712     result = CheckReadBufferAndGetInfo(env, &frameBufferId, nullptr, nullptr);
713     if (result != WebGLRenderingContextBase::NO_ERROR) {
714         SET_ERROR_WITH_LOG(result, "CheckReadBufferAndGetInfo failed");
715         return NVal::CreateNull(env).val_;
716     }
717 
718     glCopyTexImage2D(imgArg.target, imgArg.level, imgArg.internalFormat, imgArg.x, imgArg.y, imgArg.width,
719         imgArg.height, imgArg.border);
720 
721     texture->SetTextureLevel({ imgArg.target, imgArg.level, imgArg.internalFormat,
722         imgArg.width, imgArg.height, 1, 1 });
723     return NVal::CreateNull(env).val_;
724 }
725 
CopyTexSubImage2D(napi_env env,const CopyTexSubImageArg & imgArg)726 napi_value WebGLRenderingContextBaseImpl::CopyTexSubImage2D(napi_env env, const CopyTexSubImageArg& imgArg)
727 {
728     imgArg.Dump("WebGL copyTexSubImage2D");
729     GLenum result = CheckCopyTexSubImage(env, imgArg);
730     if (result != WebGLRenderingContextBase::NO_ERROR) {
731         SET_ERROR_WITH_LOG(result, "CheckCopyTexSubImage failed");
732         return NVal::CreateNull(env).val_;
733     }
734 
735     GLuint frameBufferId = 0;
736     result = CheckReadBufferAndGetInfo(env, &frameBufferId, nullptr, nullptr);
737     if (result != WebGLRenderingContextBase::NO_ERROR) {
738         SET_ERROR_WITH_LOG(result, "CheckReadBufferAndGetInfo failed");
739         return NVal::CreateNull(env).val_;
740     }
741     glCopyTexSubImage2D(
742         imgArg.target, imgArg.level, imgArg.xOffset, imgArg.yOffset, imgArg.x, imgArg.y, imgArg.width, imgArg.height);
743     return NVal::CreateNull(env).val_;
744 }
745 
CheckTextureLevel(GLenum target,GLint level)746 GLenum WebGLRenderingContextBaseImpl::CheckTextureLevel(GLenum target, GLint level)
747 {
748     GLint max = WebGLTexture::GetMaxTextureLevelForTarget(target, IsHighWebGL());
749     if (max <= 0) {
750         return WebGLRenderingContextBase::INVALID_ENUM;
751     }
752     if ((level < 0) || level > max) {
753         return WebGLRenderingContextBase::INVALID_VALUE;
754     }
755     return WebGLRenderingContextBase::NO_ERROR;
756 }
757 
CheckTexImage(napi_env env,const TexImageArg & imgArg,WebGLTexture * texture)758 GLenum WebGLRenderingContextBaseImpl::CheckTexImage(napi_env env, const TexImageArg& imgArg, WebGLTexture* texture)
759 {
760     if (imgArg.border) {
761         return WebGLRenderingContextBase::INVALID_VALUE;
762     }
763     GLenum result = CheckTextureLevel(imgArg.target, imgArg.level);
764     if (result != WebGLRenderingContextBase::NO_ERROR) {
765         return result;
766     }
767     GLenum internalFormat = imgArg.internalFormat;
768     if (imgArg.internalFormat == 0) {
769         internalFormat = texture->GetInternalFormat(imgArg.target, imgArg.level);
770     }
771     if (internalFormat == 0) {
772         LOGE("Invalid internalFormat %{public}u", internalFormat);
773         return WebGLRenderingContextBase::INVALID_OPERATION;
774     }
775     result = CheckTextureFormatAndType(env, internalFormat, imgArg.format, imgArg.type, imgArg.level);
776     if (result != WebGLRenderingContextBase::NO_ERROR) {
777         return result;
778     }
779     result = CheckTexFuncDimensions(imgArg);
780     if (result != WebGLRenderingContextBase::NO_ERROR) {
781         LOGE("Invalid texture dimension or type %{public}u", result);
782         return result;
783     }
784     return WebGLRenderingContextBase::NO_ERROR;
785 }
786 
CheckTexSubImage2D(napi_env env,const TexSubImage2DArg & imgArg,WebGLTexture * texture)787 GLenum WebGLRenderingContextBaseImpl::CheckTexSubImage2D(
788     napi_env env, const TexSubImage2DArg& imgArg, WebGLTexture* texture)
789 {
790     if (imgArg.xOffset < 0 || imgArg.yOffset < 0) {
791         LOGE("WebGL CheckTexSubImage2D invalid xOffset %{public}d", imgArg.xOffset);
792         return WebGLRenderingContextBase::INVALID_VALUE;
793     }
794 
795     // Before checking if it is in the range, check if overflow happens first.
796     if (imgArg.xOffset + imgArg.width < 0 || imgArg.yOffset + imgArg.height < 0) {
797         return WebGLRenderingContextBase::INVALID_VALUE;
798     }
799     if ((imgArg.xOffset + imgArg.width) > texture->GetWidth(imgArg.target, imgArg.level) ||
800         (imgArg.yOffset + imgArg.height) > texture->GetHeight(imgArg.target, imgArg.level)) {
801         LOGE("WebGL invalid CheckTexSubImage2D GetWidth %{public}u, GetHeight %{public}d",
802             texture->GetWidth(imgArg.target, imgArg.level), texture->GetHeight(imgArg.target, imgArg.level));
803         return WebGLRenderingContextBase::INVALID_VALUE;
804     }
805     if (!IsHighWebGL() && texture->GetType(imgArg.target, imgArg.level) != imgArg.type) {
806         LOGE("WebGL invalid CheckTexSubImage2D type %{public}d", imgArg.type);
807         return WebGLRenderingContextBase::INVALID_OPERATION;
808     }
809     return WebGLRenderingContextBase::NO_ERROR;
810 }
811 
CheckTexImageInternalFormat(napi_env env,int32_t func,GLenum internalFormat)812 bool WebGLRenderingContextBaseImpl::CheckTexImageInternalFormat(napi_env env, int32_t func, GLenum internalFormat)
813 {
814     return CheckInList(internalFormat, WebGLRenderingContextBaseImpl::GetTexImageInternalFormat());
815 }
816 
CheckTexFuncDimensions(const TexImageArg & imgArg)817 GLenum WebGLRenderingContextBaseImpl::CheckTexFuncDimensions(const TexImageArg& imgArg)
818 {
819     if (imgArg.width < 0 || imgArg.height < 0) {
820         LOGE("Invalid offset or size ");
821         return WebGLRenderingContextBase::INVALID_VALUE;
822     }
823     switch (imgArg.target) {
824         case GL_TEXTURE_2D:
825             if (static_cast<GLuint>(imgArg.width) > (static_cast<GLuint>(maxTextureSize_) >> imgArg.level) ||
826                 static_cast<GLuint>(imgArg.height) > (static_cast<GLuint>(maxTextureSize_) >> imgArg.level)) {
827                 return WebGLRenderingContextBase::INVALID_VALUE;
828             }
829             break;
830         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
831         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
832         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
833         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
834         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
835         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
836             if (imgArg.func != IMAGE_TEX_SUB_IMAGE_2D && imgArg.width != imgArg.height) {
837                 return WebGLRenderingContextBase::INVALID_VALUE;
838             }
839             if (static_cast<uint32_t>(imgArg.width) > (static_cast<uint32_t>(maxCubeMapTextureSize_) >>
840                 static_cast<uint32_t>(imgArg.level))) {
841                 return WebGLRenderingContextBase::INVALID_VALUE;
842             }
843             break;
844         default:
845             return WebGLRenderingContextBase::INVALID_ENUM;
846     }
847     return WebGLRenderingContextBase::NO_ERROR;
848 }
849 
CheckCompressedTexDimensions(const TexImageArg & imgArg)850 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexDimensions(const TexImageArg& imgArg)
851 {
852     GLenum result = CheckTexFuncDimensions(imgArg);
853     if (result != WebGLRenderingContextBase::NO_ERROR) {
854         LOGE("Invalid tex dimensions %{public}u %{public}d", imgArg.target, imgArg.level);
855         return result;
856     }
857     if (CheckInList(imgArg.internalFormat, GetExtentionAstcTexImageInternal())) {
858         return WebGLRenderingContextBase::NO_ERROR;
859     }
860     bool widthValid = true;
861     bool heightValid = true;
862     switch (imgArg.internalFormat) {
863 #ifdef GC3D_COMPRESSED_ATC_RGB_AMD
864         case GC3D_COMPRESSED_ATC_RGB_AMD:
865         case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
866         case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
867 #endif
868         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
869         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
870         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
871         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
872             widthValid = (imgArg.level && imgArg.width == 1) || (imgArg.level && imgArg.width == 2) ||
873                 !(imgArg.width % 4); // 1 2 4 ALIGNMENT
874             heightValid = (imgArg.level && imgArg.height == 1) || (imgArg.level && imgArg.height == 2) ||
875                 !(imgArg.height % 4); // 1 2 4 ALIGNMENT
876             break;
877         }
878         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
879         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
880         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
881         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
882             widthValid = (static_cast<uint32_t>(imgArg.width) & static_cast<uint32_t>(imgArg.width - 1)) == 0;
883             heightValid = (static_cast<uint32_t>(imgArg.height) & static_cast<uint32_t>(imgArg.height - 1)) == 0;
884             break;
885         }
886         default:
887             return WebGLRenderingContextBase::NO_ERROR;
888     }
889 
890     if (!widthValid || !heightValid) {
891         return WebGLRenderingContextBase::INVALID_OPERATION;
892     }
893     return WebGLRenderingContextBase::NO_ERROR;
894 }
895 
CheckCompressedTexData(const TexImageArg & imgArg,size_t dataLen)896 GLenum WebGLRenderingContextBaseImpl::CheckCompressedTexData(const TexImageArg& imgArg, size_t dataLen)
897 {
898     size_t bytesRequired = 0;
899     switch (imgArg.internalFormat) {
900         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
901         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: {
902             const int32_t kBlockWidth = 4;
903             const int32_t kBlockHeight = 4;
904             const int32_t kBlockSize = 8;
905             int32_t numBlocksAcross = (imgArg.width + kBlockWidth - 1) / kBlockWidth;
906             int32_t numBlocksDown = (imgArg.height + kBlockHeight - 1) / kBlockHeight;
907             int32_t numBlocks = numBlocksAcross * numBlocksDown;
908             bytesRequired = static_cast<size_t>(numBlocks * kBlockSize);
909             break;
910         }
911         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
912         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
913             const int32_t kBlockWidth = 4;
914             const int32_t kBlockHeight = 4;
915             const int32_t kBlockSize = 16;
916             int32_t numBlocksAcross = (imgArg.width + kBlockWidth - 1) / kBlockWidth;
917             int32_t numBlocksDown = (imgArg.height + kBlockHeight - 1) / kBlockHeight;
918             int32_t numBlocks = numBlocksAcross * numBlocksDown;
919             bytesRequired = static_cast<size_t>(numBlocks * kBlockSize);
920             break;
921         }
922         case GL_ETC1_RGB8_OES: { // 3 kBlockWidth -1, 4 kBlockWidth, 8 kBlockSize
923             bytesRequired = floor(static_cast<double>((imgArg.width + 3) / 4)) *
924                 floor(static_cast<double>((imgArg.height + 3) / 4)) * 8;
925             break;
926         }
927         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
928         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: { // 4 4BPPV1, 7 kBlockWidth -1, 8 kBlockWidth, 8 kBlockSize
929             bytesRequired = (max(imgArg.width, 8) * max(imgArg.height, 8) * 4 + 7) / 8;
930             break;
931         }
932         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
933         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { // 2 2BPPV1, 7 kBlockWidth - 1, 16 kBlockWidth, 8 kBlockSize
934             bytesRequired = (max(imgArg.width, 16) * max(imgArg.height, 8) * 2 + 7) / 8;
935             break;
936         }
937         default:
938             return WebGLRenderingContextBase::INVALID_ENUM;
939     }
940     LOGD("CheckCompressedTexData bytesRequired %{public}zu", bytesRequired);
941     if (dataLen != bytesRequired) {
942         return WebGLRenderingContextBase::INVALID_VALUE;
943     }
944     return WebGLRenderingContextBase::NO_ERROR;
945 }
946 
CheckCompressedTexSubDimensions(const TexSubImage2DArg & imgArg,WebGLTexture * texture)947 bool WebGLRenderingContextBaseImpl::CheckCompressedTexSubDimensions(
948     const TexSubImage2DArg& imgArg, WebGLTexture* texture)
949 {
950     if (imgArg.xOffset < 0 || imgArg.yOffset < 0) {
951         return WebGLRenderingContextBase::INVALID_VALUE;
952     }
953 
954     switch (imgArg.format) {
955         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
956         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
957         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
958         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
959             const int32_t kBlockWidth = 4;
960             const int32_t kBlockHeight = 4;
961             if ((imgArg.xOffset % kBlockWidth) || (imgArg.yOffset % kBlockHeight)) {
962                 return WebGLRenderingContextBase::INVALID_OPERATION;
963             }
964             if (WebGLArg::CheckOverflow<GLint, GLint>(imgArg.xOffset, imgArg.width) ||
965                 WebGLArg::CheckOverflow<GLint, GLint>(imgArg.yOffset, imgArg.height)) {
966                 return WebGLRenderingContextBase::INVALID_VALUE;
967             }
968 
969             if ((imgArg.xOffset + imgArg.width) > texture->GetWidth(imgArg.target, imgArg.level) ||
970                 (imgArg.yOffset + imgArg.height) > texture->GetHeight(imgArg.target, imgArg.level)) {
971                 return WebGLRenderingContextBase::INVALID_VALUE;
972             }
973             return CheckCompressedTexDimensions(imgArg);
974         }
975         case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
976         case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
977         case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
978         case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
979             if ((imgArg.xOffset != 0) || (imgArg.yOffset != 0)) {
980                 return WebGLRenderingContextBase::INVALID_OPERATION;
981             }
982             if (imgArg.width != texture->GetWidth(imgArg.target, imgArg.level) ||
983                 imgArg.height != texture->GetHeight(imgArg.target, imgArg.level)) {
984                 return WebGLRenderingContextBase::INVALID_OPERATION;
985             }
986             return CheckCompressedTexDimensions(imgArg);
987         }
988         case GL_ETC1_RGB8_OES: {
989             return WebGLRenderingContextBase::INVALID_OPERATION;
990         }
991         default:
992             return WebGLRenderingContextBase::INVALID_ENUM;
993     }
994     return WebGLRenderingContextBase::NO_ERROR;
995 }
996 
CheckTextureDataBuffer(const TexImageArg & arg,const WebGLReadBufferArg * bufferData)997 GLenum WebGLRenderingContextBaseImpl::CheckTextureDataBuffer(
998     const TexImageArg& arg, const WebGLReadBufferArg* bufferData)
999 {
1000     if (!bufferData) {
1001         return WebGLRenderingContextBase::INVALID_VALUE;
1002     }
1003     if (WebGLTexture::ChangeToBufferDataType(arg.type) != bufferData->GetBufferDataType()) {
1004         return WebGLRenderingContextBase::INVALID_OPERATION;
1005     }
1006     return WebGLRenderingContextBase::NO_ERROR;
1007 }
1008 
CheckCopyTexSubImage(napi_env env,const CopyTexSubImageArg & arg)1009 GLenum WebGLRenderingContextBaseImpl::CheckCopyTexSubImage(napi_env env, const CopyTexSubImageArg& arg)
1010 {
1011     GLenum result = CheckTextureLevel(arg.target, arg.level);
1012     if (result != WebGLRenderingContextBase::NO_ERROR) {
1013         return result;
1014     }
1015 
1016     WebGLTexture* texture = GetBoundTexture(env, arg.target, false);
1017     if (texture == nullptr) {
1018         return WebGLRenderingContextBase::INVALID_OPERATION;
1019     }
1020 
1021     if (!WebGLTexture::CheckTextureSize(arg.xOffset, arg.width, texture->GetWidth(arg.target, arg.level)) ||
1022         !WebGLTexture::CheckTextureSize(arg.yOffset, arg.height, texture->GetHeight(arg.target, arg.level))) {
1023         return WebGLRenderingContextBase::INVALID_VALUE;
1024     }
1025     if (arg.func == IMAGE_COPY_TEX_SUB_IMAGE_3D) {
1026         const CopyTexSubImage3DArg* img3D = reinterpret_cast<const CopyTexSubImage3DArg*>(&arg);
1027         if (!WebGLTexture::CheckTextureSize(img3D->zOffset, img3D->depth, texture->GetDepth(arg.target, arg.level))) {
1028             return WebGLRenderingContextBase::INVALID_VALUE;
1029         }
1030     }
1031     return WebGLRenderingContextBase::NO_ERROR;
1032 }
1033 
CheckDrawArrays(napi_env env,GLenum mode,GLint first,GLsizei count)1034 GLenum WebGLRenderingContextBaseImpl::CheckDrawArrays(napi_env env, GLenum mode, GLint first, GLsizei count)
1035 {
1036     if (!CheckDrawMode(env, mode)) {
1037         return WebGLRenderingContextBase::INVALID_ENUM;
1038     }
1039     if (!CheckStencil(env)) {
1040         return WebGLRenderingContextBase::INVALID_OPERATION;
1041     }
1042 
1043     if (first < 0 || count < 0) {
1044         return WebGLRenderingContextBase::INVALID_VALUE;
1045     }
1046 
1047     if (!currentProgramId_) {
1048         LOGE("WebGL drawArrays no valid shader program in use");
1049         return WebGLRenderingContextBase::INVALID_OPERATION;
1050     }
1051 
1052     return CheckFrameBufferBoundComplete(env);
1053 }
1054 
CheckDrawElements(napi_env env,GLenum mode,GLsizei count,GLenum type,int64_t offset)1055 GLenum WebGLRenderingContextBaseImpl::CheckDrawElements(
1056     napi_env env, GLenum mode, GLsizei count, GLenum type, int64_t offset)
1057 {
1058     if (!CheckDrawMode(env, mode)) {
1059         return WebGLRenderingContextBase::INVALID_ENUM;
1060     }
1061     if (!CheckStencil(env)) {
1062         return WebGLRenderingContextBase::INVALID_OPERATION;
1063     }
1064 
1065     uint32_t size = 1;
1066     switch (type) {
1067         case WebGLRenderingContextBase::UNSIGNED_BYTE:
1068             break;
1069         case WebGLRenderingContextBase::UNSIGNED_SHORT:
1070             size = sizeof(short);
1071             break;
1072         case WebGLRenderingContextBase::UNSIGNED_INT: {
1073             size = sizeof(int);
1074             if (IsHighWebGL()) {
1075                 break;
1076             }
1077             [[fallthrough]];
1078         }
1079         default:
1080             return WebGLRenderingContextBase::INVALID_ENUM;
1081     }
1082     if (count < 0 || offset < 0) {
1083         return WebGLRenderingContextBase::INVALID_VALUE;
1084     }
1085     if ((offset % static_cast<int64_t>(size)) != 0) {
1086         return WebGLRenderingContextBase::INVALID_VALUE;
1087     }
1088     WebGLBuffer* webGLBuffer =
1089         GetObjectInstance<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::ELEMENT_ARRAY_BUFFER]);
1090     if (webGLBuffer == nullptr || webGLBuffer->GetBufferSize() == 0) {
1091         return WebGLRenderingContextBase::INVALID_OPERATION;
1092     }
1093 
1094     // check count
1095     if (static_cast<uint32_t>(size * count) > static_cast<uint32_t>(webGLBuffer->GetBufferSize())) {
1096         LOGE("WebGL drawElements Insufficient buffer size %{public}d", count);
1097         return WebGLRenderingContextBase::INVALID_OPERATION;
1098     }
1099     if (static_cast<size_t>(offset) >= webGLBuffer->GetBufferSize()) {
1100         LOGE("WebGL drawElements invalid offset %{public}" PRIi64, offset);
1101         return WebGLRenderingContextBase::INVALID_VALUE;
1102     }
1103 
1104     if (!currentProgramId_) {
1105         LOGE("WebGL drawArrays no valid shader program in use");
1106         return WebGLRenderingContextBase::INVALID_OPERATION;
1107     }
1108 
1109     return CheckFrameBufferBoundComplete(env);
1110 }
1111 
CheckReadBufferAndGetInfo(napi_env env,GLuint * frameBufferId,GLenum * format,GLenum * type)1112 GLenum WebGLRenderingContextBaseImpl::CheckReadBufferAndGetInfo(
1113     napi_env env, GLuint* frameBufferId, GLenum* format, GLenum* type)
1114 {
1115     GLenum target = IsHighWebGL() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
1116     WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, target);
1117     if (frameBuffer) {
1118         LOGD("CheckReadBufferAndGetInfo frameBuffer %{public}u", frameBuffer->GetFramebuffer());
1119         if (frameBuffer->CheckStatus(env, this) != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
1120             LOGE("CheckStatus not FRAMEBUFFER_COMPLETE");
1121             return WebGLRenderingContextBase::INVALID_FRAMEBUFFER_OPERATION;
1122         }
1123         if (!GetReadBufferFormatAndType(env, frameBuffer, format, type)) {
1124             return WebGLRenderingContextBase::INVALID_OPERATION;
1125         }
1126         *frameBufferId = frameBuffer->GetFramebuffer();
1127     } else {
1128         if (defaultReadBufferMode_ == GL_NONE) {
1129             LOGE("defaultReadBufferMode_ %{public}u", defaultReadBufferMode_);
1130             return WebGLRenderingContextBase::INVALID_OPERATION;
1131         }
1132         if (format) {
1133             *format = GL_RGBA;
1134         }
1135         if (type) {
1136             *type = GL_UNSIGNED_BYTE;
1137         }
1138     }
1139     return WebGLRenderingContextBase::NO_ERROR;
1140 }
1141 
GetReadBufferFormatAndType(napi_env env,const WebGLFramebuffer * frameBuffer,GLenum * format,GLenum * type)1142 bool WebGLRenderingContextBaseImpl::GetReadBufferFormatAndType(
1143     napi_env env, const WebGLFramebuffer* frameBuffer, GLenum* format, GLenum* type)
1144 {
1145     GLenum mode = frameBuffer->GetReadBufferMode();
1146     LOGD("GetReadBufferFormatAndType mode %{public}u", mode);
1147     if (mode == GL_NONE) {
1148         return false;
1149     }
1150     WebGLAttachment* attachedObject = frameBuffer->GetAttachment(mode);
1151     if (!attachedObject) {
1152         LOGE("GetReadBufferFormatAndType no attachment %{public}u", mode);
1153         return false;
1154     }
1155     WebGLAttachmentInfo info = {};
1156     if (!frameBuffer->GetWebGLAttachmentInfo(env, this, attachedObject, info)) {
1157         LOGE("GetReadBufferFormatAndType no attachment info %{public}u", mode);
1158         return false;
1159     }
1160     if (format) {
1161         *format = info.format;
1162     }
1163     if (type) {
1164         *type = info.type;
1165     }
1166     return true;
1167 }
1168 
CheckTextureFormatAndType(napi_env env,GLenum internalFormat,GLenum format,GLenum type,GLint level)1169 GLenum WebGLRenderingContextBaseImpl::CheckTextureFormatAndType(
1170     napi_env env, GLenum internalFormat, GLenum format, GLenum type, GLint level)
1171 {
1172     LOGD("internalFormat %{public}u format %{public}u type %{public}u %{public}d",
1173         internalFormat, format, type, level);
1174     if (!CheckInList(internalFormat, WebGLTexture::GetSupportedInternalFormats())) {
1175         LOGE("Invalid internalFormat %{public}u ", internalFormat);
1176         return GL_INVALID_ENUM;
1177     }
1178     if (!CheckInList(format, WebGLTexture::GetSupportedFormats())) {
1179         LOGE("Invalid format %{public}u ", format);
1180         return GL_INVALID_ENUM;
1181     }
1182     if (!CheckInList(type, WebGLTexture::GetSupportedTypes())) {
1183         LOGE("Invalid type %{public}u ", type);
1184         return GL_INVALID_ENUM;
1185     }
1186 
1187     TextureFormatTypeMap map = { internalFormat, format, type };
1188     if (WebGLTexture::GetSupportedFormatTypeMaps().find(map) == WebGLTexture::GetSupportedFormatTypeMaps().end()) {
1189         LOGE("Invalid format type ");
1190         return GL_INVALID_OPERATION;
1191     }
1192 
1193     if ((format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_OES) && level > 0 && !IsHighWebGL()) {
1194         return GL_INVALID_OPERATION;
1195     }
1196     return 0;
1197 }
1198 } // namespace Impl
1199 } // namespace Rosen
1200 } // namespace OHOS
1201