| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | // Copyright 2016 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-30 23:07:50 -04:00
										 |  |  | #include "VideoBackends/Vulkan/TextureCache.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2016-09-30 23:07:50 -04:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Common/Assert.h"
 | 
					
						
							|  |  |  | #include "Common/CommonFuncs.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-30 23:07:50 -04:00
										 |  |  | #include "Common/Logging/Log.h"
 | 
					
						
							|  |  |  | #include "Common/MsgHandler.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/CommandBufferManager.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/FramebufferManager.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/ObjectCache.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/Renderer.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/StateTracker.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/StreamBuffer.h"
 | 
					
						
							|  |  |  | #include "VideoBackends/Vulkan/Texture2D.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:23 +10:00
										 |  |  | #include "VideoBackends/Vulkan/TextureConverter.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoBackends/Vulkan/Util.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | #include "VideoBackends/Vulkan/VKTexture.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | #include "VideoBackends/Vulkan/VulkanContext.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VideoCommon/ImageWrite.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | #include "VideoCommon/TextureConfig.h"
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Vulkan | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | TextureCache::TextureCache() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TextureCache::~TextureCache() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-01 22:22:14 +10:00
										 |  |  |   TextureCache::DeleteShaders(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | VkShaderModule TextureCache::GetCopyShader() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_copy_shader; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StreamBuffer* TextureCache::GetTextureUploadBuffer() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return m_texture_upload_buffer.get(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  | TextureCache* TextureCache::GetInstance() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return static_cast<TextureCache*>(g_texture_cache.get()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool TextureCache::Initialize() | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | { | 
					
						
							|  |  |  |   m_texture_upload_buffer = | 
					
						
							|  |  |  |       StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, | 
					
						
							|  |  |  |                            MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE); | 
					
						
							|  |  |  |   if (!m_texture_upload_buffer) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("Failed to create texture upload buffer"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:23 +10:00
										 |  |  |   m_texture_converter = std::make_unique<TextureConverter>(); | 
					
						
							|  |  |  |   if (!m_texture_converter->Initialize()) | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-11-19 23:25:23 +10:00
										 |  |  |     PanicAlert("Failed to initialize texture converter"); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!CompileShaders()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     PanicAlert("Failed to compile one or more shaders"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-30 12:45:55 -07:00
										 |  |  | void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source, | 
					
						
							|  |  |  |                                   const void* palette, TLUTFormat format) | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-09-09 14:04:26 +10:00
										 |  |  |   m_texture_converter->ConvertTexture(destination, source, palette, format); | 
					
						
							| 
									
										
										
										
											2017-06-13 14:40:01 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound.
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   static_cast<VKTexture*>(source->texture.get()) | 
					
						
							|  |  |  |       ->GetRawTexIdentifier() | 
					
						
							|  |  |  |       ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), | 
					
						
							|  |  |  |                            VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							|  |  |  |   static_cast<VKTexture*>(destination->texture.get()) | 
					
						
							|  |  |  |       ->GetRawTexIdentifier() | 
					
						
							|  |  |  |       ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), | 
					
						
							|  |  |  |                            VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-03 00:17:00 +10:00
										 |  |  | void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& params, | 
					
						
							|  |  |  |                            u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |                            const EFBRectangle& src_rect, bool scale_by_half, float y_scale, | 
					
						
							|  |  |  |                            float gamma, bool clamp_top, bool clamp_bottom, | 
					
						
							|  |  |  |                            const CopyFilterCoefficientArray& filter_coefficients) | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | { | 
					
						
							|  |  |  |   // Flush EFB pokes first, as they're expected to be included.
 | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  |   FramebufferManager::GetInstance()->FlushEFBPokes(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // MSAA case where we need to resolve first.
 | 
					
						
							| 
									
										
										
										
											2017-04-15 19:55:32 +10:00
										 |  |  |   // An out-of-bounds source region is valid here, and fine for the draw (since it is converted
 | 
					
						
							|  |  |  |   // to texture coordinates), but it's not valid to resolve an out-of-range rectangle.
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  |   TargetRectangle scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect); | 
					
						
							|  |  |  |   VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top}, | 
					
						
							|  |  |  |                      {static_cast<u32>(scaled_src_rect.GetWidth()), | 
					
						
							|  |  |  |                       static_cast<u32>(scaled_src_rect.GetHeight())}}; | 
					
						
							| 
									
										
										
										
											2017-04-15 19:55:32 +10:00
										 |  |  |   region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(), | 
					
						
							|  |  |  |                              FramebufferManager::GetInstance()->GetEFBHeight()); | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  |   Texture2D* src_texture; | 
					
						
							| 
									
										
										
										
											2017-07-30 12:45:55 -07:00
										 |  |  |   if (params.depth) | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  |     src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 22:34:36 +10:00
										 |  |  |   // End render pass before barrier (since we have no self-dependencies).
 | 
					
						
							|  |  |  |   // The barrier has to happen after the render pass, not inside it, as we are going to be
 | 
					
						
							|  |  |  |   // reading from the texture immediately afterwards.
 | 
					
						
							| 
									
										
										
										
											2016-10-22 20:50:36 +10:00
										 |  |  |   StateTracker::GetInstance()->EndRenderPass(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Transition to shader resource before reading.
 | 
					
						
							|  |  |  |   VkImageLayout original_layout = src_texture->GetLayout(); | 
					
						
							|  |  |  |   src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), | 
					
						
							|  |  |  |                                   VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |   m_texture_converter->EncodeTextureToMemory( | 
					
						
							|  |  |  |       src_texture->GetView(), dst, params, native_width, bytes_per_row, num_blocks_y, memory_stride, | 
					
						
							|  |  |  |       src_rect, scale_by_half, y_scale, gamma, clamp_top, clamp_bottom, filter_coefficients); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Transition back to original state
 | 
					
						
							|  |  |  |   src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout); | 
					
						
							| 
									
										
										
										
											2018-11-05 23:09:34 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   StateTracker::GetInstance()->OnEFBCopyToRAM(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-30 12:45:55 -07:00
										 |  |  | bool TextureCache::SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format) | 
					
						
							| 
									
										
										
										
											2016-12-09 22:23:07 +10:00
										 |  |  | { | 
					
						
							|  |  |  |   return m_texture_converter->SupportsTextureDecoding(format, palette_format); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u8* data, | 
					
						
							| 
									
										
										
										
											2016-12-09 22:23:07 +10:00
										 |  |  |                                       size_t data_size, TextureFormat format, u32 width, u32 height, | 
					
						
							|  |  |  |                                       u32 aligned_width, u32 aligned_height, u32 row_stride, | 
					
						
							| 
									
										
										
										
											2017-07-30 12:45:55 -07:00
										 |  |  |                                       const u8* palette, TLUTFormat palette_format) | 
					
						
							| 
									
										
										
										
											2016-12-09 22:23:07 +10:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-10 23:41:10 +10:00
										 |  |  |   // Group compute shader dispatches together in the init command buffer. That way we don't have to
 | 
					
						
							|  |  |  |   // pay a penalty for switching from graphics->compute, or end/restart our render pass.
 | 
					
						
							|  |  |  |   VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentInitCommandBuffer(); | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   m_texture_converter->DecodeTexture(command_buffer, entry, dst_level, data, data_size, format, | 
					
						
							|  |  |  |                                      width, height, aligned_width, aligned_height, row_stride, | 
					
						
							|  |  |  |                                      palette, palette_format); | 
					
						
							| 
									
										
										
										
											2017-06-10 23:41:10 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Last mip level? Ensure the texture is ready for use.
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   if (dst_level == (entry->GetNumLevels() - 1)) | 
					
						
							| 
									
										
										
										
											2017-06-10 23:41:10 +10:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |     static_cast<VKTexture*>(entry->texture.get()) | 
					
						
							|  |  |  |         ->GetRawTexIdentifier() | 
					
						
							|  |  |  |         ->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							| 
									
										
										
										
											2017-06-10 23:41:10 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-12-09 22:23:07 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | bool TextureCache::CompileShaders() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   static const char COPY_SHADER_SOURCE[] = R"( | 
					
						
							|  |  |  |     layout(set = 1, binding = 0) uniform sampler2DArray samp0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     layout(location = 0) in float3 uv0; | 
					
						
							|  |  |  |     layout(location = 1) in float4 col0; | 
					
						
							|  |  |  |     layout(location = 0) out float4 ocol0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void main() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ocol0 = texture(samp0, uv0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   )"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-20 15:25:33 +10:00
										 |  |  |   std::string header = g_shader_cache->GetUtilityShaderHeader(); | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  |   std::string source = header + COPY_SHADER_SOURCE; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | 
 | 
					
						
							|  |  |  |   m_copy_shader = Util::CompileAndCreateFragmentShader(source); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  |   return m_copy_shader != VK_NULL_HANDLE; | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TextureCache::DeleteShaders() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-10-01 22:22:14 +10:00
										 |  |  |   // It is safe to destroy shader modules after they are consumed by creating a pipeline.
 | 
					
						
							|  |  |  |   // Therefore, no matter where this function is called from, it won't cause an issue due to
 | 
					
						
							|  |  |  |   // pending commands, although at the time of writing should only be called at the end of
 | 
					
						
							|  |  |  |   // a frame. See Vulkan spec, section 2.3.1. Object Lifetime.
 | 
					
						
							|  |  |  |   if (m_copy_shader != VK_NULL_HANDLE) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_copy_shader, nullptr); | 
					
						
							|  |  |  |     m_copy_shader = VK_NULL_HANDLE; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   for (auto& shader : m_efb_copy_to_tex_shaders) | 
					
						
							| 
									
										
										
										
											2016-10-01 22:22:14 +10:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  |     vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader.second, nullptr); | 
					
						
							| 
									
										
										
										
											2016-10-01 22:22:14 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  |   m_efb_copy_to_tex_shaders.clear(); | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, | 
					
						
							|  |  |  |                                        const EFBRectangle& src_rect, bool scale_by_half, | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |                                        EFBCopyFormat dst_format, bool is_intensity, float gamma, | 
					
						
							|  |  |  |                                        bool clamp_top, bool clamp_bottom, | 
					
						
							|  |  |  |                                        const CopyFilterCoefficientArray& filter_coefficients) | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | { | 
					
						
							|  |  |  |   VKTexture* texture = static_cast<VKTexture*>(entry->texture.get()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // A better way of doing this would be nice.
 | 
					
						
							|  |  |  |   FramebufferManager* framebuffer_mgr = | 
					
						
							|  |  |  |       static_cast<FramebufferManager*>(g_framebuffer_manager.get()); | 
					
						
							|  |  |  |   TargetRectangle scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Flush EFB pokes first, as they're expected to be included.
 | 
					
						
							|  |  |  |   framebuffer_mgr->FlushEFBPokes(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Has to be flagged as a render target.
 | 
					
						
							| 
									
										
										
										
											2018-03-14 20:34:35 -04:00
										 |  |  |   ASSERT(texture->GetFramebuffer() != VK_NULL_HANDLE); | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Can't be done in a render pass, since we're doing our own render pass!
 | 
					
						
							|  |  |  |   VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); | 
					
						
							|  |  |  |   StateTracker::GetInstance()->EndRenderPass(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |   // Fill uniform buffer.
 | 
					
						
							|  |  |  |   struct PixelUniforms | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     float filter_coefficients[3]; | 
					
						
							|  |  |  |     float gamma_rcp; | 
					
						
							|  |  |  |     float clamp_top; | 
					
						
							|  |  |  |     float clamp_bottom; | 
					
						
							|  |  |  |     float pixel_height; | 
					
						
							|  |  |  |     u32 padding; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   PixelUniforms uniforms; | 
					
						
							|  |  |  |   for (size_t i = 0; i < filter_coefficients.size(); i++) | 
					
						
							| 
									
										
										
										
											2018-05-22 12:14:48 +10:00
										 |  |  |     uniforms.filter_coefficients[i] = filter_coefficients[i]; | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |   uniforms.gamma_rcp = 1.0f / gamma; | 
					
						
							|  |  |  |   uniforms.clamp_top = clamp_top ? src_rect.top / float(EFB_HEIGHT) : 0.0f; | 
					
						
							|  |  |  |   uniforms.clamp_bottom = clamp_bottom ? src_rect.bottom / float(EFB_HEIGHT) : 1.0f; | 
					
						
							|  |  |  |   uniforms.pixel_height = | 
					
						
							|  |  |  |       g_ActiveConfig.bCopyEFBScaled ? 1.0f / g_renderer->GetTargetHeight() : 1.0f / EFB_HEIGHT; | 
					
						
							|  |  |  |   uniforms.padding = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   // Transition EFB to shader resource before binding.
 | 
					
						
							|  |  |  |   // An out-of-bounds source region is valid here, and fine for the draw (since it is converted
 | 
					
						
							|  |  |  |   // to texture coordinates), but it's not valid to resolve an out-of-range rectangle.
 | 
					
						
							|  |  |  |   VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top}, | 
					
						
							|  |  |  |                      {static_cast<u32>(scaled_src_rect.GetWidth()), | 
					
						
							|  |  |  |                       static_cast<u32>(scaled_src_rect.GetHeight())}}; | 
					
						
							|  |  |  |   region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(), | 
					
						
							|  |  |  |                              FramebufferManager::GetInstance()->GetEFBHeight()); | 
					
						
							|  |  |  |   Texture2D* src_texture; | 
					
						
							|  |  |  |   if (is_depth_copy) | 
					
						
							|  |  |  |     src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VkSampler src_sampler = | 
					
						
							|  |  |  |       scale_by_half ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler(); | 
					
						
							|  |  |  |   VkImageLayout original_layout = src_texture->GetLayout(); | 
					
						
							|  |  |  |   src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							|  |  |  |   texture->GetRawTexIdentifier()->TransitionToLayout(command_buffer, | 
					
						
							|  |  |  |                                                      VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-25 11:07:14 +01:00
										 |  |  |   auto uid = TextureConversionShaderGen::GetShaderUid(dst_format, is_depth_copy, is_intensity, | 
					
						
							| 
									
										
										
										
											2018-05-03 14:09:32 +10:00
										 |  |  |                                                       scale_by_half, | 
					
						
							|  |  |  |                                                       NeedsCopyFilterInShader(filter_coefficients)); | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   auto it = m_efb_copy_to_tex_shaders.emplace(uid, VkShaderModule(VK_NULL_HANDLE)); | 
					
						
							|  |  |  |   VkShaderModule& shader = it.first->second; | 
					
						
							|  |  |  |   bool created = it.second; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (created) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::string source = g_shader_cache->GetUtilityShaderHeader(); | 
					
						
							| 
									
										
										
										
											2017-11-25 11:07:14 +01:00
										 |  |  |     source += | 
					
						
							|  |  |  |         TextureConversionShaderGen::GenerateShader(APIType::Vulkan, uid.GetUidData()).GetBuffer(); | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     shader = Util::CompileAndCreateFragmentShader(source); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 14:04:26 +10:00
										 |  |  |   VkRenderPass render_pass = g_object_cache->GetRenderPass( | 
					
						
							|  |  |  |       texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED, | 
					
						
							|  |  |  |       texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   UtilityShaderDraw draw(command_buffer, | 
					
						
							| 
									
										
										
										
											2017-09-09 14:04:26 +10:00
										 |  |  |                          g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, | 
					
						
							| 
									
										
										
										
											2017-08-04 17:56:24 +02:00
										 |  |  |                          g_shader_cache->GetPassthroughVertexShader(), | 
					
						
							|  |  |  |                          g_shader_cache->GetPassthroughGeometryShader(), shader); | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-29 18:52:30 +10:00
										 |  |  |   u8* ubo_ptr = draw.AllocatePSUniforms(sizeof(PixelUniforms)); | 
					
						
							|  |  |  |   std::memcpy(ubo_ptr, &uniforms, sizeof(PixelUniforms)); | 
					
						
							|  |  |  |   draw.CommitPSUniforms(sizeof(PixelUniforms)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-22 23:44:34 -05:00
										 |  |  |   draw.SetPSSampler(0, src_texture->GetView(), src_sampler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VkRect2D dest_region = {{0, 0}, {texture->GetConfig().width, texture->GetConfig().height}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   draw.BeginRenderPass(texture->GetFramebuffer(), dest_region); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   draw.DrawQuad(0, 0, texture->GetConfig().width, texture->GetConfig().height, scaled_src_rect.left, | 
					
						
							|  |  |  |                 scaled_src_rect.top, 0, scaled_src_rect.GetWidth(), scaled_src_rect.GetHeight(), | 
					
						
							|  |  |  |                 framebuffer_mgr->GetEFBWidth(), framebuffer_mgr->GetEFBHeight()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   draw.EndRenderPass(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // We touched everything, so put it back.
 | 
					
						
							|  |  |  |   StateTracker::GetInstance()->SetPendingRebind(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Transition the EFB back to its original layout.
 | 
					
						
							|  |  |  |   src_texture->TransitionToLayout(command_buffer, original_layout); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Ensure texture is in SHADER_READ_ONLY layout, ready for usage.
 | 
					
						
							|  |  |  |   texture->GetRawTexIdentifier()->TransitionToLayout(command_buffer, | 
					
						
							|  |  |  |                                                      VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 22:57:50 +10:00
										 |  |  | }  // namespace Vulkan
 |