blob: 274996a35392fc4d99931a29607db528358b76dd [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
2 * Copyright (C) 2023 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// #define LOG_NDEBUG 0
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010018
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010019#define LOG_TAG "TestPatternHelper"
20
21#include "TestPatternHelper.h"
22
23#include <complex>
24#include <cstdint>
25
26#include "log/log.h"
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010027#include "nativebase/nativebase.h"
28#include "system/graphics.h"
29#include "ui/GraphicBuffer.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010030#include "utils/Errors.h"
31
32namespace android {
33namespace companion {
34namespace virtualcamera {
35
36namespace {
37
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010038using namespace std::chrono_literals;
39
40static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
41
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010042uint8_t julia(const std::complex<float> n, const std::complex<float> c) {
43 std::complex<float> z = n;
44 for (int i = 0; i < 64; i++) {
45 z = z * z + c;
46 if (std::abs(z) > 2.0) return i * 4;
47 }
48 return 0xff;
49}
50
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010051uint8_t pixelToFractal(const int x, const int y, const int width,
52 const int height, const std::complex<float> c) {
53 std::complex<float> n(float(x) / float(width) - 0.5,
54 float(y) / float(height) - 0.5);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010055 return julia(n * 5.f, c);
56}
57
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010058void renderTestPatternYcbCr420(const android_ycbcr& ycbr, const int width,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010059 const int height, const int frameNumber) {
60 float time = float(frameNumber) / 120.0f;
61 const std::complex<float> c(std::sin(time), std::cos(time));
62
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010063 uint8_t* y = reinterpret_cast<uint8_t*>(ycbr.y);
64 uint8_t* cb = reinterpret_cast<uint8_t*>(ycbr.cb);
65 uint8_t* cr = reinterpret_cast<uint8_t*>(ycbr.cr);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010066
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010067 for (int row = 0; row < height; row++) {
68 for (int col = 0; col < width; col++) {
69 y[row * ycbr.ystride + col] =
70 pixelToFractal(col, row, width, height, c * 0.78f);
71 }
72 }
73
74 int cWidth = width / 2;
75 int cHeight = height / 2;
76 for (int row = 0; row < cHeight; row++) {
77 for (int col = 0; col < cWidth; col++) {
78 cb[row * ycbr.cstride + col * ycbr.chroma_step] =
79 static_cast<uint8_t>((float(col) / float(cWidth)) * 255.f);
80 cr[row * ycbr.cstride + col * ycbr.chroma_step] =
81 static_cast<uint8_t>((float(row) / float(cHeight)) * 255.f);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010082 }
83 }
84}
85
86} // namespace
87
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010088void renderTestPatternYCbCr420(sp<Surface> surface, int frameNumber) {
89 if (surface == nullptr) {
90 ALOGE("%s: null surface, skipping render", __func__);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010091 return;
92 }
93
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +010094 ANativeWindowBuffer* buffer;
95 int fenceFd;
96 int ret = ANativeWindow_dequeueBuffer(surface.get(), &buffer, &fenceFd);
97 if (ret != NO_ERROR) {
98 ALOGE(
99 "%s: Error while deuqueing buffer from surface, "
100 "ANativeWindow_dequeueBuffer returned %d",
101 __func__, ret);
102 return;
103 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100104
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +0100105 if (buffer == nullptr) {
106 ALOGE("%s: ANativeWindowBuffer is null after dequeing", __func__);
107 return;
108 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100109
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +0100110 sp<Fence> fence = sp<Fence>::make(fenceFd);
111 if (fence->isValid()) {
112 ret = fence->wait(kAcquireFenceTimeout.count());
113 if (ret != NO_ERROR) {
114 ALOGE("%s: Timeout while waiting for the fence to clear", __func__);
115 ANativeWindow_queueBuffer(surface.get(), buffer, fence->dup());
116 return;
117 }
118 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100119
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +0100120 sp<GraphicBuffer> gBuffer = GraphicBuffer::from(buffer);
121 android_ycbcr ycbr;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100122
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +0100123 ret = gBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &ycbr,
124 fence->dup());
125 if (ret != NO_ERROR) {
126 ALOGE("%s: Failed to lock buffer retrieved from surface, ret %d", __func__,
127 ret);
128 return;
129 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100130
Jan Sebechlebsky6402fef2024-03-25 16:30:26 +0100131 renderTestPatternYcbCr420(ycbr, gBuffer->getWidth(), gBuffer->getHeight(),
132 frameNumber);
133
134 ret = gBuffer->unlock();
135 if (ret != NO_ERROR) {
136 ALOGE("%s: Failed to unlock buffer, ret %d", __func__, ret);
137 return;
138 }
139
140 ret = ANativeWindow_queueBuffer(surface.get(), buffer, /*fenceFd=*/-1);
141 if (ret != NO_ERROR) {
142 ALOGE(
143 "%s: Error while queing buffer to surface, ANativeWindow_queueBuffer "
144 "returned %d",
145 __func__, ret);
146 return;
147 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100148}
149
150} // namespace virtualcamera
151} // namespace companion
152} // namespace android