save code

This commit is contained in:
xsl
2025-09-11 18:31:09 +08:00
parent 80ff2a091a
commit e8cf1c6a2f
3 changed files with 389 additions and 5 deletions
+361 -1
View File
@@ -20,12 +20,14 @@
*/
#include "texture_loading.h"
TextureLoading* TextureLoading::loadTextIns = nullptr;
TextureLoading::TextureLoading()
{
zoom = -2.5f;
rotation = {0.0f, 15.0f, 0.0f};
title = "Texture loading";
loadTextIns = this;
}
TextureLoading::~TextureLoading()
@@ -463,6 +465,47 @@ void TextureLoading::build_command_buffers()
}
}
// 生成简单的测试图像数据(红绿蓝三色条)
std::vector<uint8_t> generateSimpleTestImage(int width, int height, int* outRowStride = nullptr) {
int rowStride = width * 4; // RGBA 每个像素4字节
if (outRowStride) {
*outRowStride = rowStride;
}
size_t dataSize = rowStride * height;
std::vector<uint8_t> imageData(dataSize, 0);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixelOffset = y * rowStride + x * 4;
// 简单分成三个区域:红、绿、蓝
if (x < width / 3) {
// 红色区域
imageData[pixelOffset] = 255; // R
imageData[pixelOffset + 1] = 0; // G
imageData[pixelOffset + 2] = 0; // B
}
else if (x < 2 * width / 3) {
// 绿色区域
imageData[pixelOffset] = 0; // R
imageData[pixelOffset + 1] = 255; // G
imageData[pixelOffset + 2] = 0; // B
}
else {
// 蓝色区域
imageData[pixelOffset] = 0; // R
imageData[pixelOffset + 1] = 0; // G
imageData[pixelOffset + 2] = 255; // B
}
imageData[pixelOffset + 3] = 255; // A (完全不透明)
}
}
return imageData;
}
void TextureLoading::draw()
{
ApiVulkanSample::prepare_frame();
@@ -721,7 +764,21 @@ bool TextureLoading::prepare(const vkb::ApplicationOptions &options)
{
return false;
}
load_texture();
//load_texture();
int width = 640;
int height = 480;
int rowStride;
auto testImage = generateSimpleTestImage(width, height, &rowStride);
size_t dataSize = testImage.size();
std::cout << "Generated test image: " << width << "x" << height << std::endl;
std::cout << "Row stride: " << rowStride << std::endl;
std::cout << "Data size: " << dataSize << " bytes" << std::endl;
processWithVulkan(testImage.data(), width, height, 1, rowStride, dataSize);
generate_quad();
prepare_uniform_buffers();
setup_descriptor_set_layout();
@@ -739,6 +796,12 @@ void TextureLoading::render(float delta_time)
{
return;
}
if (texture.width == 0)
{
return;
}
draw();
}
@@ -762,3 +825,300 @@ std::unique_ptr<vkb::Application> create_texture_loading()
{
return std::make_unique<TextureLoading>();
}
void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize)
{
TextureLoading::Get()->processWithVulkan(data, width, height, format, rowStride, dataSize);
}
void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize)
{
Texture& out_texture = texture; //cam_text;
VkDevice& device = get_device().get_handle();
const VkPhysicalDevice& physicalDevice = get_device().get_gpu().get_handle();
// 检查是否需要创建新纹理
if (out_texture.image == VK_NULL_HANDLE) {
createTexture(device, physicalDevice, width, height, format, out_texture);
}
const VkCommandPool& commandPool = get_device().get_command_pool().get_handle();
// 更新纹理数据
updateTexture(device, physicalDevice, commandPool, queue, data, width, height,
rowStride, dataSize, out_texture);
}
void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDevice,
int width, int height, int format, Texture& texture) {
texture.width = width;
texture.height = height;
texture.mip_levels = 1;
// 创建图像
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; // 匹配 RGBA_8888
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (vkCreateImage(device, &imageInfo, nullptr, &texture.image) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image!");
}
// 分配内存
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, texture.image, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(physicalDevice,
memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (vkAllocateMemory(device, &allocInfo, nullptr, &texture.device_memory) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate image memory!");
}
vkBindImageMemory(device, texture.image, texture.device_memory, 0);
// 创建图像视图
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = texture.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device, &viewInfo, nullptr, &texture.view) != VK_SUCCESS) {
throw std::runtime_error("Failed to create texture image view!");
}
// 创建采样器
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
if (vkCreateSampler(device, &samplerInfo, nullptr, &texture.sampler) != VK_SUCCESS) {
throw std::runtime_error("Failed to create texture sampler!");
}
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDevice,
VkCommandPool commandPool, VkQueue queue,
uint8_t* data, int width, int height,
int rowStride, size_t dataSize, Texture& texture) {
// 创建临时 staging buffer
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
VkBufferCreateInfo bufferInfo = {};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = dataSize;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer) != VK_SUCCESS) {
throw std::runtime_error("Failed to create staging buffer!");
}
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements);
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(physicalDevice,
memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
if (vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory) != VK_SUCCESS) {
throw std::runtime_error("Failed to allocate staging buffer memory!");
}
vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0);
// 复制数据到 staging buffer
void* mappedData;
vkMapMemory(device, stagingBufferMemory, 0, dataSize, 0, &mappedData);
// 处理行步长不一致的情况
if (rowStride == width * 4) {
// 行步长匹配,直接复制
memcpy(mappedData, data, dataSize);
}
else {
// 需要逐行复制,处理 padding
uint8_t* dst = static_cast<uint8_t*>(mappedData);
const uint8_t* src = data;
size_t dstRowStride = width * 4;
for (int y = 0; y < height; y++) {
memcpy(dst, src, dstRowStride);
dst += dstRowStride;
src += rowStride;
}
}
vkUnmapMemory(device, stagingBufferMemory);
// 创建命令缓冲区
VkCommandBuffer commandBuffer = beginSingleTimeCommands(device, commandPool);
// 转换图像布局为传输目标
transitionImageLayout(commandBuffer, texture.image,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// 复制 buffer 到 image
VkBufferImageCopy region = {};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { static_cast<uint32_t>(width),
static_cast<uint32_t>(height), 1 };
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
// 转换图像布局为着色器读取
transitionImageLayout(commandBuffer, texture.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
endSingleTimeCommands(device, commandPool, queue, commandBuffer);
// 清理临时资源
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
// 辅助函数
uint32_t TextureLoading::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter,
VkMemoryPropertyFlags properties) {
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
if ((typeFilter & (1 << i)) &&
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
return i;
}
}
throw std::runtime_error("Failed to find suitable memory type!");
}
VkCommandBuffer TextureLoading::beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool) {
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
return commandBuffer;
}
void TextureLoading::endSingleTimeCommands(VkDevice device, VkCommandPool commandPool,
VkQueue queue, VkCommandBuffer commandBuffer) {
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(queue);
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
}
void TextureLoading::transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
VkImageLayout oldLayout, VkImageLayout newLayout) {
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED &&
newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else {
throw std::invalid_argument("Unsupported layout transition!");
}
vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0,
0, nullptr, 0, nullptr, 1, &barrier);
}
+24 -2
View File
@@ -47,7 +47,10 @@ class TextureLoading : public ApiVulkanSample
VkImageView view;
uint32_t width, height;
uint32_t mip_levels;
} texture;
};
Texture texture = {0};
Texture cam_text = {0};
std::unique_ptr<vkb::core::BufferC> vertex_buffer;
std::unique_ptr<vkb::core::BufferC> index_buffer;
@@ -71,7 +74,10 @@ class TextureLoading : public ApiVulkanSample
VkPipelineLayout pipeline_layout;
VkDescriptorSet descriptor_set;
VkDescriptorSetLayout descriptor_set_layout;
static TextureLoading* Get() {
return loadTextIns;
}
static TextureLoading* loadTextIns;
TextureLoading();
~TextureLoading();
virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override;
@@ -90,6 +96,22 @@ class TextureLoading : public ApiVulkanSample
virtual void render(float delta_time) override;
virtual void view_changed() override;
virtual void on_update_ui_overlay(vkb::Drawer &drawer) override;
public:
void processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize);
void createTexture(VkDevice device, VkPhysicalDevice physicalDevice, int width, int height, int format, Texture& texture);
void updateTexture(VkDevice device, VkPhysicalDevice physicalDevice, VkCommandPool commandPool, VkQueue queue, uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture);
// 辅助函数
uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties);
VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool);
void endSingleTimeCommands(VkDevice device, VkCommandPool commandPool, VkQueue queue, VkCommandBuffer commandBuffer);
void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout);
};
std::unique_ptr<vkb::Application> create_texture_loading();