diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 46ed36bed1..78ad6d1099 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -945,10 +945,308 @@ bool nv4097_clear_surface(u32 arg, GLGSRender* renderer) return true; } +void scale_texture(gl::texture& dst, gl::texture::sized_internal_format dst_format, size2i dst_size, const gl::texture& src, position2i point, size2i src_size) +{ + dst.bind(); + + if (dst.get_target() == gl::texture::target::texture1D) + { + glTexStorage1D((GLenum)dst.get_target(), 1, (GLenum)dst_format, dst_size.width); + } + else + { + glTexStorage2D((GLenum)dst.get_target(), 1, (GLenum)dst_format, dst_size.width, dst_size.height); + } + + gl::fbo src_fbo, dst_fbo; + src_fbo.create(); + dst_fbo.create(); + + dst_fbo.color = dst; + src_fbo.color = src; + + src_fbo.blit(dst_fbo, areai{ point.x, point.y, src_size.width, src_size.height }, coordi{ {}, dst_size }, gl::buffers::color, gl::filter::linear); +} + bool nv3089_image_in(u32 arg, GLGSRender* renderer) { - //TODO - return false; + u32 operation = rsx::method_registers[NV3089_SET_OPERATION]; + + u32 clip_x = rsx::method_registers[NV3089_CLIP_POINT] & 0xffff; + u32 clip_y = rsx::method_registers[NV3089_CLIP_POINT] >> 16; + u32 clip_w = rsx::method_registers[NV3089_CLIP_SIZE] & 0xffff; + u32 clip_h = rsx::method_registers[NV3089_CLIP_SIZE] >> 16; + + u32 out_x = rsx::method_registers[NV3089_IMAGE_OUT_POINT] & 0xffff; + u32 out_y = rsx::method_registers[NV3089_IMAGE_OUT_POINT] >> 16; + u32 out_w = rsx::method_registers[NV3089_IMAGE_OUT_SIZE] & 0xffff; + u32 out_h = rsx::method_registers[NV3089_IMAGE_OUT_SIZE] >> 16; + + u16 in_w = rsx::method_registers[NV3089_IMAGE_IN_SIZE]; + u16 in_h = rsx::method_registers[NV3089_IMAGE_IN_SIZE] >> 16; + u16 in_pitch = rsx::method_registers[NV3089_IMAGE_IN_FORMAT]; + u8 in_origin = rsx::method_registers[NV3089_IMAGE_IN_FORMAT] >> 16; + u8 in_inter = rsx::method_registers[NV3089_IMAGE_IN_FORMAT] >> 24; + u32 src_color_format = rsx::method_registers[NV3089_SET_COLOR_FORMAT]; + + u32 context_surface = rsx::method_registers[NV3089_SET_CONTEXT_SURFACE]; + + f32 scale_x = 1048576.f / rsx::method_registers[NV3089_DS_DX]; + f32 scale_y = 1048576.f / rsx::method_registers[NV3089_DT_DY]; + + f32 in_x = (arg & 0xffff) / 16.f; + f32 in_y = (arg >> 16) / 16.f; + + if (in_w <= 64 || in_h <= 64) + { + return false; + } + + if(in_origin != CELL_GCM_TRANSFER_ORIGIN_CORNER) + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", in_origin); + } + + if (in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_ZOH && in_inter != CELL_GCM_TRANSFER_INTERPOLATOR_FOH) + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", in_inter); + } + + if (operation != CELL_GCM_TRANSFER_OPERATION_SRCCOPY) + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unimplemented operation (%d)", operation); + return false; + } + + const u32 src_offset = rsx::method_registers[NV3089_IMAGE_IN_OFFSET]; + const u32 src_dma = rsx::method_registers[NV3089_SET_CONTEXT_DMA_IMAGE]; + + u32 dst_offset; + u32 dst_dma = 0; + u16 dst_color_format; + u32 out_pitch = 0; + u32 out_aligment = 64; + + switch (context_surface) + { + case CELL_GCM_CONTEXT_SURFACE2D: + dst_dma = rsx::method_registers[NV3062_SET_CONTEXT_DMA_IMAGE_DESTIN]; + dst_offset = rsx::method_registers[NV3062_SET_OFFSET_DESTIN]; + dst_color_format = rsx::method_registers[NV3062_SET_COLOR_FORMAT]; + out_pitch = rsx::method_registers[NV3062_SET_PITCH] >> 16; + out_aligment = rsx::method_registers[NV3062_SET_PITCH] & 0xffff; + break; + + case CELL_GCM_CONTEXT_SWIZZLE2D: + dst_dma = rsx::method_registers[NV309E_SET_CONTEXT_DMA_IMAGE]; + dst_offset = rsx::method_registers[NV309E_SET_OFFSET]; + dst_color_format = rsx::method_registers[NV309E_SET_FORMAT]; + break; + + default: + //LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", rsx::method_registers[NV3089_SET_CONTEXT_SURFACE]); + return false; + } + + if (dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 && + dst_color_format != CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8) + { + return false; + } + + if (src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 && + src_color_format != CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8) + { + return false; + } + + + 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; + + if (out_pitch == 0) + { + out_pitch = out_bpp * out_w; + } + + if (in_pitch == 0) + { + in_pitch = in_bpp * in_w; + } + + if (clip_w > out_w) + { + clip_w = out_w; + } + + if (clip_h > out_h) + { + clip_h = out_h; + } + + u32 convert_w = u32(scale_x * in_w); + u32 convert_h = u32(scale_y * in_h); + + //LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: src = 0x%x, dst = 0x%x", src_address, dst_address); + + rsx::tiled_region src_region = renderer->get_tiled_address(src_offset, src_dma & 0xf);//get_address(src_offset, src_dma); + rsx::tiled_region dst_region = renderer->get_tiled_address(dst_offset, dst_dma & 0xf); + + u32 src_x = 0; + u32 src_y = 0; + + gl::texture_info src_info{}; + src_info.start_address = src_region.address; + + if (src_region.tile) + { + src_x = (src_region.base % src_region.tile->pitch) / in_bpp; + src_y = src_region.base / src_region.tile->pitch; + + src_info.width = src_region.tile->pitch / in_bpp; + src_info.height = src_region.tile->size / src_region.tile->pitch; + src_info.pitch = src_region.tile->pitch; + } + else + { + src_info.width = in_w; + src_info.height = in_h; + src_info.pitch = in_pitch; + } + + src_info.depth = 1; + src_info.mipmap = 1; + src_info.dimension = src_info.height == 1 ? 1 : 2; + + switch (src_info.dimension) + { + case 1: + if (src_info.width & 1) + { + return false; + } + + src_info.target = gl::texture::target::texture1D; + break; + + case 2: + if ((src_info.width | src_info.height) & 1) + { + return false; + } + + src_info.target = gl::texture::target::texture2D; + break; + } + + switch (src_color_format) + { + case CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5: + src_info.format = gl::get_texture_format(CELL_GCM_TEXTURE_R5G6B5); + break; + + case CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8: + src_info.format = gl::get_texture_format(CELL_GCM_TEXTURE_A8R8G8B8); + break; + + default: + return false; + } + + u32 dst_x = 0; + u32 dst_y = 0; + + gl::texture_info dst_info{}; + dst_info.start_address = dst_region.address; + + if (dst_region.tile) + { + dst_x = (dst_region.base % dst_region.tile->pitch) / out_bpp; + dst_y = dst_region.base / dst_region.tile->pitch; + + dst_info.width = dst_region.tile->pitch / out_bpp; + dst_info.height = dst_region.tile->size / dst_region.tile->pitch; + dst_info.pitch = dst_region.tile->pitch; + } + else + { + dst_info.start_address += out_x * out_bpp + out_y * out_pitch; + out_x = 0; + out_y = 0; + dst_info.width = out_w; + dst_info.height = out_h; + dst_info.pitch = out_pitch; + } + + dst_info.depth = 1; + dst_info.mipmap = 1; + dst_info.dimension = dst_info.height == 1 ? 1 : 2; + + switch (dst_info.dimension) + { + case 1: + if (dst_info.width & 1) + { + return false; + } + + dst_info.target = gl::texture::target::texture1D; + break; + + case 2: + if ((dst_info.width | dst_info.height) & 1) + { + return false; + } + + dst_info.target = gl::texture::target::texture2D; + break; + } + + dst_info.swizzled = context_surface == CELL_GCM_CONTEXT_SWIZZLE2D; + + switch (dst_color_format) + { + case CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5: + dst_info.format = gl::get_texture_format(CELL_GCM_TEXTURE_R5G6B5); + break; + + case CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8: + dst_info.format = gl::get_texture_format(CELL_GCM_TEXTURE_A8R8G8B8); + break; + + default: + return false; + } + + auto &src_texture = renderer->texture_cache.entry(src_info, gl::cache_buffers::local); + auto &dst_texture = renderer->texture_cache.entry(dst_info); + + dst_texture.ignore(gl::cache_buffers::local); + + u32 src_id = src_texture.view().id(); + gl::texture tmp; + + if (convert_w != src_info.width || convert_h != src_info.height) + { + tmp.create(src_info.target); + + __glcheck scale_texture(tmp, src_info.format.internal_format, { (int)convert_w, (int)convert_h }, + src_texture.view(), { (int)src_x + int(in_x), (int)src_y + int(in_y) }, { int(src_x + in_w), int(src_y + in_h) }); + + src_id = tmp.id(); + + src_x = 0; + src_y = 0; + } + + __glcheck glCopyImageSubData( + src_id, (GLenum)src_info.target, 0, src_x, src_y, 0, + dst_texture.view().id(), (GLenum)dst_info.target, 0, dst_x + out_x, dst_y + out_y, 0, + clip_w, clip_h, 1); + dst_texture.invalidate(gl::cache_buffers::host); + + return true; } using rsx_method_impl_t = bool(*)(u32, GLGSRender*); @@ -956,7 +1254,7 @@ using rsx_method_impl_t = bool(*)(u32, GLGSRender*); static const std::unordered_map g_gl_method_tbl = { { NV4097_CLEAR_SURFACE, nv4097_clear_surface }, - //{ NV3089_IMAGE_IN, nv3089_image_in }, + { NV3089_IMAGE_IN, nv3089_image_in }, }; bool GLGSRender::do_method(u32 cmd, u32 arg) @@ -1142,21 +1440,32 @@ u32 surface_format_to_texture_format(rsx::surface_color_format format) 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 surface_info(rsx::thread &rsx, rsx::surface_color_format format, u32 offset, u32 location, u32 width, u32 height, u32 pitch) { gl::texture_info info{}; + info.format = gl::get_texture_format(surface_format_to_texture_format(format)); + + rsx::tiled_region region = rsx.get_tiled_address(offset, location); + + if (region.tile && region.base == 0) + { + info.width = region.tile->pitch / info.format.bpp; + info.height = region.tile->size / region.tile->pitch; + info.pitch = region.tile->pitch; + } + else + { + info.width = width; + info.height = height; + info.pitch = pitch; + } - info.width = width; - info.height = height; info.depth = 1; - info.pitch = pitch; info.target = gl::texture::target::texture2D; info.dimension = 2; - info.start_address = rsx::get_address(offset, location); + info.start_address = region.address; info.mipmap = 1; - info.format = gl::get_texture_format(surface_format_to_texture_format(format)); - return info; } @@ -1209,7 +1518,7 @@ void GLGSRender::init_buffers(bool skip_reading) u32 pitch = rsx::method_registers[mr_color_pitch[index]]; bool swizzled = m_surface.type == CELL_GCM_SURFACE_SWIZZLE; - gl::texture_info info = surface_info(m_surface.color_format, offset, location, m_surface.width, m_surface.height, pitch); + gl::texture_info info = surface_info(*this, m_surface.color_format, offset, location, m_surface.width, m_surface.height, pitch); info.swizzled = swizzled; @@ -1248,12 +1557,24 @@ void GLGSRender::init_buffers(bool skip_reading) gl::texture_info info{}; - info.width = m_surface.width; - info.height = m_surface.height; + rsx::tiled_region region = get_tiled_address(offset, location); + + if (region.tile && region.base == 0) + { + info.width = region.tile->pitch / info.format.bpp; + info.height = region.tile->size / region.tile->pitch; + info.pitch = region.tile->pitch; + } + else + { + info.width = m_surface.width; + info.height = m_surface.height; + info.pitch = pitch; + } + info.depth = 1; - info.pitch = pitch; info.dimension = 2; - info.start_address = rsx::get_address(offset, location); + info.start_address = region.address; info.target = gl::texture::target::texture2D; info.format.bpp = bpp; info.mipmap = 1; @@ -1341,7 +1662,7 @@ void GLGSRender::flip(int buffer) glDisable(GL_LOGIC_OP); glDisable(GL_CULL_FACE); - gl::cached_texture& texture = texture_cache.entry(surface_info(rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset, + gl::cached_texture& texture = texture_cache.entry(surface_info(*this, rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL, buffer_width, buffer_height, buffer_pitch), gl::cache_buffers::local); //std::lock_guard lock(texture); @@ -1382,9 +1703,11 @@ void GLGSRender::flip(int buffer) gl::screen.clear(gl::buffers::color_depth_stencil); - __glcheck m_flip_fbo.blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical()); + __glcheck m_flip_fbo.blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear); m_frame->flip(m_context); + + texture_cache.update_protection(); } diff --git a/rpcs3/Emu/RSX/GL/GLProcTable.h b/rpcs3/Emu/RSX/GL/GLProcTable.h index ca90322c65..d932289104 100644 --- a/rpcs3/Emu/RSX/GL/GLProcTable.h +++ b/rpcs3/Emu/RSX/GL/GLProcTable.h @@ -177,6 +177,7 @@ OPENGL_PROC(PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC, CompressedTexSubImage1D); OPENGL_PROC(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, CompressedTexSubImage2D); OPENGL_PROC(PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, CompressedTexSubImage3D); OPENGL_PROC(PFNGLCLEARTEXIMAGEPROC, ClearTexImage); +OPENGL_PROC(PFNGLTEXSUBIMAGE3DPROC, TexSubImage3D); //ARB_Copy_Image OPENGL_PROC(PFNGLCOPYIMAGESUBDATAPROC, CopyImageSubData); diff --git a/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp b/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp index 1651f2ba7c..04c06f1cf8 100644 --- a/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp +++ b/rpcs3/Emu/RSX/GL/gl_texture_cache.cpp @@ -17,7 +17,14 @@ namespace gl { void cached_texture::read() { - cached_texture* found_texture = nullptr; + struct capability_texture + { + positioni src_pos; + positioni dst_pos; + cached_texture* texture; + }; + + std::vector found_textures; u32 texture_size = info.size(); m_parent_region->for_each(info.start_address, texture_size, [&](cached_texture& texture) @@ -27,24 +34,91 @@ namespace gl return; } - if (texture.info.start_address != info.start_address || - texture.info.pitch != info.pitch || - texture.info.height < info.height || - texture.info.width < info.width) + if (texture.info.pitch != info.pitch || texture.info.format.bpp != info.format.bpp) { return; } - found_texture = &texture; + capability_texture texture_info{}; + + if (texture.info.start_address < info.start_address) + { + if (texture.info.dimension > 2) + return; + + u32 diff = info.start_address - texture.info.start_address; + + texture_info.src_pos.y = diff / info.pitch; + texture_info.src_pos.x = (diff % info.pitch) / info.format.bpp; + + //texture.sync(cache_buffers::host); + } + else if (texture.info.start_address > info.start_address) + { + if (info.dimension > 2) + return; + + u32 diff = texture.info.start_address - info.start_address; + + texture_info.dst_pos.y = diff / info.pitch; + texture_info.dst_pos.x = (diff % info.pitch) / info.format.bpp; + + //texture.sync(gl::cache_buffers::host); + } + + texture_info.texture = &texture; + found_textures.push_back(texture_info); }); - if (found_texture) + u32 covered_width = 0, covered_height = 0, covered_depth = 0; + + while (found_textures.size() > 1) { - //read from local - __glcheck 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); + bool found = false; + + for (auto& tex : found_textures) + { + if (tex.dst_pos.x == covered_width) + { + covered_width += tex.texture->info.width; + found = true; + } + + if (tex.dst_pos.y == covered_height) + { + covered_height += tex.texture->info.height; + found = true; + } + + if (0 == covered_depth) + { + covered_depth += tex.texture->info.depth; + found = true; + } + } + + if (!found) + { + if (covered_width < info.width || covered_height < info.height || covered_depth < info.depth) + { + found_textures.clear(); + } + + break; + } + } + + if (!found_textures.empty()) + { + //read from locals + + for (auto &tex : found_textures) + { + __glcheck glCopyImageSubData( + tex.texture->gl_name, (GLenum)tex.texture->info.target, 0, tex.src_pos.x, tex.src_pos.y, 0, + gl_name, (GLenum)info.target, 0, tex.dst_pos.x, tex.dst_pos.y, 0, + std::min(tex.texture->info.width, info.width), std::min(tex.texture->info.height, info.height), std::min(tex.texture->info.depth, tex.texture->info.depth)); + } } else { @@ -53,6 +127,7 @@ namespace gl m_parent_region->for_each(info.start_address, texture_size, [](cached_texture& texture) { texture.sync(gl::cache_buffers::host); + //texture.invalidate(gl::cache_buffers::local); }); bind(); @@ -101,20 +176,48 @@ namespace gl glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_depth.id()); - __glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height, - (GLenum)info.format.format, (GLenum)info.format.type, nullptr); - + switch (info.dimension) + { + case 1: __glcheck glTexSubImage1D((GLenum)info.target, 0, 0, info.width, (GLenum)info.format.format, (GLenum)info.format.type, nullptr); break; + case 2: __glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height, (GLenum)info.format.format, (GLenum)info.format.type, nullptr); break; + case 3: __glcheck glTexSubImage3D((GLenum)info.target, 0, 0, 0, 0, info.width, info.height, info.depth, (GLenum)info.format.format, (GLenum)info.format.type, nullptr); break; + } + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } else if (info.compressed_size) { - __glcheck glCompressedTexSubImage2D((GLenum)info.target, 0, - 0, 0, info.width, info.height, - (GLenum)info.format.internal_format, - info.compressed_size, vm::base_priv(info.start_address)); + switch (info.dimension) + { + case 1: + __glcheck glCompressedTexSubImage1D((GLenum)info.target, 0, + 0, info.width, + (GLenum)info.format.internal_format, + info.compressed_size, vm::base_priv(info.start_address)); + break; + + case 2: + __glcheck glCompressedTexSubImage2D((GLenum)info.target, 0, + 0, 0, info.width, info.height, + (GLenum)info.format.internal_format, + info.compressed_size, vm::base_priv(info.start_address)); + break; + + case 3: + __glcheck glCompressedTexSubImage3D((GLenum)info.target, 0, + 0, 0, 0, info.width, info.height, info.depth, + (GLenum)info.format.internal_format, + info.compressed_size, vm::base_priv(info.start_address)); + break; + } } else { + if (info.dimension > 2) + { + LOG_ERROR(RSX, "unimplemented reading swizzled %uD texture", info.dimension); + } + void *pixels = vm::base_priv(info.start_address); std::unique_ptr linear_pixels; @@ -150,8 +253,12 @@ namespace gl .swap_bytes((info.format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none) .apply(); - __glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height, - (GLenum)info.format.format, (GLenum)info.format.type, pixels); + switch (info.dimension) + { + case 1: __glcheck glTexSubImage1D((GLenum)info.target, 0, 0, info.width, (GLenum)info.format.format, (GLenum)info.format.type, pixels); break; + case 2: __glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height, (GLenum)info.format.format, (GLenum)info.format.type, pixels); break; + case 3: __glcheck glTexSubImage3D((GLenum)info.target, 0, 0, 0, 0, info.width, info.height, info.depth, (GLenum)info.format.format, (GLenum)info.format.type, pixels); break; + } } if (info.mipmap > 1) @@ -351,16 +458,6 @@ namespace gl return cache_access::none; } - void cached_texture::lock() - { - m_parent_region->lock(); - } - - void cached_texture::unlock() - { - m_parent_region->unlock(); - } - void cached_texture::bind(uint index) const { if (index != ~0u) @@ -378,7 +475,15 @@ namespace gl glGenTextures(1, &gl_name); bind(); - __glcheck glTexStorage2D((GLenum)info.target, info.mipmap, (GLenum)info.format.internal_format, info.width, info.height); + + switch (info.dimension) + { + case 1: __glcheck glTexStorage1D((GLenum)info.target, info.mipmap, (GLenum)info.format.internal_format, info.width); break; + case 2: __glcheck glTexStorage2D((GLenum)info.target, info.mipmap, (GLenum)info.format.internal_format, info.width, info.height); break; + case 3: __glcheck glTexStorage3D((GLenum)info.target, info.mipmap, (GLenum)info.format.internal_format, info.width, info.height, info.depth); break; + default: + throw EXCEPTION("bad dimension %d", info.dimension); + } //__glcheck glClearTexImage(gl_name, 0, (GLenum)info.format.format, (GLenum)info.format.type, nullptr); } @@ -501,10 +606,12 @@ namespace gl for (auto &texture : region.m_textures) { texture.second.parent(this); + if (!m_textures.emplace(texture).second) + { + throw EXCEPTION(""); + } } - 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; @@ -512,7 +619,9 @@ namespace gl } else { - pages_count = (region.start_address + region.pages_count - start_address) / vm::page_size; + //[start_address, region.start_address + region.pages_count * vm::page_size) + + pages_count = (region.start_address + region.pages_count * vm::page_size - start_address) / vm::page_size; } } @@ -558,16 +667,6 @@ namespace gl m_textures.clear(); } - void protected_region::lock() - { - m_mtx.lock(); - } - - void protected_region::unlock() - { - m_mtx.unlock(); - } - cached_texture &texture_cache::entry(const texture_info &info, cache_buffers sync) { u32 aligned_address; @@ -595,30 +694,24 @@ namespace gl } } - std::vector regions = find_regions(aligned_address, aligned_size); + std::vector::iterator> regions = find_regions(aligned_address, aligned_size); protected_region *region; if (regions.empty()) { - region = &m_protected_regions[aligned_address]; + m_protected_regions.emplace_back(); + region = &m_protected_regions.back(); region->pages_count = aligned_size / vm::page_size; region->start_address = aligned_address; } else { - region = regions[0]; - - std::vector remove_addresses; + region = &*regions[0]; 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); + m_protected_regions.erase(regions[index]); } if (region->start_address > aligned_address) @@ -647,37 +740,37 @@ namespace gl { for (auto& entry : m_protected_regions) { - if (entry.first > address) + if (entry.start_address > address) { - break; + continue; } - if (address >= entry.first && address < entry.first + entry.second.size()) + if (address >= entry.start_address && address < entry.start_address + entry.size()) { - return &entry.second; + return &entry; } } return nullptr; } - std::vector texture_cache::find_regions(u32 address, u32 size) + std::vector::iterator> texture_cache::find_regions(u32 address, u32 size) { - std::vector result; + std::vector::iterator> result; - for (auto& entry : m_protected_regions) + for (auto it = m_protected_regions.begin(); it != m_protected_regions.end(); ++it) { - if (entry.first >= address + size) - { - break; - } - - if (entry.first + entry.second.size() <= address) + if (it->start_address >= address + size) { continue; } - result.push_back(&entry.second); + if (it->start_address + it->size() <= address) + { + continue; + } + + result.push_back(it); } return result; @@ -687,7 +780,7 @@ namespace gl { for (auto& entry : m_protected_regions) { - entry.second.protect(); + entry.protect(); } } @@ -695,7 +788,7 @@ namespace gl { for (auto& entry : m_protected_regions) { - entry.second.clear(); + entry.clear(); } m_protected_regions.clear(); diff --git a/rpcs3/Emu/RSX/GL/gl_texture_cache.h b/rpcs3/Emu/RSX/GL/gl_texture_cache.h index f1b69c08eb..59c909c3f1 100644 --- a/rpcs3/Emu/RSX/GL/gl_texture_cache.h +++ b/rpcs3/Emu/RSX/GL/gl_texture_cache.h @@ -108,9 +108,6 @@ namespace gl cache_access requires_protection() const; - void lock(); - void unlock(); - protected: void create(); void remove(); @@ -126,9 +123,7 @@ namespace gl private: std::unordered_map m_textures; - u32 m_current_protection = 0; - std::mutex m_mtx; public: u32 size() const @@ -150,19 +145,16 @@ namespace gl cached_texture& add(const texture_info& info); void clear(); - - void lock(); - void unlock(); }; class texture_cache { - std::map m_protected_regions; + std::list m_protected_regions; public: cached_texture &entry(const texture_info &info, cache_buffers sync = cache_buffers::none); protected_region *find_region(u32 address); - std::vector find_regions(u32 address, u32 size); + std::vector::iterator> 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 8c48d94568..43c58c0891 100644 --- a/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp +++ b/rpcs3/Emu/RSX/GL/rsx_gl_texture.cpp @@ -178,9 +178,13 @@ void rsx::gl_texture::bind(gl::texture_cache& cache, rsx::texture& tex) info.swizzled = is_swizzled; info.target = target; info.mipmap = target != gl::texture::target::texture_rectangle ? tex.mipmap() : 1; - info.min_lod = tex.min_lod() >> 8; - info.max_lod = tex.max_lod() >> 8; - info.lod_bias = tex.bias(); + + if (info.mipmap > 1) + { + info.min_lod = tex.min_lod() >> 8; + info.max_lod = tex.max_lod() >> 8; + info.lod_bias = tex.bias(); + } if (is_compressed) { diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index a7e170bbd0..2954ecb4b6 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -180,14 +180,12 @@ namespace rsx switch (tile->comp) { - case CELL_GCM_COMPMODE_C32_2X1: case CELL_GCM_COMPMODE_DISABLED: for (int y = 0; y < height; ++y) { memcpy(ptr + (offset_y + y) * tile->pitch + offset_x, (u8*)src + pitch * y, pitch); } break; - /* case CELL_GCM_COMPMODE_C32_2X1: for (u32 y = 0; y < height; ++y) { @@ -200,7 +198,6 @@ namespace rsx } } break; - */ case CELL_GCM_COMPMODE_C32_2X2: for (u32 y = 0; y < height; ++y) { @@ -233,14 +230,12 @@ namespace rsx switch (tile->comp) { - case CELL_GCM_COMPMODE_C32_2X1: case CELL_GCM_COMPMODE_DISABLED: for (int y = 0; y < height; ++y) { memcpy((u8*)dst + pitch * y, ptr + (offset_y + y) * tile->pitch + offset_x, pitch); } break; - /* case CELL_GCM_COMPMODE_C32_2X1: for (u32 y = 0; y < height; ++y) { @@ -252,7 +247,6 @@ namespace rsx } } break; - */ case CELL_GCM_COMPMODE_C32_2X2: for (u32 y = 0; y < height; ++y) { @@ -845,7 +839,7 @@ namespace rsx tiled_region thread::get_tiled_address(u32 offset, u32 location) { - u32 address = get_address(offset, location); + u32 address; GcmTileInfo *tile = find_tile(offset, location); u32 base = 0; @@ -855,6 +849,10 @@ namespace rsx base = offset - tile->offset; address = get_address(tile->offset, location); } + else + { + address = get_address(offset, location); + } return{ address, base, tile, (u8*)vm::base(address) }; } diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index fb6ae49a97..7f08ccdb9b 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -344,8 +344,8 @@ namespace rsx u8 in_inter = method_registers[NV3089_IMAGE_IN_FORMAT] >> 24; u32 src_color_format = method_registers[NV3089_SET_COLOR_FORMAT]; - f32 in_x = (method_registers[NV3089_IMAGE_IN] & 0xffff) / 16.f; - f32 in_y = (method_registers[NV3089_IMAGE_IN] >> 16) / 16.f; + f32 in_x = (arg & 0xffff) / 16.f; + f32 in_y = (arg >> 16) / 16.f; if (in_origin != CELL_GCM_TRANSFER_ORIGIN_CORNER) { @@ -395,7 +395,7 @@ namespace rsx 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; - u32 in_offset = u32(in_x * in_bpp + in_pitch * in_y); + u32 in_offset = u32(in_x) * u32(in_bpp + in_pitch * in_y); u32 out_offset = out_x * out_bpp + out_pitch * out_y; tiled_region src_region = rsx->get_tiled_address(src_offset + in_offset, src_dma & 0xf);//get_address(src_offset, src_dma); @@ -473,7 +473,7 @@ namespace rsx if (size > src_region.tile->size - src_region.base) { u32 diff = size - (src_region.tile->size - src_region.base); - slice_h -= diff / in_pitch + (diff % in_pitch ? 1 : 0); + slice_h -= (diff + in_pitch - 1) / in_pitch; } } @@ -503,7 +503,7 @@ namespace rsx } else { - if (out_pitch != in_pitch || out_pitch != out_bpp * out_w) + if (out_pitch != in_pitch || out_pitch != out_bpp * out_w || in_pitch != in_bpp * in_w) { for (u32 y = 0; y < out_h; ++y) { @@ -561,10 +561,12 @@ namespace rsx u8* linear_pixels = pixels_src; u8* swizzled_pixels = temp2.get(); + std::unique_ptr sw_temp; + // Check and pad texture out if we are given non square texture for swizzle to be correct if (sw_width != out_w || sw_height != out_h) { - std::unique_ptr sw_temp(new u8[out_bpp * sw_width * sw_height]); + sw_temp.reset(new u8[out_bpp * sw_width * sw_height]); switch (out_bpp) {