@@ -280,15 +280,92 @@ memory for a buffer. Use `vkGetImageMemoryRequirements` instead of
280280able to use `vkMapMemory`, so you should specify that property when looking for
281281the right memory type.
282282
283+ We can now use the `vkMapMemory` function to (temporarily) access the memory of
284+ the staging image directly from our application. It returns a pointer to the
285+ first byte in the memory buffer:
286+
283287```c++
284288void* data;
285289vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
290+ ```
291+
292+ Unfortunately we can't just copy the pixel bytes directly into the image memory
293+ with ` memcpy ` and assume that this works correctly. The problem is that there
294+ may be padding bytes between rows of pixels. In other words, the graphics card
295+ may assume that one row of pixels is not ` texWidth * 4 ` bytes wide, but rather
296+ ` texWidth * 4 + paddingBytes ` . To handle this correctly, we need to query how
297+ bytes are arranged in our staging image using ` vkGetImageSubresourceLayout ` :
298+
299+ ``` c++
300+ VkImageSubresource subresource = {};
301+ subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
302+ subresource.mipLevel = 0 ;
303+ subresource.arrayLayer = 0 ;
304+
305+ VkSubresourceLayout stagingImageLayout;
306+ vkGetImageSubresourceLayout (device, stagingImage, &subresource, &stagingImageLayout);
307+ ```
308+
309+ Images contain one or more *subresources*, which are specific images within an
310+ image. For example, there is one subresource for every entry in an array image.
311+ In this case we don't have an array image, so there is simply one subresource at
312+ entry 0 and the base mipmapping level.
313+
314+ The `rowPitch` member of the `VkSubresourceLayout` struct specifies the total
315+ number of bytes of each row of pixels in the image. If this value is equal to
316+ `texWidth * 4`, then we're lucky and we *can* use `memcpy`, because there are no
317+ padding bytes in that case.
318+
319+ ```c++
320+ if (stagingImageLayout.rowPitch == texWidth * 4) {
286321 memcpy(data, pixels, (size_t) imageSize);
322+ } else {
323+
324+ }
325+ ```
326+
327+ This is usually the case when your images have a power-of-2 size (e.g. 512 or
328+ 1024). Otherwise, we'll have to copy the pixels row-by-row using the right
329+ offset:
330+
331+ ``` c++
332+ uint8_t * dataBytes = reinterpret_cast <uint8_t *>(data);
333+
334+ for (int y = 0 ; y < texHeight; y++) {
335+ memcpy (
336+ &dataBytes[y * stagingImageLayout.rowPitch],
337+ &pixels[y * texWidth * 4],
338+ texWidth * 4
339+ );
340+ }
341+ ```
342+
343+ Each subsequent row in the image memory is offset by ` rowPitch ` and the original
344+ pixels are offset by ` texWidth * 4 ` without padding bytes.
345+
346+ If you're done accessing the memory buffer, then you should unmap it with
347+ ` vkUnmapMemory ` . It is not necessary to call ` vkUnmapMemory ` now if you want to
348+ access the staging image memory again later on. The writes to the buffer will
349+ already be visible without calling this function.
350+
351+ ``` c++
352+ void * data;
353+ vkMapMemory (device, stagingImageMemory, 0, imageSize, 0, &data);
354+
355+ if (stagingImageLayout.rowPitch == texWidth * 4) {
356+ memcpy(data, pixels, (size_t) imageSize);
357+ } else {
358+ uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
359+
360+ for (int y = 0; y < texHeight; y++) {
361+ memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
362+ }
363+ }
364+
287365vkUnmapMemory(device, stagingImageMemory);
288366```
289367
290- We can now copy the pixel data straight to the memory of the image. Don't forget
291- to clean up the pixel array now:
368+ Don't forget to clean up the original pixel array now:
292369
293370```c++
294371stbi_image_free(pixels);
@@ -357,9 +434,27 @@ void createTextureImage() {
357434 VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
358435 createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory);
359436
437+ VkImageSubresource subresource = {};
438+ subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
439+ subresource.mipLevel = 0;
440+ subresource.arrayLayer = 0;
441+
442+ VkSubresourceLayout stagingImageLayout;
443+ vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
444+
360445 void* data;
361446 vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
447+
448+ if (stagingImageLayout.rowPitch == texWidth * 4) {
362449 memcpy(data, pixels, (size_t) imageSize);
450+ } else {
451+ uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
452+
453+ for (int y = 0; y < texHeight; y++) {
454+ memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
455+ }
456+ }
457+
363458 vkUnmapMemory(device, stagingImageMemory);
364459
365460 stbi_image_free(pixels);
0 commit comments