diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h index f9ecd4eb9c..f29905d225 100644 --- a/rpcs3/Emu/RSX/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -333,7 +333,7 @@ public: auto& vmfprog = vm::ps3::_ref(ptr + vmprog.program); u32 size; u32 ctrl = (vmfprog.outputFromH0 ? 0 : 0x40) | (vmfprog.depthReplace ? 0xe : 0); - std::vector td; + std::vector td; RSXFragmentProgram prog; prog.size = 0, prog.addr = vm::base(ptr + vmprog.ucode), prog.offset = 0, prog.ctrl = ctrl; GLFragmentDecompilerThread(m_glsl_shader, param_array, prog, size).Task(); diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index c35750f819..6e1ec3c1b2 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -130,16 +130,16 @@ std::string FragmentProgramDecompiler::AddTex() std::string sampler; switch (m_prog.get_texture_dimension(dst.tex_num)) { - case texture_dimension_extended::texture_dimension_1d: + case rsx::texture_dimension_extended::texture_dimension_1d: sampler = "sampler1D"; break; - case texture_dimension_extended::texture_dimension_cubemap: + case rsx::texture_dimension_extended::texture_dimension_cubemap: sampler = "samplerCube"; break; - case texture_dimension_extended::texture_dimension_2d: + case rsx::texture_dimension_extended::texture_dimension_2d: sampler = "sampler2D"; break; - case texture_dimension_extended::texture_dimension_3d: + case rsx::texture_dimension_extended::texture_dimension_3d: sampler = "sampler3D"; break; } @@ -442,16 +442,16 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case RSX_FP_OPCODE_TEX: switch (m_prog.get_texture_dimension(dst.tex_num)) { - case texture_dimension_extended::texture_dimension_1d: + case rsx::texture_dimension_extended::texture_dimension_1d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D)); return true; - case texture_dimension_extended::texture_dimension_2d: + case rsx::texture_dimension_extended::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D)); return true; - case texture_dimension_extended::texture_dimension_cubemap: + case rsx::texture_dimension_extended::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE)); return true; - case texture_dimension_extended::texture_dimension_3d: + case rsx::texture_dimension_extended::texture_dimension_3d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D)); return true; } @@ -460,16 +460,16 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case RSX_FP_OPCODE_TXP: switch (m_prog.get_texture_dimension(dst.tex_num)) { - case texture_dimension_extended::texture_dimension_1d: + case rsx::texture_dimension_extended::texture_dimension_1d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ)); return true; - case texture_dimension_extended::texture_dimension_2d: + case rsx::texture_dimension_extended::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ)); return true; - case texture_dimension_extended::texture_dimension_cubemap: + case rsx::texture_dimension_extended::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ)); return true; - case texture_dimension_extended::texture_dimension_3d: + case rsx::texture_dimension_extended::texture_dimension_3d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ)); return true; } @@ -480,16 +480,16 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) case RSX_FP_OPCODE_TXL: switch (m_prog.get_texture_dimension(dst.tex_num)) { - case texture_dimension_extended::texture_dimension_1d: + case rsx::texture_dimension_extended::texture_dimension_1d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD)); return true; - case texture_dimension_extended::texture_dimension_2d: + case rsx::texture_dimension_extended::texture_dimension_2d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD)); return true; - case texture_dimension_extended::texture_dimension_cubemap: + case rsx::texture_dimension_extended::texture_dimension_cubemap: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD)); return true; - case texture_dimension_extended::texture_dimension_3d: + case rsx::texture_dimension_extended::texture_dimension_3d: SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD)); return true; } diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index c129acfe94..b6c12ac512 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -116,32 +116,32 @@ u32 get_row_pitch_in_block(u16 width_in_block, size_t multiple_constraints_in_by size_t divided = (width_in_block * sizeof(T) + multiple_constraints_in_byte - 1) / multiple_constraints_in_byte; return static_cast(divided * multiple_constraints_in_byte / sizeof(T)); } + +/** + * Since rsx ignore unused dimensionnality some app set them to 0. + * Use 1 value instead to be more general. + */ +std::tuple get_height_depth_layer(const rsx::texture &tex) +{ + switch (tex.get_extended_texture_dimension()) + { + case rsx::texture_dimension_extended::texture_dimension_1d: return std::make_tuple(1, 1, 1); + case rsx::texture_dimension_extended::texture_dimension_2d: return std::make_tuple(tex.height(), 1, 1); + case rsx::texture_dimension_extended::texture_dimension_cubemap: return std::make_tuple(tex.height(), 1, 6); + case rsx::texture_dimension_extended::texture_dimension_3d: return std::make_tuple(tex.height(), tex.depth(), 1); + } + throw EXCEPTION("Unsupported texture dimension"); +} } std::vector get_subresources_layout(const rsx::texture &texture) { - u16 w = texture.width(), h = texture.height(); + u16 w = texture.width(); + u16 h; u16 depth; u8 layer; - if (texture.dimension() == rsx::texture_dimension::dimension1d) - { - depth = 1; - layer = 1; - h = 1; - } - else if (texture.dimension() == rsx::texture_dimension::dimension2d) - { - depth = 1; - layer = texture.cubemap() ? 6 : 1; - } - else if (texture.dimension() == rsx::texture_dimension::dimension3d) - { - depth = texture.depth(); - layer = 1; - } - else - throw EXCEPTION("Unsupported texture dimension %d", texture.dimension()); + std::tie(h, depth, layer) = get_height_depth_layer(texture); int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); @@ -152,7 +152,7 @@ std::vector get_subresources_layout(const rsx::texture & { 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); + return get_subresources_layout_impl<1, u32>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), texture.pitch(), !is_swizzled); case CELL_GCM_TEXTURE_DEPTH16: case CELL_GCM_TEXTURE_D1R5G5B5: case CELL_GCM_TEXTURE_A1R5G5B5: @@ -160,16 +160,16 @@ std::vector get_subresources_layout(const rsx::texture & 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); + return get_subresources_layout_impl<1, u16>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), 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); + return get_subresources_layout_impl<1, u64>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), 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); + return get_subresources_layout_impl<4, u64>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), 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); + return get_subresources_layout_impl<4, u128>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), 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); + return get_subresources_layout_impl<1, u8>(pixels, w, h, depth, layer, texture.get_exact_mipmap_count(), texture.pitch(), !is_swizzled); } throw EXCEPTION("Wrong format %d", format); } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 0a566f248c..bf95ed99a8 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -47,18 +47,15 @@ namespace const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); DXGI_FORMAT dxgi_format = get_texture_format(format); - if (texture.dimension() == rsx::texture_dimension::dimension1d) + switch (texture.get_extended_texture_dimension()) { + case rsx::texture_dimension_extended::texture_dimension_1d: return CD3DX12_RESOURCE_DESC::Tex1D(dxgi_format, texture.width(), 1, texture.get_exact_mipmap_count()); - } - else if (texture.dimension() == rsx::texture_dimension::dimension2d) - { -// if (texture.depth() < 2); - size_t depth = (texture.cubemap()) ? 6 : 1; - return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), (UINT)depth, texture.get_exact_mipmap_count()); - } - else if (texture.dimension() == rsx::texture_dimension::dimension3d) - { + case rsx::texture_dimension_extended::texture_dimension_2d: + return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), 1, texture.get_exact_mipmap_count()); + case rsx::texture_dimension_extended::texture_dimension_cubemap: + return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, texture.width(), texture.height(), 6, texture.get_exact_mipmap_count()); + case rsx::texture_dimension_extended::texture_dimension_3d: return CD3DX12_RESOURCE_DESC::Tex3D(dxgi_format, texture.width(), texture.height(), texture.depth(), texture.get_exact_mipmap_count()); } throw EXCEPTION("Unknow texture dimension"); @@ -146,31 +143,26 @@ ComPtr upload_single_texture( D3D12_SHADER_RESOURCE_VIEW_DESC get_srv_descriptor_with_dimensions(const rsx::texture &tex) { D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {}; - if (tex.dimension() == rsx::texture_dimension::dimension1d) + switch (tex.get_extended_texture_dimension()) { + case rsx::texture_dimension_extended::texture_dimension_1d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; shared_resource_view_desc.Texture1D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; - } - if (tex.dimension() == rsx::texture_dimension::dimension2d) - { - if (tex.cubemap()) - { - shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - shared_resource_view_desc.TextureCube.MipLevels = tex.get_exact_mipmap_count(); - return shared_resource_view_desc; - } + case rsx::texture_dimension_extended::texture_dimension_2d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shared_resource_view_desc.Texture2D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; - } - if (tex.dimension() == rsx::texture_dimension::dimension3d) - { + case rsx::texture_dimension_extended::texture_dimension_cubemap: + shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + shared_resource_view_desc.TextureCube.MipLevels = tex.get_exact_mipmap_count(); + return shared_resource_view_desc; + case rsx::texture_dimension_extended::texture_dimension_3d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; shared_resource_view_desc.Texture3D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; } - throw EXCEPTION("Wrong texture dimension %d", tex.dimension()); + throw EXCEPTION("Wrong texture dimension"); } } diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index f403294dcf..a82e97bd8d 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -1,5 +1,6 @@ #pragma once #include "GCM.h" +#include "RSXTexture.h" enum { @@ -205,18 +206,6 @@ static const std::string rsx_fp_op_names[] = "NULL", "BRK", "CAL", "IFE", "LOOP", "REP", "RET" }; - -/** - * Use an extra cubemap format - */ -enum class texture_dimension_extended : u8 -{ - texture_dimension_1d = 0, - texture_dimension_2d = 1, - texture_dimension_cubemap = 2, - texture_dimension_3d = 3, -}; - struct RSXFragmentProgram { u32 size; @@ -234,15 +223,15 @@ struct RSXFragmentProgram rsx::fog_mode fog_equation; u16 height; - texture_dimension_extended get_texture_dimension(u8 id) const + rsx::texture_dimension_extended get_texture_dimension(u8 id) const { - return (texture_dimension_extended)((texture_dimensions >> (id * 2)) & 0x3); + return (rsx::texture_dimension_extended)((texture_dimensions >> (id * 2)) & 0x3); } - void set_texture_dimension(const std::array &dimensions) + void set_texture_dimension(const std::array &dimensions) { size_t id = 0; - for (const texture_dimension_extended &dim : dimensions) + for (const rsx::texture_dimension_extended &dim : dimensions) { texture_dimensions &= ~(0x3 << (id * 2)); u8 d = (u8)dim; diff --git a/rpcs3/Emu/RSX/RSXTexture.cpp b/rpcs3/Emu/RSX/RSXTexture.cpp index e638feec05..044631a44d 100644 --- a/rpcs3/Emu/RSX/RSXTexture.cpp +++ b/rpcs3/Emu/RSX/RSXTexture.cpp @@ -65,11 +65,31 @@ namespace rsx return rsx::to_texture_dimension((method_registers[NV4097_SET_TEXTURE_FORMAT + (m_index * 8)] >> 4) & 0xf); } + rsx::texture_dimension_extended texture::get_extended_texture_dimension() const + { + switch (dimension()) + { + case rsx::texture_dimension::dimension1d: return rsx::texture_dimension_extended::texture_dimension_1d; + case rsx::texture_dimension::dimension3d: return rsx::texture_dimension_extended::texture_dimension_2d; + case rsx::texture_dimension::dimension2d: return cubemap() ? rsx::texture_dimension_extended::texture_dimension_cubemap : rsx::texture_dimension_extended::texture_dimension_2d; + } + } + u8 texture::format() const { return ((method_registers[NV4097_SET_TEXTURE_FORMAT + (m_index * 8)] >> 8) & 0xff); } + bool texture::is_compressed_format() const + { + int texture_format = format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + if (texture_format == CELL_GCM_TEXTURE_COMPRESSED_DXT1 || + texture_format == CELL_GCM_TEXTURE_COMPRESSED_DXT23 || + texture_format == CELL_GCM_TEXTURE_COMPRESSED_DXT45) + return true; + return false; + } + u16 texture::mipmap() const { return ((method_registers[NV4097_SET_TEXTURE_FORMAT + (m_index * 8)] >> 16) & 0xffff); @@ -77,7 +97,14 @@ namespace rsx u16 texture::get_exact_mipmap_count() const { - u16 max_mipmap_count = static_cast(floor(log2(std::max(width(), height()))) + 1); + if (is_compressed_format()) + { + // OpenGL considers that highest mipmap level for DXTC format is when either width or height is 1 + // not both. Assume it's the same for others backend. + u16 max_mipmap_count = static_cast(floor(log2(std::min(width() / 4, height() / 4))) + 1); + return std::min(mipmap(), max_mipmap_count); + } + u16 max_mipmap_count = static_cast(floor(log2(std::max(width(), height()))) + 1) - 2; return std::min(mipmap(), max_mipmap_count); } diff --git a/rpcs3/Emu/RSX/RSXTexture.h b/rpcs3/Emu/RSX/RSXTexture.h index 724caad77a..e776267b3d 100644 --- a/rpcs3/Emu/RSX/RSXTexture.h +++ b/rpcs3/Emu/RSX/RSXTexture.h @@ -3,6 +3,17 @@ namespace rsx { + /** + * Use an extra cubemap format + */ + enum class texture_dimension_extended : u8 + { + texture_dimension_1d = 0, + texture_dimension_2d = 1, + texture_dimension_cubemap = 2, + texture_dimension_3d = 3, + }; + class texture { protected: @@ -20,7 +31,14 @@ namespace rsx bool cubemap() const; u8 border_type() const; rsx::texture_dimension dimension() const; + /** + * 2d texture can be either plane or cubemap texture depending on cubemap bit. + * Since cubemap is a format per se in all gfx API this function directly returns + * cubemap as a separate dimension. + */ + rsx::texture_dimension_extended get_extended_texture_dimension() const; u8 format() const; + bool is_compressed_format() const; u16 mipmap() const; /** * mipmap() returns value from register which can be higher than the actual number of mipmap level. diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 3cafd5b58d..7def771356 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -724,19 +724,8 @@ namespace rsx { if (!textures[i].enabled()) texture_dimensions[i] = texture_dimension_extended::texture_dimension_2d; - else if (textures[i].dimension() == rsx::texture_dimension::dimension1d) - texture_dimensions[i] = texture_dimension_extended::texture_dimension_1d; - else if (textures[i].dimension() == rsx::texture_dimension::dimension2d) - { - if (textures[i].cubemap()) - texture_dimensions[i] = texture_dimension_extended::texture_dimension_cubemap; - else - texture_dimensions[i] = texture_dimension_extended::texture_dimension_2d; - } - else if (textures[i].dimension() == rsx::texture_dimension::dimension3d) - texture_dimensions[i] = texture_dimension_extended::texture_dimension_3d; else - throw EXCEPTION("Unable to determine texture dimension"); + texture_dimensions[i] = textures[i].get_extended_texture_dimension(); if (textures[i].enabled() && (textures[i].format() & CELL_GCM_TEXTURE_UN)) result.unnormalized_coords |= (1 << i); }