[Vulkan] Unsubsample odd-sized 4:2:2 textures

This commit is contained in:
Triang3l 2022-06-02 23:10:50 +03:00
parent 1ce45ee150
commit a8cfe9bebb
2 changed files with 60 additions and 6 deletions

View File

@ -401,6 +401,24 @@ const VulkanTextureCache::HostFormatPair
xenos::XE_GPU_TEXTURE_SWIZZLE_RGBA},
};
// Vulkan requires 2x1 (4:2:2) subsampled images to have an even width.
// Always decompressing them to RGBA8, which is required to be linear-filterable
// as UNORM and SNORM.
const VulkanTextureCache::HostFormatPair
VulkanTextureCache::kHostFormatGBGRUnaligned = {
{kLoadShaderIndexGBGR8ToRGB8, VK_FORMAT_R8G8B8A8_UNORM, false, true},
{kLoadShaderIndexGBGR8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM, false, true},
xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB,
true};
const VulkanTextureCache::HostFormatPair
VulkanTextureCache::kHostFormatBGRGUnaligned = {
{kLoadShaderIndexBGRG8ToRGB8, VK_FORMAT_R8G8B8A8_UNORM, false, true},
{kLoadShaderIndexBGRG8ToRGB8, VK_FORMAT_R8G8B8A8_SNORM, false, true},
xenos::XE_GPU_TEXTURE_SWIZZLE_RGBB,
true};
VulkanTextureCache::~VulkanTextureCache() {
const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider();
@ -573,7 +591,7 @@ VkImageView VulkanTextureCache::GetActiveBindingOrNullImageView(
bool VulkanTextureCache::IsSignedVersionSeparateForFormat(
TextureKey key) const {
const HostFormatPair& host_format_pair = host_formats_[uint32_t(key.format)];
const HostFormatPair& host_format_pair = GetHostFormatPair(key);
if (host_format_pair.format_unsigned.format == VK_FORMAT_UNDEFINED ||
host_format_pair.format_signed.format == VK_FORMAT_UNDEFINED) {
// Just one signedness.
@ -583,7 +601,7 @@ bool VulkanTextureCache::IsSignedVersionSeparateForFormat(
}
uint32_t VulkanTextureCache::GetHostFormatSwizzle(TextureKey key) const {
return host_formats_[uint32_t(key.format)].swizzle;
return GetHostFormatPair(key).swizzle;
}
uint32_t VulkanTextureCache::GetMaxHostTextureWidthHeight(
@ -633,7 +651,7 @@ uint32_t VulkanTextureCache::GetMaxHostTextureDepthOrArraySize(
std::unique_ptr<TextureCache::Texture> VulkanTextureCache::CreateTexture(
TextureKey key) {
VkFormat formats[] = {VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED};
const HostFormatPair& host_format = host_formats_[uint32_t(key.format)];
const HostFormatPair& host_format = GetHostFormatPair(key);
if (host_format.format_signed.format == VK_FORMAT_UNDEFINED) {
// Only the unsigned format may be available, if at all.
formats[0] = host_format.format_unsigned.format;
@ -735,8 +753,7 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
TextureKey texture_key = vulkan_texture.key();
// Get the pipeline.
const HostFormatPair& host_format_pair =
host_formats_[uint32_t(texture_key.format)];
const HostFormatPair& host_format_pair = GetHostFormatPair(texture_key);
bool host_format_is_signed;
if (IsSignedVersionSeparateForFormat(texture_key)) {
host_format_is_signed = bool(texture_key.signed_separate);
@ -1253,7 +1270,7 @@ VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
ViewKey view_key;
const HostFormatPair& host_format_pair =
vulkan_texture_cache.host_formats_[uint32_t(key().format)];
vulkan_texture_cache.GetHostFormatPair(key());
VkFormat format = (is_signed ? host_format_pair.format_signed
: host_format_pair.format_unsigned)
.format;
@ -1761,6 +1778,26 @@ bool VulkanTextureCache::Initialize() {
load_shaders_needed[host_format.format_signed.load_shader] = true;
}
}
if (kHostFormatGBGRUnaligned.format_unsigned.load_shader !=
kLoadShaderIndexUnknown) {
load_shaders_needed[kHostFormatGBGRUnaligned.format_unsigned.load_shader] =
true;
}
if (kHostFormatGBGRUnaligned.format_signed.load_shader !=
kLoadShaderIndexUnknown) {
load_shaders_needed[kHostFormatGBGRUnaligned.format_signed.load_shader] =
true;
}
if (kHostFormatBGRGUnaligned.format_unsigned.load_shader !=
kLoadShaderIndexUnknown) {
load_shaders_needed[kHostFormatBGRGUnaligned.format_unsigned.load_shader] =
true;
}
if (kHostFormatBGRGUnaligned.format_signed.load_shader !=
kLoadShaderIndexUnknown) {
load_shaders_needed[kHostFormatBGRGUnaligned.format_signed.load_shader] =
true;
}
std::pair<const uint32_t*, size_t> load_shader_code[kLoadShaderCount] = {};
load_shader_code[kLoadShaderIndex8bpb] = std::make_pair(
@ -2177,6 +2214,19 @@ bool VulkanTextureCache::Initialize() {
return true;
}
const VulkanTextureCache::HostFormatPair& VulkanTextureCache::GetHostFormatPair(
TextureKey key) const {
if (key.format == xenos::TextureFormat::k_Cr_Y1_Cb_Y0_REP &&
(key.GetWidth() & 1)) {
return kHostFormatGBGRUnaligned;
}
if (key.format == xenos::TextureFormat::k_Y1_Cr_Y0_Cb_REP &&
(key.GetWidth() & 1)) {
return kHostFormatBGRGUnaligned;
}
return host_formats_[uint32_t(key.format)];
}
void VulkanTextureCache::GetTextureUsageMasks(VulkanTexture::Usage usage,
VkPipelineStageFlags& stage_mask,
VkAccessFlags& access_mask,

View File

@ -236,6 +236,8 @@ class VulkanTextureCache final : public TextureCache {
bool Initialize();
const HostFormatPair& GetHostFormatPair(TextureKey key) const;
void GetTextureUsageMasks(VulkanTexture::Usage usage,
VkPipelineStageFlags& stage_mask,
VkAccessFlags& access_mask, VkImageLayout& layout);
@ -244,6 +246,8 @@ class VulkanTextureCache final : public TextureCache {
VkPipelineStageFlags guest_shader_pipeline_stages_;
static const HostFormatPair kBestHostFormats[64];
static const HostFormatPair kHostFormatGBGRUnaligned;
static const HostFormatPair kHostFormatBGRGUnaligned;
HostFormatPair host_formats_[64];
VkPipelineLayout load_pipeline_layout_ = VK_NULL_HANDLE;