diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index 21dd207c6a..afbf6e4eba 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -29,11 +29,10 @@ namespace struct copy_unmodified_block { template - static void copy_mipmap_level(gsl::span dst, const U *src_ptr, u16 row_count, u16 width_in_block, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block) + static void copy_mipmap_level(gsl::span dst, gsl::span src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block, u32 src_pitch_in_block) { size_t row_element_count = dst_pitch_in_block; static_assert(sizeof(T) == sizeof(U), "Type size doesn't match."); - gsl::span src{ src_ptr, row_count * src_pitch_in_block * depth }; for (int row = 0; row < row_count * depth; ++row) copy(dst.subspan(row * dst_pitch_in_block, width_in_block), src.subspan(row * src_pitch_in_block, width_in_block)); } @@ -42,10 +41,9 @@ struct copy_unmodified_block struct copy_unmodified_block_swizzled { template - static void copy_mipmap_level(gsl::span dst, const U *src_ptr, u16 row_count, u16 width_in_block, u16 depth, u32 dst_pitch_in_block, u32) + static void copy_mipmap_level(gsl::span dst, gsl::span src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block) { std::unique_ptr temp_swizzled(new U[width_in_block * row_count]); - gsl::span src{ src_ptr, gsl::narrow(width_in_block * row_count * depth) }; for (int d = 0; d < depth; ++d) { rsx::convert_linear_swizzle((void*)src.subspan(d * width_in_block * row_count).data(), temp_swizzled.get(), width_in_block, row_count, true); @@ -56,103 +54,169 @@ struct copy_unmodified_block_swizzled } }; -/** -* Texture upload template. -* -* Source textures are stored as following (for power of 2 textures): -* - For linear texture every mipmap level share rowpitch (which is the one of mipmap 0). This means that for non 0 mipmap there's padding between row. -* - For swizzled texture row pitch is texture width X pixel/block size. There's not padding between row. -* - There is no padding between 2 mipmap levels. This means that next mipmap level starts at offset rowpitch X row count -* - Cubemap images are 128 bytes aligned. -* -* The template iterates over all depth (including cubemap) and over all mipmaps. -* The alignment is 256 for mipmap levels and 512 for depth (DX12), varies for vulkan -* The template takes a struct with a "copy_mipmap_level" static function that copy the given mipmap level and returns the offset to add to the src buffer for next -* mipmap level (to allow same code for packed/non packed texels) -* Sometimes texture provides a pitch even if texture is swizzled (and then packed) and in such case it's ignored. It's passed via suggested_pitch and is used only if padded_row is false. -*/ -template -std::vector copy_texture_data(gsl::span dst, const SRC_TYPE *src, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count, u32 suggested_pitch_in_bytes, size_t alignment) +namespace { /** - * Note about size type: RSX texture width is stored in a 16 bits int and pitch is stored in a 20 bits int. - */ - - // <= 128 so fits in u8 - u8 block_size_in_bytes = sizeof(DST_TYPE); - - std::vector Result; - size_t offsetInDst = 0, offsetInSrc = 0; - // Always lower than width/height so fits in u16 - u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; - u16 texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; - for (unsigned layer = 0; layer < layer_count; layer++) + * Texture upload template. + * + * Source textures are stored as following (for power of 2 textures): + * - For linear texture every mipmap level share rowpitch (which is the one of mipmap 0). This means that for non 0 mipmap there's padding between row. + * - For swizzled texture row pitch is texture width X pixel/block size. There's not padding between row. + * - There is no padding between 2 mipmap levels. This means that next mipmap level starts at offset rowpitch X row count + * - Cubemap images are 128 bytes aligned. + * + * The template iterates over all depth (including cubemap) and over all mipmaps. + * Sometimes texture provides a pitch even if texture is swizzled (and then packed) and in such case it's ignored. It's passed via suggested_pitch and is used only if padded_row is false. + */ + template + std::vector get_subresources_layout_impl(const gsl::byte *texture_data_pointer, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count, u32 suggested_pitch_in_bytes, bool padded_row) { - u16 miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block; - for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++) + /** + * Note about size type: RSX texture width is stored in a 16 bits int and pitch is stored in a 20 bits int. + */ + + // <= 128 so fits in u8 + u8 block_size_in_bytes = sizeof(SRC_TYPE); + + std::vector result; + size_t offset_in_src = 0; + // Always lower than width/height so fits in u16 + u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; + u16 texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; + for (unsigned layer = 0; layer < layer_count; layer++) { - // since mip_level is up to 16 bits needs at least 17 bits. - u32 dst_pitch = align(miplevel_width_in_block * block_size_in_bytes, alignment) / block_size_in_bytes; + u16 miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block; + for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++) + { + rsx_subresource_layout current_subresource_layout = {}; + // Since <= width/height, fits on 16 bits + current_subresource_layout.height_in_block = miplevel_height_in_block; + current_subresource_layout.width_in_block = miplevel_width_in_block; + current_subresource_layout.depth = depth; + // src_pitch in texture can uses 20 bits so fits on 32 bits int. + u32 src_pitch_in_block = padded_row ? suggested_pitch_in_bytes / block_size_in_bytes : miplevel_width_in_block; + current_subresource_layout.pitch_in_bytes = src_pitch_in_block; - MipmapLevelInfo currentMipmapLevelInfo = {}; - currentMipmapLevelInfo.offset = offsetInDst; - // Since <= width/height, fits on 16 bits - currentMipmapLevelInfo.height = static_cast(miplevel_height_in_block * block_edge_in_texel); - currentMipmapLevelInfo.width = static_cast(miplevel_width_in_block * block_edge_in_texel); - currentMipmapLevelInfo.depth = depth; - currentMipmapLevelInfo.rowPitch = static_cast(dst_pitch * block_size_in_bytes); - Result.push_back(currentMipmapLevelInfo); + current_subresource_layout.data = gsl::span(texture_data_pointer + offset_in_src, src_pitch_in_block * block_size_in_bytes * miplevel_height_in_block * depth); - // TODO: uses src_pitch from texture - // src_pitch in texture can uses 20 bits so fits on 32 bits int. - u32 src_pitch_in_block = padded_row ? suggested_pitch_in_bytes / block_size_in_bytes : miplevel_width_in_block; - const SRC_TYPE *src_with_offset = reinterpret_cast(reinterpret_cast(src) + offsetInSrc); - T::copy_mipmap_level(dst.subspan(offsetInDst / block_size_in_bytes, dst_pitch * depth * miplevel_height_in_block), src_with_offset, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch, src_pitch_in_block); - offsetInSrc += miplevel_height_in_block * src_pitch_in_block * block_size_in_bytes * depth; - offsetInDst += align(miplevel_height_in_block * dst_pitch * block_size_in_bytes, 512); - miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1); - miplevel_width_in_block = MAX2(miplevel_width_in_block / 2, 1); + result.push_back(current_subresource_layout); + offset_in_src += miplevel_height_in_block * src_pitch_in_block * block_size_in_bytes * depth; + miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1); + miplevel_width_in_block = MAX2(miplevel_width_in_block / 2, 1); + } + offset_in_src = align(offset_in_src, 128); } - offsetInSrc = align(offsetInSrc, 128); + return result; } - return Result; } -/** - * Copy a single mipmap level starting at a given offset with a given rowpitch alignment - */ - -template -void copy_single_mipmap_layer(gsl::span dst, const SRC_TYPE *src, u16 width_in_texel, u16 height_in_texel, u16 depth, u8 layer_count, u16 mipmap_count, u16 mipmap_index, u16 layer_index, u32 suggested_pitch_in_bytes, u32 dst_pitch) +template +u32 get_row_pitch_in_block(u16 width_in_block, size_t alignment_in_bytes) { - u8 block_size_in_bytes = sizeof(DST_TYPE); - size_t offsetInSrc = 0; + return static_cast(align(width_in_block * sizeof(T), alignment_in_bytes) / sizeof(T)); +} +} - u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; - u16 texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; +std::vector get_subresources_layout(const rsx::texture &texture) +{ + u16 w = texture.width(), h = texture.height(); + u16 depth; + u8 layer; - for (unsigned layer = 0; layer <= layer_index; layer++) + if (texture.dimension() == 1) { - u16 miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block; - for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++) - { - u32 src_pitch_in_block = padded_row ? suggested_pitch_in_bytes / block_size_in_bytes : miplevel_width_in_block; - u32 dst_pitch_in_block = dst_pitch / block_size_in_bytes; - const SRC_TYPE *src_with_offset = reinterpret_cast(reinterpret_cast(src) + offsetInSrc); + depth = 1; + layer = 1; + h = 1; + } + else if (texture.dimension() == 2) + { + depth = 1; + layer = texture.cubemap() ? 6 : 1; + } + else if (texture.dimension() == 3) + { + depth = texture.depth(); + layer = 1; + } + else + throw EXCEPTION("Unsupported texture dimension %d", texture.dimension()); - if (mip_level == mipmap_index && - layer == layer_index) - { - T::copy_mipmap_level(dst.subspan(0, dst_pitch_in_block * depth * miplevel_height_in_block), src_with_offset, miplevel_height_in_block, miplevel_width_in_block, depth, dst_pitch_in_block, src_pitch_in_block); - break; - } + int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - offsetInSrc += miplevel_height_in_block * src_pitch_in_block * block_size_in_bytes * depth; - miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1); - miplevel_width_in_block = MAX2(miplevel_width_in_block / 2, 1); - } + const u32 texaddr = rsx::get_address(texture.offset(), texture.location()); + auto pixels = reinterpret_cast(vm::ps3::_ptr(texaddr)); + bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); + switch (format) + { + case CELL_GCM_TEXTURE_D8R8G8B8: + case CELL_GCM_TEXTURE_A8R8G8B8: + return get_subresources_layout_impl<1, u32>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + case CELL_GCM_TEXTURE_DEPTH16: + case CELL_GCM_TEXTURE_D1R5G5B5: + case CELL_GCM_TEXTURE_A1R5G5B5: + case CELL_GCM_TEXTURE_R5G5B5A1: + case CELL_GCM_TEXTURE_A4R4G4B4: + case CELL_GCM_TEXTURE_R5G6B5: + case CELL_GCM_TEXTURE_G8B8: + return get_subresources_layout_impl<1, u16>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + return get_subresources_layout_impl<1, u64>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + return get_subresources_layout_impl<4, u64>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + return get_subresources_layout_impl<4, u128>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + case CELL_GCM_TEXTURE_B8: + return get_subresources_layout_impl<1, u8>(pixels, w, h, depth, layer, texture.mipmap(), texture.pitch(), !is_swizzled); + } + throw EXCEPTION("Wrong format %d", format); +} - offsetInSrc = align(offsetInSrc, 128); +void upload_texture_subresource(gsl::span dst_buffer, const rsx_subresource_layout &src_layout, int format, bool is_swizzled, size_t dst_row_alignment) +{ + u16 w = src_layout.width_in_block; + u16 h = src_layout.height_in_block; + u16 depth = src_layout.depth; + switch (format) + { + case CELL_GCM_TEXTURE_A8R8G8B8: + case CELL_GCM_TEXTURE_D8R8G8B8: + if (is_swizzled) + copy_unmodified_block_swizzled::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment)); + else + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + case CELL_GCM_TEXTURE_DEPTH16: + case CELL_GCM_TEXTURE_D1R5G5B5: + case CELL_GCM_TEXTURE_A1R5G5B5: + case CELL_GCM_TEXTURE_R5G5B5A1: + case CELL_GCM_TEXTURE_A4R4G4B4: + case CELL_GCM_TEXTURE_R5G6B5: + case CELL_GCM_TEXTURE_G8B8: + if (is_swizzled) + copy_unmodified_block_swizzled::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span>(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment)); + else + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span>(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span>(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + case CELL_GCM_TEXTURE_B8: + if (is_swizzled) + copy_unmodified_block_swizzled::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment)); + else + copy_unmodified_block::copy_mipmap_level(as_span_workaround(dst_buffer), gsl::as_span(src_layout.data), w, h, depth, get_row_pitch_in_block(w, dst_row_alignment), src_layout.pitch_in_bytes); + break; + default: + throw EXCEPTION("Wrong format %d", format); } } @@ -160,7 +224,7 @@ void copy_single_mipmap_layer(gsl::span dst, const SRC_TYPE *src, u16 * A texture is stored as an array of blocks, where a block is a pixel for standard texture * but is a structure containing several pixels for compressed format */ -size_t get_texture_block_size(u32 format) +u8 get_format_block_size_in_bytes(int format) { switch (format) { @@ -199,7 +263,7 @@ size_t get_texture_block_size(u32 format) } } -size_t get_texture_block_edge(u32 format) +u8 get_format_block_size_in_texel(int format) { switch (format) { @@ -237,7 +301,6 @@ size_t get_texture_block_edge(u32 format) return 0; } } -} size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPitchAlignement, size_t mipmapAlignment) @@ -245,8 +308,8 @@ size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPi size_t w = texture.width(), h = texture.height(), d = MAX2(texture.depth(), 1); int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - size_t blockEdge = get_texture_block_edge(format); - size_t blockSizeInByte = get_texture_block_size(format); + size_t blockEdge = get_format_block_size_in_texel(format); + size_t blockSizeInByte = get_format_block_size_in_bytes(format); size_t heightInBlocks = (h + blockEdge - 1) / blockEdge; size_t widthInBlocks = (w + blockEdge - 1) / blockEdge; @@ -264,175 +327,6 @@ size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPi return result * (texture.cubemap() ? 6 : 1); } -std::vector upload_placed_texture(gsl::span mapped_buffer, const rsx::texture &texture, size_t rowPitchAlignment) -{ - u16 w = texture.width(), h = texture.height(); - u16 depth; - u8 layer; - - if (texture.dimension() == 1) - { - depth = 1; - layer = 1; - h = 1; - } - else if (texture.dimension() == 2) - { - depth = 1; - layer = texture.cubemap() ? 6 : 1; - } - else if (texture.dimension() == 3) - { - depth = texture.depth(); - layer = 1; - } - else - throw EXCEPTION("Unsupported texture dimension %d", texture.dimension()); - - int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - - std::vector mipInfos; - - const u32 texaddr = rsx::get_address(texture.offset(), texture.location()); - auto pixels = vm::ps3::_ptr(texaddr); - bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); - switch (format) - { - case CELL_GCM_TEXTURE_D8R8G8B8: - case CELL_GCM_TEXTURE_A8R8G8B8: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_DEPTH16: - case CELL_GCM_TEXTURE_D1R5G5B5: - case CELL_GCM_TEXTURE_A1R5G5B5: - case CELL_GCM_TEXTURE_R5G5B5A1: - case CELL_GCM_TEXTURE_A4R4G4B4: - case CELL_GCM_TEXTURE_R5G6B5: - case CELL_GCM_TEXTURE_G8B8: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), 4 * w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_COMPRESSED_DXT1: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_COMPRESSED_DXT23: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_COMPRESSED_DXT45: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - case CELL_GCM_TEXTURE_B8: - if (is_swizzled) - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - else - return copy_texture_data(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment); - } - throw EXCEPTION("Wrong format %d", format); -} - -/** - * Upload texture mipmaps where alignment and offset information is provided manually - */ -void upload_texture_mipmaps(gsl::span dst_buffer, const rsx::texture &texture, std::vector> alignment_offset_info) -{ - u16 w = texture.width(), h = texture.height(); - u16 depth; - u8 layer; - - if (texture.dimension() == 1) - { - depth = 1; - layer = 1; - h = 1; - } - else if (texture.dimension() == 2) - { - depth = 1; - layer = texture.cubemap() ? 6 : 1; - } - else if (texture.dimension() == 3) - { - depth = texture.depth(); - layer = 1; - } - else - throw EXCEPTION("Unsupported texture dimension %d", texture.dimension()); - - int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - - const u32 texaddr = rsx::get_address(texture.offset(), texture.location()); - auto pixels = vm::ps3::_ptr(texaddr); - bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); - - //TODO: Layers greater than 0 - for (u32 mip_level = 0; mip_level < texture.mipmap(); ++mip_level) - { - gsl::span mapped_buffer = dst_buffer.subspan(alignment_offset_info[mip_level].first); - - switch (format) - { - case CELL_GCM_TEXTURE_A8R8G8B8: - case CELL_GCM_TEXTURE_D8R8G8B8: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_DEPTH16: - case CELL_GCM_TEXTURE_D1R5G5B5: - case CELL_GCM_TEXTURE_A1R5G5B5: - case CELL_GCM_TEXTURE_R5G5B5A1: - case CELL_GCM_TEXTURE_A4R4G4B4: - case CELL_GCM_TEXTURE_R5G6B5: - case CELL_GCM_TEXTURE_G8B8: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_COMPRESSED_DXT1: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_COMPRESSED_DXT23: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_COMPRESSED_DXT45: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - case CELL_GCM_TEXTURE_B8: - if (is_swizzled) - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - else - copy_single_mipmap_layer(as_span_workaround(mapped_buffer), reinterpret_cast(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second); - break; - default: - throw EXCEPTION("Wrong format %d", format); - } - } -} size_t get_texture_size(const rsx::texture &texture) { diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index 7614066f23..6cc8a410f4 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -2,13 +2,13 @@ #include "../RSXTexture.h" #include -struct MipmapLevelInfo +struct rsx_subresource_layout { - size_t offset; - u16 width; - u16 height; + gsl::span data; + u16 width_in_block; + u16 height_in_block; u16 depth; - u32 rowPitch; + u32 pitch_in_bytes; }; /** @@ -18,18 +18,15 @@ struct MipmapLevelInfo size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPitchAlignement, size_t mipmapAlignment=512); /** -* Write texture data to textureData. -* Data are not packed, they are stored per rows using rowPitchAlignement. -* Similarly, offset for every mipmaplevel is aligned to rowPitchAlignement boundary. -*/ -std::vector upload_placed_texture(gsl::span mapped_buffer, const rsx::texture &texture, size_t rowPitchAlignement); + * get all rsx_subresource_layout for texture. + * The subresources are ordered per layer then per mipmap level (as in rsx memory). + */ +std::vector get_subresources_layout(const rsx::texture &texture); -/** -* Upload texture mipmaps where alignment and offset information is provided manually. -* alignment_offset info is an array of N mipmaps providing the offset into the data block and row-pitch alignment of each -* mipmap level individually. -*/ -void upload_texture_mipmaps(gsl::span dst_buffer, const rsx::texture &texture, std::vector> alignment_offset_info); +void upload_texture_subresource(gsl::span dst_buffer, const rsx_subresource_layout &src_layout, int format, bool is_swizzled, size_t dst_row_alignment); + +u8 get_format_block_size_in_bytes(int format); +u8 get_format_block_size_in_texel(int format); /** * Get number of bytes occupied by texture in RSX mem diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 35959c1b65..3de878cc01 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -79,11 +79,6 @@ ComPtr upload_single_texture( size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t heap_offset = texture_buffer_heap.alloc(buffer_size); - void *mapped_buffer_ptr = texture_buffer_heap.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); - gsl::span mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow(buffer_size) }; - std::vector mipInfos = upload_placed_texture(mapped_buffer, texture, 256); - texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); - ComPtr result; CHECK_HRESULT(device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), @@ -97,12 +92,35 @@ ComPtr upload_single_texture( const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); DXGI_FORMAT dxgi_format = get_texture_format(format); size_t mip_level = 0; - for (const MipmapLevelInfo mli : mipInfos) + + void *mapped_buffer_ptr = texture_buffer_heap.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); + gsl::span mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow(buffer_size) }; + std::vector input_layouts = get_subresources_layout(texture); + u8 block_size_in_bytes = get_format_block_size_in_bytes(format); + u8 block_size_in_texel = get_format_block_size_in_texel(format); + bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); + size_t offset_in_buffer = 0; + for (const rsx_subresource_layout &layout : input_layouts) { + upload_texture_subresource(mapped_buffer.subspan(offset_in_buffer), layout, format, is_swizzled, 256); + UINT row_pitch = align(layout.width_in_block * block_size_in_bytes, 256); command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(result.Get(), (UINT)mip_level), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset, { dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr); + &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), + { heap_offset + offset_in_buffer, + { + dxgi_format, + (UINT)layout.width_in_block * block_size_in_texel, + (UINT)layout.height_in_block * block_size_in_texel, + (UINT)layout.depth, + row_pitch + } + }), nullptr); + + offset_in_buffer += row_pitch * layout.height_in_block * layout.depth; + offset_in_buffer = align(offset_in_buffer, 512); mip_level++; } + texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(result.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); return result; @@ -124,20 +142,36 @@ void update_existing_texture( size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t heap_offset = texture_buffer_heap.alloc(buffer_size); + size_t mip_level = 0; void *mapped_buffer_ptr = texture_buffer_heap.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); gsl::span mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow(buffer_size) }; - std::vector mipInfos = upload_placed_texture(mapped_buffer, texture, 256); - texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); - - command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST)); - size_t miplevel = 0; - for (const MipmapLevelInfo mli : mipInfos) + std::vector input_layouts = get_subresources_layout(texture); + u8 block_size_in_bytes = get_format_block_size_in_bytes(format); + u8 block_size_in_texel = get_format_block_size_in_texel(format); + bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); + size_t offset_in_buffer = 0; + for (const rsx_subresource_layout &layout : input_layouts) { - command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)miplevel), 0, 0, 0, - &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + mli.offset,{ dxgi_format, (UINT)mli.width, (UINT)mli.height, (UINT)mli.depth, (UINT)mli.rowPitch } }), nullptr); - miplevel++; + upload_texture_subresource(mapped_buffer.subspan(offset_in_buffer), layout, format, is_swizzled, 256); + UINT row_pitch = align(layout.width_in_block * block_size_in_bytes, 256); + command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)mip_level), 0, 0, 0, + &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), + { heap_offset + offset_in_buffer, + { + dxgi_format, + (UINT)layout.width_in_block * block_size_in_texel, + (UINT)layout.height_in_block * block_size_in_texel, + (UINT)layout.depth, + row_pitch + } + }), nullptr); + + offset_in_buffer += row_pitch * layout.height_in_block * layout.depth; + offset_in_buffer = align(offset_in_buffer, 512); + mip_level++; } + texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); } diff --git a/rpcs3/Emu/RSX/GL/GLProcTable.h b/rpcs3/Emu/RSX/GL/GLProcTable.h index 5b7838dce0..10a8e7e8b9 100644 --- a/rpcs3/Emu/RSX/GL/GLProcTable.h +++ b/rpcs3/Emu/RSX/GL/GLProcTable.h @@ -185,5 +185,6 @@ OPENGL_PROC(PFNGLTEXSTORAGE2DPROC, TexStorage2D); OPENGL_PROC(PFNGLBLENDCOLORPROC, BlendColor); OPENGL_PROC(PFNGLBLENDEQUATIONPROC, BlendEquation); OPENGL_PROC(PFNGLCOMPRESSEDTEXIMAGE2DPROC, CompressedTexImage2D); +OPENGL_PROC(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, CompressedTexSubImage2D); OPENGL_PROC(PFNGLACTIVETEXTUREPROC, ActiveTexture); #endif diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index e82f6b7376..7ccf7509eb 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -9,30 +9,62 @@ namespace { - std::tuple get_sized_internal_format_format_type(u32 texture_format) + GLenum get_sized_internal_format(u32 texture_format) { switch (texture_format) { - case CELL_GCM_TEXTURE_B8: return std::make_tuple(GL_R8, GL_RED, GL_UNSIGNED_BYTE); - case CELL_GCM_TEXTURE_A1R5G5B5: return std::make_tuple(GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV); - case CELL_GCM_TEXTURE_A4R4G4B4: return std::make_tuple(GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4); - case CELL_GCM_TEXTURE_R5G6B5: return std::make_tuple(GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); - case CELL_GCM_TEXTURE_A8R8G8B8: return std::make_tuple(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); - case CELL_GCM_TEXTURE_G8B8: return std::make_tuple(GL_RG8, GL_RG, GL_UNSIGNED_BYTE); - case CELL_GCM_TEXTURE_R6G5B5: return std::make_tuple(GL_RGB565, GL_RGBA, GL_UNSIGNED_BYTE); - case CELL_GCM_TEXTURE_DEPTH24_D8: return std::make_tuple(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE); - case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_FLOAT); - case CELL_GCM_TEXTURE_DEPTH16: return std::make_tuple(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_SHORT); - case CELL_GCM_TEXTURE_DEPTH16_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_FLOAT); - case CELL_GCM_TEXTURE_X16: return std::make_tuple(GL_R16, GL_RED, GL_UNSIGNED_SHORT); - case CELL_GCM_TEXTURE_Y16_X16: return std::make_tuple(GL_RG16, GL_RG, GL_UNSIGNED_SHORT); - case CELL_GCM_TEXTURE_R5G5B5A1: return std::make_tuple(GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); - case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return std::make_tuple(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); - case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return std::make_tuple(GL_RGBA32F, GL_RGBA, GL_FLOAT); - case CELL_GCM_TEXTURE_X32_FLOAT: return std::make_tuple(GL_R32F, GL_RED, GL_FLOAT); - case CELL_GCM_TEXTURE_D1R5G5B5: return std::make_tuple(GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV); - case CELL_GCM_TEXTURE_D8R8G8B8: return std::make_tuple(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); - case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return std::make_tuple(GL_RG16F, GL_RG, GL_HALF_FLOAT); + case CELL_GCM_TEXTURE_B8: return GL_R8; + case CELL_GCM_TEXTURE_A1R5G5B5: return GL_RGB5_A1; + case CELL_GCM_TEXTURE_A4R4G4B4: return GL_RGBA4; + case CELL_GCM_TEXTURE_R5G6B5: return GL_RGB565; + case CELL_GCM_TEXTURE_A8R8G8B8: return GL_RGBA8; + case CELL_GCM_TEXTURE_G8B8: return GL_RG8; + case CELL_GCM_TEXTURE_R6G5B5: return GL_RGB565; + case CELL_GCM_TEXTURE_DEPTH24_D8: return GL_DEPTH_COMPONENT24; + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return GL_DEPTH_COMPONENT24; + case CELL_GCM_TEXTURE_DEPTH16: return GL_DEPTH_COMPONENT16; + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: return GL_DEPTH_COMPONENT16; + case CELL_GCM_TEXTURE_X16: return GL_R16; + case CELL_GCM_TEXTURE_Y16_X16: return GL_RG16; + case CELL_GCM_TEXTURE_R5G5B5A1: return GL_RGB5_A1; + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return GL_RGBA16F; + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return GL_RGBA32F; + case CELL_GCM_TEXTURE_X32_FLOAT: return GL_R32F; + case CELL_GCM_TEXTURE_D1R5G5B5: return GL_RGB5_A1; + case CELL_GCM_TEXTURE_D8R8G8B8: return GL_RGBA8; + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return GL_RG16F; + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + throw EXCEPTION("Compressed or unknown texture format %x", texture_format); + } + + + std::tuple get_format_type(u32 texture_format) + { + switch (texture_format) + { + case CELL_GCM_TEXTURE_B8: return std::make_tuple(GL_RED, GL_UNSIGNED_BYTE); + case CELL_GCM_TEXTURE_A1R5G5B5: return std::make_tuple(GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV); + case CELL_GCM_TEXTURE_A4R4G4B4: return std::make_tuple(GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4); + case CELL_GCM_TEXTURE_R5G6B5: return std::make_tuple(GL_RGB, GL_UNSIGNED_SHORT_5_6_5); + case CELL_GCM_TEXTURE_A8R8G8B8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); + case CELL_GCM_TEXTURE_G8B8: return std::make_tuple(GL_RG, GL_UNSIGNED_BYTE); + case CELL_GCM_TEXTURE_R6G5B5: return std::make_tuple(GL_RGBA, GL_UNSIGNED_BYTE); + case CELL_GCM_TEXTURE_DEPTH24_D8: return std::make_tuple(GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE); + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT, GL_FLOAT); + case CELL_GCM_TEXTURE_DEPTH16: return std::make_tuple(GL_DEPTH_COMPONENT, GL_SHORT); + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT, GL_FLOAT); + case CELL_GCM_TEXTURE_X16: return std::make_tuple(GL_RED, GL_UNSIGNED_SHORT); + case CELL_GCM_TEXTURE_Y16_X16: return std::make_tuple(GL_RG, GL_UNSIGNED_SHORT); + case CELL_GCM_TEXTURE_R5G5B5A1: return std::make_tuple(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return std::make_tuple(GL_RGBA, GL_HALF_FLOAT); + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return std::make_tuple(GL_RGBA, GL_FLOAT); + case CELL_GCM_TEXTURE_X32_FLOAT: return std::make_tuple(GL_RED, GL_FLOAT); + case CELL_GCM_TEXTURE_D1R5G5B5: return std::make_tuple(GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV); + case CELL_GCM_TEXTURE_D8R8G8B8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return std::make_tuple(GL_RG, GL_HALF_FLOAT); } throw EXCEPTION("Compressed or unknown texture format %x", texture_format); } @@ -283,62 +315,31 @@ namespace rsx u32 aligned_pitch = tex.pitch(); size_t texture_data_sz = get_placed_texture_storage_size(tex, 256); - std::vector data_upload_buf(texture_data_sz); - u8* texture_data = data_upload_buf.data(); + std::vector data_upload_buf(texture_data_sz); u32 block_sz = get_pitch_modifier(format); - if (is_swizzled || mandates_expansion(format)) - { - aligned_pitch = align(aligned_pitch, 256); - upload_placed_texture({ reinterpret_cast(texture_data), gsl::narrow(texture_data_sz) }, tex, 256); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - else - { - texture_data = vm::ps3::_ptr(texaddr); - } - - if (block_sz) - aligned_pitch /= block_sz; - else - aligned_pitch = 0; - - glPixelStorei(GL_UNPACK_ROW_LENGTH, aligned_pitch); + const std::vector &input_layouts = get_subresources_layout(tex); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexStorage2D(m_target, tex.mipmap(), get_sized_internal_format(format), tex.width(), tex.height()); if (!is_compressed_format(format)) { - const auto &sized_internal_format_format_type = get_sized_internal_format_format_type(format); - glTexStorage2D(m_target, tex.mipmap(), std::get<0>(sized_internal_format_format_type), tex.width(), tex.height()); - if (requires_unpack_byte(format)) - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); - glTexSubImage2D(m_target, 0, 0, 0, tex.width(), tex.height(), std::get<1>(sized_internal_format_format_type), std::get<2>(sized_internal_format_format_type), texture_data); - if (requires_unpack_byte(format)) - glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + const auto &format_type = get_format_type(format); + GLint mip_level = 0; + for (const rsx_subresource_layout &layout : input_layouts) + { + upload_texture_subresource(data_upload_buf, layout, format, is_swizzled, 4); + glTexSubImage2D(m_target, mip_level++, 0, 0, layout.width_in_block, layout.height_in_block, std::get<0>(format_type), std::get<1>(format_type), data_upload_buf.data()); + } } else { - switch (format) - { - case CELL_GCM_TEXTURE_COMPRESSED_DXT1: // Compressed 4x4 pixels into 8 bytes - { - u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 8; - glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.width(), tex.height(), 0, size, texture_data); - break; - } - case CELL_GCM_TEXTURE_COMPRESSED_DXT23: // Compressed 4x4 pixels into 16 bytes + GLint mip_level = 0; + for (const rsx_subresource_layout &layout : input_layouts) { - u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 16; - glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.width(), tex.height(), 0, size, texture_data); - } - break; - - case CELL_GCM_TEXTURE_COMPRESSED_DXT45: // Compressed 4x4 pixels into 16 bytes - { - u32 size = ((tex.width() + 3) / 4) * ((tex.height() + 3) / 4) * 16; - glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.width(), tex.height(), 0, size, texture_data); - break; - } + u32 size = layout.width_in_block * layout.height_in_block * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16); + glCompressedTexSubImage2D(m_target, mip_level++, 0, 0, layout.width_in_block * 4, layout.height_in_block * 4, get_sized_internal_format(format), size, layout.data.data()); } } @@ -386,11 +387,6 @@ namespace rsx LOG_WARNING(RSX, "Texture %d, target 0x%X, requesting mipmap filtering without any mipmaps set!", m_id, m_target); min_filter = GL_LINEAR; } - else - { - //TODO: Check if the call succeeded - glGenerateMipmap(m_target); - } } glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter); diff --git a/rpcs3/Emu/RSX/VK/VKTexture.cpp b/rpcs3/Emu/RSX/VK/VKTexture.cpp index 7fb08b06fe..c51dcdf551 100644 --- a/rpcs3/Emu/RSX/VK/VKTexture.cpp +++ b/rpcs3/Emu/RSX/VK/VKTexture.cpp @@ -433,7 +433,11 @@ namespace vk CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data)); gsl::span mapped{ (gsl::byte*)(data + layout_alignment[0].second.offset), gsl::narrow(layout_alignment[0].second.size) }; - upload_placed_texture(mapped, tex, layout_alignment[0].first); + const std::vector &subresources_layout = get_subresources_layout(tex); + for (const rsx_subresource_layout &layout : subresources_layout) + { + upload_texture_subresource(mapped, layout, tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN), !(tex.format() & CELL_GCM_TEXTURE_LN), layout_alignment[0].first); + } vkUnmapMemory((*owner), vram_allocation); } else @@ -460,7 +464,13 @@ namespace vk CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data)); gsl::span mapped{ (gsl::byte*)(data), gsl::narrow(m_memory_layout.size) }; - upload_texture_mipmaps(mapped, tex, layout_offset_info); + const std::vector &subresources_layout = get_subresources_layout(tex); + size_t idx = 0; + for (const rsx_subresource_layout &layout : subresources_layout) + { + const auto &dst_layout = layout_offset_info[idx++]; + upload_texture_subresource(mapped.subspan(dst_layout.first), layout, tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN), !(tex.format() & CELL_GCM_TEXTURE_LN), dst_layout.second); + } vkUnmapMemory((*owner), vram_allocation); } }