blob: 9ffccfb4d340f38298c61ea5354bf70b2248f2cc [file] [log] [blame]
Stan Iliev564ca3e2018-09-04 22:00:00 +00001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ImageConsumer.h"
18#include <gui/BufferQueue.h>
19#include "Properties.h"
20#include "SurfaceTexture.h"
21#include "renderstate/RenderState.h"
22#include "renderthread/EglManager.h"
23#include "renderthread/RenderThread.h"
24#include "renderthread/VulkanManager.h"
25
26// Macro for including the SurfaceTexture name in log messages
27#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
28
29namespace android {
30
31void ImageConsumer::onFreeBufferLocked(int slotIndex) {
32 mImageSlots[slotIndex].mImage.reset();
33}
34
35void ImageConsumer::onAcquireBufferLocked(BufferItem* item) {
36 // If item->mGraphicBuffer is not null, this buffer has not been acquired
37 // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage.
38 if (item->mGraphicBuffer != nullptr) {
39 mImageSlots[item->mSlot].mImage.reset();
40 }
41}
42
43void ImageConsumer::onReleaseBufferLocked(int buf) {
44 mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
45}
46
47void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) {
48 if (!mImage.get()) {
49 mImage = graphicBuffer.get()
50 ? SkImage::MakeFromAHardwareBuffer(
51 reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
52 kPremul_SkAlphaType)
53 : nullptr;
54 }
55}
56
57sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
58 uirenderer::RenderState& renderState) {
59 BufferItem item;
60 status_t err;
61 err = st.acquireBufferLocked(&item, 0);
62 if (err != OK) {
63 if (err != BufferQueue::NO_BUFFER_AVAILABLE) {
64 IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
65 } else {
66 int slot = st.mCurrentTexture;
67 if (slot != BufferItem::INVALID_BUFFER_SLOT) {
68 *queueEmpty = true;
69 mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer);
70 return mImageSlots[slot].mImage;
71 }
72 }
73 return nullptr;
74 }
75
76 int slot = item.mSlot;
77 if (item.mFence->isValid()) {
78 // Wait on the producer fence for the buffer to be ready.
79 if (uirenderer::Properties::getRenderPipelineType() ==
80 uirenderer::RenderPipelineType::SkiaGL) {
81 err = renderState.getRenderThread().eglManager().fenceWait(item.mFence);
82 } else {
83 err = renderState.getRenderThread().vulkanManager().fenceWait(item.mFence);
84 }
85 if (err != OK) {
86 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
87 EGL_NO_SYNC_KHR);
88 return nullptr;
89 }
90 }
91
92 // Release old buffer.
93 if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) {
94 // If needed, set the released slot's fence to guard against a producer accessing the
95 // buffer before the outstanding accesses have completed.
96 sp<Fence> releaseFence;
97 EGLDisplay display = EGL_NO_DISPLAY;
98 if (uirenderer::Properties::getRenderPipelineType() ==
99 uirenderer::RenderPipelineType::SkiaGL) {
100 auto& eglManager = renderState.getRenderThread().eglManager();
101 display = eglManager.eglDisplay();
102 err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].mEglFence,
103 releaseFence);
104 } else {
105 err = renderState.getRenderThread().vulkanManager().createReleaseFence(releaseFence);
106 }
107 if (OK != err) {
108 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
109 EGL_NO_SYNC_KHR);
110 return nullptr;
111 }
112
113 if (releaseFence.get()) {
114 status_t err = st.addReleaseFenceLocked(
115 st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, releaseFence);
116 if (err != OK) {
117 IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err);
118 st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
119 EGL_NO_SYNC_KHR);
120 return nullptr;
121 }
122 }
123
124 // Finally release the old buffer.
125 status_t status = st.releaseBufferLocked(
126 st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display,
127 mImageSlots[st.mCurrentTexture].mEglFence);
128 if (status < NO_ERROR) {
129 IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status);
130 err = status;
131 // Keep going, with error raised.
132 }
133 }
134
135 // Update the state.
136 st.mCurrentTexture = slot;
137 st.mCurrentCrop = item.mCrop;
138 st.mCurrentTransform = item.mTransform;
139 st.mCurrentScalingMode = item.mScalingMode;
140 st.mCurrentTimestamp = item.mTimestamp;
141 st.mCurrentDataSpace = item.mDataSpace;
142 st.mCurrentFence = item.mFence;
143 st.mCurrentFenceTime = item.mFenceTime;
144 st.mCurrentFrameNumber = item.mFrameNumber;
145 st.computeCurrentTransformMatrixLocked();
146
147 *queueEmpty = false;
148 mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer);
149 return mImageSlots[slot].mImage;
150}
151
152} /* namespace android */