• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/null/DeviceNull.h"
18 
19 using namespace dawn_native;
20 
21 namespace {
22 
ValidateValidUploadHandle(const UploadHandle & uploadHandle)23     size_t ValidateValidUploadHandle(const UploadHandle& uploadHandle) {
24         ASSERT(uploadHandle.mappedBuffer != nullptr);
25         return uploadHandle.startOffset;
26     }
27 
ValidateInvalidUploadHandle(const UploadHandle & uploadHandle)28     void ValidateInvalidUploadHandle(const UploadHandle& uploadHandle) {
29         ASSERT_EQ(uploadHandle.mappedBuffer, nullptr);
30     }
31 }  // namespace
32 
33 class RingBufferTests : public testing::Test {
34   protected:
SetUp()35     void SetUp() override {
36         // TODO(bryan.bernhart@intel.com): Create this device through the adapter.
37         mDevice = std::make_unique<null::Device>(/*adapter*/ nullptr, /*deviceDescriptor*/ nullptr);
38     }
39 
GetDevice() const40     null::Device* GetDevice() const {
41         return mDevice.get();
42     }
43 
CreateRingBuffer(size_t size)44     std::unique_ptr<RingBuffer> CreateRingBuffer(size_t size) {
45         std::unique_ptr<RingBuffer> ringBuffer = std::make_unique<RingBuffer>(mDevice.get(), size);
46         DAWN_UNUSED(ringBuffer->Initialize());
47         return ringBuffer;
48     }
49 
50   private:
51     std::unique_ptr<null::Device> mDevice;
52 };
53 
54 // Number of basic tests for Ringbuffer
TEST_F(RingBufferTests,BasicTest)55 TEST_F(RingBufferTests, BasicTest) {
56     constexpr size_t sizeInBytes = 64000;
57     std::unique_ptr<RingBuffer> buffer = CreateRingBuffer(sizeInBytes);
58 
59     // Ensure no requests exist on empty buffer.
60     EXPECT_TRUE(buffer->Empty());
61 
62     ASSERT_EQ(buffer->GetSize(), sizeInBytes);
63 
64     // Ensure failure upon sub-allocating an oversized request.
65     ValidateInvalidUploadHandle(buffer->SubAllocate(sizeInBytes + 1));
66 
67     // Fill the entire buffer with two requests of equal size.
68     ValidateValidUploadHandle(buffer->SubAllocate(sizeInBytes / 2));
69     ValidateValidUploadHandle(buffer->SubAllocate(sizeInBytes / 2));
70 
71     // Ensure the buffer is full.
72     ValidateInvalidUploadHandle(buffer->SubAllocate(1));
73 }
74 
75 // Tests that several ringbuffer allocations do not fail.
TEST_F(RingBufferTests,RingBufferManyAlloc)76 TEST_F(RingBufferTests, RingBufferManyAlloc) {
77     constexpr size_t maxNumOfFrames = 64000;
78     constexpr size_t frameSizeInBytes = 4;
79 
80     std::unique_ptr<RingBuffer> buffer = CreateRingBuffer(maxNumOfFrames * frameSizeInBytes);
81 
82     size_t offset = 0;
83     for (size_t i = 0; i < maxNumOfFrames; ++i) {
84         offset = ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
85         GetDevice()->Tick();
86         ASSERT_EQ(offset, i * frameSizeInBytes);
87     }
88 }
89 
90 // Tests ringbuffer sub-allocations of the same serial are correctly tracked.
TEST_F(RingBufferTests,AllocInSameFrame)91 TEST_F(RingBufferTests, AllocInSameFrame) {
92     constexpr size_t maxNumOfFrames = 3;
93     constexpr size_t frameSizeInBytes = 4;
94 
95     std::unique_ptr<RingBuffer> buffer = CreateRingBuffer(maxNumOfFrames * frameSizeInBytes);
96 
97     //    F1
98     //  [xxxx|--------]
99 
100     ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
101     GetDevice()->Tick();
102 
103     //    F1   F2
104     //  [xxxx|xxxx|----]
105 
106     ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
107 
108     //    F1     F2
109     //  [xxxx|xxxxxxxx]
110 
111     size_t offset = ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
112 
113     ASSERT_EQ(offset, 8u);
114     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * 3);
115 
116     buffer->Tick(1);
117 
118     // Used size does not change as previous sub-allocations were not tracked.
119     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * 3);
120 
121     buffer->Tick(2);
122 
123     ASSERT_EQ(buffer->GetUsedSize(), 0u);
124     EXPECT_TRUE(buffer->Empty());
125 }
126 
127 // Tests ringbuffer sub-allocation at various offsets.
TEST_F(RingBufferTests,RingBufferSubAlloc)128 TEST_F(RingBufferTests, RingBufferSubAlloc) {
129     constexpr size_t maxNumOfFrames = 10;
130     constexpr size_t frameSizeInBytes = 4;
131 
132     std::unique_ptr<RingBuffer> buffer = CreateRingBuffer(maxNumOfFrames * frameSizeInBytes);
133 
134     // Sub-alloc the first eight frames.
135     for (size_t i = 0; i < 8; ++i) {
136         ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
137         buffer->Track();
138         GetDevice()->Tick();
139     }
140 
141     // Each frame corrresponds to the serial number (for simplicity).
142     //
143     //    F1   F2   F3   F4   F5   F6   F7   F8
144     //  [xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|--------]
145     //
146 
147     // Ensure an oversized allocation fails (only 8 bytes left)
148     ValidateInvalidUploadHandle(buffer->SubAllocate(frameSizeInBytes * 3));
149     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * 8);
150 
151     // Reclaim the first 3 frames.
152     buffer->Tick(3);
153 
154     //                 F4   F5   F6   F7   F8
155     //  [------------|xxxx|xxxx|xxxx|xxxx|xxxx|--------]
156     //
157     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * 5);
158 
159     // Re-try the over-sized allocation.
160     size_t offset = ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes * 3));
161 
162     //        F9       F4   F5   F6   F7   F8
163     //  [xxxxxxxxxxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxxxxxx]
164     //                                         ^^^^^^^^ wasted
165 
166     // In this example, Tick(8) could not reclaim the wasted bytes. The wasted bytes
167     // were add to F9's sub-allocation.
168     // TODO(bryan.bernhart@intel.com): Decide if Tick(8) should free these wasted bytes.
169 
170     ASSERT_EQ(offset, 0u);
171     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * maxNumOfFrames);
172 
173     // Ensure we are full.
174     ValidateInvalidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
175 
176     // Reclaim the next two frames.
177     buffer->Tick(5);
178 
179     //        F9       F4   F5   F6   F7   F8
180     //  [xxxxxxxxxxxx|----|----|xxxx|xxxx|xxxx|xxxxxxxx]
181     //
182     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * 8);
183 
184     // Sub-alloc the chunk in the middle.
185     offset = ValidateValidUploadHandle(buffer->SubAllocate(frameSizeInBytes * 2));
186 
187     ASSERT_EQ(offset, frameSizeInBytes * 3);
188     ASSERT_EQ(buffer->GetUsedSize(), frameSizeInBytes * maxNumOfFrames);
189 
190     //        F9                 F6   F7   F8
191     //  [xxxxxxxxxxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxxxxxx]
192     //                ^^^^^^^^^ untracked
193 
194     // Ensure we are full.
195     ValidateInvalidUploadHandle(buffer->SubAllocate(frameSizeInBytes));
196 
197     // Reclaim all.
198     buffer->Tick(maxNumOfFrames);
199 
200     EXPECT_TRUE(buffer->Empty());
201 }
202