2016-03-21 12 views
8

Tôi đã cố gắng tải hình ảnh nén với nén S3TC (BC/DXT) trong Vulkan, nhưng cho đến nay tôi chưa có nhiều may mắn.Không thể tạo hình ảnh từ dữ liệu kết cấu nén (S3TC)

Dưới đây là những gì các đặc điểm kỹ thuật Vulkan nói về những hình ảnh nén:

https://www.khronos.org/registry/dataformat/specs/1.1/dataformat.1.1.html#S3TC:

hình ảnh kết cấu nén được lưu trữ bằng cách sử dụng các định dạng hình ảnh S3TC nén được biểu diễn dưới dạng một tập hợp các khối 4 × 4 Texel, nơi mỗi khối chứa 64 hoặc 128 bit dữ liệu texel. Hình ảnh được mã hóa dưới dạng hình ảnh raster 2D thông thường, trong đó mỗi khối 4 × 4 được coi là một pixel đơn lẻ.

https://www.khronos.org/registry/vulkan/specs/1.0/xhtml/vkspec.html#resources-images:

Đối với hình ảnh tạo ra với ốp lát tuyến tính, rowPitch, arrayPitch và depthPitch mô tả cách bố trí của các subresource trong bộ nhớ tuyến tính. Đối với các định dạng không nén, rowPitch là số byte giữa các texel với cùng toạ độ x trong các hàng liền nhau (các tọa độ y khác nhau theo một). arrayPitch là số byte giữa các texels với cùng toạ độ x và y trong các mảng mảng liền kề của ảnh (các giá trị của mảng mảng khác nhau một). depthPitch là số byte giữa các vị trí có cùng toạ độ x và y trong các lát liền kề của một hình ảnh 3D (các tọa độ z khác nhau theo một). Thể hiện dưới dạng một công thức giải quyết vấn đề, các byte khởi đầu của một Texel trong subresource có địa chỉ:

// (x, y, z, lớp) đang Texel tọa

địa chỉ (x, y, z , lớp) = lớp arrayPitch + z depthPitch + y rowPitch + x texelSize + bù đắp

Đối với các định dạng nén, các rowPitch là số byte giữa khối nén trong hàng liền kề. arrayPitch là số byte giữa các khối trong các lớp mảng lân cận. depthPitch là số byte giữa các khối trong các lát liền kề của một hình ảnh 3D.

// (x, y, z, lớp) là trong khối phối

địa chỉ (x, y, z, lớp) = lớp arrayPitch + z depthPitch + y rowPitch + x blockSize + offset;

arrayPitch không được xác định cho hình ảnh không được tạo dưới dạng mảng. depthPitch chỉ được định nghĩa cho hình ảnh 3D.

Đối với định dạng màu, thành viên aspectMask của VkImageSubresource phải là VK_IMAGE_ASPECT_COLOR_BIT. Đối với các định dạng chiều sâu/stencil, khía cạnh phải là VK_IMAGE_ASPECT_DEPTH_BIT hoặc VK_IMAGE_ASPECT_STENCIL_BIT. Trên các triển khai lưu trữ riêng các khía cạnh chiều sâu và stencil, việc truy vấn từng bố cục nguồn phụ này sẽ trả về một khoảng bù và kích thước khác thể hiện vùng bộ nhớ được sử dụng cho khía cạnh đó. Trên các triển khai lưu trữ các khía cạnh chiều sâu và stencil xen kẽ, cùng một offset và kích thước được trả về và đại diện cho phân bổ bộ nhớ xen kẽ.

Hình ảnh của tôi là một hình ảnh 2D bình thường (0 lớp, 1 mipmap), vì vậy không có arrayPitch hoặc depthPitch. Vì nén S3TC được hỗ trợ trực tiếp bởi phần cứng, nên có thể sử dụng dữ liệu hình ảnh mà không giải nén nó trước. Trong OpenGL, điều này có thể được thực hiện bằng cách sử dụng glCompressedTexImage2D và điều này đã làm việc cho tôi trong quá khứ.

Trong OpenGL tôi đã sử dụng GL_COMPRESSED_RGBA_S3TC_DXT1_EXT làm định dạng hình ảnh, cho Vulkan tôi đang sử dụng VK_FORMAT_BC1_RGBA_UNORM_BLOCK, tương đương. Dưới đây là mã của tôi cho lập bản đồ dữ liệu hình ảnh:

auto dds = load_dds("img.dds"); 
auto *srcData = static_cast<uint8_t*>(dds.data()); 
auto *destData = static_cast<uint8_t*>(vkImageMapPtr); // Pointer to mapped memory of VkImage 
destData += layout.offset(); // layout = VkImageLayout of the image 
assert((w %4) == 0); 
assert((h %4) == 0); 
assert(blockSize == 8); // S3TC BC1 
auto wBlocks = w /4; 
auto hBlocks = h /4; 
for(auto y=decltype(hBlocks){0};y<hBlocks;++y) 
{ 
    auto *rowDest = destData +y *layout.rowPitch(); // rowPitch is 0 
    auto *rowSrc = srcData +y *(wBlocks *blockSize); 
    for(auto x=decltype(wBlocks){0};x<wBlocks;++x) 
    { 
     auto *pxDest = rowDest +x *blockSize; 
     auto *pxSrc = rowSrc +x *blockSize; // 4x4 image block 
     memcpy(pxDest,pxSrc,blockSize); // 64Bit per block 
    } 
} 

Và đây là đoạn code để khởi tạo hình ảnh:

vk::Device device = ...; // Initialization 
vk::AllocationCallbacks allocatorCallbacks = ...; // Initialization 
[...] // Load the dds data 
uint32_t width = dds.width(); 
uint32_t height = dds.height(); 
auto format = dds.format(); // = vk::Format::eBc1RgbaUnormBlock; 

vk::Extent3D extent(width,height,1); 

vk::ImageCreateInfo imageInfo(
    vk::ImageCreateFlagBits(0), 
    vk::ImageType::e2D,format, 
    extent,1,1, 
    vk::SampleCountFlagBits::e1, 
    vk::ImageTiling::eLinear, 
    vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment, 
    vk::SharingMode::eExclusive, 
    0,nullptr, 
    vk::ImageLayout::eUndefined 
); 

vk::Image img = nullptr; 
device.createImage(&imageInfo,&allocatorCallbacks,&img); 

vk::MemoryRequirements memRequirements; 
device.getImageMemoryRequirements(img,&memRequirements); 
uint32_t typeIndex = 0; 
get_memory_type(memRequirements.memoryTypeBits(),vk::MemoryPropertyFlagBits::eHostVisible,typeIndex); // -> typeIndex is set to 1 
auto szMem = memRequirements.size(); 
vk::MemoryAllocateInfo memAlloc(szMem,typeIndex); 
vk::DeviceMemory mem; 
device.allocateMemory(&memAlloc,&allocatorCallbacks,&mem); // Note: Using the default allocation (nullptr) doesn't change anything 
device.bindImageMemory(img,mem,0); 

uint32_t mipLevel = 0; 
vk::ImageSubresource resource(
    vk::ImageAspectFlagBits::eColor, 
    mipLevel, 
    0 
); 
vk::SubresourceLayout layout; 
device.getImageSubresourceLayout(img,&resource,&layout); 

auto *srcData = device.mapMemory(mem,0,szMem,vk::MemoryMapFlagBits(0)); 
[...] // Map the dds-data (See code from first post) 
device.unmapMemory(mem); 

Mã này chạy mà không có vấn đề, tuy nhiên hình ảnh kết quả là không đúng. Đây là hình ảnh nguồn:

Black/Pink checkerboard pattern

Và đây là kết quả:

Green/Black checkerboard pattern, much smaller than source image

tôi chắc chắn rằng vấn đề nằm ở các mã đầu tiên snipped tôi đã đăng, tuy nhiên, trong trường hợp nó không, tôi đã viết một sự thích nghi nhỏ của bản demo tam giác từ SDK Vulkan tạo ra cùng một kết quả. Nó có thể được tải xuống here. Mã nguồn được bao gồm, tất cả những gì tôi đã thay đổi từ bản demo tam giác là "demo_prepare_texture_image" -function trong tri.c (Dòng 803 đến 903) và các tệp "dds.cpp" và "dds.h". "dds.cpp" chứa mã để tải dds và ánh xạ bộ nhớ hình ảnh.

Tôi đang sử dụng gli để tải dữ liệu dds (Được cho là "hoạt động hoàn hảo với Vulkan"), cũng được bao gồm trong tải xuống ở trên. Để xây dựng dự án, gói Vulkan SDK bao gồm thư mục phải được thêm vào dự án "tri" và đường dẫn đến dds phải được thay đổi (tri.c, Dòng 809).

Hình ảnh nguồn ("x64/Debug/test.dds" trong dự án) sử dụng nén DXT1. Tôi đã thử nghiệm trên trên phần cứng khác nhau là tốt, với kết quả tương tự.

Bất kỳ mã ví dụ nào để khởi tạo/ánh xạ hình ảnh nén cũng sẽ giúp ích rất nhiều.

Trả lời

2

Sự cố của bạn thực sự khá đơn giản - trong hàm demo_prepare_textures, dòng đầu tiên, có một biến tex_format, được đặt thành VK_FORMAT_B8G8R8A8_UNORM (đó là những gì trong mẫu ban đầu). Điều này cuối cùng được sử dụng để tạo ra VkImageView. Nếu bạn chỉ thay đổi điều này thành VK_FORMAT_BC1_RGBA_UNORM_BLOCK, nó sẽ hiển thị kết cấu chính xác trên hình tam giác.

Là một sang một bên - bạn có thể xác minh rằng kết cấu của bạn được tải chính xác, với RenderDoc, đi kèm với bản cài đặt Vulkan SDK. Chụp ảnh và tìm kiếm trong tab TextureViewer, tab Inputs cho thấy rằng kết cấu của bạn trông giống với kết cấu trên đĩa, ngay cả với định dạng không chính xác.

fixed image

+0

Nếu tôi thay đổi định dạng, thì ảnh thu được thậm chí nhiều hơn sai lầm (http: // sciolyte.com/sharex/2016-03-25_15-35-40.gif). RenderDoc gặp sự cố ngay sau khi cố gắng chạy bất kỳ chương trình nào thông qua nó. Bản demo có thực sự phù hợp với bạn với thay đổi đó không? Bạn có thay đổi gì khác không? – Silverlan

+0

Nếu nó làm việc cho bạn, bạn có thể vui lòng cung cấp mã của bạn với những thay đổi không? Tôi vẫn chưa nhận được nó để làm việc về phía tôi. – Silverlan

+1

Khác với đường dẫn tải của DDS và một số cài đặt dự án để sử dụng SDK Vulkan 1.0.5 đã cài đặt của tôi và chuỗi công cụ VS 120, tôi không thay đổi bất kỳ thứ gì khác từ tải xuống tri_dds.zip. Có lẽ một vấn đề lái xe? Có thể đính kèm vulkaninfo của bạn? – MuertoExcobito

Các vấn đề liên quan