From 09ae45c5667490bd42401dce3169904416f2b775 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 24 Jul 2016 19:28:49 +0300 Subject: [PATCH] vk: Conform to current spec (#1981) * vk: define rtt images with transfer_dst set * vk: Bind a buffer view for attribs with undefined data * vk: Properly define renderpass clip region to fit the framebuffer * vk: respect type bits from returned memory requirements --- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 52 ++++++++++------------------ rpcs3/Emu/RSX/VK/VKHelpers.h | 43 ++++++++++++++++++++--- rpcs3/Emu/RSX/VK/VKRenderTargets.h | 13 +++++-- rpcs3/Emu/RSX/VK/VKTextureCache.h | 2 +- rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp | 14 ++++++++ 5 files changed, 83 insertions(+), 41 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 322b54035a..3489b90112 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -475,12 +475,13 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) #define RING_BUFFER_SIZE 16 * 1024 * DESCRIPTOR_MAX_DRAW_CALLS + m_uniform_buffer_ring_info.init(RING_BUFFER_SIZE); - m_uniform_buffer_ring_info.heap.reset(new vk::buffer(*m_device, RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 0)); + m_uniform_buffer_ring_info.heap.reset(new vk::buffer(*m_device, RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 0)); m_index_buffer_ring_info.init(RING_BUFFER_SIZE); - m_index_buffer_ring_info.heap.reset(new vk::buffer(*m_device, RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 0)); + m_index_buffer_ring_info.heap.reset(new vk::buffer(*m_device, RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 0)); m_texture_upload_buffer_ring_info.init(8 * RING_BUFFER_SIZE); - m_texture_upload_buffer_ring_info.heap.reset(new vk::buffer(*m_device, 8 * RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0)); + m_texture_upload_buffer_ring_info.heap.reset(new vk::buffer(*m_device, 8 * RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0)); m_render_passes = get_precomputed_render_passes(*m_device, m_optimal_tiling_supported_formats); @@ -495,7 +496,7 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) descriptor_pool.create(*m_device, sizes.data(), static_cast(sizes.size())); - null_buffer = std::make_unique(*m_device, 32, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0); + null_buffer = std::make_unique(*m_device, 32, m_memory_type_mapping.host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0); null_buffer_view = std::make_unique(*m_device, null_buffer->value, VK_FORMAT_R32_SFLOAT, 0, 32); VkFenceCreateInfo fence_info = {}; @@ -613,27 +614,6 @@ void VKGSRender::begin() m_used_descriptors++; } -namespace -{ - bool normalize(rsx::vertex_base_type type) - { - switch (type) - { - case rsx::vertex_base_type::s1: - case rsx::vertex_base_type::ub: - case rsx::vertex_base_type::cmp: - return true; - case rsx::vertex_base_type::f: - case rsx::vertex_base_type::sf: - case rsx::vertex_base_type::ub256: - case rsx::vertex_base_type::s32k: - return false; - } - throw EXCEPTION("unknown vertex type"); - } -} - - void VKGSRender::end() { size_t idx = vk::get_render_pass_location( @@ -673,8 +653,8 @@ void VKGSRender::end() rp_begin.framebuffer = m_framebuffer_to_clean.back()->value; rp_begin.renderArea.offset.x = 0; rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_frame->client_width(); - rp_begin.renderArea.extent.height = m_frame->client_height(); + rp_begin.renderArea.extent.width = m_framebuffer_to_clean.back()->width(); + rp_begin.renderArea.extent.height = m_framebuffer_to_clean.back()->height(); vkCmdBeginRenderPass(m_command_buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); @@ -740,7 +720,7 @@ void VKGSRender::on_init_thread() { GSRender::on_init_thread(); m_attrib_ring_info.init(8 * RING_BUFFER_SIZE); - m_attrib_ring_info.heap.reset(new vk::buffer(*m_device, 8 * RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0)); + m_attrib_ring_info.heap.reset(new vk::buffer(*m_device, 8 * RING_BUFFER_SIZE, m_memory_type_mapping.host_visible_coherent, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0)); } void VKGSRender::on_exit() @@ -1076,14 +1056,18 @@ bool VKGSRender::load_program() m_uniform_buffer_ring_info.unmap(); const size_t fragment_constants_sz = m_prog_buffer.get_fragment_constants_buffer_size(fragment_program); - const size_t fragment_constants_offset = m_uniform_buffer_ring_info.alloc<256>(fragment_constants_sz); - buf = (u8*)m_uniform_buffer_ring_info.map(fragment_constants_offset, fragment_constants_sz); - m_prog_buffer.fill_fragment_constans_buffer({ reinterpret_cast(buf), gsl::narrow(fragment_constants_sz) }, fragment_program); - m_uniform_buffer_ring_info.unmap(); + const size_t fragment_constants_offset = m_uniform_buffer_ring_info.alloc<256>(std::max(fragment_constants_sz, static_cast(32))); + + if (fragment_constants_sz) + { + buf = (u8*)m_uniform_buffer_ring_info.map(fragment_constants_offset, fragment_constants_sz); + m_prog_buffer.fill_fragment_constans_buffer({ reinterpret_cast(buf), gsl::narrow(fragment_constants_sz) }, fragment_program); + m_uniform_buffer_ring_info.unmap(); + } m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, scale_offset_offset, 256 }, SCALE_OFFSET_BIND_SLOT, descriptor_sets); - m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, vertex_constants_offset, 512 * 4 * sizeof(float) }, VERTEX_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); - m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, fragment_constants_offset, fragment_constants_sz }, FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); + m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, vertex_constants_offset, 512 * 4 * sizeof(float) }, VERTEX_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); + m_program->bind_uniform({ m_uniform_buffer_ring_info.heap->value, fragment_constants_offset, (fragment_constants_sz? fragment_constants_sz: 32) }, FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT, descriptor_sets); return true; } diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 25d76eac43..e44ae1a4d0 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -338,7 +338,9 @@ namespace vk VkImageCreateInfo info = {}; std::shared_ptr memory; - image(VkDevice dev, uint32_t memory_type_index, + image(vk::render_device &dev, + uint32_t memory_type_index, + uint32_t access_flags, VkImageType image_type, VkFormat format, uint32_t width, uint32_t height, uint32_t depth, @@ -367,8 +369,16 @@ namespace vk VkMemoryRequirements memory_req; vkGetImageMemoryRequirements(m_device, value, &memory_req); - memory = std::make_shared(m_device, memory_req.size, memory_type_index); + + if (!(memory_req.memoryTypeBits & (1 << memory_type_index))) + { + //Suggested memory type is incompatible with this memory type. + //Go through the bitset and test for requested props. + if (!dev.get_compatible_memory_type(memory_req.memoryTypeBits, access_flags, &memory_type_index)) + throw EXCEPTION("No compatible memory type was found!"); + } + memory = std::make_shared(m_device, memory_req.size, memory_type_index); CHECK_RESULT(vkBindImageMemory(m_device, value, memory->memory, 0)); } @@ -472,7 +482,7 @@ namespace vk VkBufferCreateInfo info = {}; std::unique_ptr memory; - buffer(VkDevice dev, u64 size, uint32_t memory_type_index, VkBufferUsageFlagBits usage, VkBufferCreateFlags flags) + buffer(vk::render_device& dev, u64 size, uint32_t memory_type_index, uint32_t access_flags, VkBufferUsageFlagBits usage, VkBufferCreateFlags flags) : m_device(dev) { info.size = size; @@ -483,9 +493,18 @@ namespace vk CHECK_RESULT(vkCreateBuffer(m_device, &info, nullptr, &value)); - VkMemoryRequirements memory_reqs; //Allocate vram for this buffer + VkMemoryRequirements memory_reqs; vkGetBufferMemoryRequirements(m_device, value, &memory_reqs); + + if (!(memory_reqs.memoryTypeBits & (1 << memory_type_index))) + { + //Suggested memory type is incompatible with this memory type. + //Go through the bitset and test for requested props. + if (!dev.get_compatible_memory_type(memory_reqs.memoryTypeBits, access_flags, &memory_type_index)) + throw EXCEPTION("No compatible memory type was found!"); + } + memory.reset(new memory_block(m_device, memory_reqs.size, memory_type_index)); vkBindBufferMemory(dev, value, memory->memory, 0); } @@ -589,6 +608,9 @@ namespace vk VkFramebuffer value; VkFramebufferCreateInfo info = {}; std::vector> attachements; + u32 m_width = 0; + u32 m_height = 0; + public: framebuffer(VkDevice dev, VkRenderPass pass, u32 width, u32 height, std::vector> &&atts) : m_device(dev), attachements(std::move(atts)) @@ -608,6 +630,9 @@ namespace vk info.renderPass = pass; info.layers = 1; + m_width = width; + m_height = height; + CHECK_RESULT(vkCreateFramebuffer(dev, &info, nullptr, &value)); } @@ -616,6 +641,16 @@ namespace vk vkDestroyFramebuffer(m_device, value, nullptr); } + u32 width() + { + return m_width; + } + + u32 height() + { + return m_height; + } + framebuffer(const framebuffer&) = delete; framebuffer(framebuffer&&) = delete; diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index 56dfde49d6..9add90be66 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -22,13 +22,14 @@ namespace rsx std::unique_ptr rtt; rtt.reset(new vk::image(device, mem_mapping.device_local, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_IMAGE_TYPE_2D, requested_format, static_cast(width), static_cast(height), 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT, 0)); change_image_layout(*cmd, rtt->value, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); //Clear new surface @@ -57,7 +58,15 @@ namespace rsx std::unique_ptr ds; ds.reset(new vk::image(device, mem_mapping.device_local, - VK_IMAGE_TYPE_2D, requested_format, static_cast(width), static_cast(height), 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT, 0)); + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VK_IMAGE_TYPE_2D, + requested_format, + static_cast(width), static_cast(height), 1, 1, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0)); + change_image_layout(*cmd, ds->value, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, range); //Clear new surface.. diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 29d447b172..45304825a4 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -229,7 +229,7 @@ namespace vk bool is_cubemap = tex.get_extended_texture_dimension() == rsx::texture_dimension_extended::texture_dimension_cubemap; VkImageSubresourceRange subresource_range = vk::get_image_subresource_range(0, 0, is_cubemap ? 6 : 1, tex.get_exact_mipmap_count(), VK_IMAGE_ASPECT_COLOR_BIT); - cto.uploaded_texture = std::make_unique(*vk::get_current_renderer(), memory_type_mapping.device_local, + cto.uploaded_texture = std::make_unique(*vk::get_current_renderer(), memory_type_mapping.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image_type, vk_format, tex.width(), height, depth, tex.get_exact_mipmap_count(), layer, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 94555ff16a..2e851f43d7 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -549,6 +549,20 @@ VKGSRender::upload_vertex_data() break; } } + else + { + //This section should theoretically be unreachable (data stream without available data) + //Variable is defined in the shaders but no data is available + //Bind a buffer view to keep the driver from crashing if access is attempted. + + u32 offset_in_attrib_buffer = m_attrib_ring_info.alloc<256>(32); + void *dst = m_attrib_ring_info.map(offset_in_attrib_buffer, 32); + memset(dst, 0, 32); + m_attrib_ring_info.unmap(); + + m_buffer_view_to_clean.push_back(std::make_unique(*m_device, m_attrib_ring_info.heap->value, VK_FORMAT_R32_SFLOAT, offset_in_attrib_buffer, 32)); + m_program->bind_uniform(m_buffer_view_to_clean.back()->value, reg_table[index], descriptor_sets); + } } }