1 // Copyright (C) 2020 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include <vector>
18 
19 #include "OSWindow.h"
20 #include "aemu/base/system/System.h"
21 #include "host-common/testing/MockGraphicsAgentFactory.h"
22 #include "virgl_hw.h"
23 #include "gfxstream/virtio-gpu-gfxstream-renderer-unstable.h"
24 #include "gfxstream/virtio-gpu-gfxstream-renderer.h"
25 
26 using android::base::sleepMs;
27 
28 class GfxStreamBackendTest : public ::testing::Test {
29 private:
sWriteFence(void * cookie,struct stream_renderer_fence * fence)30  static void sWriteFence(void* cookie, struct stream_renderer_fence* fence) {
31      uint32_t current = *(uint32_t*)cookie;
32      if (current < fence->fence_id) *(uint64_t*)(cookie) = fence->fence_id;
33  }
34 
35 protected:
36     uint32_t cookie;
37     static const bool useWindow;
38     std::vector<stream_renderer_param> streamRendererParams;
39     std::vector<stream_renderer_param> minimumRequiredParams;
40     static constexpr uint32_t width = 256;
41     static constexpr uint32_t height = 256;
42     static std::unique_ptr<OSWindow> window;
43     static constexpr int rendererFlags = STREAM_RENDERER_FLAGS_USE_GLES_BIT;
44     static constexpr int surfacelessFlags = STREAM_RENDERER_FLAGS_USE_SURFACELESS_BIT;
45 
GfxStreamBackendTest()46     GfxStreamBackendTest()
47         : cookie(0),
48           streamRendererParams{{STREAM_RENDERER_PARAM_USER_DATA,
49                                 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&cookie))},
50                                {STREAM_RENDERER_PARAM_FENCE_CALLBACK,
51                                 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&sWriteFence))},
52                                {STREAM_RENDERER_PARAM_RENDERER_FLAGS, surfacelessFlags},
53                                {STREAM_RENDERER_PARAM_WIN0_WIDTH, width},
54                                {STREAM_RENDERER_PARAM_WIN0_HEIGHT, height}},
55           minimumRequiredParams{{STREAM_RENDERER_PARAM_USER_DATA,
56                                  static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&cookie))},
57                                 {STREAM_RENDERER_PARAM_FENCE_CALLBACK,
58                                  static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&sWriteFence))},
59                                 {STREAM_RENDERER_PARAM_RENDERER_FLAGS, surfacelessFlags}} {}
60 
SetUpTestSuite()61     static void SetUpTestSuite() {
62         android::emulation::injectGraphicsAgents(android::emulation::MockGraphicsAgentFactory());
63         if (useWindow) {
64             window.reset(CreateOSWindow());
65         }
66     }
67 
TearDownTestSuite()68     static void TearDownTestSuite() { window.reset(nullptr); }
69 
SetUp()70     void SetUp() override {
71         android::base::setEnvironmentVariable("ANDROID_GFXSTREAM_EGL", "1");
72         if (useWindow) {
73             window->initialize("GfxStreamBackendTestWindow", width, height);
74             window->setVisible(true);
75             window->messageLoop();
76         }
77     }
78 
TearDown()79     void TearDown() override {
80         // Ensure background threads aren't mid-initialization.
81         sleepMs(100);
82         if (useWindow) {
83             window->destroy();
84         }
85         stream_renderer_teardown();
86     }
87 };
88 
89 std::unique_ptr<OSWindow> GfxStreamBackendTest::window = nullptr;
90 
91 const bool GfxStreamBackendTest::useWindow =
92         android::base::getEnvironmentVariable("ANDROID_EMU_TEST_WITH_WINDOW") == "1";
93 
TEST_F(GfxStreamBackendTest,Init)94 TEST_F(GfxStreamBackendTest, Init) {
95     stream_renderer_init(streamRendererParams.data(), streamRendererParams.size());
96 }
97 
TEST_F(GfxStreamBackendTest,InitOpenGLWindow)98 TEST_F(GfxStreamBackendTest, InitOpenGLWindow) {
99     if (!useWindow) {
100         return;
101     }
102 
103     std::vector<stream_renderer_param> glParams = streamRendererParams;
104     for (auto& param: glParams) {
105         if (param.key == STREAM_RENDERER_PARAM_RENDERER_FLAGS) {
106             param.value = rendererFlags;
107         }
108     }
109     stream_renderer_init(glParams.data(), glParams.size());
110     gfxstream_backend_setup_window(window->getFramebufferNativeWindow(), 0, 0,
111                                        width, height, width, height);
112 }
113 
TEST_F(GfxStreamBackendTest,SimpleFlush)114 TEST_F(GfxStreamBackendTest, SimpleFlush) {
115     stream_renderer_init(streamRendererParams.data(), streamRendererParams.size());
116 
117     const uint32_t res_id = 8;
118     struct stream_renderer_resource_create_args create_resource_args = {
119         .handle = res_id,
120         .target = 2,  // PIPE_TEXTURE_2D
121         .format = VIRGL_FORMAT_R8G8B8A8_UNORM,
122         .bind = VIRGL_BIND_SAMPLER_VIEW | VIRGL_BIND_SCANOUT | VIRGL_BIND_SHARED,
123         .width = width,
124         .height = height,
125         .depth = 1,
126         .array_size = 1,
127         .last_level = 0,
128         .nr_samples = 0,
129         .flags = 0,
130     };
131     EXPECT_EQ(stream_renderer_resource_create(&create_resource_args, NULL, 0), 0);
132     // R8G8B8A8 is used, so 4 bytes per pixel
133     auto fb = std::make_unique<uint32_t[]>(width * height);
134     EXPECT_NE(fb, nullptr);
135     stream_renderer_flush(res_id);
136 }
137 
138 // Tests compile and link only.
TEST_F(GfxStreamBackendTest,DISABLED_ApiCallLinkTest)139 TEST_F(GfxStreamBackendTest, DISABLED_ApiCallLinkTest) {
140     stream_renderer_init(streamRendererParams.data(), streamRendererParams.size());
141 
142     const uint32_t res_id = 8;
143     struct stream_renderer_resource_create_args create_resource_args = {
144         .handle = res_id,
145         .target = 2,  // PIPE_TEXTURE_2D
146         .format = VIRGL_FORMAT_R8G8B8A8_UNORM,
147         .bind = VIRGL_BIND_SAMPLER_VIEW | VIRGL_BIND_SCANOUT | VIRGL_BIND_SHARED,
148         .width = width,
149         .height = height,
150         .depth = 1,
151         .array_size = 1,
152         .last_level = 0,
153         .nr_samples = 0,
154         .flags = 0,
155     };
156     EXPECT_EQ(stream_renderer_resource_create(&create_resource_args, NULL, 0), 0);
157     struct stream_renderer_command cmd;
158     cmd.ctx_id = 0;
159     cmd.cmd = nullptr;
160     cmd.cmd_size = 0;
161 
162     // R8G8B8A8 is used, so 4 bytes per pixel
163     auto fb = std::make_unique<uint32_t[]>(width * height);
164     EXPECT_NE(fb, nullptr);
165     stream_renderer_flush(res_id);
166     stream_renderer_resource_unref(0);
167     stream_renderer_context_create(0, 0, NULL, 0);
168     stream_renderer_context_destroy(0);
169     stream_renderer_submit_cmd(&cmd);
170     stream_renderer_transfer_read_iov(0, 0, 0, 0, 0, 0, 0, 0, 0);
171     stream_renderer_transfer_write_iov(0, 0, 0, 0, 0, 0, 0, 0, 0);
172 
173     stream_renderer_get_cap_set(0, 0, 0);
174     stream_renderer_fill_caps(0, 0, 0);
175 
176     stream_renderer_resource_attach_iov(0, 0, 0);
177     stream_renderer_resource_detach_iov(0, 0, 0);
178     stream_renderer_create_fence(NULL);
179     stream_renderer_ctx_attach_resource(0, 0);
180     stream_renderer_ctx_detach_resource(0, 0);
181     stream_renderer_resource_get_info(0, 0);
182 }
183 
TEST_F(GfxStreamBackendTest,MinimumRequiredParameters)184 TEST_F(GfxStreamBackendTest, MinimumRequiredParameters) {
185     // Only the minimum required parameters.
186     int initResult =
187         stream_renderer_init(minimumRequiredParams.data(), minimumRequiredParams.size());
188     EXPECT_EQ(initResult, 0);
189 }
190 
TEST_F(GfxStreamBackendTest,MissingRequiredParameter)191 TEST_F(GfxStreamBackendTest, MissingRequiredParameter) {
192     for (size_t i = 0; i < minimumRequiredParams.size(); ++i) {
193         // For each parameter, remove it and try to init, expecting failure.
194         std::vector<stream_renderer_param> insufficientParams = minimumRequiredParams;
195         insufficientParams.erase(insufficientParams.begin() + i);
196         int initResult = stream_renderer_init(insufficientParams.data(), insufficientParams.size());
197         EXPECT_NE(initResult, 0);
198 
199         // Ensure background threads aren't mid-initialization.
200         sleepMs(100);
201         stream_renderer_teardown();
202     }
203 
204     // Initialize once more for the teardown function.
205     int initResult = stream_renderer_init(streamRendererParams.data(), streamRendererParams.size());
206     EXPECT_EQ(initResult, 0);
207 }
208