• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "experimental/graphite/src/UploadTask.h"
9 
10 #include "experimental/graphite/include/Recorder.h"
11 #include "experimental/graphite/src/Buffer.h"
12 #include "experimental/graphite/src/Caps.h"
13 #include "experimental/graphite/src/CommandBuffer.h"
14 #include "experimental/graphite/src/Log.h"
15 #include "experimental/graphite/src/RecorderPriv.h"
16 #include "experimental/graphite/src/ResourceProvider.h"
17 #include "experimental/graphite/src/Texture.h"
18 #include "experimental/graphite/src/TextureProxy.h"
19 #include "src/core/SkConvertPixels.h"
20 
21 namespace skgpu {
22 
addCommand(ResourceProvider * resourceProvider,CommandBuffer * commandBuffer) const23 void UploadCommand::addCommand(ResourceProvider* resourceProvider,
24                                CommandBuffer* commandBuffer) const {
25     if (!fTextureProxy) {
26         SKGPU_LOG_E("No texture proxy specified for UploadTask");
27         return;
28     }
29     if (!fTextureProxy->instantiate(resourceProvider)) {
30         SKGPU_LOG_E("Could not instantiate texture proxy for UploadTask!");
31         return;
32     }
33 
34     commandBuffer->copyBufferToTexture(std::move(fBuffer),
35                                        fTextureProxy->refTexture(),
36                                        fCopyData.data(),
37                                        fCopyData.size());
38 }
39 
40 //---------------------------------------------------------------------------
41 
compute_combined_buffer_size(int mipLevelCount,size_t bytesPerPixel,size_t minTransferBufferAlignment,const SkISize & baseDimensions,SkTArray<size_t> * individualMipOffsets)42 size_t compute_combined_buffer_size(int mipLevelCount,
43                                     size_t bytesPerPixel,
44                                     size_t minTransferBufferAlignment,
45                                     const SkISize& baseDimensions,
46                                     SkTArray<size_t>* individualMipOffsets) {
47     SkASSERT(individualMipOffsets && !individualMipOffsets->count());
48     SkASSERT(mipLevelCount >= 1);
49 
50     individualMipOffsets->push_back(0);
51 
52     size_t combinedBufferSize = baseDimensions.width() * bytesPerPixel * baseDimensions.height();
53     SkISize levelDimensions = baseDimensions;
54 
55     for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
56         levelDimensions = {std::max(1, levelDimensions.width() /2),
57                            std::max(1, levelDimensions.height()/2)};
58 
59         size_t trimmedSize = levelDimensions.area() * bytesPerPixel;
60         combinedBufferSize = SkAlignTo(combinedBufferSize, minTransferBufferAlignment);
61         SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
62 
63         individualMipOffsets->push_back(combinedBufferSize);
64         combinedBufferSize += trimmedSize;
65     }
66 
67     SkASSERT(individualMipOffsets->count() == mipLevelCount);
68     return combinedBufferSize;
69 }
70 
appendUpload(Recorder * recorder,sk_sp<TextureProxy> textureProxy,SkColorType dataColorType,const std::vector<MipLevel> & levels,const SkIRect & dstRect)71 bool UploadList::appendUpload(Recorder* recorder,
72                               sk_sp<TextureProxy> textureProxy,
73                               SkColorType dataColorType,
74                               const std::vector<MipLevel>& levels,
75                               const SkIRect& dstRect) {
76     const Caps* caps = recorder->priv().caps();
77     SkASSERT(caps->isTexturable(textureProxy->textureInfo()));
78 
79     unsigned int mipLevelCount = levels.size();
80     // The assumption is either that we have no mipmaps, or that our rect is the entire texture
81     SkASSERT(mipLevelCount == 1 || dstRect == SkIRect::MakeSize(textureProxy->dimensions()));
82 
83     // We assume that if the texture has mip levels, we either upload to all the levels or just the
84     // first.
85     SkASSERT(mipLevelCount == 1 || mipLevelCount == textureProxy->textureInfo().numMipLevels());
86 
87     if (dstRect.isEmpty()) {
88         return false;
89     }
90 
91     SkASSERT(caps->areColorTypeAndTextureInfoCompatible(dataColorType,
92                                                         textureProxy->textureInfo()));
93 
94     if (mipLevelCount == 1 && !levels[0].fPixels) {
95         return true;   // no data to upload
96     }
97 
98     for (unsigned int i = 0; i < mipLevelCount; ++i) {
99         // We do not allow any gaps in the mip data
100         if (!levels[i].fPixels) {
101             return false;
102         }
103     }
104 
105     size_t bpp = SkColorTypeBytesPerPixel(dataColorType);
106     size_t minAlignment = caps->getTransferBufferAlignment(bpp);
107     SkTArray<size_t> individualMipOffsets(mipLevelCount);
108     size_t combinedBufferSize = compute_combined_buffer_size(mipLevelCount, bpp, minAlignment,
109                                                              dstRect.size(), &individualMipOffsets);
110     SkASSERT(combinedBufferSize);
111 
112     // TODO: get staging buffer or {void* offset, sk_sp<Buffer> buffer} pair.
113     ResourceProvider* resourceProvider = recorder->priv().resourceProvider();
114     sk_sp<Buffer> buffer = resourceProvider->findOrCreateBuffer(combinedBufferSize,
115                                                                 BufferType::kXferCpuToGpu,
116                                                                 PrioritizeGpuReads::kNo);
117 
118     std::vector<BufferTextureCopyData> copyData(mipLevelCount);
119 
120     if (!buffer) {
121         return false;
122     }
123     char* bufferData = (char*) buffer->map(); // TODO: get from staging buffer instead
124     size_t baseOffset = 0;
125 
126     int currentWidth = dstRect.width();
127     int currentHeight = dstRect.height();
128     for (unsigned int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
129         const size_t trimRowBytes = currentWidth * bpp;
130         const size_t rowBytes = levels[currentMipLevel].fRowBytes;
131 
132         // copy data into the buffer, skipping any trailing bytes
133         char* dst = bufferData + individualMipOffsets[currentMipLevel];
134         const char* src = (const char*)levels[currentMipLevel].fPixels;
135         SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
136 
137         copyData[currentMipLevel].fBufferOffset =
138                 baseOffset + individualMipOffsets[currentMipLevel];
139         copyData[currentMipLevel].fBufferRowBytes = trimRowBytes;
140         copyData[currentMipLevel].fRect = {
141             dstRect.left(), dstRect.top(), // TODO: can we recompute this for mips?
142             dstRect.left() + currentWidth, dstRect.top() + currentHeight
143         };
144         copyData[currentMipLevel].fMipLevel = currentMipLevel;
145 
146         currentWidth = std::max(1, currentWidth/2);
147         currentHeight = std::max(1, currentHeight/2);
148     }
149 
150     buffer->unmap();
151 
152     fCommands.push_back({std::move(buffer), std::move(textureProxy), std::move(copyData)});
153 
154     return true;
155 }
156 
157 //---------------------------------------------------------------------------
158 
Make(UploadList * uploadList)159 sk_sp<UploadTask> UploadTask::Make(UploadList* uploadList) {
160     return sk_sp<UploadTask>(new UploadTask(std::move(uploadList->fCommands)));
161 }
162 
UploadTask(std::vector<UploadCommand> commands)163 UploadTask::UploadTask(std::vector<UploadCommand> commands) : fCommands(std::move(commands)) {}
164 
~UploadTask()165 UploadTask::~UploadTask() {}
166 
addCommands(ResourceProvider * resourceProvider,CommandBuffer * commandBuffer)167 void UploadTask::addCommands(ResourceProvider* resourceProvider,
168                              CommandBuffer* commandBuffer) {
169     for (unsigned int i = 0; i < fCommands.size(); ++i) {
170         fCommands[i].addCommand(resourceProvider, commandBuffer);
171     }
172 }
173 
174 } // namespace skgpu
175