1/*
2 * Copyright 2016 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#define LOG_TAG "BufferQueueScheduler"
17
18#include "BufferQueueScheduler.h"
19
20#include <android/native_window.h>
21#include <gui/Surface.h>
22
23using namespace android;
24
25BufferQueueScheduler::BufferQueueScheduler(
26        const sp<SurfaceControl>& surfaceControl, const HSV& color, int id)
27      : mSurfaceControl(surfaceControl), mColor(color), mSurfaceId(id), mContinueScheduling(true) {}
28
29void BufferQueueScheduler::startScheduling() {
30    ALOGV("Starting Scheduler for %d Layer", mSurfaceId);
31    std::unique_lock<std::mutex> lock(mMutex);
32    if (mSurfaceControl == nullptr) {
33        mCondition.wait(lock, [&] { return (mSurfaceControl != nullptr); });
34    }
35
36    while (mContinueScheduling) {
37        while (true) {
38            if (mBufferEvents.empty()) {
39                break;
40            }
41
42            BufferEvent event = mBufferEvents.front();
43            lock.unlock();
44
45            bufferUpdate(event.dimensions);
46            fillSurface(event.event);
47            mColor.modulate();
48            lock.lock();
49            mBufferEvents.pop();
50        }
51        mCondition.wait(lock);
52    }
53}
54
55void BufferQueueScheduler::addEvent(const BufferEvent& event) {
56    std::lock_guard<std::mutex> lock(mMutex);
57    mBufferEvents.push(event);
58    mCondition.notify_one();
59}
60
61void BufferQueueScheduler::stopScheduling() {
62    std::lock_guard<std::mutex> lock(mMutex);
63    mContinueScheduling = false;
64    mCondition.notify_one();
65}
66
67void BufferQueueScheduler::setSurfaceControl(
68        const sp<SurfaceControl>& surfaceControl, const HSV& color) {
69    std::lock_guard<std::mutex> lock(mMutex);
70    mSurfaceControl = surfaceControl;
71    mColor = color;
72    mCondition.notify_one();
73}
74
75void BufferQueueScheduler::bufferUpdate(const Dimensions& dimensions) {
76    sp<Surface> s = mSurfaceControl->getSurface();
77    s->setBuffersDimensions(dimensions.width, dimensions.height);
78}
79
80void BufferQueueScheduler::fillSurface(const std::shared_ptr<Event>& event) {
81    ANativeWindow_Buffer outBuffer;
82    sp<Surface> s = mSurfaceControl->getSurface();
83
84    status_t status = s->lock(&outBuffer, nullptr);
85
86    if (status != NO_ERROR) {
87        ALOGE("fillSurface: failed to lock buffer, (%d)", status);
88        return;
89    }
90
91    auto color = mColor.getRGB();
92
93    auto img = reinterpret_cast<uint8_t*>(outBuffer.bits);
94    for (int y = 0; y < outBuffer.height; y++) {
95        for (int x = 0; x < outBuffer.width; x++) {
96            uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
97            pixel[0] = color.r;
98            pixel[1] = color.g;
99            pixel[2] = color.b;
100            pixel[3] = LAYER_ALPHA;
101        }
102    }
103
104    event->readyToExecute();
105
106    status = s->unlockAndPost();
107
108    ALOGE_IF(status != NO_ERROR, "fillSurface: failed to unlock and post buffer, (%d)", status);
109}
110