Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 65b519d

Browse files
committed
Fix image chapter ignoring rowPitch subresource requirements
1 parent 664832d commit 65b519d

6 files changed

Lines changed: 187 additions & 2 deletions

File tree

06_Texture_mapping/00_Images.md

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,15 +280,92 @@ memory for a buffer. Use `vkGetImageMemoryRequirements` instead of
280280
able to use `vkMapMemory`, so you should specify that property when looking for
281281
the 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++
284288
void* data;
285289
vkMapMemory(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+
287365
vkUnmapMemory(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++
294371
stbi_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);

code/depth_buffering.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,9 +794,27 @@ class HelloTriangleApplication {
794794
VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
795795
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);
796796

797+
VkImageSubresource subresource = {};
798+
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
799+
subresource.mipLevel = 0;
800+
subresource.arrayLayer = 0;
801+
802+
VkSubresourceLayout stagingImageLayout;
803+
vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
804+
797805
void* data;
798806
vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
807+
808+
if (stagingImageLayout.rowPitch == texWidth * 4) {
799809
memcpy(data, pixels, (size_t) imageSize);
810+
} else {
811+
uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
812+
813+
for (int y = 0; y < texHeight; y++) {
814+
memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
815+
}
816+
}
817+
800818
vkUnmapMemory(device, stagingImageMemory);
801819

802820
stbi_image_free(pixels);

code/model_loading.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,9 +800,27 @@ class HelloTriangleApplication {
800800
VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
801801
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);
802802

803+
VkImageSubresource subresource = {};
804+
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
805+
subresource.mipLevel = 0;
806+
subresource.arrayLayer = 0;
807+
808+
VkSubresourceLayout stagingImageLayout;
809+
vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
810+
803811
void* data;
804812
vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
813+
814+
if (stagingImageLayout.rowPitch == texWidth * 4) {
805815
memcpy(data, pixels, (size_t) imageSize);
816+
} else {
817+
uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
818+
819+
for (int y = 0; y < texHeight; y++) {
820+
memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
821+
}
822+
}
823+
806824
vkUnmapMemory(device, stagingImageMemory);
807825

808826
stbi_image_free(pixels);

code/sampler.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,9 +705,27 @@ class HelloTriangleApplication {
705705
VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
706706
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);
707707

708+
VkImageSubresource subresource = {};
709+
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
710+
subresource.mipLevel = 0;
711+
subresource.arrayLayer = 0;
712+
713+
VkSubresourceLayout stagingImageLayout;
714+
vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
715+
708716
void* data;
709717
vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
718+
719+
if (stagingImageLayout.rowPitch == texWidth * 4) {
710720
memcpy(data, pixels, (size_t) imageSize);
721+
} else {
722+
uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
723+
724+
for (int y = 0; y < texHeight; y++) {
725+
memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
726+
}
727+
}
728+
711729
vkUnmapMemory(device, stagingImageMemory);
712730

713731
stbi_image_free(pixels);

code/texture_image.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,27 @@ class HelloTriangleApplication {
718718
VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
719719
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);
720720

721+
VkImageSubresource subresource = {};
722+
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
723+
subresource.mipLevel = 0;
724+
subresource.arrayLayer = 0;
725+
726+
VkSubresourceLayout stagingImageLayout;
727+
vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
728+
721729
void* data;
722730
vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
731+
732+
if (stagingImageLayout.rowPitch == texWidth * 4) {
723733
memcpy(data, pixels, (size_t) imageSize);
734+
} else {
735+
uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
736+
737+
for (int y = 0; y < texHeight; y++) {
738+
memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
739+
}
740+
}
741+
724742
vkUnmapMemory(device, stagingImageMemory);
725743

726744
stbi_image_free(pixels);

code/texture_mapping.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,9 +719,27 @@ class HelloTriangleApplication {
719719
VDeleter<VkDeviceMemory> stagingImageMemory{device, vkFreeMemory};
720720
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);
721721

722+
VkImageSubresource subresource = {};
723+
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
724+
subresource.mipLevel = 0;
725+
subresource.arrayLayer = 0;
726+
727+
VkSubresourceLayout stagingImageLayout;
728+
vkGetImageSubresourceLayout(device, stagingImage, &subresource, &stagingImageLayout);
729+
722730
void* data;
723731
vkMapMemory(device, stagingImageMemory, 0, imageSize, 0, &data);
732+
733+
if (stagingImageLayout.rowPitch == texWidth * 4) {
724734
memcpy(data, pixels, (size_t) imageSize);
735+
} else {
736+
uint8_t* dataBytes = reinterpret_cast<uint8_t*>(data);
737+
738+
for (int y = 0; y < texHeight; y++) {
739+
memcpy(&dataBytes[y * stagingImageLayout.rowPitch], &pixels[y * texWidth * 4], texWidth * 4);
740+
}
741+
}
742+
725743
vkUnmapMemory(device, stagingImageMemory);
726744

727745
stbi_image_free(pixels);

0 commit comments

Comments
 (0)