• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <gtest/gtest.h>
16 
17 #include "dawn_native/Toggles.h"
18 #include "mocks/BindGroupLayoutMock.h"
19 #include "mocks/BindGroupMock.h"
20 #include "mocks/BufferMock.h"
21 #include "mocks/CommandBufferMock.h"
22 #include "mocks/ComputePipelineMock.h"
23 #include "mocks/DeviceMock.h"
24 #include "mocks/ExternalTextureMock.h"
25 #include "mocks/PipelineLayoutMock.h"
26 #include "mocks/QuerySetMock.h"
27 #include "mocks/RenderPipelineMock.h"
28 #include "mocks/SamplerMock.h"
29 #include "mocks/ShaderModuleMock.h"
30 #include "mocks/SwapChainMock.h"
31 #include "mocks/TextureMock.h"
32 #include "tests/DawnNativeTest.h"
33 #include "utils/ComboRenderPipelineDescriptor.h"
34 
35 namespace dawn_native { namespace {
36 
37     using ::testing::_;
38     using ::testing::ByMove;
39     using ::testing::InSequence;
40     using ::testing::Return;
41     using ::testing::Test;
42 
43     class DestroyObjectTests : public Test {
44       public:
DestroyObjectTests()45         DestroyObjectTests() : Test() {
46             // Skipping validation on descriptors as coverage for validation is already present.
47             mDevice.SetToggle(Toggle::SkipValidation, true);
48         }
49 
GetTexture()50         Ref<TextureMock> GetTexture() {
51             if (mTexture != nullptr) {
52                 return mTexture;
53             }
54             mTexture =
55                 AcquireRef(new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal));
56             EXPECT_CALL(*mTexture.Get(), DestroyImpl).Times(1);
57             return mTexture;
58         }
59 
GetPipelineLayout()60         Ref<PipelineLayoutMock> GetPipelineLayout() {
61             if (mPipelineLayout != nullptr) {
62                 return mPipelineLayout;
63             }
64             mPipelineLayout = AcquireRef(new PipelineLayoutMock(&mDevice));
65             EXPECT_CALL(*mPipelineLayout.Get(), DestroyImpl).Times(1);
66             return mPipelineLayout;
67         }
68 
GetVertexShaderModule()69         Ref<ShaderModuleMock> GetVertexShaderModule() {
70             if (mVsModule != nullptr) {
71                 return mVsModule;
72             }
73             DAWN_TRY_ASSIGN_WITH_CLEANUP(
74                 mVsModule, ShaderModuleMock::Create(&mDevice, R"(
75             [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
76                 return vec4<f32>(0.0, 0.0, 0.0, 1.0);
77             })"),
78                 { ASSERT(false); }, mVsModule);
79             EXPECT_CALL(*mVsModule.Get(), DestroyImpl).Times(1);
80             return mVsModule;
81         }
82 
GetComputeShaderModule()83         Ref<ShaderModuleMock> GetComputeShaderModule() {
84             if (mCsModule != nullptr) {
85                 return mCsModule;
86             }
87             DAWN_TRY_ASSIGN_WITH_CLEANUP(
88                 mCsModule, ShaderModuleMock::Create(&mDevice, R"(
89             [[stage(compute), workgroup_size(1)]] fn main() {
90             })"),
91                 { ASSERT(false); }, mCsModule);
92             EXPECT_CALL(*mCsModule.Get(), DestroyImpl).Times(1);
93             return mCsModule;
94         }
95 
96       protected:
97         DeviceMock mDevice;
98 
99         // The following lazy-initialized objects are used to facilitate creation of dependent
100         // objects under test.
101         Ref<TextureMock> mTexture;
102         Ref<PipelineLayoutMock> mPipelineLayout;
103         Ref<ShaderModuleMock> mVsModule;
104         Ref<ShaderModuleMock> mCsModule;
105     };
106 
TEST_F(DestroyObjectTests,BindGroupExplicit)107     TEST_F(DestroyObjectTests, BindGroupExplicit) {
108         BindGroupMock bindGroupMock(&mDevice);
109         EXPECT_CALL(bindGroupMock, DestroyImpl).Times(1);
110 
111         EXPECT_TRUE(bindGroupMock.IsAlive());
112         bindGroupMock.Destroy();
113         EXPECT_FALSE(bindGroupMock.IsAlive());
114     }
115 
116     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
117     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,BindGroupImplicit)118     TEST_F(DestroyObjectTests, BindGroupImplicit) {
119         BindGroupMock* bindGroupMock = new BindGroupMock(&mDevice);
120         EXPECT_CALL(*bindGroupMock, DestroyImpl).Times(1);
121         {
122             BindGroupDescriptor desc = {};
123             Ref<BindGroupBase> bindGroup;
124             EXPECT_CALL(mDevice, CreateBindGroupImpl)
125                 .WillOnce(Return(ByMove(AcquireRef(bindGroupMock))));
126             DAWN_ASSERT_AND_ASSIGN(bindGroup, mDevice.CreateBindGroup(&desc));
127 
128             EXPECT_TRUE(bindGroup->IsAlive());
129         }
130     }
131 
TEST_F(DestroyObjectTests,BindGroupLayoutExplicit)132     TEST_F(DestroyObjectTests, BindGroupLayoutExplicit) {
133         BindGroupLayoutMock bindGroupLayoutMock(&mDevice);
134         EXPECT_CALL(bindGroupLayoutMock, DestroyImpl).Times(1);
135 
136         EXPECT_TRUE(bindGroupLayoutMock.IsAlive());
137         bindGroupLayoutMock.Destroy();
138         EXPECT_FALSE(bindGroupLayoutMock.IsAlive());
139     }
140 
141     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
142     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,BindGroupLayoutImplicit)143     TEST_F(DestroyObjectTests, BindGroupLayoutImplicit) {
144         BindGroupLayoutMock* bindGroupLayoutMock = new BindGroupLayoutMock(&mDevice);
145         EXPECT_CALL(*bindGroupLayoutMock, DestroyImpl).Times(1);
146         {
147             BindGroupLayoutDescriptor desc = {};
148             Ref<BindGroupLayoutBase> bindGroupLayout;
149             EXPECT_CALL(mDevice, CreateBindGroupLayoutImpl)
150                 .WillOnce(Return(ByMove(AcquireRef(bindGroupLayoutMock))));
151             DAWN_ASSERT_AND_ASSIGN(bindGroupLayout, mDevice.CreateBindGroupLayout(&desc));
152 
153             EXPECT_TRUE(bindGroupLayout->IsAlive());
154             EXPECT_TRUE(bindGroupLayout->IsCachedReference());
155         }
156     }
157 
TEST_F(DestroyObjectTests,BufferExplicit)158     TEST_F(DestroyObjectTests, BufferExplicit) {
159         {
160             BufferMock bufferMock(&mDevice, BufferBase::BufferState::Unmapped);
161             EXPECT_CALL(bufferMock, DestroyImpl).Times(1);
162 
163             EXPECT_TRUE(bufferMock.IsAlive());
164             bufferMock.Destroy();
165             EXPECT_FALSE(bufferMock.IsAlive());
166         }
167         {
168             BufferMock bufferMock(&mDevice, BufferBase::BufferState::Mapped);
169             {
170                 InSequence seq;
171                 EXPECT_CALL(bufferMock, DestroyImpl).Times(1);
172                 EXPECT_CALL(bufferMock, UnmapImpl).Times(1);
173             }
174 
175             EXPECT_TRUE(bufferMock.IsAlive());
176             bufferMock.Destroy();
177             EXPECT_FALSE(bufferMock.IsAlive());
178         }
179     }
180 
181     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
182     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,BufferImplicit)183     TEST_F(DestroyObjectTests, BufferImplicit) {
184         {
185             BufferMock* bufferMock = new BufferMock(&mDevice, BufferBase::BufferState::Unmapped);
186             EXPECT_CALL(*bufferMock, DestroyImpl).Times(1);
187             {
188                 BufferDescriptor desc = {};
189                 Ref<BufferBase> buffer;
190                 EXPECT_CALL(mDevice, CreateBufferImpl)
191                     .WillOnce(Return(ByMove(AcquireRef(bufferMock))));
192                 DAWN_ASSERT_AND_ASSIGN(buffer, mDevice.CreateBuffer(&desc));
193 
194                 EXPECT_TRUE(buffer->IsAlive());
195             }
196         }
197         {
198             BufferMock* bufferMock = new BufferMock(&mDevice, BufferBase::BufferState::Mapped);
199             {
200                 InSequence seq;
201                 EXPECT_CALL(*bufferMock, DestroyImpl).Times(1);
202                 EXPECT_CALL(*bufferMock, UnmapImpl).Times(1);
203             }
204             {
205                 BufferDescriptor desc = {};
206                 Ref<BufferBase> buffer;
207                 EXPECT_CALL(mDevice, CreateBufferImpl)
208                     .WillOnce(Return(ByMove(AcquireRef(bufferMock))));
209                 DAWN_ASSERT_AND_ASSIGN(buffer, mDevice.CreateBuffer(&desc));
210 
211                 EXPECT_TRUE(buffer->IsAlive());
212             }
213         }
214     }
215 
TEST_F(DestroyObjectTests,CommandBufferExplicit)216     TEST_F(DestroyObjectTests, CommandBufferExplicit) {
217         CommandBufferMock commandBufferMock(&mDevice);
218         EXPECT_CALL(commandBufferMock, DestroyImpl).Times(1);
219 
220         EXPECT_TRUE(commandBufferMock.IsAlive());
221         commandBufferMock.Destroy();
222         EXPECT_FALSE(commandBufferMock.IsAlive());
223     }
224 
225     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
226     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,CommandBufferImplicit)227     TEST_F(DestroyObjectTests, CommandBufferImplicit) {
228         CommandBufferMock* commandBufferMock = new CommandBufferMock(&mDevice);
229         EXPECT_CALL(*commandBufferMock, DestroyImpl).Times(1);
230         {
231             CommandBufferDescriptor desc = {};
232             Ref<CommandBufferBase> commandBuffer;
233             EXPECT_CALL(mDevice, CreateCommandBuffer)
234                 .WillOnce(Return(ByMove(AcquireRef(commandBufferMock))));
235             DAWN_ASSERT_AND_ASSIGN(commandBuffer, mDevice.CreateCommandBuffer(nullptr, &desc));
236 
237             EXPECT_TRUE(commandBuffer->IsAlive());
238         }
239     }
240 
TEST_F(DestroyObjectTests,ComputePipelineExplicit)241     TEST_F(DestroyObjectTests, ComputePipelineExplicit) {
242         ComputePipelineMock computePipelineMock(&mDevice);
243         EXPECT_CALL(computePipelineMock, DestroyImpl).Times(1);
244 
245         EXPECT_TRUE(computePipelineMock.IsAlive());
246         computePipelineMock.Destroy();
247         EXPECT_FALSE(computePipelineMock.IsAlive());
248     }
249 
250     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
251     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,ComputePipelineImplicit)252     TEST_F(DestroyObjectTests, ComputePipelineImplicit) {
253         // ComputePipelines usually set their hash values at construction, but the mock does not, so
254         // we set it here.
255         constexpr size_t hash = 0x12345;
256         ComputePipelineMock* computePipelineMock = new ComputePipelineMock(&mDevice);
257         computePipelineMock->SetContentHash(hash);
258         ON_CALL(*computePipelineMock, ComputeContentHash).WillByDefault(Return(hash));
259 
260         // Compute pipelines are initialized during their creation via the device.
261         EXPECT_CALL(*computePipelineMock, Initialize).Times(1);
262         EXPECT_CALL(*computePipelineMock, DestroyImpl).Times(1);
263 
264         {
265             ComputePipelineDescriptor desc = {};
266             desc.layout = GetPipelineLayout().Get();
267             desc.compute.module = GetComputeShaderModule().Get();
268 
269             Ref<ComputePipelineBase> computePipeline;
270             EXPECT_CALL(mDevice, CreateUninitializedComputePipelineImpl)
271                 .WillOnce(Return(ByMove(AcquireRef(computePipelineMock))));
272             DAWN_ASSERT_AND_ASSIGN(computePipeline, mDevice.CreateComputePipeline(&desc));
273 
274             EXPECT_TRUE(computePipeline->IsAlive());
275             EXPECT_TRUE(computePipeline->IsCachedReference());
276         }
277     }
278 
TEST_F(DestroyObjectTests,ExternalTextureExplicit)279     TEST_F(DestroyObjectTests, ExternalTextureExplicit) {
280         ExternalTextureMock externalTextureMock(&mDevice);
281         EXPECT_CALL(externalTextureMock, DestroyImpl).Times(1);
282 
283         EXPECT_TRUE(externalTextureMock.IsAlive());
284         externalTextureMock.Destroy();
285         EXPECT_FALSE(externalTextureMock.IsAlive());
286     }
287 
288     // We can use an actual ExternalTexture object to test the implicit case.
TEST_F(DestroyObjectTests,ExternalTextureImplicit)289     TEST_F(DestroyObjectTests, ExternalTextureImplicit) {
290         ExternalTextureDescriptor desc = {};
291         Ref<ExternalTextureBase> externalTexture;
292         DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
293 
294         EXPECT_TRUE(externalTexture->IsAlive());
295     }
296 
TEST_F(DestroyObjectTests,PipelineLayoutExplicit)297     TEST_F(DestroyObjectTests, PipelineLayoutExplicit) {
298         PipelineLayoutMock pipelineLayoutMock(&mDevice);
299         EXPECT_CALL(pipelineLayoutMock, DestroyImpl).Times(1);
300 
301         EXPECT_TRUE(pipelineLayoutMock.IsAlive());
302         pipelineLayoutMock.Destroy();
303         EXPECT_FALSE(pipelineLayoutMock.IsAlive());
304     }
305 
306     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
307     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,PipelineLayoutImplicit)308     TEST_F(DestroyObjectTests, PipelineLayoutImplicit) {
309         PipelineLayoutMock* pipelineLayoutMock = new PipelineLayoutMock(&mDevice);
310         EXPECT_CALL(*pipelineLayoutMock, DestroyImpl).Times(1);
311         {
312             PipelineLayoutDescriptor desc = {};
313             Ref<PipelineLayoutBase> pipelineLayout;
314             EXPECT_CALL(mDevice, CreatePipelineLayoutImpl)
315                 .WillOnce(Return(ByMove(AcquireRef(pipelineLayoutMock))));
316             DAWN_ASSERT_AND_ASSIGN(pipelineLayout, mDevice.CreatePipelineLayout(&desc));
317 
318             EXPECT_TRUE(pipelineLayout->IsAlive());
319             EXPECT_TRUE(pipelineLayout->IsCachedReference());
320         }
321     }
322 
TEST_F(DestroyObjectTests,QuerySetExplicit)323     TEST_F(DestroyObjectTests, QuerySetExplicit) {
324         QuerySetMock querySetMock(&mDevice);
325         EXPECT_CALL(querySetMock, DestroyImpl).Times(1);
326 
327         EXPECT_TRUE(querySetMock.IsAlive());
328         querySetMock.Destroy();
329         EXPECT_FALSE(querySetMock.IsAlive());
330     }
331 
332     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
333     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,QuerySetImplicit)334     TEST_F(DestroyObjectTests, QuerySetImplicit) {
335         QuerySetMock* querySetMock = new QuerySetMock(&mDevice);
336         EXPECT_CALL(*querySetMock, DestroyImpl).Times(1);
337         {
338             QuerySetDescriptor desc = {};
339             Ref<QuerySetBase> querySet;
340             EXPECT_CALL(mDevice, CreateQuerySetImpl)
341                 .WillOnce(Return(ByMove(AcquireRef(querySetMock))));
342             DAWN_ASSERT_AND_ASSIGN(querySet, mDevice.CreateQuerySet(&desc));
343 
344             EXPECT_TRUE(querySet->IsAlive());
345         }
346     }
347 
TEST_F(DestroyObjectTests,RenderPipelineExplicit)348     TEST_F(DestroyObjectTests, RenderPipelineExplicit) {
349         RenderPipelineMock renderPipelineMock(&mDevice);
350         EXPECT_CALL(renderPipelineMock, DestroyImpl).Times(1);
351 
352         EXPECT_TRUE(renderPipelineMock.IsAlive());
353         renderPipelineMock.Destroy();
354         EXPECT_FALSE(renderPipelineMock.IsAlive());
355     }
356 
357     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
358     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,RenderPipelineImplicit)359     TEST_F(DestroyObjectTests, RenderPipelineImplicit) {
360         // RenderPipelines usually set their hash values at construction, but the mock does not, so
361         // we set it here.
362         constexpr size_t hash = 0x12345;
363         RenderPipelineMock* renderPipelineMock = new RenderPipelineMock(&mDevice);
364         renderPipelineMock->SetContentHash(hash);
365         ON_CALL(*renderPipelineMock, ComputeContentHash).WillByDefault(Return(hash));
366 
367         // Render pipelines are initialized during their creation via the device.
368         EXPECT_CALL(*renderPipelineMock, Initialize).Times(1);
369         EXPECT_CALL(*renderPipelineMock, DestroyImpl).Times(1);
370 
371         {
372             RenderPipelineDescriptor desc = {};
373             desc.layout = GetPipelineLayout().Get();
374             desc.vertex.module = GetVertexShaderModule().Get();
375 
376             Ref<RenderPipelineBase> renderPipeline;
377             EXPECT_CALL(mDevice, CreateUninitializedRenderPipelineImpl)
378                 .WillOnce(Return(ByMove(AcquireRef(renderPipelineMock))));
379             DAWN_ASSERT_AND_ASSIGN(renderPipeline, mDevice.CreateRenderPipeline(&desc));
380 
381             EXPECT_TRUE(renderPipeline->IsAlive());
382             EXPECT_TRUE(renderPipeline->IsCachedReference());
383         }
384     }
385 
TEST_F(DestroyObjectTests,SamplerExplicit)386     TEST_F(DestroyObjectTests, SamplerExplicit) {
387         SamplerMock samplerMock(&mDevice);
388         EXPECT_CALL(samplerMock, DestroyImpl).Times(1);
389 
390         EXPECT_TRUE(samplerMock.IsAlive());
391         samplerMock.Destroy();
392         EXPECT_FALSE(samplerMock.IsAlive());
393     }
394 
395     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
396     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,SamplerImplicit)397     TEST_F(DestroyObjectTests, SamplerImplicit) {
398         SamplerMock* samplerMock = new SamplerMock(&mDevice);
399         EXPECT_CALL(*samplerMock, DestroyImpl).Times(1);
400         {
401             SamplerDescriptor desc = {};
402             Ref<SamplerBase> sampler;
403             EXPECT_CALL(mDevice, CreateSamplerImpl)
404                 .WillOnce(Return(ByMove(AcquireRef(samplerMock))));
405             DAWN_ASSERT_AND_ASSIGN(sampler, mDevice.CreateSampler(&desc));
406 
407             EXPECT_TRUE(sampler->IsAlive());
408             EXPECT_TRUE(sampler->IsCachedReference());
409         }
410     }
411 
TEST_F(DestroyObjectTests,ShaderModuleExplicit)412     TEST_F(DestroyObjectTests, ShaderModuleExplicit) {
413         ShaderModuleMock shaderModuleMock(&mDevice);
414         EXPECT_CALL(shaderModuleMock, DestroyImpl).Times(1);
415 
416         EXPECT_TRUE(shaderModuleMock.IsAlive());
417         shaderModuleMock.Destroy();
418         EXPECT_FALSE(shaderModuleMock.IsAlive());
419     }
420 
421     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
422     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,ShaderModuleImplicit)423     TEST_F(DestroyObjectTests, ShaderModuleImplicit) {
424         ShaderModuleMock* shaderModuleMock = new ShaderModuleMock(&mDevice);
425         EXPECT_CALL(*shaderModuleMock, DestroyImpl).Times(1);
426         {
427             ShaderModuleWGSLDescriptor wgslDesc;
428             wgslDesc.source = R"(
429                 [[stage(compute), workgroup_size(1)]] fn main() {
430                 }
431             )";
432             ShaderModuleDescriptor desc = {};
433             desc.nextInChain = &wgslDesc;
434             Ref<ShaderModuleBase> shaderModule;
435             EXPECT_CALL(mDevice, CreateShaderModuleImpl)
436                 .WillOnce(Return(ByMove(AcquireRef(shaderModuleMock))));
437             DAWN_ASSERT_AND_ASSIGN(shaderModule, mDevice.CreateShaderModule(&desc));
438 
439             EXPECT_TRUE(shaderModule->IsAlive());
440             EXPECT_TRUE(shaderModule->IsCachedReference());
441         }
442     }
443 
TEST_F(DestroyObjectTests,SwapChainExplicit)444     TEST_F(DestroyObjectTests, SwapChainExplicit) {
445         SwapChainMock swapChainMock(&mDevice);
446         EXPECT_CALL(swapChainMock, DestroyImpl).Times(1);
447 
448         EXPECT_TRUE(swapChainMock.IsAlive());
449         swapChainMock.Destroy();
450         EXPECT_FALSE(swapChainMock.IsAlive());
451     }
452 
453     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
454     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,SwapChainImplicit)455     TEST_F(DestroyObjectTests, SwapChainImplicit) {
456         SwapChainMock* swapChainMock = new SwapChainMock(&mDevice);
457         EXPECT_CALL(*swapChainMock, DestroyImpl).Times(1);
458         {
459             SwapChainDescriptor desc = {};
460             Ref<SwapChainBase> swapChain;
461             EXPECT_CALL(mDevice, CreateSwapChainImpl(_))
462                 .WillOnce(Return(ByMove(AcquireRef(swapChainMock))));
463             DAWN_ASSERT_AND_ASSIGN(swapChain, mDevice.CreateSwapChain(nullptr, &desc));
464 
465             EXPECT_TRUE(swapChain->IsAlive());
466         }
467     }
468 
TEST_F(DestroyObjectTests,TextureExplicit)469     TEST_F(DestroyObjectTests, TextureExplicit) {
470         {
471             TextureMock textureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
472             EXPECT_CALL(textureMock, DestroyImpl).Times(1);
473 
474             EXPECT_TRUE(textureMock.IsAlive());
475             textureMock.Destroy();
476             EXPECT_FALSE(textureMock.IsAlive());
477         }
478         {
479             TextureMock textureMock(&mDevice, TextureBase::TextureState::OwnedExternal);
480             EXPECT_CALL(textureMock, DestroyImpl).Times(1);
481 
482             EXPECT_TRUE(textureMock.IsAlive());
483             textureMock.Destroy();
484             EXPECT_FALSE(textureMock.IsAlive());
485         }
486     }
487 
488     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
489     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,TextureImplicit)490     TEST_F(DestroyObjectTests, TextureImplicit) {
491         {
492             TextureMock* textureMock =
493                 new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
494             EXPECT_CALL(*textureMock, DestroyImpl).Times(1);
495             {
496                 TextureDescriptor desc = {};
497                 Ref<TextureBase> texture;
498                 EXPECT_CALL(mDevice, CreateTextureImpl)
499                     .WillOnce(Return(ByMove(AcquireRef(textureMock))));
500                 DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
501 
502                 EXPECT_TRUE(texture->IsAlive());
503             }
504         }
505         {
506             TextureMock* textureMock =
507                 new TextureMock(&mDevice, TextureBase::TextureState::OwnedExternal);
508             EXPECT_CALL(*textureMock, DestroyImpl).Times(1);
509             {
510                 TextureDescriptor desc = {};
511                 Ref<TextureBase> texture;
512                 EXPECT_CALL(mDevice, CreateTextureImpl)
513                     .WillOnce(Return(ByMove(AcquireRef(textureMock))));
514                 DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
515 
516                 EXPECT_TRUE(texture->IsAlive());
517             }
518         }
519     }
520 
TEST_F(DestroyObjectTests,TextureViewExplicit)521     TEST_F(DestroyObjectTests, TextureViewExplicit) {
522         TextureViewMock textureViewMock(GetTexture().Get());
523         EXPECT_CALL(textureViewMock, DestroyImpl).Times(1);
524 
525         EXPECT_TRUE(textureViewMock.IsAlive());
526         textureViewMock.Destroy();
527         EXPECT_FALSE(textureViewMock.IsAlive());
528     }
529 
530     // If the reference count on API objects reach 0, they should delete themselves. Note that GTest
531     // will also complain if there is a memory leak.
TEST_F(DestroyObjectTests,TextureViewImplicit)532     TEST_F(DestroyObjectTests, TextureViewImplicit) {
533         TextureViewMock* textureViewMock = new TextureViewMock(GetTexture().Get());
534         EXPECT_CALL(*textureViewMock, DestroyImpl).Times(1);
535         {
536             TextureViewDescriptor desc = {};
537             Ref<TextureViewBase> textureView;
538             EXPECT_CALL(mDevice, CreateTextureViewImpl)
539                 .WillOnce(Return(ByMove(AcquireRef(textureViewMock))));
540             DAWN_ASSERT_AND_ASSIGN(textureView,
541                                    mDevice.CreateTextureView(GetTexture().Get(), &desc));
542 
543             EXPECT_TRUE(textureView->IsAlive());
544         }
545     }
546 
547     // Destroying the objects on the mDevice should result in all created objects being destroyed in
548     // order.
TEST_F(DestroyObjectTests,DestroyObjects)549     TEST_F(DestroyObjectTests, DestroyObjects) {
550         BindGroupMock* bindGroupMock = new BindGroupMock(&mDevice);
551         BindGroupLayoutMock* bindGroupLayoutMock = new BindGroupLayoutMock(&mDevice);
552         BufferMock* bufferMock = new BufferMock(&mDevice, BufferBase::BufferState::Unmapped);
553         CommandBufferMock* commandBufferMock = new CommandBufferMock(&mDevice);
554         ComputePipelineMock* computePipelineMock = new ComputePipelineMock(&mDevice);
555         PipelineLayoutMock* pipelineLayoutMock = new PipelineLayoutMock(&mDevice);
556         QuerySetMock* querySetMock = new QuerySetMock(&mDevice);
557         RenderPipelineMock* renderPipelineMock = new RenderPipelineMock(&mDevice);
558         SamplerMock* samplerMock = new SamplerMock(&mDevice);
559         ShaderModuleMock* shaderModuleMock = new ShaderModuleMock(&mDevice);
560         SwapChainMock* swapChainMock = new SwapChainMock(&mDevice);
561         TextureMock* textureMock =
562             new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
563         TextureViewMock* textureViewMock = new TextureViewMock(GetTexture().Get());
564         {
565             InSequence seq;
566             EXPECT_CALL(*commandBufferMock, DestroyImpl).Times(1);
567             EXPECT_CALL(*renderPipelineMock, DestroyImpl).Times(1);
568             EXPECT_CALL(*computePipelineMock, DestroyImpl).Times(1);
569             EXPECT_CALL(*pipelineLayoutMock, DestroyImpl).Times(1);
570             EXPECT_CALL(*swapChainMock, DestroyImpl).Times(1);
571             EXPECT_CALL(*bindGroupMock, DestroyImpl).Times(1);
572             EXPECT_CALL(*bindGroupLayoutMock, DestroyImpl).Times(1);
573             EXPECT_CALL(*shaderModuleMock, DestroyImpl).Times(1);
574             EXPECT_CALL(*textureViewMock, DestroyImpl).Times(1);
575             EXPECT_CALL(*textureMock, DestroyImpl).Times(1);
576             EXPECT_CALL(*querySetMock, DestroyImpl).Times(1);
577             EXPECT_CALL(*samplerMock, DestroyImpl).Times(1);
578             EXPECT_CALL(*bufferMock, DestroyImpl).Times(1);
579         }
580 
581         Ref<BindGroupBase> bindGroup;
582         {
583             BindGroupDescriptor desc = {};
584             EXPECT_CALL(mDevice, CreateBindGroupImpl)
585                 .WillOnce(Return(ByMove(AcquireRef(bindGroupMock))));
586             DAWN_ASSERT_AND_ASSIGN(bindGroup, mDevice.CreateBindGroup(&desc));
587             EXPECT_TRUE(bindGroup->IsAlive());
588         }
589 
590         Ref<BindGroupLayoutBase> bindGroupLayout;
591         {
592             BindGroupLayoutDescriptor desc = {};
593             EXPECT_CALL(mDevice, CreateBindGroupLayoutImpl)
594                 .WillOnce(Return(ByMove(AcquireRef(bindGroupLayoutMock))));
595             DAWN_ASSERT_AND_ASSIGN(bindGroupLayout, mDevice.CreateBindGroupLayout(&desc));
596             EXPECT_TRUE(bindGroupLayout->IsAlive());
597             EXPECT_TRUE(bindGroupLayout->IsCachedReference());
598         }
599 
600         Ref<BufferBase> buffer;
601         {
602             BufferDescriptor desc = {};
603             EXPECT_CALL(mDevice, CreateBufferImpl).WillOnce(Return(ByMove(AcquireRef(bufferMock))));
604             DAWN_ASSERT_AND_ASSIGN(buffer, mDevice.CreateBuffer(&desc));
605             EXPECT_TRUE(buffer->IsAlive());
606         }
607 
608         Ref<CommandBufferBase> commandBuffer;
609         {
610             CommandBufferDescriptor desc = {};
611             EXPECT_CALL(mDevice, CreateCommandBuffer)
612                 .WillOnce(Return(ByMove(AcquireRef(commandBufferMock))));
613             DAWN_ASSERT_AND_ASSIGN(commandBuffer, mDevice.CreateCommandBuffer(nullptr, &desc));
614             EXPECT_TRUE(commandBuffer->IsAlive());
615         }
616 
617         Ref<ComputePipelineBase> computePipeline;
618         {
619             // Compute pipelines usually set their hash values at construction, but the mock does
620             // not, so we set it here.
621             constexpr size_t hash = 0x12345;
622             computePipelineMock->SetContentHash(hash);
623             ON_CALL(*computePipelineMock, ComputeContentHash).WillByDefault(Return(hash));
624 
625             // Compute pipelines are initialized during their creation via the device.
626             EXPECT_CALL(*computePipelineMock, Initialize).Times(1);
627 
628             ComputePipelineDescriptor desc = {};
629             desc.layout = GetPipelineLayout().Get();
630             desc.compute.module = GetComputeShaderModule().Get();
631             EXPECT_CALL(mDevice, CreateUninitializedComputePipelineImpl)
632                 .WillOnce(Return(ByMove(AcquireRef(computePipelineMock))));
633             DAWN_ASSERT_AND_ASSIGN(computePipeline, mDevice.CreateComputePipeline(&desc));
634             EXPECT_TRUE(computePipeline->IsAlive());
635             EXPECT_TRUE(computePipeline->IsCachedReference());
636         }
637 
638         Ref<ExternalTextureBase> externalTexture;
639         {
640             ExternalTextureDescriptor desc = {};
641             DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
642             EXPECT_TRUE(externalTexture->IsAlive());
643         }
644 
645         Ref<PipelineLayoutBase> pipelineLayout;
646         {
647             PipelineLayoutDescriptor desc = {};
648             EXPECT_CALL(mDevice, CreatePipelineLayoutImpl)
649                 .WillOnce(Return(ByMove(AcquireRef(pipelineLayoutMock))));
650             DAWN_ASSERT_AND_ASSIGN(pipelineLayout, mDevice.CreatePipelineLayout(&desc));
651             EXPECT_TRUE(pipelineLayout->IsAlive());
652             EXPECT_TRUE(pipelineLayout->IsCachedReference());
653         }
654 
655         Ref<QuerySetBase> querySet;
656         {
657             QuerySetDescriptor desc = {};
658             EXPECT_CALL(mDevice, CreateQuerySetImpl)
659                 .WillOnce(Return(ByMove(AcquireRef(querySetMock))));
660             DAWN_ASSERT_AND_ASSIGN(querySet, mDevice.CreateQuerySet(&desc));
661             EXPECT_TRUE(querySet->IsAlive());
662         }
663 
664         Ref<RenderPipelineBase> renderPipeline;
665         {
666             // Render pipelines usually set their hash values at construction, but the mock does
667             // not, so we set it here.
668             constexpr size_t hash = 0x12345;
669             renderPipelineMock->SetContentHash(hash);
670             ON_CALL(*renderPipelineMock, ComputeContentHash).WillByDefault(Return(hash));
671 
672             // Render pipelines are initialized during their creation via the device.
673             EXPECT_CALL(*renderPipelineMock, Initialize).Times(1);
674 
675             RenderPipelineDescriptor desc = {};
676             desc.layout = GetPipelineLayout().Get();
677             desc.vertex.module = GetVertexShaderModule().Get();
678             EXPECT_CALL(mDevice, CreateUninitializedRenderPipelineImpl)
679                 .WillOnce(Return(ByMove(AcquireRef(renderPipelineMock))));
680             DAWN_ASSERT_AND_ASSIGN(renderPipeline, mDevice.CreateRenderPipeline(&desc));
681             EXPECT_TRUE(renderPipeline->IsAlive());
682             EXPECT_TRUE(renderPipeline->IsCachedReference());
683         }
684 
685         Ref<SamplerBase> sampler;
686         {
687             SamplerDescriptor desc = {};
688             EXPECT_CALL(mDevice, CreateSamplerImpl)
689                 .WillOnce(Return(ByMove(AcquireRef(samplerMock))));
690             DAWN_ASSERT_AND_ASSIGN(sampler, mDevice.CreateSampler(&desc));
691             EXPECT_TRUE(sampler->IsAlive());
692             EXPECT_TRUE(sampler->IsCachedReference());
693         }
694 
695         Ref<ShaderModuleBase> shaderModule;
696         {
697             ShaderModuleWGSLDescriptor wgslDesc;
698             wgslDesc.source = R"(
699                 [[stage(compute), workgroup_size(1)]] fn main() {
700                 }
701             )";
702             ShaderModuleDescriptor desc = {};
703             desc.nextInChain = &wgslDesc;
704 
705             EXPECT_CALL(mDevice, CreateShaderModuleImpl)
706                 .WillOnce(Return(ByMove(AcquireRef(shaderModuleMock))));
707             DAWN_ASSERT_AND_ASSIGN(shaderModule, mDevice.CreateShaderModule(&desc));
708             EXPECT_TRUE(shaderModule->IsAlive());
709             EXPECT_TRUE(shaderModule->IsCachedReference());
710         }
711 
712         Ref<SwapChainBase> swapChain;
713         {
714             SwapChainDescriptor desc = {};
715             EXPECT_CALL(mDevice, CreateSwapChainImpl(_))
716                 .WillOnce(Return(ByMove(AcquireRef(swapChainMock))));
717             DAWN_ASSERT_AND_ASSIGN(swapChain, mDevice.CreateSwapChain(nullptr, &desc));
718             EXPECT_TRUE(swapChain->IsAlive());
719         }
720 
721         Ref<TextureBase> texture;
722         {
723             TextureDescriptor desc = {};
724             EXPECT_CALL(mDevice, CreateTextureImpl)
725                 .WillOnce(Return(ByMove(AcquireRef(textureMock))));
726             DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
727             EXPECT_TRUE(texture->IsAlive());
728         }
729 
730         Ref<TextureViewBase> textureView;
731         {
732             TextureViewDescriptor desc = {};
733             EXPECT_CALL(mDevice, CreateTextureViewImpl)
734                 .WillOnce(Return(ByMove(AcquireRef(textureViewMock))));
735             DAWN_ASSERT_AND_ASSIGN(textureView,
736                                    mDevice.CreateTextureView(GetTexture().Get(), &desc));
737             EXPECT_TRUE(textureView->IsAlive());
738         }
739 
740         mDevice.DestroyObjects();
741         EXPECT_FALSE(bindGroup->IsAlive());
742         EXPECT_FALSE(bindGroupLayout->IsAlive());
743         EXPECT_FALSE(buffer->IsAlive());
744         EXPECT_FALSE(commandBuffer->IsAlive());
745         EXPECT_FALSE(computePipeline->IsAlive());
746         EXPECT_FALSE(externalTexture->IsAlive());
747         EXPECT_FALSE(pipelineLayout->IsAlive());
748         EXPECT_FALSE(querySet->IsAlive());
749         EXPECT_FALSE(renderPipeline->IsAlive());
750         EXPECT_FALSE(sampler->IsAlive());
751         EXPECT_FALSE(shaderModule->IsAlive());
752         EXPECT_FALSE(swapChain->IsAlive());
753         EXPECT_FALSE(texture->IsAlive());
754         EXPECT_FALSE(textureView->IsAlive());
755     }
756 
757 }}  // namespace dawn_native::
758