blob: f21b96454a2acf99296982e209c766e1f1e1427b [file]
/*
**
** Copyright 2012 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 express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
// #define LOG_NDEBUG 0
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <log/log.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
#include "../SurfaceFlinger.h"
#include "FramebufferSurface.h"
#include "HWComposer.h"
#include "HwcSlotTracker.h"
#include "MutexUtils.h"
namespace android {
using ui::Dataspace;
FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
const ui::Size& size, const ui::Size& maxSize)
: mDisplayId(displayId), mMaxSize(maxSize), mLimitedSize(limitSize(size)), mHwc(hwc) {
ALOGV("Creating for display %s", to_string(displayId).c_str());
std::tie(mRendererConsumer, mRendererSurface) = BufferItemConsumer::create(
GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
mRendererConsumer->setName(String8("FramebufferSurface"));
mRendererConsumer->setDefaultBufferSize(mLimitedSize.width, mLimitedSize.height);
mRendererConsumer->setMaxAcquiredBufferCount(SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
}
void FramebufferSurface::onFirstRef() {
mRendererConsumer->setBufferFreedListener(
wp<BufferItemConsumer::BufferFreedListener>::fromExisting(this));
}
void FramebufferSurface::onBufferFreed(const sp<GraphicBuffer>& graphicBuffer) {
Mutex::Autolock lock(mMutex);
onBufferFreedLocked(graphicBuffer);
}
void FramebufferSurface::onBufferFreedLocked(const sp<GraphicBuffer>& graphicBuffer) {
mHwcSlotTracker.remove(graphicBuffer);
}
void FramebufferSurface::resizeBuffers(const ui::Size& newSize) {
const auto limitedSize = limitSize(newSize);
mRendererConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
}
status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
return NO_ERROR;
}
status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) {
return NO_ERROR;
}
status_t FramebufferSurface::advanceFrame(float hdrSdrRatio) {
Mutex::Autolock lock(mMutex);
BufferItem item;
status_t err = mRendererConsumer->acquireBuffer(&item, 0, /*waitForFence*/ false,
[&](const sp<GraphicBuffer>& buffer) {
ASSERT_MUTEX(mMutex);
onBufferFreedLocked(buffer);
});
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
mDataspace = Dataspace::UNKNOWN;
return NO_ERROR;
} else if (err != NO_ERROR) {
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
mDataspace = Dataspace::UNKNOWN;
return err;
}
if (mFrameData && mFrameData->mBuffer != item.mGraphicBuffer) {
mPreviousFrameData.swap(mFrameData);
}
mFrameData = {item.mGraphicBuffer, item.mFence};
mDataspace = static_cast<Dataspace>(item.mDataSpace);
// If HWC hasn't seen the buffer before, or the buffer has changed, send it to HWC. Otherwise,
// all we need is the slot itself.
auto [requiresRefresh, hwcSlot] = mHwcSlotTracker.getSlot(mFrameData->mBuffer);
sp<GraphicBuffer> hwcBuffer = requiresRefresh ? mFrameData->mBuffer : nullptr;
status_t result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFrameData->mFence, hwcBuffer,
mDataspace, hdrSdrRatio);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %s (%d)", strerror(-result), result);
return result;
}
return NO_ERROR;
}
void FramebufferSurface::onFrameCommitted() {
Mutex::Autolock lock(mMutex);
// We only release the frame once an entire new frame has replaced it. This is because the frame
// will be alive in the display hardware for panel refreshes until another has replaced it.
if (mPreviousFrameData) {
sp<Fence> fence =
Fence::merge("FramebufferSurface-Acquire+Present", mPreviousFrameData->mFence,
mHwc.getPresentFence(mDisplayId));
status_t result = mRendererConsumer->releaseBuffer(mPreviousFrameData->mBuffer, fence,
[&](const sp<GraphicBuffer>& buffer) {
ASSERT_MUTEX(mMutex);
onBufferFreedLocked(buffer);
});
ALOGE_IF(result != NO_ERROR,
"onFrameCommitted: error releasing buffer:"
" %s (%d)",
strerror(-result), result);
mPreviousFrameData.reset();
}
}
ui::Size FramebufferSurface::limitSize(const ui::Size& size) {
return limitSizeInternal(size, mMaxSize);
}
ui::Size FramebufferSurface::limitSizeInternal(const ui::Size& size, const ui::Size& maxSize) {
ui::Size limitedSize = size;
bool wasLimited = false;
if (size.width > maxSize.width && maxSize.width != 0) {
const float aspectRatio = static_cast<float>(size.width) / size.height;
limitedSize.height = maxSize.width / aspectRatio;
limitedSize.width = maxSize.width;
wasLimited = true;
}
if (limitedSize.height > maxSize.height && maxSize.height != 0) {
const float aspectRatio = static_cast<float>(size.width) / size.height;
limitedSize.height = maxSize.height;
limitedSize.width = maxSize.height * aspectRatio;
wasLimited = true;
}
ALOGI_IF(wasLimited, "Framebuffer size has been limited to [%dx%d] from [%dx%d]",
limitedSize.width, limitedSize.height, size.width, size.height);
return limitedSize;
}
void FramebufferSurface::dumpAsString(String8& result) const {
Mutex::Autolock lock(mMutex);
result.append(" FramebufferSurface\n");
result.appendFormat(" mDataspace=%s (%d)\n",
dataspaceDetails(static_cast<android_dataspace>(mDataspace)).c_str(),
mDataspace);
mRendererConsumer->dumpState(result);
}
const sp<Fence>& FramebufferSurface::getClientTargetAcquireFence() const {
return mFrameData ? mFrameData->mFence : Fence::NO_FENCE;
}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"