Changed when depth/stencil renderbuffers are created
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-framebuffer.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "gles-graphics-framebuffer.h"
20
21 // external headers
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/gl-defines.h>
24
25 // Internal headers
26 #include <dali/internal/graphics/gles-impl/gles-graphics-texture.h>
27 #include "egl-graphics-controller.h"
28
29 namespace Dali::Graphics::GLES
30 {
31 namespace
32 {
33 const GLenum COLOR_ATTACHMENTS[] =
34   {
35     GL_COLOR_ATTACHMENT0,
36     GL_COLOR_ATTACHMENT1,
37     GL_COLOR_ATTACHMENT2,
38     GL_COLOR_ATTACHMENT3,
39     GL_COLOR_ATTACHMENT4,
40     GL_COLOR_ATTACHMENT5,
41     GL_COLOR_ATTACHMENT6,
42     GL_COLOR_ATTACHMENT7,
43 };
44
45 struct DEPTH_STENCIL_ATTACHMENT_TYPE
46 {
47   constexpr explicit DEPTH_STENCIL_ATTACHMENT_TYPE(Graphics::Format textureFormat)
48   {
49     switch(textureFormat)
50     {
51       case Graphics::Format::D16_UNORM:
52       case Graphics::Format::D32_SFLOAT:
53       case Graphics::Format::X8_D24_UNORM_PACK32:
54       {
55         attachment = GL_DEPTH_ATTACHMENT;
56         break;
57       }
58
59       case Graphics::Format::S8_UINT: // Probably won't work as a standalone texture.
60       {
61         attachment = GL_STENCIL_ATTACHMENT;
62         break;
63       }
64
65       case Graphics::Format::D16_UNORM_S8_UINT:
66       case Graphics::Format::D24_UNORM_S8_UINT:
67       case Graphics::Format::D32_SFLOAT_S8_UINT:
68       {
69         attachment = GL_DEPTH_STENCIL_ATTACHMENT;
70         break;
71       }
72       default:
73       {
74         attachment = GL_NONE;
75         break;
76       }
77     }
78   }
79   Dali::GLenum attachment{GL_NONE};
80 };
81
82 } // anonymous namespace
83
84 Framebuffer::Framebuffer(const Graphics::FramebufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
85 : FramebufferResource(createInfo, controller)
86 {
87   // Add framebuffer to the Resource queue
88   mController.AddFramebuffer(*this);
89 }
90
91 Framebuffer::~Framebuffer() = default;
92
93 bool Framebuffer::InitializeResource()
94 {
95   auto context = mController.GetCurrentContext();
96   auto gl      = mController.GetGL();
97   if(gl && context && !mInitialized)
98   {
99     mInitialized = true;
100
101     context->GenFramebuffers(1, &mFramebufferId);
102     context->BindFrameBuffer(GL_FRAMEBUFFER, mFramebufferId);
103
104     for(Graphics::ColorAttachment& attachment : mCreateInfo.colorAttachments)
105     {
106       AttachTexture(attachment.texture, COLOR_ATTACHMENTS[attachment.attachmentId], attachment.layerId, attachment.levelId);
107     }
108
109     // @todo is this per framebuffer, or more immediate state that needs setting when framebuffer changed?
110     context->DrawBuffers(mCreateInfo.colorAttachments.size(), COLOR_ATTACHMENTS);
111
112     if(mCreateInfo.depthStencilAttachment.depthTexture)
113     {
114       // Create a depth or depth/stencil render target.
115       auto depthTexture = static_cast<const GLES::Texture*>(mCreateInfo.depthStencilAttachment.depthTexture);
116       auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(depthTexture->GetCreateInfo().format).attachment;
117
118       AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel);
119     }
120     else if(mCreateInfo.depthStencilAttachment.depthUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
121     {
122       gl->GenRenderbuffers(1, &mDepthBufferId);
123       gl->BindRenderbuffer(GL_RENDERBUFFER, mDepthBufferId);
124       gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mCreateInfo.size.width, mCreateInfo.size.height);
125       gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferId);
126     }
127
128     if(mCreateInfo.depthStencilAttachment.stencilTexture)
129     {
130       auto stencilTexture = static_cast<const GLES::Texture*>(mCreateInfo.depthStencilAttachment.stencilTexture);
131       auto attachmentId   = DEPTH_STENCIL_ATTACHMENT_TYPE(stencilTexture->GetCreateInfo().format).attachment;
132
133       AttachTexture(stencilTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.stencilLevel);
134     }
135     else if(mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
136     {
137       gl->GenRenderbuffers(1, &mStencilBufferId);
138       gl->BindRenderbuffer(GL_RENDERBUFFER, mStencilBufferId);
139       gl->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, mCreateInfo.size.width, mCreateInfo.size.height);
140       gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mStencilBufferId);
141     }
142
143     context->BindFrameBuffer(GL_FRAMEBUFFER, 0);
144   }
145
146   return mInitialized;
147 }
148
149 void Framebuffer::DestroyResource()
150 {
151   auto context = mController.GetCurrentContext();
152   auto gl      = mController.GetGL();
153   if(gl && context && mInitialized)
154   {
155     if(mDepthBufferId)
156     {
157       gl->DeleteRenderbuffers(1, &mDepthBufferId);
158     }
159     if(mStencilBufferId)
160     {
161       gl->DeleteRenderbuffers(1, &mStencilBufferId);
162     }
163
164     context->DeleteFramebuffers(1, &mFramebufferId);
165
166     mFramebufferId = 0u;
167     mInitialized   = false;
168   }
169 }
170
171 void Framebuffer::DiscardResource()
172 {
173   mController.DiscardResource(this);
174 }
175
176 void Framebuffer::Bind() const
177 {
178   auto context = mController.GetCurrentContext();
179   auto gl      = mController.GetGL();
180
181   if(gl && context)
182   {
183     context->BindFrameBuffer(GL_FRAMEBUFFER, mFramebufferId);
184   }
185 }
186
187 void Framebuffer::AttachTexture(const Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId)
188 {
189   auto gl = mController.GetGL();
190   if(gl)
191   {
192     auto graphicsTexture = static_cast<const GLES::Texture*>(texture);
193     if(graphicsTexture->GetCreateInfo().textureType == Graphics::TextureType::TEXTURE_2D)
194     {
195       gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, graphicsTexture->GetGlTarget(), graphicsTexture->GetGLTexture(), levelId);
196     }
197     else
198     {
199       gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId, graphicsTexture->GetGLTexture(), levelId);
200     }
201   }
202 }
203
204 uint32_t Framebuffer::GetGlFramebufferId() const
205 {
206   return mFramebufferId;
207 }
208
209 uint32_t Framebuffer::GetGlDepthBufferId() const
210 {
211   return mDepthBufferId;
212 }
213
214 uint32_t Framebuffer::GetGlStencilBufferId() const
215 {
216   return mStencilBufferId;
217 }
218
219 } //namespace Dali::Graphics::GLES