1 /*
2 * Copyright 2015 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 
8 #ifndef GrVkCommandBuffer_DEFINED
9 #define GrVkCommandBuffer_DEFINED
10 
11 #include "GrVkGpu.h"
12 #include "GrVkResource.h"
13 #include "GrVkSemaphore.h"
14 #include "GrVkUtil.h"
15 #include "vk/GrVkDefines.h"
16 
17 class GrVkFramebuffer;
18 class GrVkPipeline;
19 class GrVkRenderPass;
20 class GrVkRenderTarget;
21 class GrVkTransferBuffer;
22 
23 class GrVkCommandBuffer : public GrVkResource {
24 public:
25     void invalidateState();
26 
27     ////////////////////////////////////////////////////////////////////////////
28     // CommandBuffer commands
29     ////////////////////////////////////////////////////////////////////////////
30     enum BarrierType {
31         kMemory_BarrierType,
32         kBufferMemory_BarrierType,
33         kImageMemory_BarrierType
34     };
35 
36     void pipelineBarrier(const GrVkGpu* gpu,
37                          VkPipelineStageFlags srcStageMask,
38                          VkPipelineStageFlags dstStageMask,
39                          bool byRegion,
40                          BarrierType barrierType,
41                          void* barrier) const;
42 
bindVertexBuffer(GrVkGpu * gpu,GrVkVertexBuffer * vbuffer)43     void bindVertexBuffer(GrVkGpu* gpu, GrVkVertexBuffer* vbuffer) {
44         VkBuffer vkBuffer = vbuffer->buffer();
45         // TODO: once vbuffer->offset() no longer always returns 0, we will need to track the offset
46         // to know if we can skip binding or not.
47         if (!fBoundVertexBufferIsValid || vkBuffer != fBoundVertexBuffer) {
48             VkDeviceSize offset = vbuffer->offset();
49             GR_VK_CALL(gpu->vkInterface(), CmdBindVertexBuffers(fCmdBuffer,
50                                                                 0,
51                                                                 1,
52                                                                 &vkBuffer,
53                                                                 &offset));
54             fBoundVertexBufferIsValid = true;
55             fBoundVertexBuffer = vkBuffer;
56             addResource(vbuffer->resource());
57         }
58     }
59 
bindIndexBuffer(GrVkGpu * gpu,GrVkIndexBuffer * ibuffer)60     void bindIndexBuffer(GrVkGpu* gpu, GrVkIndexBuffer* ibuffer) {
61         VkBuffer vkBuffer = ibuffer->buffer();
62         // TODO: once ibuffer->offset() no longer always returns 0, we will need to track the offset
63         // to know if we can skip binding or not.
64         if (!fBoundIndexBufferIsValid || vkBuffer != fBoundIndexBuffer) {
65             GR_VK_CALL(gpu->vkInterface(), CmdBindIndexBuffer(fCmdBuffer,
66                                                               vkBuffer,
67                                                               ibuffer->offset(),
68                                                               VK_INDEX_TYPE_UINT16));
69             fBoundIndexBufferIsValid = true;
70             fBoundIndexBuffer = vkBuffer;
71             addResource(ibuffer->resource());
72         }
73     }
74 
75     void bindPipeline(const GrVkGpu* gpu, const GrVkPipeline* pipeline);
76 
77     void bindDescriptorSets(const GrVkGpu* gpu,
78                             GrVkPipelineState*,
79                             VkPipelineLayout layout,
80                             uint32_t firstSet,
81                             uint32_t setCount,
82                             const VkDescriptorSet* descriptorSets,
83                             uint32_t dynamicOffsetCount,
84                             const uint32_t* dynamicOffsets);
85 
86     void bindDescriptorSets(const GrVkGpu* gpu,
87                             const SkTArray<const GrVkRecycledResource*>&,
88                             const SkTArray<const GrVkResource*>&,
89                             VkPipelineLayout layout,
90                             uint32_t firstSet,
91                             uint32_t setCount,
92                             const VkDescriptorSet* descriptorSets,
93                             uint32_t dynamicOffsetCount,
94                             const uint32_t* dynamicOffsets);
95 
96     void setViewport(const GrVkGpu* gpu,
97                      uint32_t firstViewport,
98                      uint32_t viewportCount,
99                      const VkViewport* viewports);
100 
101     void setScissor(const GrVkGpu* gpu,
102                     uint32_t firstScissor,
103                     uint32_t scissorCount,
104                     const VkRect2D* scissors);
105 
106     void setBlendConstants(const GrVkGpu* gpu, const float blendConstants[4]);
107 
108     // Commands that only work inside of a render pass
109     void clearAttachments(const GrVkGpu* gpu,
110                           int numAttachments,
111                           const VkClearAttachment* attachments,
112                           int numRects,
113                           const VkClearRect* clearRects) const;
114 
115     void drawIndexed(const GrVkGpu* gpu,
116                      uint32_t indexCount,
117                      uint32_t instanceCount,
118                      uint32_t firstIndex,
119                      int32_t vertexOffset,
120                      uint32_t firstInstance) const;
121 
122     void draw(const GrVkGpu* gpu,
123               uint32_t vertexCount,
124               uint32_t instanceCount,
125               uint32_t firstVertex,
126               uint32_t firstInstance) const;
127 
128     // Add ref-counted resource that will be tracked and released when this
129     // command buffer finishes execution
addResource(const GrVkResource * resource)130     void addResource(const GrVkResource* resource) {
131         resource->ref();
132         fTrackedResources.append(1, &resource);
133     }
134 
135     // Add ref-counted resource that will be tracked and released when this command buffer finishes
136     // execution. When it is released, it will signal that the resource can be recycled for reuse.
addRecycledResource(const GrVkRecycledResource * resource)137     void addRecycledResource(const GrVkRecycledResource* resource) {
138         resource->ref();
139         fTrackedRecycledResources.append(1, &resource);
140     }
141 
142     void reset(GrVkGpu* gpu);
143 
144 protected:
145         GrVkCommandBuffer(VkCommandBuffer cmdBuffer, const GrVkRenderPass* rp = VK_NULL_HANDLE)
fIsActive(false)146             : fIsActive(false)
147             , fActiveRenderPass(rp)
148             , fCmdBuffer(cmdBuffer)
149             , fBoundVertexBufferIsValid(false)
150             , fBoundIndexBufferIsValid(false)
151             , fNumResets(0) {
152             fTrackedResources.setReserve(kInitialTrackedResourcesCount);
153             fTrackedRecycledResources.setReserve(kInitialTrackedResourcesCount);
154             this->invalidateState();
155         }
156 
157         SkTDArray<const GrVkResource*>          fTrackedResources;
158         SkTDArray<const GrVkRecycledResource*>  fTrackedRecycledResources;
159 
160         // Tracks whether we are in the middle of a command buffer begin/end calls and thus can add
161         // new commands to the buffer;
162         bool fIsActive;
163 
164         // Stores a pointer to the current active render pass (i.e. begin has been called but not
165         // end). A nullptr means there is no active render pass. The GrVKCommandBuffer does not own
166         // the render pass.
167         const GrVkRenderPass*     fActiveRenderPass;
168 
169         VkCommandBuffer           fCmdBuffer;
170 
171 private:
172     static const int kInitialTrackedResourcesCount = 32;
173 
174     void freeGPUData(const GrVkGpu* gpu) const override;
175     virtual void onFreeGPUData(const GrVkGpu* gpu) const = 0;
176     void abandonSubResources() const override;
177 
onReset(GrVkGpu * gpu)178     virtual void onReset(GrVkGpu* gpu) {}
179 
180     VkBuffer                                fBoundVertexBuffer;
181     bool                                    fBoundVertexBufferIsValid;
182 
183     VkBuffer                                fBoundIndexBuffer;
184     bool                                    fBoundIndexBufferIsValid;
185 
186     // When resetting the command buffer, we remove the tracked resources from their arrays, and
187     // we prefer to not free all the memory every time so usually we just rewind. However, to avoid
188     // all arrays growing to the max size, after so many resets we'll do a full reset of the tracked
189     // resource arrays.
190     static const int kNumRewindResetsBeforeFullReset = 8;
191     int              fNumResets;
192 
193     // Cached values used for dynamic state updates
194     VkViewport fCachedViewport;
195     VkRect2D   fCachedScissor;
196     float      fCachedBlendConstant[4];
197 };
198 
199 class GrVkSecondaryCommandBuffer;
200 
201 class GrVkPrimaryCommandBuffer : public GrVkCommandBuffer {
202 public:
203     ~GrVkPrimaryCommandBuffer() override;
204 
205     static GrVkPrimaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool);
206 
207     void begin(const GrVkGpu* gpu);
208     void end(const GrVkGpu* gpu);
209 
210     // Begins render pass on this command buffer. The framebuffer from GrVkRenderTarget will be used
211     // in the render pass.
212     void beginRenderPass(const GrVkGpu* gpu,
213                          const GrVkRenderPass* renderPass,
214                          const VkClearValue* clearValues,
215                          const GrVkRenderTarget& target,
216                          const SkIRect& bounds,
217                          bool forSecondaryCB);
218     void endRenderPass(const GrVkGpu* gpu);
219 
220     // Submits the SecondaryCommandBuffer into this command buffer. It is required that we are
221     // currently inside a render pass that is compatible with the one used to create the
222     // SecondaryCommandBuffer.
223     void executeCommands(const GrVkGpu* gpu,
224                          GrVkSecondaryCommandBuffer* secondaryBuffer);
225 
226     // Commands that only work outside of a render pass
227     void clearColorImage(const GrVkGpu* gpu,
228                          GrVkImage* image,
229                          const VkClearColorValue* color,
230                          uint32_t subRangeCount,
231                          const VkImageSubresourceRange* subRanges);
232 
233     void clearDepthStencilImage(const GrVkGpu* gpu,
234                                 GrVkImage* image,
235                                 const VkClearDepthStencilValue* color,
236                                 uint32_t subRangeCount,
237                                 const VkImageSubresourceRange* subRanges);
238 
239     void copyImage(const GrVkGpu* gpu,
240                    GrVkImage* srcImage,
241                    VkImageLayout srcLayout,
242                    GrVkImage* dstImage,
243                    VkImageLayout dstLayout,
244                    uint32_t copyRegionCount,
245                    const VkImageCopy* copyRegions);
246 
247     void blitImage(const GrVkGpu* gpu,
248                    const GrVkResource* srcResource,
249                    VkImage srcImage,
250                    VkImageLayout srcLayout,
251                    const GrVkResource* dstResource,
252                    VkImage dstImage,
253                    VkImageLayout dstLayout,
254                    uint32_t blitRegionCount,
255                    const VkImageBlit* blitRegions,
256                    VkFilter filter);
257 
blitImage(const GrVkGpu * gpu,const GrVkImage & srcImage,const GrVkImage & dstImage,uint32_t blitRegionCount,const VkImageBlit * blitRegions,VkFilter filter)258     void blitImage(const GrVkGpu* gpu,
259                    const GrVkImage& srcImage,
260                    const GrVkImage& dstImage,
261                    uint32_t blitRegionCount,
262                    const VkImageBlit* blitRegions,
263                    VkFilter filter) {
264         this->blitImage(gpu,
265                         srcImage.resource(),
266                         srcImage.image(),
267                         srcImage.currentLayout(),
268                         dstImage.resource(),
269                         dstImage.image(),
270                         dstImage.currentLayout(),
271                         blitRegionCount,
272                         blitRegions,
273                         filter);
274     }
275 
276     void copyImageToBuffer(const GrVkGpu* gpu,
277                            GrVkImage* srcImage,
278                            VkImageLayout srcLayout,
279                            GrVkTransferBuffer* dstBuffer,
280                            uint32_t copyRegionCount,
281                            const VkBufferImageCopy* copyRegions);
282 
283     void copyBufferToImage(const GrVkGpu* gpu,
284                            GrVkTransferBuffer* srcBuffer,
285                            GrVkImage* dstImage,
286                            VkImageLayout dstLayout,
287                            uint32_t copyRegionCount,
288                            const VkBufferImageCopy* copyRegions);
289 
290     void updateBuffer(GrVkGpu* gpu,
291                       GrVkBuffer* dstBuffer,
292                       VkDeviceSize dstOffset,
293                       VkDeviceSize dataSize,
294                       const void* data);
295 
296     void resolveImage(GrVkGpu* gpu,
297                       const GrVkImage& srcImage,
298                       const GrVkImage& dstImage,
299                       uint32_t regionCount,
300                       const VkImageResolve* regions);
301 
302     void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync,
303                        const GrVkSemaphore::Resource* signalSemaphore,
304                        SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores);
305     bool finished(const GrVkGpu* gpu) const;
306 
307 #ifdef SK_TRACE_VK_RESOURCES
dumpInfo()308     void dumpInfo() const override {
309         SkDebugf("GrVkPrimaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt());
310     }
311 #endif
312 
313 private:
GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer)314     explicit GrVkPrimaryCommandBuffer(VkCommandBuffer cmdBuffer)
315         : INHERITED(cmdBuffer)
316         , fSubmitFence(VK_NULL_HANDLE) {}
317 
318     void onFreeGPUData(const GrVkGpu* gpu) const override;
319 
320     void onReset(GrVkGpu* gpu) override;
321 
322     SkTArray<GrVkSecondaryCommandBuffer*, true> fSecondaryCommandBuffers;
323     VkFence                                     fSubmitFence;
324 
325     typedef GrVkCommandBuffer INHERITED;
326 };
327 
328 class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer {
329 public:
330     static GrVkSecondaryCommandBuffer* Create(const GrVkGpu* gpu, VkCommandPool cmdPool);
331 
332     void begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer,
333                const GrVkRenderPass* compatibleRenderPass);
334     void end(const GrVkGpu* gpu);
335 
336 #ifdef SK_TRACE_VK_RESOURCES
dumpInfo()337     void dumpInfo() const override {
338         SkDebugf("GrVkSecondaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt());
339     }
340 #endif
341 
342 private:
GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer)343     explicit GrVkSecondaryCommandBuffer(VkCommandBuffer cmdBuffer)
344         : INHERITED(cmdBuffer) {
345     }
346 
onFreeGPUData(const GrVkGpu * gpu)347     void onFreeGPUData(const GrVkGpu* gpu) const override {}
348 
349     friend class GrVkPrimaryCommandBuffer;
350 
351     typedef GrVkCommandBuffer INHERITED;
352 };
353 
354 #endif
355