NicolBolas 是正确的,它需要硬件自动将非 4 通道图像传输到 4 通道图像内存,或者支持 3 通道图像纹理。但是,为什么不充分利用吞吐量增强功能并使用计算着色器将纹理作为着色器缓冲区,并以正确的格式读出数据,而不是像从主机逐像素复制图像那样缓慢地进行操作?
这就是我的意思:
使用图像的示例
正如所指出的,您还可以直接写入图像缓冲区,这意味着您不必调用单独的缓冲区副本来复制图像。
#version 450
// should be tightly packed if I read the spec correctly
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf
layout(std430, binding = 0) buffer in_3_channel
{
vec3 input_channel[ ];
};
layout (binding = 1, rgba32f) uniform image2D result_image;
layout (local_size_x = 256) in;
layout (binding = 2) uniform UBO
{
int image_size;
int image_cols;
} ubo;
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= ubo.image_size){
return;
}
vec3 in_color = input_channel[index];
vec4 out_color = vec4(in_color, 1.0);
// using an image instead, we would write using this:
int row = gl_GlobalInvocationID.x / image_cols;
int col = gl_GlobalInvocationID.x % image_cols;
ivec2 image_write_location = ivec2(row, col);
imageStore(result_image, image_write_location, out_color);
}
使用缓冲区的示例:
#version 450
// should be tightly packed if I read the spec correctly
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf
layout(std430, binding = 0) buffer in_3_channel
{
vec3 input_channel[ ];
};
layout(std430, binding = 1) buffer out_4_channel{
vec4 output_channel[ ];
};
//alternatively you could use a image buffer directly ex:
//
//layout (binding = 1, rgba32f) uniform image2D result_image;
layout (local_size_x = 256) in;
layout (binding = 2) uniform UBO
{
int image_size;
} ubo;
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= ubo.image_size){
return;
}
vec3 in_color = input_channel[index];
vec4 out_color = vec4(in_color, 1.0);
output_channel[index] = out_color;
// using an image instead, we would write using this:
// ivec2 image_write_location = ivec2(gl_GlobalInvocationID.x / image_cols, gl_GlobalInvocationID.x % image_cols);
//imageStore(result_image, image_write_location, out_color);
}
如果您想将缓冲区复制到纹理,则可以将数据复制到图像,如下例所示:https://vulkan-tutorial.com/Texture_mapping/Images https://vulkan-tutorial.com/Texture_mapping/Images
//staging buffer is your new converted RGB -> RGBA buffer.
transitionImageLayout(textureImage, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
transitionImageLayout(textureImage, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
结论
现在,您已经获得了主机->设备带宽优势,利用了 GPU 的计算能力,并且仅在 3 通道内存的初始传输中接触了主机。