• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2023 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 #pragma once
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 #include <android-base/expected.h>
21 #include <inttypes.h>
22 
23 #include <future>
24 #include <memory>
25 #include <optional>
26 #include <string>
27 #include <thread>
28 #include <unordered_set>
29 #include <variant>
30 
31 // clang-format off
32 #include <EGL/egl.h>
33 #include <EGL/eglext.h>
34 #include "OpenGLESDispatch/gldefs.h"
35 #include "OpenGLESDispatch/gles_functions.h"
36 #include "OpenGLESDispatch/RenderEGL_functions.h"
37 #include "OpenGLESDispatch/RenderEGL_extensions_functions.h"
38 
39 #define VULKAN_HPP_NAMESPACE vkhpp
40 #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
41 #define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 1
42 #define VULKAN_HPP_NO_CONSTRUCTORS
43 #define VULKAN_HPP_NO_EXCEPTIONS
44 #include <vulkan/vulkan.hpp>
45 #include <vulkan/vk_android_native_buffer.h>
46 // clang-format on
47 
48 #include "Sync.h"
49 #include "drm_fourcc.h"
50 #include "gfxstream/guest/ANativeWindow.h"
51 #include "gfxstream/guest/Gralloc.h"
52 #include "gfxstream/guest/RenderControlApi.h"
53 
54 namespace gfxstream {
55 namespace tests {
56 
57 constexpr const bool kSaveImagesIfComparisonFailed = false;
58 
59 MATCHER(IsOk, "an ok result") {
60   auto& result = arg;
61   if (!result.ok()) {
62     *result_listener << "which is an error with message: \""
63                      << result.error()
64                      << "\"";
65     return false;
66   }
67   return true;
68 }
69 
70 MATCHER(IsError, "an error result") {
71     auto& result = arg;
72     if (result.ok()) {
73         *result_listener << "which is an ok result";
74         return false;
75     }
76     return true;
77 }
78 
79 MATCHER(IsVkSuccess, "is VK_SUCCESS") {
80     auto& result = arg;
81     if (result != vkhpp::Result::eSuccess) {
82         *result_listener << "which is " << vkhpp::to_string(result);
83         return false;
84     }
85     return true;
86 }
87 
88 MATCHER(IsValidHandle, "a non-null handle") {
89     auto& result = arg;
90     if (!result) {
91         *result_listener << "which is a VK_NULL_HANDLE";
92         return false;
93     }
94     return true;
95 }
96 
97 struct Ok {};
98 
99 template <typename GlType>
100 using GlExpected = android::base::expected<GlType, std::string>;
101 
102 #define GL_ASSERT(x)                        \
103     ({                                      \
104         auto gl_result = (x);               \
105         if (!gl_result.ok()) {              \
106             ASSERT_THAT(gl_result, IsOk()); \
107         }                                   \
108         std::move(gl_result.value());       \
109     })
110 
111 #define GL_EXPECT(x)                                             \
112     ({                                                           \
113         auto gl_result = (x);                                    \
114         if (!gl_result.ok()) {                                   \
115             return android::base::unexpected(gl_result.error()); \
116         }                                                        \
117         std::move(gl_result.value());                            \
118     })
119 
120 template <typename VkType>
121 using VkExpected = android::base::expected<VkType, vkhpp::Result>;
122 
123 #define VK_ASSERT(x)                                                          \
124   ({                                                                          \
125     auto vk_expect_android_base_expected = (x);                               \
126     if (!vk_expect_android_base_expected.ok()) {                              \
127       ASSERT_THAT(vk_expect_android_base_expected.ok(), ::testing::IsTrue()); \
128     };                                                                        \
129     std::move(vk_expect_android_base_expected.value());                       \
130   })
131 
132 #define VK_ASSERT_RV(x)                                                       \
133   ({                                                                          \
134     auto vkhpp_result_value = (x);                                            \
135     ASSERT_THAT(vkhpp_result_value.result, IsVkSuccess());                    \
136     std::move(vkhpp_result_value.value);                                      \
137   })
138 
139 #define VK_EXPECT_RESULT(x)                                                   \
140   ({                                                                          \
141     auto vkhpp_result = (x);                                                  \
142     if (vkhpp_result != vkhpp::Result::eSuccess) {                            \
143         return android::base::unexpected(vkhpp_result);                       \
144     }                                                                         \
145   })
146 
147 #define VK_EXPECT_RV(x)                                                       \
148   ({                                                                          \
149     auto vkhpp_result_value = (x);                                            \
150     if (vkhpp_result_value.result != vkhpp::Result::eSuccess) {               \
151         return android::base::unexpected(vkhpp_result_value.result);          \
152     }                                                                         \
153     std::move(vkhpp_result_value.value);                                      \
154   })
155 
156 #define VK_TRY(x)                                                                   \
157     ({                                                                              \
158         auto vk_try_android_base_expected = (x);                                    \
159         if (!vk_try_android_base_expected.ok()) {                                   \
160             return android::base::unexpected(vk_try_android_base_expected.error()); \
161         }                                                                           \
162         std::move(vk_try_android_base_expected.value());                            \
163     })
164 
165 #define VK_TRY_RESULT(x)                               \
166     ({                                                 \
167         auto vkhpp_result = (x);                       \
168         if (vkhpp_result != vkhpp::Result::eSuccess) { \
169             return vkhpp_result;                       \
170         }                                              \
171     })
172 
173 #define VK_TRY_RV(x)                                                          \
174   ({                                                                          \
175     auto vkhpp_result_value = (x);                                            \
176     if (vkhpp_result_value.result != vkhpp::Result::eSuccess) {               \
177         return vkhpp_result_value.result;                                     \
178     }                                                                         \
179     std::move(vkhpp_result_value.value);                                      \
180   })
181 
182 struct GuestGlDispatchTable {
183 #define DECLARE_EGL_FUNCTION(return_type, function_name, signature) \
184     return_type(*function_name) signature = nullptr;
185 
186 #define DECLARE_GLES_FUNCTION(return_type, function_name, signature, args) \
187     return_type(*function_name) signature = nullptr;
188 
189     LIST_RENDER_EGL_FUNCTIONS(DECLARE_EGL_FUNCTION)
190     LIST_RENDER_EGL_EXTENSIONS_FUNCTIONS(DECLARE_EGL_FUNCTION)
191     LIST_GLES_FUNCTIONS(DECLARE_GLES_FUNCTION, DECLARE_GLES_FUNCTION)
192 };
193 
194 struct GuestRenderControlDispatchTable {
195     PFN_rcCreateDevice rcCreateDevice = nullptr;
196     PFN_rcDestroyDevice rcDestroyDevice = nullptr;
197     PFN_rcCompose rcCompose = nullptr;
198 };
199 
200 class ScopedRenderControlDevice {
201    public:
ScopedRenderControlDevice()202     ScopedRenderControlDevice() {}
203 
ScopedRenderControlDevice(GuestRenderControlDispatchTable & dispatch)204     ScopedRenderControlDevice(GuestRenderControlDispatchTable& dispatch) : mDispatch(&dispatch) {
205         mDevice = dispatch.rcCreateDevice();
206     }
207 
208     ScopedRenderControlDevice(const ScopedRenderControlDevice& rhs) = delete;
209     ScopedRenderControlDevice& operator=(const ScopedRenderControlDevice& rhs) = delete;
210 
ScopedRenderControlDevice(ScopedRenderControlDevice && rhs)211     ScopedRenderControlDevice(ScopedRenderControlDevice&& rhs)
212         : mDispatch(rhs.mDispatch), mDevice(rhs.mDevice) {
213         rhs.mDevice = nullptr;
214     }
215 
216     ScopedRenderControlDevice& operator=(ScopedRenderControlDevice&& rhs) {
217         mDispatch = rhs.mDispatch;
218         std::swap(mDevice, rhs.mDevice);
219         return *this;
220     }
221 
~ScopedRenderControlDevice()222     ~ScopedRenderControlDevice() {
223         if (mDevice != nullptr) {
224             mDispatch->rcDestroyDevice(mDevice);
225             mDevice = nullptr;
226         }
227     }
228 
229     operator RenderControlDevice*() { return mDevice; }
230     operator RenderControlDevice*() const { return mDevice; }
231 
232    private:
233     GuestRenderControlDispatchTable* mDispatch = nullptr;
234     RenderControlDevice* mDevice = nullptr;
235 };
236 
237 class ScopedGlType {
238    public:
239     using GlDispatch = GuestGlDispatchTable;
240     using GlDispatchGenFunc = void (*GuestGlDispatchTable::*)(GLsizei, GLuint*);
241     using GlDispatchDelFunc = void (*GuestGlDispatchTable::*)(GLsizei, const GLuint*);
242 
ScopedGlType()243     ScopedGlType() {}
244 
ScopedGlType(GlDispatch & glDispatch,GlDispatchGenFunc glGenFunc,GlDispatchDelFunc glDelFunc)245     ScopedGlType(GlDispatch& glDispatch, GlDispatchGenFunc glGenFunc, GlDispatchDelFunc glDelFunc)
246         : mGlDispatch(&glDispatch), mGlGenFunc(glGenFunc), mGlDelFunc(glDelFunc) {
247         (mGlDispatch->*mGlGenFunc)(1, &mHandle);
248     }
249 
250     ScopedGlType(const ScopedGlType& rhs) = delete;
251     ScopedGlType& operator=(const ScopedGlType& rhs) = delete;
252 
ScopedGlType(ScopedGlType && rhs)253     ScopedGlType(ScopedGlType&& rhs)
254         : mGlDispatch(rhs.mGlDispatch),
255           mGlGenFunc(rhs.mGlGenFunc),
256           mGlDelFunc(rhs.mGlDelFunc),
257           mHandle(rhs.mHandle) {
258         rhs.mHandle = 0;
259     }
260 
261     ScopedGlType& operator=(ScopedGlType&& rhs) {
262         mGlDispatch = rhs.mGlDispatch;
263         mGlGenFunc = rhs.mGlGenFunc;
264         mGlDelFunc = rhs.mGlDelFunc;
265         std::swap(mHandle, rhs.mHandle);
266         return *this;
267     }
268 
~ScopedGlType()269     ~ScopedGlType() {
270         if (mHandle != 0) {
271             (mGlDispatch->*mGlDelFunc)(1, &mHandle);
272             mHandle = 0;
273         }
274     }
275 
GLuint()276     operator GLuint() { return mHandle; }
GLuint()277     operator GLuint() const { return mHandle; }
278 
279    private:
280     GlDispatch* mGlDispatch = nullptr;
281     GlDispatchGenFunc mGlGenFunc = nullptr;
282     GlDispatchDelFunc mGlDelFunc = nullptr;
283     GLuint mHandle = 0;
284 };
285 
286 class ScopedGlBuffer : public ScopedGlType {
287    public:
ScopedGlBuffer(GlDispatch & dispatch)288     ScopedGlBuffer(GlDispatch& dispatch)
289         : ScopedGlType(dispatch, &GlDispatch::glGenBuffers, &GlDispatch::glDeleteBuffers) {}
290 };
291 
292 class ScopedGlTexture : public ScopedGlType {
293    public:
ScopedGlTexture(GlDispatch & dispatch)294     ScopedGlTexture(GlDispatch& dispatch)
295         : ScopedGlType(dispatch, &GlDispatch::glGenTextures, &GlDispatch::glDeleteTextures) {}
296 };
297 
298 class ScopedGlFramebuffer : public ScopedGlType {
299    public:
ScopedGlFramebuffer(GlDispatch & dispatch)300     ScopedGlFramebuffer(GlDispatch& dispatch)
301         : ScopedGlType(dispatch, &GlDispatch::glGenFramebuffers,
302                        &GlDispatch::glDeleteFramebuffers) {}
303 };
304 
305 class ScopedGlShader {
306    public:
307     using GlDispatch = GuestGlDispatchTable;
308 
309     ScopedGlShader() = default;
310 
311     ScopedGlShader(const ScopedGlShader& rhs) = delete;
312     ScopedGlShader& operator=(const ScopedGlShader& rhs) = delete;
313 
314     static GlExpected<ScopedGlShader> MakeShader(GlDispatch& dispatch, GLenum type,
315                                                  const std::string& source);
316 
ScopedGlShader(ScopedGlShader && rhs)317     ScopedGlShader(ScopedGlShader&& rhs) : mGlDispatch(rhs.mGlDispatch), mHandle(rhs.mHandle) {
318         rhs.mHandle = 0;
319     }
320 
321     ScopedGlShader& operator=(ScopedGlShader&& rhs) {
322         mGlDispatch = rhs.mGlDispatch;
323         std::swap(mHandle, rhs.mHandle);
324         return *this;
325     }
326 
~ScopedGlShader()327     ~ScopedGlShader() {
328         if (mHandle != 0) {
329             mGlDispatch->glDeleteShader(mHandle);
330             mHandle = 0;
331         }
332     }
333 
GLuint()334     operator GLuint() { return mHandle; }
GLuint()335     operator GLuint() const { return mHandle; }
336 
337    private:
ScopedGlShader(GlDispatch & dispatch,GLuint handle)338     ScopedGlShader(GlDispatch& dispatch, GLuint handle) : mGlDispatch(&dispatch), mHandle(handle) {}
339 
340     GlDispatch* mGlDispatch = nullptr;
341     GLuint mHandle = 0;
342 };
343 
344 class ScopedGlProgram {
345    public:
346     using GlDispatch = GuestGlDispatchTable;
347 
348     ScopedGlProgram() = default;
349 
350     ScopedGlProgram(const ScopedGlProgram& rhs) = delete;
351     ScopedGlProgram& operator=(const ScopedGlProgram& rhs) = delete;
352 
353     static GlExpected<ScopedGlProgram> MakeProgram(GlDispatch& dispatch,
354                                                    const std::string& vertShader,
355                                                    const std::string& fragShader);
356 
357     static GlExpected<ScopedGlProgram> MakeProgram(GlDispatch& dispatch, GLenum programBinaryFormat,
358                                                    const std::vector<uint8_t>& programBinaryData);
359 
ScopedGlProgram(ScopedGlProgram && rhs)360     ScopedGlProgram(ScopedGlProgram&& rhs) : mGlDispatch(rhs.mGlDispatch), mHandle(rhs.mHandle) {
361         rhs.mHandle = 0;
362     }
363 
364     ScopedGlProgram& operator=(ScopedGlProgram&& rhs) {
365         mGlDispatch = rhs.mGlDispatch;
366         std::swap(mHandle, rhs.mHandle);
367         return *this;
368     }
369 
~ScopedGlProgram()370     ~ScopedGlProgram() {
371         if (mHandle != 0) {
372             mGlDispatch->glDeleteProgram(mHandle);
373             mHandle = 0;
374         }
375     }
376 
GLuint()377     operator GLuint() { return mHandle; }
GLuint()378     operator GLuint() const { return mHandle; }
379 
380    private:
ScopedGlProgram(GlDispatch & dispatch,GLuint handle)381     ScopedGlProgram(GlDispatch& dispatch, GLuint handle)
382         : mGlDispatch(&dispatch), mHandle(handle) {}
383 
384     GlDispatch* mGlDispatch = nullptr;
385     GLuint mHandle = 0;
386 };
387 
388 class ScopedAHardwareBuffer {
389    public:
390     ScopedAHardwareBuffer() = default;
391 
392     static GlExpected<ScopedAHardwareBuffer> Allocate(Gralloc& gralloc, uint32_t width,
393                                                       uint32_t height, uint32_t format);
394 
395     ScopedAHardwareBuffer(const ScopedAHardwareBuffer& rhs) = delete;
396     ScopedAHardwareBuffer& operator=(const ScopedAHardwareBuffer& rhs) = delete;
397 
ScopedAHardwareBuffer(ScopedAHardwareBuffer && rhs)398     ScopedAHardwareBuffer(ScopedAHardwareBuffer&& rhs)
399         : mGralloc(rhs.mGralloc), mHandle(rhs.mHandle) {
400         rhs.mHandle = nullptr;
401     }
402 
403     ScopedAHardwareBuffer& operator=(ScopedAHardwareBuffer&& rhs) {
404         mGralloc = rhs.mGralloc;
405         std::swap(mHandle, rhs.mHandle);
406         return *this;
407     }
408 
~ScopedAHardwareBuffer()409     ~ScopedAHardwareBuffer() {
410         if (mHandle != nullptr) {
411             mGralloc->release(mHandle);
412             mHandle = 0;
413         }
414     }
415 
GetWidth()416     uint32_t GetWidth() const { return mGralloc->getWidth(mHandle); }
417 
GetHeight()418     uint32_t GetHeight() const { return mGralloc->getHeight(mHandle); }
419 
GetAHBFormat()420     uint32_t GetAHBFormat() const { return mGralloc->getFormat(mHandle); }
421 
Lock()422     GlExpected<uint8_t*> Lock() {
423         uint8_t* mapped = nullptr;
424         int status = mGralloc->lock(mHandle, &mapped);
425         if (status != 0) {
426             return android::base::unexpected("Failed to lock AHB");
427         }
428         return mapped;
429     }
430 
Unlock()431     void Unlock() { mGralloc->unlock(mHandle); }
432 
433     operator AHardwareBuffer*() { return mHandle; }
434     operator AHardwareBuffer*() const { return mHandle; }
435 
436    private:
ScopedAHardwareBuffer(Gralloc & gralloc,AHardwareBuffer * handle)437     ScopedAHardwareBuffer(Gralloc& gralloc, AHardwareBuffer* handle)
438         : mGralloc(&gralloc), mHandle(handle) {}
439 
440     Gralloc* mGralloc = nullptr;
441     AHardwareBuffer* mHandle = nullptr;
442 };
443 
444 struct Image {
445     uint32_t width;
446     uint32_t height;
447     std::vector<uint32_t> pixels;
448 };
449 
450 enum class GfxstreamTransport {
451   kVirtioGpuAsg,
452   kVirtioGpuPipe,
453 };
454 
455 struct TestParams {
456     bool with_gl;
457     bool with_vk;
458     int samples = 1;
459     std::unordered_set<std::string> with_features;
460     GfxstreamTransport with_transport = GfxstreamTransport::kVirtioGpuAsg;
461 
462     std::string ToString() const;
463     friend std::ostream& operator<<(std::ostream& os, const TestParams& params);
464 };
465 
466 std::string GetTestName(const ::testing::TestParamInfo<TestParams>& info);
467 
468 // Generates the cartesian product of params with and without the given features.
469 std::vector<TestParams> WithAndWithoutFeatures(const std::vector<TestParams>& params,
470                                                const std::vector<std::string>& features);
471 
472 struct TypicalVkTestEnvironmentOptions {
473     uint32_t apiVersion{VK_API_VERSION_1_2};
474     std::optional<const void*> instanceCreateInfoPNext;
475     std::optional<std::vector<std::string>> deviceExtensions;
476     std::optional<const void*> deviceCreateInfoPNext;
477 };
478 
479 class GfxstreamEnd2EndTest : public ::testing::TestWithParam<TestParams> {
480    public:
481     std::unique_ptr<GuestGlDispatchTable> SetupGuestGl();
482     std::unique_ptr<GuestRenderControlDispatchTable> SetupGuestRc();
483     std::unique_ptr<vkhpp::DynamicLoader> SetupGuestVk();
484 
485     void SetUp() override;
486 
487     void TearDownGuest();
488     void TearDownHost();
489     void TearDown() override;
490 
491     void SetUpEglContextAndSurface(uint32_t contextVersion,
492                                    uint32_t width,
493                                    uint32_t height,
494                                    EGLDisplay* outDisplay,
495                                    EGLContext* outContext,
496                                    EGLSurface* outSurface);
497 
498     void TearDownEglContextAndSurface(EGLDisplay display,
499                                       EGLContext context,
500                                       EGLSurface surface);
501 
502     GlExpected<ScopedGlShader> SetUpShader(GLenum type, const std::string& source);
503 
504     GlExpected<ScopedGlProgram> SetUpProgram(const std::string& vertSource,
505                                              const std::string& fragSource);
506 
507     GlExpected<ScopedGlProgram> SetUpProgram(GLenum programBinaryFormat,
508                                              const std::vector<uint8_t>& programBinaryData);
509 
510     struct TypicalVkTestEnvironment {
511         vkhpp::UniqueInstance instance;
512         vkhpp::PhysicalDevice physicalDevice;
513         vkhpp::UniqueDevice device;
514         vkhpp::Queue queue;
515         uint32_t queueFamilyIndex;
516     };
517     VkExpected<TypicalVkTestEnvironment> SetUpTypicalVkTestEnvironment(
518         const TypicalVkTestEnvironmentOptions& opts = {});
519 
520     void SnapshotSaveAndLoad();
521 
522     GlExpected<Image> LoadImage(const std::string& basename);
523 
524     GlExpected<Image> AsImage(ScopedAHardwareBuffer& ahb);
525 
526     GlExpected<ScopedAHardwareBuffer> CreateAHBFromImage(const std::string& basename);
527 
528     bool ArePixelsSimilar(uint32_t expectedPixel, uint32_t actualPixel);
529 
530     bool AreImagesSimilar(const Image& expected, const Image& actual);
531 
532     GlExpected<Ok> CompareAHBWithGolden(ScopedAHardwareBuffer& ahb,
533                                         const std::string& goldenBasename);
534 
535     std::unique_ptr<ANativeWindowHelper> mAnwHelper;
536     std::unique_ptr<Gralloc> mGralloc;
537     std::unique_ptr<SyncHelper> mSync;
538     std::unique_ptr<GuestGlDispatchTable> mGl;
539     std::unique_ptr<GuestRenderControlDispatchTable> mRc;
540     std::unique_ptr<vkhpp::DynamicLoader> mVk;
541 };
542 
543 }  // namespace tests
544 }  // namespace gfxstream
545