[Tizen] Support to get raw pixel informations of framebuffer for old driver device
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-graphics-framebuffer.cpp
1 /*
2  * Copyright (c) 2022 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   // Check whether we need to consider multisampling
88   if(createInfo.multiSamplingLevel > 1u && controller.GetGraphicsInterface()->IsMultisampledRenderToTextureSupported())
89   {
90     mMultisamples = std::min(createInfo.multiSamplingLevel, controller.GetGraphicsInterface()->GetMaxTextureSamples());
91   }
92
93   // Add framebuffer to the Resource queue
94   mController.AddFramebuffer(*this);
95 }
96
97 Framebuffer::~Framebuffer() = default;
98
99 bool Framebuffer::InitializeResource()
100 {
101   auto context = mController.GetCurrentContext();
102   auto gl      = mController.GetGL();
103   if(gl && context && !mInitialized)
104   {
105     mInitialized = true;
106
107     context->GenFramebuffers(1, &mFramebufferId);
108     context->BindFrameBuffer(GL_FRAMEBUFFER, mFramebufferId);
109
110     for(Graphics::ColorAttachment& attachment : mCreateInfo.colorAttachments)
111     {
112       AttachTexture(attachment.texture, COLOR_ATTACHMENTS[attachment.attachmentId], attachment.layerId, attachment.levelId);
113     }
114
115     // @todo is this per framebuffer, or more immediate state that needs setting when framebuffer changed?
116     context->DrawBuffers(mCreateInfo.colorAttachments.size(), COLOR_ATTACHMENTS);
117
118     // @todo Currently, we don't assume that GL_EXT_PACKED_DEPTH_STENCIL valid.
119     // We will assume that stencilTexture / stencilBufferId always mean depth-stencil.
120     if(mCreateInfo.depthStencilAttachment.stencilTexture)
121     {
122       // bind depth 24 bits + stencil 8 bits texture, or 8 tencil texture.
123       auto stencilTexture = static_cast<const GLES::Texture*>(mCreateInfo.depthStencilAttachment.stencilTexture);
124       auto attachmentId   = DEPTH_STENCIL_ATTACHMENT_TYPE(stencilTexture->GetCreateInfo().format).attachment;
125
126       if(attachmentId != GL_DEPTH_STENCIL_ATTACHMENT)
127       {
128         DALI_LOG_ERROR("Current Depth/Stencil Texture Type doesn't support. Please check depth/stencil texture's pixel format");
129       }
130
131       AttachTexture(stencilTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.stencilLevel);
132     }
133     else if(mCreateInfo.depthStencilAttachment.depthTexture)
134     {
135       // bind depth texture.
136       auto depthTexture = static_cast<const GLES::Texture*>(mCreateInfo.depthStencilAttachment.depthTexture);
137       auto attachmentId = DEPTH_STENCIL_ATTACHMENT_TYPE(depthTexture->GetCreateInfo().format).attachment;
138
139       if(attachmentId != GL_DEPTH_STENCIL_ATTACHMENT && mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
140       {
141         DALI_LOG_ERROR("Current Depth Texture Type doesn't support to store Stencil. Please check depth texture's pixel format");
142       }
143
144       AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel);
145     }
146     else
147     {
148       const bool depthWrite   = mCreateInfo.depthStencilAttachment.depthUsage == Graphics::DepthStencilAttachment::Usage::WRITE;
149       const bool stencilWrite = mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE;
150
151       // Check whether we need to use RenderBuffer
152       if(depthWrite || stencilWrite)
153       {
154         // if stencil is write, use renderbuffer as mStencilBufferId.
155         uint32_t&  bufferId       = stencilWrite ? mStencilBufferId : mDepthBufferId;
156         const auto internalFormat = depthWrite ? (stencilWrite ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16) : GL_STENCIL_INDEX8;
157         const auto attachment     = depthWrite ? (stencilWrite ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT) : GL_STENCIL_ATTACHMENT;
158
159         gl->GenRenderbuffers(1, &bufferId);
160         gl->BindRenderbuffer(GL_RENDERBUFFER, bufferId);
161
162         if(mMultisamples <= 1u)
163         {
164           gl->RenderbufferStorage(GL_RENDERBUFFER, internalFormat, mCreateInfo.size.width, mCreateInfo.size.height);
165         }
166         else
167         {
168           gl->RenderbufferStorageMultisample(GL_RENDERBUFFER, mMultisamples, internalFormat, mCreateInfo.size.width, mCreateInfo.size.height);
169         }
170         gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, bufferId);
171       }
172     }
173
174     context->BindFrameBuffer(GL_FRAMEBUFFER, 0);
175   }
176
177   return mInitialized;
178 }
179
180 void Framebuffer::DestroyResource()
181 {
182   auto context = mController.GetCurrentContext();
183   auto gl      = mController.GetGL();
184   if(gl && context && mInitialized)
185   {
186     if(mDepthBufferId)
187     {
188       gl->DeleteRenderbuffers(1, &mDepthBufferId);
189     }
190     if(mStencilBufferId)
191     {
192       gl->DeleteRenderbuffers(1, &mStencilBufferId);
193     }
194
195     context->DeleteFramebuffers(1, &mFramebufferId);
196
197     mFramebufferId = 0u;
198     mInitialized   = false;
199   }
200 }
201
202 void Framebuffer::DiscardResource()
203 {
204   mController.DiscardResource(this);
205
206   mCaptureRenderedResult = false;
207   mCapturedBuffer = nullptr;
208   mCapturedCallback = nullptr;
209 }
210
211 void Framebuffer::Bind() const
212 {
213   auto context = mController.GetCurrentContext();
214   auto gl      = mController.GetGL();
215
216   if(gl && context)
217   {
218     context->BindFrameBuffer(GL_FRAMEBUFFER, mFramebufferId);
219   }
220 }
221
222 void Framebuffer::AttachTexture(const Graphics::Texture* texture, uint32_t attachmentId, uint32_t layerId, uint32_t levelId)
223 {
224   auto gl = mController.GetGL();
225   if(gl)
226   {
227     auto graphicsTexture = static_cast<const GLES::Texture*>(texture);
228     auto textarget       = (graphicsTexture->GetCreateInfo().textureType == Graphics::TextureType::TEXTURE_2D) ? graphicsTexture->GetGlTarget() : GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId;
229     if(mMultisamples <= 1u)
230     {
231       gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, textarget, graphicsTexture->GetGLTexture(), levelId);
232     }
233     else
234     {
235       gl->FramebufferTexture2DMultisample(GL_FRAMEBUFFER, attachmentId, textarget, graphicsTexture->GetGLTexture(), levelId, mMultisamples);
236     }
237   }
238 }
239
240 uint32_t Framebuffer::GetGlFramebufferId() const
241 {
242   return mFramebufferId;
243 }
244
245 uint32_t Framebuffer::GetGlDepthBufferId() const
246 {
247   return mDepthBufferId;
248 }
249
250 uint32_t Framebuffer::GetGlStencilBufferId() const
251 {
252   return mStencilBufferId;
253 }
254
255 void Framebuffer::CaptureRenderingResult(CallbackBase* capturedCallback, uint8_t* capturedBuffer)
256 {
257   // Let we make to capture the result.
258   mCaptureRenderedResult = true;
259
260   mCapturedCallback = capturedCallback;
261   mCapturedBuffer   = capturedBuffer;
262 }
263
264 void Framebuffer::DrawRenderedBuffer()
265 {
266   auto gl = mController.GetGL();
267   if(gl && mCaptureRenderedResult && mCapturedCallback && mCapturedBuffer != nullptr)
268   {
269     gl->ReadPixels(0, 0, mCreateInfo.size.width, mCreateInfo.size.height, GL_RGBA, GL_UNSIGNED_BYTE, mCapturedBuffer);
270
271     CallbackBase::Execute(*mCapturedCallback, mCapturedBuffer);
272
273     mCaptureRenderedResult = false;
274     mCapturedBuffer = nullptr;
275     mCapturedCallback = nullptr;
276   }
277 }
278
279 } //namespace Dali::Graphics::GLES