diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index b0e799ca0c..dfee0dee72 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/Memory/vm.h" #include "TextureUtils.h" #include "../RSXThread.h" @@ -525,6 +525,31 @@ u8 get_format_block_size_in_bytes(rsx::surface_color_format format) } } +/** + * Returns number of texel lines decoded in one pitch-length number of bytes + */ +u8 get_format_texel_rows_per_line(u32 format) +{ + switch (format) + { + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + // Layout is 4x4 blocks, i.e one row of pitch bytes in length actually encodes 4 texel rows + return 4; + default: + return 1; + } +} + +u32 get_format_packed_pitch(u32 format, u16 width) +{ + const auto texels_per_block = get_format_block_size_in_texel(format); + const auto bytes_per_block = get_format_block_size_in_bytes(format); + + return ((width + texels_per_block - 1) / texels_per_block) * bytes_per_block; +} + size_t get_placed_texture_storage_size(u16 width, u16 height, u32 depth, u8 format, u16 mipmap, bool cubemap, size_t row_pitch_alignment, size_t mipmap_alignment) { format &= ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); @@ -559,89 +584,39 @@ size_t get_placed_texture_storage_size(const rsx::vertex_texture &texture, size_ row_pitch_alignment, mipmap_alignment); } - -static size_t get_texture_size(u32 w, u32 h, u8 format) +static size_t get_texture_size(u32 format, u16 width, u16 height, u16 depth, u32 pitch, u16 mipmaps, u16 layers) { - format &= ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + const auto gcm_format = format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + const auto texel_rows_per_line = get_format_texel_rows_per_line(gcm_format); - // TODO: Take mipmaps into account - switch (format) + if (pitch == 0) { - case CELL_GCM_TEXTURE_B8: - return w * h; - case CELL_GCM_TEXTURE_G8B8: - return w * h * 2; - case CELL_GCM_TEXTURE_R5G5B5A1: - return w * h * 4; - case CELL_GCM_TEXTURE_D8R8G8B8: - return w * h * 4; - case CELL_GCM_TEXTURE_A8R8G8B8: - return w * h * 4; - case CELL_GCM_TEXTURE_D1R5G5B5: - return w * h * 2; - case CELL_GCM_TEXTURE_A1R5G5B5: - return w * h * 2; - case CELL_GCM_TEXTURE_A4R4G4B4: - return w * h * 2; - case CELL_GCM_TEXTURE_R6G5B5: - return w * h * 2; - case CELL_GCM_TEXTURE_R5G6B5: - return w * h * 2; - case CELL_GCM_TEXTURE_COMPRESSED_DXT1: - w = align(w, 4); - h = align(h, 4); - return w * h / 6; - case CELL_GCM_TEXTURE_COMPRESSED_DXT23: - w = align(w, 4); - h = align(h, 4); - return w * h / 4; - case CELL_GCM_TEXTURE_COMPRESSED_DXT45: - w = align(w, 4); - h = align(h, 4); - return w * h / 4; - case CELL_GCM_TEXTURE_DEPTH16: - return w * h * 2; - case CELL_GCM_TEXTURE_DEPTH16_FLOAT: - return w * h * 2; - case CELL_GCM_TEXTURE_DEPTH24_D8: - return w * h * 4; - case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: - return w * h * 4; - case CELL_GCM_TEXTURE_X16: - return w * h * 2; - case CELL_GCM_TEXTURE_Y16_X16: - return w * h * 4; - case CELL_GCM_TEXTURE_Y16_X16_FLOAT: - return w * h * 4; - case CELL_GCM_TEXTURE_X32_FLOAT: - return w * h * 4; - case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: - return w * h * 8; - case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: - return w * h * 16; - case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: - return w * h * 4; - case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: - return w * h * 4; - case CELL_GCM_TEXTURE_COMPRESSED_HILO8: - return w * h; - case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: - return w * h; - case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: - case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: - return w * h * 2; - default: - LOG_ERROR(RSX, "Unimplemented texture size for texture format: 0x%x", format); - return 0; + pitch = get_format_packed_pitch(gcm_format, width); } + + u32 size = 0; + for (u32 layer = 0; layer < layers; ++layer) + { + u32 mip_height = (height + texel_rows_per_line - 1) / texel_rows_per_line; // Convert texels to blocks + + for (u32 mipmap = 0; mipmap < mipmaps; ++mipmap) + { + size += pitch * mip_height; + mip_height = std::max(mip_height / 2u, 1u); + } + } + + return size; } size_t get_texture_size(const rsx::fragment_texture &texture) { - return get_texture_size(texture.width(), texture.height(), texture.format()); + return get_texture_size(texture.format(), texture.width(), texture.height(), texture.depth(), + texture.pitch(), texture.get_exact_mipmap_count(), texture.cubemap() ? 6 : 1); } size_t get_texture_size(const rsx::vertex_texture &texture) { - return get_texture_size(texture.width(), texture.height(), texture.format()); + return get_texture_size(texture.format(), texture.width(), texture.height(), texture.depth(), + texture.pitch(), texture.get_exact_mipmap_count(), texture.cubemap() ? 6 : 1); } diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index 0edd91a6ea..f95f1b659a 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "../RSXTexture.h" @@ -69,4 +69,9 @@ u8 get_format_block_size_in_bytes(rsx::surface_color_format format); * Get number of bytes occupied by texture in RSX mem */ size_t get_texture_size(const rsx::fragment_texture &texture); -size_t get_texture_size(const rsx::vertex_texture &texture); \ No newline at end of file +size_t get_texture_size(const rsx::vertex_texture &texture); + +/** +* Get packed pitch +*/ +u32 get_format_packed_pitch(u32 format, u16 width); \ No newline at end of file diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 772c18dd40..5011db294f 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -288,7 +288,7 @@ namespace rsx virtual image_view_type create_temporary_subresource_view(commandbuffer_type&, image_storage_type* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h, const texture_channel_remap_t& remap_vector) = 0; virtual section_storage_type* create_new_texture(commandbuffer_type&, const address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u32 gcm_format, rsx::texture_upload_context context, rsx::texture_dimension_extended type, texture_create_flags flags) = 0; - virtual section_storage_type* upload_image_from_cpu(commandbuffer_type&, u32 rsx_address, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, texture_upload_context context, + virtual section_storage_type* upload_image_from_cpu(commandbuffer_type&, const address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool swizzled) = 0; virtual void enforce_surface_creation_type(section_storage_type& section, u32 gcm_format, texture_create_flags expected) = 0; virtual void insert_texture_barrier(commandbuffer_type&, image_storage_type* tex) = 0; @@ -1688,18 +1688,18 @@ namespace rsx sampled_image_descriptor upload_texture(commandbuffer_type& cmd, RsxTextureType& tex, surface_store_type& m_rtts, Args&&... extras) { const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); - const u32 tex_size = (u32)get_placed_texture_storage_size(tex, 256, 512); + const u32 tex_size = (u32)get_texture_size(tex); const address_range tex_range = address_range::start_length(texaddr, tex_size); const u32 format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); const bool is_compressed_format = (format == CELL_GCM_TEXTURE_COMPRESSED_DXT1 || format == CELL_GCM_TEXTURE_COMPRESSED_DXT23 || format == CELL_GCM_TEXTURE_COMPRESSED_DXT45); const auto extended_dimension = tex.get_extended_texture_dimension(); - u16 depth; - u16 tex_height = (u16)tex.height(); const u16 tex_width = tex.width(); - u16 tex_pitch = is_compressed_format? (u16)(get_texture_size(tex) / tex_height) : tex.pitch(); //NOTE: Compressed textures dont have a real pitch (tex_size = (w*h)/6) - if (tex_pitch == 0) tex_pitch = tex_width * get_format_block_size_in_bytes(format); + u16 tex_height = tex.height(); + u16 tex_pitch = (u16)tex.pitch(); + if (tex_pitch == 0) tex_pitch = get_format_packed_pitch(format, tex_width); + u16 depth; switch (extended_dimension) { case rsx::texture_dimension_extended::texture_dimension_1d: @@ -1888,7 +1888,7 @@ namespace rsx invalidate_range_impl_base(tex_range, invalidation_cause::read, std::forward(extras)...); //NOTE: SRGB correction is to be handled in the fragment shader; upload as linear RGB - return{ upload_image_from_cpu(cmd, texaddr, tex_width, tex_height, depth, tex.get_exact_mipmap_count(), tex_pitch, format, + return{ upload_image_from_cpu(cmd, tex_range, tex_width, tex_height, depth, tex.get_exact_mipmap_count(), tex_pitch, format, texture_upload_context::shader_read, subresources_layout, extended_dimension, is_swizzled)->get_view(tex.remap(), tex.decoded_remap()), texture_upload_context::shader_read, is_depth_format, scale_x, scale_y, extended_dimension }; } @@ -2156,7 +2156,8 @@ namespace rsx { lock.upgrade(); - invalidate_range_impl_base(address_range::start_length(src_address, src.pitch * src.slice_h), invalidation_cause::read, std::forward(extras)...); + const auto rsx_range = address_range::start_length(src_address, src.pitch * src.slice_h); + invalidate_range_impl_base(rsx_range, invalidation_cause::read, std::forward(extras)...); const u16 pitch_in_block = src_is_argb8 ? src.pitch >> 2 : src.pitch >> 1; std::vector subresource_layout; @@ -2169,7 +2170,7 @@ namespace rsx subresource_layout.push_back(subres); const u32 gcm_format = src_is_argb8 ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_R5G6B5; - vram_texture = upload_image_from_cpu(cmd, src_address, src.width, src.slice_h, 1, 1, src.pitch, gcm_format, texture_upload_context::blit_engine_src, + vram_texture = upload_image_from_cpu(cmd, rsx_range, src.width, src.slice_h, 1, 1, src.pitch, gcm_format, texture_upload_context::blit_engine_src, subresource_layout, rsx::texture_dimension_extended::texture_dimension_2d, dst.swizzled)->get_raw_texture(); typeless_info.src_context = texture_upload_context::blit_engine_src; @@ -2296,7 +2297,9 @@ namespace rsx dst_dimensions.height = section_length / dst.pitch; lock.upgrade(); - invalidate_range_impl_base(address_range::start_length(dst.rsx_address, section_length), invalidation_cause::write, std::forward(extras)...); + + const auto rsx_range = address_range::start_length(dst.rsx_address, section_length); + invalidate_range_impl_base(rsx_range, invalidation_cause::write, std::forward(extras)...); const u16 pitch_in_block = dst_is_argb8 ? dst.pitch >> 2 : dst.pitch >> 1; std::vector subresource_layout; @@ -2308,7 +2311,7 @@ namespace rsx subres.data = { (const gsl::byte*)dst.pixels, dst.pitch * dst_dimensions.height }; subresource_layout.push_back(subres); - cached_dest = upload_image_from_cpu(cmd, dst.rsx_address, dst_dimensions.width, dst_dimensions.height, 1, 1, dst.pitch, + cached_dest = upload_image_from_cpu(cmd, rsx_range, dst_dimensions.width, dst_dimensions.height, 1, 1, dst.pitch, gcm_format, rsx::texture_upload_context::blit_engine_dst, subresource_layout, rsx::texture_dimension_extended::texture_dimension_2d, false); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index 3c40b75c68..3336b11755 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -573,7 +573,7 @@ namespace gl return remap_values; } - void upload_texture(GLuint id, u32 texaddr, u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, bool is_swizzled, rsx::texture_dimension_extended type, + void upload_texture(GLuint id, u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, bool is_swizzled, rsx::texture_dimension_extended type, const std::vector& subresources_layout) { size_t texture_data_sz = get_placed_texture_storage_size(width, height, depth, gcm_format, mipmaps, type == rsx::texture_dimension_extended::texture_dimension_cubemap, 256, 512); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index 3eae41e5fa..99f36a44bd 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -30,7 +30,7 @@ namespace gl * - second vector contains overrides to force the value to either 0 or 1 instead of reading from texture * static_state - set up the texture without consideration for sampler state (useful for vertex textures which have no real sampler state on RSX) */ - void upload_texture(GLuint id, u32 texaddr, u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, bool is_swizzled, rsx::texture_dimension_extended type, + void upload_texture(GLuint id, u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, bool is_swizzled, rsx::texture_dimension_extended type, const std::vector& subresources_layout); class sampler_state diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index a2f83e7713..24469dfe56 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -998,15 +998,14 @@ namespace gl return &cached; } - cached_texture_section* upload_image_from_cpu(void*&, u32 rsx_address, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, + cached_texture_section* upload_image_from_cpu(void*&, const utils::address_range& rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, rsx::texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool input_swizzled) override { void* unused = nullptr; - const utils::address_range rsx_range = utils::address_range::start_length(rsx_address, pitch * height); auto section = create_new_texture(unused, rsx_range, width, height, depth, mipmaps, gcm_format, context, type, rsx::texture_create_flags::default_component_order); - gl::upload_texture(section->get_raw_texture()->id(), rsx_address, gcm_format, width, height, depth, mipmaps, + gl::upload_texture(section->get_raw_texture()->id(), gcm_format, width, height, depth, mipmaps, input_swizzled, type, subresource_layout); return section; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 92d4b7237d..401c4e16c7 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -870,10 +870,9 @@ namespace vk return ®ion; } - cached_texture_section* upload_image_from_cpu(vk::command_buffer& cmd, u32 rsx_address, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, + cached_texture_section* upload_image_from_cpu(vk::command_buffer& cmd, const utils::address_range& rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, rsx::texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool swizzled) override { - const utils::address_range rsx_range = utils::address_range::start_length(rsx_address, pitch * height); auto section = create_new_texture(cmd, rsx_range, width, height, depth, mipmaps, gcm_format, context, type, rsx::texture_create_flags::default_component_order);