diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9b01bfc8c..17339c66b 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -404,61 +404,69 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) { } void RasterizerFlushRegion(PAddr start, u32 size) { - if (VideoCore::g_renderer != nullptr) { - VideoCore::g_renderer->Rasterizer()->FlushRegion(start, size); + if (VideoCore::g_renderer == nullptr) { + return; } + + VideoCore::g_renderer->Rasterizer()->FlushRegion(start, size); } void RasterizerInvalidateRegion(PAddr start, u32 size) { - if (VideoCore::g_renderer != nullptr) { - VideoCore::g_renderer->Rasterizer()->InvalidateRegion(start, size); + if (VideoCore::g_renderer == nullptr) { + return; } + + VideoCore::g_renderer->Rasterizer()->InvalidateRegion(start, size); } void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) { // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be // null here - if (VideoCore::g_renderer != nullptr) { - VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); + if (VideoCore::g_renderer == nullptr) { + return; } + + VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size); } void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) { // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be // null here - if (VideoCore::g_renderer != nullptr) { - VAddr end = start + size; - - auto CheckRegion = [&](VAddr region_start, VAddr region_end) { - if (start >= region_end || end <= region_start) { - // No overlap with region - return; - } - - VAddr overlap_start = std::max(start, region_start); - VAddr overlap_end = std::min(end, region_end); - - PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value(); - u32 overlap_size = overlap_end - overlap_start; - - auto* rasterizer = VideoCore::g_renderer->Rasterizer(); - switch (mode) { - case FlushMode::Flush: - rasterizer->FlushRegion(physical_start, overlap_size); - break; - case FlushMode::Invalidate: - rasterizer->InvalidateRegion(physical_start, overlap_size); - break; - case FlushMode::FlushAndInvalidate: - rasterizer->FlushAndInvalidateRegion(physical_start, overlap_size); - break; - } - }; - - CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END); - CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END); - CheckRegion(VRAM_VADDR, VRAM_VADDR_END); + if (VideoCore::g_renderer == nullptr) { + return; } + + VAddr end = start + size; + + auto CheckRegion = [&](VAddr region_start, VAddr region_end) { + if (start >= region_end || end <= region_start) { + // No overlap with region + return; + } + + VAddr overlap_start = std::max(start, region_start); + VAddr overlap_end = std::min(end, region_end); + + PAddr physical_start = TryVirtualToPhysicalAddress(overlap_start).value(); + u32 overlap_size = overlap_end - overlap_start; + + auto* rasterizer = VideoCore::g_renderer->Rasterizer(); + switch (mode) { + case FlushMode::Flush: + rasterizer->FlushRegion(physical_start, overlap_size); + break; + case FlushMode::Invalidate: + rasterizer->InvalidateRegion(physical_start, overlap_size); + break; + case FlushMode::FlushAndInvalidate: + rasterizer->FlushAndInvalidateRegion(physical_start, overlap_size); + break; + } + }; + + CheckRegion(LINEAR_HEAP_VADDR, LINEAR_HEAP_VADDR_END); + CheckRegion(NEW_LINEAR_HEAP_VADDR, NEW_LINEAR_HEAP_VADDR_END); + CheckRegion(VRAM_VADDR, VRAM_VADDR_END); } u8 Read8(const VAddr addr) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 6b3bbaab8..f4ead0848 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1150,8 +1150,8 @@ void RasterizerOpenGL::SamplerInfo::Create() { wrap_s = wrap_t = TextureConfig::Repeat; border_color = 0; - glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR + // default is GL_LINEAR_MIPMAP_LINEAR + glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Other attributes have correct defaults } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 37c2abe3d..4e7dc1048 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -34,8 +34,6 @@ using SurfaceType = SurfaceParams::SurfaceType; using PixelFormat = SurfaceParams::PixelFormat; -static std::array transfer_framebuffers; - struct FormatTuple { GLint internal_format; GLenum format; @@ -153,7 +151,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr glbuf_next_tile(); } - u8* const buffer_end = tile_buffer + aligned_end - aligned_start; + const u8* const buffer_end = tile_buffer + aligned_end - aligned_start; while (tile_buffer < buffer_end) { MortonCopyTile(stride, tile_buffer, gl_buffer); tile_buffer += tile_size; @@ -234,7 +232,8 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup } static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle& src_rect, GLuint dst_tex, - const MathUtil::Rectangle& dst_rect, SurfaceType type) { + const MathUtil::Rectangle& dst_rect, SurfaceType type, + GLuint read_handle, GLuint draw_handle) { OpenGLState state = OpenGLState::GetCurState(); OpenGLState prev_state = state; @@ -246,8 +245,8 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle& src_rec state.ResetTexture(dst_tex); // Keep track of previous framebuffer bindings - state.draw.read_framebuffer = transfer_framebuffers[0].handle; - state.draw.draw_framebuffer = transfer_framebuffers[1].handle; + state.draw.read_framebuffer = read_handle; + state.draw.draw_framebuffer = draw_handle; state.Apply(); u32 buffers = 0; @@ -294,7 +293,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle& src_rec } static bool FillSurface(const Surface& surface, const u8* fill_data, - const MathUtil::Rectangle& fill_rect) { + const MathUtil::Rectangle& fill_rect, GLuint draw_handle) { OpenGLState state = OpenGLState::GetCurState(); OpenGLState prev_state = state; @@ -308,7 +307,7 @@ static bool FillSurface(const Surface& surface, const u8* fill_data, state.scissor.width = static_cast(fill_rect.GetWidth()); state.scissor.height = static_cast(fill_rect.GetHeight()); - state.draw.draw_framebuffer = transfer_framebuffers[1].handle; + state.draw.draw_framebuffer = draw_handle; state.Apply(); if (surface->type == SurfaceType::Color || surface->type == SurfaceType::Texture) { @@ -610,13 +609,14 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac for (int i : {0, 1, 2, 3}) fill_buffer[i] = src_surface->fill_data[fill_buff_pos++ % src_surface->fill_size]; - FillSurface(dst_surface, &fill_buffer[0], dst_surface->GetScaledSubRect(subrect_params)); + FillSurface(dst_surface, &fill_buffer[0], dst_surface->GetScaledSubRect(subrect_params), + draw_framebuffer.handle); return; } if (src_surface->CanSubRect(subrect_params)) { BlitTextures(src_surface->texture.handle, src_surface->GetScaledSubRect(subrect_params), dst_surface->texture.handle, dst_surface->GetScaledSubRect(subrect_params), - src_surface->type); + src_surface->type, read_framebuffer.handle, draw_framebuffer.handle); return; } UNREACHABLE(); @@ -777,7 +777,7 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle& rect) { scaled_rect.bottom *= res_scale; BlitTextures(unscaled_tex.handle, {0, rect.GetHeight(), rect.GetWidth(), 0}, texture.handle, - scaled_rect, type); + scaled_rect, type, read_framebuffer_handle, draw_framebuffer_handle); } } @@ -814,7 +814,8 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle& rect) { MathUtil::Rectangle unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); - BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type); + BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type, + read_framebuffer_handle, draw_framebuffer_handle); state.texture_units[0].texture_2d = unscaled_tex.handle; state.Apply(); @@ -823,7 +824,7 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle& rect) { glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]); } else { state.ResetTexture(texture.handle); - state.draw.read_framebuffer = transfer_framebuffers[0].handle; + state.draw.read_framebuffer = read_framebuffer_handle; state.Apply(); if (type == SurfaceType::Color || type == SurfaceType::Texture) { @@ -952,16 +953,16 @@ Surface FindMatch(const SurfaceCache& surface_cache, const SurfaceParams& params } RasterizerCacheOpenGL::RasterizerCacheOpenGL() { - transfer_framebuffers[0].Create(); - transfer_framebuffers[1].Create(); + read_framebuffer.Create(); + draw_framebuffer.Create(); } RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { FlushAll(); while (!surface_cache.empty()) UnregisterSurface(*surface_cache.begin()->second.begin()); - transfer_framebuffers[0].Release(); - transfer_framebuffers[1].Release(); + read_framebuffer.Release(); + draw_framebuffer.Release(); } bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, @@ -972,7 +973,8 @@ bool RasterizerCacheOpenGL::BlitSurfaces(const Surface& src_surface, return false; return BlitTextures(src_surface->texture.handle, src_rect, dst_surface->texture.handle, - dst_rect, src_surface->type); + dst_rect, src_surface->type, read_framebuffer.handle, + draw_framebuffer.handle); } Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, @@ -1203,6 +1205,9 @@ Surface RasterizerCacheOpenGL::GetFillSurface(const GPU::Regs::MemoryFillConfig& new_surface->size = new_surface->end - new_surface->addr; new_surface->type = SurfaceType::Fill; new_surface->res_scale = std::numeric_limits::max(); + new_surface->read_framebuffer_handle = read_framebuffer.handle; + new_surface->draw_framebuffer_handle = draw_framebuffer.handle; + std::memcpy(&new_surface->fill_data[0], &config.value_32bit, 4); if (config.fill_32bit) { new_surface->fill_size = 4; @@ -1274,7 +1279,7 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr, return; } - for (;;) { + while (true) { const auto it = surface->invalid_regions.find(validate_interval); if (it == surface->invalid_regions.end()) break; @@ -1309,6 +1314,8 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, Surface flush_surf for (auto& pair : RangeFromInterval(dirty_regions, flush_interval)) { // small sizes imply that this most likely comes from the cpu, flush the entire region + // the point is to avoid thousands of small writes every frame if the cpu decides to access + // that region, anything higher than 8 you're guaranteed it comes from a service const auto interval = size <= 8 ? pair.first : pair.first & flush_interval; auto& surface = pair.second; @@ -1397,6 +1404,8 @@ void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u32 size, const Surface Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) { Surface surface = std::make_shared(); static_cast(*surface) = params; + surface->read_framebuffer_handle = read_framebuffer.handle; + surface->draw_framebuffer_handle = draw_framebuffer.handle; surface->texture.Create(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index e4db19af7..c4632f24e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -224,11 +224,11 @@ struct SurfaceParams { } u32 PixelsInBytes(u32 size) const { - return size * 8 / GetFormatBpp(pixel_format); + return size * CHAR_BIT / GetFormatBpp(pixel_format); } u32 BytesInPixels(u32 pixels) const { - return pixels * GetFormatBpp(pixel_format) / 8; + return pixels * GetFormatBpp(pixel_format) / CHAR_BIT; } bool ExactMatch(const SurfaceParams& other_surface) const; @@ -284,6 +284,9 @@ struct CachedSurface : SurfaceParams { std::unique_ptr gl_buffer; size_t gl_buffer_size = 0; + GLuint read_framebuffer_handle; + GLuint draw_framebuffer_handle; + // Read/Write data in 3DS memory to/from gl_buffer void LoadGLBuffer(PAddr load_start, PAddr load_end); void FlushGLBuffer(PAddr flush_start, PAddr flush_end); @@ -359,4 +362,6 @@ private: SurfaceMap dirty_regions; PageMap cached_pages; SurfaceSet remove_surfaces; + OGLFramebuffer read_framebuffer; + OGLFramebuffer draw_framebuffer; };