rsx/common/d3d12/gl/vulkan: Unify texture upload code.

This commit is contained in:
Vincent Lejeune 2016-03-13 20:11:19 +01:00
parent e33c684b49
commit 5de70628d7
6 changed files with 296 additions and 364 deletions

View File

@ -29,11 +29,10 @@ namespace
struct copy_unmodified_block struct copy_unmodified_block
{ {
template<typename T, typename U> template<typename T, typename U>
static void copy_mipmap_level(gsl::span<T> 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<T> dst, gsl::span<const U> 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; size_t row_element_count = dst_pitch_in_block;
static_assert(sizeof(T) == sizeof(U), "Type size doesn't match."); static_assert(sizeof(T) == sizeof(U), "Type size doesn't match.");
gsl::span<const U> src{ src_ptr, row_count * src_pitch_in_block * depth };
for (int row = 0; row < row_count * depth; ++row) 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)); 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 struct copy_unmodified_block_swizzled
{ {
template<typename T, typename U> template<typename T, typename U>
static void copy_mipmap_level(gsl::span<T> 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<T> dst, gsl::span<const U> src, u16 width_in_block, u16 row_count, u16 depth, u32 dst_pitch_in_block)
{ {
std::unique_ptr<U[]> temp_swizzled(new U[width_in_block * row_count]); std::unique_ptr<U[]> temp_swizzled(new U[width_in_block * row_count]);
gsl::span<const U> src{ src_ptr, gsl::narrow<int>(width_in_block * row_count * depth) };
for (int d = 0; d < depth; ++d) for (int d = 0; d < depth; ++d)
{ {
rsx::convert_linear_swizzle<U>((void*)src.subspan(d * width_in_block * row_count).data(), temp_swizzled.get(), width_in_block, row_count, true); rsx::convert_linear_swizzle<U>((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
} }
}; };
/** namespace
* 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 <typename T, bool padded_row, u8 block_edge_in_texel, typename DST_TYPE, typename SRC_TYPE>
std::vector<MipmapLevelInfo> copy_texture_data(gsl::span<DST_TYPE> 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)
{ {
/** /**
* Note about size type: RSX texture width is stored in a 16 bits int and pitch is stored in a 20 bits int. * Texture upload template.
*/ *
* Source textures are stored as following (for power of 2 textures):
// <= 128 so fits in u8 * - 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.
u8 block_size_in_bytes = sizeof(DST_TYPE); * - 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
std::vector<MipmapLevelInfo> Result; * - Cubemap images are 128 bytes aligned.
size_t offsetInDst = 0, offsetInSrc = 0; *
// Always lower than width/height so fits in u16 * The template iterates over all depth (including cubemap) and over all mipmaps.
u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; * 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.
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++) template <u8 block_edge_in_texel, typename SRC_TYPE>
std::vector<rsx_subresource_layout> 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<rsx_subresource_layout> 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. u16 miplevel_height_in_block = texture_height_in_block, miplevel_width_in_block = texture_width_in_block;
u32 dst_pitch = align(miplevel_width_in_block * block_size_in_bytes, alignment) / block_size_in_bytes; 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 = {}; current_subresource_layout.data = gsl::span<const gsl::byte>(texture_data_pointer + offset_in_src, src_pitch_in_block * block_size_in_bytes * miplevel_height_in_block * depth);
currentMipmapLevelInfo.offset = offsetInDst;
// Since <= width/height, fits on 16 bits
currentMipmapLevelInfo.height = static_cast<u16>(miplevel_height_in_block * block_edge_in_texel);
currentMipmapLevelInfo.width = static_cast<u16>(miplevel_width_in_block * block_edge_in_texel);
currentMipmapLevelInfo.depth = depth;
currentMipmapLevelInfo.rowPitch = static_cast<u32>(dst_pitch * block_size_in_bytes);
Result.push_back(currentMipmapLevelInfo);
// TODO: uses src_pitch from texture result.push_back(current_subresource_layout);
// src_pitch in texture can uses 20 bits so fits on 32 bits int. offset_in_src += miplevel_height_in_block * src_pitch_in_block * block_size_in_bytes * depth;
u32 src_pitch_in_block = padded_row ? suggested_pitch_in_bytes / block_size_in_bytes : miplevel_width_in_block; miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1);
const SRC_TYPE *src_with_offset = reinterpret_cast<const SRC_TYPE*>(reinterpret_cast<const char*>(src) + offsetInSrc); miplevel_width_in_block = MAX2(miplevel_width_in_block / 2, 1);
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; offset_in_src = align(offset_in_src, 128);
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);
} }
offsetInSrc = align(offsetInSrc, 128); return result;
} }
return Result;
} }
/** template<typename T>
* Copy a single mipmap level starting at a given offset with a given rowpitch alignment u32 get_row_pitch_in_block(u16 width_in_block, size_t alignment_in_bytes)
*/
template <typename T, bool padded_row, u8 block_edge_in_texel, typename DST_TYPE, typename SRC_TYPE>
void copy_single_mipmap_layer(gsl::span<DST_TYPE> 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)
{ {
u8 block_size_in_bytes = sizeof(DST_TYPE); return static_cast<u32>(align(width_in_block * sizeof(T), alignment_in_bytes) / sizeof(T));
size_t offsetInSrc = 0; }
}
u16 texture_height_in_block = (height_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; std::vector<rsx_subresource_layout> get_subresources_layout(const rsx::texture &texture)
u16 texture_width_in_block = (width_in_texel + block_edge_in_texel - 1) / block_edge_in_texel; {
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; depth = 1;
for (unsigned mip_level = 0; mip_level < mipmap_count; mip_level++) layer = 1;
{ h = 1;
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; else if (texture.dimension() == 2)
const SRC_TYPE *src_with_offset = reinterpret_cast<const SRC_TYPE*>(reinterpret_cast<const char*>(src) + offsetInSrc); {
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 && int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
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;
}
offsetInSrc += miplevel_height_in_block * src_pitch_in_block * block_size_in_bytes * depth; const u32 texaddr = rsx::get_address(texture.offset(), texture.location());
miplevel_height_in_block = MAX2(miplevel_height_in_block / 2, 1); auto pixels = reinterpret_cast<const gsl::byte*>(vm::ps3::_ptr<const u8>(texaddr));
miplevel_width_in_block = MAX2(miplevel_width_in_block / 2, 1); 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<gsl::byte> 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<u32>(dst_buffer), gsl::as_span<const u32>(src_layout.data), w, h, depth, get_row_pitch_in_block<u32>(w, dst_row_alignment));
else
copy_unmodified_block::copy_mipmap_level(as_span_workaround<u32>(dst_buffer), gsl::as_span<const u32>(src_layout.data), w, h, depth, get_row_pitch_in_block<u32>(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<u16>(dst_buffer), gsl::as_span<const be_t<u16>>(src_layout.data), w, h, depth, get_row_pitch_in_block<u16>(w, dst_row_alignment));
else
copy_unmodified_block::copy_mipmap_level(as_span_workaround<u16>(dst_buffer), gsl::as_span<const be_t<u16>>(src_layout.data), w, h, depth, get_row_pitch_in_block<u16>(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<u64>(dst_buffer), gsl::as_span<const be_t<u64>>(src_layout.data), w, h, depth, get_row_pitch_in_block<u64>(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<u64>(dst_buffer), gsl::as_span<const u64>(src_layout.data), w, h, depth, get_row_pitch_in_block<u64>(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<u128>(dst_buffer), gsl::as_span<const u128>(src_layout.data), w, h, depth, get_row_pitch_in_block<u128>(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<u8>(dst_buffer), gsl::as_span<const u8>(src_layout.data), w, h, depth, get_row_pitch_in_block<u8>(w, dst_row_alignment));
else
copy_unmodified_block::copy_mipmap_level(as_span_workaround<u8>(dst_buffer), gsl::as_span<const u8>(src_layout.data), w, h, depth, get_row_pitch_in_block<u8>(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_TYPE> dst, const SRC_TYPE *src, u16
* A texture is stored as an array of blocks, where a block is a pixel for standard texture * 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 * 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) 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) switch (format)
{ {
@ -237,7 +301,6 @@ size_t get_texture_block_edge(u32 format)
return 0; return 0;
} }
} }
}
size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPitchAlignement, size_t mipmapAlignment) 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); 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); int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
size_t blockEdge = get_texture_block_edge(format); size_t blockEdge = get_format_block_size_in_texel(format);
size_t blockSizeInByte = get_texture_block_size(format); size_t blockSizeInByte = get_format_block_size_in_bytes(format);
size_t heightInBlocks = (h + blockEdge - 1) / blockEdge; size_t heightInBlocks = (h + blockEdge - 1) / blockEdge;
size_t widthInBlocks = (w + 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); return result * (texture.cubemap() ? 6 : 1);
} }
std::vector<MipmapLevelInfo> upload_placed_texture(gsl::span<gsl::byte> 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<MipmapLevelInfo> mipInfos;
const u32 texaddr = rsx::get_address(texture.offset(), texture.location());
auto pixels = vm::ps3::_ptr<const u8>(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<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u32>(mapped_buffer), reinterpret_cast<const u32*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 1>(as_span_workaround<u32>(mapped_buffer), reinterpret_cast<const u32*>(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<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
return copy_texture_data<copy_unmodified_block, true, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(pixels), 4 * w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
case CELL_GCM_TEXTURE_COMPRESSED_DXT1:
if (is_swizzled)
return copy_texture_data<copy_unmodified_block, false, 4>(as_span_workaround<u64>(mapped_buffer), reinterpret_cast<const u64*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 4>(as_span_workaround<u64>(mapped_buffer), reinterpret_cast<const u64*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
case CELL_GCM_TEXTURE_COMPRESSED_DXT23:
if (is_swizzled)
return copy_texture_data<copy_unmodified_block, false, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
case CELL_GCM_TEXTURE_COMPRESSED_DXT45:
if (is_swizzled)
return copy_texture_data<copy_unmodified_block, false, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
case CELL_GCM_TEXTURE_B8:
if (is_swizzled)
return copy_texture_data<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u8>(mapped_buffer), reinterpret_cast<const u8*>(pixels), w, h, depth, layer, texture.mipmap(), texture.pitch(), rowPitchAlignment);
else
return copy_texture_data<copy_unmodified_block, true, 1>(as_span_workaround<u8>(mapped_buffer), reinterpret_cast<const u8*>(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<gsl::byte> dst_buffer, const rsx::texture &texture, std::vector<std::pair<u64, u32>> 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<const u8>(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<gsl::byte> 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<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u32>(mapped_buffer), reinterpret_cast<const u32*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 1>(as_span_workaround<u32>(mapped_buffer), reinterpret_cast<const u32*>(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<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(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<copy_unmodified_block, true, 1>(as_span_workaround<u16>(mapped_buffer), reinterpret_cast<const be_t<u16>*>(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<copy_unmodified_block, false, 4>(as_span_workaround<u64>(mapped_buffer), reinterpret_cast<const u64*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 4>(as_span_workaround<u64>(mapped_buffer), reinterpret_cast<const u64*>(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<copy_unmodified_block, false, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(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<copy_unmodified_block, false, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 4>(as_span_workaround<u128>(mapped_buffer), reinterpret_cast<const u128*>(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<copy_unmodified_block_swizzled, false, 1>(as_span_workaround<u8>(mapped_buffer), reinterpret_cast<const u8*>(pixels), w, h, depth, layer, texture.mipmap(), mip_level, 0, texture.pitch(), alignment_offset_info[mip_level].second);
else
copy_single_mipmap_layer<copy_unmodified_block, true, 1>(as_span_workaround<u8>(mapped_buffer), reinterpret_cast<const u8*>(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) size_t get_texture_size(const rsx::texture &texture)
{ {

View File

@ -2,13 +2,13 @@
#include "../RSXTexture.h" #include "../RSXTexture.h"
#include <vector> #include <vector>
struct MipmapLevelInfo struct rsx_subresource_layout
{ {
size_t offset; gsl::span<const gsl::byte> data;
u16 width; u16 width_in_block;
u16 height; u16 height_in_block;
u16 depth; 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); size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPitchAlignement, size_t mipmapAlignment=512);
/** /**
* Write texture data to textureData. * get all rsx_subresource_layout for texture.
* Data are not packed, they are stored per rows using rowPitchAlignement. * The subresources are ordered per layer then per mipmap level (as in rsx memory).
* Similarly, offset for every mipmaplevel is aligned to rowPitchAlignement boundary. */
*/ std::vector<rsx_subresource_layout> get_subresources_layout(const rsx::texture &texture);
std::vector<MipmapLevelInfo> upload_placed_texture(gsl::span<gsl::byte> mapped_buffer, const rsx::texture &texture, size_t rowPitchAlignement);
/** void upload_texture_subresource(gsl::span<gsl::byte> dst_buffer, const rsx_subresource_layout &src_layout, int format, bool is_swizzled, size_t dst_row_alignment);
* 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 u8 get_format_block_size_in_bytes(int format);
* mipmap level individually. u8 get_format_block_size_in_texel(int format);
*/
void upload_texture_mipmaps(gsl::span<gsl::byte> dst_buffer, const rsx::texture &texture, std::vector<std::pair<u64, u32>> alignment_offset_info);
/** /**
* Get number of bytes occupied by texture in RSX mem * Get number of bytes occupied by texture in RSX mem

View File

@ -79,11 +79,6 @@ ComPtr<ID3D12Resource> upload_single_texture(
size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t buffer_size = get_placed_texture_storage_size(texture, 256);
size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size); size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
void *mapped_buffer_ptr = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
gsl::span<gsl::byte> mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow<int>(buffer_size) };
std::vector<MipmapLevelInfo> mipInfos = upload_placed_texture(mapped_buffer, texture, 256);
texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
ComPtr<ID3D12Resource> result; ComPtr<ID3D12Resource> result;
CHECK_HRESULT(device->CreateCommittedResource( CHECK_HRESULT(device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
@ -97,12 +92,35 @@ ComPtr<ID3D12Resource> upload_single_texture(
const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
DXGI_FORMAT dxgi_format = get_texture_format(format); DXGI_FORMAT dxgi_format = get_texture_format(format);
size_t mip_level = 0; size_t mip_level = 0;
for (const MipmapLevelInfo mli : mipInfos)
void *mapped_buffer_ptr = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
gsl::span<gsl::byte> mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow<int>(buffer_size) };
std::vector<rsx_subresource_layout> 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, 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++; 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)); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(result.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
return result; return result;
@ -124,20 +142,36 @@ void update_existing_texture(
size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t buffer_size = get_placed_texture_storage_size(texture, 256);
size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size); size_t heap_offset = texture_buffer_heap.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(buffer_size);
size_t mip_level = 0;
void *mapped_buffer_ptr = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); void *mapped_buffer_ptr = texture_buffer_heap.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
gsl::span<gsl::byte> mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow<int>(buffer_size) }; gsl::span<gsl::byte> mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, gsl::narrow<int>(buffer_size) };
std::vector<MipmapLevelInfo> mipInfos = upload_placed_texture(mapped_buffer, texture, 256); std::vector<rsx_subresource_layout> input_layouts = get_subresources_layout(texture);
texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); u8 block_size_in_bytes = get_format_block_size_in_bytes(format);
u8 block_size_in_texel = get_format_block_size_in_texel(format);
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST)); bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN);
size_t miplevel = 0; size_t offset_in_buffer = 0;
for (const MipmapLevelInfo mli : mipInfos) for (const rsx_subresource_layout &layout : input_layouts)
{ {
command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)miplevel), 0, 0, 0, upload_texture_subresource(mapped_buffer.subspan(offset_in_buffer), layout, format, is_swizzled, 256);
&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); UINT row_pitch = align(layout.width_in_block * block_size_in_bytes, 256);
miplevel++; 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)); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
} }

View File

@ -185,5 +185,6 @@ OPENGL_PROC(PFNGLTEXSTORAGE2DPROC, TexStorage2D);
OPENGL_PROC(PFNGLBLENDCOLORPROC, BlendColor); OPENGL_PROC(PFNGLBLENDCOLORPROC, BlendColor);
OPENGL_PROC(PFNGLBLENDEQUATIONPROC, BlendEquation); OPENGL_PROC(PFNGLBLENDEQUATIONPROC, BlendEquation);
OPENGL_PROC(PFNGLCOMPRESSEDTEXIMAGE2DPROC, CompressedTexImage2D); OPENGL_PROC(PFNGLCOMPRESSEDTEXIMAGE2DPROC, CompressedTexImage2D);
OPENGL_PROC(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, CompressedTexSubImage2D);
OPENGL_PROC(PFNGLACTIVETEXTUREPROC, ActiveTexture); OPENGL_PROC(PFNGLACTIVETEXTUREPROC, ActiveTexture);
#endif #endif

View File

@ -9,30 +9,62 @@
namespace namespace
{ {
std::tuple<GLenum, GLenum, GLenum> get_sized_internal_format_format_type(u32 texture_format) GLenum get_sized_internal_format(u32 texture_format)
{ {
switch (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_B8: return GL_R8;
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_A1R5G5B5: return GL_RGB5_A1;
case CELL_GCM_TEXTURE_A4R4G4B4: return std::make_tuple(GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4); case CELL_GCM_TEXTURE_A4R4G4B4: return GL_RGBA4;
case CELL_GCM_TEXTURE_R5G6B5: return std::make_tuple(GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); case CELL_GCM_TEXTURE_R5G6B5: return GL_RGB565;
case CELL_GCM_TEXTURE_A8R8G8B8: return std::make_tuple(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); case CELL_GCM_TEXTURE_A8R8G8B8: return GL_RGBA8;
case CELL_GCM_TEXTURE_G8B8: return std::make_tuple(GL_RG8, GL_RG, GL_UNSIGNED_BYTE); case CELL_GCM_TEXTURE_G8B8: return GL_RG8;
case CELL_GCM_TEXTURE_R6G5B5: return std::make_tuple(GL_RGB565, GL_RGBA, GL_UNSIGNED_BYTE); case CELL_GCM_TEXTURE_R6G5B5: return GL_RGB565;
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: return GL_DEPTH_COMPONENT24;
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_FLOAT); case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: return GL_DEPTH_COMPONENT24;
case CELL_GCM_TEXTURE_DEPTH16: return std::make_tuple(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_SHORT); case CELL_GCM_TEXTURE_DEPTH16: return GL_DEPTH_COMPONENT16;
case CELL_GCM_TEXTURE_DEPTH16_FLOAT: return std::make_tuple(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_FLOAT); case CELL_GCM_TEXTURE_DEPTH16_FLOAT: return GL_DEPTH_COMPONENT16;
case CELL_GCM_TEXTURE_X16: return std::make_tuple(GL_R16, GL_RED, GL_UNSIGNED_SHORT); case CELL_GCM_TEXTURE_X16: return GL_R16;
case CELL_GCM_TEXTURE_Y16_X16: return std::make_tuple(GL_RG16, GL_RG, GL_UNSIGNED_SHORT); case CELL_GCM_TEXTURE_Y16_X16: return GL_RG16;
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_R5G5B5A1: return GL_RGB5_A1;
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return std::make_tuple(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT); case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: return GL_RGBA16F;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return std::make_tuple(GL_RGBA32F, GL_RGBA, GL_FLOAT); case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: return GL_RGBA32F;
case CELL_GCM_TEXTURE_X32_FLOAT: return std::make_tuple(GL_R32F, GL_RED, GL_FLOAT); case CELL_GCM_TEXTURE_X32_FLOAT: return GL_R32F;
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_D1R5G5B5: return GL_RGB5_A1;
case CELL_GCM_TEXTURE_D8R8G8B8: return std::make_tuple(GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8); case CELL_GCM_TEXTURE_D8R8G8B8: return GL_RGBA8;
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return std::make_tuple(GL_RG16F, GL_RG, GL_HALF_FLOAT); 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<GLenum, GLenum> 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); throw EXCEPTION("Compressed or unknown texture format %x", texture_format);
} }
@ -283,62 +315,31 @@ namespace rsx
u32 aligned_pitch = tex.pitch(); u32 aligned_pitch = tex.pitch();
size_t texture_data_sz = get_placed_texture_storage_size(tex, 256); size_t texture_data_sz = get_placed_texture_storage_size(tex, 256);
std::vector<u8> data_upload_buf(texture_data_sz); std::vector<gsl::byte> data_upload_buf(texture_data_sz);
u8* texture_data = data_upload_buf.data();
u32 block_sz = get_pitch_modifier(format); u32 block_sz = get_pitch_modifier(format);
if (is_swizzled || mandates_expansion(format)) const std::vector<rsx_subresource_layout> &input_layouts = get_subresources_layout(tex);
{ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
aligned_pitch = align(aligned_pitch, 256); glTexStorage2D(m_target, tex.mipmap(), get_sized_internal_format(format), tex.width(), tex.height());
upload_placed_texture({ reinterpret_cast<gsl::byte*>(texture_data), gsl::narrow<int>(texture_data_sz) }, tex, 256);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
else
{
texture_data = vm::ps3::_ptr<u8>(texaddr);
}
if (block_sz)
aligned_pitch /= block_sz;
else
aligned_pitch = 0;
glPixelStorei(GL_UNPACK_ROW_LENGTH, aligned_pitch);
if (!is_compressed_format(format)) if (!is_compressed_format(format))
{ {
const auto &sized_internal_format_format_type = get_sized_internal_format_format_type(format); const auto &format_type = get_format_type(format);
glTexStorage2D(m_target, tex.mipmap(), std::get<0>(sized_internal_format_format_type), tex.width(), tex.height()); GLint mip_level = 0;
if (requires_unpack_byte(format)) for (const rsx_subresource_layout &layout : input_layouts)
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); upload_texture_subresource(data_upload_buf, layout, format, is_swizzled, 4);
if (requires_unpack_byte(format)) 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());
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); }
} }
else 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; u32 size = layout.width_in_block * layout.height_in_block * ((format == CELL_GCM_TEXTURE_COMPRESSED_DXT1) ? 8 : 16);
glCompressedTexImage2D(m_target, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.width(), tex.height(), 0, size, texture_data); 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());
}
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;
}
} }
} }
@ -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); LOG_WARNING(RSX, "Texture %d, target 0x%X, requesting mipmap filtering without any mipmaps set!", m_id, m_target);
min_filter = GL_LINEAR; min_filter = GL_LINEAR;
} }
else
{
//TODO: Check if the call succeeded
glGenerateMipmap(m_target);
}
} }
glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter); glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter);

View File

@ -433,7 +433,11 @@ namespace vk
CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data)); CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data));
gsl::span<gsl::byte> mapped{ (gsl::byte*)(data + layout_alignment[0].second.offset), gsl::narrow<int>(layout_alignment[0].second.size) }; gsl::span<gsl::byte> mapped{ (gsl::byte*)(data + layout_alignment[0].second.offset), gsl::narrow<int>(layout_alignment[0].second.size) };
upload_placed_texture(mapped, tex, layout_alignment[0].first); const std::vector<rsx_subresource_layout> &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); vkUnmapMemory((*owner), vram_allocation);
} }
else else
@ -460,7 +464,13 @@ namespace vk
CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data)); CHECK_RESULT(vkMapMemory((*owner), vram_allocation, 0, m_memory_layout.size, 0, (void**)&data));
gsl::span<gsl::byte> mapped{ (gsl::byte*)(data), gsl::narrow<int>(m_memory_layout.size) }; gsl::span<gsl::byte> mapped{ (gsl::byte*)(data), gsl::narrow<int>(m_memory_layout.size) };
upload_texture_mipmaps(mapped, tex, layout_offset_info); const std::vector<rsx_subresource_layout> &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); vkUnmapMemory((*owner), vram_allocation);
} }
} }