1 /* 2 * Copyright 2022 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 8 #ifndef skgpu_graphite_task_UploadTask_DEFINED 9 #define skgpu_graphite_task_UploadTask_DEFINED 10 11 #include "src/gpu/graphite/task/Task.h" 12 13 #include "include/core/SkImageInfo.h" 14 #include "include/core/SkRect.h" 15 #include "include/core/SkRefCnt.h" 16 #include "include/private/base/SkTArray.h" 17 #include "src/gpu/graphite/CommandTypes.h" 18 19 #include <memory> 20 21 namespace skgpu::graphite { 22 23 class Buffer; 24 class Recorder; 25 class TextureProxy; 26 27 struct MipLevel { 28 const void* fPixels = nullptr; 29 size_t fRowBytes = 0; 30 }; 31 32 /** 33 * The ConditionalUploadContext, if set, is used to determine whether an upload needs to occur 34 * on Recording playback. Clients will need to create their own subclasses to store the 35 * necessary data and override the needsUpload() method to do this check. 36 */ 37 class ConditionalUploadContext { 38 public: ~ConditionalUploadContext()39 virtual ~ConditionalUploadContext() {} 40 41 // Return true if the upload needs to occur; false if it should be skipped this time. 42 virtual bool needsUpload(Context*) = 0; 43 44 // Return true if the upload should be kept in the task (and possibly re-executed on replay 45 // depending on needsUpload()'s return value), or false if it should be discarded and never 46 // attempt to be uploaded on any replay. uploadSubmitted()47 virtual bool uploadSubmitted() { return true; } 48 }; 49 50 /** 51 * ImageUploadContext is an implementation of ConditionalUploadContext that returns true on 52 * the first call to needsUpload() and then returns false on subsequent calls. This is used to 53 * upload an image once and then avoid redundant uploads after that. 54 */ 55 class ImageUploadContext : public ConditionalUploadContext { 56 public: ~ImageUploadContext()57 ~ImageUploadContext() override {} 58 59 // Always upload, since it will be discarded right afterwards needsUpload(Context *)60 bool needsUpload(Context*) override { return true; } 61 62 // Always return false so the upload instance is discarded after the first execution uploadSubmitted()63 bool uploadSubmitted() override { return false; } 64 }; 65 66 /** 67 * An UploadInstance represents a single set of uploads from a buffer to texture that 68 * can be processed in a single command. 69 */ 70 class UploadInstance { 71 public: 72 static UploadInstance Make(Recorder*, 73 sk_sp<TextureProxy> targetProxy, 74 const SkColorInfo& srcColorInfo, 75 const SkColorInfo& dstColorInfo, 76 SkSpan<const MipLevel> levels, 77 const SkIRect& dstRect, 78 std::unique_ptr<ConditionalUploadContext>); 79 static UploadInstance MakeCompressed(Recorder*, 80 sk_sp<TextureProxy> targetProxy, 81 const void* data, 82 size_t dataSize); 83 Invalid()84 static UploadInstance Invalid() { return {}; } 85 86 UploadInstance(UploadInstance&&); 87 UploadInstance& operator=(UploadInstance&&); 88 ~UploadInstance(); 89 isValid()90 bool isValid() const { return fBuffer != nullptr && fTextureProxy != nullptr; } 91 92 bool prepareResources(ResourceProvider*); 93 94 // Adds upload command to the given CommandBuffer, returns false if the instance should be 95 // discarded. 96 Task::Status addCommand(Context*, CommandBuffer*, Task::ReplayTargetData) const; 97 98 private: 99 UploadInstance(); 100 // Copy data is appended directly after the object is created 101 UploadInstance(const Buffer*, 102 size_t bytesPerPixel, 103 sk_sp<TextureProxy>, 104 std::unique_ptr<ConditionalUploadContext> = nullptr); 105 106 const Buffer* fBuffer; 107 size_t fBytesPerPixel; 108 sk_sp<TextureProxy> fTextureProxy; 109 skia_private::STArray<1, BufferTextureCopyData> fCopyData; 110 std::unique_ptr<ConditionalUploadContext> fConditionalContext; 111 }; 112 113 /** 114 * An UploadList is a mutable collection of UploadCommands. 115 * 116 * Currently commands are accumulated in order and processed in the same order. Dependency 117 * management is expected to be handled by the TaskGraph. 118 * 119 * When an upload is appended to the list its data will be copied to a Buffer in 120 * preparation for a deferred upload. 121 */ 122 class UploadList { 123 public: 124 bool recordUpload(Recorder*, 125 sk_sp<TextureProxy> targetProxy, 126 const SkColorInfo& srcColorInfo, 127 const SkColorInfo& dstColorInfo, 128 SkSpan<const MipLevel> levels, 129 const SkIRect& dstRect, 130 std::unique_ptr<ConditionalUploadContext>); 131 size()132 int size() { return fInstances.size(); } 133 134 private: 135 friend class UploadTask; 136 137 skia_private::STArray<1, UploadInstance> fInstances; 138 }; 139 140 /* 141 * An UploadTask is a immutable collection of UploadCommands. 142 * 143 * When adding commands to the commandBuffer the texture proxies in those 144 * commands will be instantiated and the copy command added. 145 */ 146 class UploadTask final : public Task { 147 public: 148 static sk_sp<UploadTask> Make(UploadList*); 149 static sk_sp<UploadTask> Make(UploadInstance); 150 151 ~UploadTask() override; 152 153 Status prepareResources(ResourceProvider*, 154 ScratchResourceManager*, 155 const RuntimeEffectDictionary*) override; 156 157 Status addCommands(Context*, CommandBuffer*, ReplayTargetData) override; 158 159 private: 160 UploadTask(skia_private::TArray<UploadInstance>&&); 161 UploadTask(UploadInstance); 162 163 skia_private::STArray<1, UploadInstance> fInstances; 164 }; 165 166 } // namespace skgpu::graphite 167 168 #endif // skgpu_graphite_task_UploadTask_DEFINED 169