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