diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 3b68545bf9..9e126f15e1 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -662,6 +662,8 @@ void GLGSRender::end() invalidate_buffers(); rsx::thread::end(); + + m_texture_cache.update_protection(); } void GLGSRender::set_viewport() @@ -799,7 +801,15 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer) { //LOG_NOTICE(Log::RSX, "nv4097_clear_surface(0x%x)", arg); - if ((arg & 0xf3) == 0) + enum + { + depth = 1 << 0, + stencil = 1 << 1, + depth_stencil = depth | stencil, + color_mask = 0xf0, + }; + + if ((arg & (depth_stencil | color_mask)) == 0) { //do nothing return; @@ -818,29 +828,45 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer) GLbitfield mask = 0; - if (arg & 0x1) + if (arg & depth_stencil) { - rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7); - u32 max_depth_value = get_max_depth_value(surface_depth_format); + if (arg & depth) + { + rsx::surface_depth_format surface_depth_format = rsx::to_surface_depth_format((rsx::method_registers[NV4097_SET_SURFACE_FORMAT] >> 5) & 0x7); + u32 max_depth_value = get_max_depth_value(surface_depth_format); - u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8; + u32 clear_depth = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] >> 8; - glDepthMask(GL_TRUE); - glClearDepth(double(clear_depth) / max_depth_value); - mask |= GLenum(gl::buffers::depth); + glDepthMask(GL_TRUE); + glClearDepth(double(clear_depth) / max_depth_value); + mask |= GLenum(gl::buffers::depth); + } + + if (arg & stencil) + { + u8 clear_stencil = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] & 0xff; + + __glcheck glStencilMask(rsx::method_registers[NV4097_SET_STENCIL_MASK]); + glClearStencil(clear_stencil); + + mask |= GLenum(gl::buffers::stencil); + } + + if (gl::cached_texture* texture = renderer->cached_depth_buffer) + { + if ((arg & depth_stencil) == depth_stencil) + { + texture->ignore(gl::cache_buffers::local); + texture->invalidate(gl::cache_buffers::host); + } + else + { + texture->sync(gl::cache_buffers::local); + } + } } - if (arg & 0x2) - { - u8 clear_stencil = rsx::method_registers[NV4097_SET_ZSTENCIL_CLEAR_VALUE] & 0xff; - - __glcheck glStencilMask(rsx::method_registers[NV4097_SET_STENCIL_MASK]); - glClearStencil(clear_stencil); - - mask |= GLenum(gl::buffers::stencil); - } - - if (arg & 0xf0) + if (arg & color_mask) { u32 clear_color = rsx::method_registers[NV4097_SET_COLOR_CLEAR_VALUE]; u8 clear_a = clear_color >> 24; @@ -852,10 +878,27 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer) glClearColor(clear_r / 255.f, clear_g / 255.f, clear_b / 255.f, clear_a / 255.f); mask |= GLenum(gl::buffers::color); + + rsx::for_each_active_color_surface([&](int index) + { + gl::cached_texture* texture = renderer->cached_color_buffers[index]; + + if (texture) + { + if ((arg & color_mask) == color_mask) + { + texture->ignore(gl::cache_buffers::local); + texture->invalidate(gl::cache_buffers::host); + } + else + { + texture->sync(gl::cache_buffers::local); + } + } + }); } glClear(mask); - renderer->invalidate_buffers(); } using rsx_method_impl_t = void(*)(u32, GLGSRender*); @@ -1021,6 +1064,52 @@ std::pair surface_depth_format_to_gl(rsx } } +[[noreturn]] void unimplemented() +{ + throw EXCEPTION(""); +} + +u32 surface_format_to_texture_format(rsx::surface_color_format format) +{ + switch (format) + { + case rsx::surface_color_format::x1r5g5b5_z1r5g5b5: unimplemented(); + case rsx::surface_color_format::x1r5g5b5_o1r5g5b5: unimplemented(); + case rsx::surface_color_format::r5g6b5: return CELL_GCM_TEXTURE_R5G6B5; + case rsx::surface_color_format::x8r8g8b8_z8r8g8b8: unimplemented(); + case rsx::surface_color_format::x8r8g8b8_o8r8g8b8: unimplemented(); + case rsx::surface_color_format::a8r8g8b8: return CELL_GCM_TEXTURE_A8R8G8B8; + case rsx::surface_color_format::b8: return CELL_GCM_TEXTURE_B8; + case rsx::surface_color_format::g8b8: return CELL_GCM_TEXTURE_G8B8; + case rsx::surface_color_format::w16z16y16x16: return CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT; + case rsx::surface_color_format::w32z32y32x32: return CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT; + case rsx::surface_color_format::x32: return CELL_GCM_TEXTURE_X32_FLOAT; + case rsx::surface_color_format::x8b8g8r8_z8b8g8r8: unimplemented(); + case rsx::surface_color_format::x8b8g8r8_o8b8g8r8: unimplemented(); + case rsx::surface_color_format::a8b8g8r8: unimplemented(); + } + + return CELL_GCM_TEXTURE_A8R8G8B8; +} + +gl::texture_info surface_info(rsx::surface_color_format format, u32 offset, u32 location, u32 width, u32 height, u32 pitch) +{ + gl::texture_info info; + + info.width = width; + info.height = height; + info.depth = 1; + info.pitch = pitch; + info.compressed_size = 0; + info.target = gl::texture::target::texture2D; + info.dimension = 2; + info.start_address = rsx::get_address(offset, location); + + info.format = gl::get_texture_format(surface_format_to_texture_format(format)); + + return info; +} + void GLGSRender::init_buffers(bool skip_reading) { static const u32 mr_color_offset[rsx::limits::color_buffers_count] = @@ -1049,44 +1138,99 @@ void GLGSRender::init_buffers(bool skip_reading) static const gl::texture_view null_texture{ gl::texture::target::texture2D, 0 }; + u32 surface_format = rsx::method_registers[NV4097_SET_SURFACE_FORMAT]; + + u32 clip_horizontal = rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL]; + u32 clip_vertical = rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL]; + + u32 clip_width = clip_horizontal >> 16; + u32 clip_height = clip_vertical >> 16; + u32 clip_x = clip_horizontal & 0xffff; + u32 clip_y = clip_vertical & 0xffff; + + m_surface.unpack(surface_format); + m_surface.width = clip_width + clip_x; + m_surface.height = clip_height + clip_y; + rsx::for_each_active_color_surface([&](int index) { - //TODO + u32 offset = rsx::method_registers[mr_color_offset[index]]; + u32 location = rsx::method_registers[mr_color_dma[index]]; + u32 pitch = rsx::method_registers[mr_color_pitch[index]]; - if (true) + if (!location) { - m_cached_color_buffers[index] = nullptr; + cached_color_buffers[index] = nullptr; draw_fbo.color[index] = null_texture; } else { - gl::texture_info info{}; - - //TODO - - m_cached_color_buffers[index] = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local); - - draw_fbo.color[index] = m_cached_color_buffers[index]->view(); + gl::texture_info info = surface_info(m_surface.color_format, offset, location, m_surface.width, m_surface.height, pitch); + cached_color_buffers[index] = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local); + draw_fbo.color[index] = cached_color_buffers[index]->view(); } }); { - //TODO + u32 offset = rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET]; + u32 location = rsx::method_registers[NV4097_SET_CONTEXT_DMA_ZETA]; + u32 pitch = rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z]; - if (true) + if (!location) { - m_cached_depth_buffer = nullptr; + cached_depth_buffer = nullptr; draw_fbo.depth_stencil = null_texture; } else { - gl::texture_info info{}; + gl::texture_info info; - //TODO + info.width = m_surface.width; + info.height = m_surface.height; + info.depth = 1; + info.pitch = pitch; + info.dimension = 2; + info.compressed_size = 0; + info.start_address = rsx::get_address(offset, location); + info.target = gl::texture::target::texture2D; - m_cached_depth_buffer = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local); + switch (m_surface.depth_format) + { + case rsx::surface_depth_format::z16: + info.format.bpp = 2; + info.format.flags = gl::texture_flags::swap_bytes; + info.format.type = gl::texture::type::ushort; + info.format.internal_format = gl::texture::internal_format::depth16; + info.format.format = gl::texture::format::depth; + break; - draw_fbo.depth_stencil = m_cached_depth_buffer->view(); + case rsx::surface_depth_format::z24s8: + info.format.bpp = 4; + info.format.flags = gl::texture_flags::swap_bytes; + info.format.type = gl::texture::type::uint_24_8; + info.format.internal_format = gl::texture::internal_format::depth24_stencil8; + info.format.format = gl::texture::format::depth_stencil; + break; + + default: + throw EXCEPTION(""); + } + + info.format.remap = { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO }; + + cached_depth_buffer = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local); + + + switch (m_surface.depth_format) + { + case rsx::surface_depth_format::z16: + draw_fbo.depth = cached_depth_buffer->view(); + break; + + case rsx::surface_depth_format::z24s8: + draw_fbo.depth_stencil = cached_depth_buffer->view(); + break; + } } } @@ -1126,15 +1270,10 @@ void GLGSRender::invalidate_buffers() void GLGSRender::flip(int buffer) { - //LOG_NOTICE(Log::RSX, "flip(%d)", buffer); u32 buffer_width = gcm_buffers[buffer].width; u32 buffer_height = gcm_buffers[buffer].height; u32 buffer_pitch = gcm_buffers[buffer].pitch; - //rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL); - - //TODO - glDisable(GL_SCISSOR_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -1142,11 +1281,8 @@ void GLGSRender::flip(int buffer) glDisable(GL_LOGIC_OP); glDisable(GL_CULL_FACE); - gl::texture_info info{}; - - //TODO - - gl::cached_texture& texture = m_texture_cache.entry(info); + gl::cached_texture& texture = m_texture_cache.entry(surface_info(rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset, + CELL_GCM_LOCATION_LOCAL, buffer_width, buffer_height, buffer_pitch), gl::cache_buffers::local); m_flip_fbo.bind(); m_flip_fbo.color = texture.view(); @@ -1203,7 +1339,7 @@ bool GLGSRender::on_access_violation(u32 address, bool is_writing) { if (is_writing) { - const bool accurate_cache = false; + const bool accurate_cache = true; if (accurate_cache) { @@ -1249,14 +1385,16 @@ void GLGSRender::for_each_active_surface(std::function callback); }; diff --git a/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp b/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp index 5a8d70cf2f..44ffa8632a 100644 --- a/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp +++ b/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp @@ -16,19 +16,20 @@ namespace gl { void cached_texture::read() { - LOG_WARNING(RSX, "cached_texture at 0x%x reading from host buffer", info.start_address); - cached_texture* found_texture = nullptr; - u32 texture_size = info.size(); + u32 texture_size = info->size(); - m_parent_region->for_each(info.start_address, texture_size, [&](cached_texture& texture) + m_parent_region->for_each(info->start_address, texture_size, [&](cached_texture& texture) { if ((texture.m_state & cache_entry_state::local_synchronized) == cache_entry_state::invalid) { return; } - if (texture.info.start_address > info.start_address || texture.info.pitch != info.pitch || texture.info.height < info.height) + if (texture.info->start_address != info->start_address || + texture.info->pitch != info->pitch || + texture.info->height < info->height || + texture.info->width < info->width) { return; } @@ -39,20 +40,53 @@ namespace gl if (found_texture) { //read from local + LOG_WARNING(RSX, "cached_texture at 0x%x reading from local buffer", info->start_address); - //TODO + glCopyImageSubData( + found_texture->gl_name, (GLenum)found_texture->info->target, 0, 0, 0, 0, + gl_name, (GLenum)info->target, 0, 0, 0, 0, + info->width, info->height, info->depth); } else { //read from host - //flush all local textures at region - m_parent_region->for_each(info.start_address, texture_size, [](cached_texture& texture) + m_parent_region->for_each(info->start_address, texture_size, [](cached_texture& texture) { texture.sync(gl::cache_buffers::host); }); - //TODO + bind(); + + if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil) + { + LOG_ERROR(RSX, "cached_texture at 0x%x: unimplemented reading depth(stencil) from host buffer", info->start_address); + + //TODO + } + else if (info->compressed_size) + { + LOG_WARNING(RSX, "cached_texture at 0x%x: reading compressed texture from host buffer", info->start_address); + + glCompressedTexImage2D((GLenum)info->target, 0, + (GLenum)info->format.internal_format, + info->width, info->height, + 0, + info->compressed_size, vm::base_priv(info->start_address)); + } + else + { + LOG_WARNING(RSX, "cached_texture at 0x%x reading from host buffer", info->start_address); + + gl::pixel_unpack_settings{} + .row_length(info->pitch / info->format.bpp) + .aligment(1) + .swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none) + .apply(); + + glTexImage2D((GLenum)info->target, 0, (GLenum)info->format.internal_format, info->width, info->height, 0, + (GLenum)info->format.format, (GLenum)info->format.type, vm::base_priv(info->start_address)); + } } ignore(gl::cache_buffers::all); @@ -60,9 +94,30 @@ namespace gl void cached_texture::write() { - LOG_WARNING(RSX, "cached_texture at 0x%x writing to host buffer", info.start_address); + LOG_WARNING(RSX, "cached_texture at 0x%x writing to host buffer", info->start_address); - //TODO + bind(); + + if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil) + { + LOG_ERROR(RSX, "cached_texture at 0x%x: unimplemented writing depth(stencil) to host buffer", info->start_address); + + //TODO + } + else if (info->compressed_size) + { + LOG_ERROR(RSX, "writing compressed texture[0x%x] to host buffer", info->start_address); + } + else + { + gl::pixel_pack_settings{} + .row_length(info->pitch / info->format.bpp) + .aligment(1) + .swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none) + .apply(); + + glGetTexImage((GLenum)info->target, 0, (GLenum)info->format.format, (GLenum)info->format.type, vm::base_priv(info->start_address)); + } ignore(gl::cache_buffers::all); } @@ -101,17 +156,14 @@ namespace gl { if ((buffers & cache_buffers::host) != cache_buffers::none) { - if ((m_state & cache_entry_state::host_synchronized) != cache_entry_state::invalid) - { - m_state &= ~cache_entry_state::host_synchronized; - - m_parent_region->m_write_protected++; - } - - m_parent_region->for_each(info.start_address, info.size(), [this](cached_texture& texture) + m_state &= ~cache_entry_state::host_synchronized; + m_parent_region->for_each(info->start_address, info->size(), [this](cached_texture& texture) { if (std::addressof(texture) != this) { + //LOG_WARNING(RSX, "cached_texture[0x%x,0x%x) invalidate cached_texture[0x%x, 0x%x)", + // info->start_address, info->start_address + info->size(), + // texture.info->start_address, texture.info->start_address + texture.info->size()); texture.invalidate(cache_buffers::local); } }); @@ -119,12 +171,7 @@ namespace gl if ((buffers & cache_buffers::local) != cache_buffers::none) { - if ((m_state & cache_entry_state::local_synchronized) != cache_entry_state::invalid) - { - m_state &= ~cache_entry_state::local_synchronized; - - m_parent_region->m_read_protected++; - } + m_state &= ~cache_entry_state::local_synchronized; } } @@ -132,22 +179,12 @@ namespace gl { if ((buffers & cache_buffers::host) != cache_buffers::none) { - if ((m_state & cache_entry_state::host_synchronized) == cache_entry_state::invalid) - { - m_state |= cache_entry_state::host_synchronized; - - m_parent_region->m_write_protected--; - } + m_state |= cache_entry_state::host_synchronized; } if ((buffers & cache_buffers::local) != cache_buffers::none) { - if ((m_state & cache_entry_state::local_synchronized) == cache_entry_state::invalid) - { - m_state |= cache_entry_state::local_synchronized; - - m_parent_region->m_read_protected--; - } + m_state |= cache_entry_state::local_synchronized; } } @@ -177,6 +214,20 @@ namespace gl return true; } + cache_access cached_texture::requires_protection() const + { + switch (m_state) + { + case cache_entry_state::local_synchronized: + return cache_access::read_write; + + case cache_entry_state::synchronized: + return cache_access::write; + } + + return cache_access::none; + } + void cached_texture::bind(uint index) const { if (index != ~0u) @@ -184,7 +235,7 @@ namespace gl glActiveTexture(GL_TEXTURE0 + index); } - glBindTexture((GLenum)info.target, gl_name); + glBindTexture((GLenum)info->target, gl_name); } void cached_texture::create() @@ -192,6 +243,9 @@ namespace gl assert(!created()); glGenTextures(1, &gl_name); + bind(); + glTexImage2D((GLenum)info->target, 0, (GLenum)info->format.internal_format, info->width, info->height, 0, + (GLenum)info->format.format, (GLenum)info->format.type, nullptr); } void cached_texture::remove() @@ -208,6 +262,19 @@ namespace gl return gl_name != 0; } + cache_access protected_region::requires_protection() const + { + //TODO + cache_access result = cache_access::none; + + for (auto &entry : m_textures) + { + result |= entry.second.requires_protection(); + } + + return result; + } + void protected_region::for_each(std::function callback) { for (auto &entry : m_textures) @@ -220,38 +287,39 @@ namespace gl { for (auto &entry : m_textures) { - u32 entry_address = entry.first; - cached_texture &entry_texture = entry.second; - - if (entry_address > start_address) + if (entry.first.start_address >= start_address + size) { - break; + continue; } - u32 entry_size = entry_texture.info.size(); - //TODO + if (entry.first.start_address + entry.first.size() <= start_address) + { + continue; + } - callback(entry_texture); + callback(entry.second); } } void protected_region::protect() { - u32 flags = 0; + cache_access required_protection = requires_protection(); - if (m_read_protected) + u32 flags = 0; + if ((required_protection & cache_access::read) != cache_access::none) { flags |= vm::page_readable; } - if (m_write_protected) + if ((required_protection & cache_access::write) != cache_access::none) { flags |= vm::page_writable; } if (m_current_protection != flags) { - vm::page_protect(start_address, size(), 0, flags, m_current_protection & ~flags); + LOG_WARNING(RSX, "protection region [0x%x, 0x%x)", start_address, start_address + size()); + vm::page_protect(start_address, size(), 0, m_current_protection & ~flags, flags); m_current_protection = flags; } } @@ -262,7 +330,7 @@ namespace gl if ((access & cache_access::read) != cache_access::none) { - if (m_read_protected) + if (m_current_protection & vm::page_readable) { flags |= vm::page_readable; } @@ -270,13 +338,14 @@ namespace gl if ((access & cache_access::write) != cache_access::none) { - if (m_write_protected) + if (m_current_protection & vm::page_writable) { flags |= vm::page_writable; } } - vm::page_protect(start_address, size(), 0, 0, flags); + LOG_WARNING(RSX, "unprotected region [0x%x, 0x%x)", start_address, start_address + size()); + vm::page_protect(start_address, size(), 0, flags, 0); m_current_protection &= ~flags; } @@ -290,9 +359,57 @@ namespace gl //TODO } - void protected_region::combine(const protected_region& region) + void protected_region::combine(protected_region& region) { - //TODO + region.unprotect(); + unprotect(); + + for (auto &texture : region.m_textures) + { + texture.second.parent(this); + } + + m_textures.insert(region.m_textures.begin(), region.m_textures.end()); + + if (region.start_address < start_address) + { + pages_count += (start_address - region.start_address) / vm::page_size; + start_address = region.start_address; + } + else + { + pages_count = (region.start_address + region.pages_count - start_address) / vm::page_size; + } + } + + cached_texture& protected_region::add(const texture_info& info) + { + LOG_WARNING(RSX, "new texture in cache at 0x%x", info.start_address); + auto &result = m_textures.emplace(info, cached_texture{}); + + if (!result.second) + { + throw EXCEPTION(""); + } + + auto& texture_info = *result.first; + + texture_info.second.info = &texture_info.first; + texture_info.second.parent(this); + + return texture_info.second; + } + + cached_texture* protected_region::find(const texture_info& info) + { + auto it = m_textures.find(info); + + if (it == m_textures.end()) + { + return nullptr; + } + + return &it->second; } void protected_region::clear() @@ -305,32 +422,58 @@ namespace gl } m_textures.clear(); - - m_read_protected = 0; - m_write_protected = 0; } - cached_texture &texture_cache::entry(texture_info &info, cache_buffers sync_buffers) + cached_texture &texture_cache::entry(texture_info &info, cache_buffers sync) { - auto region = find_region(info.start_address, info.size()); + u32 aligned_address = info.start_address & ~(vm::page_size - 1); + u32 aligned_size = align(info.size(), vm::page_size); - if (!region) + std::vector regions = find_regions(aligned_address, aligned_size); + protected_region *region; + + if (regions.empty()) { - region = &m_protected_regions[info.start_address & ~(vm::page_size - 1)]; - region->pages_count = (info.size() + vm::page_size - 1) / vm::page_size; + region = &m_protected_regions[aligned_address]; + region->pages_count = aligned_size / vm::page_size; + region->start_address = aligned_address; } else { - //TODO + region = regions[0]; + + std::vector remove_addresses; + + for (std::size_t index = 1; index < regions.size(); ++index) + { + region->combine(*regions[index]); + remove_addresses.push_back(regions[index]->start_address); + } + + for (u32 address : remove_addresses) + { + m_protected_regions.erase(address); + } + + if (region->start_address > aligned_address) + { + region->pages_count += (region->start_address - aligned_address) / vm::page_size; + region->start_address = aligned_address; + } + + u32 new_pages_count = (aligned_address + aligned_size - region->start_address) / vm::page_size; + region->pages_count = std::max(region->pages_count, new_pages_count); } - cached_texture *result = nullptr; + cached_texture *result = region->find(info); - //TODO + if (!result) + { + result = ®ion->add(info); + } - result->sync(sync_buffers); - - region->protect(); + result->sync(sync); + //region->protect(); return *result; } @@ -353,24 +496,34 @@ namespace gl return nullptr; } - protected_region *texture_cache::find_region(u32 address, u32 size) + std::vector texture_cache::find_regions(u32 address, u32 size) { + std::vector result; + for (auto& entry : m_protected_regions) { - if (entry.first > address + size) + if (entry.first >= address + size) { break; } - if (entry.first + entry.second.size() < address) + if (entry.first + entry.second.size() <= address) { continue; } - return &entry.second; + result.push_back(&entry.second); } - return nullptr; + return result; + } + + void texture_cache::update_protection() + { + for (auto& entry : m_protected_regions) + { + entry.second.protect(); + } } void texture_cache::clear() diff --git a/rpcs3/Emu/RSX/GL/gl_texture_cache.h b/rpcs3/Emu/RSX/GL/gl_texture_cache.h index 821c477cab..6eba96dc1a 100644 --- a/rpcs3/Emu/RSX/GL/gl_texture_cache.h +++ b/rpcs3/Emu/RSX/GL/gl_texture_cache.h @@ -45,7 +45,7 @@ namespace gl struct texture_format { u8 bpp; - const GLint *remap; + std::array remap; texture::internal_format internal_format; texture::format format; texture::type type; @@ -68,7 +68,7 @@ namespace gl u32 size() const { - return height * pitch * depth; + return compressed_size ? compressed_size : height * pitch * depth; } }; @@ -76,7 +76,7 @@ namespace gl struct cached_texture { - texture_info info; + const texture_info *info; GLuint gl_name = 0; private: @@ -99,9 +99,11 @@ namespace gl gl::texture_view view() const { - return{ info.target, gl_name }; + return{ info->target, gl_name }; } + cache_access requires_protection() const; + protected: void create(); void remove(); @@ -116,10 +118,8 @@ namespace gl u32 pages_count; private: - std::map m_textures; + std::unordered_map m_textures; - u32 m_read_protected = 0; - u32 m_write_protected = 0; u32 m_current_protection = 0; public: @@ -128,6 +128,7 @@ namespace gl return pages_count * vm::page_size; } + cache_access requires_protection() const; void for_each(std::function callback); void for_each(u32 start_address, u32 size, std::function callback); void protect(); @@ -135,11 +136,12 @@ namespace gl bool empty() const; void separate(protected_region& dst); - void combine(const protected_region& region); + void combine(protected_region& region); + + cached_texture* find(const texture_info& info); + cached_texture& add(const texture_info& info); void clear(); - - friend cached_texture; }; class texture_cache @@ -147,9 +149,10 @@ namespace gl std::map m_protected_regions; public: - cached_texture &entry(texture_info &info, cache_buffers sync_buffers = cache_buffers::none); + cached_texture &entry(texture_info &info, cache_buffers sync = cache_buffers::none); protected_region *find_region(u32 address); - protected_region *find_region(u32 address, u32 size); + std::vector find_regions(u32 address, u32 size); + void update_protection(); void clear(); }; } diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp index 2bd43fd868..53c0684cb2 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -8,17 +8,17 @@ #include "../Common/TextureUtils.h" #include "gl_texture_cache.h" -const GLint default_remap[4]{ GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE }; -const GLint remap_B8[4]{ GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE }; -const GLint remap_G8B8[4]{ GL_RED, GL_GREEN, GL_RED, GL_GREEN }; -const GLint remap_R6G5B5[4]{ GL_ALPHA, GL_GREEN, GL_RED, GL_BLUE }; -const GLint remap_X16[4]{ GL_RED, GL_ONE, GL_RED, GL_ONE }; -const GLint remap_Y16_X16[4]{ GL_GREEN, GL_RED, GL_GREEN, GL_RED }; -const GLint remap_FLOAT[4]{ GL_RED, GL_ONE, GL_ONE, GL_ONE }; -const GLint remap_X32_FLOAT[4]{ GL_RED, GL_ONE, GL_ONE, GL_ONE }; -const GLint remap_D1R5G5B5[4]{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; -const GLint remap_D8R8G8B8[4]{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; -const GLint remap_Y16_X16_FLOAT[4]{ GL_RED, GL_GREEN, GL_RED, GL_GREEN }; +const std::array default_remap{ GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE }; +const std::array remap_B8{ GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE }; +const std::array remap_G8B8{ GL_RED, GL_GREEN, GL_RED, GL_GREEN }; +const std::array remap_R6G5B5{ GL_ALPHA, GL_GREEN, GL_RED, GL_BLUE }; +const std::array remap_X16{ GL_RED, GL_ONE, GL_RED, GL_ONE }; +const std::array remap_Y16_X16{ GL_GREEN, GL_RED, GL_GREEN, GL_RED }; +const std::array remap_FLOAT{ GL_RED, GL_ONE, GL_ONE, GL_ONE }; +const std::array remap_X32_FLOAT{ GL_RED, GL_ONE, GL_ONE, GL_ONE }; +const std::array remap_D1R5G5B5{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; +const std::array remap_D8R8G8B8{ GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; +const std::array remap_Y16_X16_FLOAT{ GL_RED, GL_GREEN, GL_RED, GL_GREEN }; const std::unordered_map textures_fromats { @@ -44,6 +44,14 @@ const std::unordered_map textures_fromats { CELL_GCM_TEXTURE_Y16_X16_FLOAT,{ 4, remap_Y16_X16_FLOAT, gl::texture::internal_format::rgba, gl::texture::format::rg, gl::texture::type::f16, gl::texture_flags::allow_remap | gl::texture_flags::swap_bytes } }, }; +namespace gl +{ + const texture_format& get_texture_format(u32 texture_id) + { + return textures_fromats.at(texture_id); + } +} + static const int gl_tex_min_filter[] = { GL_NEAREST, // unused @@ -147,7 +155,7 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te bool is_compressed = compressed_format(full_format); - const GLint *remap = default_remap; + const GLint *remap = default_remap.data(); //TODO gl::texture_info info{}; @@ -156,6 +164,8 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te info.height = std::max(tex.height(), 1); info.depth = std::max(tex.depth(), 1); info.dimension = tex.dimension(); + info.start_address = rsx::get_address(tex.offset(), tex.location()); + info.target = target; if (is_compressed) { @@ -183,6 +193,10 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te default: throw EXCEPTION("bad compressed format"); } + + info.format.bpp = 1; + info.format.format = gl::texture::format::rgba; + info.format.flags = gl::texture_flags::none; } else { @@ -201,7 +215,7 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, int index, rsx::texture& te info.pitch = info.width * info.format.bpp; } - remap = info.format.remap; + remap = info.format.remap.data(); } cache.entry(info, gl::cache_buffers::local).bind(index); diff --git a/rpcs3/Emu/RSX/GL/rsx_gl_texture.h b/rpcs3/Emu/RSX/GL/rsx_gl_texture.h index 172b119a03..17855d1af3 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.h +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.h @@ -6,12 +6,16 @@ namespace gl { class texture_cache; + struct texture_format; + + const texture_format& get_texture_format(u32 texture_id); } namespace rsx { class texture; + namespace gl_texture { void bind(gl::texture_cache& cache, int index, rsx::texture& tex); diff --git a/rpcs3/Gui/RSXDebugger.cpp b/rpcs3/Gui/RSXDebugger.cpp index ef2179aa3a..a31b8aa990 100644 --- a/rpcs3/Gui/RSXDebugger.cpp +++ b/rpcs3/Gui/RSXDebugger.cpp @@ -667,7 +667,7 @@ void RSXDebugger::GetBuffers() if(!vm::check_addr(RSXbuffer_addr)) continue; - auto RSXbuffer = vm::ps3::_ptr(RSXbuffer_addr); + auto RSXbuffer = (u8*)vm::base_priv(RSXbuffer_addr); u32 width = buffers[bufferId].width; u32 height = buffers[bufferId].height;