rsx: Separate subresource_layout:dim_in_block and

subresource_layout::dim_in_texel

- These two are not always linked when working with compressed textures.
The actual texels extend past the actual size of the image if the size
is not aligned. e.g if height is 1, the real height is 4, but its not
possible to determine this from the aligned size. It could be 1, 2, 3 or
4 for example.
- Fixes image out-of-bounds writes when uploading from CPU
This commit is contained in:
kd-11 2019-10-28 21:06:15 +03:00 committed by kd-11
parent b99992d570
commit aa3eeaa417
6 changed files with 49 additions and 30 deletions

View File

@ -338,10 +338,6 @@ namespace
std::vector<rsx_subresource_layout> result;
size_t offset_in_src = 0;
// Always lower than width/height so fits in u16
u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
u16 texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel;
u8 border_size = border ? (padded_row ? 1 : 4) : 0;
u32 src_pitch_in_block;
u32 full_height_in_block;
@ -349,43 +345,58 @@ namespace
for (unsigned layer = 0; layer < layer_count; layer++)
{
u16 miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block;
u16 miplevel_width_in_texel = width_in_texel, miplevel_height_in_texel = height_in_texel;
for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++)
{
rsx_subresource_layout current_subresource_layout = {};
// Since <= width/height, fits on 16 bits
current_subresource_layout.height_in_block = miplevel_height_in_block;
current_subresource_layout.width_in_block = miplevel_width_in_block;
result.push_back({});
rsx_subresource_layout& current_subresource_layout = result.back();
current_subresource_layout.width_in_texel = miplevel_width_in_texel;
current_subresource_layout.height_in_texel = miplevel_height_in_texel;
current_subresource_layout.level = mip_level;
current_subresource_layout.layer = layer;
current_subresource_layout.depth = depth;
current_subresource_layout.border = border_size;
if constexpr (block_edge_in_texel == 1)
{
current_subresource_layout.width_in_block = miplevel_width_in_texel;
current_subresource_layout.height_in_block = miplevel_height_in_texel;
}
else
{
current_subresource_layout.width_in_block = rsx::aligned_div(miplevel_width_in_texel, block_edge_in_texel);
current_subresource_layout.height_in_block = rsx::aligned_div(miplevel_height_in_texel, block_edge_in_texel);
}
if (padded_row)
{
src_pitch_in_block = suggested_pitch_in_bytes / block_size_in_bytes;
full_height_in_block = miplevel_height_in_block + border_size + border_size;
full_height_in_block = current_subresource_layout.height_in_block + (border_size + border_size);
}
else if (!border)
{
src_pitch_in_block = miplevel_width_in_block + border_size + border_size;
full_height_in_block = miplevel_height_in_block;
src_pitch_in_block = current_subresource_layout.width_in_block;
full_height_in_block = current_subresource_layout.height_in_block;
}
else
{
src_pitch_in_block = rsx::next_pow2(miplevel_width_in_block + border_size + border_size);
full_height_in_block = rsx::next_pow2(miplevel_height_in_block + border_size + border_size);
src_pitch_in_block = rsx::next_pow2(current_subresource_layout.width_in_block + border_size + border_size);
full_height_in_block = rsx::next_pow2(current_subresource_layout.height_in_block + border_size + border_size);
}
slice_sz = src_pitch_in_block * block_size_in_bytes * full_height_in_block * depth;
current_subresource_layout.pitch_in_block = src_pitch_in_block;
current_subresource_layout.data = gsl::span<const gsl::byte>(texture_data_pointer + offset_in_src, slice_sz);
result.push_back(current_subresource_layout);
offset_in_src += slice_sz;
miplevel_height_in_block = std::max(miplevel_height_in_block / 2, 1);
miplevel_width_in_block = std::max(miplevel_width_in_block / 2, 1);
miplevel_width_in_texel = std::max(miplevel_width_in_texel / 2, 1);
miplevel_height_in_texel = std::max(miplevel_height_in_texel / 2, 1);
}
offset_in_src = align(offset_in_src, 128);
}
return result;
}
}

View File

@ -89,9 +89,13 @@ namespace rsx
struct rsx_subresource_layout
{
gsl::span<const gsl::byte> data;
u16 width_in_texel;
u16 height_in_texel;
u16 width_in_block;
u16 height_in_block;
u16 depth;
u16 level;
u16 layer;
u8 border;
u8 reserved;
u32 pitch_in_block;

View File

@ -2401,8 +2401,8 @@ namespace rsx
std::vector<rsx_subresource_layout> subresource_layout;
rsx_subresource_layout subres = {};
subres.width_in_block = image_width;
subres.height_in_block = image_height;
subres.width_in_block = subres.width_in_texel = image_width;
subres.height_in_block = subres.height_in_texel = image_height;
subres.pitch_in_block = full_width;
subres.depth = 1;
subres.data = { vm::_ptr<const gsl::byte>(image_base), src.pitch * image_height };
@ -2533,8 +2533,8 @@ namespace rsx
const u16 pitch_in_block = dst.pitch / dst_bpp;
std::vector<rsx_subresource_layout> subresource_layout;
rsx_subresource_layout subres = {};
subres.width_in_block = dst_dimensions.width;
subres.height_in_block = dst_dimensions.height;
subres.width_in_block = subres.width_in_texel = dst_dimensions.width;
subres.height_in_block = subres.height_in_texel = dst_dimensions.height;
subres.pitch_in_block = pitch_in_block;
subres.depth = 1;
subres.data = { vm::get_super_ptr<const gsl::byte>(dst.rsx_address), dst.pitch * dst_dimensions.height };

View File

@ -241,8 +241,8 @@ namespace vk
}
rsx_subresource_layout subres{};
subres.width_in_block = surface_width * samples_x;
subres.height_in_block = surface_height * samples_y;
subres.width_in_block = subres.width_in_texel = surface_width * samples_x;
subres.height_in_block = subres.height_in_texel = surface_height * samples_y;
subres.pitch_in_block = rsx_pitch / get_bpp();
subres.depth = 1;
subres.data = { (const gsl::byte*)vm::get_super_ptr(base_addr), s32(rsx_pitch * surface_height * samples_y) };

View File

@ -542,7 +542,6 @@ namespace vk
const std::vector<rsx_subresource_layout>& subresource_layout, int format, bool is_swizzled, u16 mipmap_count,
VkImageAspectFlags flags, vk::data_heap &upload_heap, u32 heap_align)
{
u32 mipmap_level = 0;
u32 block_in_pixel = get_format_block_size_in_texel(format);
u8 block_size_in_bytes = get_format_block_size_in_bytes(format);
@ -591,13 +590,13 @@ namespace vk
copy_regions.push_back({});
auto& copy_info = copy_regions.back();
copy_info.bufferOffset = offset_in_buffer;
copy_info.imageExtent.height = layout.height_in_block * block_in_pixel;
copy_info.imageExtent.width = std::min<u32>(layout.width_in_block, layout.pitch_in_block) * block_in_pixel;
copy_info.imageExtent.height = layout.height_in_texel;
copy_info.imageExtent.width = layout.width_in_texel;
copy_info.imageExtent.depth = layout.depth;
copy_info.imageSubresource.aspectMask = flags;
copy_info.imageSubresource.layerCount = 1;
copy_info.imageSubresource.baseArrayLayer = mipmap_level / mipmap_count;
copy_info.imageSubresource.mipLevel = mipmap_level % mipmap_count;
copy_info.imageSubresource.baseArrayLayer = layout.layer;
copy_info.imageSubresource.mipLevel = layout.level;
copy_info.bufferRowLength = block_in_pixel * row_pitch / block_size_in_bytes;
if (opt.require_swap || dst_image->aspect() & VK_IMAGE_ASPECT_STENCIL_BIT)
@ -621,8 +620,6 @@ namespace vk
scratch_offset += image_linear_size;
verify("Out of scratch memory" HERE), (scratch_offset + image_linear_size) <= scratch_buf->size();
}
mipmap_level++;
}
if (opt.require_swap || dst_image->aspect() & VK_IMAGE_ASPECT_STENCIL_BIT)

View File

@ -277,6 +277,13 @@ namespace rsx
return ((value + alignment - 1) / alignment) * alignment;
}
// General purpose aligned division, the result is rounded up not truncated
template <typename T, typename U>
static inline T aligned_div(T value, U alignment)
{
return (value + alignment - 1) / alignment;
}
// Copy memory in inverse direction from source
// Used to scale negatively x axis while transfering image data
template <typename Ts = u8, typename Td = Ts>