• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 
16 #include "webgl/webgl_framebuffer.h"
17 
18 #include "context/webgl2_rendering_context_base.h"
19 #include "context/webgl_rendering_context_base.h"
20 #include "context/webgl_rendering_context_base_impl.h"
21 #include "napi/n_class.h"
22 #include "napi/n_func_arg.h"
23 #include "napi/n_val.h"
24 #include "util/util.h"
25 
26 namespace OHOS {
27 namespace Rosen {
28 using namespace std;
Constructor(napi_env env,napi_callback_info info)29 napi_value WebGLFramebuffer::Constructor(napi_env env, napi_callback_info info)
30 {
31     NFuncArg funcArg(env, info);
32     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
33         return nullptr;
34     }
35 
36     unique_ptr<WebGLFramebuffer> webGlFramebuffer = make_unique<WebGLFramebuffer>();
37     if (!NClass::SetEntityFor<WebGLFramebuffer>(env, funcArg.GetThisVar(), move(webGlFramebuffer))) {
38         LOGE("SetEntityFor webGlFramebuffer failed.");
39         return nullptr;
40     }
41     return funcArg.GetThisVar();
42 }
43 
Export(napi_env env,napi_value exports)44 bool WebGLFramebuffer::Export(napi_env env, napi_value exports)
45 {
46     vector<napi_property_descriptor> props = {};
47 
48     string className = GetClassName();
49     bool succ = false;
50     napi_value clas = nullptr;
51     tie(succ, clas) = NClass::DefineClass(exports_.env_, className, WebGLFramebuffer::Constructor, std::move(props));
52     if (!succ) {
53         LOGE("DefineClass webGlFramebuffer failed.");
54         return false;
55     }
56     succ = NClass::SaveClass(exports_.env_, className, clas);
57     if (!succ) {
58         LOGE("SaveClass webGlFramebuffer failed.");
59         return false;
60     }
61 
62     return exports_.AddProp(className, clas);
63 }
64 
GetClassName()65 string WebGLFramebuffer::GetClassName()
66 {
67     return WebGLFramebuffer::className;
68 }
69 
CreateObjectInstance(napi_env env,WebGLFramebuffer ** instance)70 NVal WebGLFramebuffer::CreateObjectInstance(napi_env env, WebGLFramebuffer** instance)
71 {
72     return WebGLObject::CreateObjectInstance<WebGLFramebuffer>(env, instance);
73 }
74 
~WebGLFramebuffer()75 WebGLFramebuffer::~WebGLFramebuffer()
76 {
77     auto it = attachments_.begin();
78     while (it != attachments_.end()) {
79         delete it->second;
80         attachments_.erase(it);
81         it = attachments_.begin();
82     }
83 }
84 
AddAttachment(GLenum target,GLenum attachment,GLuint id)85 bool WebGLFramebuffer::AddAttachment(GLenum target, GLenum attachment, GLuint id)
86 {
87     WebGLAttachment* attachmentObject = new WebGLAttachment(AttachmentType::RENDER_BUFFER, attachment, id);
88     if (attachmentObject == nullptr) {
89         return false;
90     }
91     LOGD("AddAttachment target %{public}u attachment [%{public}u %{public}u]", target, attachment, id);
92     if (attachments_[attachment]) {
93         DoDetachment(target, attachments_[attachment]);
94         delete attachments_[attachment];
95     }
96     attachments_[attachment] = attachmentObject;
97     return true;
98 }
99 
AddAttachment(GLenum target,GLenum attachment,GLuint id,GLenum textureTarget,GLint level)100 bool WebGLFramebuffer::AddAttachment(GLenum target, GLenum attachment, GLuint id, GLenum textureTarget, GLint level)
101 {
102     AttachmentTexture* attachmentObject = new AttachmentTexture(AttachmentType::TEXTURE, attachment, id);
103     if (attachmentObject == nullptr) {
104         return false;
105     }
106     LOGD("AddAttachment target %{public}u attachment [%{public}u %{public}u] texture [%{public}u %{public}d]", target,
107         attachment, id, textureTarget, level);
108     if (attachments_[attachment]) {
109         DoDetachment(target, attachments_[attachment]);
110         delete attachments_[attachment];
111     }
112     attachments_[attachment] = attachmentObject;
113     attachmentObject->target = textureTarget;
114     attachmentObject->level = level;
115     return true;
116 }
117 
DoDetachment(GLenum target,WebGLAttachment * attachment)118 void WebGLFramebuffer::DoDetachment(GLenum target, WebGLAttachment* attachment)
119 {
120     if (attachment == nullptr) {
121         return;
122     }
123     LOGD("DoDetachment target %{public}u attachment [%{public}u %{public}u] %{public}u",
124         target, attachment->attachment, attachment->id, attachment->type);
125     if (attachment->IsRenderBuffer()) {
126         if (attachment->attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
127             glFramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
128             glFramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
129         } else {
130             glFramebufferRenderbuffer(target, attachment->attachment, GL_RENDERBUFFER, 0);
131         }
132     } else {
133         auto textureAttachment = static_cast<const AttachmentTexture*>(attachment);
134         if (attachment->attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
135             glFramebufferTexture2D(target,
136                 GL_DEPTH_ATTACHMENT, textureAttachment->target, 0, textureAttachment->level);
137             glFramebufferTexture2D(target,
138                 GL_STENCIL_ATTACHMENT, textureAttachment->target, 0, textureAttachment->level);
139         } else {
140             glFramebufferTexture2D(target,
141                 attachment->attachment, textureAttachment->target, 0, textureAttachment->level);
142         }
143     }
144 }
145 
RemoveAttachment(GLenum target,GLuint id,AttachmentType type)146 void WebGLFramebuffer::RemoveAttachment(GLenum target, GLuint id, AttachmentType type)
147 {
148     for (auto iter = attachments_.begin(); iter != attachments_.end(); iter++) {
149         auto object = iter->second;
150         if (object != nullptr && object->id == id && type == object->type) {
151             DoDetachment(target, iter->second);
152             delete iter->second;
153             attachments_.erase(iter);
154             break;
155         }
156     }
157 }
158 
GetAttachment(GLenum attachment) const159 WebGLAttachment* WebGLFramebuffer::GetAttachment(GLenum attachment) const
160 {
161     auto it = attachments_.find(attachment);
162     if (it != attachments_.end()) {
163         return it->second;
164     }
165     return nullptr;
166 }
167 
IsDepthRenderAble(GLenum internalFormat,bool includesDepthStencil) const168 bool WebGLFramebuffer::IsDepthRenderAble(GLenum internalFormat, bool includesDepthStencil) const
169 {
170     switch (internalFormat) {
171         case GL_DEPTH_COMPONENT:
172         case GL_DEPTH_COMPONENT16:
173         case GL_DEPTH_COMPONENT24:
174         case GL_DEPTH_COMPONENT32F:
175             return true;
176         case GL_DEPTH_STENCIL:
177         case GL_DEPTH24_STENCIL8:
178         case GL_DEPTH32F_STENCIL8:
179             return includesDepthStencil;
180         default:
181             return false;
182     }
183 }
184 
IsColorRenderAble(GLenum internalFormat) const185 bool WebGLFramebuffer::IsColorRenderAble(GLenum internalFormat) const
186 {
187     switch (internalFormat) {
188         case WebGLRenderingContextBase::RGB:
189         case WebGLRenderingContextBase::RGBA:
190         case WebGL2RenderingContextBase::R8:
191         case WebGL2RenderingContextBase::R8UI:
192         case WebGL2RenderingContextBase::R8I:
193         case WebGL2RenderingContextBase::R16UI:
194         case WebGL2RenderingContextBase::R16I:
195         case WebGL2RenderingContextBase::R32UI:
196         case WebGL2RenderingContextBase::R32I:
197         case WebGL2RenderingContextBase::RG8:
198         case WebGL2RenderingContextBase::RG8UI:
199         case WebGL2RenderingContextBase::RG8I:
200         case WebGL2RenderingContextBase::RG16UI:
201         case WebGL2RenderingContextBase::RG16I:
202         case WebGL2RenderingContextBase::RG32UI:
203         case WebGL2RenderingContextBase::RG32I:
204         case WebGL2RenderingContextBase::RGB8:
205         case WebGLRenderingContextBase::RGB565:
206         case WebGL2RenderingContextBase::RGBA8:
207         case WebGL2RenderingContextBase::SRGB8_ALPHA8:
208         case WebGLRenderingContextBase::RGB5_A1:
209         case WebGLRenderingContextBase::RGBA4:
210         case WebGL2RenderingContextBase::RGB10_A2:
211         case WebGL2RenderingContextBase::RGBA8UI:
212         case WebGL2RenderingContextBase::RGBA8I:
213         case WebGL2RenderingContextBase::RGB10_A2UI:
214         case WebGL2RenderingContextBase::RGBA16UI:
215         case WebGL2RenderingContextBase::RGBA16I:
216         case WebGL2RenderingContextBase::RGBA32UI:
217         case WebGL2RenderingContextBase::RGBA32I:
218             return true;
219         default:
220             return false;
221     }
222 }
223 
IsStencilRenderAble(GLenum internalFormat,bool includesDepthStencil) const224 bool WebGLFramebuffer::IsStencilRenderAble(GLenum internalFormat, bool includesDepthStencil) const
225 {
226     switch (internalFormat) {
227         case WebGLRenderingContextBase::STENCIL_INDEX8:
228             return true;
229         case WebGLRenderingContextBase::DEPTH_STENCIL:
230         case WebGL2RenderingContextBase::DEPTH24_STENCIL8:
231         case WebGL2RenderingContextBase::DEPTH32F_STENCIL8:
232             return includesDepthStencil;
233         default:
234             return false;
235     }
236 }
237 
GetWebGLAttachmentInfo(napi_env env,Impl::WebGLRenderingContextBaseImpl * context,const WebGLAttachment * attachedObject,WebGLAttachmentInfo & info) const238 bool WebGLFramebuffer::GetWebGLAttachmentInfo(napi_env env, Impl::WebGLRenderingContextBaseImpl* context,
239     const WebGLAttachment* attachedObject, WebGLAttachmentInfo& info) const
240 {
241     if (attachedObject == nullptr) {
242         return false;
243     }
244     LOGD("GetWebGLAttachmentInfo %{public}u %{public}d %{public}lu", attachedObject->type, attachedObject->attachment,
245         attachedObject->id);
246     if (attachedObject->IsRenderBuffer()) {
247         WebGLRenderbuffer* renderBuffer =
248             context->GetObjectInstance<WebGLRenderbuffer>(env, static_cast<uint64_t>(attachedObject->id));
249         if (renderBuffer == nullptr) {
250             return false;
251         }
252         info.format = renderBuffer->GetInternalFormat();
253         info.width = renderBuffer->GetWidth();
254         info.height = renderBuffer->GetHeight();
255         info.type = 0;
256         return true;
257     }
258     if (attachedObject->IsTexture()) {
259         WebGLTexture* texture = context->GetObjectInstance<WebGLTexture>(
260             env, static_cast<uint64_t>(attachedObject->id));
261         if (texture == nullptr) {
262             return false;
263         }
264         auto textureAttachment = static_cast<const AttachmentTexture *>(attachedObject);
265         LOGD("GetWebGLAttachmentInfo textureAttachment target %{public}u %{public}d",
266             textureAttachment->target, textureAttachment->level);
267         info.format = texture->GetInternalFormat(textureAttachment->target, textureAttachment->level);
268         info.width = texture->GetWidth(textureAttachment->target, textureAttachment->level);
269         info.height = texture->GetHeight(textureAttachment->target, textureAttachment->level);
270         info.type = texture->GetType(textureAttachment->target, textureAttachment->level);
271         return true;
272     }
273     return false;
274 }
275 
CheckAttachmentComplete(bool isHighWebGL,WebGLAttachment * attachedObject,const WebGLAttachmentInfo & info,std::vector<WebGLAttachment * > & attachments) const276 bool WebGLFramebuffer::CheckAttachmentComplete(bool isHighWebGL, WebGLAttachment* attachedObject,
277     const WebGLAttachmentInfo& info, std::vector<WebGLAttachment*>& attachments) const
278 {
279     switch (attachedObject->attachment) {
280         case WebGLRenderingContextBase::DEPTH_ATTACHMENT: {
281             if (!IsDepthRenderAble(info.format, isHighWebGL)) {
282                 return false;
283             }
284             attachments[0] = attachedObject; // attachments[0]: depthAttachment
285             break;
286         }
287         case WebGLRenderingContextBase::STENCIL_ATTACHMENT: {
288             if (!IsStencilRenderAble(info.format, isHighWebGL)) {
289                 return false;
290             }
291             attachments[1] = attachedObject; // attachments[1]: stencilAttachment
292             break;
293         }
294         case WebGLRenderingContextBase::DEPTH_STENCIL_ATTACHMENT: {
295             if (info.format != GL_DEPTH_STENCIL_OES) {
296                 return false;
297             }
298             attachments[2] = attachedObject; // attachments[2]: depthStencilAttachment
299             break;
300         }
301         default:
302             if (!IsColorRenderAble(info.format)) {
303                 return false;
304             }
305             break;
306     }
307     return true;
308 }
309 
CheckStatus(napi_env env,Impl::WebGLRenderingContextBaseImpl * context,WebGLAttachmentInfo info,std::vector<WebGLAttachment * > & attachments,WebGLAttachment * attachedObject) const310 GLenum WebGLFramebuffer::CheckStatus(napi_env env, Impl::WebGLRenderingContextBaseImpl* context,
311     WebGLAttachmentInfo info, std::vector<WebGLAttachment*>& attachments, WebGLAttachment* attachedObject) const
312 {
313     if (!GetWebGLAttachmentInfo(env, context, attachedObject, info)) {
314         LOGE("GetWebGLAttachmentInfo failed.");
315         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
316     }
317     if (!info.format || !info.width || !info.height) {
318         LOGE("CheckStatus info failed.");
319         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
320     }
321     if (!CheckAttachmentComplete(context->IsHighWebGL(), attachedObject, info, attachments)) {
322         LOGE("CheckAttachmentComplete failed.");
323         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
324     }
325     return WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE;
326 }
327 
CheckAttachStatus(Impl::WebGLRenderingContextBaseImpl * context,std::vector<WebGLAttachment * > & attachments) const328 GLenum WebGLFramebuffer::CheckAttachStatus(Impl::WebGLRenderingContextBaseImpl* context,
329     std::vector<WebGLAttachment*>& attachments) const
330 {
331     // WebGL 1 specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
332     // 0 depthAttachment, 1 stencilAttachment, 2 depthStencilAttachment
333     if (!context->IsHighWebGL() && ((attachments[2] && (attachments[0] || attachments[1])) ||
334         (attachments[0] && attachments[1]))) {
335         LOGE("Check status depthStencilAttachment failed.");
336         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
337     }
338     if (context->IsHighWebGL() && (attachments[0] && attachments[1] && attachments[0]->id != attachments[1]->id)) {
339         LOGE("Check status depthAttachment failed.");
340         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
341     }
342     return WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE;
343 }
344 
CheckStatus(napi_env env,Impl::WebGLRenderingContextBaseImpl * context) const345 GLenum WebGLFramebuffer::CheckStatus(napi_env env, Impl::WebGLRenderingContextBaseImpl* context) const
346 {
347     uint32_t count = 0;
348     GLsizei width = 0;
349     GLsizei height = 0;
350     std::vector<WebGLAttachment*> attachments = {nullptr, nullptr, nullptr};
351     WebGLAttachmentInfo info;
352     GLenum result;
353     LOGD("CheckStatus %{public}u", attachments_.size());
354     for (const auto& it : attachments_) {
355         WebGLAttachment* attachedObject = it.second;
356         result = CheckStatus(env, context, info, attachments, attachedObject);
357         if (result != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
358             return result;
359         }
360         if (!context->IsHighWebGL()) {
361             if (!count) {
362                 width = info.width;
363                 height = info.height;
364             } else if (width != info.width || height != info.height) {
365                 LOGE("CheckStatus attachmentInfo failed.");
366                 return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
367             }
368         }
369         ++count;
370     }
371     if (!count) {
372         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
373     }
374 
375     return CheckAttachStatus(context, attachments);
376 }
377 } // namespace Rosen
378 } // namespace OHOS
379