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/webgl2_rendering_context_base.h"
16 #include "context/webgl2_rendering_context_impl.h"
17 #include "context/webgl_rendering_context_base.h"
18 #include "napi/n_func_arg.h"
19 #include "util/log.h"
20 #include "webgl/webgl_arg.h"
21 #include "webgl/webgl_buffer.h"
22 #include "webgl/webgl_framebuffer.h"
23 #include "webgl/webgl_program.h"
24 #include "webgl/webgl_renderbuffer.h"
25 #include "webgl/webgl_sampler.h"
26 #include "webgl/webgl_shader.h"
27 #include "webgl/webgl_texture.h"
28 #include "webgl/webgl_transform_feedback.h"
29 #include "webgl/webgl_uniform_location.h"
30 #include "webgl/webgl_vertex_array_object.h"
31
32 namespace OHOS {
33 namespace Rosen {
34 namespace Impl {
35 using namespace std;
GetParameter(napi_env env,GLenum pname)36 napi_value WebGL2RenderingContextImpl::GetParameter(napi_env env, GLenum pname)
37 {
38 switch (pname) {
39 case GL_SHADING_LANGUAGE_VERSION: {
40 std::string str("WebGL GLSL ES 3.00 (");
41 str += std::string(const_cast<char*>(reinterpret_cast<const char*>(glGetString(pname))));
42 str += ")";
43 return NVal::CreateUTF8String(env, str).val_;
44 }
45 case GL_VERSION: {
46 std::string str("WebGL 2.0 (");
47 str += std::string(const_cast<char*>(reinterpret_cast<const char*>(glGetString(pname))));
48 str += ")";
49 return NVal::CreateUTF8String(env, str).val_;
50 }
51 case GL_COPY_READ_BUFFER_BINDING:
52 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::COPY_READ_BUFFER]);
53 case GL_COPY_WRITE_BUFFER_BINDING:
54 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::COPY_WRITE_BUFFER]);
55 case GL_DRAW_FRAMEBUFFER_BINDING:
56 return GetObject<WebGLBuffer>(env, boundFrameBufferIds_[BoundFrameBufferType::DRAW_FRAMEBUFFER]);
57 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
58 return WebGLArg::GetUint32Parameter(env, pname);
59 case GL_MAX_3D_TEXTURE_SIZE:
60 case GL_MAX_ARRAY_TEXTURE_LAYERS:
61 case GL_MAX_COLOR_ATTACHMENTS:
62 case GL_MAX_COMBINED_UNIFORM_BLOCKS:
63 case GL_MAX_DRAW_BUFFERS:
64 case GL_MAX_ELEMENTS_INDICES:
65 case GL_MAX_ELEMENTS_VERTICES:
66 case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
67 case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: //
68 case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
69 case GL_MAX_PROGRAM_TEXEL_OFFSET:
70 case GL_MAX_SAMPLES:
71 case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
72 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
73 case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
74 case GL_MAX_UNIFORM_BUFFER_BINDINGS:
75 case GL_MAX_VARYING_COMPONENTS:
76 case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
77 case GL_MAX_VERTEX_UNIFORM_BLOCKS:
78 case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
79 case GL_MIN_PROGRAM_TEXEL_OFFSET:
80 case GL_PACK_ROW_LENGTH:
81 case GL_PACK_SKIP_PIXELS:
82 case GL_PACK_SKIP_ROWS:
83 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
84 case GL_UNPACK_IMAGE_HEIGHT:
85 case GL_UNPACK_ROW_LENGTH:
86 return WebGLArg::GetInt32Parameter(env, pname);
87 case GL_MAX_UNIFORM_BLOCK_SIZE:
88 case GL_MAX_SERVER_WAIT_TIMEOUT:
89 case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
90 case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
91 case GL_MAX_ELEMENT_INDEX:
92 return WebGLArg::GetInt64Parameter(env, pname);
93 case GL_MAX_TEXTURE_LOD_BIAS:
94 return WebGLArg::GetFloatParameter(env, pname);
95 case GL_PIXEL_PACK_BUFFER_BINDING: //
96 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::PIXEL_PACK_BUFFER]);
97 case GL_PIXEL_UNPACK_BUFFER_BINDING:
98 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::PIXEL_UNPACK_BUFFER]);
99 case GL_RASTERIZER_DISCARD:
100 case GL_SAMPLE_ALPHA_TO_COVERAGE:
101 case GL_SAMPLE_COVERAGE:
102 case GL_TRANSFORM_FEEDBACK_ACTIVE:
103 case GL_TRANSFORM_FEEDBACK_PAUSED:
104 case GL_UNPACK_SKIP_IMAGES:
105 case GL_UNPACK_SKIP_PIXELS:
106 case GL_UNPACK_SKIP_ROWS:
107 return WebGLArg::GetBoolParameter(env, pname);
108 case WebGL2RenderingContextBase::MAX_CLIENT_WAIT_TIMEOUT_WEBGL:
109 return WebGLArg::GetInt32Parameter(env, WebGL2RenderingContextBase::MAX_CLIENT_WAIT_TIMEOUT_WEBGL);
110 case GL_READ_BUFFER:{
111 WebGLFramebuffer* readFrameBuffer = GetBoundFrameBuffer(env, GL_READ_FRAMEBUFFER);
112 GLenum value = readFrameBuffer != nullptr ? readFrameBuffer->GetReadBufferMode() : defaultReadBufferMode_;
113 return NVal::CreateInt64(env, value).val_;
114 }
115 case GL_READ_FRAMEBUFFER_BINDING:
116 return GetObject<WebGLFramebuffer>(env, boundBufferIds_[BoundFrameBufferType::READ_FRAMEBUFFER]);
117 case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
118 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::TRANSFORM_FEEDBACK_BUFFER]);
119 case GL_TRANSFORM_FEEDBACK_BINDING:
120 return GetObject<WebGLTransformFeedback>(env, boundTransformFeedback_);
121 case GL_UNIFORM_BUFFER_BINDING:
122 return GetObject<WebGLBuffer>(env, boundBufferIds_[BoundBufferType::UNIFORM_BUFFER]);
123 case GL_SAMPLER_BINDING:
124 return GetObject<WebGLSampler>(env, samplerUnits_[activeTextureIndex_]);
125 case GL_TEXTURE_BINDING_2D_ARRAY:
126 return GetObject<WebGLTexture>(env, boundTexture_[BoundTextureType::TEXTURE_2D_ARRAY][activeTextureIndex_]);
127 case GL_TEXTURE_BINDING_3D:
128 return GetObject<WebGLTexture>(env, boundTexture_[BoundTextureType::TEXTURE_3D][activeTextureIndex_]);
129 case GL_VERTEX_ARRAY_BINDING:
130 return GetObject<WebGLVertexArrayObject>(env, boundVertexArrayId_);
131 default:
132 break;
133 }
134 return WebGLRenderingContextBaseImpl::GetParameter(env, pname);
135 }
136
GetTexParameter(napi_env env,GLenum target,GLenum pname)137 napi_value WebGL2RenderingContextImpl::GetTexParameter(napi_env env, GLenum target, GLenum pname)
138 {
139 if (GetBoundTexture(env, target, false) == nullptr) {
140 return NVal::CreateNull(env).val_;
141 }
142 switch (pname) {
143 case GL_TEXTURE_WRAP_R:
144 case GL_TEXTURE_COMPARE_FUNC:
145 case GL_TEXTURE_COMPARE_MODE:
146 case GL_TEXTURE_IMMUTABLE_LEVELS: {
147 GLint value = 0;
148 glGetTexParameteriv(target, pname, &value);
149 return NVal::CreateInt64(env, static_cast<int64_t>(value)).val_;
150 }
151 case GL_TEXTURE_IMMUTABLE_FORMAT: {
152 GLint value = 0;
153 glGetTexParameteriv(target, pname, &value);
154 return NVal::CreateBool(env, value != 0).val_;
155 }
156 case GL_TEXTURE_BASE_LEVEL:
157 case GL_TEXTURE_MAX_LEVEL: {
158 GLint value = 0;
159 glGetTexParameteriv(target, pname, &value);
160 return NVal::CreateInt64(env, static_cast<int64_t>(value)).val_;
161 }
162 case GL_TEXTURE_MAX_LOD:
163 case GL_TEXTURE_MIN_LOD: {
164 GLfloat value = 0.f;
165 glGetTexParameterfv(target, pname, &value);
166 return NVal::CreateDouble(env, static_cast<double>(value)).val_;
167 }
168 default:
169 break;
170 }
171 return WebGLRenderingContextBaseImpl::GetTexParameter(env, target, pname);
172 }
173
CheckGetFrameBufferAttachmentParameter(napi_env env,GLenum target,GLenum attachment,const WebGLFramebuffer * frameBuffer)174 bool WebGL2RenderingContextImpl::CheckGetFrameBufferAttachmentParameter(
175 napi_env env, GLenum target, GLenum attachment, const WebGLFramebuffer* frameBuffer)
176 {
177 uint32_t index;
178 if (!CheckFrameBufferTarget(env, target, index)) {
179 SET_ERROR(GL_INVALID_ENUM);
180 return false;
181 }
182 if (frameBuffer == nullptr) { // for the default framebuffer
183 switch (attachment) {
184 case GL_BACK:
185 case GL_DEPTH:
186 case GL_STENCIL:
187 break;
188 default:
189 SET_ERROR(GL_INVALID_ENUM);
190 return false;
191 }
192 return true;
193 }
194 switch (attachment) {
195 case GL_COLOR_ATTACHMENT0:
196 case GL_DEPTH_ATTACHMENT:
197 case GL_STENCIL_ATTACHMENT:
198 case GL_DEPTH_STENCIL_ATTACHMENT:
199 break;
200 default:
201 if (attachment > GL_COLOR_ATTACHMENT0 &&
202 attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + GetMaxColorAttachments())) {
203 break;
204 }
205 SET_ERROR(GL_INVALID_ENUM);
206 return false;
207 }
208 return true;
209 }
210
GetFrameBufferAttachmentParameterForDefault(napi_env env,GLenum target,GLenum attachment,GLenum pname)211 napi_value WebGL2RenderingContextImpl::GetFrameBufferAttachmentParameterForDefault(
212 napi_env env, GLenum target, GLenum attachment, GLenum pname)
213 {
214 auto contextAttributes = webGLRenderingContext_->CreateWebGlContextAttributes();
215 if (contextAttributes == nullptr) {
216 return NVal::CreateNull(env).val_;
217 }
218 if ((attachment == GL_DEPTH && !contextAttributes->depth_) ||
219 (attachment == GL_STENCIL && !contextAttributes->stencil_)) {
220 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) {
221 return NVal::CreateInt64(env, GL_FRAMEBUFFER_DEFAULT).val_;
222 } else {
223 SET_ERROR(GL_INVALID_ENUM);
224 return NVal::CreateNull(env).val_;
225 }
226 }
227 switch (pname) {
228 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
229 return NVal::CreateInt64(env, GL_FRAMEBUFFER_DEFAULT).val_;
230 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
231 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
232 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: {
233 GLint value = attachment == GL_BACK ? 8 : 0; // 8 GREEN size
234 return NVal::CreateInt64(env, value).val_;
235 }
236 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: {
237 GLint value = (attachment == GL_BACK && contextAttributes->alpha_) ? 8 : 0; // 8 ALPHA size
238 return NVal::CreateInt64(env, value).val_;
239 }
240 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: {
241 // For ES3 capable backend, DEPTH24_STENCIL8 has to be supported.
242 GLint value = attachment == GL_DEPTH ? 24 : 0; // 24 depth size
243 return NVal::CreateInt64(env, value).val_;
244 }
245 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: {
246 GLint value = attachment == GL_STENCIL ? 8 : 0; // 8 STENCIL size
247 return NVal::CreateInt64(env, value).val_;
248 }
249 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
250 return NVal::CreateInt64(env, GL_UNSIGNED_NORMALIZED).val_;
251 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
252 return NVal::CreateInt64(env, GL_LINEAR).val_;
253 default:
254 break;
255 }
256 SET_ERROR(GL_INVALID_ENUM);
257 return NVal::CreateNull(env).val_;
258 }
259
HandleFrameBufferPname(napi_env env,GLenum target,GLenum attachment,GLenum pname,WebGLAttachment * attachmentObject)260 napi_value WebGL2RenderingContextImpl::HandleFrameBufferPname(
261 napi_env env, GLenum target, GLenum attachment, GLenum pname, WebGLAttachment* attachmentObject)
262 {
263 switch (pname) {
264 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
265 return attachmentObject->IsTexture() ? NVal::CreateInt64(env, GL_TEXTURE).val_ :
266 NVal::CreateInt64(env, GL_RENDERBUFFER).val_;
267 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
268 return attachmentObject->IsTexture() ? GetObject<WebGLTexture>(env, attachmentObject->id) :
269 GetObject<WebGLRenderbuffer>(env, attachmentObject->id);
270 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
271 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
272 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
273 if (!attachmentObject->IsTexture()) {
274 break;
275 }
276 [[fallthrough]];
277 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
278 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
279 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
280 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
281 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
282 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: {
283 GLint value = 0;
284 glGetFramebufferAttachmentParameteriv(target, attachment, pname, &value);
285 return NVal::CreateInt64(env, value).val_;
286 }
287 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
288 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
289 SET_ERROR(GL_INVALID_OPERATION);
290 return NVal::CreateNull(env).val_;
291 }
292 [[fallthrough]];
293 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: {
294 GLint value = 0;
295 glGetFramebufferAttachmentParameteriv(target, attachment, pname, &value);
296 return NVal::CreateInt64(env, value).val_;
297 }
298 default:
299 break;
300 }
301 SET_ERROR(GL_INVALID_ENUM);
302 return NVal::CreateNull(env).val_;
303 }
304
GetFrameBufferAttachmentParameter(napi_env env,GLenum target,GLenum attachment,GLenum pname)305 napi_value WebGL2RenderingContextImpl::GetFrameBufferAttachmentParameter(
306 napi_env env, GLenum target, GLenum attachment, GLenum pname)
307 {
308 WebGLFramebuffer* frameBuffer = GetBoundFrameBuffer(env, target);
309 if (CheckGetFrameBufferAttachmentParameter(env, target, attachment, frameBuffer)) {
310 return NVal::CreateNull(env).val_;
311 }
312
313 if (frameBuffer == nullptr) {
314 return GetFrameBufferAttachmentParameterForDefault(env, target, attachment, pname);
315 }
316
317 WebGLAttachment* attachmentObject = nullptr;
318 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
319 WebGLAttachment* depthAttachment = frameBuffer->GetAttachment(GL_DEPTH_ATTACHMENT);
320 WebGLAttachment* stencilAttachment = frameBuffer->GetAttachment(GL_STENCIL_ATTACHMENT);
321 if (depthAttachment == nullptr || stencilAttachment == nullptr ||
322 depthAttachment->id != stencilAttachment->id) {
323 SET_ERROR(GL_INVALID_OPERATION);
324 return NVal::CreateNull(env).val_;
325 }
326 attachmentObject = depthAttachment;
327 } else {
328 attachmentObject = frameBuffer->GetAttachment(attachment);
329 }
330
331 if (attachmentObject == nullptr) {
332 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) {
333 return NVal::CreateInt64(env, GL_NONE).val_;
334 } else if (pname != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
335 SET_ERROR(GL_INVALID_OPERATION);
336 }
337 return NVal::CreateNull(env).val_;
338 }
339 return HandleFrameBufferPname(env, target, attachment, pname, attachmentObject);
340 }
341
DoObjectDelete(int32_t type,WebGLObject * obj)342 void WebGL2RenderingContextImpl::DoObjectDelete(int32_t type, WebGLObject *obj)
343 {
344 WebGLRenderingContextBaseImpl::DoObjectDelete(type, obj);
345 if (type == WebGLObject::WEBGL_OBJECT_BUFFER) {
346 WebGLBuffer *buffer = static_cast<WebGLBuffer *>(obj);
347 LOGD("DoObjectDelete %{public}d %{public}u", type, buffer->GetBufferId());
348 for (size_t i = 0; i < boundIndexedTransformFeedbackBuffers_.size(); ++i) {
349 if (boundIndexedTransformFeedbackBuffers_[i] == buffer->GetBufferId()) {
350 boundIndexedTransformFeedbackBuffers_.erase(i);
351 break;
352 }
353 }
354 for (auto it = boundIndexedUniformBuffers_.begin(); it != boundIndexedUniformBuffers_.end(); ++it) {
355 if (it->second == buffer->GetBufferId()) {
356 boundIndexedUniformBuffers_.erase(it);
357 break;
358 }
359 }
360 }
361 }
362 } // namespace Impl
363 } // namespace Rosen
364 } // namespace OHOS
365