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