diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 0c4f5b2406..13124c2f56 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -204,7 +204,7 @@ namespace rsx std::vector& subresource_layout, const rsx::texture_dimension_extended type, const bool swizzled, std::pair, std::array>& remap_vector) = 0; virtual void enforce_surface_creation_type(section_storage_type& section, const texture_create_flags expected) = 0; virtual void insert_texture_barrier() = 0; - virtual image_view_type generate_cubemap_from_images(commandbuffer_type&, std::array& sources) = 0; + virtual image_view_type generate_cubemap_from_images(commandbuffer_type&, const u32 gcm_format, u16 size, std::array& sources) = 0; constexpr u32 get_block_size() const { return 0x1000000; } inline u32 get_block_address(u32 address) const { return (address & ~0xFFFFFF); } @@ -229,11 +229,13 @@ namespace rsx struct deferred_subresource { image_resource_type external_handle = 0; + std::array external_cubemap_sources; u32 gcm_format = 0; u16 x = 0; u16 y = 0; u16 width = 0; u16 height = 0; + bool is_cubemap = false; deferred_subresource() {} @@ -246,7 +248,7 @@ namespace rsx struct sampled_image_descriptor : public sampled_image_descriptor_base { image_view_type image_handle = 0; - deferred_subresource external_subresource_desc; + deferred_subresource external_subresource_desc = {}; bool flag = false; sampled_image_descriptor() @@ -274,6 +276,12 @@ namespace rsx scale_y = y_scale; image_type = type; } + + void set_external_cubemap_resources(std::array images) + { + external_subresource_desc.external_cubemap_sources = images; + external_subresource_desc.is_cubemap = true; + } }; private: @@ -990,15 +998,65 @@ namespace rsx sampled_image_descriptor process_framebuffer_resource(render_target_type texptr, const u32 texaddr, const u32 gcm_format, surface_store_type& m_rtts, const u16 tex_width, const u16 tex_height, const rsx::texture_dimension_extended extended_dimension, const bool is_depth) { + const u32 format = gcm_format & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); + const auto surface_width = texptr->get_surface_width(); + const auto surface_height = texptr->get_surface_height(); + if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d && extended_dimension != rsx::texture_dimension_extended::texture_dimension_1d) { + if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_cubemap) + { + if (surface_height == (surface_width * 6)) + { + //TODO: Unwrap long RTT block into 6 images and generate cubemap from them + LOG_ERROR(RSX, "Unwrapping block rtt to cubemap is unimplemented!"); + return{}; + } + + std::array image_array; + image_array[0] = texptr->get_surface(); + bool can_cast = true; + + u32 image_size = texptr->get_rsx_pitch() * texptr->get_surface_height(); + u32 image_address = texaddr + image_size; + + for (int n = 1; n < 6; ++n) + { + render_target_type img = nullptr; + if (!!(img = m_rtts.get_texture_from_render_target_if_applicable(image_address)) || + !!(img = m_rtts.get_texture_from_depth_stencil_if_applicable(image_address))) + { + if (img->get_surface_width() != surface_width || + img->get_surface_width() != img->get_surface_height()) + { + can_cast = false; + break; + } + + image_address += image_size; + image_array[n] = img->get_surface(); + } + else + { + can_cast = false; + break; + } + } + + if (can_cast) + { + sampled_image_descriptor desc = { texptr->get_surface(), format, 0, 0, surface_width, surface_height, texture_upload_context::framebuffer_storage, + is_depth, 1.f, 1.f, rsx::texture_dimension_extended::texture_dimension_cubemap }; + + desc.set_external_cubemap_resources(image_array); + return desc; + } + } + LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension); } - const auto surface_width = texptr->get_surface_width(); - const auto surface_height = texptr->get_surface_height(); - u32 internal_width = tex_width; u32 internal_height = tex_height; get_native_dimensions(internal_width, internal_height, texptr); @@ -1025,10 +1083,9 @@ namespace rsx texptr->aa_mode = aa_mode; } - const u32 format = gcm_format & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); const bool unnormalized = (gcm_format & CELL_GCM_TEXTURE_UN) != 0; - f32 scale_x = (unnormalized)? get_internal_scaling_x(texptr) : 1.f; - f32 scale_y = (unnormalized)? get_internal_scaling_y(texptr) : 1.f; + f32 scale_x = (unnormalized)? (1.f / tex_width) : 1.f; + f32 scale_y = (unnormalized)? (1.f / tex_height) : 1.f; if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d) { @@ -1188,8 +1245,8 @@ namespace rsx else { const bool unnormalized = (tex.format() & CELL_GCM_TEXTURE_UN) != 0; - f32 scale_x = (unnormalized)? get_internal_scaling_x(rsc.surface) : 1.f; - f32 scale_y = (unnormalized)? get_internal_scaling_x(rsc.surface) : 1.f; + f32 scale_x = (unnormalized)? (1.f / tex_width) : 1.f; + f32 scale_y = (unnormalized)? (1.f / tex_height) : 1.f; u16 internal_height = rsx::apply_resolution_scale(rsc.h, true); if (extended_dimension == rsx::texture_dimension_extended::texture_dimension_1d) diff --git a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp index 5e3167b960..f8eb4de782 100644 --- a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.cpp @@ -37,13 +37,13 @@ namespace gl case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD: return "textureGrad($t, $0.x, $1.x, $2.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D: - return "texture($t, $0.xy * $t_coord_scale)"; + return "texture($t, $0.xy * texture_parameters[$_i].xy)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ: return "textureProj($t, $0 , $1.x)"; // Note: $1.x is bias case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD: - return "textureLod($t, $0.xy * $t_coord_scale, $1.x)"; + return "textureLod($t, $0.xy * texture_parameters[$_i].xy, $1.x)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD: - return "textureGrad($t, $0.xy * $t_coord_scale , $1.xy, $2.xy)"; + return "textureGrad($t, $0.xy * texture_parameters[$_i].xy , $1.xy, $2.xy)"; case FUNCTION::FUNCTION_TEXTURE_SHADOW2D: return "texture($t, $0.xyz)"; case FUNCTION::FUNCTION_TEXTURE_SHADOW2D_PROJ: @@ -71,7 +71,7 @@ namespace gl case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D: return "textureLod($t, $0.xy, 0)"; case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA: - return "texture2DReconstruct($t, $0.xy * $t_coord_scale)"; + return "texture2DReconstruct($t, $0.xy * texture_parameters[$_i].xy)"; } } diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index a83d138184..4e7dce671a 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -173,11 +173,6 @@ namespace case rsx::texture_dimension_extended::texture_dimension_3d: case rsx::texture_dimension_extended::texture_dimension_cubemap: vec_type = "vec3"; } - - if (prog.unnormalized_coords & (1 << index)) - OS << "\t" << vec_type << " tex" << index << "_coord_scale = texture_parameters[" << index << "].xy / textureSize(tex" << index << ", 0);\n"; - else - OS << "\t" << vec_type << " tex" << index << "_coord_scale = texture_parameters[" << index << "].xy;\n"; } std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index b9e5be8c99..ddf142cc06 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -945,6 +945,7 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count) auto &vertex_program = current_vertex_program; vertex_program.skip_vertex_input_check = true; //not needed for us since decoding is done server side + fragment_program.unnormalized_coords = 0; //unused void* pipeline_properties = nullptr; m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, pipeline_properties); diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 93413355df..412e215f0c 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -645,9 +645,38 @@ namespace gl } } - u32 generate_cubemap_from_images(void*&, std::array& sources) override + u32 generate_cubemap_from_images(void*&, const u32 gcm_format, u16 size, std::array& sources) override { - return 0; + const GLenum ifmt = gl::get_sized_internal_format(gcm_format); + GLuint dst_id = 0; + + glGenTextures(1, &dst_id); + glBindTexture(GL_TEXTURE_CUBE_MAP, dst_id); + glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, ifmt, size, size); + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + + //Empty GL_ERROR + glGetError(); + + for (int i = 0; i < 6; ++i) + { + glCopyImageSubData(sources[i], GL_TEXTURE_2D, 0, 0, 0, 0, + dst_id, GL_TEXTURE_CUBE_MAP, 0, 0, 0, i, size, size, 1); + } + + m_temporary_surfaces.push_back(dst_id); + + if (GLenum err = glGetError()) + { + LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err); + return 0; + } + + return dst_id; } cached_texture_section* create_new_texture(void*&, u32 rsx_address, u32 rsx_size, u16 width, u16 height, u16 depth, u16 mipmaps, const u32 gcm_format, @@ -755,7 +784,10 @@ namespace gl inline u32 create_temporary_subresource(deferred_subresource& desc) { void* unused = nullptr; - return create_temporary_subresource_view(unused, &desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height); + if (!desc.is_cubemap) + return create_temporary_subresource_view(unused, &desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height); + else + return generate_cubemap_from_images(unused, desc.gcm_format, desc.width, desc.external_cubemap_sources); } bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index df79b9a547..7e9f88ff18 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1353,8 +1353,8 @@ namespace rsx for (u32 i = 0; i < rsx::limits::fragment_textures_count; ++i) { auto &tex = rsx::method_registers.fragment_textures[i]; - result.texture_scale[i][0] = 1.f; - result.texture_scale[i][1] = 1.f; + result.texture_scale[i][0] = sampler_descriptors[i]->scale_x; + result.texture_scale[i][1] = sampler_descriptors[i]->scale_y; result.textures_alpha_kill[i] = 0; result.textures_zfunc[i] = 0; @@ -1383,18 +1383,6 @@ namespace rsx if (raw_format & CELL_GCM_TEXTURE_UN) result.unnormalized_coords |= (1 << i); - if (sampler_descriptors[i]->upload_context == rsx::texture_upload_context::framebuffer_storage && - raw_format & CELL_GCM_TEXTURE_UN) - { - result.texture_scale[i][0] = (resolution_scale * sampler_descriptors[i]->scale_x); - result.texture_scale[i][1] = (resolution_scale * sampler_descriptors[i]->scale_y); - } - else - { - result.texture_scale[i][0] = sampler_descriptors[i]->scale_x; - result.texture_scale[i][1] = sampler_descriptors[i]->scale_y; - } - if (sampler_descriptors[i]->is_depth_texture) { const u32 format = raw_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index 84b7a60159..6ca7cd0b0f 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -118,11 +118,7 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS) const auto mask = (1 << index); - if (m_prog.unnormalized_coords & mask) - { - samplerType = "sampler2DRect"; - } - else if (m_prog.shadow_textures & mask) + if (m_prog.shadow_textures & mask) { if (m_shadow_sampled_textures & mask) { diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 9f1aac9bc5..9bf89d4726 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1085,7 +1085,6 @@ void VKGSRender::end() const auto wrap_s = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_s()); const auto wrap_t = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_t()); const auto wrap_r = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_r()); - const auto unnormalized_coords = !!(rsx::method_registers.fragment_textures[i].format() & CELL_GCM_TEXTURE_UN); const auto mag_filter = vk::get_mag_filter(rsx::method_registers.fragment_textures[i].mag_filter()); const auto border_color = vk::get_border_color(rsx::method_registers.fragment_textures[i].border_color()); @@ -1104,7 +1103,7 @@ void VKGSRender::end() if (fs_sampler_handles[i]) { - if (!fs_sampler_handles[i]->matches(wrap_s, wrap_t, wrap_r, unnormalized_coords, lod_bias, af_level, min_lod, max_lod, + if (!fs_sampler_handles[i]->matches(wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod, min_filter, mag_filter, mip_mode, border_color, fs_sampler_state[i]->is_depth_texture, depth_compare)) { m_current_frame->samplers_to_clean.push_back(std::move(fs_sampler_handles[i])); @@ -1114,7 +1113,7 @@ void VKGSRender::end() if (replace) { - fs_sampler_handles[i] = std::make_unique(*m_device, wrap_s, wrap_t, wrap_r, unnormalized_coords, lod_bias, af_level, min_lod, max_lod, + fs_sampler_handles[i] = std::make_unique(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod, min_filter, mag_filter, mip_mode, border_color, fs_sampler_state[i]->is_depth_texture, depth_compare); } } @@ -2135,6 +2134,7 @@ void VKGSRender::load_program(u32 vertex_count, u32 vertex_base) //Load current program from buffer vertex_program.skip_vertex_input_check = true; + fragment_program.unnormalized_coords = 0; m_program = m_prog_buffer->getGraphicPipelineState(vertex_program, fragment_program, properties, *m_device, pipeline_layout).get(); if (m_prog_buffer->check_cache_missed()) diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index 775f746994..5ce794bd3b 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -22,6 +22,10 @@ namespace vk bool dirty = false; u16 native_pitch = 0; u16 rsx_pitch = 0; + + u16 surface_width = 0; + u16 surface_height = 0; + VkImageAspectFlags attachment_aspect_flag = VK_IMAGE_ASPECT_COLOR_BIT; std::unique_ptr view; @@ -61,12 +65,12 @@ namespace vk u16 get_surface_width() const override { - return rsx::apply_inverse_resolution_scale(width(), true); + return surface_width; } u16 get_surface_height() const override { - return rsx::apply_inverse_resolution_scale(height(), true); + return surface_height; } u16 get_rsx_pitch() const override @@ -143,6 +147,8 @@ namespace rsx rtt->native_component_map = fmt.second; rtt->native_pitch = (u16)width * get_format_block_size_in_bytes(format); + rtt->surface_width = (u16)width; + rtt->surface_height = (u16)height; if (old_surface != nullptr && old_surface->info.format == requested_format) { @@ -197,6 +203,8 @@ namespace rsx ds->native_pitch *= 2; ds->attachment_aspect_flag = range.aspectMask; + ds->surface_width = (u16)width; + ds->surface_height = (u16)height; if (old_surface != nullptr && old_surface->info.format == requested_format) { diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 079d66ac46..39768fd386 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -511,9 +511,65 @@ namespace vk return create_temporary_subresource_view(cmd, *source, gcm_format, x, y, w, h); } - vk::image_view* generate_cubemap_from_images(vk::command_buffer&, std::array& sources) override + vk::image_view* generate_cubemap_from_images(vk::command_buffer& cmd, const u32 gcm_format, u16 size, std::array& sources) override { - return nullptr; + std::unique_ptr image; + std::unique_ptr view; + + image.reset(new vk::image(*vk::get_current_renderer(), m_memory_types.device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VK_IMAGE_TYPE_2D, + vk::get_compatible_sampler_format(gcm_format), + size, size, 1, 1, 6, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)); + + VkImageSubresourceRange subresource_range = {}; + VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT; + + for (u32 n = 0; n < 6; ++n) + { + if (!view) + { + switch (sources[0]->info.format) + { + case VK_FORMAT_D16_UNORM: + aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + } + + VkImageSubresourceRange view_range = { aspect & ~(VK_IMAGE_ASPECT_STENCIL_BIT), 0, 1, 0, 6 }; + view.reset(new vk::image_view(*vk::get_current_renderer(), image->value, VK_IMAGE_VIEW_TYPE_CUBE, image->info.format, image->native_component_map, view_range)); + subresource_range = view_range; + vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresource_range); + subresource_range.layerCount = 1; + } + + VkImageLayout old_src_layout = sources[n]->current_layout; + vk::change_image_layout(cmd, sources[n], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, subresource_range); + + VkImageCopy copy_rgn; + copy_rgn.srcOffset = { 0, 0, 0 }; + copy_rgn.dstOffset = { 0, 0, 0 }; + copy_rgn.dstSubresource = { aspect, 0, n, 1 }; + copy_rgn.srcSubresource = { aspect, 0, 0, 1 }; + copy_rgn.extent = { size, size, 1 }; + + vkCmdCopyImage(cmd, sources[n]->value, sources[n]->current_layout, image->value, image->current_layout, 1, ©_rgn); + vk::change_image_layout(cmd, sources[n], old_src_layout, subresource_range); + } + + subresource_range.layerCount = 6; + vk::change_image_layout(cmd, image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresource_range); + + const u32 resource_memory = size * size * 6 * 4; //Rough approximate + m_discardable_storage.push_back({ image, view }); + m_discardable_storage.back().block_size = resource_memory; + m_discarded_memory_size += resource_memory; + + return m_discardable_storage.back().view.get(); } cached_texture_section* create_new_texture(vk::command_buffer& cmd, u32 rsx_address, u32 rsx_size, u16 width, u16 height, u16 depth, u16 mipmaps, const u32 gcm_format, @@ -732,7 +788,10 @@ namespace vk inline vk::image_view* create_temporary_subresource(vk::command_buffer &cmd, deferred_subresource& desc) { - return create_temporary_subresource_view(cmd, desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height); + if (!desc.is_cubemap) + return create_temporary_subresource_view(cmd, desc.external_handle, desc.gcm_format, desc.x, desc.y, desc.width, desc.height); + else + return generate_cubemap_from_images(cmd, desc.gcm_format, desc.width, desc.external_cubemap_sources); } bool is_depth_texture(const u32 rsx_address, const u32 rsx_size) override