X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fgraphics%2Fgles-impl%2Fgles-context.cpp;h=b7e2b5edbc5b21a907433bc87338958257c4c6d1;hb=3c26763ff93197deeaba6129aa44cb66505012c3;hp=1d981bc781917d92b246ab4484f6c3050245e1e2;hpb=0231b1cb39eeae17854dd08944e0c0a87d5be346;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..b7e2b5e 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) 2024 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,13 +34,15 @@ #include #include #include +#include namespace Dali::Graphics::GLES { struct Context::Impl { - explicit Impl(EglGraphicsController& controller) - : mController(controller) + explicit Impl(EglGraphicsController& controller, Integration::GlAbstraction* gl) + : mController(controller), + mGL(gl) { } @@ -53,27 +55,64 @@ 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) { - auto& gl = *mController.GetGL(); - auto iter = mProgramVAOMap.find(program); + // Calculate attributes location hash unordered. + std::size_t hash = 0; + for(const auto& attr : vertexInputState.attributes) + { + // Make unordered hash value by location. + // Note : This hash function varified for locations only under < 20. + std::size_t salt = attr.location + 1; + hash += salt << (sizeof(std::size_t) * 6); + salt *= salt; + salt ^= attr.location; + hash += salt << (sizeof(std::size_t) * 4); + salt *= salt; + hash += salt; + } + + auto* gl = GetGL(); + if(!gl) // early out if no gl + { + return; + } + + if(DALI_UNLIKELY(!mDiscardedVAOList.empty())) + { + gl->DeleteVertexArrays(static_cast(mDiscardedVAOList.size()), mDiscardedVAOList.data()); + mDiscardedVAOList.clear(); + } + + 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; + gl->GenVertexArrays(1, &vao); + gl->BindVertexArray(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); + gl->EnableVertexAttribArray(attr.location); } mProgramVAOCurrentState = vao; @@ -84,42 +123,48 @@ struct Context::Impl */ void InitializeGlState() { - auto& gl = *mController.GetGL(); + auto* gl = GetGL(); + if(gl) + { + mGlStateCache.mClearColorSet = false; + mGlStateCache.mColorMask = true; + mGlStateCache.mStencilMask = 0xFF; + mGlStateCache.mBlendEnabled = false; + mGlStateCache.mDepthBufferEnabled = false; + mGlStateCache.mDepthMaskEnabled = false; + mGlStateCache.mScissorTestEnabled = false; + mGlStateCache.mStencilBufferEnabled = false; - mGlStateCache.mClearColorSet = false; - mGlStateCache.mColorMask = true; - mGlStateCache.mStencilMask = 0xFF; - mGlStateCache.mBlendEnabled = false; - mGlStateCache.mDepthBufferEnabled = false; - mGlStateCache.mDepthMaskEnabled = false; - mGlStateCache.mScissorTestEnabled = false; - mGlStateCache.mStencilBufferEnabled = false; + gl->Disable(GL_DITHER); - gl.Disable(GL_DITHER); + mGlStateCache.mBoundArrayBufferId = 0; + mGlStateCache.mBoundElementArrayBufferId = 0; + mGlStateCache.mActiveTextureUnit = 0; - mGlStateCache.mBoundArrayBufferId = 0; - mGlStateCache.mBoundElementArrayBufferId = 0; - mGlStateCache.mActiveTextureUnit = 0; + mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE; + mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO; + mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE; + mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO; - mGlStateCache.mBlendFuncSeparateSrcRGB = BlendFactor::ONE; - mGlStateCache.mBlendFuncSeparateDstRGB = BlendFactor::ZERO; - mGlStateCache.mBlendFuncSeparateSrcAlpha = BlendFactor::ONE; - mGlStateCache.mBlendFuncSeparateDstAlpha = BlendFactor::ZERO; + // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes + mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD; + mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD; - // initial state is GL_FUNC_ADD for both RGB and Alpha blend modes - mGlStateCache.mBlendEquationSeparateModeRGB = BlendOp::ADD; - mGlStateCache.mBlendEquationSeparateModeAlpha = BlendOp::ADD; + mGlStateCache.mCullFaceMode = CullMode::NONE; // By default cullface is disabled, front face is set to CCW and cull face is set to back - mGlStateCache.mCullFaceMode = CullMode::NONE; //By default cullface is disabled, front face is set to CCW and cull face is set to back + // Initialze vertex attribute cache + memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState)); + memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState)); - //Initialze vertex attribute cache - memset(&mGlStateCache.mVertexAttributeCachedState, 0, sizeof(mGlStateCache.mVertexAttributeCachedState)); - memset(&mGlStateCache.mVertexAttributeCurrentState, 0, sizeof(mGlStateCache.mVertexAttributeCurrentState)); + // Initialize bound 2d texture cache + memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId)); - //Initialize bound 2d texture cache - memset(&mGlStateCache.mBoundTextureId, 0, sizeof(mGlStateCache.mBoundTextureId)); + mGlStateCache.mFrameBufferStateCache.Reset(); - 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); + } } /** @@ -127,23 +172,25 @@ struct Context::Impl */ void FlushVertexAttributeLocations() { - auto& gl = *mController.GetGL(); - - for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i) + auto* gl = GetGL(); + if(gl) { - // see if the cached state is different to the actual state - if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i]) + for(unsigned int i = 0; i < MAX_ATTRIBUTE_CACHE_SIZE; ++i) { - // it's different so make the change to the driver and update the cached state - mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i]; - - if(mGlStateCache.mVertexAttributeCurrentState[i]) + // see if the cached state is different to the actual state + if(mGlStateCache.mVertexAttributeCurrentState[i] != mGlStateCache.mVertexAttributeCachedState[i]) { - gl.EnableVertexAttribArray(i); - } - else - { - gl.DisableVertexAttribArray(i); + // it's different so make the change to the driver and update the cached state + mGlStateCache.mVertexAttributeCurrentState[i] = mGlStateCache.mVertexAttributeCachedState[i]; + + if(mGlStateCache.mVertexAttributeCurrentState[i]) + { + gl->EnableVertexAttribArray(i); + } + else + { + gl->DisableVertexAttribArray(i); + } } } } @@ -157,29 +204,41 @@ struct Context::Impl */ void SetVertexAttributeLocation(unsigned int location, bool state) { - auto& gl = *mController.GetGL(); - - if(location >= MAX_ATTRIBUTE_CACHE_SIZE) + auto* gl = GetGL(); + if(gl) { - // not cached, make the gl call through context - if(state) + if(location >= MAX_ATTRIBUTE_CACHE_SIZE) { - gl.EnableVertexAttribArray(location); + // not cached, make the gl call through context + if(state) + { + gl->EnableVertexAttribArray(location); + } + else + { + gl->DisableVertexAttribArray(location); + } } else { - gl.DisableVertexAttribArray(location); + // set the cached state, it will be set at the next draw call + // if it's different from the current driver state + mGlStateCache.mVertexAttributeCachedState[location] = state; } } - else - { - // set the cached state, it will be set at the next draw call - // if it's different from the current driver state - mGlStateCache.mVertexAttributeCachedState[location] = state; - } } - EglGraphicsController& mController; + /** + * Get the pointer to the GL implementation + * @return The GL implementation, nullptr if the context has not been created or shutting down + */ + [[nodiscard]] inline Integration::GlAbstraction* GetGL() const + { + return mGlContextCreated ? mGL : nullptr; + } + + EglGraphicsController& mController; + Integration::GlAbstraction* mGL{nullptr}; const GLES::PipelineImpl* mCurrentPipeline{nullptr}; ///< Currently bound pipeline const GLES::PipelineImpl* mNewPipeline{nullptr}; ///< New pipeline to be set on flush @@ -206,11 +265,13 @@ 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 + std::vector mDiscardedVAOList{}; - 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 @@ -219,9 +280,9 @@ struct Context::Impl EGLContext mCacheEGLGraphicsContext{0u}; ///< cached window context }; -Context::Context(EglGraphicsController& controller) +Context::Context(EglGraphicsController& controller, Integration::GlAbstraction* glAbstraction) { - mImpl = std::make_unique(controller); + mImpl = std::make_unique(controller, glAbstraction); } Context::~Context() @@ -236,7 +297,11 @@ Context::~Context() void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES::TextureDependencyChecker& dependencyChecker) { - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } static const bool hasGLES3(mImpl->mController.GetGLESVersion() >= GLESVersion::GLES_30); @@ -265,11 +330,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 +356,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) + // for each attribute bind vertices, unless the pipeline+buffer is the same + if(programChanged || mImpl->mVertexBuffersChanged) { - mImpl->BindProgramVAO(static_cast(pipelineState.programState->program)->GetImplementation(), *vertexInputState); - } - - for(const auto& attr : vertexInputState->attributes) - { - // 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 +482,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 +513,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 +570,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 +605,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 +617,7 @@ void Context::BindUniformBuffers(const UniformBufferBindingDescriptor* uboBindin { mImpl->mCurrentUBOBindings[i] = *it; } + ++it; } } @@ -485,14 +632,18 @@ void Context::ResolveBlendState() return; } - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(!currentBlendState || currentBlendState->blendEnable != newBlendState->blendEnable) { if(newBlendState->blendEnable != mImpl->mGlStateCache.mBlendEnabled) { mImpl->mGlStateCache.mBlendEnabled = newBlendState->blendEnable; - newBlendState->blendEnable ? gl.Enable(GL_BLEND) : gl.Disable(GL_BLEND); + newBlendState->blendEnable ? gl->Enable(GL_BLEND) : gl->Disable(GL_BLEND); } } @@ -524,11 +675,11 @@ void Context::ResolveBlendState() if(newSrcRGB == newSrcAlpha && newDstRGB == newDstAlpha) { - gl.BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB)); + gl->BlendFunc(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB)); } else { - gl.BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha)); + gl->BlendFuncSeparate(GLBlendFunc(newSrcRGB), GLBlendFunc(newDstRGB), GLBlendFunc(newSrcAlpha), GLBlendFunc(newDstAlpha)); } } } @@ -545,15 +696,15 @@ void Context::ResolveBlendState() if(newBlendState->colorBlendOp == newBlendState->alphaBlendOp) { - gl.BlendEquation(GLBlendOp(newBlendState->colorBlendOp)); + gl->BlendEquation(GLBlendOp(newBlendState->colorBlendOp)); if(newBlendState->colorBlendOp >= Graphics::ADVANCED_BLEND_OPTIONS_START) { - gl.BlendBarrier(); + gl->BlendBarrier(); } } else { - gl.BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp)); + gl->BlendEquationSeparate(GLBlendOp(newBlendState->colorBlendOp), GLBlendOp(newBlendState->alphaBlendOp)); } } } @@ -570,7 +721,11 @@ void Context::ResolveRasterizationState() return; } - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(!currentRasterizationState || currentRasterizationState->cullMode != newRasterizationState->cullMode) @@ -580,12 +735,12 @@ void Context::ResolveRasterizationState() mImpl->mGlStateCache.mCullFaceMode = newRasterizationState->cullMode; if(newRasterizationState->cullMode == CullMode::NONE) { - gl.Disable(GL_CULL_FACE); + gl->Disable(GL_CULL_FACE); } else { - gl.Enable(GL_CULL_FACE); - gl.CullFace(GLCullMode(newRasterizationState->cullMode)); + gl->Enable(GL_CULL_FACE); + gl->CullFace(GLCullMode(newRasterizationState->cullMode)); } } } @@ -600,6 +755,22 @@ void Context::ResolveUniformBuffers() { ResolveStandaloneUniforms(); } + if(!mImpl->mCurrentUBOBindings.empty()) + { + ResolveGpuUniformBuffers(); + } +} + +void Context::ResolveGpuUniformBuffers() +{ + if(auto* gl = mImpl->GetGL()) + { + auto i = 0u; + for(auto& binding : mImpl->mCurrentUBOBindings) + { + gl->BindBufferRange(GL_UNIFORM_BUFFER, i++, binding.buffer->GetGLBuffer(), GLintptr(binding.offset), GLintptr(binding.dataSize)); + } + } } void Context::ResolveStandaloneUniforms() @@ -631,7 +802,11 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) const auto& targetInfo = renderTarget.GetCreateInfo(); - auto& gl = *mImpl->mController.GetGL(); + auto* gl = mImpl->GetGL(); + if(!gl) // Early out if no gl + { + return; + } if(targetInfo.surface) { @@ -671,10 +846,10 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) !Dali::Equals(mImpl->mGlStateCache.mClearColor.a, clearValues[0].color.a) || !mImpl->mGlStateCache.mClearColorSet) { - gl.ClearColor(clearValues[0].color.r, - clearValues[0].color.g, - clearValues[0].color.b, - 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(clearValues[0].color.r, @@ -693,7 +868,7 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) if(!mImpl->mGlStateCache.mDepthMaskEnabled) { mImpl->mGlStateCache.mDepthMaskEnabled = true; - gl.DepthMask(true); + gl->DepthMask(true); } mask |= GL_DEPTH_BUFFER_BIT; } @@ -702,14 +877,14 @@ void Context::BeginRenderPass(const BeginRenderPassDescriptor& renderPassBegin) if(mImpl->mGlStateCache.mStencilMask != 0xFF) { mImpl->mGlStateCache.mStencilMask = 0xFF; - gl.StencilMask(0xFF); + gl->StencilMask(0xFF); } mask |= GL_STENCIL_BUFFER_BIT; } } SetScissorTestEnabled(true); - gl.Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height); + gl->Scissor(renderPassBegin.renderArea.x, renderPassBegin.renderArea.y, renderPassBegin.renderArea.width, renderPassBegin.renderArea.height); ClearBuffer(mask, true); SetScissorTestEnabled(false); @@ -722,10 +897,10 @@ void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker) if(mImpl->mCurrentRenderTarget) { GLES::Framebuffer* framebuffer = mImpl->mCurrentRenderTarget->GetFramebuffer(); - if(framebuffer) + auto* gl = mImpl->GetGL(); + if(framebuffer && gl) { - auto& gl = *mImpl->mController.GetGL(); - gl.Flush(); + 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, @@ -746,16 +921,16 @@ void Context::EndRenderPass(GLES::TextureDependencyChecker& dependencyChecker) void Context::ClearState() { mImpl->mCurrentTextureBindings.clear(); + mImpl->mCurrentUBOBindings.clear(); } void Context::ColorMask(bool enabled) { - if(enabled != mImpl->mGlStateCache.mColorMask) + auto* gl = mImpl->GetGL(); + if(gl && enabled != mImpl->mGlStateCache.mColorMask) { mImpl->mGlStateCache.mColorMask = enabled; - - auto& gl = *mImpl->mController.GetGL(); - gl.ColorMask(enabled, enabled, enabled, enabled); + gl->ColorMask(enabled, enabled, enabled, enabled); } } @@ -771,66 +946,67 @@ void Context::ClearDepthBuffer() void Context::ClearBuffer(uint32_t mask, bool forceClear) { - mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled); - if(mask > 0) + mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled); + auto* gl = mImpl->GetGL(); + if(mask > 0 && gl) { - auto& gl = *mImpl->mController.GetGL(); - gl.Clear(mask); + gl->Clear(mask); } } void Context::InvalidateDepthStencilBuffers() { - auto& gl = *mImpl->mController.GetGL(); - - GLenum attachments[] = {GL_DEPTH, GL_STENCIL}; - gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); + if(auto* gl = mImpl->GetGL()) + { + GLenum attachments[] = {GL_DEPTH, GL_STENCIL}; + gl->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); + } } void Context::SetScissorTestEnabled(bool scissorEnabled) { - if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled) { mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled; - auto& gl = *mImpl->mController.GetGL(); if(scissorEnabled) { - gl.Enable(GL_SCISSOR_TEST); + gl->Enable(GL_SCISSOR_TEST); } else { - gl.Disable(GL_SCISSOR_TEST); + gl->Disable(GL_SCISSOR_TEST); } } } void Context::SetStencilTestEnable(bool stencilEnable) { - if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled) + auto* gl = mImpl->GetGL(); + if(gl && stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled) { mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable; - auto& gl = *mImpl->mController.GetGL(); if(stencilEnable) { - gl.Enable(GL_STENCIL_TEST); + gl->Enable(GL_STENCIL_TEST); } else { - gl.Disable(GL_STENCIL_TEST); + gl->Disable(GL_STENCIL_TEST); } } } void Context::StencilMask(uint32_t writeMask) { - if(writeMask != mImpl->mGlStateCache.mStencilMask) + auto* gl = mImpl->GetGL(); + if(gl && writeMask != mImpl->mGlStateCache.mStencilMask) { mImpl->mGlStateCache.mStencilMask = writeMask; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilMask(writeMask); + gl->StencilMask(writeMask); } } @@ -838,16 +1014,17 @@ void Context::StencilFunc(Graphics::CompareOp compareOp, uint32_t reference, uint32_t compareMask) { - if(compareOp != mImpl->mGlStateCache.mStencilFunc || - reference != mImpl->mGlStateCache.mStencilFuncRef || - compareMask != mImpl->mGlStateCache.mStencilFuncMask) + auto* gl = mImpl->GetGL(); + if(gl && + (compareOp != mImpl->mGlStateCache.mStencilFunc || + reference != mImpl->mGlStateCache.mStencilFuncRef || + compareMask != mImpl->mGlStateCache.mStencilFuncMask)) { mImpl->mGlStateCache.mStencilFunc = compareOp; mImpl->mGlStateCache.mStencilFuncRef = reference; mImpl->mGlStateCache.mStencilFuncMask = compareMask; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask); + gl->StencilFunc(GLCompareOp(compareOp).op, reference, compareMask); } } @@ -855,130 +1032,163 @@ void Context::StencilOp(Graphics::StencilOp failOp, Graphics::StencilOp depthFailOp, Graphics::StencilOp passOp) { - if(failOp != mImpl->mGlStateCache.mStencilOpFail || - depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail || - passOp != mImpl->mGlStateCache.mStencilOpDepthPass) + auto* gl = mImpl->GetGL(); + if(gl && + (failOp != mImpl->mGlStateCache.mStencilOpFail || + depthFailOp != mImpl->mGlStateCache.mStencilOpDepthFail || + passOp != mImpl->mGlStateCache.mStencilOpDepthPass)) { mImpl->mGlStateCache.mStencilOpFail = failOp; mImpl->mGlStateCache.mStencilOpDepthFail = depthFailOp; mImpl->mGlStateCache.mStencilOpDepthPass = passOp; - auto& gl = *mImpl->mController.GetGL(); - gl.StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op); + gl->StencilOp(GLStencilOp(failOp).op, GLStencilOp(depthFailOp).op, GLStencilOp(passOp).op); } } void Context::SetDepthCompareOp(Graphics::CompareOp compareOp) { - if(compareOp != mImpl->mGlStateCache.mDepthFunction) + auto* gl = mImpl->GetGL(); + if(gl && compareOp != mImpl->mGlStateCache.mDepthFunction) { mImpl->mGlStateCache.mDepthFunction = compareOp; - auto& gl = *mImpl->mController.GetGL(); - gl.DepthFunc(GLCompareOp(compareOp).op); + + gl->DepthFunc(GLCompareOp(compareOp).op); } } void Context::SetDepthTestEnable(bool depthTestEnable) { - if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled) + auto* gl = mImpl->GetGL(); + if(gl && depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled) { mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable; - auto& gl = *mImpl->mController.GetGL(); if(depthTestEnable) { - gl.Enable(GL_DEPTH_TEST); + gl->Enable(GL_DEPTH_TEST); } else { - gl.Disable(GL_DEPTH_TEST); + gl->Disable(GL_DEPTH_TEST); } } } void Context::SetDepthWriteEnable(bool depthWriteEnable) { - if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled) + auto* gl = mImpl->GetGL(); + if(gl && depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled) { mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable; - auto& gl = *mImpl->mController.GetGL(); - gl.DepthMask(depthWriteEnable); + gl->DepthMask(depthWriteEnable); } } void Context::ActiveTexture(uint32_t textureBindingIndex) { - if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex) { mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex; - auto& gl = *mImpl->mController.GetGL(); - gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex); + gl->ActiveTexture(GL_TEXTURE0 + textureBindingIndex); } } void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId) { uint32_t typeId = static_cast(textureTypeId); - if(mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId) + auto* gl = mImpl->GetGL(); + if(gl && mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] != textureId) { mImpl->mGlStateCache.mBoundTextureId[mImpl->mGlStateCache.mActiveTextureUnit][typeId] = textureId; - auto& gl = *mImpl->mController.GetGL(); - gl.BindTexture(target, textureId); + gl->BindTexture(target, textureId); } } void Context::GenerateMipmap(GLenum target) { - auto& gl = *mImpl->mController.GetGL(); - gl.GenerateMipmap(target); + if(auto* gl = mImpl->GetGL()) + { + gl->GenerateMipmap(target); + } } -void Context::BindBuffer(GLenum target, uint32_t bufferId) +bool Context::BindBuffer(GLenum target, uint32_t bufferId) { - if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId) + if(auto* gl = mImpl->GetGL()) { - mImpl->mGlStateCache.mBoundArrayBufferId = bufferId; + switch(target) + { + 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; + } + } - auto& gl = *mImpl->mController.GetGL(); - gl.BindBuffer(target, bufferId); + // Cache miss. Bind buffer. + gl->BindBuffer(target, bufferId); + return true; } + return false; } void Context::DrawBuffers(uint32_t count, const GLenum* buffers) { - mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, - mImpl->mGlStateCache.DepthBufferWriteEnabled(), - mImpl->mGlStateCache.StencilBufferWriteEnabled()); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask, + mImpl->mGlStateCache.DepthBufferWriteEnabled(), + mImpl->mGlStateCache.StencilBufferWriteEnabled()); - auto& gl = *mImpl->mController.GetGL(); - gl.DrawBuffers(count, buffers); + gl->DrawBuffers(count, buffers); + } } void Context::BindFrameBuffer(GLenum target, uint32_t bufferId) { - mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId); - auto& gl = *mImpl->mController.GetGL(); - gl.BindFramebuffer(target, bufferId); + gl->BindFramebuffer(target, bufferId); + } } void Context::GenFramebuffers(uint32_t count, uint32_t* framebuffers) { - auto& gl = *mImpl->mController.GetGL(); - gl.GenFramebuffers(count, framebuffers); - - mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers); + if(auto* gl = mImpl->GetGL()) + { + gl->GenFramebuffers(count, framebuffers); + mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersCreated(count, framebuffers); + } } void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers) { - mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers); + if(auto* gl = mImpl->GetGL()) + { + mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers); - auto& gl = *mImpl->mController.GetGL(); - gl.DeleteFramebuffers(count, framebuffers); + gl->DeleteFramebuffers(count, framebuffers); + } } GLStateCache& Context::GetGLStateCache() @@ -1009,6 +1219,40 @@ void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline) { mImpl->mCurrentPipeline = nullptr; } + + // Remove cached VAO map + auto* gl = mImpl->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; + + // Do not delete vao now. (Since Context might not be current.) + mImpl->mDiscardedVAOList.emplace_back(vao); + if(mImpl->mProgramVAOCurrentState == vao) + { + mImpl->mProgramVAOCurrentState = 0u; + } + } + + // Clear cached Vertex buffer. + mImpl->mCurrentVertexBufferBindings.clear(); + + mImpl->mProgramVAOMap.erase(iter); + } + } + } + } } void Context::PrepareForNativeRendering()