RenderPass and surface presentation
[platform/core/uifw/dali-adaptor.git] / dali / internal / graphics / gles-impl / gles-context.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 #include "gles-context.h"
19 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
20 #include <dali/integration-api/gl-abstraction.h>
21 #include <dali/integration-api/gl-defines.h>
22 #include <dali/internal/graphics/common/graphics-interface.h>
23
24 #include "egl-graphics-controller.h"
25 #include "gles-graphics-buffer.h"
26 #include "gles-graphics-pipeline.h"
27 #include "gles-graphics-program.h"
28 #include "gles-graphics-render-pass.h"
29 #include "gles-graphics-render-target.h"
30
31 namespace Dali::Graphics::GLES
32 {
33 struct Context::Impl
34 {
35   Impl(EglGraphicsController& controller)
36   : mController(controller)
37   {
38   }
39
40   ~Impl() = default;
41
42   EglGraphicsController& mController;
43
44   const GLES::Pipeline* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
45   const GLES::Pipeline* mNewPipeline{nullptr};     ///< New pipeline to be set on flush
46
47   std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
48   std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
49   GLES::IndexBufferBindingDescriptor    mCurrentIndexBufferBinding{};
50
51   struct VertexBufferBinding
52   {
53     GLES::Buffer* buffer{nullptr};
54     uint32_t      offset{0u};
55   };
56
57   // Currently bound buffers
58   std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
59
60   // Currently bound UBOs (check if it's needed per program!)
61   std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
62   UniformBufferBindingDescriptor              mCurrentStandaloneUBOBinding{};
63
64   // Current render pass and render target
65   const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
66   const GLES::RenderPass*   mCurrentRenderPass{nullptr};
67 };
68
69 Context::Context(EglGraphicsController& controller)
70 {
71   mImpl = std::make_unique<Impl>(controller);
72 }
73
74 Context::~Context() = default;
75
76 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
77 {
78   auto& gl = *mImpl->mController.GetGL();
79
80   // Change pipeline
81   if(mImpl->mNewPipeline)
82   {
83     // Execute states if different
84     mImpl->mCurrentPipeline = mImpl->mNewPipeline;
85     mImpl->mNewPipeline     = nullptr;
86   }
87   mImpl->mCurrentPipeline->GetPipeline().Bind(nullptr);
88
89   // Blend state
90   ResolveBlendState();
91
92   // Resolve rasterization state
93   ResolveRasterizationState();
94
95   // Resolve uniform buffers
96   ResolveUniformBuffers();
97
98   // Bind textures
99   for(const auto& binding : mImpl->mCurrentTextureBindings)
100   {
101     auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
102
103     // Texture may not have been initialized yet...(tbm_surface timing issue?)
104     if(!texture->GetGLTexture())
105     {
106       // Attempt to reinitialize
107       // @todo need to put this somewhere else where it isn't const.
108       // Maybe post it back on end of initialize queue if initialization fails?
109       texture->InitializeResource();
110     }
111
112     texture->Bind(binding);
113     texture->Prepare(); // @todo also non-const.
114   }
115
116   // for each attribute bind vertices
117   const auto& pipelineState = mImpl->mCurrentPipeline->GetCreateInfo();
118   const auto& vi            = pipelineState.vertexInputState;
119   for(const auto& attr : vi->attributes)
120   {
121     // Enable location
122     gl.EnableVertexAttribArray(attr.location);
123     const auto& bufferSlot    = mImpl->mCurrentVertexBufferBindings[attr.binding];
124     const auto& bufferBinding = vi->bufferBindings[attr.binding];
125
126     auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
127
128     // Bind buffer
129     gl.BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
130     gl.VertexAttribPointer(attr.location,
131                            GLVertexFormat(attr.format).size,
132                            GLVertexFormat(attr.format).format,
133                            GL_FALSE,
134                            bufferBinding.stride,
135                            reinterpret_cast<void*>(attr.offset));
136   }
137
138   // Resolve topology
139   const auto& ia = mImpl->mCurrentPipeline->GetCreateInfo().inputAssemblyState;
140
141   // Bind uniforms
142
143   // Resolve draw call
144   switch(drawCall.type)
145   {
146     case DrawCallDescriptor::Type::DRAW:
147     {
148       gl.DrawArrays(GLESTopology(ia->topology),
149                     drawCall.draw.firstVertex,
150                     drawCall.draw.vertexCount);
151       break;
152     }
153     case DrawCallDescriptor::Type::DRAW_INDEXED:
154     {
155       const auto& binding    = mImpl->mCurrentIndexBufferBinding;
156       const auto* glesBuffer = binding.buffer;
157       gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, glesBuffer->GetGLBuffer());
158       auto indexBufferFormat = GLIndexFormat(binding.format).format;
159       gl.DrawElements(GLESTopology(ia->topology),
160                       drawCall.drawIndexed.indexCount,
161                       indexBufferFormat,
162                       reinterpret_cast<void*>(binding.offset));
163       break;
164     }
165     case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
166     {
167       break;
168     }
169   }
170
171   ClearState();
172 }
173
174 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
175 {
176   // for each texture allocate slot
177   for(const auto& binding : bindings)
178   {
179     // Resize binding array if needed
180     if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
181     {
182       mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
183     }
184     // Store the binding details
185     mImpl->mCurrentTextureBindings[binding.binding] = binding;
186   }
187 }
188
189 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
190 {
191   if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
192   {
193     mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
194   }
195   // Copy only set slots
196   std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
197     return (nullptr != item.buffer);
198   });
199 }
200
201 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
202 {
203   mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
204 }
205
206 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
207 {
208   mImpl->mNewPipeline = newPipeline;
209 }
210
211 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
212                                  const UniformBufferBindingDescriptor&              standaloneBindings)
213 {
214   if(standaloneBindings.buffer)
215   {
216     mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
217   }
218
219   if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
220   {
221     mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
222   }
223
224   auto it = uboBindings.begin();
225   for(auto i = 0u; i < uboBindings.size(); ++i)
226   {
227     if(it->buffer)
228     {
229       mImpl->mCurrentUBOBindings[i] = *it;
230     }
231   }
232 }
233
234 void Context::ResolveBlendState()
235 {
236   const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
237   const auto& bs    = state.colorBlendState;
238   auto&       gl    = *mImpl->mController.GetGL();
239
240   // TODO: prevent leaking the state
241   if(!bs)
242   {
243     return;
244   }
245
246   bs->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
247   if(!bs->blendEnable)
248   {
249     return;
250   }
251
252   gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
253
254   if((GLBlendFunc(bs->srcColorBlendFactor) == GLBlendFunc(bs->srcAlphaBlendFactor)) &&
255      (GLBlendFunc(bs->dstColorBlendFactor) == GLBlendFunc(bs->dstAlphaBlendFactor)))
256   {
257     gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
258   }
259   else
260   {
261     gl.BlendFuncSeparate(GLBlendFunc(bs->srcColorBlendFactor),
262                          GLBlendFunc(bs->dstColorBlendFactor),
263                          GLBlendFunc(bs->srcAlphaBlendFactor),
264                          GLBlendFunc(bs->dstAlphaBlendFactor));
265   }
266   if(GLBlendOp(bs->colorBlendOp) == GLBlendOp(bs->alphaBlendOp))
267   {
268     gl.BlendEquation(GLBlendOp(bs->colorBlendOp));
269   }
270   else
271   {
272     gl.BlendEquationSeparate(GLBlendOp(bs->colorBlendOp), GLBlendOp(bs->alphaBlendOp));
273   }
274 }
275
276 void Context::ResolveRasterizationState()
277 {
278   const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
279   const auto& rs    = state.rasterizationState;
280   auto&       gl    = *mImpl->mController.GetGL();
281
282   // TODO: prevent leaking the state
283   if(!rs)
284   {
285     return;
286   }
287
288   if(rs->cullMode == CullMode::NONE)
289   {
290     gl.Disable(GL_CULL_FACE);
291   }
292   else
293   {
294     gl.Enable(GL_CULL_FACE);
295     gl.CullFace(GLCullMode(rs->cullMode));
296   }
297
298   // TODO: implement polygon mode (fill, line, points)
299   //       seems like we don't support it (no glPolygonMode())
300 }
301
302 void Context::ResolveUniformBuffers()
303 {
304   // Resolve standalone uniforms if we have binding
305   if(mImpl->mCurrentStandaloneUBOBinding.buffer)
306   {
307     ResolveStandaloneUniforms();
308   }
309 }
310
311 void Context::ResolveStandaloneUniforms()
312 {
313   auto& gl = *mImpl->mController.GetGL();
314
315   // Find reflection for program
316   const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
317
318   const auto& reflection = program->GetReflection();
319
320   auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
321
322   const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress());
323
324   for(const auto& info : extraInfos)
325   {
326     auto type   = GLTypeConversion(info.type).type;
327     auto offset = info.offset;
328     switch(type)
329     {
330       case GLType::FLOAT_VEC2:
331       {
332         gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
333         break;
334       }
335       case GLType::FLOAT_VEC3:
336       {
337         gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
338         break;
339       }
340       case GLType::FLOAT_VEC4:
341       {
342         gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
343         break;
344       }
345       case GLType::INT_VEC2:
346       {
347         gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
348         break;
349       }
350       case GLType::INT_VEC3:
351       {
352         gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
353         break;
354       }
355       case GLType::INT_VEC4:
356       {
357         gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
358         break;
359       }
360       case GLType::BOOL:
361       {
362         // not supported by DALi
363         break;
364       }
365       case GLType::BOOL_VEC2:
366       {
367         // not supported by DALi
368         break;
369       }
370       case GLType::BOOL_VEC3:
371       {
372         // not supported by DALi
373         break;
374       }
375       case GLType::BOOL_VEC4:
376       {
377         // not supported by DALi
378         break;
379       }
380       case GLType::FLOAT:
381       {
382         gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
383         break;
384       }
385       case GLType::FLOAT_MAT2:
386       {
387         gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
388         break;
389       }
390       case GLType::FLOAT_MAT3:
391       {
392         gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
393         break;
394       }
395       case GLType::FLOAT_MAT4:
396       {
397         gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
398         break;
399       }
400       case GLType::SAMPLER_2D:
401       {
402         break;
403       }
404       case GLType::SAMPLER_CUBE:
405       {
406         break;
407       }
408       default:
409       {
410       }
411     }
412   }
413 }
414
415 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
416 {
417   auto& renderPass   = *renderPassBegin.renderPass;
418   auto& renderTarget = *renderPassBegin.renderTarget;
419
420   const auto& passInfo   = renderPass.GetCreateInfo();
421   const auto& targetInfo = renderTarget.GetCreateInfo();
422
423   auto& gl       = *mImpl->mController.GetGL();
424   auto& graphics = *mImpl->mController.GetGraphicsInterface();
425
426   if(targetInfo.surface)
427   {
428     // switch context to surface bound
429     graphics.ActivateSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(targetInfo.surface));
430
431     // Bind surface FB
432     gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
433   }
434   else if(targetInfo.framebuffer)
435   {
436     // if needed, switch to shared context.
437     graphics.ActivateResourceContext();
438
439     // bind framebuffer and swap.
440     renderTarget.GetFramebuffer()->Bind();
441   }
442
443   // clear (ideally cache the setup)
444
445   // In GL we assume that the last attachment is depth/stencil (we may need
446   // to cache extra information inside GLES RenderTarget if we want to be
447   // more specific in case of MRT)
448
449   // For GLES2.0 we clear only a single color attachment
450   if(mImpl->mController.GetGLESVersion() == GLESVersion::GLES_20)
451   {
452     const auto& attachments = *renderPass.GetCreateInfo().attachments;
453     const auto& color0      = attachments[0];
454     GLuint      mask        = 0;
455     if(color0.loadOp == AttachmentLoadOp::CLEAR)
456     {
457       mask |= GL_COLOR_BUFFER_BIT;
458
459       // Set clear color (todo: cache it!)
460       // Something goes wrong here if Alpha mask is GL_TRUE
461       gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
462       gl.ClearColor(renderPassBegin.clearValues[0].color.r,
463                     renderPassBegin.clearValues[0].color.g,
464                     renderPassBegin.clearValues[0].color.b,
465                     renderPassBegin.clearValues[0].color.a);
466     }
467
468     // check for depth stencil
469     if(attachments.size() > 1)
470     {
471       const auto& depthStencil = attachments.back();
472       if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
473       {
474         mask |= GL_DEPTH_BUFFER_BIT;
475       }
476       if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
477       {
478         mask |= GL_STENCIL_BUFFER_BIT;
479       }
480     }
481
482     gl.Enable(GL_SCISSOR_TEST);
483     gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
484     gl.Clear(mask);
485     gl.Disable(GL_SCISSOR_TEST);
486   }
487
488   mImpl->mCurrentRenderPass   = &renderPass;
489   mImpl->mCurrentRenderTarget = &renderTarget;
490 }
491
492 void Context::EndRenderPass()
493 {
494   if(mImpl->mCurrentRenderTarget)
495   {
496     if(mImpl->mCurrentRenderTarget->GetFramebuffer())
497     {
498       auto& gl = *mImpl->mController.GetGL();
499       gl.Flush();
500     }
501   }
502 }
503
504 void Context::ClearState()
505 {
506   mImpl->mCurrentTextureBindings.clear();
507 }
508
509 } // namespace Dali::Graphics::GLES