/* * Copyright 2013 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. */ #include "VirtualDisplaySurface.h" #include "HWComposer.h" // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const String8& name) : mHwc(hwc), mDisplayId(dispId), mName(name) { if (mDisplayId >= 0) { mInterposer = new BufferQueueInterposer(sink, name); mSourceProducer = mInterposer; } else { mSourceProducer = sink; } } VirtualDisplaySurface::~VirtualDisplaySurface() { if (mAcquiredBuffer != NULL) { status_t result = mInterposer->releaseBuffer(Fence::NO_FENCE); ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " "failed to release buffer: %d", mName.string(), result); } } sp VirtualDisplaySurface::getIGraphicBufferProducer() const { return mSourceProducer; } status_t VirtualDisplaySurface::compositionComplete() { return NO_ERROR; } status_t VirtualDisplaySurface::advanceFrame() { if (mInterposer == NULL) return NO_ERROR; Mutex::Autolock lock(mMutex); status_t result = NO_ERROR; if (mAcquiredBuffer != NULL) { ALOGE("VirtualDisplaySurface \"%s\": " "advanceFrame called twice without onFrameCommitted", mName.string()); return INVALID_OPERATION; } sp fence; result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) { result = mInterposer->pullEmptyBuffer(); if (result != NO_ERROR) return result; result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence); } if (result != NO_ERROR) return result; result = mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer); if (result == NO_ERROR) { result = mHwc.setOutputBuffer(mDisplayId, fence, mAcquiredBuffer); } return result; } void VirtualDisplaySurface::onFrameCommitted() { if (mInterposer == NULL) return; Mutex::Autolock lock(mMutex); if (mAcquiredBuffer != NULL) { // fbFence signals when reads from the framebuffer are finished // outFence signals when writes to the output buffer are finished // It's unlikely that there will be an implementation where fbFence // signals after outFence (in fact they'll typically be the same // sync_pt), but just to be pedantic we merge them so the sink will // be sure to wait until both are complete. sp fbFence = mHwc.getAndResetReleaseFence(mDisplayId); sp outFence = mHwc.getLastRetireFence(mDisplayId); sp fence = Fence::merge( String8::format("HWC done: %.21s", mName.string()), fbFence, outFence); status_t result = mInterposer->releaseBuffer(fence); ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": " "failed to release buffer: %d", mName.string(), result); mAcquiredBuffer.clear(); } } void VirtualDisplaySurface::dump(String8& result) const { } // --------------------------------------------------------------------------- } // namespace android // ---------------------------------------------------------------------------