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