From ef5f391ef53c12fddc0cf1161e1f9860bcc06fcf Mon Sep 17 00:00:00 2001 From: xiangsilian Date: Sun, 14 Sep 2025 20:37:53 +0800 Subject: [PATCH] save code --- .../api/texture_loading/texture_loading.cpp | 395 +----------------- samples/api/texture_loading/texture_loading.h | 30 +- 2 files changed, 7 insertions(+), 418 deletions(-) diff --git a/samples/api/texture_loading/texture_loading.cpp b/samples/api/texture_loading/texture_loading.cpp index e06dbd4..3165905 100644 --- a/samples/api/texture_loading/texture_loading.cpp +++ b/samples/api/texture_loading/texture_loading.cpp @@ -1,23 +1,4 @@ -/* Copyright (c) 2019-2025, Sascha Willems - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 the "License"; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Texture loading (and display) example (including mip maps) - */ #include "texture_loading.h" TextureLoading* TextureLoading::loadTextIns = nullptr; @@ -44,7 +25,7 @@ TextureLoading::~TextureLoading() } destroy_texture(texture); - + destroy_texture(cam_text); vertex_buffer.reset(); index_buffer.reset(); uniform_buffer_vs.reset(); @@ -60,354 +41,6 @@ void TextureLoading::request_gpu_features(vkb::PhysicalDevice &gpu) } } -/* - Upload texture image data to the GPU - - Vulkan offers two types of image tiling (memory layout): - - Linear tiled images: - These are stored as is and can be copied directly to. But due to the linear nature they're not a good match for GPUs and format and feature support is very limited. - It's not advised to use linear tiled images for anything else than copying from host to GPU if buffer copies are not an option. - Linear tiling is thus only implemented for learning purposes, one should always prefer optimal tiled image. - - Optimal tiled images: - These are stored in an implementation specific layout matching the capability of the hardware. They usually support more formats and features and are much faster. - Optimal tiled images are stored on the device and not accessible by the host. So they can't be written directly to (like liner tiled images) and always require - some sort of data copy, either from a buffer or a linear tiled image. - - In Short: Always use optimal tiled images for rendering. -*/ -void TextureLoading::load_texture() -{ - // We use the Khronos texture format (https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/) - std::string filename = vkb::fs::path::get(vkb::fs::path::Assets, "textures/metalplate01_rgba.ktx"); - // ktx1 doesn't know whether the content is sRGB or linear, but most tools save in sRGB, so assume that. - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - ktxTexture *ktx_texture; - KTX_error_code result; - - result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktx_texture); - - if (ktx_texture == nullptr) - { - throw std::runtime_error("Couldn't load texture"); - } - - // assert(!tex2D.empty()); - - texture.width = ktx_texture->baseWidth; - texture.height = ktx_texture->baseHeight; - texture.mip_levels = ktx_texture->numLevels; - - // We prefer using staging to copy the texture data to a device local optimal image - VkBool32 use_staging = true; - - // Only use linear tiling if forced - bool force_linear_tiling = false; - if (force_linear_tiling) - { - // Don't use linear if format is not supported for (linear) shader sampling - // Get device properties for the requested texture format - VkFormatProperties format_properties; - vkGetPhysicalDeviceFormatProperties(get_device().get_gpu().get_handle(), format, &format_properties); - use_staging = !(format_properties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); - } - - VkMemoryAllocateInfo memory_allocate_info = vkb::initializers::memory_allocate_info(); - VkMemoryRequirements memory_requirements = {}; - - ktx_uint8_t *ktx_image_data = ktx_texture->pData; - ktx_size_t ktx_texture_size = ktx_texture->dataSize; - - if (use_staging) - { - // Copy data to an optimal tiled image - // This loads the texture data into a host local buffer that is copied to the optimal tiled image on the device - - // Create a host-visible staging buffer that contains the raw image data - // This buffer will be the data source for copying texture data to the optimal tiled image on the device - VkBuffer staging_buffer; - VkDeviceMemory staging_memory; - - VkBufferCreateInfo buffer_create_info = vkb::initializers::buffer_create_info(); - buffer_create_info.size = ktx_texture_size; - // This buffer is used as a transfer source for the buffer copy - buffer_create_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK(vkCreateBuffer(get_device().get_handle(), &buffer_create_info, nullptr, &staging_buffer)); - - // Get memory requirements for the staging buffer (alignment, memory type bits) - vkGetBufferMemoryRequirements(get_device().get_handle(), staging_buffer, &memory_requirements); - memory_allocate_info.allocationSize = memory_requirements.size; - // Get memory type index for a host visible buffer - memory_allocate_info.memoryTypeIndex = - get_device().get_gpu().get_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VK_CHECK(vkAllocateMemory(get_device().get_handle(), &memory_allocate_info, nullptr, &staging_memory)); - VK_CHECK(vkBindBufferMemory(get_device().get_handle(), staging_buffer, staging_memory, 0)); - - // Copy texture data into host local staging buffer - - uint8_t *data; - VK_CHECK(vkMapMemory(get_device().get_handle(), staging_memory, 0, memory_requirements.size, 0, (void **) &data)); - memcpy(data, ktx_image_data, ktx_texture_size); - vkUnmapMemory(get_device().get_handle(), staging_memory); - - // Setup buffer copy regions for each mip level - std::vector buffer_copy_regions; - for (uint32_t i = 0; i < texture.mip_levels; i++) - { - ktx_size_t offset; - KTX_error_code result = ktxTexture_GetImageOffset(ktx_texture, i, 0, 0, &offset); - VkBufferImageCopy buffer_copy_region = {}; - buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - buffer_copy_region.imageSubresource.mipLevel = i; - buffer_copy_region.imageSubresource.baseArrayLayer = 0; - buffer_copy_region.imageSubresource.layerCount = 1; - buffer_copy_region.imageExtent.width = ktx_texture->baseWidth >> i; - buffer_copy_region.imageExtent.height = ktx_texture->baseHeight >> i; - buffer_copy_region.imageExtent.depth = 1; - buffer_copy_region.bufferOffset = offset; - buffer_copy_regions.push_back(buffer_copy_region); - } - - // Create optimal tiled target image on the device - VkImageCreateInfo image_create_info = vkb::initializers::image_create_info(); - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.format = format; - image_create_info.mipLevels = texture.mip_levels; - image_create_info.arrayLayers = 1; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - // Set initial layout of the image to undefined - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_create_info.extent = {texture.width, texture.height, 1}; - image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - VK_CHECK(vkCreateImage(get_device().get_handle(), &image_create_info, nullptr, &texture.image)); - - vkGetImageMemoryRequirements(get_device().get_handle(), texture.image, &memory_requirements); - memory_allocate_info.allocationSize = memory_requirements.size; - memory_allocate_info.memoryTypeIndex = get_device().get_gpu().get_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK(vkAllocateMemory(get_device().get_handle(), &memory_allocate_info, nullptr, &texture.device_memory)); - VK_CHECK(vkBindImageMemory(get_device().get_handle(), texture.image, texture.device_memory, 0)); - - VkCommandBuffer copy_command = get_device().create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Image memory barriers for the texture image - - // The sub resource range describes the regions of the image that will be transitioned using the memory barriers below - VkImageSubresourceRange subresource_range = {}; - // Image only contains color data - subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // Start at first mip level - subresource_range.baseMipLevel = 0; - // We will transition on all mip levels - subresource_range.levelCount = texture.mip_levels; - // The 2D texture only has one layer - subresource_range.layerCount = 1; - - // Transition the texture image layout to transfer target, so we can safely copy our buffer data to it. - VkImageMemoryBarrier image_memory_barrier = vkb::initializers::image_memory_barrier(); - - image_memory_barrier.image = texture.image; - image_memory_barrier.subresourceRange = subresource_range; - image_memory_barrier.srcAccessMask = 0; - image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) - // Destination pipeline stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - vkCmdPipelineBarrier( - copy_command, - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &image_memory_barrier); - - // Copy mip levels from staging buffer - vkCmdCopyBufferToImage( - copy_command, - staging_buffer, - texture.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(buffer_copy_regions.size()), - buffer_copy_regions.data()); - - // Once the data has been uploaded we transfer to the texture image to the shader read layout, so it can be sampled from - image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage stage is copy command execution (VK_PIPELINE_STAGE_TRANSFER_BIT) - // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - vkCmdPipelineBarrier( - copy_command, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &image_memory_barrier); - - // Store current layout for later reuse - texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - get_device().flush_command_buffer(copy_command, queue, true); - - // Clean up staging resources - vkDestroyBuffer(get_device().get_handle(), staging_buffer, nullptr); - vkFreeMemory(get_device().get_handle(), staging_memory, nullptr); - } - else - { - // Copy data to a linear tiled image - - VkImage mappable_image; - VkDeviceMemory mappable_memory; - - // Load mip map level 0 to linear tiling image - VkImageCreateInfo image_create_info = vkb::initializers::image_create_info(); - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.format = format; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.tiling = VK_IMAGE_TILING_LINEAR; - image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - image_create_info.extent = {texture.width, texture.height, 1}; - VK_CHECK(vkCreateImage(get_device().get_handle(), &image_create_info, nullptr, &mappable_image)); - - // Get memory requirements for this image like size and alignment - vkGetImageMemoryRequirements(get_device().get_handle(), mappable_image, &memory_requirements); - // Set memory allocation size to required memory size - memory_allocate_info.allocationSize = memory_requirements.size; - // Get memory type that can be mapped to host memory - memory_allocate_info.memoryTypeIndex = - get_device().get_gpu().get_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VK_CHECK(vkAllocateMemory(get_device().get_handle(), &memory_allocate_info, nullptr, &mappable_memory)); - VK_CHECK(vkBindImageMemory(get_device().get_handle(), mappable_image, mappable_memory, 0)); - - // Map image memory - void *data; - ktx_size_t ktx_image_size = ktxTexture_GetImageSize(ktx_texture, 0); - VK_CHECK(vkMapMemory(get_device().get_handle(), mappable_memory, 0, memory_requirements.size, 0, &data)); - // Copy image data of the first mip level into memory - memcpy(data, ktx_image_data, ktx_image_size); - vkUnmapMemory(get_device().get_handle(), mappable_memory); - - // Linear tiled images don't need to be staged and can be directly used as textures - texture.image = mappable_image; - texture.device_memory = mappable_memory; - texture.image_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - // Setup image memory barrier transfer image to shader read layout - VkCommandBuffer copy_command = get_device().create_command_buffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // The sub resource range describes the regions of the image we will be transition - VkImageSubresourceRange subresource_range = {}; - subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresource_range.baseMipLevel = 0; - subresource_range.levelCount = 1; - subresource_range.layerCount = 1; - - // Transition the texture image layout to shader read, so it can be sampled from - VkImageMemoryBarrier image_memory_barrier = vkb::initializers::image_memory_barrier(); - ; - image_memory_barrier.image = texture.image; - image_memory_barrier.subresourceRange = subresource_range; - image_memory_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - // Insert a memory dependency at the proper pipeline stages that will execute the image layout transition - // Source pipeline stage is host write/read execution (VK_PIPELINE_STAGE_HOST_BIT) - // Destination pipeline stage fragment shader access (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) - vkCmdPipelineBarrier( - copy_command, - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, nullptr, - 0, nullptr, - 1, &image_memory_barrier); - - get_device().flush_command_buffer(copy_command, queue, true); - } - - // now, the ktx_texture can be destroyed - ktxTexture_Destroy(ktx_texture); - - // Calculate valid filter and mipmap modes - VkFilter filter = VK_FILTER_LINEAR; - VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - vkb::make_filters_valid(get_device().get_gpu().get_handle(), format, &filter, &mipmap_mode); - - // Create a texture sampler - // In Vulkan textures are accessed by samplers - // This separates all the sampling information from the texture data. This means you could have multiple sampler objects for the same texture with different settings - // Note: Similar to the samplers available with OpenGL 3.3 - VkSamplerCreateInfo sampler = vkb::initializers::sampler_create_info(); - sampler.magFilter = filter; - sampler.minFilter = filter; - sampler.mipmapMode = mipmap_mode; - sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - sampler.mipLodBias = 0.0f; - sampler.compareOp = VK_COMPARE_OP_NEVER; - sampler.minLod = 0.0f; - // Set max level-of-detail to mip level count of the texture - sampler.maxLod = (use_staging) ? static_cast(texture.mip_levels) : 0.0f; - // Enable anisotropic filtering - // This feature is optional, so we must check if it's supported on the device - if (get_device().get_gpu().get_features().samplerAnisotropy) - { - // Use max. level of anisotropy for this example - sampler.maxAnisotropy = get_device().get_gpu().get_properties().limits.maxSamplerAnisotropy; - sampler.anisotropyEnable = VK_TRUE; - } - else - { - // The device does not support anisotropic filtering - sampler.maxAnisotropy = 1.0; - sampler.anisotropyEnable = VK_FALSE; - } - sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK(vkCreateSampler(get_device().get_handle(), &sampler, nullptr, &texture.sampler)); - - // Create image view - // Textures are not directly accessed by the shaders and - // are abstracted by image views containing additional - // information and sub resource ranges - VkImageViewCreateInfo view = vkb::initializers::image_view_create_info(); - view.viewType = VK_IMAGE_VIEW_TYPE_2D; - view.format = format; - view.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; - // The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view - // It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image - view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view.subresourceRange.baseMipLevel = 0; - view.subresourceRange.baseArrayLayer = 0; - view.subresourceRange.layerCount = 1; - // Linear tiling usually won't support mip maps - // Only set mip map count if optimal tiling is used - view.subresourceRange.levelCount = (use_staging) ? texture.mip_levels : 1; - // The view will be based on the texture's image - view.image = texture.image; - VK_CHECK(vkCreateImageView(get_device().get_handle(), &view, nullptr, &texture.view)); -} - -// Free all Vulkan resources used by a texture object void TextureLoading::destroy_texture(Texture texture) { vkDestroyImageView(get_device().get_handle(), texture.view, nullptr); @@ -776,7 +409,7 @@ bool TextureLoading::prepare(const vkb::ApplicationOptions &options) std::cout << "Row stride: " << rowStride << std::endl; std::cout << "Data size: " << dataSize << " bytes" << std::endl; - processWithVulkan(testImage.data(), width, height, 1, rowStride, dataSize); + processWithVulkan(testImage.data(), width, height, 1, rowStride, dataSize, texture); generate_quad(); @@ -828,23 +461,20 @@ std::unique_ptr create_texture_loading() 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); + TextureLoading::Texture& cam_texture = TextureLoading::Get()->cam_text; + TextureLoading::Get()->processWithVulkan(data, width, height, format, rowStride, dataSize, cam_texture); } -void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize) +void TextureLoading::processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize, Texture& out_texture) { - 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); } @@ -856,7 +486,6 @@ void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDev texture.height = height; texture.mip_levels = 1; - // 创建图像 VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -876,7 +505,6 @@ void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDev throw std::runtime_error("Failed to create image!"); } - // 分配内存 VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(device, texture.image, &memRequirements); @@ -892,7 +520,6 @@ void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDev vkBindImageMemory(device, texture.image, texture.device_memory, 0); - // 创建图像视图 VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = texture.image; @@ -908,7 +535,6 @@ void TextureLoading::createTexture(VkDevice device, VkPhysicalDevice physicalDev 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; @@ -939,7 +565,6 @@ void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDev uint8_t* data, int width, int height, int rowStride, size_t dataSize, Texture& texture) { - // 创建临时 staging buffer VkBuffer stagingBuffer; VkDeviceMemory stagingBufferMemory; @@ -969,17 +594,13 @@ void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDev 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; @@ -993,15 +614,12 @@ void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDev 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; @@ -1017,21 +635,18 @@ void TextureLoading::updateTexture(VkDevice device, VkPhysicalDevice physicalDev 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; diff --git a/samples/api/texture_loading/texture_loading.h b/samples/api/texture_loading/texture_loading.h index 08f3b4a..fc2f0df 100644 --- a/samples/api/texture_loading/texture_loading.h +++ b/samples/api/texture_loading/texture_loading.h @@ -1,23 +1,3 @@ -/* Copyright (c) 2019-2024, Sascha Willems - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 the "License"; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Texture loading (and display) example (including mip maps) - */ #pragma once @@ -25,7 +5,6 @@ #include "api_vulkan_sample.h" -// Vertex layout for this example struct TextureLoadingVertexStructure { float pos[3]; @@ -36,8 +15,6 @@ struct TextureLoadingVertexStructure class TextureLoading : public ApiVulkanSample { public: - // Contains all Vulkan objects that are required to store and use a texture - // Note that this repository contains a texture class (vulkan_texture.h) that encapsulates texture loading functionality in a class that is used in subsequent demos struct Texture { VkSampler sampler; @@ -81,8 +58,6 @@ class TextureLoading : public ApiVulkanSample TextureLoading(); ~TextureLoading(); virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; - void load_texture(); - void destroy_texture(Texture texture); void build_command_buffers() override; void draw(); void generate_quad(); @@ -96,17 +71,16 @@ 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; - + void destroy_texture(Texture texture); public: - void processWithVulkan(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, Texture& out_texture); 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);