1 // Copyright 2021 The Dawn Authors
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 "tests/unittests/wire/WireTest.h"
16 
17 #include "dawn_wire/WireClient.h"
18 #include "dawn_wire/WireServer.h"
19 
20 using namespace testing;
21 using namespace dawn_wire;
22 
23 class WireInjectSwapChainTests : public WireTest {
24   public:
WireInjectSwapChainTests()25     WireInjectSwapChainTests() {
26     }
27     ~WireInjectSwapChainTests() override = default;
28 };
29 
30 // Test that reserving and injecting a swapchain makes calls on the client object forward to the
31 // server object correctly.
TEST_F(WireInjectSwapChainTests, CallAfterReserveInject)32 TEST_F(WireInjectSwapChainTests, CallAfterReserveInject) {
33     ReservedSwapChain reservation = GetWireClient()->ReserveSwapChain(device);
34 
35     WGPUSwapChain apiSwapchain = api.GetNewSwapChain();
36     EXPECT_CALL(api, SwapChainReference(apiSwapchain));
37     ASSERT_TRUE(GetWireServer()->InjectSwapChain(apiSwapchain, reservation.id,
38                                                  reservation.generation, reservation.deviceId,
39                                                  reservation.deviceGeneration));
40 
41     wgpuSwapChainPresent(reservation.swapchain);
42     EXPECT_CALL(api, SwapChainPresent(apiSwapchain));
43     FlushClient();
44 }
45 
46 // Test that reserve correctly returns different IDs each time.
TEST_F(WireInjectSwapChainTests, ReserveDifferentIDs)47 TEST_F(WireInjectSwapChainTests, ReserveDifferentIDs) {
48     ReservedSwapChain reservation1 = GetWireClient()->ReserveSwapChain(device);
49     ReservedSwapChain reservation2 = GetWireClient()->ReserveSwapChain(device);
50 
51     ASSERT_NE(reservation1.id, reservation2.id);
52     ASSERT_NE(reservation1.swapchain, reservation2.swapchain);
53 }
54 
55 // Test that injecting the same id without a destroy first fails.
TEST_F(WireInjectSwapChainTests, InjectExistingID)56 TEST_F(WireInjectSwapChainTests, InjectExistingID) {
57     ReservedSwapChain reservation = GetWireClient()->ReserveSwapChain(device);
58 
59     WGPUSwapChain apiSwapchain = api.GetNewSwapChain();
60     EXPECT_CALL(api, SwapChainReference(apiSwapchain));
61     ASSERT_TRUE(GetWireServer()->InjectSwapChain(apiSwapchain, reservation.id,
62                                                  reservation.generation, reservation.deviceId,
63                                                  reservation.deviceGeneration));
64 
65     // ID already in use, call fails.
66     ASSERT_FALSE(GetWireServer()->InjectSwapChain(apiSwapchain, reservation.id,
67                                                   reservation.generation, reservation.deviceId,
68                                                   reservation.deviceGeneration));
69 }
70 
71 // Test that the server only borrows the swapchain and does a single reference-release
TEST_F(WireInjectSwapChainTests, InjectedSwapChainLifetime)72 TEST_F(WireInjectSwapChainTests, InjectedSwapChainLifetime) {
73     ReservedSwapChain reservation = GetWireClient()->ReserveSwapChain(device);
74 
75     // Injecting the swapchain adds a reference
76     WGPUSwapChain apiSwapchain = api.GetNewSwapChain();
77     EXPECT_CALL(api, SwapChainReference(apiSwapchain));
78     ASSERT_TRUE(GetWireServer()->InjectSwapChain(apiSwapchain, reservation.id,
79                                                  reservation.generation, reservation.deviceId,
80                                                  reservation.deviceGeneration));
81 
82     // Releasing the swapchain removes a single reference.
83     wgpuSwapChainRelease(reservation.swapchain);
84     EXPECT_CALL(api, SwapChainRelease(apiSwapchain));
85     FlushClient();
86 
87     // Deleting the server doesn't release a second reference.
88     DeleteServer();
89     Mock::VerifyAndClearExpectations(&api);
90 }
91 
92 // Test that a swapchain reservation can be reclaimed. This is necessary to
93 // avoid leaking ObjectIDs for reservations that are never injected.
TEST_F(WireInjectSwapChainTests, ReclaimSwapChainReservation)94 TEST_F(WireInjectSwapChainTests, ReclaimSwapChainReservation) {
95     // Test that doing a reservation and full release is an error.
96     {
97         ReservedSwapChain reservation = GetWireClient()->ReserveSwapChain(device);
98         wgpuSwapChainRelease(reservation.swapchain);
99         FlushClient(false);
100     }
101 
102     // Test that doing a reservation and then reclaiming it recycles the ID.
103     {
104         ReservedSwapChain reservation1 = GetWireClient()->ReserveSwapChain(device);
105         GetWireClient()->ReclaimSwapChainReservation(reservation1);
106 
107         ReservedSwapChain reservation2 = GetWireClient()->ReserveSwapChain(device);
108 
109         // The ID is the same, but the generation is still different.
110         ASSERT_EQ(reservation1.id, reservation2.id);
111         ASSERT_NE(reservation1.generation, reservation2.generation);
112 
113         // No errors should occur.
114         FlushClient();
115     }
116 }
117