// Copyright 2022 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "CompositorGl.h" #include "BorrowedImageGl.h" #include "DebugGl.h" #include "DisplaySurfaceGl.h" #include "OpenGLESDispatch/DispatchTables.h" #include "TextureDraw.h" #include "host-common/GfxstreamFatalError.h" #include "host-common/misc.h" namespace gfxstream { namespace gl { namespace { const BorrowedImageInfoGl* getInfoOrAbort(const std::unique_ptr& info) { auto imageGl = static_cast(info.get()); if (imageGl != nullptr) { return imageGl; } GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER)) << "CompositorGl did not find BorrowedImageInfoGl"; return nullptr; } std::shared_future getCompletedFuture() { std::shared_future completedFuture = std::async(std::launch::deferred, [] {}).share(); completedFuture.wait(); return completedFuture; } } // namespace CompositorGl::CompositorGl(TextureDraw* textureDraw) : m_textureDraw(textureDraw) {} CompositorGl::~CompositorGl() {} void CompositorGl::bindToSurfaceImpl(gfxstream::DisplaySurface* surface) { const auto* surfaceGl = static_cast(surface->getImpl()); std::optional contextBind; if (mUseBoundSurfaceContext) { contextBind.emplace(surfaceGl->getContextHelper()); if (!contextBind->isOk()) { return; } } s_gles2.glGenFramebuffers(1, &m_composeFbo); } void CompositorGl::unbindFromSurfaceImpl() { const auto* surface = getBoundSurface(); if (!surface) { return; } const auto* surfaceGl = static_cast(surface->getImpl()); std::optional contextBind; if (mUseBoundSurfaceContext) { contextBind.emplace(surfaceGl->getContextHelper()); if (!contextBind->isOk()) { return; } } if (m_composeFbo) { s_gles2.glDeleteFramebuffers(1, &m_composeFbo); m_composeFbo = 0; } } Compositor::CompositionFinishedWaitable CompositorGl::compose( const CompositionRequest& composeRequest) { const auto* surface = getBoundSurface(); if (!surface) { return getCompletedFuture(); } const auto* surfaceGl = static_cast(surface->getImpl()); std::optional contextBind; if (mUseBoundSurfaceContext) { contextBind.emplace(surfaceGl->getContextHelper()); if (!contextBind->isOk()) { return getCompletedFuture(); } } const auto* targetImage = getInfoOrAbort(composeRequest.target); const uint32_t targetWidth = targetImage->width; const uint32_t targetHeight = targetImage->height; const GLuint targetTexture = targetImage->texture; GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() into texture:%d", targetTexture); GLint restoredViewport[4] = {0, 0, 0, 0}; s_gles2.glGetIntegerv(GL_VIEWPORT, restoredViewport); s_gles2.glViewport(0, 0, targetWidth, targetHeight); s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, m_composeFbo); s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, targetTexture, /*level=*/0); m_textureDraw->prepareForDrawLayer(); for (const CompositionRequestLayer& layer : composeRequest.layers) { if (layer.props.composeMode == HWC2_COMPOSITION_DEVICE) { const BorrowedImageInfoGl* layerImage = getInfoOrAbort(layer.source); const GLuint layerTexture = layerImage->texture; GL_SCOPED_DEBUG_GROUP("CompositorGl::compose() from layer texture:%d", layerTexture); m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, layerImage->width, layerImage->height, layerTexture); } else { m_textureDraw->drawLayer(layer.props, targetWidth, targetHeight, 1, 1, 0); } } s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); s_gles2.glViewport(restoredViewport[0], restoredViewport[1], restoredViewport[2], restoredViewport[3]); m_textureDraw->cleanupForDrawLayer(); targetImage->onCommandsIssued(); // Note: This should be returning a future when all work, both CPU and GPU, is // complete but is currently only returning a future when all CPU work is completed. // In the future, CompositionFinishedWaitable should be replaced with something that // passes along a GL fence or VK fence. return getCompletedFuture(); } } // namespace gl } // namespace gfxstream