1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 #include "common/MemoryBuffer.h"
8 
9 #include <algorithm>
10 #include <cstdlib>
11 
12 #include "common/debug.h"
13 
14 namespace angle
15 {
16 
17 // MemoryBuffer implementation.
~MemoryBuffer()18 MemoryBuffer::~MemoryBuffer()
19 {
20     if (mData)
21     {
22         free(mData);
23         mData = nullptr;
24     }
25 }
26 
resize(size_t size)27 bool MemoryBuffer::resize(size_t size)
28 {
29     if (size == 0)
30     {
31         if (mData)
32         {
33             free(mData);
34             mData = nullptr;
35         }
36         mSize = 0;
37         return true;
38     }
39 
40     if (size == mSize)
41     {
42         return true;
43     }
44 
45     // Only reallocate if the size has changed.
46     uint8_t *newMemory = static_cast<uint8_t *>(malloc(sizeof(uint8_t) * size));
47     if (newMemory == nullptr)
48     {
49         return false;
50     }
51 
52     if (mData)
53     {
54         // Copy the intersection of the old data and the new data
55         std::copy(mData, mData + std::min(mSize, size), newMemory);
56         free(mData);
57     }
58 
59     mData = newMemory;
60     mSize = size;
61 
62     return true;
63 }
64 
fill(uint8_t datum)65 void MemoryBuffer::fill(uint8_t datum)
66 {
67     if (!empty())
68     {
69         std::fill(mData, mData + mSize, datum);
70     }
71 }
72 
MemoryBuffer(MemoryBuffer && other)73 MemoryBuffer::MemoryBuffer(MemoryBuffer &&other) : MemoryBuffer()
74 {
75     *this = std::move(other);
76 }
77 
operator =(MemoryBuffer && other)78 MemoryBuffer &MemoryBuffer::operator=(MemoryBuffer &&other)
79 {
80     std::swap(mSize, other.mSize);
81     std::swap(mData, other.mData);
82     return *this;
83 }
84 
85 namespace
86 {
87 static constexpr uint32_t kDefaultScratchBufferLifetime = 1000u;
88 
89 }  // anonymous namespace
90 
91 // ScratchBuffer implementation.
ScratchBuffer()92 ScratchBuffer::ScratchBuffer() : ScratchBuffer(kDefaultScratchBufferLifetime) {}
93 
ScratchBuffer(uint32_t lifetime)94 ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) {}
95 
~ScratchBuffer()96 ScratchBuffer::~ScratchBuffer() {}
97 
ScratchBuffer(ScratchBuffer && other)98 ScratchBuffer::ScratchBuffer(ScratchBuffer &&other)
99 {
100     *this = std::move(other);
101 }
102 
operator =(ScratchBuffer && other)103 ScratchBuffer &ScratchBuffer::operator=(ScratchBuffer &&other)
104 {
105     std::swap(mLifetime, other.mLifetime);
106     std::swap(mResetCounter, other.mResetCounter);
107     std::swap(mScratchMemory, other.mScratchMemory);
108     return *this;
109 }
110 
get(size_t requestedSize,MemoryBuffer ** memoryBufferOut)111 bool ScratchBuffer::get(size_t requestedSize, MemoryBuffer **memoryBufferOut)
112 {
113     return getImpl(requestedSize, memoryBufferOut, Optional<uint8_t>::Invalid());
114 }
115 
getInitialized(size_t requestedSize,MemoryBuffer ** memoryBufferOut,uint8_t initValue)116 bool ScratchBuffer::getInitialized(size_t requestedSize,
117                                    MemoryBuffer **memoryBufferOut,
118                                    uint8_t initValue)
119 {
120     return getImpl(requestedSize, memoryBufferOut, Optional<uint8_t>(initValue));
121 }
122 
getImpl(size_t requestedSize,MemoryBuffer ** memoryBufferOut,Optional<uint8_t> initValue)123 bool ScratchBuffer::getImpl(size_t requestedSize,
124                             MemoryBuffer **memoryBufferOut,
125                             Optional<uint8_t> initValue)
126 {
127     if (mScratchMemory.size() == requestedSize)
128     {
129         mResetCounter    = mLifetime;
130         *memoryBufferOut = &mScratchMemory;
131         return true;
132     }
133 
134     if (mScratchMemory.size() > requestedSize)
135     {
136         tick();
137     }
138 
139     if (mScratchMemory.size() < requestedSize)
140     {
141         if (!mScratchMemory.resize(requestedSize))
142         {
143             return false;
144         }
145         mResetCounter = mLifetime;
146         if (initValue.valid())
147         {
148             mScratchMemory.fill(initValue.value());
149         }
150     }
151 
152     ASSERT(mScratchMemory.size() >= requestedSize);
153 
154     *memoryBufferOut = &mScratchMemory;
155     return true;
156 }
157 
tick()158 void ScratchBuffer::tick()
159 {
160     if (mResetCounter > 0)
161     {
162         --mResetCounter;
163         if (mResetCounter == 0)
164         {
165             clear();
166         }
167     }
168 }
169 
clear()170 void ScratchBuffer::clear()
171 {
172     mResetCounter = mLifetime;
173     if (mScratchMemory.size() > 0)
174     {
175         mScratchMemory.clear();
176     }
177 }
178 
179 }  // namespace angle
180