Adjust blit src{X,Y} to account for centred sampling before calling into helper shader

Since the blit engine itself samples from pixel corners and the helper shader from pixel centres teh src coordinates need to be adjusted to avoid the helper shader wrapping round on the final column.
This commit is contained in:
Billy Laws 2022-08-10 15:39:37 +01:00
parent 08f36aac33
commit c32bec071c
5 changed files with 27 additions and 20 deletions

View File

@ -108,7 +108,7 @@ namespace skyline::gpu::interconnect {
Fermi2D::Fermi2D(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor) {} Fermi2D::Fermi2D(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), channelCtx(channelCtx), executor(executor) {}
void Fermi2D::Blit(const Surface &srcSurface, const Surface &dstSurface, float srcRectX, float srcRectY, u32 dstRectWidth, u32 dstRectHeight, u32 dstRectX, u32 dstRectY, float duDx, float dvDy, bool resolve, bool bilinearFilter) { void Fermi2D::Blit(const Surface &srcSurface, const Surface &dstSurface, float srcRectX, float srcRectY, u32 dstRectWidth, u32 dstRectHeight, u32 dstRectX, u32 dstRectY, float duDx, float dvDy, SampleModeOrigin sampleOrigin, bool resolve, SampleModeFilter filter) {
// TODO: When we support MSAA perform a resolve operation rather than blit when the `resolve` flag is set. // TODO: When we support MSAA perform a resolve operation rather than blit when the `resolve` flag is set.
auto srcGuestTexture{GetGuestTexture(srcSurface)}; auto srcGuestTexture{GetGuestTexture(srcSurface)};
auto dstGuestTexture{GetGuestTexture(dstSurface)}; auto dstGuestTexture{GetGuestTexture(dstSurface)};
@ -120,13 +120,17 @@ namespace skyline::gpu::interconnect {
auto dstTextureView{textureManager.FindOrCreate(dstGuestTexture, executor.tag)}; auto dstTextureView{textureManager.FindOrCreate(dstGuestTexture, executor.tag)};
executor.AttachTexture(dstTextureView.get()); executor.AttachTexture(dstTextureView.get());
// Blit shader always samples from centre so adjust if necessary
float centredSrcRectX{sampleOrigin == SampleModeOrigin::Corner ? srcRectX - 0.5f : srcRectX};
float centredSrcRectY{sampleOrigin == SampleModeOrigin::Corner ? srcRectY - 0.5f : srcRectY};
gpu.helperShaders.blitHelperShader.Blit( gpu.helperShaders.blitHelperShader.Blit(
gpu, gpu,
{ {
.width = duDx * dstRectWidth, .width = duDx * dstRectWidth,
.height = dvDy * dstRectHeight, .height = dvDy * dstRectHeight,
.x = srcRectX, .x = centredSrcRectX,
.y = srcRectY, .y = centredSrcRectY,
}, },
{ {
.width = static_cast<float>(dstRectWidth), .width = static_cast<float>(dstRectWidth),
@ -136,7 +140,7 @@ namespace skyline::gpu::interconnect {
}, },
srcGuestTexture.dimensions, dstGuestTexture.dimensions, srcGuestTexture.dimensions, dstGuestTexture.dimensions,
duDx, dvDy, duDx, dvDy,
bilinearFilter, filter == SampleModeFilter::Bilinear,
srcTextureView.get(), dstTextureView.get(), srcTextureView.get(), dstTextureView.get(),
[=](auto &&executionCallback) { [=](auto &&executionCallback) {
auto dst{dstTextureView.get()}; auto dst{dstTextureView.get()};

View File

@ -26,6 +26,8 @@ namespace skyline::gpu::interconnect {
private: private:
using IOVA = soc::gm20b::IOVA; using IOVA = soc::gm20b::IOVA;
using Surface = skyline::soc::gm20b::engine::fermi2d::type::Surface; using Surface = skyline::soc::gm20b::engine::fermi2d::type::Surface;
using SampleModeOrigin = skyline::soc::gm20b::engine::fermi2d::type::SampleModeOrigin;
using SampleModeFilter = skyline::soc::gm20b::engine::fermi2d::type::SampleModeFilter;
GPU &gpu; GPU &gpu;
soc::gm20b::ChannelContext &channelCtx; soc::gm20b::ChannelContext &channelCtx;
@ -36,6 +38,6 @@ namespace skyline::gpu::interconnect {
public: public:
Fermi2D(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor); Fermi2D(GPU &gpu, soc::gm20b::ChannelContext &channelCtx, gpu::interconnect::CommandExecutor &executor);
void Blit(const Surface &srcSurface, const Surface &dstSurface, float srcRectX, float srcRectY, u32 dstRectWidth, u32 dstRectHeight, u32 dstRectX, u32 dstRectY, float duDx, float dvDy, bool resolve, bool bilinearFilter); void Blit(const Surface &srcSurface, const Surface &dstSurface, float srcRectX, float srcRectY, u32 dstRectWidth, u32 dstRectHeight, u32 dstRectX, u32 dstRectY, float duDx, float dvDy, SampleModeOrigin sampleOrigin, bool resolve, SampleModeFilter filter);
}; };
} }

View File

@ -89,5 +89,15 @@ namespace skyline::soc::gm20b::engine::fermi2d::type {
Address address; Address address;
}; };
enum class SampleModeOrigin : u8 {
Center = 0,
Corner = 1
};
enum class SampleModeFilter : u8 {
Point = 0,
Bilinear = 1
};
#pragma pack(pop) #pragma pack(pop)
} }

View File

@ -41,7 +41,7 @@ namespace skyline::soc::gm20b::engine::fermi2d {
float duDx{fixedToFloating(pixelsFromMemory.duDx)}; float duDx{fixedToFloating(pixelsFromMemory.duDx)};
float dvDy{fixedToFloating(pixelsFromMemory.dvDy)}; float dvDy{fixedToFloating(pixelsFromMemory.dvDy)};
if (registers.pixelsFromMemory->sampleMode.origin == Registers::PixelsFromMemory::SampleModeOrigin::Center) { if (registers.pixelsFromMemory->sampleMode.origin == type::SampleModeOrigin::Center) {
// This is an MSAA resolve operation, sampling from the center of each pixel in order to resolve the final image from the MSAA samples // This is an MSAA resolve operation, sampling from the center of each pixel in order to resolve the final image from the MSAA samples
// MSAA images are stored in memory like regular images but each pixels dimensions are scaled: e.g for 2x2 MSAA // MSAA images are stored in memory like regular images but each pixels dimensions are scaled: e.g for 2x2 MSAA
/* 112233 /* 112233
@ -61,8 +61,9 @@ namespace skyline::soc::gm20b::engine::fermi2d {
pixelsFromMemory.dstWidth, pixelsFromMemory.dstHeight, pixelsFromMemory.dstWidth, pixelsFromMemory.dstHeight,
pixelsFromMemory.dstX0, pixelsFromMemory.dstY0, pixelsFromMemory.dstX0, pixelsFromMemory.dstY0,
duDx, dvDy, duDx, dvDy,
registers.pixelsFromMemory->sampleMode.origin == Registers::PixelsFromMemory::SampleModeOrigin::Center, registers.pixelsFromMemory->sampleMode.origin,
pixelsFromMemory.sampleMode.filter == Registers::PixelsFromMemory::SampleModeFilter::Bilinear); registers.pixelsFromMemory->sampleMode.origin == type::SampleModeOrigin::Center,
pixelsFromMemory.sampleMode.filter);
} }
} }

View File

@ -46,16 +46,6 @@ namespace skyline::soc::gm20b::engine::fermi2d {
Shape16x4 = 2 Shape16x4 = 2
}; };
enum class SampleModeOrigin : u8 {
Center = 0,
Corner = 1
};
enum class SampleModeFilter : u8 {
Point = 0,
Bilinear = 1
};
BlockShapeV blockShape : 3; BlockShapeV blockShape : 3;
u32 _pad0_ : 29; u32 _pad0_ : 29;
u16 corralSize : 10; u16 corralSize : 10;
@ -63,9 +53,9 @@ namespace skyline::soc::gm20b::engine::fermi2d {
bool safeOverlap : 1; bool safeOverlap : 1;
u32 _pad2_ : 31; u32 _pad2_ : 31;
struct { struct {
SampleModeOrigin origin : 1; type::SampleModeOrigin origin : 1;
u8 _pad0_ : 3; u8 _pad0_ : 3;
SampleModeFilter filter : 1; type::SampleModeFilter filter : 1;
u32 _pad1_ : 27; u32 _pad1_ : 27;
} sampleMode; } sampleMode;