• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #ifndef skgpu_AsyncReadTypes_DEFINED
8 #define skgpu_AsyncReadTypes_DEFINED
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkImage.h"
12 #include "include/private/base/SkTArray.h"
13 #include "src/core/SkMessageBus.h"
14 #include <algorithm>
15 #include <forward_list>
16 
17 namespace skgpu {
18 /**
19  * We sometimes hand clients objects that contain mapped buffers. The client may consume
20  * the mapped buffer on another thread. This object manages receiving messages that buffers are
21  * ready to be unmapped (on the owner's thread). It also handles cleaning up mapped
22  * buffers if the owner is destroyed before the client has finished with the buffer.
23  *
24  * Buffers are first registered using insert() before being passed the client. process() should be
25  * called periodically on the owner's thread to poll for messages and process them.
26  */
27 template <typename T, typename IDType>
28 class TClientMappedBufferManager {
29 public:
30     /**
31      * The message type that internal users of this should post to unmap the buffer.
32      * Set fInboxID to inboxID(). fBuffer must have been previously passed to insert().
33      */
34     struct BufferFinishedMessage {
BufferFinishedMessageBufferFinishedMessage35         BufferFinishedMessage(sk_sp<T> buffer,
36                               IDType intendedRecipient)
37                 : fBuffer(std::move(buffer)), fIntendedRecipient(intendedRecipient) {}
BufferFinishedMessageBufferFinishedMessage38         BufferFinishedMessage(BufferFinishedMessage&& other) {
39             fBuffer = std::move(other.fBuffer);
40             fIntendedRecipient = other.fIntendedRecipient;
41             other.fIntendedRecipient.makeInvalid();
42         }
43         sk_sp<T> fBuffer;
44         IDType   fIntendedRecipient;
45     };
46     using BufferFinishedMessageBus = SkMessageBus<BufferFinishedMessage,
47                                                   IDType,
48                                                   false>;
49 
TClientMappedBufferManager(IDType ownerID)50     TClientMappedBufferManager(IDType ownerID)
51             : fFinishedBufferInbox(ownerID) {}
52     TClientMappedBufferManager(const TClientMappedBufferManager&) = delete;
53     TClientMappedBufferManager(TClientMappedBufferManager&&) = delete;
54 
~TClientMappedBufferManager()55     ~TClientMappedBufferManager() {
56         this->process();
57         if (!fAbandoned) {
58             // If we're going down before we got the messages we go ahead and unmap all the buffers.
59             // It's up to the client to ensure that they aren't being accessed on another thread
60             // while this is happening (or afterwards on any thread).
61             for (auto& b : fClientHeldBuffers) {
62                 b->unmap();
63             }
64         }
65     }
66 
67     TClientMappedBufferManager& operator=(const TClientMappedBufferManager&) = delete;
68     TClientMappedBufferManager& operator=(TClientMappedBufferManager&&) = delete;
69 
70     /** Initialize BufferFinishedMessage::fIntendedRecipient to this value. It is the
71      *  unique ID of the object that owns this buffer manager.
72      */
ownerID()73     IDType ownerID() const {
74         return fFinishedBufferInbox.uniqueID();
75     }
76 
77     /**
78      * Let the manager know to expect a message with buffer 'b'. It's illegal for a buffer to be
79      * inserted again before it is unmapped by process().
80      */
insert(sk_sp<T> b)81     void insert(sk_sp<T> b) {
82         SkDEBUGCODE(auto end = fClientHeldBuffers.end());
83         SkASSERT(std::find(fClientHeldBuffers.begin(), end, b) == end);
84         fClientHeldBuffers.emplace_front(std::move(b));
85     }
86 
87     /** Poll for messages and unmap any incoming buffers. */
process()88     void process() {
89         SkSTArray<4, BufferFinishedMessage> messages;
90         fFinishedBufferInbox.poll(&messages);
91         if (!fAbandoned) {
92             for (auto& m : messages) {
93                 this->remove(m.fBuffer);
94                 m.fBuffer->unmap();
95             }
96         }
97     }
98 
99     /** Notifies the manager that the context has been abandoned. No more unmaps() will occur.*/
abandon()100     void abandon() {
101         fAbandoned = true;
102         fClientHeldBuffers.clear();
103     }
104 
105 private:
106     typename BufferFinishedMessageBus::Inbox fFinishedBufferInbox;
107     std::forward_list<sk_sp<T>> fClientHeldBuffers;
108     bool fAbandoned = false;
109 
remove(const sk_sp<T> & b)110     void remove(const sk_sp<T>& b) {
111         // There is no convenient remove only the first element that equals a value functionality in
112         // std::forward_list.
113         auto prev = fClientHeldBuffers.before_begin();
114         auto end = fClientHeldBuffers.end();
115         SkASSERT(std::find(fClientHeldBuffers.begin(), end, b) != end);
116         for (auto cur = fClientHeldBuffers.begin(); cur != end; prev = cur++) {
117             if (*cur == b) {
118                 fClientHeldBuffers.erase_after(prev);
119                 break;
120             }
121         }
122         SkASSERT(std::find(fClientHeldBuffers.begin(), end, b) == end);
123     }
124 };
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 
128 template <typename T, typename IDType, typename TransferResultType>
129 class TAsyncReadResult : public SkImage::AsyncReadResult {
130 public:
TAsyncReadResult(IDType intendedRecipient)131     TAsyncReadResult(IDType intendedRecipient)
132         : fIntendedRecipient(intendedRecipient) {
133     }
134 
~TAsyncReadResult()135     ~TAsyncReadResult() override {
136         for (int i = 0; i < fPlanes.size(); ++i) {
137             fPlanes[i].releaseMappedBuffer(fIntendedRecipient);
138         }
139     }
140 
count()141     int count() const override { return fPlanes.size(); }
data(int i)142     const void* data(int i) const override { return fPlanes[i].data(); }
rowBytes(int i)143     size_t rowBytes(int i) const override { return fPlanes[i].rowBytes(); }
144 
addTransferResult(const TransferResultType & result,SkISize dimensions,size_t rowBytes,TClientMappedBufferManager<T,IDType> * manager)145     bool addTransferResult(const TransferResultType& result,
146                            SkISize dimensions,
147                            size_t rowBytes,
148                            TClientMappedBufferManager<T, IDType>* manager) {
149         SkASSERT(!result.fTransferBuffer->isMapped());
150         const void* mappedData = result.fTransferBuffer->map();
151         if (!mappedData) {
152             return false;
153         }
154         if (result.fPixelConverter) {
155             size_t size = rowBytes*dimensions.height();
156             sk_sp<SkData> data = SkData::MakeUninitialized(size);
157             result.fPixelConverter(data->writable_data(), mappedData);
158             this->addCpuPlane(std::move(data), rowBytes);
159             result.fTransferBuffer->unmap();
160         } else {
161             manager->insert(result.fTransferBuffer);
162             this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
163         }
164         return true;
165     }
166 
addCpuPlane(sk_sp<SkData> data,size_t rowBytes)167     void addCpuPlane(sk_sp<SkData> data, size_t rowBytes) {
168         SkASSERT(data);
169         SkASSERT(rowBytes > 0);
170         fPlanes.emplace_back(std::move(data), rowBytes);
171     }
172 
173 private:
addMappedPlane(const void * data,size_t rowBytes,sk_sp<T> mappedBuffer)174     void addMappedPlane(const void* data, size_t rowBytes, sk_sp<T> mappedBuffer) {
175         SkASSERT(data);
176         SkASSERT(rowBytes > 0);
177         SkASSERT(mappedBuffer);
178         SkASSERT(mappedBuffer->isMapped());
179         fPlanes.emplace_back(std::move(mappedBuffer), rowBytes);
180     }
181 
182     class Plane {
183     public:
Plane(sk_sp<T> buffer,size_t rowBytes)184         Plane(sk_sp<T> buffer, size_t rowBytes)
185                 : fMappedBuffer(std::move(buffer)), fRowBytes(rowBytes) {}
Plane(sk_sp<SkData> data,size_t rowBytes)186         Plane(sk_sp<SkData> data, size_t rowBytes) : fData(std::move(data)), fRowBytes(rowBytes) {}
187 
188         Plane(Plane&&) = default;
189 
~Plane()190         ~Plane() { SkASSERT(!fMappedBuffer); }
191 
192         Plane& operator=(const Plane&) = delete;
193         Plane& operator=(Plane&&) = default;
194 
releaseMappedBuffer(IDType intendedRecipient)195         void releaseMappedBuffer(IDType intendedRecipient) {
196             if (fMappedBuffer) {
197                 TClientMappedBufferManager<T, IDType>::BufferFinishedMessageBus::Post(
198                         {std::move(fMappedBuffer), intendedRecipient});
199             }
200         }
201 
data()202         const void* data() const {
203             if (fMappedBuffer) {
204                 SkASSERT(!fData);
205                 SkASSERT(fMappedBuffer->isMapped());
206                 return fMappedBuffer->map();
207             }
208             SkASSERT(fData);
209             return fData->data();
210         }
211 
rowBytes()212         size_t rowBytes() const { return fRowBytes; }
213 
214     private:
215         sk_sp<SkData> fData;
216         sk_sp<T> fMappedBuffer;
217         size_t fRowBytes;
218     };
219     SkSTArray<3, Plane> fPlanes;
220     IDType fIntendedRecipient;
221 };
222 
223 }  // namespace skgpu
224 
225 #endif  // skgpu_AsyncReadTypes_DEFINED
226 
227