GrDeferredProxyUploader.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Copyright 2017 Google Inc.
  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 GrDeferredProxyUploader_DEFINED
  8. #define GrDeferredProxyUploader_DEFINED
  9. #include "include/core/SkRefCnt.h"
  10. #include "include/private/SkSemaphore.h"
  11. #include "src/core/SkAutoPixmapStorage.h"
  12. #include "src/core/SkMakeUnique.h"
  13. #include "src/gpu/GrOpFlushState.h"
  14. #include "src/gpu/GrTextureProxyPriv.h"
  15. /**
  16. * GrDeferredProxyUploader assists with threaded generation of textures. Currently used by both
  17. * software clip masks, and the software path renderer. The calling code typically needs to store
  18. * some additional data (T) for use on the worker thread. GrTDeferredProxyUploader allows storing
  19. * such data. The common flow is:
  20. *
  21. * 1) A GrTDeferredProxyUploader is created, with some payload (eg an SkPath to draw).
  22. * The uploader is owned by the proxy that it's going to populate.
  23. * 2) A task is created with a pointer to the uploader. A worker thread executes that task, using
  24. * the payload data to allocate and fill in the fPixels pixmap.
  25. * 3) The worker thread calls signalAndFreeData(), which notifies the main thread that the pixmap
  26. * is ready, and then deletes the payload data (which is no longer needed).
  27. * 4) In parallel to 2-3, on the main thread... Some op is created that refers to the proxy. When
  28. * that op is added to an op list, the op list retains a pointer to the "deferred" proxies.
  29. * 5) At flush time, the op list ensures that the deferred proxies are instantiated, then calls
  30. * scheduleUpload on those proxies, which calls scheduleUpload on the uploader (below).
  31. * 6) scheduleUpload defers the upload even further, by adding an ASAPUpload to the flush.
  32. * 7) When the ASAP upload happens, we wait to make sure that the pixels are marked ready
  33. * (from step #3 on the worker thread). Then we perform the actual upload to the texture.
  34. * Finally, we call resetDeferredUploader, which deletes the uploader object, causing fPixels
  35. * to be freed.
  36. */
  37. class GrDeferredProxyUploader : public SkNoncopyable {
  38. public:
  39. GrDeferredProxyUploader() : fScheduledUpload(false), fWaited(false) {}
  40. virtual ~GrDeferredProxyUploader() {
  41. // In normal usage (i.e., through GrTDeferredProxyUploader) this will be redundant
  42. this->wait();
  43. }
  44. void scheduleUpload(GrOpFlushState* flushState, GrTextureProxy* proxy) {
  45. if (fScheduledUpload) {
  46. // Multiple references to the owning proxy may have caused us to already execute
  47. return;
  48. }
  49. auto uploadMask = [this, proxy](GrDeferredTextureUploadWritePixelsFn& writePixelsFn) {
  50. this->wait();
  51. GrColorType pixelColorType = SkColorTypeToGrColorType(this->fPixels.info().colorType());
  52. // If the worker thread was unable to allocate pixels, this check will fail, and we'll
  53. // end up drawing with an uninitialized mask texture, but at least we won't crash.
  54. if (this->fPixels.addr()) {
  55. writePixelsFn(proxy, 0, 0, this->fPixels.width(), this->fPixels.height(),
  56. pixelColorType, this->fPixels.addr(), this->fPixels.rowBytes());
  57. }
  58. // Upload has finished, so tell the proxy to release this GrDeferredProxyUploader
  59. proxy->texPriv().resetDeferredUploader();
  60. };
  61. flushState->addASAPUpload(std::move(uploadMask));
  62. fScheduledUpload = true;
  63. }
  64. void signalAndFreeData() {
  65. this->freeData();
  66. fPixelsReady.signal();
  67. }
  68. SkAutoPixmapStorage* getPixels() { return &fPixels; }
  69. protected:
  70. void wait() {
  71. if (!fWaited) {
  72. fPixelsReady.wait();
  73. fWaited = true;
  74. }
  75. }
  76. private:
  77. virtual void freeData() {}
  78. SkAutoPixmapStorage fPixels;
  79. SkSemaphore fPixelsReady;
  80. bool fScheduledUpload;
  81. bool fWaited;
  82. };
  83. template <typename T>
  84. class GrTDeferredProxyUploader : public GrDeferredProxyUploader {
  85. public:
  86. template <typename... Args>
  87. GrTDeferredProxyUploader(Args&&... args)
  88. : fData(skstd::make_unique<T>(std::forward<Args>(args)...)) {
  89. }
  90. ~GrTDeferredProxyUploader() override {
  91. // We need to wait here, so that we don't free fData before the worker thread is done
  92. // with it. (This happens if the proxy is deleted early due to a full clear or failure
  93. // of an op list to instantiate).
  94. this->wait();
  95. }
  96. T& data() { return *fData; }
  97. private:
  98. void freeData() override {
  99. fData.reset();
  100. }
  101. std::unique_ptr<T> fData;
  102. };
  103. #endif