diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index e93de9030e..c54037d760 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -663,15 +663,32 @@ namespace gl /** * Check for sampleable rtts from previous render passes */ - gl::texture *texptr = nullptr; + gl::render_target *texptr = nullptr; if (texptr = m_rtts.get_texture_from_render_target_if_applicable(texaddr)) { + for (auto tex : m_rtts.m_bound_render_targets) + { + if (std::get<0>(tex) == texaddr) + { + LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr); + create_temporary_subresource(texptr->id(), (GLenum)texptr->get_compatible_internal_format(), 0, 0, texptr->width(), texptr->height()); + return; + } + } + texptr->bind(); return; } if (texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) { + if (texaddr == std::get<0>(m_rtts.m_bound_depth_stencil)) + { + LOG_WARNING(RSX, "Attempting to sample a currently bound depth surface @ 0x%x", texaddr); + create_temporary_subresource(texptr->id(), (GLenum)texptr->get_compatible_internal_format(), 0, 0, texptr->width(), texptr->height()); + return; + } + texptr->bind(); return; } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index c4fd5029a8..556f70ef4b 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -123,10 +123,10 @@ namespace vk case VK_FORMAT_R32G32B32A32_SFLOAT: color_format_idx = 3; break; - case VK_FORMAT_R8_UINT: + case VK_FORMAT_R8_UNORM: color_format_idx = 4; break; - case VK_FORMAT_R8G8_UINT: + case VK_FORMAT_R8G8_UNORM: color_format_idx = 5; break; case VK_FORMAT_A1R5G5B5_UNORM_PACK16: @@ -359,7 +359,7 @@ namespace std::array result = {}; const std::array depth_format_list = { VK_FORMAT_UNDEFINED, VK_FORMAT_D16_UNORM, gpu_format_support.d24_unorm_s8 ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT }; - const std::array color_format_list = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R8_UINT, VK_FORMAT_R8G8_UINT, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_R32_SFLOAT }; + const std::array color_format_list = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R8_UNORM, VK_FORMAT_R8G8_UNORM, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_R32_SFLOAT }; for (const VkFormat &color_format : color_format_list) @@ -1265,6 +1265,7 @@ void VKGSRender::process_swap_request() //m_texture_cache.merge_dirty_textures(m_rtts.invalidated_resources); m_rtts.invalidated_resources.clear(); + m_rtts.invalidate_surface_cache_data(&*m_current_command_buffer); m_texture_cache.flush(); m_buffer_view_to_clean.clear(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index e96630f69e..800dedb0e7 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -255,6 +255,12 @@ namespace vk vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); } + void change_image_layout(VkCommandBuffer cmd, vk::image *image, VkImageLayout new_layout, VkImageSubresourceRange range) + { + change_image_layout(cmd, image->value, image->current_layout, new_layout, range); + image->current_layout = new_layout; + } + void enter_uninterruptible() { g_cb_no_interrupt_flag = true; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index c002043b60..6f74c25634 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -56,6 +56,7 @@ namespace vk class swap_chain_image; class physical_device; class command_buffer; + struct image; vk::context *get_current_thread_ctx(); void set_current_thread_ctx(const vk::context &ctx); @@ -73,6 +74,7 @@ namespace vk void destroy_global_resources(); void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, VkImageSubresourceRange range); + void change_image_layout(VkCommandBuffer cmd, vk::image *image, VkImageLayout new_layout, VkImageSubresourceRange range); void copy_image(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout, u32 width, u32 height, u32 mipmaps, VkImageAspectFlagBits aspect); void copy_scaled_image(VkCommandBuffer cmd, VkImage &src, VkImage &dst, VkImageLayout srcLayout, VkImageLayout dstLayout, u32 src_x_offset, u32 src_y_offset, u32 src_width, u32 src_height, u32 dst_x_offset, u32 dst_y_offset, u32 dst_width, u32 dst_height, u32 mipmaps, VkImageAspectFlagBits aspect); @@ -358,7 +360,8 @@ namespace vk struct image { VkImage value; - VkComponentMapping native_layout = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + VkComponentMapping native_component_map = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + VkImageLayout current_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageCreateInfo info = {}; std::shared_ptr memory; @@ -416,6 +419,21 @@ namespace vk image(const image&) = delete; image(image&&) = delete; + u32 width() const + { + return info.extent.width; + } + + u32 height() const + { + return info.extent.height; + } + + u32 depth() const + { + return info.extent.depth; + } + private: VkDevice m_device; }; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 6fa5ba4242..6a77b8eb05 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -128,8 +128,7 @@ namespace vk return (protection == utils::protection::rw && uploaded_image_view.get() == nullptr && managed_texture.get() == nullptr); } - void copy_texture(vk::command_buffer& cmd, u32 heap_index, VkQueue submit_queue, - bool manage_cb_lifetime = false, VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + void copy_texture(vk::command_buffer& cmd, u32 heap_index, VkQueue submit_queue, bool manage_cb_lifetime = false) { if (m_device == nullptr) { @@ -172,9 +171,10 @@ namespace vk VkImageSubresourceRange subresource_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - change_image_layout(cmd, vram_texture->value, layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, subresource_range); + VkImageLayout layout = vram_texture->current_layout; + change_image_layout(cmd, vram_texture, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, subresource_range); vkCmdCopyImageToBuffer(cmd, vram_texture->value, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dma_buffer->value, 1, ©Region); - change_image_layout(cmd, vram_texture->value, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layout, subresource_range); + change_image_layout(cmd, vram_texture, layout, subresource_range); if (manage_cb_lifetime) { @@ -227,7 +227,7 @@ namespace vk if (!synchronized) { LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base); - copy_texture(cmd, heap_index, submit_queue, true, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + copy_texture(cmd, heap_index, submit_queue, true); } protect(utils::protection::rw); @@ -297,7 +297,7 @@ namespace vk return tex; else { - LOG_ERROR(RSX, "Cached object for address 0x%X was found, but it does not match stored parameters."); + LOG_ERROR(RSX, "Cached object for address 0x%X was found, but it does not match stored parameters.", rsx_address); LOG_ERROR(RSX, "%d x %d vs %d x %d", width, height, tex.get_width(), tex.get_height()); } } @@ -396,6 +396,57 @@ namespace vk return { mapping[1], mapping[2], mapping[3], mapping[0] }; } + vk::image_view* create_temporary_subresource(vk::command_buffer& cmd, vk::image* source, u32 x, u32 y, u32 w, u32 h, const vk::memory_type_mapping &memory_type_mapping) + { + VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; + + switch (source->info.format) + { + case VK_FORMAT_D16_UNORM: + aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + } + + VkImageSubresourceRange subresource_range = { aspect, 0, 1, 0, 1 }; + + std::unique_ptr image; + std::unique_ptr view; + + image.reset(new vk::image(*vk::get_current_renderer(), memory_type_mapping.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + source->info.imageType, + source->info.format, + source->width(), source->height(), source->depth(), 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, source->info.flags)); + + VkImageSubresourceRange view_range = { aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 1 }; + view.reset(new vk::image_view(*vk::get_current_renderer(), image->value, VK_IMAGE_VIEW_TYPE_2D, source->info.format, source->native_component_map, view_range)); + + VkImageLayout old_src_layout = source->current_layout; + + vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_GENERAL, subresource_range); + vk::change_image_layout(cmd, source, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, subresource_range); + + VkImageCopy copy_rgn; + copy_rgn.srcOffset = { (s32)x, (s32)y, 0 }; + copy_rgn.dstOffset = { (s32)x, (s32)y, 0 }; + copy_rgn.dstSubresource = { aspect, 0, 0, 1 }; + copy_rgn.srcSubresource = { aspect, 0, 0, 1 }; + copy_rgn.extent = { w, h, 1 }; + + vkCmdCopyImage(cmd, source->value, source->current_layout, image->value, image->current_layout, 1, ©_rgn); + vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); + vk::change_image_layout(cmd, source, old_src_layout, subresource_range); + + m_dirty_textures.push_back(std::move(image)); + m_temporary_image_view.push_back(std::move(view)); + + return m_temporary_image_view.back().get(); + } + public: texture_cache() {} @@ -422,16 +473,31 @@ namespace vk vk::image *rtt_texture = nullptr; if (rtt_texture = m_rtts.get_texture_from_render_target_if_applicable(texaddr)) { + for (auto tex : m_rtts.m_bound_render_targets) + { + if (std::get<0>(tex) == texaddr) + { + LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr); + return create_temporary_subresource(cmd, rtt_texture, 0, 0, rtt_texture->width(), rtt_texture->height(), memory_type_mapping); + } + } + m_temporary_image_view.push_back(std::make_unique(*vk::get_current_renderer(), rtt_texture->value, VK_IMAGE_VIEW_TYPE_2D, rtt_texture->info.format, - rtt_texture->native_layout, + rtt_texture->native_component_map, vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT))); return m_temporary_image_view.back().get(); } if (rtt_texture = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) { + if (std::get<0>(m_rtts.m_bound_depth_stencil) == texaddr) + { + LOG_WARNING(RSX, "Attempting to sample a currently bound depth surface @ 0x%x", texaddr); + return create_temporary_subresource(cmd, rtt_texture, 0, 0, rtt_texture->width(), rtt_texture->height(), memory_type_mapping); + } + m_temporary_image_view.push_back(std::make_unique(*vk::get_current_renderer(), rtt_texture->value, VK_IMAGE_VIEW_TYPE_2D, rtt_texture->info.format, - rtt_texture->native_layout, + rtt_texture->native_component_map, vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_DEPTH_BIT))); return m_temporary_image_view.back().get(); } @@ -501,7 +567,7 @@ namespace vk vk_format, tex.width(), height, depth, tex.get_exact_mipmap_count(), layer, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0); - change_image_layout(cmd, image->value, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresource_range); + change_image_layout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresource_range); vk::image_view *view = new vk::image_view(*vk::get_current_renderer(), image->value, image_view_type, vk_format, mapping, @@ -513,7 +579,7 @@ namespace vk copy_mipmaped_image_using_buffer(cmd, image->value, get_subresources_layout(tex), format, !(tex.format() & CELL_GCM_TEXTURE_LN), tex.get_exact_mipmap_count(), upload_heap, upload_buffer); - change_image_layout(cmd, image->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); + change_image_layout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); vk::leave_uninterruptible();