From ce452049d3053662b3a0af6ad26eb267a699c742 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 14 Sep 2018 11:33:55 -0400 Subject: [PATCH] gl_rasterizer_cache: Keep track of surface 2D size separately from total size. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 60 +++++++++++-------- .../renderer_opengl/gl_rasterizer_cache.h | 18 ++++-- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 24a540258..b11206925 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -71,7 +71,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { break; } - params.size_in_bytes = params.SizeInBytes(); + params.size_in_bytes_total = params.SizeInBytesTotal(); + params.size_in_bytes_2d = params.SizeInBytes2D(); return params; } @@ -89,7 +90,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; params.depth = 1; - params.size_in_bytes = params.SizeInBytes(); + params.size_in_bytes_total = params.SizeInBytesTotal(); + params.size_in_bytes_2d = params.SizeInBytes2D(); return params; } @@ -108,7 +110,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { params.unaligned_height = zeta_height; params.target = SurfaceTarget::Texture2D; params.depth = 1; - params.size_in_bytes = params.SizeInBytes(); + params.size_in_bytes_total = params.SizeInBytesTotal(); + params.size_in_bytes_2d = params.SizeInBytes2D(); return params; } @@ -585,10 +588,13 @@ void CachedSurface::LoadGLBuffer() { const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format); const u32 copy_size = params.width * params.height * bytes_per_pixel; + const std::size_t total_size = copy_size * params.depth; MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); if (params.is_tiled) { + gl_buffer.resize(total_size); + // TODO(bunnei): This only unswizzles and copies a 2D texture - we do not yet know how to do // this for 3D textures, etc. switch (params.target) { @@ -601,13 +607,11 @@ void CachedSurface::LoadGLBuffer() { UNREACHABLE(); } - gl_buffer.resize(static_cast(params.depth) * copy_size); morton_to_gl_fns[static_cast(params.pixel_format)]( params.width, params.block_height, params.height, gl_buffer.data(), copy_size, params.addr); } else { - const u8* const texture_src_data_end{texture_src_data + - (static_cast(params.depth) * copy_size)}; + const u8* const texture_src_data_end{texture_src_data + total_size}; gl_buffer.assign(texture_src_data, texture_src_data_end); } @@ -663,15 +667,15 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle glCompressedTexImage2D( SurfaceTargetToGL(params.target), 0, tuple.internal_format, static_cast(params.width), static_cast(params.height), 0, - static_cast(params.size_in_bytes), &gl_buffer[buffer_offset]); + static_cast(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); break; case SurfaceParams::SurfaceTarget::Texture3D: case SurfaceParams::SurfaceTarget::Texture2DArray: glCompressedTexImage3D( SurfaceTargetToGL(params.target), 0, tuple.internal_format, static_cast(params.width), static_cast(params.height), - static_cast(params.depth), 0, static_cast(params.size_in_bytes), - &gl_buffer[buffer_offset]); + static_cast(params.depth), 0, + static_cast(params.size_in_bytes_total), &gl_buffer[buffer_offset]); break; default: LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", @@ -679,8 +683,8 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle UNREACHABLE(); glCompressedTexImage2D( GL_TEXTURE_2D, 0, tuple.internal_format, static_cast(params.width), - static_cast(params.height), 0, static_cast(params.size_in_bytes), - &gl_buffer[buffer_offset]); + static_cast(params.height), 0, + static_cast(params.size_in_bytes_2d), &gl_buffer[buffer_offset]); } } else { @@ -811,15 +815,15 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { return surface; } -Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, +Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, const SurfaceParams& new_params) { // Verify surface is compatible for blitting - const auto& params{surface->GetSurfaceParams()}; + const auto& old_params{old_surface->GetSurfaceParams()}; // Get a new surface with the new parameters, and blit the previous surface to it Surface new_surface{GetUncachedSurface(new_params)}; - if (params.pixel_format == new_params.pixel_format || + if (old_params.pixel_format == new_params.pixel_format || !Settings::values.use_accurate_framebuffers) { // If the format is the same, just do a framebuffer blit. This is significantly faster than // using PBOs. The is also likely less accurate, as textures will be converted rather than @@ -833,24 +837,26 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // where pixels are reinterpreted as a new format (without conversion). This code path uses // OpenGL PBOs and is quite slow. - auto source_format = GetFormatTuple(params.pixel_format, params.component_type); + auto source_format = GetFormatTuple(old_params.pixel_format, old_params.component_type); auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); - std::size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); + std::size_t buffer_size = + std::max(old_params.size_in_bytes_total, new_params.size_in_bytes_total); glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); if (source_format.compressed) { - glGetCompressedTextureImage(surface->Texture().handle, 0, - static_cast(params.SizeInBytes()), nullptr); + glGetCompressedTextureImage(old_surface->Texture().handle, 0, + static_cast(old_params.size_in_bytes_total), + nullptr); } else { - glGetTextureImage(surface->Texture().handle, 0, source_format.format, - source_format.type, static_cast(params.SizeInBytes()), - nullptr); + glGetTextureImage(old_surface->Texture().handle, 0, source_format.format, + source_format.type, + static_cast(old_params.size_in_bytes_total), nullptr); } // If the new texture is bigger than the previous one, we need to fill in the rest with data // from the CPU. - if (params.SizeInBytes() < new_params.SizeInBytes()) { + if (old_params.size_in_bytes_total < new_params.size_in_bytes_total) { // Upload the rest of the memory. if (new_params.is_tiled) { // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest @@ -860,10 +866,12 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " "reinterpretation but the texture is tiled."); } - std::size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); + std::size_t remaining_size = + new_params.size_in_bytes_total - old_params.size_in_bytes_total; std::vector data(remaining_size); - Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size()); - glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size, + Memory::ReadBlock(new_params.addr + old_params.size_in_bytes_total, data.data(), + data.size()); + glBufferSubData(GL_PIXEL_PACK_BUFFER, old_params.size_in_bytes_total, remaining_size, data.data()); } @@ -898,7 +906,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, break; default: LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", - static_cast(params.target)); + static_cast(new_params.target)); UNREACHABLE(); } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 80c5f324b..9df909d01 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -689,13 +689,18 @@ struct SurfaceParams { /// Returns the rectangle corresponding to this surface MathUtil::Rectangle GetRect() const; - /// Returns the size of this surface in bytes, adjusted for compression - std::size_t SizeInBytes() const { + /// Returns the size of this surface as a 2D texture in bytes, adjusted for compression + std::size_t SizeInBytes2D() const { const u32 compression_factor{GetCompressionFactor(pixel_format)}; ASSERT(width % compression_factor == 0); ASSERT(height % compression_factor == 0); return (width / compression_factor) * (height / compression_factor) * - GetFormatBpp(pixel_format) * depth / CHAR_BIT; + GetFormatBpp(pixel_format) / CHAR_BIT; + } + + /// Returns the total size of this surface in bytes, adjusted for compression + std::size_t SizeInBytesTotal() const { + return SizeInBytes2D() * depth; } /// Creates SurfaceParams from a texture configuration @@ -725,7 +730,8 @@ struct SurfaceParams { u32 height; u32 depth; u32 unaligned_height; - std::size_t size_in_bytes; + std::size_t size_in_bytes_total; + std::size_t size_in_bytes_2d; SurfaceTarget target; }; @@ -759,7 +765,7 @@ public: } std::size_t GetSizeInBytes() const { - return params.size_in_bytes; + return params.size_in_bytes_total; } const OGLTexture& Texture() const { @@ -822,7 +828,7 @@ private: Surface GetUncachedSurface(const SurfaceParams& params); /// Recreates a surface with new parameters - Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params); + Surface RecreateSurface(const Surface& old_surface, const SurfaceParams& new_params); /// Reserves a unique surface that can be reused later void ReserveSurface(const Surface& surface);