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/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"
26 namespace Dali::Graphics::GLES
30 Impl(EglGraphicsController& controller)
31 : mController(controller)
37 EglGraphicsController& mController;
39 const GLES::Pipeline* mCurrentPipeline{nullptr}; ///< Currently bound pipeline
40 const GLES::Pipeline* mNewPipeline{nullptr}; ///< New pipeline to be set on flush
42 std::vector<Graphics::TextureBinding> mCurrentTextureBindings{};
43 std::vector<Graphics::SamplerBinding> mCurrentSamplerBindings{};
44 GLES::IndexBufferBindingDescriptor mCurrentIndexBufferBinding{};
46 struct VertexBufferBinding
48 GLES::Buffer* buffer{nullptr};
52 // Currently bound buffers
53 std::vector<VertexBufferBindingDescriptor> mCurrentVertexBufferBindings{};
55 // Currently bound UBOs (check if it's needed per program!)
56 std::vector<UniformBufferBindingDescriptor> mCurrentUBOBindings{};
57 UniformBufferBindingDescriptor mCurrentStandaloneUBOBinding{};
60 Context::Context(EglGraphicsController& controller)
62 mImpl = std::make_unique<Impl>(controller);
65 Context::~Context() = default;
67 void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall)
69 auto& gl = *mImpl->mController.GetGL();
72 if(mImpl->mNewPipeline)
74 // Execute states if different
75 mImpl->mCurrentPipeline = mImpl->mNewPipeline;
76 mImpl->mNewPipeline = nullptr;
78 mImpl->mCurrentPipeline->GetPipeline().Bind(nullptr);
83 // Resolve rasterization state
84 ResolveRasterizationState();
86 // Resolve uniform buffers
87 ResolveUniformBuffers();
90 for(const auto& binding : mImpl->mCurrentTextureBindings)
92 auto texture = const_cast<GLES::Texture*>(static_cast<const GLES::Texture*>(binding.texture));
94 // Texture may not have been initialized yet...(tbm_surface timing issue?)
95 if(!texture->GetGLTexture())
97 // Attempt to reinitialize
98 // @todo need to put this somewhere else where it isn't const.
99 // Maybe post it back on end of initialize queue if initialization fails?
100 texture->InitializeResource();
103 texture->Bind(binding);
104 texture->Prepare(); // @todo also non-const.
107 // for each attribute bind vertices
108 const auto& pipelineState = mImpl->mCurrentPipeline->GetCreateInfo();
109 const auto& vi = pipelineState.vertexInputState;
110 for(const auto& attr : vi->attributes)
113 gl.EnableVertexAttribArray(attr.location);
114 const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding];
115 const auto& bufferBinding = vi->bufferBindings[attr.binding];
117 auto glesBuffer = bufferSlot.buffer->GetGLBuffer();
120 gl.BindBuffer(GL_ARRAY_BUFFER, glesBuffer);
121 gl.VertexAttribPointer(attr.location,
122 GLVertexFormat(attr.format).size,
123 GLVertexFormat(attr.format).format,
125 bufferBinding.stride,
126 reinterpret_cast<void*>(attr.offset));
130 const auto& ia = mImpl->mCurrentPipeline->GetCreateInfo().inputAssemblyState;
135 switch(drawCall.type)
137 case DrawCallDescriptor::Type::DRAW:
139 gl.DrawArrays(GLESTopology(ia->topology),
140 drawCall.draw.firstVertex,
141 drawCall.draw.vertexCount);
144 case DrawCallDescriptor::Type::DRAW_INDEXED:
146 const auto& binding = mImpl->mCurrentIndexBufferBinding;
147 const auto* glesBuffer = binding.buffer;
148 gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, glesBuffer->GetGLBuffer());
149 auto indexBufferFormat = GLIndexFormat(binding.format).format;
150 gl.DrawElements(GLESTopology(ia->topology),
151 drawCall.drawIndexed.indexCount,
153 reinterpret_cast<void*>(binding.offset));
156 case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT:
165 void Context::BindTextures(const std::vector<Graphics::TextureBinding>& bindings)
167 // for each texture allocate slot
168 for(const auto& binding : bindings)
170 // Resize binding array if needed
171 if(mImpl->mCurrentTextureBindings.size() <= binding.binding)
173 mImpl->mCurrentTextureBindings.resize(binding.binding + 1);
175 // Store the binding details
176 mImpl->mCurrentTextureBindings[binding.binding] = binding;
180 void Context::BindVertexBuffers(const std::vector<GLES::VertexBufferBindingDescriptor>& bindings)
182 if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size())
184 mImpl->mCurrentVertexBufferBindings.resize(bindings.size());
186 // Copy only set slots
187 std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) {
188 return (nullptr != item.buffer);
192 void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding)
194 mImpl->mCurrentIndexBufferBinding = indexBufferBinding;
197 void Context::BindPipeline(const GLES::Pipeline* newPipeline)
199 mImpl->mNewPipeline = newPipeline;
202 void Context::BindUniformBuffers(const std::vector<UniformBufferBindingDescriptor>& uboBindings,
203 const UniformBufferBindingDescriptor& standaloneBindings)
205 if(standaloneBindings.buffer)
207 mImpl->mCurrentStandaloneUBOBinding = standaloneBindings;
210 if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size())
212 mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1);
215 auto it = uboBindings.begin();
216 for(auto i = 0u; i < uboBindings.size(); ++i)
220 mImpl->mCurrentUBOBindings[i] = *it;
225 void Context::ResolveBlendState()
227 const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
228 const auto& bs = state.colorBlendState;
229 auto& gl = *mImpl->mController.GetGL();
231 // TODO: prevent leaking the state
237 bs->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND);
243 gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
245 if((GLBlendFunc(bs->srcColorBlendFactor) == GLBlendFunc(bs->srcAlphaBlendFactor)) &&
246 (GLBlendFunc(bs->dstColorBlendFactor) == GLBlendFunc(bs->dstAlphaBlendFactor)))
248 gl.BlendFunc(GLBlendFunc(bs->srcColorBlendFactor), GLBlendFunc(bs->dstColorBlendFactor));
252 gl.BlendFuncSeparate(GLBlendFunc(bs->srcColorBlendFactor),
253 GLBlendFunc(bs->dstColorBlendFactor),
254 GLBlendFunc(bs->srcAlphaBlendFactor),
255 GLBlendFunc(bs->dstAlphaBlendFactor));
257 if(GLBlendOp(bs->colorBlendOp) == GLBlendOp(bs->alphaBlendOp))
259 gl.BlendEquation(GLBlendOp(bs->colorBlendOp));
263 gl.BlendEquationSeparate(GLBlendOp(bs->colorBlendOp), GLBlendOp(bs->alphaBlendOp));
267 void Context::ResolveRasterizationState()
269 const auto& state = mImpl->mCurrentPipeline->GetCreateInfo();
270 const auto& rs = state.rasterizationState;
271 auto& gl = *mImpl->mController.GetGL();
273 // TODO: prevent leaking the state
279 if(rs->cullMode == CullMode::NONE)
281 gl.Disable(GL_CULL_FACE);
285 gl.Enable(GL_CULL_FACE);
286 gl.CullFace(GLCullMode(rs->cullMode));
289 // TODO: implement polygon mode (fill, line, points)
290 // seems like we don't support it (no glPolygonMode())
293 void Context::ResolveUniformBuffers()
295 // Resolve standalone uniforms if we have binding
296 if(mImpl->mCurrentStandaloneUBOBinding.buffer)
298 ResolveStandaloneUniforms();
302 void Context::ResolveStandaloneUniforms()
304 auto& gl = *mImpl->mController.GetGL();
306 // Find reflection for program
307 const auto program = static_cast<const GLES::Program*>(mImpl->mCurrentPipeline->GetCreateInfo().programState->program);
309 const auto& reflection = program->GetReflection();
311 auto extraInfos = reflection.GetStandaloneUniformExtraInfo();
313 const auto ptr = reinterpret_cast<const char*>(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress());
315 for(const auto& info : extraInfos)
317 auto type = GLTypeConversion(info.type).type;
318 auto offset = info.offset;
321 case GLType::FLOAT_VEC2:
323 gl.Uniform2fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
326 case GLType::FLOAT_VEC3:
328 gl.Uniform3fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
331 case GLType::FLOAT_VEC4:
333 gl.Uniform4fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
336 case GLType::INT_VEC2:
338 gl.Uniform2iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
341 case GLType::INT_VEC3:
343 gl.Uniform3iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
346 case GLType::INT_VEC4:
348 gl.Uniform4iv(info.location, info.arraySize, reinterpret_cast<const GLint*>(&ptr[offset]));
353 // not supported by DALi
356 case GLType::BOOL_VEC2:
358 // not supported by DALi
361 case GLType::BOOL_VEC3:
363 // not supported by DALi
366 case GLType::BOOL_VEC4:
368 // not supported by DALi
373 gl.Uniform1fv(info.location, info.arraySize, reinterpret_cast<const float*>(&ptr[offset]));
376 case GLType::FLOAT_MAT2:
378 gl.UniformMatrix2fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
381 case GLType::FLOAT_MAT3:
383 gl.UniformMatrix3fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
386 case GLType::FLOAT_MAT4:
388 gl.UniformMatrix4fv(info.location, info.arraySize, GL_FALSE, reinterpret_cast<const float*>(&ptr[offset]));
391 case GLType::SAMPLER_2D:
395 case GLType::SAMPLER_CUBE:
406 void Context::ClearState()
408 mImpl->mCurrentTextureBindings.clear();
411 } // namespace Dali::Graphics::GLES