ETH官方钱包

前往
大廳
主題

Vulkan 學習筆記 Image buffer

%%鼠 拒收病婿 | 2025-01-08 19:36:01 | 巴幣 1328 | 人氣 46

成品:
  • 可以resize
  • 套用貼圖
現有問題: Validation會彈出錯誤警告,有些裝置可能跑不起來。




STB讀取圖片

一張圖片需要 image , view , memory ,sampler。

在cpp檔案引入stb header:
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>


void ltn::Image::load_texture(const char* path)
{
    // STBI_rgb_alpha value forces the image to be loaded with an alpha channel, even if it doesn't have one.
    // The pixels are laid out row by row with 4 bytes per pixel in the case of STBI_rgb_alpha.
    stbi_uc* pixels = stbi_load(path, &m_width, &m_height, &m_channel, STBI_rgb_alpha);
    VkDeviceSize imageSize = m_width * m_height * 4;

    if (!pixels) {
        throw std::runtime_error("failed to load texture image!");
    }
    // create a buffer to hold the pixel data
    createBuffer(
        m_core_instance.get_device(),
        m_core_instance.get_physical_device(),
        imageSize,
        VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
        m_staging_buffer,
        m_staging_buffer_memory);

    void* data;
    vkMapMemory(m_core_instance.get_device(), m_staging_buffer_memory, 0, imageSize, 0, &data);
    memcpy(data, pixels, static_cast<size_t>(imageSize));
    vkUnmapMemory(m_core_instance.get_device(), m_staging_buffer_memory);
    stbi_image_free(pixels);
    // move buffer to image memory
    create_texture();
    createTextureImageView();
    createTextureSampler();

    //----------------
    //  Descriptor
    //----------------
    create_descriptor_pool();
    createDescriptorSetLayout();
    create_descriptor();
}


Image view


void ltn::Image::createTextureImageView()
{
    VkImageViewCreateInfo viewInfo{};
    viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    viewInfo.image = m_texture_image;
    viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
    viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
    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(
        m_core_instance.get_device(),
        &viewInfo, nullptr, &m_texture_imageView) != VK_SUCCESS) {
        throw std::runtime_error("failed to create texture image view!");
    }
}

Sampler


void ltn::Image::createTextureSampler()
{
    // Get maxAnisotropy
    VkPhysicalDeviceProperties properties{};
    vkGetPhysicalDeviceProperties(m_core_instance.get_physical_device(), &properties);

    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_REPEAT;
    samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
    //samplerInfo.anisotropyEnable = VK_TRUE;
    samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
    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;

    samplerInfo.anisotropyEnable = VK_FALSE;  // Temp
    samplerInfo.maxAnisotropy = 1.0f;
    if (vkCreateSampler(m_core_instance.get_device(), &samplerInfo, nullptr, &m_texture_sampler) != VK_SUCCESS) {
        throw std::runtime_error("failed to create texture sampler!");
    }
}

在Pipeline要設定

pipelineLayoutInfo.setLayoutCount = descriptors->size();
pipelineLayoutInfo.pSetLayouts = descriptors->data();

因為我是用vector串接descriptors,所以第二個append上來的是image的descriptor,使用set = 1
#version 450

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;

layout(location = 0) out vec4 outColor;

layout(set=1,binding = 0) uniform sampler2D texSampler;
void main() {

    outColor = texture(texSampler, fragTexCoord);
}

串接方式:
  • 未來優化方向: 應該規劃好哪些元件會綁到哪個descriptorSet編號。

std::vector<VkDescriptorSetLayout>* ltn::GameObject::get_all_descriptorLayouts()
{
    for (int i = 0; i < m_components.size(); ++i) {
        auto descrip = m_components[i]->get_descriptorset_layout();
        if (descrip != NULL) {
            m_descriptorSetLayouts.push_back(descrip);
        }
    }

    return &m_descriptorSetLayouts;
}


搬運Image Memory

比起一般的buffer物件,圖片有自己Image的類別。 為了將記憶體轉成Shader最佳化的Image類別,我們需要VkImageMemoryBarrier來轉換Image的layout。

從一開始的VK_IMAGE_LAYOUT_UNDEFINED轉成TRANSFER_DST_OPTIMAL (因為要把它從staging buffer轉到GPU local memory上)。最後再轉成SHADER_READ_ONLY_OPTIMAL (shader讀取最佳化格式)

送禮物贊助創作者 !
0
留言

創作回應

相關創作

更多創作