X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fgraphics%2Fgles-impl%2Fgles-context.cpp;h=569fdfc1aa4de1578de4611a32072a4b2f4528e0;hb=b30ac188a1e76825e564b3ea8dc3f7166902323c;hp=1d981bc781917d92b246ab4484f6c3050245e1e2;hpb=710a932acbde35cfcfad41fe3f7c225021258c32;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index 1d981bc..569fdfc 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ #include #include #include +#include namespace Dali::Graphics::GLES { @@ -53,24 +54,42 @@ struct Context::Impl * that VertexInputState has been set correctly for the pipeline. * */ - void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState) + void BindProgramVAO(const GLES::ProgramImpl* program, const VertexInputState& vertexInputState) { + // Calculate attributes location hash unordered. + std::size_t hash = 0; + for(const auto& attr : vertexInputState.attributes) + { + hash ^= std::hash{}(attr.location); + } + auto& gl = *mController.GetGL(); auto iter = mProgramVAOMap.find(program); if(iter != mProgramVAOMap.end()) { - if(mProgramVAOCurrentState != iter->second) + auto attributeIter = iter->second.find(hash); + if(attributeIter != iter->second.end()) { - mProgramVAOCurrentState = iter->second; - gl.BindVertexArray(iter->second); + if(mProgramVAOCurrentState != attributeIter->second) + { + mProgramVAOCurrentState = attributeIter->second; + gl.BindVertexArray(attributeIter->second); + + // Binding VAO seems to reset the index buffer binding so the cache must be reset + mGlStateCache.mBoundElementArrayBufferId = 0; + } + return; } - return; } uint32_t vao; gl.GenVertexArrays(1, &vao); gl.BindVertexArray(vao); - mProgramVAOMap[program] = vao; + + // Binding VAO seems to reset the index buffer binding so the cache must be reset + mGlStateCache.mBoundElementArrayBufferId = 0; + + mProgramVAOMap[program][hash] = vao; for(const auto& attr : vertexInputState.attributes) { gl.EnableVertexAttribArray(attr.location); @@ -120,6 +139,10 @@ struct Context::Impl memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId)); mGlStateCache.mFrameBufferStateCache.Reset(); + + GLint maxTextures; + gl.GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextures); + DALI_LOG_RELEASE_INFO("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d\n", maxTextures); } /** @@ -206,11 +229,12 @@ struct Context::Impl const GLES::RenderPass* mCurrentRenderPass{nullptr}; // Each context must have own VAOs as they cannot be shared - std::map mProgramVAOMap; ///< GL program-VAO map - uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO - GLStateCache mGlStateCache{}; ///< GL status cache + std::unordered_map> mProgramVAOMap; ///< GL program-VAO map + uint32_t mProgramVAOCurrentState{0u}; ///< Currently bound VAO + GLStateCache mGlStateCache{}; ///< GL status cache - bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + bool mVertexBuffersChanged{true}; ///< True if BindVertexBuffers changed any buffer bindings EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context @@ -265,11 +289,16 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: return; } + // If this draw uses a different pipeline _AND_ the pipeline has a different GL Program, + // Then bind the new program. Ensure vertex atrributes are set. + + bool programChanged = false; if(mImpl->mNewPipeline && mImpl->mCurrentPipeline != mImpl->mNewPipeline) { if(!currentProgram || currentProgram->GetImplementation()->GetGlProgram() != newProgram->GetImplementation()->GetGlProgram()) { mImpl->mNewPipeline->Bind(newProgram->GetImplementation()->GetGlProgram()); + programChanged = true; } // Blend state @@ -286,73 +315,118 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: // Map binding# to sampler location const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection(); const auto& samplers = reflection.GetSamplers(); + + uint32_t currentSampler = 0; + uint32_t currentElement = 0; + + // @warning Assume that binding.binding is strictly linear in the same order as mCurrentTextureBindings + // elements. This avoids having to sort the bindings. for(const auto& binding : mImpl->mCurrentTextureBindings) { + if(currentSampler >= samplers.size()) + { + // Don't bind more textures than there are active samplers. + break; + } + auto texture = const_cast(static_cast(binding.texture)); // Texture may not have been initialized yet...(tbm_surface timing issue?) if(!texture->GetGLTexture()) { - // Attempt to reinitialize - // @todo need to put this somewhere else where it isn't const. - // Maybe post it back on end of initialize queue if initialization fails? texture->InitializeResource(); } // Warning, this may cause glWaitSync to occur on the GPU. dependencyChecker.CheckNeedsSync(this, texture); - texture->Bind(binding); + texture->Prepare(); - texture->Prepare(); // @todo also non-const. - - if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order) + if(programChanged) { - // Offset is set to the lexical offset within the frag shader, map it to the texture unit - // @todo Explicitly set the texture unit through the graphics interface - gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset); + // @warning Assume that location of array elements is sequential. + // @warning GL does not guarantee this, but in practice, it is. + gl.Uniform1i(samplers[currentSampler].location + currentElement, + samplers[currentSampler].offset + currentElement); + ++currentElement; + if(currentElement >= samplers[currentSampler].elementCount) + { + ++currentSampler; + currentElement = 0; + } } } - // for each attribute bind vertices - const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo(); const auto& vertexInputState = pipelineState.vertexInputState; - if(hasGLES3) - { - mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); - } - - for(const auto& attr : vertexInputState->attributes) + // for each attribute bind vertices, unless the pipeline+buffer is the same + if(programChanged || mImpl->mVertexBuffersChanged) { - // Enable location - if(!hasGLES3) + if(hasGLES3) { - mImpl->SetVertexAttributeLocation(attr.location, true); + mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); } - const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; - const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; + for(const auto& attr : vertexInputState->attributes) + { + // Enable location + if(!hasGLES3) + { + mImpl->SetVertexAttributeLocation(attr.location, true); + } + + const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; + const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; - auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); + auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); - // Bind buffer - BindBuffer(GL_ARRAY_BUFFER, glesBuffer); + BindBuffer(GL_ARRAY_BUFFER, glesBuffer); // Cached - gl.VertexAttribPointer(attr.location, - GLVertexFormat(attr.format).size, - GLVertexFormat(attr.format).format, - GL_FALSE, - bufferBinding.stride, - reinterpret_cast(attr.offset)); + if(attr.format == VertexInputFormat::FLOAT || + attr.format == VertexInputFormat::FVECTOR2 || + attr.format == VertexInputFormat::FVECTOR3 || + attr.format == VertexInputFormat::FVECTOR4) + { + gl.VertexAttribPointer(attr.location, // Not cached... + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + GL_FALSE, + bufferBinding.stride, + reinterpret_cast(attr.offset)); + } + else + { + gl.VertexAttribIPointer(attr.location, + GLVertexFormat(attr.format).size, + GLVertexFormat(attr.format).format, + bufferBinding.stride, + reinterpret_cast(attr.offset)); + } + + if(hasGLES3) + { + switch(bufferBinding.inputRate) + { + case Graphics::VertexInputRate::PER_VERTEX: + { + gl.VertexAttribDivisor(attr.location, 0); + break; + } + case Graphics::VertexInputRate::PER_INSTANCE: + { + //@todo Get actual instance rate... + gl.VertexAttribDivisor(attr.location, 1); + break; + } + } + } + } } // Resolve topology const auto& ia = pipelineState.inputAssemblyState; - // Bind uniforms - // Resolve draw call switch(drawCall.type) { @@ -367,9 +441,19 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: mImpl->FlushVertexAttributeLocations(); } - gl.DrawArrays(GLESTopology(ia->topology), - drawCall.draw.firstVertex, - drawCall.draw.vertexCount); + if(drawCall.draw.instanceCount == 0) + { + gl.DrawArrays(GLESTopology(ia->topology), + drawCall.draw.firstVertex, + drawCall.draw.vertexCount); + } + else + { + gl.DrawArraysInstanced(GLESTopology(ia->topology), + drawCall.draw.firstVertex, + drawCall.draw.vertexCount, + drawCall.draw.instanceCount); + } break; } case DrawCallDescriptor::Type::DRAW_INDEXED: @@ -388,10 +472,21 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: } auto indexBufferFormat = GLIndexFormat(binding.format).format; - gl.DrawElements(GLESTopology(ia->topology), - drawCall.drawIndexed.indexCount, - indexBufferFormat, - reinterpret_cast(binding.offset)); + if(drawCall.drawIndexed.instanceCount == 0) + { + gl.DrawElements(GLESTopology(ia->topology), + drawCall.drawIndexed.indexCount, + indexBufferFormat, + reinterpret_cast(binding.offset)); + } + else + { + gl.DrawElementsInstanced(GLESTopology(ia->topology), + drawCall.drawIndexed.indexCount, + indexBufferFormat, + reinterpret_cast(binding.offset), + drawCall.drawIndexed.instanceCount); + } break; } case DrawCallDescriptor::Type::DRAW_INDEXED_INDIRECT: @@ -434,9 +529,19 @@ void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindi mImpl->mCurrentVertexBufferBindings.resize(count); } // Copy only set slots - std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) { - return (nullptr != item.buffer); - }); + mImpl->mVertexBuffersChanged = false; + auto toIter = mImpl->mCurrentVertexBufferBindings.begin(); + for(auto fromIter = bindings, end = bindings + count; fromIter != end; ++fromIter) + { + if(fromIter->buffer != nullptr) + { + if(toIter->buffer != fromIter->buffer || toIter->offset != fromIter->offset) + { + mImpl->mVertexBuffersChanged = true; + } + *toIter++ = *fromIter; + } + } } void Context::BindIndexBuffer(const IndexBufferBindingDescriptor& indexBufferBinding) @@ -459,9 +564,9 @@ void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindin mImpl->mCurrentStandaloneUBOBinding = standaloneBindings; } - if(uboCount >= mImpl->mCurrentUBOBindings.size()) + if(uboCount && uboCount > mImpl->mCurrentUBOBindings.size()) { - mImpl->mCurrentUBOBindings.resize(uboCount + 1); + mImpl->mCurrentUBOBindings.resize(uboCount); } auto it = uboBindings; @@ -471,6 +576,7 @@ void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindin { mImpl->mCurrentUBOBindings[i] = *it; } + ++it; } } @@ -600,6 +706,20 @@ void Context::ResolveUniformBuffers() { ResolveStandaloneUniforms(); } + if(!mImpl->mCurrentUBOBindings.empty()) + { + ResolveGpuUniformBuffers(); + } +} + +void Context::ResolveGpuUniformBuffers() +{ + auto& gl = *mImpl->mController.GetGL(); + auto i = 0u; + for(auto& binding : mImpl->mCurrentUBOBindings) + { + gl.BindBufferRange(GL_UNIFORM_BUFFER, i++, binding.buffer->GetGLBuffer(), GLintptr(binding.offset), binding.dataSize); + } } void Context::ResolveStandaloneUniforms() @@ -746,6 +866,7 @@ void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker) void Context::ClearState() { mImpl->mCurrentTextureBindings.clear(); + mImpl->mCurrentUBOBindings.clear(); } void Context::ColorMask(bool enabled) @@ -936,15 +1057,34 @@ void Context::GenerateMipmap(GLenum target) gl.GenerateMipmap(target); } -void Context::BindBuffer(GLenum target, uint32_t bufferId) +bool Context::BindBuffer(GLenum target, uint32_t bufferId) { - if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId) + switch(target) { - mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; - - auto& gl = *mImpl->mController.GetGL(); - gl.BindBuffer(target, bufferId); + case GL_ARRAY_BUFFER: + { + if(mImpl->mGlStateCache.mBoundArrayBufferId == bufferId) + { + return false; + } + mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; + break; + } + case GL_ELEMENT_ARRAY_BUFFER: + { + if(mImpl->mGlStateCache.mBoundElementArrayBufferId == bufferId) + { + return false; + } + mImpl->mGlStateCache.mBoundElementArrayBufferId = bufferId; + break; + } } + + // Cache miss. Bind buffer. + auto& gl = *mImpl->mController.GetGL(); + gl.BindBuffer(target, bufferId); + return true; } void Context::DrawBuffers(uint32_t count, const GLenum* buffers) @@ -1009,6 +1149,34 @@ void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline) { mImpl->mCurrentPipeline = nullptr; } + + // Remove cached VAO map + auto* gl = mImpl->mController.GetGL(); + if(gl) + { + const auto* program = pipeline->GetCreateInfo().programState->program; + if(program) + { + const auto* programImpl = static_cast(program)->GetImplementation(); + if(programImpl) + { + auto iter = mImpl->mProgramVAOMap.find(programImpl); + if(iter != mImpl->mProgramVAOMap.end()) + { + for(auto& attributeHashPair : iter->second) + { + auto vao = attributeHashPair.second; + gl->DeleteVertexArrays(1, &vao); + if(mImpl->mProgramVAOCurrentState == vao) + { + mImpl->mProgramVAOCurrentState = 0u; + } + } + mImpl->mProgramVAOMap.erase(iter); + } + } + } + } } void Context::PrepareForNativeRendering()