renderer_vulkan: Fix mipmap generation

This commit is contained in:
emufan
2022-06-19 12:44:44 +03:00
parent 69bde2b13b
commit 18cc68c687
5 changed files with 75 additions and 34 deletions

View File

@ -328,6 +328,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
}
// Sync and bind the texture surfaces
VKTexture temp_tex;
const auto pica_textures = regs.texturing.GetTextures();
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
const auto& texture = pica_textures[texture_index];
@ -336,7 +337,16 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
//texture_samplers[texture_index].SyncWithConfig(texture.config);
Surface surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) {
state.SetTexture(texture_index, surface->texture);
if (color_surface && color_surface->texture.GetHandle() ==
surface->texture.GetHandle()) {
// The game is trying to use a surface as a texture and framebuffer at the same time
// which causes unpredictable behavior on the host.
// Making a copy to sample from eliminates this issue and seems to be fairly cheap.
temp_tex.Create(color_surface->texture);
state.SetTexture(texture_index, temp_tex);
} else {
state.SetTexture(texture_index, surface->texture);
}
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
// HACK: In this case, the correct behaviour for the PICA is to use the last
@ -1141,6 +1151,9 @@ void RasterizerVulkan::SyncCullMode() {
const auto& regs = Pica::g_state.regs;
auto& state = VulkanState::Get();
state.SetCullMode(vk::CullModeFlagBits::eNone);
return;
switch (regs.rasterizer.cull_mode) {
case Pica::RasterizerRegs::CullMode::KeepAll:
state.SetCullMode(vk::CullModeFlagBits::eNone);

View File

@ -239,23 +239,28 @@ inline vk::ImageSubresourceRange SubResourceLayersToRange(const vk::ImageSubreso
}
static bool BlitTextures(const Surface& src_surface, const Common::Rectangle<u32>& src_rect,
const Surface& dst_surface, const Common::Rectangle<u32>& dst_rect, SurfaceType type) {
vk::ImageSubresourceLayers image_range{{}, {}, 0, 1};
switch (src_surface->type) {
case SurfaceParams::SurfaceType::Color:
case SurfaceParams::SurfaceType::Texture:
image_range.aspectMask = vk::ImageAspectFlagBits::eColor;
break;
case SurfaceParams::SurfaceType::Depth:
image_range.aspectMask = vk::ImageAspectFlagBits::eDepth;
break;
case SurfaceParams::SurfaceType::DepthStencil:
image_range.aspectMask =
vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
break;
default:
UNIMPLEMENTED();
}
const Surface& dst_surface, const Common::Rectangle<u32>& dst_rect,
u32 src_level = 0, u32 dst_level = 0) {
vk::ImageSubresourceLayers src_range{{}, src_level, 0, 1};
vk::ImageSubresourceLayers dst_range{{}, dst_level, 0, 1};
auto GetAspect = [](SurfaceType type) -> vk::ImageAspectFlags {
switch (type) {
case SurfaceParams::SurfaceType::Color:
case SurfaceParams::SurfaceType::Texture:
return vk::ImageAspectFlagBits::eColor;
case SurfaceParams::SurfaceType::Depth:
return vk::ImageAspectFlagBits::eDepth;
case SurfaceParams::SurfaceType::DepthStencil:
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
default:
UNIMPLEMENTED();
return vk::ImageAspectFlagBits::eNone;
}
};
src_range.aspectMask = GetAspect(src_surface->type);
dst_range.aspectMask = GetAspect(dst_surface->type);
// Prepare images for transfer
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
@ -276,7 +281,7 @@ static bool BlitTextures(const Surface& src_surface, const Common::Rectangle<u32
vk::Offset3D{static_cast<s32>(dst_rect.right), static_cast<s32>(dst_rect.top), 1}
};
vk::ImageBlit blit_area{image_range, src_offsets, image_range, dst_offsets};
vk::ImageBlit blit_area{src_range, src_offsets, dst_range, dst_offsets};
cmdbuffer.blitImage(src_texture.GetHandle(), vk::ImageLayout::eTransferSrcOptimal,
dst_texture.GetHandle(), vk::ImageLayout::eTransferDstOptimal,
{blit_area}, vk::Filter::eNearest);
@ -497,10 +502,8 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac
return;
}
if (src_surface->CanSubRect(subrect_params)) {
auto srect = src_surface->GetScaledSubRect(subrect_params);
auto drect = dst_surface->GetScaledSubRect(subrect_params);
BlitTextures(src_surface, srect, dst_surface, drect, src_surface->type);
BlitTextures(src_surface, src_surface->GetScaledSubRect(subrect_params),
dst_surface, dst_surface->GetScaledSubRect(subrect_params));
return;
}
@ -811,7 +814,7 @@ bool RasterizerCacheVulkan::BlitSurfaces(const Surface& src_surface,
return false;
dst_surface->InvalidateAllWatcher();
return BlitTextures(src_surface, src_rect, dst_surface, dst_rect, src_surface->type);
return BlitTextures(src_surface, src_rect, dst_surface, dst_rect);
}
Surface RasterizerCacheVulkan::GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
@ -1016,12 +1019,10 @@ Surface RasterizerCacheVulkan::GetTextureSurface(const Pica::Texture::TextureInf
ValidateSurface(level_surface, level_surface->addr, level_surface->size);
}
//state.ResetTexture(level_surface->texture.handle);
//state.Apply();
if (!surface->is_custom /*&& texture_filterer->IsNull()*/) {
auto src_rect = level_surface->GetScaledRect();
auto dst_rect = surface_params.GetScaledRect();
BlitSurfaces(level_surface, src_rect, surface, dst_rect);
BlitTextures(level_surface, level_surface->GetScaledRect(),
surface, surface_params.GetScaledRect(),
0, level);
}
watcher->Validate();
}

View File

@ -468,7 +468,6 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
render_pipeline_builder.SetBlendAttachment(att.blendEnable, att.srcColorBlendFactor, att.dstColorBlendFactor,
att.colorBlendOp, att.srcAlphaBlendFactor, att.dstAlphaBlendFactor,
att.alphaBlendOp, att.colorWriteMask);
std::cout << "New pipeline!\n";
// Cache the resulted pipeline
pipeline = render_pipeline_builder.Build();
render_pipelines.emplace(render_pipeline_key, vk::UniquePipeline{pipeline});

View File

@ -101,8 +101,6 @@ void VKTexture::Create(const Info& create_info) {
info.format = vk::Format::eD32SfloatS8Uint;
}
std::cout << "New surface!\n";
// Create the texture
image_size = info.width * info.height * BytesPerPixel(info.format);
aspect = GetImageAspect(info.format);
@ -139,6 +137,36 @@ void VKTexture::Create(const Info& create_info) {
view = device.createImageView(view_info);
}
void VKTexture::Create(VKTexture& other) {
auto info = other.info;
Create(info);
// Copy the buffer contents
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
Transition(cmdbuffer, vk::ImageLayout::eTransferDstOptimal);
auto old_layout = other.GetLayout();
other.Transition(cmdbuffer, vk::ImageLayout::eTransferSrcOptimal);
u32 copy_count = 0;
std::array<vk::ImageCopy, 16> copy_regions;
for (u32 i = 0; i < info.levels; i++) {
copy_regions[copy_count++] = vk::ImageCopy{
vk::ImageSubresourceLayers{aspect, i, 0, 1}, {0},
vk::ImageSubresourceLayers{aspect, i, 0, 1}, {0},
{info.width, info.height, 0}
};
}
cmdbuffer.copyImage(other.GetHandle(), vk::ImageLayout::eTransferSrcOptimal,
texture, vk::ImageLayout::eTransferDstOptimal, copy_count,
copy_regions.data());
Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
other.Transition(cmdbuffer, old_layout);
}
void VKTexture::Adopt(const Info& create_info, vk::Image image) {
info = create_info;
image_size = info.width * info.height * BytesPerPixel(info.format);
@ -167,7 +195,6 @@ void VKTexture::Destroy() {
memory = memory]() {
auto device = g_vk_instace->GetDevice();
if (texture) {
std::cout << "Surface destroyed!\n";
device.destroyImage(texture);
device.destroyImageView(view);
device.freeMemory(memory);

View File

@ -37,6 +37,7 @@ public:
/// Create a new Vulkan texture object
void Create(const Info& info);
void Create(VKTexture& texture);
void Adopt(const Info& info, vk::Image image);
void Destroy();
@ -55,10 +56,10 @@ public:
void Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span<u8> dst);
/// Used to transition the image to an optimal layout during transfers
void OverrideImageLayout(vk::ImageLayout new_layout);
void Transition(vk::CommandBuffer cmdbuffer, vk::ImageLayout new_layout);
void Transition(vk::CommandBuffer cmdbuffer, vk::ImageLayout new_layout, u32 start_level, u32 level_count,
u32 start_layer, u32 layer_count);
void OverrideImageLayout(vk::ImageLayout new_layout);
private:
std::vector<u8> RGBToRGBA(std::span<u8> data);