diff --git a/Utilities/File.cpp b/Utilities/File.cpp index bea4bc905c..896fda922b 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1207,7 +1207,7 @@ const std::string& fs::get_executable_dir() return s_dir; } -void fs::remove_all(const std::string& path) +void fs::remove_all(const std::string& path, bool remove_root) { for (const auto& entry : dir(path)) { @@ -1227,7 +1227,10 @@ void fs::remove_all(const std::string& path) } } - remove_dir(path); + if (remove_root) + { + remove_dir(path); + } } u64 fs::get_dir_size(const std::string& path) diff --git a/Utilities/File.h b/Utilities/File.h index 5fd7645fd4..aaa2c9ee41 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -440,7 +440,7 @@ namespace fs const std::string& get_executable_dir(); // Delete directory and all its contents recursively - void remove_all(const std::string& path); + void remove_all(const std::string& path, bool remove_root = true); // Get size of all files recursively u64 get_dir_size(const std::string& path); diff --git a/bin/data/.gitignore b/bin/data/.gitignore deleted file mode 100644 index 5e7d2734cf..0000000000 --- a/bin/data/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/bin/data/cache/.gitignore b/bin/data/cache/.gitignore deleted file mode 100644 index 5e7d2734cf..0000000000 --- a/bin/data/cache/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index 960512b5af..15769117be 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -120,7 +120,8 @@ u32 get_row_pitch_in_block(u16 width_in_block, size_t multiple_constraints_in_by * 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) +template +std::tuple get_height_depth_layer(const RsxTextureType &tex) { switch (tex.get_extended_texture_dimension()) { @@ -133,7 +134,8 @@ std::tuple get_height_depth_layer(const rsx::texture &tex) } } -std::vector get_subresources_layout(const rsx::texture &texture) +template +std::vector get_subresources_layout_impl(const RsxTextureType &texture) { u16 w = texture.width(); u16 h; @@ -184,6 +186,16 @@ std::vector get_subresources_layout(const rsx::texture & throw EXCEPTION("Wrong format 0x%x", format); } +std::vector get_subresources_layout(const rsx::texture &texture) +{ + return get_subresources_layout_impl(texture); +} + +std::vector get_subresources_layout(const rsx::vertex_texture &texture) +{ + return get_subresources_layout_impl(texture); +} + void upload_texture_subresource(gsl::span dst_buffer, const rsx_subresource_layout &src_layout, int format, bool is_swizzled, size_t dst_row_pitch_multiple_of) { u16 w = src_layout.width_in_block; @@ -339,36 +351,48 @@ u8 get_format_block_size_in_texel(int format) } } - -size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t rowPitchAlignement, size_t mipmapAlignment) +static size_t get_placed_texture_storage_size(u16 width, u16 height, u32 depth, u8 format, u16 mipmap, bool cubemap, size_t row_pitch_alignement, size_t mipmap_alignment) { - size_t w = texture.width(), h = texture.height(), d = std::max(texture.depth(), 1); + size_t w = width; + size_t h = std::max(height, 1); + size_t d = std::max(depth, 1); - int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - size_t blockEdge = get_format_block_size_in_texel(format); - size_t blockSizeInByte = get_format_block_size_in_bytes(format); + format &= ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + size_t block_edge = get_format_block_size_in_texel(format); + size_t block_size_in_byte = get_format_block_size_in_bytes(format); - size_t heightInBlocks = (h + blockEdge - 1) / blockEdge; - size_t widthInBlocks = (w + blockEdge - 1) / blockEdge; + size_t height_in_blocks = (h + block_edge - 1) / block_edge; + size_t width_in_blocks = (w + block_edge - 1) / block_edge; size_t result = 0; - for (unsigned mipmap = 0; mipmap < texture.mipmap(); ++mipmap) + for (u16 i = 0; i < mipmap; ++i) { - size_t rowPitch = align(blockSizeInByte * widthInBlocks, rowPitchAlignement); - result += align(rowPitch * heightInBlocks * d, mipmapAlignment); - heightInBlocks = std::max(heightInBlocks / 2, 1); - widthInBlocks = std::max(widthInBlocks / 2, 1); + size_t rowPitch = align(block_size_in_byte * width_in_blocks, row_pitch_alignement); + result += align(rowPitch * height_in_blocks * d, mipmap_alignment); + height_in_blocks = std::max(height_in_blocks / 2, 1); + width_in_blocks = std::max(width_in_blocks / 2, 1); } - return result * (texture.cubemap() ? 6 : 1); + return result * (cubemap ? 6 : 1); +} + +size_t get_placed_texture_storage_size(const rsx::texture &texture, size_t row_pitch_alignement, size_t mipmap_alignment) +{ + return get_placed_texture_storage_size(texture.width(), texture.height(), texture.depth(), texture.format(), texture.mipmap(), texture.cubemap(), + row_pitch_alignement, mipmap_alignment); +} + +size_t get_placed_texture_storage_size(const rsx::vertex_texture &texture, size_t row_pitch_alignement, size_t mipmap_alignment) +{ + return get_placed_texture_storage_size(texture.width(), texture.height(), texture.depth(), texture.format(), texture.mipmap(), texture.cubemap(), + row_pitch_alignement, mipmap_alignment); } -size_t get_texture_size(const rsx::texture &texture) +static size_t get_texture_size(u32 w, u32 h, u8 format) { - size_t w = texture.width(), h = texture.height(); + format &= ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); - int format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); // TODO: Take mipmaps into account switch (format) { @@ -434,3 +458,13 @@ size_t get_texture_size(const rsx::texture &texture) return 0; } } + +size_t get_texture_size(const rsx::texture &texture) +{ + return get_texture_size(texture.width(), texture.height(), texture.format()); +} + +size_t get_texture_size(const rsx::vertex_texture &texture) +{ + return get_texture_size(texture.width(), texture.height(), texture.format()); +} diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.h b/rpcs3/Emu/RSX/Common/TextureUtils.h index c88a6a558a..c45c453841 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.h +++ b/rpcs3/Emu/RSX/Common/TextureUtils.h @@ -18,13 +18,15 @@ struct rsx_subresource_layout * Get size to store texture in a linear fashion. * Storage is assumed to use a rowPitchAlignement boundary for every row of texture. */ -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 row_pitch_alignement, size_t mipmap_alignment = 0x200); +size_t get_placed_texture_storage_size(const rsx::vertex_texture &texture, size_t row_pitch_alignement, size_t mipmap_alignment = 0x200); /** * 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); +std::vector get_subresources_layout(const rsx::vertex_texture &texture); void upload_texture_subresource(gsl::span dst_buffer, const rsx_subresource_layout &src_layout, int format, bool is_swizzled, size_t dst_row_pitch_multiple_of); @@ -35,3 +37,4 @@ u8 get_format_block_size_in_texel(int format); * Get number of bytes occupied by texture in RSX mem */ size_t get_texture_size(const rsx::texture &texture); +size_t get_texture_size(const rsx::vertex_texture &texture); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 56c4b4d9eb..aeacddc532 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -235,6 +235,18 @@ namespace } throw EXCEPTION("Unknow texture target"); } + + GLenum get_gl_target_for_texture(const rsx::vertex_texture& tex) + { + switch (tex.get_extended_texture_dimension()) + { + case rsx::texture_dimension_extended::texture_dimension_1d: return GL_TEXTURE_1D; + case rsx::texture_dimension_extended::texture_dimension_2d: return GL_TEXTURE_2D; + case rsx::texture_dimension_extended::texture_dimension_cubemap: return GL_TEXTURE_CUBE_MAP; + case rsx::texture_dimension_extended::texture_dimension_3d: return GL_TEXTURE_3D; + } + throw EXCEPTION("Unknow texture target"); + } } void GLGSRender::end() @@ -295,7 +307,6 @@ void GLGSRender::end() //setup textures { - //int texture_index = 0; for (int i = 0; i < rsx::limits::textures_count; ++i) { int location; @@ -311,12 +322,9 @@ void GLGSRender::end() } m_gl_textures[i].set_target(get_gl_target_for_texture(textures[i])); + __glcheck m_gl_texture_cache.upload_texture(i, textures[i], m_gl_textures[i], m_rtts); - __glcheck glProgramUniform1i(m_program->id(), location, i); - //__glcheck m_gl_textures[i].init(i, textures[i]); - - //texture_index++; if (m_program->uniforms.has_location("ftexture" + std::to_string(i) + "_cm", &location)) { @@ -331,21 +339,39 @@ void GLGSRender::end() } } } - /* + for (int i = 0; i < rsx::limits::vertex_textures_count; ++i) { - if (vertex_textures[i].enabled()) + int location; + if (m_program->uniforms.has_location("vtexture" + std::to_string(i), &location)) { - int location; - if (m_program->uniforms.has_location("vtexture" + std::to_string(i), &location)) + if (!textures[i].enabled()) { - glProgramUniform1i(m_program->id(), location, texture_index); - m_gl_vertex_textures[i].init(texture_index, vertex_textures[i]); - texture_index++; + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + glProgramUniform1i(m_program->id(), location, i); + + continue; + } + + m_gl_vertex_textures[i].set_target(get_gl_target_for_texture(vertex_textures[i])); + + __glcheck m_gl_texture_cache.upload_texture(i, vertex_textures[i], m_gl_vertex_textures[i], m_rtts); + __glcheck glProgramUniform1i(m_program->id(), location, i); + + if (m_program->uniforms.has_location("vtexture" + std::to_string(i) + "_cm", &location)) + { + if (textures[i].format() & CELL_GCM_TEXTURE_UN) + { + u32 width = std::max(textures[i].width(), 1); + u32 height = std::max(textures[i].height(), 1); + u32 depth = std::max(textures[i].depth(), 1); + + glProgramUniform4f(m_program->id(), location, 1.f / width, 1.f / height, 1.f / depth, 1.0f); + } } } } - */ } u32 offset_in_index_buffer = set_vertex_buffer(); diff --git a/rpcs3/Emu/RSX/GL/gl_texture_cache.h b/rpcs3/Emu/RSX/GL/gl_texture_cache.h index ceedf7f19b..9a0fb0f44d 100644 --- a/rpcs3/Emu/RSX/GL/gl_texture_cache.h +++ b/rpcs3/Emu/RSX/GL/gl_texture_cache.h @@ -424,7 +424,8 @@ namespace gl } } - void upload_texture(int index, rsx::texture &tex, rsx::gl::texture &gl_texture, gl_render_targets &m_rtts) + template + void upload_texture(int index, RsxTextureType &tex, rsx::gl::texture &gl_texture, gl_render_targets &m_rtts) { const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); const u32 range = (u32)get_texture_size(tex); @@ -458,7 +459,7 @@ namespace gl if (texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) { - texptr->bind(); + texptr->bind(); return; } diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp index bced7df7fc..2b237d7188 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_cache.cpp @@ -127,7 +127,6 @@ static void insert_texture_lod_fetch_function(std::string &dst, const rsx::decom dst += "}\n"; } - static void insert_texture_proj_fetch_function(std::string &dst, const rsx::decompiled_shader &shader, const rsx::program_state &state) { if (shader.textures.empty()) @@ -237,26 +236,6 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, result.code += "\n"; - for (const rsx::texture_info& texture : shader.textures) - { - result.code += "uniform vec4 " + texture.name + "_cm = vec4(1.0);\n"; - - rsx::texture_target target = state.textures[texture.id]; - - - result.code += "uniform sampler"; - - switch (target) - { - default: - case rsx::texture_target::_1: result.code += "1D"; break; - case rsx::texture_target::_2: result.code += "2D"; break; - case rsx::texture_target::_3: result.code += "3D"; break; - case rsx::texture_target::cube: result.code += "Cube"; break; - } - result.code += " " + texture.name + ";\n"; - } - std::string prepare; std::string finalize; int location = 1; @@ -264,6 +243,24 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, switch (shader.raw->type) { case rsx::program_type::fragment: + for (const rsx::texture_info& texture : shader.textures) + { + result.code += "uniform vec4 " + texture.name + "_cm = vec4(1.0);\n"; + rsx::texture_target target = state.textures[texture.id]; + + result.code += "uniform sampler"; + + switch (target) + { + default: + case rsx::texture_target::_1: result.code += "1D"; break; + case rsx::texture_target::_2: result.code += "2D"; break; + case rsx::texture_target::_3: result.code += "3D"; break; + case rsx::texture_target::cube: result.code += "Cube"; break; + } + result.code += " " + texture.name + ";\n"; + } + insert_texture_fetch_function(result.code, shader, state); insert_texture_bias_fetch_function(result.code, shader, state); insert_texture_grad_fetch_function(result.code, shader, state); @@ -524,20 +521,33 @@ rsx::complete_shader glsl_complete_shader(const rsx::decompiled_shader &shader, break; case rsx::program_type::vertex: + for (const rsx::texture_info& texture : shader.textures) + { + result.code += "uniform vec4 " + texture.name + "_cm = vec4(1.0);\n"; + + rsx::texture_target target = state.vertex_textures[texture.id]; + + result.code += "uniform sampler"; + + switch (target) + { + default: + case rsx::texture_target::_1: result.code += "1D"; break; + case rsx::texture_target::_2: result.code += "2D"; break; + case rsx::texture_target::_3: result.code += "3D"; break; + case rsx::texture_target::cube: result.code += "Cube"; break; + } + result.code += " " + texture.name + ";\n"; + } + + insert_texture_lod_fetch_function(result.code, shader, state); + result.code += "out vec4 wpos;\n"; - - // TODO - if (0) - { - finalize += "\tgl_Position = o0;\n"; - } - else - { - finalize += - " wpos = window_matrix * viewport_matrix * vec4(o0.xyz, 1.0);\n" - " gl_Position = normalize_matrix * vec4(wpos.xyz, 1.0);\n" - " gl_Position.w = o0.w;\n"; - } + + finalize += + " wpos = window_matrix * viewport_matrix * vec4(o0.xyz, 1.0);\n" + " gl_Position = normalize_matrix * vec4(wpos.xyz, 1.0);\n" + " gl_Position.w = o0.w;\n"; { std::string code_end; diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index ad2814693e..969717b0dd 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -536,6 +536,111 @@ namespace rsx __glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); } + void texture::init(int index, rsx::vertex_texture& tex) + { + switch (tex.dimension()) + { + case rsx::texture_dimension::dimension3d: + if (!tex.depth()) + { + return; + } + + case rsx::texture_dimension::dimension2d: + if (!tex.height()) + { + return; + } + + case rsx::texture_dimension::dimension1d: + if (!tex.width()) + { + return; + } + + break; + } + + const u32 texaddr = rsx::get_address(tex.offset(), tex.location()); + + //We can't re-use texture handles if using immutable storage + if (m_id) + { + __glcheck remove(); + } + __glcheck create(); + + __glcheck glActiveTexture(GL_TEXTURE0 + index); + bind(); + + u32 full_format = tex.format(); + + u32 format = full_format & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + bool is_swizzled = !!(~full_format & CELL_GCM_TEXTURE_LN); + + __glcheck::gl::pixel_pack_settings().apply(); + __glcheck::gl::pixel_unpack_settings().apply(); + + 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); + u32 block_sz = get_pitch_modifier(format); + + __glcheck glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + __glcheck create_and_fill_texture(tex.get_extended_texture_dimension(), tex.get_exact_mipmap_count(), format, tex.width(), tex.height(), tex.depth(), get_subresources_layout(tex), is_swizzled, data_upload_buf); + + const std::array& glRemap = get_swizzle_remap(format); + + glTexParameteri(m_target, GL_TEXTURE_MAX_LEVEL, tex.get_exact_mipmap_count() - 1); + + /* + if (format != CELL_GCM_TEXTURE_B8 && format != CELL_GCM_TEXTURE_X16 && format != CELL_GCM_TEXTURE_X32_FLOAT) + { + u8 remap_a = tex.remap() & 0x3; + u8 remap_r = (tex.remap() >> 2) & 0x3; + u8 remap_g = (tex.remap() >> 4) & 0x3; + u8 remap_b = (tex.remap() >> 6) & 0x3; + + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]); + } + else + { + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_A, glRemap[0]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_R, glRemap[1]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, glRemap[2]); + __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, glRemap[3]); + } + + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r())); + */ + + __glcheck glTexParameterf(m_target, GL_TEXTURE_LOD_BIAS, tex.bias()); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_LOD, (tex.min_lod() >> 8)); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MAX_LOD, (tex.max_lod() >> 8)); + + int min_filter = gl_tex_min_filter(tex.min_filter()); + + if (min_filter != GL_LINEAR && min_filter != GL_NEAREST) + { + if (tex.get_exact_mipmap_count() <= 1 || m_target == GL_TEXTURE_RECTANGLE) + { + LOG_WARNING(RSX, "Texture %d, target 0x%X, requesting mipmap filtering without any mipmaps set!", m_id, m_target); + min_filter = GL_LINEAR; + } + } + + __glcheck glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter); + __glcheck glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter(tex.mag_filter())); + __glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); + } + void texture::bind() { glBindTexture(m_target, m_id); diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.h b/rpcs3/Emu/RSX/GL/rsx_gl_texture.h index 8198e583ba..dbdd21cdcc 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.h +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.h @@ -3,6 +3,7 @@ namespace rsx { + class vertex_texture; class texture; namespace gl @@ -38,6 +39,7 @@ namespace rsx } void init(int index, rsx::texture& tex); + void init(int index, rsx::vertex_texture& tex); /** * If a format is marked as mandating expansion, any request to have the data uploaded to the GPU shall require that the pixel data diff --git a/rpcs3/Emu/RSX/RSXTexture.cpp b/rpcs3/Emu/RSX/RSXTexture.cpp index 1cfc84acd1..2517ebd75d 100644 --- a/rpcs3/Emu/RSX/RSXTexture.cpp +++ b/rpcs3/Emu/RSX/RSXTexture.cpp @@ -299,9 +299,21 @@ namespace rsx return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 8)] >> 3) & 0x1); } - u8 vertex_texture::dimension() const + rsx::texture_dimension vertex_texture::dimension() const { - return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 8)] >> 4) & 0xf); + return rsx::to_texture_dimension((method_registers[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 8)] >> 4) & 0xf); + } + + rsx::texture_dimension_extended vertex_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; + + default: ASSUME(0); + } } u8 vertex_texture::format() const @@ -314,6 +326,12 @@ namespace rsx return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 8)] >> 16) & 0xffff); } + u16 vertex_texture::get_exact_mipmap_count() const + { + u16 max_mipmap_count = static_cast(floor(log2(std::max(width(), height()))) + 1); + return std::min(mipmap(), max_mipmap_count); + } + u8 vertex_texture::unsigned_remap() const { return ((method_registers[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 8)] >> 12) & 0xf); @@ -341,7 +359,7 @@ namespace rsx bool vertex_texture::enabled() const { - return ((method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 8)] >> 31) & 0x1); + return location() <= 1 && ((method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 8)] >> 31) & 0x1); } u16 vertex_texture::min_lod() const @@ -354,9 +372,9 @@ namespace rsx return ((method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 8)] >> 7) & 0xfff); } - u8 vertex_texture::max_aniso() const + rsx::texture_max_anisotropy vertex_texture::max_aniso() const { - return ((method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 8)] >> 4) & 0x7); + return rsx::to_texture_max_anisotropy((method_registers[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 8)] >> 4) & 0x7); } bool vertex_texture::alpha_kill_enabled() const @@ -369,14 +387,14 @@ namespace rsx return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 8)]) & 0x1fff); } - u8 vertex_texture::min_filter() const + rsx::texture_minify_filter vertex_texture::min_filter() const { - return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 8)] >> 16) & 0x7); + return rsx::to_texture_minify_filter((method_registers[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 8)] >> 16) & 0x7); } - u8 vertex_texture::mag_filter() const + rsx::texture_magnify_filter vertex_texture::mag_filter() const { - return ((method_registers[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 8)] >> 24) & 0x7); + return rsx::to_texture_magnify_filter((method_registers[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 8)] >> 24) & 0x7); } u8 vertex_texture::convolution_filter() const diff --git a/rpcs3/Emu/RSX/RSXTexture.h b/rpcs3/Emu/RSX/RSXTexture.h index e776267b3d..9c258b75c9 100644 --- a/rpcs3/Emu/RSX/RSXTexture.h +++ b/rpcs3/Emu/RSX/RSXTexture.h @@ -84,9 +84,6 @@ namespace rsx u32 border_color() const; u16 depth() const; u32 pitch() const; - - //custom info - u8 index() const; }; class vertex_texture @@ -102,12 +99,12 @@ namespace rsx u32 offset() const; // Format - u8 location() const; + u8 location() const; bool cubemap() const; - u8 border_type() const; - u8 dimension() const; - u8 format() const; - u16 mipmap() const; + u8 border_type() const; + rsx::texture_dimension dimension() const; + u8 format() const; + u16 mipmap() const; // Address u8 unsigned_remap() const; @@ -118,16 +115,16 @@ namespace rsx // Control0 bool enabled() const; - u16 min_lod() const; - u16 max_lod() const; - u8 max_aniso() const; + u16 min_lod() const; + u16 max_lod() const; + rsx::texture_max_anisotropy max_aniso() const; bool alpha_kill_enabled() const; // Filter u16 bias() const; - u8 min_filter() const; - u8 mag_filter() const; - u8 convolution_filter() const; + rsx::texture_minify_filter min_filter() const; + rsx::texture_magnify_filter mag_filter() const; + u8 convolution_filter() const; bool a_signed() const; bool r_signed() const; bool g_signed() const; @@ -142,7 +139,7 @@ namespace rsx u16 depth() const; u32 pitch() const; - //custom info - u8 index() const; + rsx::texture_dimension_extended get_extended_texture_dimension() const; + u16 get_exact_mipmap_count() const; }; } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index bb080f3818..6393cea19d 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -351,14 +351,14 @@ namespace rsx void thread::end() { + transform_constants.clear(); + for (u8 index = 0; index < rsx::limits::vertex_count; ++index) { register_vertex_info[index].size = 0; register_vertex_data[index].clear(); } - transform_constants.clear(); - if (capture_current_frame) { for (const auto &first_count : first_count_commands) @@ -468,14 +468,19 @@ namespace rsx u32 reg = cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT ? first_cmd : first_cmd + i; u32 value = args[i]; - LOG_TRACE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value); + //LOG_NOTICE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value); method_registers[reg] = value; + if (capture_current_frame) + { frame_debug.command_queue.push_back(std::make_pair(reg, value)); + } if (auto method = methods[reg]) + { method(this, value); + } } ctrl->get = get + (count + 1) * 4; @@ -822,6 +827,27 @@ namespace rsx } } + for (u8 index = 0; index < rsx::limits::vertex_textures_count; ++index) + { + if (!textures[index].enabled()) + { + result.state.vertex_textures[index] = rsx::texture_target::none; + continue; + } + + switch (textures[index].get_extended_texture_dimension()) + { + case rsx::texture_dimension_extended::texture_dimension_1d: result.state.vertex_textures[index] = rsx::texture_target::_1; break; + case rsx::texture_dimension_extended::texture_dimension_2d: result.state.vertex_textures[index] = rsx::texture_target::_2; break; + case rsx::texture_dimension_extended::texture_dimension_3d: result.state.vertex_textures[index] = rsx::texture_target::_3; break; + case rsx::texture_dimension_extended::texture_dimension_cubemap: result.state.vertex_textures[index] = rsx::texture_target::cube; break; + + default: + result.state.vertex_textures[index] = rsx::texture_target::none; + break; + } + } + result.vertex_shader.ucode_ptr = transform_program; result.vertex_shader.offset = rsx::method_registers[NV4097_SET_TRANSFORM_PROGRAM_START]; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index e25a8942f2..10488e37c8 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -268,7 +268,7 @@ namespace rsx u32 tiles_addr; u32 zculls_addr; - vm::ps3::ptr gcm_buffers; + vm::ps3::ptr gcm_buffers = vm::null; u32 gcm_buffers_count; u32 gcm_current_buffer; u32 ctxt_addr; diff --git a/rpcs3/Emu/RSX/rsx_cache.cpp b/rpcs3/Emu/RSX/rsx_cache.cpp index 61a5434684..2ff2ecfafe 100644 --- a/rpcs3/Emu/RSX/rsx_cache.cpp +++ b/rpcs3/Emu/RSX/rsx_cache.cpp @@ -4,6 +4,11 @@ namespace rsx { + void shaders_cache::path(const std::string &path_) + { + m_path = path_; + } + shader_info shaders_cache::get(const program_cache_context &ctxt, raw_shader &raw_shader, const program_state& state) { auto found_entry = m_entries.find(raw_shader); @@ -11,8 +16,6 @@ namespace rsx shader_info info; entry_t *entry; - static const std::string &path = fs::get_executable_dir() + "data/cache/"; - if (found_entry != m_entries.end()) { entry = &found_entry->second; @@ -21,11 +24,19 @@ namespace rsx { //analyze_raw_shader(raw_shader); - fs::file{ path + fmt::format("%016llx.", raw_shader.hash()) + (raw_shader.type == rsx::program_type::fragment ? "fp" : "vp") + ".ucode", fs::rewrite } - .write(raw_shader.ucode.data(), raw_shader.ucode.size()); + std::string shader_name_base = + fmt::format("%lld.%016llx", ++m_index, raw_shader.hash()) + + (raw_shader.type == rsx::program_type::fragment ? ".fp" : ".vp"); + + fs::file{ m_path + shader_name_base + ".ucode", fs::rewrite } + .write(raw_shader.ucode.data(), raw_shader.ucode.size()); rsx::decompiled_shader decompiled_shader = decompile(raw_shader, ctxt.lang); - auto inserted = m_entries.insert({ raw_shader, entry_t{ decompiled_shader } }).first; + + fs::file{ m_path + shader_name_base + (ctxt.lang == rsx::decompile_language::glsl ? ".glsl" : ".hlsl"), fs::rewrite } + .write(decompiled_shader.code); + + auto inserted = m_entries.insert({ raw_shader, entry_t{ m_index, decompiled_shader } }).first; inserted->second.decompiled.raw = &inserted->first; entry = &inserted->second; } @@ -45,7 +56,15 @@ namespace rsx info.complete = &entry->complete.insert({ state, complete_shader }).first->second; info.complete->user_data = nullptr; - fs::file{ path + fmt::format("%016llx.", raw_shader.hash()) + (raw_shader.type == rsx::program_type::fragment ? "fp" : "vp") + "." + (ctxt.lang == rsx::decompile_language::glsl ? "glsl" : "hlsl"), fs::rewrite }.write(info.complete->code); + const std::string hash_combination = fmt::format("%lld.%016llx.%016llx", entry->index, raw_shader.hash(), state.hash()); + + std::string shader_name = + hash_combination + + (raw_shader.type == rsx::program_type::fragment ? ".fp" : ".vp") + + (ctxt.lang == rsx::decompile_language::glsl ? ".glsl" : ".hlsl"); + + fs::file{ m_path + shader_name, fs::rewrite }.write(info.complete->code); + fs::file{ m_path + hash_combination + ".state", fs::rewrite }.write(state); } if (info.complete->user_data == nullptr) @@ -69,6 +88,27 @@ namespace rsx m_entries.clear(); } + programs_cache::programs_cache() + { + std::string path{ fs::get_executable_dir() + "data/cache/" }; + std::string title = Emu.GetTitleID(); + + if (title.empty()) + { + path += "temporary/"; + fs::remove_all(path, false); + } + else + { + path += title + "/"; + } + + fs::create_path(path); + + m_vertex_shaders_cache.path(path); + m_fragment_shader_cache.path(path); + } + programs_cache::~programs_cache() { clear(); diff --git a/rpcs3/Emu/RSX/rsx_cache.h b/rpcs3/Emu/RSX/rsx_cache.h index 306130b384..6fc12d683f 100644 --- a/rpcs3/Emu/RSX/rsx_cache.h +++ b/rpcs3/Emu/RSX/rsx_cache.h @@ -28,17 +28,22 @@ namespace rsx void(*remove_shader)(void *ptr); }; - struct shaders_cache + class shaders_cache { struct entry_t { + std::int64_t index; decompiled_shader decompiled; std::unordered_map complete; }; std::unordered_map m_entries; + std::string m_path; + std::int64_t m_index = -1; public: + void path(const std::string &path_); + shader_info get(const program_cache_context &ctxt, raw_shader &raw_shader, const program_state& state); void clear(const program_cache_context& context); }; @@ -53,6 +58,7 @@ namespace rsx public: program_cache_context context; + programs_cache(); ~programs_cache(); program_info get(raw_program raw_program_, decompile_language lang); diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index a5d5f95259..03cea5e20e 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -433,6 +433,37 @@ namespace rsx return; } + if (dst_dma == CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER) + { + //HACK: it's extension of the flip-hack. remove this when textures cache would be properly implemented + for (int i = 0; i < rsx::limits::color_buffers_count; ++i) + { + u32 begin = rsx->gcm_buffers[i].offset; + + if (dst_offset < begin || !begin) + { + continue; + } + + if (rsx->gcm_buffers[i].width < 720 || rsx->gcm_buffers[i].height < 480) + { + continue; + } + + if (begin == dst_offset) + { + return; + } + + u32 end = begin + rsx->gcm_buffers[i].height * rsx->gcm_buffers[i].pitch; + + if (dst_offset < end) + { + return; + } + } + } + u32 in_bpp = src_color_format == CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 ? 2 : 4; // bytes per pixel u32 out_bpp = dst_color_format == CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 ? 2 : 4; @@ -645,31 +676,51 @@ namespace rsx { force_inline void buffer_notify(u32 arg) { - const u32 inPitch = method_registers[NV0039_PITCH_IN]; - const u32 outPitch = method_registers[NV0039_PITCH_OUT]; - const u32 lineLength = method_registers[NV0039_LINE_LENGTH_IN]; - const u32 lineCount = method_registers[NV0039_LINE_COUNT]; - const u8 outFormat = method_registers[NV0039_FORMAT] >> 8; - const u8 inFormat = method_registers[NV0039_FORMAT]; + u32 in_pitch = method_registers[NV0039_PITCH_IN]; + u32 out_pitch = method_registers[NV0039_PITCH_OUT]; + const u32 line_length = method_registers[NV0039_LINE_LENGTH_IN]; + const u32 line_count = method_registers[NV0039_LINE_COUNT]; + const u8 out_format = method_registers[NV0039_FORMAT] >> 8; + const u8 in_format = method_registers[NV0039_FORMAT]; const u32 notify = arg; // The existing GCM commands use only the value 0x1 for inFormat and outFormat - if (inFormat != 0x01 || outFormat != 0x01) + if (in_format != 0x01 || out_format != 0x01) { - LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", inFormat, outFormat); + LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", in_format, out_format); } - if (lineCount == 1 && !inPitch && !outPitch && !notify) + if (!in_pitch) { - std::memcpy( - vm::base(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT])), - vm::base(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN])), - lineLength); + in_pitch = line_length; + } + + if (!out_pitch) + { + out_pitch = line_length; + } + + u32 src_offset = method_registers[NV0039_OFFSET_IN]; + u32 src_dma = method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN]; + + u32 dst_offset = method_registers[NV0039_OFFSET_OUT]; + u32 dst_dma = method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT]; + + u8 *dst = (u8*)vm::base(get_address(dst_offset, dst_dma)); + const u8 *src = (u8*)vm::base(get_address(src_offset, src_dma)); + + if (in_pitch == out_pitch && out_pitch == line_length) + { + std::memcpy(dst, src, line_length * line_count); } else { - LOG_ERROR(RSX, "NV0039_OFFSET_IN: bad offset(in=0x%x, out=0x%x), pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x", - method_registers[NV0039_OFFSET_IN], method_registers[NV0039_OFFSET_OUT], inPitch, outPitch, lineLength, lineCount, inFormat, outFormat, notify); + for (u32 i = 0; i < line_count; ++i) + { + std::memcpy(dst, src, line_length); + dst += out_pitch; + src += in_pitch; + } } } } diff --git a/rsx_program_decompiler b/rsx_program_decompiler index aa6bcbc589..05d1fc4389 160000 --- a/rsx_program_decompiler +++ b/rsx_program_decompiler @@ -1 +1 @@ -Subproject commit aa6bcbc58961356733ae1fc0742a37a0a6190f31 +Subproject commit 05d1fc438948aaaf260d2244be9d75427ea9d3e9