X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fgraphics%2Fgles-impl%2Fgles-context.cpp;h=f2962a07812006327aa0ed87349f3406cdbb7580;hb=ffee1abdac31e9756f02edfbded64f6d9b3d30b1;hp=89a6010a299d779908ac8e1c12882e2b8b57b3b4;hpb=177e1023cdb7fb21f9a9cfad861c1688c179eecd;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 89a6010..f2962a0 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) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -20,6 +20,7 @@ #include #include #include +#include #include "egl-graphics-controller.h" #include "gles-graphics-buffer.h" @@ -27,12 +28,17 @@ #include "gles-graphics-program.h" #include "gles-graphics-render-pass.h" #include "gles-graphics-render-target.h" +#include "gles-texture-dependency-checker.h" + +#include +#include +#include namespace Dali::Graphics::GLES { struct Context::Impl { - Impl(EglGraphicsController& controller) + explicit Impl(EglGraphicsController& controller) : mController(controller) { } @@ -40,6 +46,39 @@ struct Context::Impl ~Impl() = default; /** + * Binds (and creates) VAO + * + * VAO is fixed per program so it has to be created only once assuming + * that VertexInputState has been set correctly for the pipeline. + * + */ + void BindProgramVAO(GLES::ProgramImpl* program, const VertexInputState& vertexInputState) + { + auto& gl = *mController.GetGL(); + auto iter = mProgramVAOMap.find(program); + if(iter != mProgramVAOMap.end()) + { + if(mProgramVAOCurrentState != iter->second) + { + mProgramVAOCurrentState = iter->second; + gl.BindVertexArray(iter->second); + } + return; + } + + uint32_t vao; + gl.GenVertexArrays(1, &vao); + gl.BindVertexArray(vao); + mProgramVAOMap[program] = vao; + for(const auto& attr : vertexInputState.attributes) + { + gl.EnableVertexAttribArray(attr.location); + } + + mProgramVAOCurrentState = vao; + } + + /** * Sets the initial GL state. */ void InitializeGlState() @@ -165,9 +204,18 @@ struct Context::Impl const GLES::RenderTarget* mCurrentRenderTarget{nullptr}; const GLES::RenderPass* mCurrentRenderPass{nullptr}; - GLStateCache mGlStateCache{}; ///< GL status cache + // 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 bool mGlContextCreated{false}; ///< True if the OpenGL context has been created + + EGLContext mNativeDrawContext{0u}; ///< Native rendering EGL context compatible with window context + + EGLSurface mCacheDrawReadSurface{0u}; ///< cached 'read' surface + EGLSurface mCacheDrawWriteSurface{0u}; ///< cached 'write' surface + EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context }; Context::Context(EglGraphicsController& controller) @@ -175,12 +223,22 @@ Context::Context(EglGraphicsController& controller) mImpl = std::make_unique(controller); } -Context::~Context() = default; +Context::~Context() +{ + // Destroy native rendering context if one exists + if(mImpl->mNativeDrawContext) + { + eglDestroyContext(eglGetCurrentDisplay(), mImpl->mNativeDrawContext); + mImpl->mNativeDrawContext = EGL_NO_CONTEXT; + } +} -void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) +void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker) { auto& gl = *mImpl->mController.GetGL(); + static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30); + // early out if neither current nor new pipelines are set // this behaviour may be valid so no assert if(!mImpl->mCurrentPipeline && !mImpl->mNewPipeline) @@ -229,10 +287,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) { // 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? + // Maybe post it bac/k 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(); // @todo also non-const. @@ -246,15 +307,25 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) } // for each attribute bind vertices - const auto& pipelineState = mImpl->mNewPipeline ? mImpl->mNewPipeline->GetCreateInfo() : mImpl->mCurrentPipeline->GetCreateInfo(); - const auto& vi = pipelineState.vertexInputState; - for(const auto& attr : vi->attributes) + + 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) { // Enable location - mImpl->SetVertexAttributeLocation(attr.location, true); + if(!hasGLES3) + { + mImpl->SetVertexAttributeLocation(attr.location, true); + } const auto& bufferSlot = mImpl->mCurrentVertexBufferBindings[attr.binding]; - const auto& bufferBinding = vi->bufferBindings[attr.binding]; + const auto& bufferBinding = vertexInputState->bufferBindings[attr.binding]; auto glesBuffer = bufferSlot.buffer->GetGLBuffer(); @@ -282,8 +353,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, mImpl->mGlStateCache.DepthBufferWriteEnabled(), mImpl->mGlStateCache.StencilBufferWriteEnabled()); - mImpl->FlushVertexAttributeLocations(); + // For GLES3+ we use VAO, for GLES2 internal cache + if(!hasGLES3) + { + mImpl->FlushVertexAttributeLocations(); + } + //@todo Wait if textures need syncing gl.DrawArrays(GLESTopology(ia->topology), drawCall.draw.firstVertex, drawCall.draw.vertexCount); @@ -297,7 +373,12 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, mImpl->mGlStateCache.DepthBufferWriteEnabled(), mImpl->mGlStateCache.StencilBufferWriteEnabled()); - mImpl->FlushVertexAttributeLocations(); + + // For GLES3+ we use VAO, for GLES2 internal cache + if(!hasGLES3) + { + mImpl->FlushVertexAttributeLocations(); + } auto indexBufferFormat = GLIndexFormat(binding.format).format; gl.DrawElements(GLESTopology(ia->topology), @@ -322,11 +403,13 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall) } } -void Context::BindTextures(const std::vector& bindings) +void Context::BindTextures(const Graphics::TextureBinding* bindings, uint32_t count) { // for each texture allocate slot - for(const auto& binding : bindings) + for(auto i = 0u; i < count; ++i) { + auto& binding = bindings[i]; + // Resize binding array if needed if(mImpl->mCurrentTextureBindings.size() <= binding.binding) { @@ -337,14 +420,14 @@ void Context::BindTextures(const std::vector& bindings } } -void Context::BindVertexBuffers(const std::vector& bindings) +void Context::BindVertexBuffers(const GLES::VertexBufferBindingDescriptor* bindings, uint32_t count) { - if(bindings.size() > mImpl->mCurrentVertexBufferBindings.size()) + if(count > mImpl->mCurrentVertexBufferBindings.size()) { - mImpl->mCurrentVertexBufferBindings.resize(bindings.size()); + mImpl->mCurrentVertexBufferBindings.resize(count); } // Copy only set slots - std::copy_if(bindings.begin(), bindings.end(), mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) { + std::copy_if(bindings, bindings + count, mImpl->mCurrentVertexBufferBindings.begin(), [](auto& item) { return (nullptr != item.buffer); }); } @@ -360,21 +443,22 @@ void Context::BindPipeline(const GLES::Pipeline* newPipeline) mImpl->mNewPipeline = &newPipeline->GetPipeline(); } -void Context::BindUniformBuffers(const std::vector& uboBindings, - const UniformBufferBindingDescriptor& standaloneBindings) +void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindings, + uint32_t uboCount, + const UniformBufferBindingDescriptor& standaloneBindings) { if(standaloneBindings.buffer) { mImpl->mCurrentStandaloneUBOBinding = standaloneBindings; } - if(uboBindings.size() >= mImpl->mCurrentUBOBindings.size()) + if(uboCount >= mImpl->mCurrentUBOBindings.size()) { - mImpl->mCurrentUBOBindings.resize(uboBindings.size() + 1); + mImpl->mCurrentUBOBindings.resize(uboCount + 1); } - auto it = uboBindings.begin(); - for(auto i = 0u; i < uboBindings.size(); ++i) + auto it = uboBindings; + for(auto i = 0u; i < uboCount; ++i) { if(it->buffer) { @@ -455,6 +539,10 @@ void Context::ResolveBlendState() if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp) { gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp)); + if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START) + { + gl.BlendBarrier(); + } } else { @@ -510,11 +598,23 @@ void Context::ResolveUniformBuffers() void Context::ResolveStandaloneUniforms() { // Find reflection for program - const auto program = static_cast(mImpl->mNewPipeline->GetCreateInfo().programState->program); - const auto ptr = reinterpret_cast(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset; + const GLES::Program* program{nullptr}; + + if(mImpl->mNewPipeline) + { + program = static_cast(mImpl->mNewPipeline->GetCreateInfo().programState->program); + } + else if(mImpl->mCurrentPipeline) + { + program = static_cast(mImpl->mCurrentPipeline->GetCreateInfo().programState->program); + } - // Update program uniforms - program->GetImplementation()->UpdateStandaloneUniformBlock(ptr); + if(program) + { + const auto ptr = reinterpret_cast(mImpl->mCurrentStandaloneUBOBinding.buffer->GetCPUAllocatedAddress()) + mImpl->mCurrentStandaloneUBOBinding.offset; + // Update program uniforms + program->GetImplementation()->UpdateStandaloneUniformBlock(ptr); + } } void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) @@ -534,7 +634,8 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) else if(targetInfo.framebuffer) { // bind framebuffer and swap. - renderTarget.GetFramebuffer()->Bind(); + auto framebuffer = renderTarget.GetFramebuffer(); + framebuffer->Bind(); } // clear (ideally cache the setup) @@ -546,6 +647,7 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) const auto& attachments = *renderPass.GetCreateInfo().attachments; const auto& color0 = attachments[0]; GLuint mask = 0; + if(color0.loadOp == AttachmentLoadOp::CLEAR) { mask |= GL_COLOR_BUFFER_BIT; @@ -554,22 +656,24 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) // Something goes wrong here if Alpha mask is GL_TRUE ColorMask(true); - if(!mImpl->mGlStateCache.mClearColorSet || - mImpl->mGlStateCache.mClearColor.r != renderPassBegin.clearValues[0].color.r || - mImpl->mGlStateCache.mClearColor.g != renderPassBegin.clearValues[0].color.g || - mImpl->mGlStateCache.mClearColor.b != renderPassBegin.clearValues[0].color.b || - mImpl->mGlStateCache.mClearColor.a != renderPassBegin.clearValues[0].color.a) + const auto clearValues = renderPassBegin.clearValues.Ptr(); + + if(!Dali::Equals(mImpl->mGlStateCache.mClearColor.r, clearValues[0].color.r) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.g, clearValues[0].color.g) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.b, clearValues[0].color.b) || + !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) || + !mImpl->mGlStateCache.mClearColorSet) { - gl.ClearColor(renderPassBegin.clearValues[0].color.r, - renderPassBegin.clearValues[0].color.g, - renderPassBegin.clearValues[0].color.b, - renderPassBegin.clearValues[0].color.a); + gl.ClearColor(clearValues[0].color.r, + clearValues[0].color.g, + clearValues[0].color.b, + clearValues[0].color.a); mImpl->mGlStateCache.mClearColorSet = true; - mImpl->mGlStateCache.mClearColor = Vector4(renderPassBegin.clearValues[0].color.r, - renderPassBegin.clearValues[0].color.g, - renderPassBegin.clearValues[0].color.b, - renderPassBegin.clearValues[0].color.a); + mImpl->mGlStateCache.mClearColor = Vector4(clearValues[0].color.r, + clearValues[0].color.g, + clearValues[0].color.b, + clearValues[0].color.a); } } @@ -606,14 +710,28 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) mImpl->mCurrentRenderTarget = &renderTarget; } -void Context::EndRenderPass() +void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker) { if(mImpl->mCurrentRenderTarget) { - if(mImpl->mCurrentRenderTarget->GetFramebuffer()) + GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer(); + if(framebuffer) { auto& gl = *mImpl->mController.GetGL(); gl.Flush(); + + /* @todo Full dependency checking would need to store textures in Begin, and create + * fence objects here; but we're going to draw all fbos on shared context in serial, + * so no real need (yet). Might want to consider ensuring order of render passes, + * but that needs doing in the controller, and would need doing before ProcessCommandQueues. + * + * Currently up to the client to create render tasks in the right order. + */ + + /* Create fence sync objects. Other contexts can then wait on these fences before reading + * textures. + */ + dependencyChecker.AddTextures(this, framebuffer); } } } @@ -886,4 +1004,55 @@ void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline) } } +void Context::PrepareForNativeRendering() +{ + // this should be pretty much constant + auto display = eglGetCurrentDisplay(); + auto drawSurface = eglGetCurrentSurface(EGL_DRAW); + auto readSurface = eglGetCurrentSurface(EGL_READ); + auto context = eglGetCurrentContext(); + + // push the surface and context data to the impl + // It's needed to restore context + if(!mImpl->mCacheEGLGraphicsContext) + { + mImpl->mCacheDrawWriteSurface = drawSurface; + mImpl->mCacheDrawReadSurface = readSurface; + mImpl->mCacheEGLGraphicsContext = context; + } + + if(!mImpl->mNativeDrawContext) + { + EGLint configId{0u}; + EGLint size{0u}; + eglGetConfigs(display, nullptr, 0, &size); + std::vector configs; + configs.resize(size); + eglGetConfigs(display, configs.data(), configs.size(), &size); + + eglQueryContext(display, context, EGL_CONFIG_ID, &configId); + + auto version = int(mImpl->mController.GetGLESVersion()); + + std::vector attribs; + attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); + attribs.push_back(version / 10); + attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); + attribs.push_back(version % 10); + attribs.push_back(EGL_NONE); + + mImpl->mNativeDrawContext = eglCreateContext(display, configs[configId], mImpl->mController.GetSharedContext(), attribs.data()); + } + + eglMakeCurrent(display, drawSurface, readSurface, mImpl->mNativeDrawContext); +} + +void Context::RestoreFromNativeRendering() +{ + auto display = eglGetCurrentDisplay(); + + // bring back original context + eglMakeCurrent(display, mImpl->mCacheDrawWriteSurface, mImpl->mCacheDrawReadSurface, mImpl->mCacheEGLGraphicsContext); +} + } // namespace Dali::Graphics::GLES