renderer_vulkan: Fix mipmap generation
This commit is contained in:
@ -328,6 +328,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sync and bind the texture surfaces
|
// Sync and bind the texture surfaces
|
||||||
|
VKTexture temp_tex;
|
||||||
const auto pica_textures = regs.texturing.GetTextures();
|
const auto pica_textures = regs.texturing.GetTextures();
|
||||||
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||||
const auto& texture = pica_textures[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);
|
//texture_samplers[texture_index].SyncWithConfig(texture.config);
|
||||||
Surface surface = res_cache.GetTextureSurface(texture);
|
Surface surface = res_cache.GetTextureSurface(texture);
|
||||||
if (surface != nullptr) {
|
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 {
|
} else {
|
||||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
// 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
|
// 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;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
auto& state = VulkanState::Get();
|
auto& state = VulkanState::Get();
|
||||||
|
state.SetCullMode(vk::CullModeFlagBits::eNone);
|
||||||
|
return;
|
||||||
|
|
||||||
switch (regs.rasterizer.cull_mode) {
|
switch (regs.rasterizer.cull_mode) {
|
||||||
case Pica::RasterizerRegs::CullMode::KeepAll:
|
case Pica::RasterizerRegs::CullMode::KeepAll:
|
||||||
state.SetCullMode(vk::CullModeFlagBits::eNone);
|
state.SetCullMode(vk::CullModeFlagBits::eNone);
|
||||||
|
@ -239,23 +239,28 @@ inline vk::ImageSubresourceRange SubResourceLayersToRange(const vk::ImageSubreso
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool BlitTextures(const Surface& src_surface, const Common::Rectangle<u32>& src_rect,
|
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) {
|
const Surface& dst_surface, const Common::Rectangle<u32>& dst_rect,
|
||||||
vk::ImageSubresourceLayers image_range{{}, {}, 0, 1};
|
u32 src_level = 0, u32 dst_level = 0) {
|
||||||
switch (src_surface->type) {
|
vk::ImageSubresourceLayers src_range{{}, src_level, 0, 1};
|
||||||
case SurfaceParams::SurfaceType::Color:
|
vk::ImageSubresourceLayers dst_range{{}, dst_level, 0, 1};
|
||||||
case SurfaceParams::SurfaceType::Texture:
|
|
||||||
image_range.aspectMask = vk::ImageAspectFlagBits::eColor;
|
auto GetAspect = [](SurfaceType type) -> vk::ImageAspectFlags {
|
||||||
break;
|
switch (type) {
|
||||||
case SurfaceParams::SurfaceType::Depth:
|
case SurfaceParams::SurfaceType::Color:
|
||||||
image_range.aspectMask = vk::ImageAspectFlagBits::eDepth;
|
case SurfaceParams::SurfaceType::Texture:
|
||||||
break;
|
return vk::ImageAspectFlagBits::eColor;
|
||||||
case SurfaceParams::SurfaceType::DepthStencil:
|
case SurfaceParams::SurfaceType::Depth:
|
||||||
image_range.aspectMask =
|
return vk::ImageAspectFlagBits::eDepth;
|
||||||
vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
case SurfaceParams::SurfaceType::DepthStencil:
|
||||||
break;
|
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
return vk::ImageAspectFlagBits::eNone;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
src_range.aspectMask = GetAspect(src_surface->type);
|
||||||
|
dst_range.aspectMask = GetAspect(dst_surface->type);
|
||||||
|
|
||||||
// Prepare images for transfer
|
// Prepare images for transfer
|
||||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
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::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,
|
cmdbuffer.blitImage(src_texture.GetHandle(), vk::ImageLayout::eTransferSrcOptimal,
|
||||||
dst_texture.GetHandle(), vk::ImageLayout::eTransferDstOptimal,
|
dst_texture.GetHandle(), vk::ImageLayout::eTransferDstOptimal,
|
||||||
{blit_area}, vk::Filter::eNearest);
|
{blit_area}, vk::Filter::eNearest);
|
||||||
@ -497,10 +502,8 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (src_surface->CanSubRect(subrect_params)) {
|
if (src_surface->CanSubRect(subrect_params)) {
|
||||||
auto srect = src_surface->GetScaledSubRect(subrect_params);
|
BlitTextures(src_surface, src_surface->GetScaledSubRect(subrect_params),
|
||||||
auto drect = dst_surface->GetScaledSubRect(subrect_params);
|
dst_surface, dst_surface->GetScaledSubRect(subrect_params));
|
||||||
|
|
||||||
BlitTextures(src_surface, srect, dst_surface, drect, src_surface->type);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,7 +814,7 @@ bool RasterizerCacheVulkan::BlitSurfaces(const Surface& src_surface,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
dst_surface->InvalidateAllWatcher();
|
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,
|
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);
|
ValidateSurface(level_surface, level_surface->addr, level_surface->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//state.ResetTexture(level_surface->texture.handle);
|
|
||||||
//state.Apply();
|
|
||||||
if (!surface->is_custom /*&& texture_filterer->IsNull()*/) {
|
if (!surface->is_custom /*&& texture_filterer->IsNull()*/) {
|
||||||
auto src_rect = level_surface->GetScaledRect();
|
BlitTextures(level_surface, level_surface->GetScaledRect(),
|
||||||
auto dst_rect = surface_params.GetScaledRect();
|
surface, surface_params.GetScaledRect(),
|
||||||
BlitSurfaces(level_surface, src_rect, surface, dst_rect);
|
0, level);
|
||||||
}
|
}
|
||||||
watcher->Validate();
|
watcher->Validate();
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,6 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) {
|
|||||||
render_pipeline_builder.SetBlendAttachment(att.blendEnable, att.srcColorBlendFactor, att.dstColorBlendFactor,
|
render_pipeline_builder.SetBlendAttachment(att.blendEnable, att.srcColorBlendFactor, att.dstColorBlendFactor,
|
||||||
att.colorBlendOp, att.srcAlphaBlendFactor, att.dstAlphaBlendFactor,
|
att.colorBlendOp, att.srcAlphaBlendFactor, att.dstAlphaBlendFactor,
|
||||||
att.alphaBlendOp, att.colorWriteMask);
|
att.alphaBlendOp, att.colorWriteMask);
|
||||||
std::cout << "New pipeline!\n";
|
|
||||||
// Cache the resulted pipeline
|
// Cache the resulted pipeline
|
||||||
pipeline = render_pipeline_builder.Build();
|
pipeline = render_pipeline_builder.Build();
|
||||||
render_pipelines.emplace(render_pipeline_key, vk::UniquePipeline{pipeline});
|
render_pipelines.emplace(render_pipeline_key, vk::UniquePipeline{pipeline});
|
||||||
|
@ -101,8 +101,6 @@ void VKTexture::Create(const Info& create_info) {
|
|||||||
info.format = vk::Format::eD32SfloatS8Uint;
|
info.format = vk::Format::eD32SfloatS8Uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "New surface!\n";
|
|
||||||
|
|
||||||
// Create the texture
|
// Create the texture
|
||||||
image_size = info.width * info.height * BytesPerPixel(info.format);
|
image_size = info.width * info.height * BytesPerPixel(info.format);
|
||||||
aspect = GetImageAspect(info.format);
|
aspect = GetImageAspect(info.format);
|
||||||
@ -139,6 +137,36 @@ void VKTexture::Create(const Info& create_info) {
|
|||||||
view = device.createImageView(view_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) {
|
void VKTexture::Adopt(const Info& create_info, vk::Image image) {
|
||||||
info = create_info;
|
info = create_info;
|
||||||
image_size = info.width * info.height * BytesPerPixel(info.format);
|
image_size = info.width * info.height * BytesPerPixel(info.format);
|
||||||
@ -167,7 +195,6 @@ void VKTexture::Destroy() {
|
|||||||
memory = memory]() {
|
memory = memory]() {
|
||||||
auto device = g_vk_instace->GetDevice();
|
auto device = g_vk_instace->GetDevice();
|
||||||
if (texture) {
|
if (texture) {
|
||||||
std::cout << "Surface destroyed!\n";
|
|
||||||
device.destroyImage(texture);
|
device.destroyImage(texture);
|
||||||
device.destroyImageView(view);
|
device.destroyImageView(view);
|
||||||
device.freeMemory(memory);
|
device.freeMemory(memory);
|
||||||
|
@ -37,6 +37,7 @@ public:
|
|||||||
|
|
||||||
/// Create a new Vulkan texture object
|
/// Create a new Vulkan texture object
|
||||||
void Create(const Info& info);
|
void Create(const Info& info);
|
||||||
|
void Create(VKTexture& texture);
|
||||||
void Adopt(const Info& info, vk::Image image);
|
void Adopt(const Info& info, vk::Image image);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
@ -55,10 +56,10 @@ public:
|
|||||||
void Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span<u8> dst);
|
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
|
/// 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);
|
||||||
void Transition(vk::CommandBuffer cmdbuffer, vk::ImageLayout new_layout, u32 start_level, u32 level_count,
|
void Transition(vk::CommandBuffer cmdbuffer, vk::ImageLayout new_layout, u32 start_level, u32 level_count,
|
||||||
u32 start_layer, u32 layer_count);
|
u32 start_layer, u32 layer_count);
|
||||||
void OverrideImageLayout(vk::ImageLayout new_layout);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<u8> RGBToRGBA(std::span<u8> data);
|
std::vector<u8> RGBToRGBA(std::span<u8> data);
|
||||||
|
Reference in New Issue
Block a user