2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
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"
31 namespace Dali::Graphics::GLES
35 Impl(EglGraphicsController& controller)
36 : mController(controller)
42 EglGraphicsController& mController;
44 const GLES::Pipeline* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
45 const GLES::Pipeline* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
47 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
48 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
49 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
51 struct VertexBufferBinding
53 GLES::Buffer* buffer{nullptr};
57 // Currently bound buffers
58 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
60 // Currently bound UBOs (check if it's needed per program!)
61 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
62 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
64 // Current render pass and render target
65 const GLES::RenderTarget* mCurrentRenderTarget{nullptr};
66 const GLES::RenderPass* mCurrentRenderPass{nullptr};
69 Context::Context(EglGraphicsController& controller)
71 mImpl = std::make_unique<Impl>(controller);
74 Context::~Context() = default;
76 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
78 auto& gl = *mImpl->mController.GetGL();
81 if(mImpl->mNewPipeline)
83 // Execute states if different
84 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
85 mImpl->mNewPipeline = nullptr;
87 mImpl->mCurrentPipeline->GetPipeline().Bind(nullptr);
92 // Resolve rasterization state
93 ResolveRasterizationState();
95 // Resolve uniform buffers
96 ResolveUniformBuffers();
99 // Map binding# to sampler location
100 const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
102 const auto& reflection = program->GetReflection();
103 const auto& samplers = reflection.GetSamplers();
104 for(const auto& binding : mImpl->mCurrentTextureBindings)
106 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
108 // Texture may not have been initialized yet...(tbm_surface timing issue?)
109 if(!texture->GetGLTexture())
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();
117 texture->Bind(binding);
118 texture->Prepare(); // @todo also non-const.
120 if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order)
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);
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)
134 gl.EnableVertexAttribArray(attr.location);
135 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
136 const auto& bufferBinding = vi->bufferBindings[attr.binding];
138 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
141 gl.BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
142 gl.VertexAttribPointer(attr.location,
143 GLVertexFormat(attr.format).size,
144 GLVertexFormat(attr.format).format,
146 bufferBinding.stride,
147 reinterpret_cast<void*>(attr.offset));
151 const auto& ia = mImpl->mCurrentPipeline->GetCreateInfo().inputAssemblyState;
156 switch(drawCall.type)
158 case DrawCallDescriptor::Type::DRAW:
160 gl.DrawArrays(GLESTopology(ia->topology),
161 drawCall.draw.firstVertex,
162 drawCall.draw.vertexCount);
165 case DrawCallDescriptor::Type::DRAW_INDEXED:
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,
174 reinterpret_cast<void*>(binding.offset));
177 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
186 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
188 // for each texture allocate slot
189 for(const auto& binding : bindings)
191 // Resize binding array if needed
192 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
194 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
196 // Store the binding details
197 mImpl->mCurrentTextureBindings[binding.binding] = binding;
201 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
203 if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
205 mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
207 // Copy only set slots
208 std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
209 return (nullptr != item.buffer);
213 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
215 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
218 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
220 mImpl->mNewPipeline = newPipeline;
223 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
224 const UniformBufferBindingDescriptor& standaloneBindings)
226 if(standaloneBindings.buffer)
228 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
231 if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
233 mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
236 auto it = uboBindings.begin();
237 for(auto i = 0u; i < uboBindings.size(); ++i)
241 mImpl->mCurrentUBOBindings[i] = *it;
246 void Context::ResolveBlendState()
248 const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
249 const auto& bs = state.colorBlendState;
250 auto& gl = *mImpl->mController.GetGL();
252 // TODO: prevent leaking the state
258 bs->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
264 gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
266 if((GLBlendFunc(bs->srcColorBlendFactor) == GLBlendFunc(bs->srcAlphaBlendFactor)) &&
267 (GLBlendFunc(bs->dstColorBlendFactor) == GLBlendFunc(bs->dstAlphaBlendFactor)))
269 gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
273 gl.BlendFuncSeparate(GLBlendFunc(bs->srcColorBlendFactor),
274 GLBlendFunc(bs->dstColorBlendFactor),
275 GLBlendFunc(bs->srcAlphaBlendFactor),
276 GLBlendFunc(bs->dstAlphaBlendFactor));
278 if(GLBlendOp(bs->colorBlendOp) == GLBlendOp(bs->alphaBlendOp))
280 gl.BlendEquation(GLBlendOp(bs->colorBlendOp));
284 gl.BlendEquationSeparate(GLBlendOp(bs->colorBlendOp), GLBlendOp(bs->alphaBlendOp));
288 void Context::ResolveRasterizationState()
290 const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
291 const auto& rs = state.rasterizationState;
292 auto& gl = *mImpl->mController.GetGL();
294 // TODO: prevent leaking the state
300 if(rs->cullMode == CullMode::NONE)
302 gl.Disable(GL_CULL_FACE);
306 gl.Enable(GL_CULL_FACE);
307 gl.CullFace(GLCullMode(rs->cullMode));
310 // TODO: implement polygon mode (fill, line, points)
311 // seems like we don't support it (no glPolygonMode())
314 void Context::ResolveUniformBuffers()
316 // Resolve standalone uniforms if we have binding
317 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
319 ResolveStandaloneUniforms();
323 void Context::ResolveStandaloneUniforms()
325 auto& gl = *mImpl->mController.GetGL();
327 // Find reflection for program
328 const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
330 const auto& reflection = program->GetReflection();
332 auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
334 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress());
336 for(const auto& info : extraInfos)
338 auto type = GLTypeConversion(info.type).type;
339 auto offset = info.offset;
342 case GLType::FLOAT_VEC2:
344 gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
347 case GLType::FLOAT_VEC3:
349 gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
352 case GLType::FLOAT_VEC4:
354 gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
357 case GLType::INT_VEC2:
359 gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
362 case GLType::INT_VEC3:
364 gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
367 case GLType::INT_VEC4:
369 gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
374 // not supported by DALi
377 case GLType::BOOL_VEC2:
379 // not supported by DALi
382 case GLType::BOOL_VEC3:
384 // not supported by DALi
387 case GLType::BOOL_VEC4:
389 // not supported by DALi
394 gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
397 case GLType::FLOAT_MAT2:
399 gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
402 case GLType::FLOAT_MAT3:
404 gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
407 case GLType::FLOAT_MAT4:
409 gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
412 case GLType::SAMPLER_2D:
416 case GLType::SAMPLER_CUBE:
427 void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin)
429 auto& renderPass = *renderPassBegin.renderPass;
430 auto& renderTarget = *renderPassBegin.renderTarget;
432 const auto& targetInfo = renderTarget.GetCreateInfo();
434 auto& gl = *mImpl->mController.GetGL();
435 auto& graphics = *mImpl->mController.GetGraphicsInterface();
437 if(targetInfo.surface)
440 gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
442 else if(targetInfo.framebuffer)
444 // bind framebuffer and swap.
445 renderTarget.GetFramebuffer()->Bind();
448 // clear (ideally cache the setup)
450 // In GL we assume that the last attachment is depth/stencil (we may need
451 // to cache extra information inside GLES RenderTarget if we want to be
452 // more specific in case of MRT)
454 // For GLES2.0 we clear only a single color attachment
455 if(mImpl->mController.GetGLESVersion() == GLESVersion::GLES_20)
457 const auto& attachments = *renderPass.GetCreateInfo().attachments;
458 const auto& color0 = attachments[0];
460 if(color0.loadOp == AttachmentLoadOp::CLEAR)
462 mask |= GL_COLOR_BUFFER_BIT;
464 // Set clear color (todo: cache it!)
465 // Something goes wrong here if Alpha mask is GL_TRUE
466 gl.ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
467 gl.ClearColor(renderPassBegin.clearValues[0].color.r,
468 renderPassBegin.clearValues[0].color.g,
469 renderPassBegin.clearValues[0].color.b,
470 renderPassBegin.clearValues[0].color.a);
473 // check for depth stencil
474 if(attachments.size() > 1)
476 const auto& depthStencil = attachments.back();
477 if(depthStencil.loadOp == AttachmentLoadOp::CLEAR)
479 mask |= GL_DEPTH_BUFFER_BIT;
481 if(depthStencil.stencilLoadOp == AttachmentLoadOp::CLEAR)
483 mask |= GL_STENCIL_BUFFER_BIT;
487 gl.Enable(GL_SCISSOR_TEST);
488 gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height);
490 gl.Disable(GL_SCISSOR_TEST);
493 mImpl->mCurrentRenderPass = &renderPass;
494 mImpl->mCurrentRenderTarget = &renderTarget;
497 void Context::EndRenderPass()
499 if(mImpl->mCurrentRenderTarget)
501 if(mImpl->mCurrentRenderTarget->GetFramebuffer())
503 auto& gl = *mImpl->mController.GetGL();
509 void Context::ClearState()
511 mImpl->mCurrentTextureBindings.clear();
514 } // namespace Dali::Graphics::GLES