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