diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 36102bac31..a50a0f6f7f 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -116,7 +116,7 @@ namespace gl glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(depth_target ? GL_TRUE : GL_FALSE); - // AMD driver bug, disabling depth test doesnt work when doing depth replace (gl_FragDepth writes still go through the depth test) + // Disabling depth test will also disable depth writes which is not desired glDepthFunc(GL_ALWAYS); glEnable(GL_DEPTH_TEST); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 5eeaa498a8..de88e7dbe2 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1417,6 +1417,16 @@ namespace rsx } result.set_texture_dimension(texture_dimensions); + + //Sanity checks + if (result.ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) + { + //Check that the depth stage is not disabled + if (!rsx::method_registers.depth_test_enabled()) + { + LOG_ERROR(RSX, "FS exports depth component but depth test is disabled (INVALID_OPERATION)"); + } + } } void thread::get_current_fragment_program_legacy(std::function(u32, fragment_texture&, bool)> get_surface_info) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 7045063d53..588812a07e 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -644,6 +644,9 @@ VKGSRender::VKGSRender() : GSRender() m_text_writer->init(*m_device, m_memory_type_mapping, m_render_passes[idx]); } + m_depth_converter.reset(new vk::depth_convert_pass()); + m_depth_converter->create(*m_device); + m_prog_buffer.reset(new VKProgramBuffer(m_render_passes.data())); if (g_cfg.video.disable_vertex_cache) @@ -754,6 +757,10 @@ VKGSRender::~VKGSRender() //Overlay text handler m_text_writer.reset(); + //RGBA->depth cast helper + m_depth_converter->destroy(); + m_depth_converter.reset(); + //Pipeline descriptors vkDestroyPipelineLayout(*m_device, pipeline_layout, nullptr); vkDestroyDescriptorSetLayout(*m_device, descriptor_layouts, nullptr); @@ -1246,6 +1253,96 @@ void VKGSRender::end() std::chrono::time_point program_stop = steady_clock::now(); m_setup_time += std::chrono::duration_cast(program_stop - program_start).count(); + textures_start = program_stop; + + for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) + { + if (m_program->has_uniform("tex" + std::to_string(i))) + { + if (!rsx::method_registers.fragment_textures[i].enabled()) + { + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); + continue; + } + + auto sampler_state = static_cast(fs_sampler_state[i].get()); + auto image_ptr = sampler_state->image_handle; + + if (!image_ptr && sampler_state->external_subresource_desc.external_handle) + { + //Requires update, copy subresource + image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); + } + + if (!image_ptr) + { + LOG_ERROR(RSX, "Texture upload failed to texture index %d. Binding null sampler.", i); + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); + continue; + } + + m_program->bind_uniform({ fs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); + } + } + + for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) + { + if (m_program->has_uniform("vtex" + std::to_string(i))) + { + if (!rsx::method_registers.vertex_textures[i].enabled()) + { + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); + continue; + } + + auto sampler_state = static_cast(vs_sampler_state[i].get()); + auto image_ptr = sampler_state->image_handle; + + if (!image_ptr && sampler_state->external_subresource_desc.external_handle) + { + image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); + m_vertex_textures_dirty[i] = true; + } + + if (!image_ptr) + { + LOG_ERROR(RSX, "Texture upload failed to vtexture index %d. Binding null sampler.", i); + m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); + continue; + } + + m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); + } + } + + textures_end = steady_clock::now(); + m_textures_upload_time += std::chrono::duration_cast(textures_end - textures_start).count(); + + //While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point + //Only textures are synchronized tightly with the GPU and they have been read back above + vk::enter_uninterruptible(); + + auto ds = std::get<1>(m_rtts.m_bound_depth_stencil); + + //Check for data casts + if (ds && ds->old_contents) + { + if (ds->old_contents->info.format == VK_FORMAT_B8G8R8A8_UNORM) + { + auto rp = vk::get_render_pass_location(VK_FORMAT_UNDEFINED, ds->info.format, 0); + auto render_pass = m_render_passes[rp]; + m_depth_converter->run(*m_current_command_buffer, ds->width(), ds->height(), ds, ds->old_contents->get_view(), render_pass, m_framebuffers_to_clean); + + ds->old_contents = nullptr; + ds->dirty = false; + } + else if (!g_cfg.video.strict_rendering_mode) + { + //Clear this to avoid dereferencing stale ptr + ds->old_contents = nullptr; + } + } + if (g_cfg.video.strict_rendering_mode) { auto copy_rtt_contents = [&](vk::render_target* surface) @@ -1295,82 +1392,12 @@ void VKGSRender::end() } } - if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) + if (ds && ds->old_contents) { - if (ds->old_contents != nullptr) - copy_rtt_contents(ds); + copy_rtt_contents(ds); } } - textures_start = steady_clock::now(); - - for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) - { - if (m_program->has_uniform("tex" + std::to_string(i))) - { - if (!rsx::method_registers.fragment_textures[i].enabled()) - { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); - continue; - } - - auto sampler_state = static_cast(fs_sampler_state[i].get()); - auto image_ptr = sampler_state->image_handle; - - if (!image_ptr && sampler_state->external_subresource_desc.external_handle) - { - //Requires update, copy subresource - image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); - } - - if (!image_ptr) - { - LOG_ERROR(RSX, "Texture upload failed to texture index %d. Binding null sampler.", i); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); - continue; - } - - m_program->bind_uniform({ fs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "tex" + std::to_string(i), m_current_frame->descriptor_set); - } - } - - for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) - { - if (m_program->has_uniform("vtex" + std::to_string(i))) - { - if (!rsx::method_registers.vertex_textures[i].enabled()) - { - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); - continue; - } - - auto sampler_state = static_cast(vs_sampler_state[i].get()); - auto image_ptr = sampler_state->image_handle; - - if (!image_ptr && sampler_state->external_subresource_desc.external_handle) - { - image_ptr = m_texture_cache.create_temporary_subresource(*m_current_command_buffer, sampler_state->external_subresource_desc); - m_vertex_textures_dirty[i] = true; - } - - if (!image_ptr) - { - LOG_ERROR(RSX, "Texture upload failed to vtexture index %d. Binding null sampler.", i); - m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); - continue; - } - - m_program->bind_uniform({ vs_sampler_handles[i]->value, image_ptr->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, "vtex" + std::to_string(i), m_current_frame->descriptor_set); - } - } - - textures_end = steady_clock::now(); - m_textures_upload_time += std::chrono::duration_cast(textures_end - textures_start).count(); - - //While vertex upload is an interruptible process, if we made it this far, there's no need to sync anything that occurs past this point - //Only textures are synchronized tightly with the GPU and they have been read back above - vk::enter_uninterruptible(); - update_draw_state(); begin_render_pass(); @@ -1383,20 +1410,17 @@ void VKGSRender::end() buffers_to_clear.reserve(4); const auto targets = rsx::utility::get_rtt_indexes(rsx::method_registers.surface_color_target()); - if (auto ds = std::get<1>(m_rtts.m_bound_depth_stencil)) + if (ds && ds->dirty) { - if (ds->dirty) - { - //Clear this surface before drawing on it - VkClearValue depth_clear_value; - depth_clear_value.depthStencil.depth = 1.f; - depth_clear_value.depthStencil.stencil = 255; + //Clear this surface before drawing on it + VkClearValue depth_clear_value; + depth_clear_value.depthStencil.depth = 1.f; + depth_clear_value.depthStencil.stencil = 255; - VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value }; - buffers_to_clear.push_back(clear_desc); + VkClearAttachment clear_desc = { ds->attachment_aspect_flag, 0, depth_clear_value }; + buffers_to_clear.push_back(clear_desc); - ds->dirty = false; - } + ds->dirty = false; } for (int index = 0; index < targets.size(); ++index) @@ -1939,6 +1963,8 @@ void VKGSRender::process_swap_request(frame_context_t *ctx, bool free_resources) m_text_writer->reset_descriptors(); } + m_depth_converter->free_resources(); + ctx->buffer_views_to_clean.clear(); ctx->samplers_to_clean.clear(); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index fe0981bd39..e7e054f85a 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -5,6 +5,7 @@ #include "VKRenderTargets.h" #include "VKFormats.h" #include "VKTextOut.h" +#include "VKOverlays.h" #include "restore_new.h" #include "define_new_memleakdetect.h" #include "VKProgramBuffer.h" @@ -134,6 +135,7 @@ private: std::unique_ptr null_buffer_view; std::unique_ptr m_text_writer; + std::unique_ptr m_depth_converter; std::mutex m_sampler_mutex; u64 surface_store_tag = 0; diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 8cc2a4b890..537f9f2119 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -2,11 +2,348 @@ #include "VKHelpers.h" #include "VKVertexProgram.h" #include "VKFragmentProgram.h" +#include "VKRenderTargets.h" namespace vk { + //TODO: Refactor text print class to inherit from this base class struct overlay_pass { - //TODO + VKVertexProgram m_vertex_shader; + VKFragmentProgram m_fragment_shader; + + vk::descriptor_pool m_descriptor_pool; + VkDescriptorSet m_descriptor_set = nullptr; + VkDescriptorSetLayout m_descriptor_layout = nullptr; + VkPipelineLayout m_pipeline_layout = nullptr; + u32 m_used_descriptors = 0; + + std::unordered_map> m_program_cache; + std::unique_ptr m_sampler; + std::unique_ptr m_draw_fbo; + vk::render_device* m_device = nullptr; + + std::string vs_src; + std::string fs_src; + + struct + { + int color_attachments = 0; + bool write_color = true; + bool write_depth = true; + bool no_depth_test = true; + } + renderpass_config; + + bool initialized = false; + bool compiled = false; + + void init_descriptors() + { + VkDescriptorPoolSize descriptor_pools[1] = + { + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 120 }, + }; + + //Reserve descriptor pools + m_descriptor_pool.create(*m_device, descriptor_pools, 1); + + VkDescriptorSetLayoutBinding bindings[1] = {}; + + bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[0].descriptorCount = 1; + bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + bindings[0].binding = 0; + + VkDescriptorSetLayoutCreateInfo infos = {}; + infos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + infos.pBindings = bindings; + infos.bindingCount = 1; + + CHECK_RESULT(vkCreateDescriptorSetLayout(*m_device, &infos, nullptr, &m_descriptor_layout)); + + VkPipelineLayoutCreateInfo layout_info = {}; + layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &m_descriptor_layout; + + CHECK_RESULT(vkCreatePipelineLayout(*m_device, &layout_info, nullptr, &m_pipeline_layout)); + } + + vk::glsl::program* build_pipeline(VkRenderPass render_pass) + { + if (!compiled) + { + m_vertex_shader.shader = vs_src; + m_vertex_shader.Compile(); + + m_fragment_shader.shader = fs_src; + m_fragment_shader.Compile(); + + compiled = true; + } + + VkPipelineShaderStageCreateInfo shader_stages[2] = {}; + shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_stages[0].module = m_vertex_shader.handle; + shader_stages[0].pName = "main"; + + shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].module = m_fragment_shader.handle; + shader_stages[1].pName = "main"; + + VkDynamicState dynamic_state_descriptors[VK_DYNAMIC_STATE_RANGE_SIZE] = {}; + VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; + dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_descriptors[dynamic_state_info.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; + dynamic_state_descriptors[dynamic_state_info.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; + dynamic_state_info.pDynamicStates = dynamic_state_descriptors; + + VkPipelineVertexInputStateCreateInfo vi = {}; + vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + VkPipelineViewportStateCreateInfo vp = {}; + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.scissorCount = 1; + vp.viewportCount = 1; + + VkPipelineMultisampleStateCreateInfo ms = {}; + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.pSampleMask = NULL; + ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineInputAssemblyStateCreateInfo ia = {}; + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + + VkPipelineRasterizationStateCreateInfo rs = {}; + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.lineWidth = 1.f; + rs.polygonMode = VK_POLYGON_MODE_FILL; + + VkPipelineColorBlendAttachmentState att = {}; + if (renderpass_config.write_color) + att.colorWriteMask = 0xf; + + VkPipelineColorBlendStateCreateInfo cs = {}; + cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + cs.attachmentCount = renderpass_config.color_attachments; + cs.pAttachments = &att; + + VkPipelineDepthStencilStateCreateInfo ds = {}; + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.depthWriteEnable = renderpass_config.write_depth? VK_TRUE: VK_FALSE; + ds.depthTestEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_ALWAYS; + + VkPipeline pipeline; + VkGraphicsPipelineCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.pVertexInputState = &vi; + info.pInputAssemblyState = &ia; + info.pRasterizationState = &rs; + info.pColorBlendState = &cs; + info.pMultisampleState = &ms; + info.pViewportState = &vp; + info.pDepthStencilState = &ds; + info.stageCount = 2; + info.pStages = shader_stages; + info.pDynamicState = &dynamic_state_info; + info.layout = m_pipeline_layout; + info.basePipelineIndex = -1; + info.basePipelineHandle = VK_NULL_HANDLE; + info.renderPass = render_pass; + + CHECK_RESULT(vkCreateGraphicsPipelines(*m_device, nullptr, 1, &info, NULL, &pipeline)); + + const std::vector unused; + std::vector fs_inputs; + fs_inputs.push_back({ ::glsl::program_domain::glsl_fragment_program, vk::glsl::program_input_type::input_type_texture, {}, {}, 0, "fs0"}); + auto program = std::make_unique(*m_device, pipeline, unused, fs_inputs); + auto result = program.get(); + m_program_cache[render_pass] = std::move(program); + + return result; + } + + void load_program(vk::command_buffer cmd, VkRenderPass pass, vk::image_view *src) + { + vk::glsl::program *program = nullptr; + auto found = m_program_cache.find(pass); + if (found != m_program_cache.end()) + program = found->second.get(); + else + program = build_pipeline(pass); + + verify(HERE), m_used_descriptors < 120; + + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.descriptorPool = m_descriptor_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &m_descriptor_layout; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + + CHECK_RESULT(vkAllocateDescriptorSets(*m_device, &alloc_info, &m_descriptor_set)); + m_used_descriptors++; + + if (!m_sampler) + { + m_sampler = std::make_unique(*m_device, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + VK_FALSE, 0.f, 1.f, 0.f, 0.f, VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); + } + + VkDescriptorImageInfo info = { m_sampler->value, src->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + program->bind_uniform(info, "fs0", m_descriptor_set); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, program->pipeline); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, &m_descriptor_set, 0, nullptr); + } + + void create(vk::render_device &dev) + { + if (!initialized) + { + m_device = &dev; + init_descriptors(); + + initialized = true; + } + } + + void destroy() + { + if (initialized) + { + m_program_cache.clear(); + m_sampler.reset(); + + vkDestroyDescriptorSetLayout(*m_device, m_descriptor_layout, nullptr); + vkDestroyPipelineLayout(*m_device, m_pipeline_layout, nullptr); + m_descriptor_pool.destroy(); + + initialized = false; + } + } + + void free_resources() + { + if (m_used_descriptors == 0) + return; + + vkResetDescriptorPool(*m_device, m_descriptor_pool, 0); + m_used_descriptors = 0; + } + + vk::framebuffer* get_framebuffer(vk::image* target, VkRenderPass render_pass, std::list>& framebuffer_resources) + { + std::vector test = {target}; + for (auto It = framebuffer_resources.begin(); It != framebuffer_resources.end(); It++) + { + auto fbo = It->get(); + if (fbo->matches(test, target->width(), target->height())) + { + fbo->deref_count = 0; + return fbo; + } + } + + //No match, create new fbo and add to the list + std::vector> views; + VkComponentMapping mapping = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + + switch (target->info.format) + { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; //We are only writing to depth + break; + } + + auto view = std::make_unique(*m_device, target->value, VK_IMAGE_VIEW_TYPE_2D, target->info.format, mapping, range); + views.push_back(std::move(view)); + + auto fbo = std::make_unique(*m_device, render_pass, target->width(), target->height(), std::move(views)); + auto result = fbo.get(); + framebuffer_resources.push_back(std::move(fbo)); + + return result; + } + + void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, vk::image_view* src, VkRenderPass render_pass, std::list>& framebuffer_resources) + { + vk::framebuffer *fbo = get_framebuffer(target, render_pass, framebuffer_resources); + + VkViewport vp{}; + vp.width = (f32)w; + vp.height = (f32)h; + vp.minDepth = 0.f; + vp.maxDepth = 1.f; + vkCmdSetViewport(cmd, 0, 1, &vp); + + VkRect2D vs = { { 0, 0 },{ 0u + w, 0u + h } }; + vkCmdSetScissor(cmd, 0, 1, &vs); + + load_program(cmd, render_pass, src); + + VkRenderPassBeginInfo rp_begin = {}; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.renderPass = render_pass; + rp_begin.framebuffer = fbo->value; + rp_begin.renderArea.offset.x = 0; + rp_begin.renderArea.offset.y = 0; + rp_begin.renderArea.extent.width = w; + rp_begin.renderArea.extent.height = h; + + vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + vkCmdDraw(cmd, 4, 1, 0, 0); + vkCmdEndRenderPass(cmd); + } + }; + + struct depth_convert_pass : public overlay_pass + { + depth_convert_pass() + { + vs_src = + { + "#version 450\n" + "#extension GL_ARB_separate_shader_objects : enable\n" + "layout(location=0) out vec2 tc0;\n" + "\n" + "void main()\n" + "{\n" + " vec2 positions[] = {vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)};\n" + " vec2 coords[] = {vec2(0., 0.), vec2(1., 0.), vec2(0., 1.), vec2(1., 1.)};\n" + " gl_Position = vec4(positions[gl_VertexIndex % 4], 0., 1.);\n" + " tc0 = coords[gl_VertexIndex % 4];\n" + "}\n" + }; + + fs_src = + { + "#version 420\n" + "#extension GL_ARB_separate_shader_objects : enable\n" + "layout(set=0, binding=0) uniform sampler2D fs0;\n" + "layout(location=0) in vec2 tc0;\n" + "\n" + "void main()\n" + "{\n" + " vec4 rgba_in = texture(fs0, tc0);\n" + " uint raw_value = uint(rgba_in.b * 255.) | (uint(rgba_in.g * 255.) << 8) | (uint(rgba_in.r * 255.) << 16);\n" + " gl_FragDepth = float(raw_value) / 16777215.;\n" + " //gl_FragDepth = rgba_in.r * 0.99609 + rgba_in.g * 0.00389 + rgba_in.b * 0.00002;\n" + "}\n" + }; + + renderpass_config.write_color = false; + + m_vertex_shader.id = 100002; + m_fragment_shader.id = 100003; + } }; } diff --git a/rpcs3/Emu/RSX/VK/VKTextOut.h b/rpcs3/Emu/RSX/VK/VKTextOut.h index aba9dea317..eb8bee4188 100644 --- a/rpcs3/Emu/RSX/VK/VKTextOut.h +++ b/rpcs3/Emu/RSX/VK/VKTextOut.h @@ -103,9 +103,11 @@ namespace vk }; m_vertex_shader.shader = vs; + m_vertex_shader.id = 100000; m_vertex_shader.Compile(); m_fragment_shader.shader = fs; + m_fragment_shader.id = 100001; m_fragment_shader.Compile(); VkPipelineShaderStageCreateInfo shader_stages[2] = {};