+void Context::ColorMask(bool enabled)
+{
+ if(enabled != mImpl->mGlStateCache.mColorMask)
+ {
+ mImpl->mGlStateCache.mColorMask = enabled;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.ColorMask(enabled, enabled, enabled, enabled);
+ }
+}
+
+void Context::ClearStencilBuffer()
+{
+ ClearBuffer(GL_STENCIL_BUFFER_BIT, false);
+}
+
+void Context::ClearDepthBuffer()
+{
+ ClearBuffer(GL_DEPTH_BUFFER_BIT, false);
+}
+
+void Context::ClearBuffer(uint32_t mask, bool forceClear)
+{
+ mask = mImpl->mGlStateCache.mFrameBufferStateCache.GetClearMask(mask, forceClear, mImpl->mGlStateCache.mScissorTestEnabled);
+ if(mask > 0)
+ {
+ auto& gl = *mImpl->mController.GetGL();
+ gl.Clear(mask);
+ }
+}
+
+void Context::InvalidateDepthStencilBuffers()
+{
+ auto& gl = *mImpl->mController.GetGL();
+
+ GLenum attachments[] = {GL_DEPTH, GL_STENCIL};
+ gl.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+}
+
+void Context::SetScissorTestEnabled(bool scissorEnabled)
+{
+ if(mImpl->mGlStateCache.mScissorTestEnabled != scissorEnabled)
+ {
+ mImpl->mGlStateCache.mScissorTestEnabled = scissorEnabled;
+
+ auto& gl = *mImpl->mController.GetGL();
+ if(scissorEnabled)
+ {
+ gl.Enable(GL_SCISSOR_TEST);
+ }
+ else
+ {
+ gl.Disable(GL_SCISSOR_TEST);
+ }
+ }
+}
+
+void Context::SetStencilTestEnable(bool stencilEnable)
+{
+ if(stencilEnable != mImpl->mGlStateCache.mStencilBufferEnabled)
+ {
+ mImpl->mGlStateCache.mStencilBufferEnabled = stencilEnable;
+
+ auto& gl = *mImpl->mController.GetGL();
+ if(stencilEnable)
+ {
+ gl.Enable(GL_STENCIL_TEST);
+ }
+ else
+ {
+ gl.Disable(GL_STENCIL_TEST);
+ }
+ }
+}
+
+void Context::StencilMask(uint32_t writeMask)
+{
+ if(writeMask != mImpl->mGlStateCache.mStencilMask)
+ {
+ mImpl->mGlStateCache.mStencilMask = writeMask;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.StencilMask(writeMask);
+ }
+}
+
+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)
+ {
+ mImpl->mGlStateCache.mStencilFunc = compareOp;
+ mImpl->mGlStateCache.mStencilFuncRef = reference;
+ mImpl->mGlStateCache.mStencilFuncMask = compareMask;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.StencilFunc(GLCompareOp(compareOp).op, reference, compareMask);
+ }
+}
+
+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)
+ {
+ 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);
+ }
+}
+
+void Context::SetDepthCompareOp(Graphics::CompareOp compareOp)
+{
+ if(compareOp != mImpl->mGlStateCache.mDepthFunction)
+ {
+ mImpl->mGlStateCache.mDepthFunction = compareOp;
+ auto& gl = *mImpl->mController.GetGL();
+ gl.DepthFunc(GLCompareOp(compareOp).op);
+ }
+}
+
+void Context::SetDepthTestEnable(bool depthTestEnable)
+{
+ if(depthTestEnable != mImpl->mGlStateCache.mDepthBufferEnabled)
+ {
+ mImpl->mGlStateCache.mDepthBufferEnabled = depthTestEnable;
+
+ auto& gl = *mImpl->mController.GetGL();
+ if(depthTestEnable)
+ {
+ gl.Enable(GL_DEPTH_TEST);
+ }
+ else
+ {
+ gl.Disable(GL_DEPTH_TEST);
+ }
+ }
+}
+
+void Context::SetDepthWriteEnable(bool depthWriteEnable)
+{
+ if(depthWriteEnable != mImpl->mGlStateCache.mDepthMaskEnabled)
+ {
+ mImpl->mGlStateCache.mDepthMaskEnabled = depthWriteEnable;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.DepthMask(depthWriteEnable);
+ }
+}
+
+void Context::ActiveTexture(uint32_t textureBindingIndex)
+{
+ if(mImpl->mGlStateCache.mActiveTextureUnit != textureBindingIndex)
+ {
+ mImpl->mGlStateCache.mActiveTextureUnit = textureBindingIndex;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.ActiveTexture(GL_TEXTURE0 + textureBindingIndex);
+ }
+}
+
+void Context::BindTexture(GLenum target, BoundTextureType textureTypeId, uint32_t textureId)
+{
+ uint32_t typeId = static_cast<uint32_t>(textureTypeId);
+ if(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);
+ }
+}
+
+void Context::GenerateMipmap(GLenum target)
+{
+ auto& gl = *mImpl->mController.GetGL();
+ gl.GenerateMipmap(target);
+}
+
+void Context::BindBuffer(GLenum target, uint32_t bufferId)
+{
+ if(mImpl->mGlStateCache.mBoundArrayBufferId != bufferId)
+ {
+ mImpl->mGlStateCache.mBoundArrayBufferId = bufferId;
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.BindBuffer(target, bufferId);
+ }
+}
+
+void Context::DrawBuffers(uint32_t count, const GLenum* buffers)
+{
+ mImpl->mGlStateCache.mFrameBufferStateCache.DrawOperation(mImpl->mGlStateCache.mColorMask,
+ mImpl->mGlStateCache.DepthBufferWriteEnabled(),
+ mImpl->mGlStateCache.StencilBufferWriteEnabled());
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.DrawBuffers(count, buffers);
+}
+
+void Context::BindFrameBuffer(GLenum target, uint32_t bufferId)
+{
+ mImpl->mGlStateCache.mFrameBufferStateCache.SetCurrentFrameBuffer(bufferId);
+
+ auto& gl = *mImpl->mController.GetGL();
+ 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);
+}
+
+void Context::DeleteFramebuffers(uint32_t count, uint32_t* framebuffers)
+{
+ mImpl->mGlStateCache.mFrameBufferStateCache.FrameBuffersDeleted(count, framebuffers);
+
+ auto& gl = *mImpl->mController.GetGL();
+ gl.DeleteFramebuffers(count, framebuffers);
+}
+
+GLStateCache& Context::GetGLStateCache()
+{
+ return mImpl->mGlStateCache;
+}
+
+void Context::GlContextCreated()
+{
+ if(!mImpl->mGlContextCreated)
+ {
+ mImpl->mGlContextCreated = true;
+
+ // Set the initial GL state
+ mImpl->InitializeGlState();
+ }
+}
+
+void Context::GlContextDestroyed()
+{
+ mImpl->mGlContextCreated = false;
+}
+
+void Context::InvalidateCachedPipeline(GLES::Pipeline* pipeline)
+{
+ // Since the pipeline is deleted, invalidate the cached pipeline.
+ if(mImpl->mCurrentPipeline == &pipeline->GetPipeline())
+ {
+ mImpl->mCurrentPipeline = nullptr;
+ }
+}
+
+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<EGLConfig> 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<EGLint> 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);
+}
+