Merge "Merge branch 'devel/master' into devel/graphics" into devel/master
[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   // Map binding# to sampler location
100   const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
101
102   const auto& reflection = program->GetReflection();
103   const auto& samplers   = reflection.GetSamplers();
104   for(const auto& binding : mImpl->mCurrentTextureBindings)
105   {
106     auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
107
108     // Texture may not have been initialized yet...(tbm_surface timing issue?)
109     if(!texture->GetGLTexture())
110     {
111       // Attempt to reinitialize
112       // @todo need to put this somewhere else where it isn't const.
113       // Maybe post it back on end of initialize queue if initialization fails?
114       texture->InitializeResource();
115     }
116
117     texture->Bind(binding);
118     texture->Prepare(); // @todo also non-const.
119
120     if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
121     {
122       // Offset is set to the lexical offset within the frag shader, map it to the texture unit
123       // @todo Explicitly set the texture unit through the graphics interface
124       gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset);
125     }
126   }
127
128   // for each attribute bind vertices
129   const auto& pipelineState = mImpl->mCurrentPipeline->GetCreateInfo();
130   const auto& vi            = pipelineState.vertexInputState;
131   for(const auto& attr : vi->attributes)
132   {
133     // Enable location
134     gl.EnableVertexAttribArray(attr.location);
135     const auto& bufferSlot    = mImpl->mCurrentVertexBufferBindings[attr.binding];
136     const auto& bufferBinding = vi->bufferBindings[attr.binding];
137
138     auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
139
140     // Bind buffer
141     gl.BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
142     gl.VertexAttribPointer(attr.location,
143                            GLVertexFormat(attr.format).size,
144                            GLVertexFormat(attr.format).format,
145                            GL_FALSE,
146                            bufferBinding.stride,
147                            reinterpret_cast<void*>(attr.offset));
148   }
149
150   // Resolve topology
151   const auto& ia = mImpl->mCurrentPipeline->GetCreateInfo().inputAssemblyState;
152
153   // Bind uniforms
154
155   // Resolve draw call
156   switch(drawCall.type)
157   {
158     case DrawCallDescriptor::Type::DRAW:
159     {
160       gl.DrawArrays(GLESTopology(ia->topology),
161                     drawCall.draw.firstVertex,
162                     drawCall.draw.vertexCount);
163       break;
164     }
165     case DrawCallDescriptor::Type::DRAW_INDEXED:
166     {
167       const auto& binding    = mImpl->mCurrentIndexBufferBinding;
168       const auto* glesBuffer = binding.buffer;
169       gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, glesBuffer->GetGLBuffer());
170       auto indexBufferFormat = GLIndexFormat(binding.format).format;
171       gl.DrawElements(GLESTopology(ia->topology),
172                       drawCall.drawIndexed.indexCount,
173                       indexBufferFormat,
174                       reinterpret_cast<void*>(binding.offset));
175       break;
176     }
177     case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
178     {
179       break;
180     }
181   }
182
183   ClearState();
184 }
185
186 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
187 {
188   // for each texture allocate slot
189   for(const auto& binding : bindings)
190   {
191     // Resize binding array if needed
192     if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
193     {
194       mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
195     }
196     // Store the binding details
197     mImpl->mCurrentTextureBindings[binding.binding] = binding;
198   }
199 }
200
201 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
202 {
203   if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
204   {
205     mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
206   }
207   // Copy only set slots
208   std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
209     return (nullptr != item.buffer);
210   });
211 }
212
213 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
214 {
215   mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
216 }
217
218 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
219 {
220   mImpl->mNewPipeline = newPipeline;
221 }
222
223 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
224                                  const UniformBufferBindingDescriptor&              standaloneBindings)
225 {
226   if(standaloneBindings.buffer)
227   {
228     mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
229   }
230
231   if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
232   {
233     mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
234   }
235
236   auto it = uboBindings.begin();
237   for(auto i = 0u; i < uboBindings.size(); ++i)
238   {
239     if(it->buffer)
240     {
241       mImpl->mCurrentUBOBindings[i] = *it;
242     }
243   }
244 }
245
246 void Context::ResolveBlendState()
247 {
248   const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
249   const auto& bs    = state.colorBlendState;
250   auto&       gl    = *mImpl->mController.GetGL();
251
252   // TODO: prevent leaking the state
253   if(!bs)
254   {
255     return;
256   }
257
258   bs->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
259   if(!bs->blendEnable)
260   {
261     return;
262   }
263
264   gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
265
266   if((GLBlendFunc(bs->srcColorBlendFactor) == GLBlendFunc(bs->srcAlphaBlendFactor)) &&
267      (GLBlendFunc(bs->dstColorBlendFactor) == GLBlendFunc(bs->dstAlphaBlendFactor)))
268   {
269     gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
270   }
271   else
272   {
273     gl.BlendFuncSeparate(GLBlendFunc(bs->srcColorBlendFactor),
274                          GLBlendFunc(bs->dstColorBlendFactor),
275                          GLBlendFunc(bs->srcAlphaBlendFactor),
276                          GLBlendFunc(bs->dstAlphaBlendFactor));
277   }
278   if(GLBlendOp(bs->colorBlendOp) == GLBlendOp(bs->alphaBlendOp))
279   {
280     gl.BlendEquation(GLBlendOp(bs->colorBlendOp));
281   }
282   else
283   {
284     gl.BlendEquationSeparate(GLBlendOp(bs->colorBlendOp), GLBlendOp(bs->alphaBlendOp));
285   }
286 }
287
288 void Context::ResolveRasterizationState()
289 {
290   const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
291   const auto& rs    = state.rasterizationState;
292   auto&       gl    = *mImpl->mController.GetGL();
293
294   // TODO: prevent leaking the state
295   if(!rs)
296   {
297     return;
298   }
299
300   if(rs->cullMode == CullMode::NONE)
301   {
302     gl.Disable(GL_CULL_FACE);
303   }
304   else
305   {
306     gl.Enable(GL_CULL_FACE);
307     gl.CullFace(GLCullMode(rs->cullMode));
308   }
309
310   // TODO: implement polygon mode (fill, line, points)
311   //       seems like we don't support it (no glPolygonMode())
312 }
313
314 void Context::ResolveUniformBuffers()
315 {
316   // Resolve standalone uniforms if we have binding
317   if(mImpl->mCurrentStandaloneUBOBinding.buffer)
318   {
319     ResolveStandaloneUniforms();
320   }
321 }
322
323 void Context::ResolveStandaloneUniforms()
324 {
325   auto& gl = *mImpl->mController.GetGL();
326
327   // Find reflection for program
328   const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
329
330   const auto& reflection = program->GetReflection();
331
332   auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
333
334   const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset;
335
336   for(const auto& info : extraInfos)
337   {
338     auto type   = GLTypeConversion(info.type).type;
339     auto offset = info.offset;
340     switch(type)
341     {
342       case GLType::FLOAT_VEC2:
343       {
344         gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
345         break;
346       }
347       case GLType::FLOAT_VEC3:
348       {
349         gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
350         break;
351       }
352       case GLType::FLOAT_VEC4:
353       {
354         gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
355         break;
356       }
357       case GLType::INT_VEC2:
358       {
359         gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
360         break;
361       }
362       case GLType::INT_VEC3:
363       {
364         gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
365         break;
366       }
367       case GLType::INT_VEC4:
368       {
369         gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
370         break;
371       }
372       case GLType::BOOL:
373       {
374         // not supported by DALi
375         break;
376       }
377       case GLType::BOOL_VEC2:
378       {
379         // not supported by DALi
380         break;
381       }
382       case GLType::BOOL_VEC3:
383       {
384         // not supported by DALi
385         break;
386       }
387       case GLType::BOOL_VEC4:
388       {
389         // not supported by DALi
390         break;
391       }
392       case GLType::FLOAT:
393       {
394         gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
395         break;
396       }
397       case GLType::FLOAT_MAT2:
398       {
399         gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
400         break;
401       }
402       case GLType::FLOAT_MAT3:
403       {
404         gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
405         break;
406       }
407       case GLType::FLOAT_MAT4:
408       {
409         gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
410         break;
411       }
412       case GLType::SAMPLER_2D:
413       {
414         break;
415       }
416       case GLType::SAMPLER_CUBE:
417       {
418         break;
419       }
420       default:
421       {
422       }
423     }
424   }
425 }
426
427 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
428 {
429   auto& renderPass   = *renderPassBegin.renderPass;
430   auto& renderTarget = *renderPassBegin.renderTarget;
431
432   const auto& targetInfo = renderTarget.GetCreateInfo();
433
434   auto& gl = *mImpl->mController.GetGL();
435
436   if(targetInfo.surface)
437   {
438     // Bind surface FB
439     gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
440   }
441   else if(targetInfo.framebuffer)
442   {
443     // bind framebuffer and swap.
444     renderTarget.GetFramebuffer()->Bind();
445   }
446
447   // clear (ideally cache the setup)
448
449   // In GL we assume that the last attachment is depth/stencil (we may need
450   // to cache extra information inside GLES RenderTarget if we want to be
451   // more specific in case of MRT)
452
453   const auto& attachments = *renderPass.GetCreateInfo().attachments;
454   const auto& color0      = attachments[0];
455   GLuint      mask        = 0;
456   if(color0.loadOp == AttachmentLoadOp::CLEAR)
457   {
458     mask |= GL_COLOR_BUFFER_BIT;
459
460     // Set clear color (todo: cache it!)
461     // Something goes wrong here if Alpha mask is GL_TRUE
462     gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
463     gl.ClearColor(renderPassBegin.clearValues[0].color.r,
464                   renderPassBegin.clearValues[0].color.g,
465                   renderPassBegin.clearValues[0].color.b,
466                   renderPassBegin.clearValues[0].color.a);
467   }
468
469   // check for depth stencil
470   if(attachments.size() > 1)
471   {
472     const auto& depthStencil = attachments.back();
473     if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
474     {
475       gl.DepthMask(true);
476       mask |= GL_DEPTH_BUFFER_BIT;
477     }
478     if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
479     {
480       gl.StencilMask(0xFF);
481       mask |= GL_STENCIL_BUFFER_BIT;
482     }
483   }
484
485   gl.Enable(GL_SCISSOR_TEST);
486   gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
487   gl.Clear(mask);
488   gl.Disable(GL_SCISSOR_TEST);
489
490   mImpl->mCurrentRenderPass   = &renderPass;
491   mImpl->mCurrentRenderTarget = &renderTarget;
492 }
493
494 void Context::EndRenderPass()
495 {
496   if(mImpl->mCurrentRenderTarget)
497   {
498     if(mImpl->mCurrentRenderTarget->GetFramebuffer())
499     {
500       auto& gl = *mImpl->mController.GetGL();
501       gl.Flush();
502     }
503   }
504 }
505
506 void Context::ClearState()
507 {
508   mImpl->mCurrentTextureBindings.clear();
509 }
510
511 void Context::ColorMask(bool enabled)
512 {
513   auto& gl = *mImpl->mController.GetGL();
514   gl.ColorMask(enabled, enabled, enabled, enabled);
515 }
516
517 void Context::ClearStencilBuffer()
518 {
519   auto& gl = *mImpl->mController.GetGL();
520   gl.Clear(GL_STENCIL_BUFFER_BIT);
521 }
522
523 void Context::ClearDepthBuffer()
524 {
525   auto& gl = *mImpl->mController.GetGL();
526   gl.Clear(GL_DEPTH_BUFFER_BIT);
527 }
528
529 void Context::SetStencilTestEnable(bool stencilEnable)
530 {
531   auto& gl = *mImpl->mController.GetGL();
532   if(stencilEnable)
533   {
534     gl.Enable(GL_STENCIL_TEST);
535   }
536   else
537   {
538     gl.Disable(GL_STENCIL_TEST);
539   }
540 }
541
542 void Context::StencilMask(uint32_t writeMask)
543 {
544   auto& gl = *mImpl->mController.GetGL();
545   gl.StencilMask(writeMask);
546 }
547
548 void Context::StencilFunc(Graphics::CompareOp compareOp,
549                           uint32_t            reference,
550                           uint32_t            compareMask)
551 {
552   auto& gl = *mImpl->mController.GetGL();
553   gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
554 }
555
556 void Context::StencilOp(Graphics::StencilOp failOp,
557                         Graphics::StencilOp depthFailOp,
558                         Graphics::StencilOp passOp)
559 {
560   auto& gl = *mImpl->mController.GetGL();
561   gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op);
562 }
563
564 void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
565 {
566   auto& gl = *mImpl->mController.GetGL();
567   gl.DepthFunc(GLCompareOp(compareOp).op);
568 }
569
570 void Context::SetDepthTestEnable(bool depthTestEnable)
571 {
572   auto& gl = *mImpl->mController.GetGL();
573   if(depthTestEnable)
574   {
575     gl.Enable(GL_DEPTH_TEST);
576   }
577   else
578   {
579     gl.Disable(GL_DEPTH_TEST);
580   }
581 }
582
583 void Context::SetDepthWriteEnable(bool depthWriteEnable)
584 {
585   auto& gl = *mImpl->mController.GetGL();
586   gl.DepthMask(depthWriteEnable);
587 }
588
589 } // namespace Dali::Graphics::GLES