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