From f039149198657c1891e1c6462ed30c31ed4b8486 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 15 Feb 2019 11:59:50 +1000 Subject: Move most backend functionality to VideoCommon --- .../VideoBackends/Vulkan/FramebufferManager.cpp | 1198 -------------------- 1 file changed, 1198 deletions(-) delete mode 100644 Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp (limited to 'Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp') diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp deleted file mode 100644 index cd1fbd9c82..0000000000 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ /dev/null @@ -1,1198 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/Vulkan/FramebufferManager.h" - -#include -#include - -#include "Common/Assert.h" -#include "Common/CommonFuncs.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" - -#include "Core/HW/Memmap.h" - -#include "VideoBackends/Vulkan/CommandBufferManager.h" -#include "VideoBackends/Vulkan/ObjectCache.h" -#include "VideoBackends/Vulkan/StateTracker.h" -#include "VideoBackends/Vulkan/StreamBuffer.h" -#include "VideoBackends/Vulkan/Texture2D.h" -#include "VideoBackends/Vulkan/Util.h" -#include "VideoBackends/Vulkan/VKTexture.h" -#include "VideoBackends/Vulkan/VertexFormat.h" -#include "VideoBackends/Vulkan/VulkanContext.h" - -#include "VideoCommon/RenderBase.h" -#include "VideoCommon/VideoConfig.h" - -namespace Vulkan -{ -// Maximum number of pixels poked in one batch * 6 -constexpr size_t MAX_POKE_VERTICES = 8192; -constexpr size_t POKE_VERTEX_BUFFER_SIZE = 8 * 1024 * 1024; - -FramebufferManager::FramebufferManager() -{ -} - -FramebufferManager::~FramebufferManager() -{ - DestroyEFBFramebuffer(); - - DestroyConversionShaders(); - - DestroyReadbackFramebuffer(); - DestroyReadbackTextures(); - DestroyReadbackShaders(); - - DestroyPokeVertexBuffer(); - DestroyPokeShaders(); -} - -FramebufferManager* FramebufferManager::GetInstance() -{ - return static_cast(g_framebuffer_manager.get()); -} - -u32 FramebufferManager::GetEFBWidth() const -{ - return m_efb_color_texture->GetWidth(); -} - -u32 FramebufferManager::GetEFBHeight() const -{ - return m_efb_color_texture->GetHeight(); -} - -u32 FramebufferManager::GetEFBLayers() const -{ - return m_efb_color_texture->GetLayers(); -} - -VkSampleCountFlagBits FramebufferManager::GetEFBSamples() const -{ - return m_efb_color_texture->GetSamples(); -} - -MultisamplingState FramebufferManager::GetEFBMultisamplingState() const -{ - MultisamplingState ms = {}; - ms.per_sample_shading = g_ActiveConfig.MultisamplingEnabled() && g_ActiveConfig.bSSAA; - ms.samples = static_cast(GetEFBSamples()); - return ms; -} - -bool FramebufferManager::Initialize() -{ - if (!CreateEFBRenderPasses()) - { - PanicAlert("Failed to create EFB render pass"); - return false; - } - if (!CreateEFBFramebuffer()) - { - PanicAlert("Failed to create EFB textures"); - return false; - } - - if (!CompileConversionShaders()) - { - PanicAlert("Failed to compile EFB shaders"); - return false; - } - - if (!CreateReadbackRenderPasses()) - { - PanicAlert("Failed to create readback render passes"); - return false; - } - if (!CompileReadbackShaders()) - { - PanicAlert("Failed to compile readback shaders"); - return false; - } - if (!CreateReadbackTextures()) - { - PanicAlert("Failed to create readback textures"); - return false; - } - if (!CreateReadbackFramebuffer()) - { - PanicAlert("Failed to create readback framebuffer"); - return false; - } - - CreatePokeVertexFormat(); - if (!CreatePokeVertexBuffer()) - { - PanicAlert("Failed to create poke vertex buffer"); - return false; - } - - if (!CompilePokeShaders()) - { - PanicAlert("Failed to compile poke shaders"); - return false; - } - - return true; -} - -bool FramebufferManager::CreateEFBRenderPasses() -{ - m_efb_load_render_pass = g_object_cache->GetRenderPass( - EFB_COLOR_TEXTURE_FORMAT, Util::GetVkFormatForHostTextureFormat(GetEFBDepthFormat()), - g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_LOAD); - m_efb_clear_render_pass = g_object_cache->GetRenderPass( - EFB_COLOR_TEXTURE_FORMAT, Util::GetVkFormatForHostTextureFormat(GetEFBDepthFormat()), - g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_CLEAR); - m_depth_resolve_render_pass = g_object_cache->GetRenderPass( - EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); - return m_efb_load_render_pass != VK_NULL_HANDLE && m_efb_clear_render_pass != VK_NULL_HANDLE && - m_depth_resolve_render_pass != VK_NULL_HANDLE; -} - -bool FramebufferManager::CreateEFBFramebuffer() -{ - u32 efb_width = static_cast(std::max(g_renderer->GetTargetWidth(), 1)); - u32 efb_height = static_cast(std::max(g_renderer->GetTargetHeight(), 1)); - u32 efb_layers = (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1; - VkSampleCountFlagBits efb_samples = - static_cast(g_ActiveConfig.iMultisamples); - INFO_LOG(VIDEO, "EFB size: %ux%ux%u", efb_width, efb_height, efb_layers); - - // Update the static variable in the base class. Why does this even exist? - FramebufferManagerBase::m_EFBLayers = efb_layers; - - // Allocate EFB render targets - m_efb_color_texture = - Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - - // We need a second texture to swap with for changing pixel formats - m_efb_convert_color_texture = - Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - - m_efb_depth_texture = Texture2D::Create( - efb_width, efb_height, 1, efb_layers, - Util::GetVkFormatForHostTextureFormat(GetEFBDepthFormat()), efb_samples, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - - if (!m_efb_color_texture || !m_efb_convert_color_texture || !m_efb_depth_texture) - return false; - - // Create resolved textures if MSAA is on - if (g_ActiveConfig.MultisamplingEnabled()) - { - m_efb_resolve_color_texture = Texture2D::Create( - efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT); - - m_efb_resolve_depth_texture = Texture2D::Create( - efb_width, efb_height, 1, efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT); - - if (!m_efb_resolve_color_texture || !m_efb_resolve_depth_texture) - return false; - - VkImageView attachment = m_efb_resolve_depth_texture->GetView(); - VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - 0, - m_depth_resolve_render_pass, - 1, - &attachment, - efb_width, - efb_height, - efb_layers}; - - VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_depth_resolve_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - } - - VkImageView framebuffer_attachments[] = { - m_efb_color_texture->GetView(), - m_efb_depth_texture->GetView(), - }; - - VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - 0, - m_efb_load_render_pass, - static_cast(ArraySize(framebuffer_attachments)), - framebuffer_attachments, - efb_width, - efb_height, - efb_layers}; - - VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_efb_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - - // Create second framebuffer for format conversions - framebuffer_attachments[0] = m_efb_convert_color_texture->GetView(); - res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_efb_convert_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - - // Transition to state that can be used to clear - m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - m_efb_convert_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Clear the contents of the buffers. - static const VkClearColorValue clear_color = {{0.0f, 0.0f, 0.0f, 0.0f}}; - static const VkClearDepthStencilValue clear_depth = {0.0f, 0}; - VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, efb_layers}; - VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, efb_layers}; - vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clear_color, 1, &clear_color_range); - vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_efb_convert_color_texture->GetImage(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &clear_color_range); - vkCmdClearDepthStencilImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_efb_depth_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clear_depth, 1, &clear_depth_range); - - // Transition to color attachment state ready for rendering. - m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - - return true; -} - -void FramebufferManager::DestroyEFBFramebuffer() -{ - if (m_efb_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_efb_framebuffer, nullptr); - m_efb_framebuffer = VK_NULL_HANDLE; - } - - if (m_efb_convert_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_efb_convert_framebuffer, nullptr); - m_efb_convert_framebuffer = VK_NULL_HANDLE; - } - - if (m_depth_resolve_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_depth_resolve_framebuffer, nullptr); - m_depth_resolve_framebuffer = VK_NULL_HANDLE; - } - - m_efb_color_texture.reset(); - m_efb_convert_color_texture.reset(); - m_efb_depth_texture.reset(); - m_efb_resolve_color_texture.reset(); - m_efb_resolve_depth_texture.reset(); -} - -void FramebufferManager::RecreateEFBFramebuffer() -{ - DestroyEFBFramebuffer(); - - if (!CreateEFBRenderPasses()) - PanicAlert("Failed to create EFB render pass"); - - if (!CreateEFBFramebuffer()) - PanicAlert("Failed to create EFB textures"); -} - -void FramebufferManager::RecompileShaders() -{ - DestroyConversionShaders(); - - if (!CompileConversionShaders()) - PanicAlert("Failed to compile EFB shaders"); - - DestroyReadbackShaders(); - if (!CompileReadbackShaders()) - PanicAlert("Failed to compile readback shaders"); -} - -void FramebufferManager::ReinterpretPixelData(int convtype) -{ - VkShaderModule pixel_shader = VK_NULL_HANDLE; - if (convtype == 0) - { - pixel_shader = m_ps_rgb8_to_rgba6; - } - else if (convtype == 2) - { - pixel_shader = m_ps_rgba6_to_rgb8; - } - else - { - ERROR_LOG(VIDEO, "Unhandled reinterpret pixel data %d", convtype); - return; - } - - // Transition EFB color buffer to shader resource, and the convert buffer to color attachment. - m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_efb_convert_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_efb_load_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - g_shader_cache->GetScreenQuadGeometryShader(), pixel_shader); - - VkRect2D region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; - draw.SetMultisamplingState(GetEFBMultisamplingState()); - draw.BeginRenderPass(m_efb_convert_framebuffer, region); - draw.SetPSSampler(0, m_efb_color_texture->GetView(), g_object_cache->GetPointSampler()); - draw.SetViewportAndScissor(0, 0, GetEFBWidth(), GetEFBHeight()); - draw.DrawWithoutVertexBuffer(4); - draw.EndRenderPass(); - - // Swap EFB texture pointers - std::swap(m_efb_color_texture, m_efb_convert_color_texture); - std::swap(m_efb_framebuffer, m_efb_convert_framebuffer); -} - -Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) -{ - // Return the normal EFB texture if multisampling is off. - if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT) - return m_efb_color_texture.get(); - - // Can't resolve within a render pass. - StateTracker::GetInstance()->EndRenderPass(); - - // It's not valid to resolve out-of-bounds coordinates. - // Ensuring the region is within the image is the caller's responsibility. - ASSERT(region.offset.x >= 0 && region.offset.y >= 0 && - (static_cast(region.offset.x) + region.extent.width) <= GetEFBWidth() && - (static_cast(region.offset.y) + region.extent.height) <= GetEFBHeight()); - - // Resolving is considered to be a transfer operation. - m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - m_efb_resolve_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Resolve to our already-created texture. - VkImageResolve resolve = { - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers srcSubresource - {region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers dstSubresource - {region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset - {region.extent.width, region.extent.height, GetEFBLayers()} // VkExtent3D extent - }; - vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - m_efb_resolve_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &resolve); - - // Restore MSAA texture ready for rendering again - m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - return m_efb_resolve_color_texture.get(); -} - -Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) -{ - // Return the normal EFB texture if multisampling is off. - if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT) - return m_efb_depth_texture.get(); - - // Can't resolve within a render pass. - StateTracker::GetInstance()->EndRenderPass(); - - m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_efb_resolve_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Draw using resolve shader to write the minimum depth of all samples to the resolve texture. - UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_depth_resolve_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - g_shader_cache->GetScreenQuadGeometryShader(), m_ps_depth_resolve); - draw.BeginRenderPass(m_depth_resolve_framebuffer, region); - draw.SetPSSampler(0, m_efb_depth_texture->GetView(), g_object_cache->GetPointSampler()); - draw.SetViewportAndScissor(region.offset.x, region.offset.y, region.extent.width, - region.extent.height); - draw.DrawWithoutVertexBuffer(4); - draw.EndRenderPass(); - - // Restore MSAA texture ready for rendering again - m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - - return m_efb_resolve_depth_texture.get(); -} - -bool FramebufferManager::CompileConversionShaders() -{ - static const char RGB8_TO_RGBA6_SHADER_SOURCE[] = R"( - #if MSAA_ENABLED - SAMPLER_BINDING(0) uniform sampler2DMSArray samp0; - #else - SAMPLER_BINDING(0) uniform sampler2DArray samp0; - #endif - layout(location = 0) in vec3 uv0; - layout(location = 0) out vec4 ocol0; - - void main() - { - int layer = 0; - #if EFB_LAYERS > 1 - layer = int(uv0.z); - #endif - - ivec3 coords = ivec3(gl_FragCoord.xy, layer); - - vec4 val; - #if !MSAA_ENABLED - // No MSAA - just load the first (and only) sample - val = texelFetch(samp0, coords, 0); - #elif SSAA_ENABLED - // Sample shading, shader runs once per sample - val = texelFetch(samp0, coords, gl_SampleID); - #else - // MSAA without sample shading, average out all samples. - val = vec4(0, 0, 0, 0); - for (int i = 0; i < MSAA_SAMPLES; i++) - val += texelFetch(samp0, coords, i); - val /= float(MSAA_SAMPLES); - #endif - - ivec4 src8 = ivec4(round(val * 255.f)); - ivec4 dst6; - dst6.r = src8.r >> 2; - dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4); - dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6); - dst6.a = src8.b & 0x3F; - - ocol0 = float4(dst6) / 63.f; - } - )"; - - static const char RGBA6_TO_RGB8_SHADER_SOURCE[] = R"( - #if MSAA_ENABLED - SAMPLER_BINDING(0) uniform sampler2DMSArray samp0; - #else - SAMPLER_BINDING(0) uniform sampler2DArray samp0; - #endif - layout(location = 0) in vec3 uv0; - layout(location = 0) out vec4 ocol0; - - void main() - { - int layer = 0; - #if EFB_LAYERS > 1 - layer = int(uv0.z); - #endif - - ivec3 coords = ivec3(gl_FragCoord.xy, layer); - - vec4 val; - #if !MSAA_ENABLED - // No MSAA - just load the first (and only) sample - val = texelFetch(samp0, coords, 0); - #elif SSAA_ENABLED - // Sample shading, shader runs once per sample - val = texelFetch(samp0, coords, gl_SampleID); - #else - // MSAA without sample shading, average out all samples. - val = vec4(0, 0, 0, 0); - for (int i = 0; i < MSAA_SAMPLES; i++) - val += texelFetch(samp0, coords, i); - val /= float(MSAA_SAMPLES); - #endif - - ivec4 src6 = ivec4(round(val * 63.f)); - ivec4 dst8; - dst8.r = (src6.r << 2) | (src6.g >> 4); - dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2); - dst8.b = ((src6.b & 0x3) << 6) | src6.a; - dst8.a = 255; - - ocol0 = float4(dst8) / 255.f; - } - )"; - - static const char DEPTH_RESOLVE_SHADER_SOURCE[] = R"( - SAMPLER_BINDING(0) uniform sampler2DMSArray samp0; - layout(location = 0) in vec3 uv0; - layout(location = 0) out float ocol0; - - void main() - { - int layer = 0; - #if EFB_LAYERS > 1 - layer = int(uv0.z); - #endif - - // gl_FragCoord is in window coordinates, and we're rendering to - // the same rectangle in the resolve texture. - ivec3 coords = ivec3(gl_FragCoord.xy, layer); - - // Take the minimum of all depth samples. - ocol0 = texelFetch(samp0, coords, 0).r; - for (int i = 1; i < MSAA_SAMPLES; i++) - ocol0 = min(ocol0, texelFetch(samp0, coords, i).r); - } - )"; - - std::string header = g_shader_cache->GetUtilityShaderHeader(); - DestroyConversionShaders(); - - m_ps_rgb8_to_rgba6 = Util::CompileAndCreateFragmentShader(header + RGB8_TO_RGBA6_SHADER_SOURCE); - m_ps_rgba6_to_rgb8 = Util::CompileAndCreateFragmentShader(header + RGBA6_TO_RGB8_SHADER_SOURCE); - if (GetEFBSamples() != VK_SAMPLE_COUNT_1_BIT) - m_ps_depth_resolve = Util::CompileAndCreateFragmentShader(header + DEPTH_RESOLVE_SHADER_SOURCE); - - return (m_ps_rgba6_to_rgb8 != VK_NULL_HANDLE && m_ps_rgb8_to_rgba6 != VK_NULL_HANDLE && - (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE)); -} - -void FramebufferManager::DestroyConversionShaders() -{ - auto DestroyShader = [this](VkShaderModule& shader) { - if (shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr); - shader = VK_NULL_HANDLE; - } - }; - - DestroyShader(m_ps_rgb8_to_rgba6); - DestroyShader(m_ps_rgba6_to_rgb8); - DestroyShader(m_ps_depth_resolve); -} - -u32 FramebufferManager::PeekEFBColor(u32 x, u32 y) -{ - if (!m_color_readback_texture_valid && !PopulateColorReadbackTexture()) - return 0; - - u32 value; - m_color_readback_texture->ReadTexel(x, y, &value); - return value; -} - -bool FramebufferManager::PopulateColorReadbackTexture() -{ - // Can't be in our normal render pass. - StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnCPUEFBAccess(); - - // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. - VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; - Texture2D* src_texture = m_efb_color_texture.get(); - if (GetEFBSamples() > 1) - src_texture = ResolveEFBColorTexture(src_region); - - if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) - { - // Transition EFB to shader read before drawing. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_copy_color_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - VK_NULL_HANDLE, m_copy_color_shader); - - VkRect2D rect = {{0, 0}, {EFB_WIDTH, EFB_HEIGHT}}; - draw.BeginRenderPass(m_color_copy_framebuffer, rect); - draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); - draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - draw.DrawWithoutVertexBuffer(4); - draw.EndRenderPass(); - - // Restore EFB to color attachment, since we're done with it. - if (src_texture == m_efb_color_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } - - // Use this as a source texture now. - src_texture = m_color_copy_texture.get(); - } - - // Copy from EFB or copy texture to staging texture. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - static_cast(m_color_readback_texture.get()) - ->CopyFromTexture(src_texture, m_color_readback_texture->GetConfig().GetRect(), 0, 0, - m_color_readback_texture->GetConfig().GetRect()); - - // Restore original layout if we used the EFB as a source. - if (src_texture == m_efb_color_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } - - // Wait until the copy is complete. - m_color_readback_texture->Flush(); - m_color_readback_texture_valid = true; - return true; -} - -float FramebufferManager::PeekEFBDepth(u32 x, u32 y) -{ - if (!m_depth_readback_texture_valid && !PopulateDepthReadbackTexture()) - return 0.0f; - - float value; - m_depth_readback_texture->ReadTexel(x, y, &value); - return value; -} - -bool FramebufferManager::PopulateDepthReadbackTexture() -{ - // Can't be in our normal render pass. - StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnCPUEFBAccess(); - - // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. - VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; - Texture2D* src_texture = m_efb_depth_texture.get(); - if (GetEFBSamples() > 1) - { - // EFB depth resolves are written out as color textures - src_texture = ResolveEFBDepthTexture(src_region); - } - if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) - { - // Transition EFB to shader read before drawing. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - m_copy_depth_render_pass, g_shader_cache->GetScreenQuadVertexShader(), - VK_NULL_HANDLE, m_copy_depth_shader); - - VkRect2D rect = {{0, 0}, {EFB_WIDTH, EFB_HEIGHT}}; - draw.BeginRenderPass(m_depth_copy_framebuffer, rect); - draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); - draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - draw.DrawWithoutVertexBuffer(4); - draw.EndRenderPass(); - - // Restore EFB to depth attachment, since we're done with it. - if (src_texture == m_efb_depth_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } - - // Use this as a source texture now. - src_texture = m_depth_copy_texture.get(); - } - - // Copy from EFB or copy texture to staging texture. - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - static_cast(m_depth_readback_texture.get()) - ->CopyFromTexture(src_texture, m_depth_readback_texture->GetConfig().GetRect(), 0, 0, - m_depth_readback_texture->GetConfig().GetRect()); - - // Restore original layout if we used the EFB as a source. - if (src_texture == m_efb_depth_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } - - // Wait until the copy is complete. - m_depth_readback_texture->Flush(); - m_depth_readback_texture_valid = true; - return true; -} - -void FramebufferManager::InvalidatePeekCache() -{ - m_color_readback_texture_valid = false; - m_depth_readback_texture_valid = false; -} - -bool FramebufferManager::CreateReadbackRenderPasses() -{ - m_copy_color_render_pass = g_object_cache->GetRenderPass( - EFB_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); - m_copy_depth_render_pass = g_object_cache->GetRenderPass( - EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); - if (m_copy_color_render_pass == VK_NULL_HANDLE || m_copy_depth_render_pass == VK_NULL_HANDLE) - return false; - - // Some devices don't support point sizes >1 (e.g. Adreno). - // If we can't use a point size above our maximum IR, use triangles instead. - // This means a 6x increase in the size of the vertices, though. - if (!g_vulkan_context->GetDeviceFeatures().largePoints || - g_vulkan_context->GetDeviceLimits().pointSizeGranularity > 1 || - g_vulkan_context->GetDeviceLimits().pointSizeRange[0] > 1 || - g_vulkan_context->GetDeviceLimits().pointSizeRange[1] < 16) - { - m_poke_primitive = PrimitiveType::TriangleStrip; - } - else - { - // Points should be okay. - m_poke_primitive = PrimitiveType::Points; - } - - return true; -} - -bool FramebufferManager::CompileReadbackShaders() -{ - std::string source; - - // TODO: Use input attachment here instead? - // TODO: MSAA resolve in shader. - static const char COPY_COLOR_SHADER_SOURCE[] = R"( - SAMPLER_BINDING(0) uniform sampler2DArray samp0; - layout(location = 0) in vec3 uv0; - layout(location = 0) out vec4 ocol0; - void main() - { - ocol0 = texture(samp0, uv0); - } - )"; - - static const char COPY_DEPTH_SHADER_SOURCE[] = R"( - SAMPLER_BINDING(0) uniform sampler2DArray samp0; - layout(location = 0) in vec3 uv0; - layout(location = 0) out float ocol0; - void main() - { - ocol0 = texture(samp0, uv0).r; - } - )"; - - source = g_shader_cache->GetUtilityShaderHeader() + COPY_COLOR_SHADER_SOURCE; - m_copy_color_shader = Util::CompileAndCreateFragmentShader(source); - - source = g_shader_cache->GetUtilityShaderHeader() + COPY_DEPTH_SHADER_SOURCE; - m_copy_depth_shader = Util::CompileAndCreateFragmentShader(source); - - return m_copy_color_shader != VK_NULL_HANDLE && m_copy_depth_shader != VK_NULL_HANDLE; -} - -void FramebufferManager::DestroyReadbackShaders() -{ - if (m_copy_color_shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_copy_color_shader, nullptr); - m_copy_color_shader = VK_NULL_HANDLE; - } - if (m_copy_depth_shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_copy_depth_shader, nullptr); - m_copy_depth_shader = VK_NULL_HANDLE; - } -} - -bool FramebufferManager::CreateReadbackTextures() -{ - m_color_copy_texture = - Texture2D::Create(EFB_WIDTH, EFB_HEIGHT, 1, 1, EFB_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - - m_depth_copy_texture = - Texture2D::Create(EFB_WIDTH, EFB_HEIGHT, 1, 1, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - - if (!m_color_copy_texture || !m_depth_copy_texture) - { - ERROR_LOG(VIDEO, "Failed to create EFB copy textures"); - return false; - } - - TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, - AbstractTextureFormat::RGBA8, false); - m_color_readback_texture = - g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config); - m_depth_readback_texture = - g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config); - if (!m_color_readback_texture || !m_depth_readback_texture) - { - ERROR_LOG(VIDEO, "Failed to create EFB readback textures"); - return false; - } - - return true; -} - -void FramebufferManager::DestroyReadbackTextures() -{ - m_color_copy_texture.reset(); - m_color_readback_texture.reset(); - m_color_readback_texture_valid = false; - m_depth_copy_texture.reset(); - m_depth_readback_texture.reset(); - m_depth_readback_texture_valid = false; -} - -bool FramebufferManager::CreateReadbackFramebuffer() -{ - VkImageView framebuffer_attachment = m_color_copy_texture->GetView(); - VkFramebufferCreateInfo framebuffer_info = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkFramebufferCreateFlags flags - m_copy_color_render_pass, // VkRenderPass renderPass - 1, // uint32_t attachmentCount - &framebuffer_attachment, // const VkImageView* pAttachments - EFB_WIDTH, // uint32_t width - EFB_HEIGHT, // uint32_t height - 1 // uint32_t layers - }; - VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_color_copy_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - - // Swap for depth - framebuffer_info.renderPass = m_copy_depth_render_pass; - framebuffer_attachment = m_depth_copy_texture->GetView(); - res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, - &m_depth_copy_framebuffer); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: "); - return false; - } - - return true; -} - -void FramebufferManager::DestroyReadbackFramebuffer() -{ - if (m_color_copy_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_color_copy_framebuffer, nullptr); - m_color_copy_framebuffer = VK_NULL_HANDLE; - } - if (m_depth_copy_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_depth_copy_framebuffer, nullptr); - m_depth_copy_framebuffer = VK_NULL_HANDLE; - } -} - -void FramebufferManager::PokeEFBColor(u32 x, u32 y, u32 color) -{ - // Flush if we exceeded the number of vertices per batch. - if ((m_color_poke_vertices.size() + 6) > MAX_POKE_VERTICES) - FlushEFBPokes(); - - CreatePokeVertices(&m_color_poke_vertices, x, y, 0.0f, color); - - // Update the peek cache if it's valid, since we know the color of the pixel now. - if (m_color_readback_texture_valid) - m_color_readback_texture->WriteTexel(x, y, &color); -} - -void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth) -{ - // Flush if we exceeded the number of vertices per batch. - if ((m_color_poke_vertices.size() + 6) > MAX_POKE_VERTICES) - FlushEFBPokes(); - - CreatePokeVertices(&m_depth_poke_vertices, x, y, depth, 0); - - // Update the peek cache if it's valid, since we know the color of the pixel now. - if (m_depth_readback_texture_valid) - m_depth_readback_texture->WriteTexel(x, y, &depth); -} - -void FramebufferManager::CreatePokeVertices(std::vector* destination_list, u32 x, - u32 y, float z, u32 color) -{ - if (m_poke_primitive == PrimitiveType::Points) - { - // GPU will expand the point to a quad. - float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f; - float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f; - float point_size = GetEFBWidth() / static_cast(EFB_WIDTH); - destination_list->push_back({{cs_x, cs_y, z, point_size}, color}); - return; - } - - // Some devices don't support point sizes >1 (e.g. Adreno). - // Generate quad from the single point (clip-space coordinates). - float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f; - float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f; - float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f; - float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f; - destination_list->push_back({{x1, y1, z, 1.0f}, color}); - destination_list->push_back({{x2, y1, z, 1.0f}, color}); - destination_list->push_back({{x1, y2, z, 1.0f}, color}); - destination_list->push_back({{x1, y2, z, 1.0f}, color}); - destination_list->push_back({{x2, y1, z, 1.0f}, color}); - destination_list->push_back({{x2, y2, z, 1.0f}, color}); -} - -void FramebufferManager::FlushEFBPokes() -{ - if (!m_color_poke_vertices.empty()) - { - DrawPokeVertices(m_color_poke_vertices.data(), m_color_poke_vertices.size(), true, false); - m_color_poke_vertices.clear(); - } - - if (!m_depth_poke_vertices.empty()) - { - DrawPokeVertices(m_depth_poke_vertices.data(), m_depth_poke_vertices.size(), false, true); - m_depth_poke_vertices.clear(); - } -} - -void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t vertex_count, - bool write_color, bool write_depth) -{ - // Relatively simple since we don't have any bindings. - VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - - // We don't use the utility shader in order to keep the vertices compact. - PipelineInfo pipeline_info = {}; - pipeline_info.vertex_format = m_poke_vertex_format.get(); - pipeline_info.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); - pipeline_info.vs = m_poke_vertex_shader; - pipeline_info.gs = (GetEFBLayers() > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE; - pipeline_info.ps = m_poke_fragment_shader; - pipeline_info.render_pass = m_efb_load_render_pass; - pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; - pipeline_info.rasterization_state.primitive = m_poke_primitive; - pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex; - pipeline_info.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; - pipeline_info.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; - pipeline_info.blend_state.colorupdate = write_color; - pipeline_info.blend_state.alphaupdate = write_color; - if (write_depth) - { - pipeline_info.depth_state.testenable = true; - pipeline_info.depth_state.updateenable = true; - pipeline_info.depth_state.func = ZMode::ALWAYS; - } - - VkPipeline pipeline = g_shader_cache->GetPipeline(pipeline_info); - if (pipeline == VK_NULL_HANDLE) - { - PanicAlert("Failed to get pipeline for EFB poke draw"); - return; - } - - // Populate vertex buffer. - size_t vertices_size = sizeof(EFBPokeVertex) * m_color_poke_vertices.size(); - if (!m_poke_vertex_stream_buffer->ReserveMemory(vertices_size, sizeof(EfbPokeData), true, true, - false)) - { - // Kick a command buffer first. - WARN_LOG(VIDEO, "Kicking command buffer due to no EFB poke space."); - Util::ExecuteCurrentCommandsAndRestoreState(false); - command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - - if (!m_poke_vertex_stream_buffer->ReserveMemory(vertices_size, sizeof(EfbPokeData), true, true, - false)) - { - PanicAlert("Failed to get space for EFB poke vertices"); - return; - } - } - VkBuffer vb_buffer = m_poke_vertex_stream_buffer->GetBuffer(); - VkDeviceSize vb_offset = m_poke_vertex_stream_buffer->GetCurrentOffset(); - memcpy(m_poke_vertex_stream_buffer->GetCurrentHostPointer(), vertices, vertices_size); - m_poke_vertex_stream_buffer->CommitMemory(vertices_size); - - // Set up state. - StateTracker::GetInstance()->EndClearRenderPass(); - StateTracker::GetInstance()->BeginRenderPass(); - StateTracker::GetInstance()->SetPendingRebind(); - Util::SetViewportAndScissor(command_buffer, 0, 0, GetEFBWidth(), GetEFBHeight()); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset); - vkCmdDraw(command_buffer, static_cast(vertex_count), 1, 0, 0); -} - -void FramebufferManager::CreatePokeVertexFormat() -{ - PortableVertexDeclaration vtx_decl = {}; - vtx_decl.position.enable = true; - vtx_decl.position.type = VAR_FLOAT; - vtx_decl.position.components = 4; - vtx_decl.position.integer = false; - vtx_decl.position.offset = offsetof(EFBPokeVertex, position); - vtx_decl.colors[0].enable = true; - vtx_decl.colors[0].type = VAR_UNSIGNED_BYTE; - vtx_decl.colors[0].components = 4; - vtx_decl.colors[0].integer = false; - vtx_decl.colors[0].offset = offsetof(EFBPokeVertex, color); - vtx_decl.stride = sizeof(EFBPokeVertex); - - m_poke_vertex_format = std::make_unique(vtx_decl); -} - -bool FramebufferManager::CreatePokeVertexBuffer() -{ - m_poke_vertex_stream_buffer = StreamBuffer::Create( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, POKE_VERTEX_BUFFER_SIZE, POKE_VERTEX_BUFFER_SIZE); - if (!m_poke_vertex_stream_buffer) - { - ERROR_LOG(VIDEO, "Failed to create EFB poke vertex buffer"); - return false; - } - - return true; -} - -void FramebufferManager::DestroyPokeVertexBuffer() -{ - m_poke_vertex_stream_buffer.reset(); -} - -bool FramebufferManager::CompilePokeShaders() -{ - static const char POKE_VERTEX_SHADER_SOURCE[] = R"( - layout(location = 0) in vec4 ipos; - layout(location = 5) in vec4 icol0; - - layout(location = 0) out vec4 col0; - - void main() - { - gl_Position = vec4(ipos.xyz, 1.0f); - #if USE_POINT_SIZE - gl_PointSize = ipos.w; - #endif - col0 = icol0; - } - - )"; - - static const char POKE_GEOMETRY_SHADER_SOURCE[] = R"( - layout(triangles) in; - layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out; - - VARYING_LOCATION(0) in VertexData - { - vec4 col0; - } in_data[]; - - VARYING_LOCATION(0) out VertexData - { - vec4 col0; - } out_data; - - void main() - { - for (int j = 0; j < EFB_LAYERS; j++) - { - for (int i = 0; i < 3; i++) - { - gl_Layer = j; - gl_Position = gl_in[i].gl_Position; - out_data.col0 = in_data[i].col0; - EmitVertex(); - } - EndPrimitive(); - } - } - )"; - - static const char POKE_PIXEL_SHADER_SOURCE[] = R"( - layout(location = 0) in vec4 col0; - layout(location = 0) out vec4 ocol0; - void main() - { - ocol0 = col0; - } - )"; - - std::string source = g_shader_cache->GetUtilityShaderHeader(); - if (m_poke_primitive == PrimitiveType::Points) - source += "#define USE_POINT_SIZE 1\n"; - source += POKE_VERTEX_SHADER_SOURCE; - m_poke_vertex_shader = Util::CompileAndCreateVertexShader(source); - if (m_poke_vertex_shader == VK_NULL_HANDLE) - return false; - - if (g_vulkan_context->SupportsGeometryShaders()) - { - source = g_shader_cache->GetUtilityShaderHeader() + POKE_GEOMETRY_SHADER_SOURCE; - m_poke_geometry_shader = Util::CompileAndCreateGeometryShader(source); - if (m_poke_geometry_shader == VK_NULL_HANDLE) - return false; - } - - source = g_shader_cache->GetUtilityShaderHeader() + POKE_PIXEL_SHADER_SOURCE; - m_poke_fragment_shader = Util::CompileAndCreateFragmentShader(source); - if (m_poke_fragment_shader == VK_NULL_HANDLE) - return false; - - return true; -} - -void FramebufferManager::DestroyPokeShaders() -{ - if (m_poke_vertex_shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_poke_vertex_shader, nullptr); - m_poke_vertex_shader = VK_NULL_HANDLE; - } - if (m_poke_geometry_shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_poke_geometry_shader, nullptr); - m_poke_geometry_shader = VK_NULL_HANDLE; - } - if (m_poke_fragment_shader != VK_NULL_HANDLE) - { - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_poke_fragment_shader, nullptr); - m_poke_vertex_shader = VK_NULL_HANDLE; - } -} - -} // namespace Vulkan -- cgit v1.2.3