render parity unit K: 40250 DDS mip levels
DXT DDS textures upload the file's own mip levels like 40250 CGraphicImageTexture::CreateDDSTexture (max(1, dwMipMapCount), level i read at sum(dwLinearSize>>2k), Copy of dwLinearSize>>2i bytes) instead of a regenerated chain. Non-DDS images keep the D3DX_DEFAULT full chain and mem: textures get one level. The invented is_ui_tex no-mip rule (icon/, ui/, locale/, <=128px) is deleted. dxt_decode_test is registered in ctest with mip-level cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
dda885a17a
commit
d2356d59c3
+35
-21
@@ -2578,17 +2578,13 @@ private:
|
||||
}
|
||||
#endif
|
||||
if (!decoded.ok()) return it->second;
|
||||
bool is_ui_tex = false;
|
||||
if (texture_name.rfind("icon/", 0) == 0 ||
|
||||
texture_name.rfind("d:/ymir work/ui/", 0) == 0 ||
|
||||
texture_name.rfind("d:\\ymir work\\ui\\", 0) == 0 ||
|
||||
texture_name.rfind("locale/", 0) == 0 ||
|
||||
texture_name.rfind("locale\\", 0) == 0 ||
|
||||
texture_name.rfind("mem:", 0) == 0 ||
|
||||
(decoded.w <= 128 && decoded.h <= 128)) {
|
||||
is_ui_tex = true;
|
||||
}
|
||||
upload_texture(decoded.w, decoded.h, decoded.rgba.data(), it->second, true, !is_ui_tex);
|
||||
// 40250 CGraphicImageTexture: DXT DDS -> CreateDDSTexture with the file's levels;
|
||||
// other files -> D3DXCreateTextureFromFileInMemoryEx(D3DX_DEFAULT) = full chain;
|
||||
// memory images (mem:, CreateTexture(w, h, 1, ...)) -> one level.
|
||||
const bool is_memory_tex = texture_name.rfind("mem:", 0) == 0;
|
||||
upload_texture(
|
||||
decoded.w, decoded.h, decoded.rgba.data(), it->second, true,
|
||||
!is_memory_tex && decoded.file_mip_levels == 0, &decoded.mips);
|
||||
it->second.descriptor = allocate_texture_descriptor_set(it->second.view, fallback_texture_.view);
|
||||
it->second.ui_descriptor = allocate_ui_texture_descriptor_set(it->second.view, fallback_texture_.view);
|
||||
return it->second;
|
||||
@@ -2681,11 +2677,15 @@ private:
|
||||
const std::uint8_t* rgba,
|
||||
GpuTexture& texture,
|
||||
bool count_upload,
|
||||
bool generate_mips = true) {
|
||||
const VkDeviceSize byte_size = VkDeviceSize(width) * height * 4;
|
||||
bool generate_mips = true,
|
||||
const std::vector<std::vector<std::uint8_t>>* file_mips = nullptr) {
|
||||
const bool has_file_mips = !generate_mips && file_mips && !file_mips->empty();
|
||||
VkDeviceSize byte_size = VkDeviceSize(width) * height * 4;
|
||||
if (has_file_mips)
|
||||
for (const auto& level : *file_mips) byte_size += level.size();
|
||||
const std::uint32_t mip_levels = generate_mips
|
||||
? (static_cast<std::uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1u)
|
||||
: 1u;
|
||||
: has_file_mips ? 1u + static_cast<std::uint32_t>(file_mips->size()) : 1u;
|
||||
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory staging_memory = VK_NULL_HANDLE;
|
||||
VkBufferCreateInfo buffer_info{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
|
||||
@@ -2703,7 +2703,11 @@ private:
|
||||
check(vkBindBufferMemory(device_, staging_buffer, staging_memory, 0), "vkBindBufferMemory staging");
|
||||
void* mapped = nullptr;
|
||||
check(vkMapMemory(device_, staging_memory, 0, byte_size, 0, &mapped), "vkMapMemory staging");
|
||||
std::memcpy(mapped, rgba, byte_size);
|
||||
std::memcpy(mapped, rgba, VkDeviceSize(width) * height * 4);
|
||||
if (has_file_mips) {
|
||||
auto* dst = static_cast<std::uint8_t*>(mapped) + VkDeviceSize(width) * height * 4;
|
||||
for (const auto& level : *file_mips) { std::memcpy(dst, level.data(), level.size()); dst += level.size(); }
|
||||
}
|
||||
vkUnmapMemory(device_, staging_memory);
|
||||
|
||||
VkImageCreateInfo image_info{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
|
||||
@@ -2746,14 +2750,22 @@ private:
|
||||
upload_cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, 0, nullptr, 0, nullptr, 1, &to_transfer);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.imageExtent = {width, height, 1};
|
||||
vkCmdCopyBufferToImage(upload_cmd, staging_buffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
std::vector<VkBufferImageCopy> regions(has_file_mips ? mip_levels : 1u);
|
||||
VkDeviceSize region_offset = 0;
|
||||
for (std::uint32_t i = 0; i < regions.size(); ++i) {
|
||||
const std::uint32_t lw = std::max(1u, width >> i), lh = std::max(1u, height >> i);
|
||||
regions[i].bufferOffset = region_offset;
|
||||
regions[i].imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, i, 0, 1};
|
||||
regions[i].imageExtent = {lw, lh, 1};
|
||||
region_offset += VkDeviceSize(lw) * lh * 4;
|
||||
}
|
||||
vkCmdCopyBufferToImage(
|
||||
upload_cmd, staging_buffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
static_cast<std::uint32_t>(regions.size()), regions.data());
|
||||
|
||||
std::int32_t mip_w = static_cast<std::int32_t>(width);
|
||||
std::int32_t mip_h = static_cast<std::int32_t>(height);
|
||||
for (std::uint32_t i = 1; i < mip_levels; ++i) {
|
||||
for (std::uint32_t i = 1; generate_mips && i < mip_levels; ++i) {
|
||||
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
barrier.image = texture.image;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
@@ -2802,7 +2814,9 @@ private:
|
||||
to_shader.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
to_shader.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
to_shader.image = texture.image;
|
||||
to_shader.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, mip_levels - 1, 1, 0, 1};
|
||||
to_shader.subresourceRange = generate_mips
|
||||
? VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, mip_levels - 1, 1, 0, 1}
|
||||
: VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, mip_levels, 0, 1};
|
||||
vkCmdPipelineBarrier(
|
||||
upload_cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
0, 0, nullptr, 0, nullptr, 1, &to_shader);
|
||||
|
||||
Reference in New Issue
Block a user