• 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         it = attachments_.erase(it);
81     }
82 }
83 
AddAttachment(GLenum target,GLenum attachment,GLuint id)84 bool WebGLFramebuffer::AddAttachment(GLenum target, GLenum attachment, GLuint id)
85 {
86     WebGLAttachment* attachmentObject = new(std::nothrow) WebGLAttachment(
87         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(std::nothrow) 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 
245     LOGD("GetWebGLAttachmentInfo %{public}u %{public}d %{public}lu",
246          static_cast<unsigned int>(attachedObject->type), attachedObject->attachment,
247          static_cast<unsigned long>(attachedObject->id));
248     if (attachedObject->IsRenderBuffer()) {
249         WebGLRenderbuffer* renderBuffer =
250             context->GetObjectInstance<WebGLRenderbuffer>(env, static_cast<uint64_t>(attachedObject->id));
251         if (renderBuffer == nullptr) {
252             return false;
253         }
254         info.format = renderBuffer->GetInternalFormat();
255         info.width = renderBuffer->GetWidth();
256         info.height = renderBuffer->GetHeight();
257         info.type = 0;
258         return true;
259     }
260     if (attachedObject->IsTexture()) {
261         WebGLTexture* texture = context->GetObjectInstance<WebGLTexture>(
262             env, static_cast<uint64_t>(attachedObject->id));
263         if (texture == nullptr) {
264             return false;
265         }
266         auto textureAttachment = static_cast<const AttachmentTexture *>(attachedObject);
267         LOGD("GetWebGLAttachmentInfo textureAttachment target %{public}u %{public}d",
268             textureAttachment->target, textureAttachment->level);
269         info.format = texture->GetInternalFormat(textureAttachment->target, textureAttachment->level);
270         info.width = texture->GetWidth(textureAttachment->target, textureAttachment->level);
271         info.height = texture->GetHeight(textureAttachment->target, textureAttachment->level);
272         info.type = texture->GetType(textureAttachment->target, textureAttachment->level);
273         return true;
274     }
275     return false;
276 }
277 
CheckAttachmentComplete(bool isHighWebGL,WebGLAttachment * attachedObject,const WebGLAttachmentInfo & info,std::vector<WebGLAttachment * > & attachments) const278 bool WebGLFramebuffer::CheckAttachmentComplete(bool isHighWebGL, WebGLAttachment* attachedObject,
279     const WebGLAttachmentInfo& info, std::vector<WebGLAttachment*>& attachments) const
280 {
281     switch (attachedObject->attachment) {
282         case WebGLRenderingContextBase::DEPTH_ATTACHMENT: {
283             if (!IsDepthRenderAble(info.format, isHighWebGL)) {
284                 return false;
285             }
286             attachments[0] = attachedObject; // attachments[0]: depthAttachment
287             break;
288         }
289         case WebGLRenderingContextBase::STENCIL_ATTACHMENT: {
290             if (!IsStencilRenderAble(info.format, isHighWebGL)) {
291                 return false;
292             }
293             attachments[1] = attachedObject; // attachments[1]: stencilAttachment
294             break;
295         }
296         case WebGLRenderingContextBase::DEPTH_STENCIL_ATTACHMENT: {
297             if (info.format != GL_DEPTH_STENCIL_OES) {
298                 return false;
299             }
300             attachments[2] = attachedObject; // attachments[2]: depthStencilAttachment
301             break;
302         }
303         default:
304             if (!IsColorRenderAble(info.format)) {
305                 return false;
306             }
307             break;
308     }
309     return true;
310 }
311 
CheckStatus(napi_env env,Impl::WebGLRenderingContextBaseImpl * context,WebGLAttachmentInfo info,std::vector<WebGLAttachment * > & attachments,WebGLAttachment * attachedObject) const312 GLenum WebGLFramebuffer::CheckStatus(napi_env env, Impl::WebGLRenderingContextBaseImpl* context,
313     WebGLAttachmentInfo info, std::vector<WebGLAttachment*>& attachments, WebGLAttachment* attachedObject) const
314 {
315     if (!GetWebGLAttachmentInfo(env, context, attachedObject, info)) {
316         LOGE("GetWebGLAttachmentInfo failed.");
317         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
318     }
319     if (!info.format || !info.width || !info.height) {
320         LOGE("CheckStatus info failed.");
321         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
322     }
323     if (!CheckAttachmentComplete(context->IsHighWebGL(), attachedObject, info, attachments)) {
324         LOGE("CheckAttachmentComplete failed.");
325         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
326     }
327     return WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE;
328 }
329 
CheckAttachStatus(Impl::WebGLRenderingContextBaseImpl * context,std::vector<WebGLAttachment * > & attachments) const330 GLenum WebGLFramebuffer::CheckAttachStatus(Impl::WebGLRenderingContextBaseImpl* context,
331     std::vector<WebGLAttachment*>& attachments) const
332 {
333     // WebGL 1 specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
334     // 0 depthAttachment, 1 stencilAttachment, 2 depthStencilAttachment
335     if (!context->IsHighWebGL() && ((attachments[2] && (attachments[0] || attachments[1])) ||
336         (attachments[0] && attachments[1]))) {
337         LOGE("Check status depthStencilAttachment failed.");
338         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
339     }
340     if (context->IsHighWebGL() && (attachments[0] && attachments[1] && attachments[0]->id != attachments[1]->id)) {
341         LOGE("Check status depthAttachment failed.");
342         return WebGLRenderingContextBase::FRAMEBUFFER_UNSUPPORTED;
343     }
344     return WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE;
345 }
346 
CheckStatus(napi_env env,Impl::WebGLRenderingContextBaseImpl * context) const347 GLenum WebGLFramebuffer::CheckStatus(napi_env env, Impl::WebGLRenderingContextBaseImpl* context) const
348 {
349     uint32_t count = 0;
350     GLsizei width = 0;
351     GLsizei height = 0;
352     std::vector<WebGLAttachment*> attachments = {nullptr, nullptr, nullptr};
353     WebGLAttachmentInfo info;
354     GLenum result;
355     LOGD("CheckStatus %{public}u", static_cast<unsigned int>(attachments_.size()));
356     for (const auto& it : attachments_) {
357         WebGLAttachment* attachedObject = it.second;
358         result = CheckStatus(env, context, info, attachments, attachedObject);
359         if (result != WebGLRenderingContextBase::FRAMEBUFFER_COMPLETE) {
360             return result;
361         }
362         if (!context->IsHighWebGL()) {
363             if (!count) {
364                 width = info.width;
365                 height = info.height;
366             } else if (width != info.width || height != info.height) {
367                 LOGE("CheckStatus attachmentInfo failed.");
368                 return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
369             }
370         }
371         ++count;
372     }
373     if (!count) {
374         return WebGLRenderingContextBase::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
375     }
376 
377     return CheckAttachStatus(context, attachments);
378 }
379 } // namespace Rosen
380 } // namespace OHOS
381