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