forked from suyu/suyu
gl_rasterizer_cache: Improve accuracy of RecreateSurface for non-2D textures.
This commit is contained in:
parent
fdd5c97a14
commit
23ae7cf9db
2 changed files with 45 additions and 27 deletions
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
@ -54,8 +55,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.depth = config.tic.Depth();
|
params.depth = config.tic.Depth();
|
||||||
params.unaligned_height = config.tic.Height();
|
params.unaligned_height = config.tic.Height();
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
|
params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
@ -74,8 +75,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.depth = 1;
|
params.depth = 1;
|
||||||
params.unaligned_height = config.height;
|
params.unaligned_height = config.height;
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
params.target = SurfaceTarget::Texture2D;
|
params.target = SurfaceTarget::Texture2D;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
@ -95,8 +96,8 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
|
||||||
params.depth = 1;
|
params.depth = 1;
|
||||||
params.unaligned_height = zeta_height;
|
params.unaligned_height = zeta_height;
|
||||||
params.size_in_bytes = params.SizeInBytes();
|
params.size_in_bytes = params.SizeInBytes();
|
||||||
params.cache_width = Common::AlignUp(params.width, 16);
|
params.cache_width = Common::AlignUp(params.width, 8);
|
||||||
params.cache_height = Common::AlignUp(params.height, 16);
|
params.cache_height = Common::AlignUp(params.height, 8);
|
||||||
params.target = SurfaceTarget::Texture2D;
|
params.target = SurfaceTarget::Texture2D;
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
@ -697,6 +698,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
||||||
read_framebuffer.Create();
|
read_framebuffer.Create();
|
||||||
draw_framebuffer.Create();
|
draw_framebuffer.Create();
|
||||||
|
copy_pbo.Create();
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
|
Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
|
||||||
|
@ -827,8 +829,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
|
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
|
||||||
if (params.pixel_format == new_params.pixel_format) {
|
if (params.pixel_format == new_params.pixel_format) {
|
||||||
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
|
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
|
||||||
new_surface->GetSurfaceParams().GetRect(), params.type,
|
params.GetRect(), params.type, read_framebuffer.handle,
|
||||||
read_framebuffer.handle, draw_framebuffer.handle);
|
draw_framebuffer.handle);
|
||||||
return new_surface;
|
return new_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,12 +841,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
|
|
||||||
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
|
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
|
||||||
|
|
||||||
// Use a Pixel Buffer Object to download the previous texture and then upload it to the new
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
|
||||||
// one using the new format.
|
|
||||||
OGLBuffer pbo;
|
|
||||||
pbo.Create();
|
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
|
|
||||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
||||||
if (source_format.compressed) {
|
if (source_format.compressed) {
|
||||||
glGetCompressedTextureImage(surface->Texture().handle, 0,
|
glGetCompressedTextureImage(surface->Texture().handle, 0,
|
||||||
|
@ -863,7 +860,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
// of the data in this case. Games like Super Mario Odyssey seem to hit this case
|
// of the data in this case. Games like Super Mario Odyssey seem to hit this case
|
||||||
// when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
|
// when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
|
||||||
// but it doesn't clear it beforehand, the texture is already full of zeros.
|
// but it doesn't clear it beforehand, the texture is already full of zeros.
|
||||||
LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
|
LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
|
||||||
"reinterpretation but the texture is tiled.");
|
"reinterpretation but the texture is tiled.");
|
||||||
}
|
}
|
||||||
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
|
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
|
||||||
|
@ -877,21 +874,38 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
|
|
||||||
const auto& dest_rect{new_params.GetRect()};
|
const auto& dest_rect{new_params.GetRect()};
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle);
|
||||||
if (dest_format.compressed) {
|
if (dest_format.compressed) {
|
||||||
glCompressedTexSubImage2D(
|
LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!");
|
||||||
GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
|
UNREACHABLE();
|
||||||
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
|
||||||
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
|
|
||||||
} else {
|
} else {
|
||||||
|
switch (new_params.target) {
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||||
|
glTextureSubImage1D(new_surface->Texture().handle, 0, 0,
|
||||||
|
static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format,
|
||||||
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||||
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
|
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
|
||||||
static_cast<GLsizei>(dest_rect.GetWidth()),
|
static_cast<GLsizei>(dest_rect.GetWidth()),
|
||||||
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
|
||||||
dest_format.type, nullptr);
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||||
|
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||||
|
glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0,
|
||||||
|
static_cast<GLsizei>(dest_rect.GetWidth()),
|
||||||
|
static_cast<GLsizei>(dest_rect.GetHeight()),
|
||||||
|
static_cast<GLsizei>(new_params.depth), dest_format.format,
|
||||||
|
dest_format.type, nullptr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
|
||||||
|
static_cast<u32>(params.target));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
pbo.Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_surface;
|
return new_surface;
|
||||||
|
|
|
@ -807,6 +807,10 @@ private:
|
||||||
|
|
||||||
OGLFramebuffer read_framebuffer;
|
OGLFramebuffer read_framebuffer;
|
||||||
OGLFramebuffer draw_framebuffer;
|
OGLFramebuffer draw_framebuffer;
|
||||||
|
|
||||||
|
/// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one
|
||||||
|
/// using the new format.
|
||||||
|
OGLBuffer copy_pbo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
Loading…
Reference in a new issue