From e8cf1c6a2feee5efc0a1ece497f48f83682b1716 Mon Sep 17 00:00:00 2001 From: Xiang Silian Date: Thu, 11 Sep 2025 18:31:09 +0800 Subject: [PATCH] save code --- components/android/src/context.cpp | 6 +- .../api/texture_loading/texture_loading.cpp | 362 +++++++++++++++++- samples/api/texture_loading/texture_loading.h | 26 +- 3 files changed, 389 insertions(+), 5 deletions(-) diff --git a/components/android/src/context.cpp b/components/android/src/context.cpp index b8002af..9c3c9a4 100644 --- a/components/android/src/context.cpp +++ b/components/android/src/context.cpp @@ -109,6 +109,8 @@ Java_com_khronos_vulkan_1samples_MainActivity_nativeButtonClicked(JNIEnv *env, j LOGI("call MainActivity_nativeButtonClicked."); } +extern void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize); + void processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize) { // Vulkan 处理逻辑 @@ -116,8 +118,8 @@ void processWithVulkan(uint8_t* data, int width, int height, int format, // 2. 将数据复制到 Vulkan 图像内存 // 3. 执行 Vulkan 渲染或计算操作 - LOGI("ProcessingImage: %dx%d, stride: %d, size: %zu", - width, height, rowStride, dataSize); + LOGI("ProcessingImage: %dx%d, stride: %d, size: %zu", width, height, rowStride, dataSize); + TextureLoadProcessWithVulkan(data, width, height, format, rowStride, dataSize); } extern "C" diff --git a/samples/api/texture_loading/texture_loading.cpp b/samples/api/texture_loading/texture_loading.cpp index 71ad321..e06dbd4 100644 --- a/samples/api/texture_loading/texture_loading.cpp +++ b/samples/api/texture_loading/texture_loading.cpp @@ -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() } } +// ɼ򵥵IJͼݣɫ +std::vector 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 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 create_texture_loading() { return std::make_unique(); } + +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(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(width), + static_cast(height), 1 }; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + // תͼ񲼾Ϊɫȡ + 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); +} \ No newline at end of file diff --git a/samples/api/texture_loading/texture_loading.h b/samples/api/texture_loading/texture_loading.h index 3484b65..08f3b4a 100644 --- a/samples/api/texture_loading/texture_loading.h +++ b/samples/api/texture_loading/texture_loading.h @@ -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 vertex_buffer; std::unique_ptr 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 create_texture_loading();