Talvos  0.1
SPIR-V interpreter and dynamic analysis framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Commands.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018 the Talvos developers. All rights reserved.
2 //
3 // This file is distributed under a three-clause BSD license. For full license
4 // terms please see the LICENSE file distributed with this source code.
5 
8 
9 #include <algorithm>
10 #include <cassert>
11 #include <cmath>
12 
13 #include "PipelineExecutor.h"
14 #include "talvos/Commands.h"
15 #include "talvos/Device.h"
16 #include "talvos/Image.h"
17 #include "talvos/Memory.h"
18 #include "talvos/RenderPass.h"
19 
20 namespace talvos
21 {
22 
23 void Command::run(Device &Dev) const
24 {
25  Dev.reportCommandBegin(this);
26  runImpl(Dev);
27  Dev.reportCommandComplete(this);
28 }
29 
30 void BeginRenderPassCommand::runImpl(Device &Dev) const { RPI->begin(); }
31 
33 {
34  // TODO: Handle linear filtering.
35  assert(Filter == VK_FILTER_NEAREST);
36 
37  for (const VkImageBlit &Region : Regions)
38  {
39  uint32_t SrcLevel = Region.srcSubresource.mipLevel;
40  uint32_t DstLevel = Region.dstSubresource.mipLevel;
41 
42  int32_t XMin = std::min(Region.dstOffsets[0].x, Region.dstOffsets[1].x);
43  int32_t XMax = std::max(Region.dstOffsets[0].x, Region.dstOffsets[1].x);
44  int32_t YMin = std::min(Region.dstOffsets[0].y, Region.dstOffsets[1].y);
45  int32_t YMax = std::max(Region.dstOffsets[0].y, Region.dstOffsets[1].y);
46  int32_t ZMin = std::min(Region.dstOffsets[0].z, Region.dstOffsets[1].z);
47  int32_t ZMax = std::max(Region.dstOffsets[0].z, Region.dstOffsets[1].z);
48 
49  // Blit region one texel at a time.
50  for (uint32_t LayerOffset = 0;
51  LayerOffset < Region.dstSubresource.layerCount; LayerOffset++)
52  {
53  for (int32_t Z = ZMin; Z < ZMax; Z++)
54  {
55  for (int32_t Y = YMin; Y < YMax; Y++)
56  {
57  for (int32_t X = XMin; X < XMax; X++)
58  {
59  // Generate scaled coordinate for source image.
60  float U = X + 0.5f - Region.dstOffsets[0].x;
61  float V = Y + 0.5f - Region.dstOffsets[0].y;
62  float W = Z + 0.5f - Region.dstOffsets[0].z;
63  U *= (float)(Region.srcOffsets[1].x - Region.srcOffsets[0].x) /
64  (float)(Region.dstOffsets[1].x - Region.dstOffsets[0].x);
65  V *= (float)(Region.srcOffsets[1].y - Region.srcOffsets[0].y) /
66  (float)(Region.dstOffsets[1].y - Region.dstOffsets[0].y);
67  W *= (float)(Region.srcOffsets[1].z - Region.srcOffsets[0].z) /
68  (float)(Region.dstOffsets[1].z - Region.dstOffsets[0].z);
69  U += Region.srcOffsets[0].x;
70  V += Region.srcOffsets[0].y;
71  W += Region.srcOffsets[0].z;
72  int32_t SrcX = std::clamp<int32_t>(std::floor(U), 0,
73  SrcImage.getExtent().width - 1);
74  int32_t SrcY = std::clamp<int32_t>(std::floor(V), 0,
75  SrcImage.getExtent().height - 1);
76  int32_t SrcZ = std::clamp<int32_t>(std::floor(W), 0,
77  SrcImage.getExtent().depth - 1);
78 
79  uint32_t SrcLayer =
80  Region.srcSubresource.baseArrayLayer + LayerOffset;
81  uint32_t DstLayer =
82  Region.dstSubresource.baseArrayLayer + LayerOffset;
83  uint64_t SrcAddress =
84  SrcImage.getTexelAddress(SrcX, SrcY, SrcZ, SrcLayer, SrcLevel);
85  uint64_t DstAddress =
86  DstImage.getTexelAddress(X, Y, Z, DstLayer, DstLevel);
87 
88  // Copy texel from source to destination.
89  Image::Texel T;
90  SrcImage.read(T, SrcAddress);
91  DstImage.write(T, DstAddress);
92  }
93  }
94  }
95  }
96  }
97 }
98 
100 {
101  // Loop over attachments.
102  for (auto &Attachment : ClearAttachments)
103  {
104  // TODO: Handle clearing depth/stencil attachments.
105  assert(Attachment.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
106 
107  // Get target image view.
109  uint32_t AttachIndex = SP.ColorAttachments[Attachment.colorAttachment];
110  ImageView *DstImage = RPI.getFramebuffer().getAttachments()[AttachIndex];
111 
112  // Loop over clear regions.
113  for (auto &Rect : ClearRects)
114  {
115  // Compute start and end coordinates.
116  uint32_t XMin = Rect.rect.offset.x;
117  uint32_t XMax = XMin + Rect.rect.extent.width;
118  uint32_t YMin = Rect.rect.offset.y;
119  uint32_t YMax = YMin + Rect.rect.extent.height;
120  uint32_t LastLayer = Rect.baseArrayLayer + Rect.layerCount - 1;
121 
122  // Loop over array layers.
123  for (uint32_t Layer = Rect.baseArrayLayer; Layer <= LastLayer; Layer++)
124  {
125  // Store pixel data to each pixel in image.
126  for (uint32_t Y = YMin; Y < YMax; Y++)
127  {
128  for (uint32_t X = XMin; X < XMax; X++)
129  {
130  DstImage->write(Attachment.clearValue.color, X, Y, 0, Layer);
131  }
132  }
133  }
134  }
135  }
136 }
137 
139 {
140  // Loop over ranges in command.
141  for (auto &Range : Ranges)
142  {
143  // Compute last mip level in range.
144  uint32_t LastLevel = Range.baseMipLevel + Range.levelCount - 1;
145  if (Range.levelCount == VK_REMAINING_MIP_LEVELS)
146  LastLevel = DstImage.getNumMipLevels() - 1;
147 
148  // Compute last array layer in range.
149  uint32_t LastLayer = Range.baseArrayLayer + Range.layerCount - 1;
150  if (Range.layerCount == VK_REMAINING_ARRAY_LAYERS)
151  LastLayer = DstImage.getNumArrayLayers() - 1;
152 
153  // Loop over mip levels.
154  for (uint32_t Level = Range.baseMipLevel; Level <= LastLevel; Level++)
155  {
156  // Loop over array layers.
157  for (uint32_t Layer = Range.baseArrayLayer; Layer <= LastLayer; Layer++)
158  {
159  // Store pixel data to each pixel in image.
160  for (uint32_t Z = 0; Z < DstImage.getDepth(Level); Z++)
161  {
162  for (uint32_t Y = 0; Y < DstImage.getHeight(Level); Y++)
163  {
164  for (uint32_t X = 0; X < DstImage.getWidth(Level); X++)
165  {
167  DstImage.getTexelAddress(X, Y, Z, Layer, Level));
168  }
169  }
170  }
171  }
172  }
173  }
174 }
175 
177 {
178  for (const VkBufferCopy &Region : Regions)
179  {
180  Memory::copy(DstAddr + Region.dstOffset, Dev.getGlobalMemory(),
181  SrcAddr + Region.srcOffset, Dev.getGlobalMemory(),
182  Region.size);
183  }
184 }
185 
187 {
188  uint32_t ElementSize = DstImage.getElementSize();
189 
190  for (const VkBufferImageCopy &Region : Regions)
191  {
192  uint32_t MipLevel = Region.imageSubresource.mipLevel;
193  uint64_t MipOffset = DstImage.getMipLevelOffset(MipLevel);
194  uint32_t ImageWidth = DstImage.getWidth(MipLevel);
195  uint32_t ImageHeight = DstImage.getHeight(MipLevel);
196  uint32_t ImageDepth = DstImage.getDepth(MipLevel);
197  uint32_t ImageLayerSize = ImageWidth * ImageHeight * ImageDepth;
198 
199  // TODO: Handle VK_REMAINING_ARRAY_LAYERS
200  for (uint32_t LayerOffset = 0;
201  LayerOffset < Region.imageSubresource.layerCount; LayerOffset++)
202  {
203  uint32_t BufferWidth = Region.bufferRowLength ? Region.bufferRowLength
204  : Region.imageExtent.width;
205  uint32_t BufferHeight = Region.bufferImageHeight
206  ? Region.bufferImageHeight
207  : Region.imageExtent.height;
208  uint64_t SrcBase = SrcAddr + Region.bufferOffset;
209  SrcBase += BufferWidth * BufferHeight * ElementSize * LayerOffset;
210 
211  uint64_t DstBase =
212  DstImage.getAddress() + MipOffset +
213  (Region.imageOffset.x +
214  (Region.imageOffset.y + (Region.imageOffset.z * ImageHeight)) *
215  ImageWidth) *
216  ElementSize;
217  DstBase += ImageLayerSize * ElementSize *
218  (Region.imageSubresource.baseArrayLayer + LayerOffset);
219 
220  // Copy region one scanline at a time.
221  for (uint32_t z = 0; z < Region.imageExtent.depth; z++)
222  {
223  for (uint32_t y = 0; y < Region.imageExtent.height; y++)
224  {
225  Memory::copy(
226  DstBase + (((z * ImageHeight) + y) * ImageWidth) * ElementSize,
227  Dev.getGlobalMemory(),
228  SrcBase + (((z * BufferHeight) + y) * BufferWidth) * ElementSize,
229  Dev.getGlobalMemory(), Region.imageExtent.width * ElementSize);
230  }
231  }
232  }
233  }
234 }
235 
237 {
238  uint32_t SrcElementSize = SrcImage.getElementSize();
239  uint32_t DstElementSize = DstImage.getElementSize();
240 
241  assert(SrcElementSize == DstElementSize);
242  for (const VkImageCopy &Region : Regions)
243  {
244  // TODO: Handle mip levels.
245  assert(Region.srcSubresource.mipLevel == 0 &&
246  Region.dstSubresource.mipLevel == 0);
247 
248  // TODO: Handle array layers.
249  assert(Region.srcSubresource.baseArrayLayer == 0 &&
250  Region.srcSubresource.layerCount == 1);
251  assert(Region.srcSubresource.baseArrayLayer == 0 &&
252  Region.dstSubresource.layerCount == 1);
253 
254  uint32_t DstImageWidth = DstImage.getWidth();
255  uint32_t DstImageHeight = DstImage.getHeight();
256  uint64_t DstBase =
257  DstImage.getAddress() +
258  (Region.dstOffset.x +
259  (Region.dstOffset.y + (Region.dstOffset.z * DstImageHeight)) *
260  DstImageWidth) *
261  DstElementSize;
262 
263  uint32_t SrcImageWidth = SrcImage.getWidth();
264  uint32_t SrcImageHeight = SrcImage.getHeight();
265  uint64_t SrcBase =
266  SrcImage.getAddress() +
267  (Region.srcOffset.x +
268  (Region.srcOffset.y + (Region.srcOffset.z * SrcImageHeight)) *
269  SrcImageWidth) *
270  SrcElementSize;
271 
272  // Copy region one scanline at a time.
273  for (uint32_t z = 0; z < Region.extent.depth; z++)
274  {
275  for (uint32_t y = 0; y < Region.extent.height; y++)
276  {
277  Memory::copy(DstBase + (((z * DstImageHeight) + y) * DstImageWidth) *
278  DstElementSize,
279  Dev.getGlobalMemory(),
280  SrcBase + (((z * SrcImageHeight) + y) * SrcImageWidth) *
281  SrcElementSize,
282  Dev.getGlobalMemory(),
283  Region.extent.width * SrcElementSize);
284  }
285  }
286  }
287 }
288 
290 {
291  uint32_t ElementSize = SrcImage.getElementSize();
292 
293  for (const VkBufferImageCopy &Region : Regions)
294  {
295  uint32_t MipLevel = Region.imageSubresource.mipLevel;
296  uint64_t MipOffset = SrcImage.getMipLevelOffset(MipLevel);
297  uint32_t ImageWidth = SrcImage.getWidth(MipLevel);
298  uint32_t ImageHeight = SrcImage.getHeight(MipLevel);
299  uint32_t ImageDepth = SrcImage.getDepth(MipLevel);
300  uint32_t ImageLayerSize = ImageWidth * ImageHeight * ImageDepth;
301 
302  // TODO: Handle VK_REMAINING_ARRAY_LAYERS
303  for (uint32_t LayerOffset = 0;
304  LayerOffset < Region.imageSubresource.layerCount; LayerOffset++)
305  {
306  uint32_t BufferWidth = Region.bufferRowLength ? Region.bufferRowLength
307  : Region.imageExtent.width;
308  uint32_t BufferHeight = Region.bufferImageHeight
309  ? Region.bufferImageHeight
310  : Region.imageExtent.height;
311  uint64_t DstBase = DstAddr + Region.bufferOffset;
312  DstBase += BufferWidth * BufferHeight * ElementSize * LayerOffset;
313 
314  uint64_t SrcBase =
315  SrcImage.getAddress() + MipOffset +
316  (Region.imageOffset.x +
317  (Region.imageOffset.y + (Region.imageOffset.z * ImageHeight)) *
318  ImageWidth) *
319  ElementSize;
320  SrcBase += ImageLayerSize * ElementSize *
321  (Region.imageSubresource.baseArrayLayer + LayerOffset);
322 
323  // Copy region one scanline at a time.
324  for (uint32_t z = 0; z < Region.imageExtent.depth; z++)
325  {
326  for (uint32_t y = 0; y < Region.imageExtent.height; y++)
327  {
328  Memory::copy(
329  DstBase + (((z * BufferHeight) + y) * BufferWidth) * ElementSize,
330  Dev.getGlobalMemory(),
331  SrcBase + (((z * ImageHeight) + y) * ImageWidth) * ElementSize,
332  Dev.getGlobalMemory(), Region.imageExtent.width * ElementSize);
333  }
334  }
335  }
336  }
337 }
338 
340 {
341  Dev.getPipelineExecutor().run(*this);
342 }
343 
344 void DrawCommand::runImpl(Device &Dev) const
345 {
346  Dev.getPipelineExecutor().run(*this);
347 }
348 
350 {
351  Dev.getPipelineExecutor().run(*this);
352 }
353 
354 void EndRenderPassCommand::runImpl(Device &Dev) const { RPI->end(); }
355 
357 {
358  for (uint64_t Address = Base; Address < Base + NumBytes; Address += 4)
359  Dev.getGlobalMemory().store(Address, 4, (const uint8_t *)&Data);
360 }
361 
362 void NextSubpassCommand::runImpl(Device &Dev) const { RPI->nextSubpass(); }
363 
364 void ResetEventCommand::runImpl(Device &Dev) const { *Event = false; }
365 
366 void SetEventCommand::runImpl(Device &Dev) const { *Event = true; }
367 
368 UpdateBufferCommand::UpdateBufferCommand(uint64_t Base, uint64_t NumBytes,
369  const void *Data)
370  : Command(UPDATE_BUFFER), Base(Base), NumBytes(NumBytes)
371 {
372  this->Data = new uint8_t[NumBytes];
373  memcpy(this->Data, Data, NumBytes);
374 }
375 
377 
379 {
381 }
382 
384 {
385  // Wait for all events to be set.
386  for (volatile bool *Event : Events)
387  {
388  while (!*Event)
389  ;
390  }
391 }
392 
393 } // namespace talvos
void run(Device &Dev) const
Run this command on Dev.
Definition: Commands.cpp:23
uint32_t getSubpassIndex() const
Returns the index of the current subpass.
Definition: RenderPass.h:116
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:236
std::vector< VkClearAttachment > ClearAttachments
The attachments to clear.
Definition: Commands.h:141
const Subpass & getSubpass(uint32_t Index) const
Returns the subpass at index Index.
Definition: RenderPass.cpp:23
std::shared_ptr< RenderPassInstance > RPI
The render pass instance.
Definition: Commands.h:88
uint8_t * Data
The data to update the buffer with.
Definition: Commands.h:553
const Image & SrcImage
The source image.
Definition: Commands.h:108
const Image & SrcImage
The source image.
Definition: Commands.h:268
This file declares the Device class.
void write(const Image::Texel &T, uint32_t X, uint32_t Y=0, uint32_t Z=0, uint32_t Layer=0, uint32_t MipLevel=0) const
Write a texel to the image view at the specified coordinate.
Definition: Image.cpp:511
uint64_t getMipLevelOffset(uint32_t Level) const
Returns the offset in bytes to the beginning of the specified mip level.
Definition: Image.cpp:167
uint64_t DstAddr
The memory address of the destination buffer.
Definition: Commands.h:193
This structure describes the attachments used by a subpass.
Definition: RenderPass.h:59
static void copy(uint64_t DstAddress, Memory &DstMem, uint64_t SrcAddress, const Memory &SrcMem, uint64_t NumBytes)
Copy data between memory instances.
Definition: Memory.cpp:328
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:349
void run(const DispatchCommand &Cmd)
Run a compute dispatch command to completion.
std::shared_ptr< RenderPassInstance > RPI
The render pass instance.
Definition: Commands.h:454
uint64_t NumBytes
The number of bytes to fill.
Definition: Commands.h:475
const RenderPassInstance & RPI
The render pass instance this command is operating inside.
Definition: Commands.h:138
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:362
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:176
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:356
std::vector< VkImageBlit > Regions
The regions to copy.
Definition: Commands.h:114
std::vector< VkBufferCopy > Regions
The regions to copy.
Definition: Commands.h:196
This class represents a view into a range of image subresources.
Definition: Image.h:178
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:383
void write(const Texel &T, uint64_t Address) const
Write a texel to the image at the specified address.
Definition: Image.cpp:330
VkFilter Filter
The filter to use when scaling.
Definition: Commands.h:117
std::vector< VkBufferImageCopy > Regions
The regions to copy.
Definition: Commands.h:222
const Framebuffer & getFramebuffer() const
Returns the framebuffer associated with this render pass instance.
Definition: RenderPass.h:110
uint32_t getWidth(uint32_t Level=0) const
Returns the width of the image at the specified mip level.
Definition: Image.cpp:188
std::vector< VkBufferImageCopy > Regions
The regions to copy.
Definition: Commands.h:274
uint32_t Data
The data to fill the buffer with.
Definition: Commands.h:478
uint32_t getNumArrayLayers() const
Returns the number of array layers in the image.
Definition: Image.h:135
std::vector< VkClearRect > ClearRects
The regions to clear.
Definition: Commands.h:144
std::vector< volatile bool * > Events
The events to wait for.
Definition: Commands.h:571
uint64_t Base
The memory address to begin updating from.
Definition: Commands.h:547
This class is a base class for all commands.
Definition: Commands.h:31
std::vector< VkImageSubresourceRange > Ranges
The image subranges to clear.
Definition: Commands.h:170
This class represents a single texel with four 32-bit component values.
Definition: Image.h:28
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:289
const Image & DstImage
The destination image.
Definition: Commands.h:219
const Image & DstImage
The image to clear.
Definition: Commands.h:164
uint64_t Base
The memory address to begin filling from.
Definition: Commands.h:472
std::shared_ptr< RenderPassInstance > RPI
The render pass instance.
Definition: Commands.h:496
volatile bool * Event
The flag to reset when this command executes.
Definition: Commands.h:513
const Image & SrcImage
The source image.
Definition: Commands.h:242
const Image & DstImage
The destination image.
Definition: Commands.h:245
void reportCommandBegin(const Command *Cmd)
Definition: Device.cpp:243
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:30
uint64_t SrcAddr
The memory address of the source buffer.
Definition: Commands.h:216
volatile bool * Event
The flag to set when this command executes.
Definition: Commands.h:529
This file declares the PipelineExecutor class.
uint64_t DstAddr
The memory address of the destination buffer.
Definition: Commands.h:271
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:366
uint32_t getHeight(uint32_t Level=0) const
Returns the height of the image at the specified mip level.
Definition: Image.cpp:161
This file declares data structures and functions for handling images.
std::vector< VkImageCopy > Regions
The regions to copy.
Definition: Commands.h:248
VkClearColorValue Color
The clear color to use.
Definition: Commands.h:167
virtual void runImpl(Device &Dev) const =0
Command execution method for subclasses.
A Device instance encapsulates properties and state for the virtual device.
Definition: Device.h:29
uint32_t getDepth(uint32_t Level=0) const
Returns the depth of the image at the specified mip level.
Definition: Image.cpp:150
uint64_t NumBytes
The number of bytes to update.
Definition: Commands.h:550
const std::vector< ImageView * > & getAttachments() const
Returns the list of attachments backing this framebuffer.
Definition: RenderPass.h:32
void read(Texel &T, uint64_t Address) const
Read a texel from the image at the specified address.
Definition: Image.cpp:194
This file declares the RenderPass class and related data structures.
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:32
const RenderPass & getRenderPass() const
Returns the render pass.
Definition: RenderPass.h:113
This file declares the Memory class.
uint64_t SrcAddr
The memory address of the source buffer.
Definition: Commands.h:190
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:378
uint32_t getElementSize() const
Returns the size in bytes of a single pixel in the image.
Definition: Image.cpp:156
PipelineExecutor & getPipelineExecutor()
Returns the PipelineExecutor for this device.
Definition: Device.h:45
Memory & getGlobalMemory()
Get the global memory instance associated with this device.
Definition: Device.h:42
VkExtent3D getExtent() const
Returns the size of a single layer of the image.
Definition: Image.h:123
std::vector< uint32_t > ColorAttachments
Definition: RenderPass.h:62
This file declares the Command base class and its subclasses.
const Image & DstImage
The destination image.
Definition: Commands.h:111
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:354
uint64_t getTexelAddress(uint32_t X, uint32_t Y=0, uint32_t Z=0, uint32_t Layer=0, uint32_t MipLevel=0) const
Returns the address in memory of the texel at the specified coordinate.
Definition: Image.cpp:179
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:99
void store(uint64_t Address, uint64_t NumBytes, const uint8_t *Data)
Store NumBytes of data from Data to Address.
Definition: Memory.cpp:306
void reportCommandComplete(const Command *Cmd)
Definition: Device.cpp:248
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:138
UpdateBufferCommand(uint64_t Base, uint64_t NumBytes, const void *Data)
Create a new UpdateBufferCommand.
Definition: Commands.cpp:368
uint64_t getAddress() const
Returns the memory address of the beginning of the image.
Definition: Image.h:114
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:339
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:344
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:186
virtual void runImpl(Device &Dev) const override
Command execution handler.
Definition: Commands.cpp:364
uint32_t getNumMipLevels() const
Returns the number of mip levels in the image.
Definition: Image.h:138