summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2019-02-08 23:32:24 -0500
committerGravatar GitHub2019-02-08 23:32:24 -0500
commit1d98027a0e7b64c638960869ea042aaba10dd04f (patch)
tree1dfa79b8d353e9d0ef7f79b96f73c5c8c7a5ba7b
parentMerge pull request #2096 from FearlessTobi/patch-3 (diff)
parentgl_rasterizer_cache: Mark surface copy destinations as modified. (diff)
downloadyuzu-1d98027a0e7b64c638960869ea042aaba10dd04f.tar.gz
yuzu-1d98027a0e7b64c638960869ea042aaba10dd04f.tar.xz
yuzu-1d98027a0e7b64c638960869ea042aaba10dd04f.zip
Merge pull request #1904 from bunnei/better-fermi-copy
gl_rasterizer: Implement a more accurate fermi 2D copy.
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/fermi_2d.cpp62
-rw-r--r--src/video_core/engines/fermi_2d.h29
-rw-r--r--src/video_core/rasterizer_interface.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp159
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h8
7 files changed, 206 insertions, 72 deletions
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 9f1533263..ec1a57226 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -21,7 +21,9 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) {
21 regs.reg_array[method_call.method] = method_call.argument; 21 regs.reg_array[method_call.method] = method_call.argument;
22 22
23 switch (method_call.method) { 23 switch (method_call.method) {
24 case FERMI2D_REG_INDEX(trigger): { 24 // Trigger the surface copy on the last register write. This is blit_src_y, but this is 64-bit,
25 // so trigger on the second 32-bit write.
26 case FERMI2D_REG_INDEX(blit_src_y) + 1: {
25 HandleSurfaceCopy(); 27 HandleSurfaceCopy();
26 break; 28 break;
27 } 29 }
@@ -32,57 +34,23 @@ void Fermi2D::HandleSurfaceCopy() {
32 LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}", 34 LOG_WARNING(HW_GPU, "Requested a surface copy with operation {}",
33 static_cast<u32>(regs.operation)); 35 static_cast<u32>(regs.operation));
34 36
35 const GPUVAddr source = regs.src.Address();
36 const GPUVAddr dest = regs.dst.Address();
37
38 // TODO(Subv): Only same-format and same-size copies are allowed for now.
39 ASSERT(regs.src.format == regs.dst.format);
40 ASSERT(regs.src.width * regs.src.height == regs.dst.width * regs.dst.height);
41
42 // TODO(Subv): Only raw copies are implemented. 37 // TODO(Subv): Only raw copies are implemented.
43 ASSERT(regs.operation == Regs::Operation::SrcCopy); 38 ASSERT(regs.operation == Regs::Operation::SrcCopy);
44 39
45 const auto source_cpu = memory_manager.GpuToCpuAddress(source); 40 const u32 src_blit_x1{static_cast<u32>(regs.blit_src_x >> 32)};
46 const auto dest_cpu = memory_manager.GpuToCpuAddress(dest); 41 const u32 src_blit_y1{static_cast<u32>(regs.blit_src_y >> 32)};
47 ASSERT_MSG(source_cpu, "Invalid source GPU address"); 42 const u32 src_blit_x2{
48 ASSERT_MSG(dest_cpu, "Invalid destination GPU address"); 43 static_cast<u32>((regs.blit_src_x + (regs.blit_dst_width * regs.blit_du_dx)) >> 32)};
49 44 const u32 src_blit_y2{
50 u32 src_bytes_per_pixel = RenderTargetBytesPerPixel(regs.src.format); 45 static_cast<u32>((regs.blit_src_y + (regs.blit_dst_height * regs.blit_dv_dy)) >> 32)};
51 u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format);
52
53 if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) {
54 // All copies here update the main memory, so mark all rasterizer states as invalid.
55 Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite();
56 46
57 rasterizer.FlushRegion(*source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); 47 const MathUtil::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
58 // We have to invalidate the destination region to evict any outdated surfaces from the 48 const MathUtil::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y,
59 // cache. We do this before actually writing the new data because the destination address 49 regs.blit_dst_x + regs.blit_dst_width,
60 // might contain a dirty surface that will have to be written back to memory. 50 regs.blit_dst_y + regs.blit_dst_height};
61 rasterizer.InvalidateRegion(*dest_cpu,
62 dst_bytes_per_pixel * regs.dst.width * regs.dst.height);
63 51
64 if (regs.src.linear == regs.dst.linear) { 52 if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, src_rect, dst_rect)) {
65 // If the input layout and the output layout are the same, just perform a raw copy. 53 UNIMPLEMENTED();
66 ASSERT(regs.src.BlockHeight() == regs.dst.BlockHeight());
67 Memory::CopyBlock(*dest_cpu, *source_cpu,
68 src_bytes_per_pixel * regs.dst.width * regs.dst.height);
69 return;
70 }
71 u8* src_buffer = Memory::GetPointer(*source_cpu);
72 u8* dst_buffer = Memory::GetPointer(*dest_cpu);
73 if (!regs.src.linear && regs.dst.linear) {
74 // If the input is tiled and the output is linear, deswizzle the input and copy it over.
75 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth,
76 src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer,
77 dst_buffer, true, regs.src.BlockHeight(),
78 regs.src.BlockDepth(), 0);
79 } else {
80 // If the input is linear and the output is tiled, swizzle the input and copy it over.
81 Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth,
82 src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer,
83 src_buffer, false, regs.dst.BlockHeight(),
84 regs.dst.BlockDepth(), 0);
85 }
86 } 54 }
87} 55}
88 56
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index 50009bf75..c69f74cc5 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -94,12 +94,22 @@ public:
94 94
95 Operation operation; 95 Operation operation;
96 96
97 INSERT_PADDING_WORDS(0x9); 97 INSERT_PADDING_WORDS(0x177);
98 98
99 // TODO(Subv): This is only a guess. 99 u32 blit_control;
100 u32 trigger;
101 100
102 INSERT_PADDING_WORDS(0x1A3); 101 INSERT_PADDING_WORDS(0x8);
102
103 u32 blit_dst_x;
104 u32 blit_dst_y;
105 u32 blit_dst_width;
106 u32 blit_dst_height;
107 u64 blit_du_dx;
108 u64 blit_dv_dy;
109 u64 blit_src_x;
110 u64 blit_src_y;
111
112 INSERT_PADDING_WORDS(0x21);
103 }; 113 };
104 std::array<u32, NUM_REGS> reg_array; 114 std::array<u32, NUM_REGS> reg_array;
105 }; 115 };
@@ -122,7 +132,16 @@ private:
122ASSERT_REG_POSITION(dst, 0x80); 132ASSERT_REG_POSITION(dst, 0x80);
123ASSERT_REG_POSITION(src, 0x8C); 133ASSERT_REG_POSITION(src, 0x8C);
124ASSERT_REG_POSITION(operation, 0xAB); 134ASSERT_REG_POSITION(operation, 0xAB);
125ASSERT_REG_POSITION(trigger, 0xB5); 135ASSERT_REG_POSITION(blit_control, 0x223);
136ASSERT_REG_POSITION(blit_dst_x, 0x22c);
137ASSERT_REG_POSITION(blit_dst_y, 0x22d);
138ASSERT_REG_POSITION(blit_dst_width, 0x22e);
139ASSERT_REG_POSITION(blit_dst_height, 0x22f);
140ASSERT_REG_POSITION(blit_du_dx, 0x230);
141ASSERT_REG_POSITION(blit_dv_dy, 0x232);
142ASSERT_REG_POSITION(blit_src_x, 0x234);
143ASSERT_REG_POSITION(blit_src_y, 0x236);
144
126#undef ASSERT_REG_POSITION 145#undef ASSERT_REG_POSITION
127 146
128} // namespace Tegra::Engines 147} // namespace Tegra::Engines
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 77da135a0..b2a223705 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -46,7 +46,9 @@ public:
46 46
47 /// Attempt to use a faster method to perform a surface copy 47 /// Attempt to use a faster method to perform a surface copy
48 virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 48 virtual bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
49 const Tegra::Engines::Fermi2D::Regs::Surface& dst) { 49 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
50 const MathUtil::Rectangle<u32>& src_rect,
51 const MathUtil::Rectangle<u32>& dst_rect) {
50 return false; 52 return false;
51 } 53 }
52 54
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 974ca6a20..12d876120 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -778,15 +778,11 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
778} 778}
779 779
780bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 780bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
781 const Tegra::Engines::Fermi2D::Regs::Surface& dst) { 781 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
782 const MathUtil::Rectangle<u32>& src_rect,
783 const MathUtil::Rectangle<u32>& dst_rect) {
782 MICROPROFILE_SCOPE(OpenGL_Blits); 784 MICROPROFILE_SCOPE(OpenGL_Blits);
783 785 res_cache.FermiCopySurface(src, dst, src_rect, dst_rect);
784 if (Settings::values.use_accurate_gpu_emulation) {
785 // Skip the accelerated copy and perform a slow but more accurate copy
786 return false;
787 }
788
789 res_cache.FermiCopySurface(src, dst);
790 return true; 786 return true;
791} 787}
792 788
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index f3b607f4d..258d62259 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -61,7 +61,9 @@ public:
61 void InvalidateRegion(VAddr addr, u64 size) override; 61 void InvalidateRegion(VAddr addr, u64 size) override;
62 void FlushAndInvalidateRegion(VAddr addr, u64 size) override; 62 void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
63 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, 63 bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src,
64 const Tegra::Engines::Fermi2D::Regs::Surface& dst) override; 64 const Tegra::Engines::Fermi2D::Regs::Surface& dst,
65 const MathUtil::Rectangle<u32>& src_rect,
66 const MathUtil::Rectangle<u32>& dst_rect) override;
65 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, 67 bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr,
66 u32 pixel_stride) override; 68 u32 pixel_stride) override;
67 bool AccelerateDrawBatch(bool is_indexed) override; 69 bool AccelerateDrawBatch(bool is_indexed) override;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 126dcbbb3..59f671048 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -437,7 +437,8 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
437 } 437 }
438} 438}
439 439
440static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { 440void RasterizerCacheOpenGL::FastCopySurface(const Surface& src_surface,
441 const Surface& dst_surface) {
441 const auto& src_params{src_surface->GetSurfaceParams()}; 442 const auto& src_params{src_surface->GetSurfaceParams()};
442 const auto& dst_params{dst_surface->GetSurfaceParams()}; 443 const auto& dst_params{dst_surface->GetSurfaceParams()};
443 444
@@ -447,12 +448,15 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
447 glCopyImageSubData(src_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0, 448 glCopyImageSubData(src_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0,
448 0, dst_surface->Texture().handle, SurfaceTargetToGL(dst_params.target), 0, 0, 449 0, dst_surface->Texture().handle, SurfaceTargetToGL(dst_params.target), 0, 0,
449 0, 0, width, height, 1); 450 0, 0, width, height, 1);
451
452 dst_surface->MarkAsModified(true, *this);
450} 453}
451 454
452MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); 455MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
453static void CopySurface(const Surface& src_surface, const Surface& dst_surface, 456void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surface& dst_surface,
454 const GLuint copy_pbo_handle, const GLenum src_attachment = 0, 457 const GLuint copy_pbo_handle, const GLenum src_attachment,
455 const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0) { 458 const GLenum dst_attachment,
459 const std::size_t cubemap_face) {
456 MICROPROFILE_SCOPE(OpenGL_CopySurface); 460 MICROPROFILE_SCOPE(OpenGL_CopySurface);
457 ASSERT_MSG(dst_attachment == 0, "Unimplemented"); 461 ASSERT_MSG(dst_attachment == 0, "Unimplemented");
458 462
@@ -532,6 +536,8 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
532 } 536 }
533 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 537 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
534 } 538 }
539
540 dst_surface->MarkAsModified(true, *this);
535} 541}
536 542
537CachedSurface::CachedSurface(const SurfaceParams& params) 543CachedSurface::CachedSurface(const SurfaceParams& params)
@@ -1051,26 +1057,161 @@ void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface,
1051 } 1057 }
1052 address += layer_size; 1058 address += layer_size;
1053 } 1059 }
1060
1061 dst_surface->MarkAsModified(true, *this);
1062}
1063
1064static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
1065 const MathUtil::Rectangle<u32>& src_rect,
1066 const MathUtil::Rectangle<u32>& dst_rect, GLuint read_fb_handle,
1067 GLuint draw_fb_handle, GLenum src_attachment = 0, GLenum dst_attachment = 0,
1068 std::size_t cubemap_face = 0) {
1069
1070 const auto& src_params{src_surface->GetSurfaceParams()};
1071 const auto& dst_params{dst_surface->GetSurfaceParams()};
1072
1073 OpenGLState prev_state{OpenGLState::GetCurState()};
1074 SCOPE_EXIT({ prev_state.Apply(); });
1075
1076 OpenGLState state;
1077 state.draw.read_framebuffer = read_fb_handle;
1078 state.draw.draw_framebuffer = draw_fb_handle;
1079 state.Apply();
1080
1081 u32 buffers{};
1082
1083 if (src_params.type == SurfaceType::ColorTexture) {
1084 switch (src_params.target) {
1085 case SurfaceTarget::Texture2D:
1086 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1087 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
1088 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1089 0, 0);
1090 break;
1091 case SurfaceTarget::TextureCubemap:
1092 glFramebufferTexture2D(
1093 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1094 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
1095 src_surface->Texture().handle, 0);
1096 glFramebufferTexture2D(
1097 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1098 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
1099 break;
1100 case SurfaceTarget::Texture2DArray:
1101 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1102 src_surface->Texture().handle, 0, 0);
1103 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
1104 break;
1105 case SurfaceTarget::Texture3D:
1106 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1107 SurfaceTargetToGL(src_params.target),
1108 src_surface->Texture().handle, 0, 0);
1109 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1110 SurfaceTargetToGL(src_params.target), 0, 0, 0);
1111 break;
1112 default:
1113 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1114 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
1115 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1116 0, 0);
1117 break;
1118 }
1119
1120 switch (dst_params.target) {
1121 case SurfaceTarget::Texture2D:
1122 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1123 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
1124 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1125 0, 0);
1126 break;
1127 case SurfaceTarget::TextureCubemap:
1128 glFramebufferTexture2D(
1129 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1130 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
1131 dst_surface->Texture().handle, 0);
1132 glFramebufferTexture2D(
1133 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1134 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
1135 break;
1136 case SurfaceTarget::Texture2DArray:
1137 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1138 dst_surface->Texture().handle, 0, 0);
1139 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
1140 break;
1141
1142 case SurfaceTarget::Texture3D:
1143 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1144 SurfaceTargetToGL(dst_params.target),
1145 dst_surface->Texture().handle, 0, 0);
1146 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
1147 SurfaceTargetToGL(dst_params.target), 0, 0, 0);
1148 break;
1149 default:
1150 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1151 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
1152 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1153 0, 0);
1154 break;
1155 }
1156
1157 buffers = GL_COLOR_BUFFER_BIT;
1158 } else if (src_params.type == SurfaceType::Depth) {
1159 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1160 GL_TEXTURE_2D, 0, 0);
1161 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
1162 src_surface->Texture().handle, 0);
1163 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
1164
1165 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1166 GL_TEXTURE_2D, 0, 0);
1167 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
1168 dst_surface->Texture().handle, 0);
1169 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
1170
1171 buffers = GL_DEPTH_BUFFER_BIT;
1172 } else if (src_params.type == SurfaceType::DepthStencil) {
1173 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
1174 GL_TEXTURE_2D, 0, 0);
1175 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1176 src_surface->Texture().handle, 0);
1177
1178 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
1179 GL_TEXTURE_2D, 0, 0);
1180 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
1181 dst_surface->Texture().handle, 0);
1182
1183 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
1184 }
1185
1186 glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
1187 dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
1188 buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
1189
1190 return true;
1054} 1191}
1055 1192
1056void RasterizerCacheOpenGL::FermiCopySurface( 1193void RasterizerCacheOpenGL::FermiCopySurface(
1057 const Tegra::Engines::Fermi2D::Regs::Surface& src_config, 1194 const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
1058 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { 1195 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config,
1196 const MathUtil::Rectangle<u32>& src_rect, const MathUtil::Rectangle<u32>& dst_rect) {
1059 1197
1060 const auto& src_params = SurfaceParams::CreateForFermiCopySurface(src_config); 1198 const auto& src_params = SurfaceParams::CreateForFermiCopySurface(src_config);
1061 const auto& dst_params = SurfaceParams::CreateForFermiCopySurface(dst_config); 1199 const auto& dst_params = SurfaceParams::CreateForFermiCopySurface(dst_config);
1062 1200
1063 ASSERT(src_params.width == dst_params.width);
1064 ASSERT(src_params.height == dst_params.height);
1065 ASSERT(src_params.pixel_format == dst_params.pixel_format); 1201 ASSERT(src_params.pixel_format == dst_params.pixel_format);
1066 ASSERT(src_params.block_height == dst_params.block_height); 1202 ASSERT(src_params.block_height == dst_params.block_height);
1067 ASSERT(src_params.is_tiled == dst_params.is_tiled); 1203 ASSERT(src_params.is_tiled == dst_params.is_tiled);
1068 ASSERT(src_params.depth == dst_params.depth); 1204 ASSERT(src_params.depth == dst_params.depth);
1069 ASSERT(src_params.depth == 1); // Currently, FastCopySurface only works with 2D surfaces
1070 ASSERT(src_params.target == dst_params.target); 1205 ASSERT(src_params.target == dst_params.target);
1071 ASSERT(src_params.rt.index == dst_params.rt.index); 1206 ASSERT(src_params.rt.index == dst_params.rt.index);
1072 1207
1073 FastCopySurface(GetSurface(src_params, true), GetSurface(dst_params, false)); 1208 auto src_surface = GetSurface(src_params, true);
1209 auto dst_surface = GetSurface(dst_params, true);
1210
1211 BlitSurface(src_surface, dst_surface, src_rect, dst_rect, read_framebuffer.handle,
1212 draw_framebuffer.handle);
1213
1214 dst_surface->MarkAsModified(true, *this);
1074} 1215}
1075 1216
1076void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface, 1217void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 49ff99e2f..b81882d04 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -423,7 +423,9 @@ public:
423 423
424 /// Copies the contents of one surface to another 424 /// Copies the contents of one surface to another
425 void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config, 425 void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config,
426 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config); 426 const Tegra::Engines::Fermi2D::Regs::Surface& dst_config,
427 const MathUtil::Rectangle<u32>& src_rect,
428 const MathUtil::Rectangle<u32>& dst_rect);
427 429
428private: 430private:
429 void LoadSurface(const Surface& surface); 431 void LoadSurface(const Surface& surface);
@@ -444,6 +446,10 @@ private:
444 /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data 446 /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
445 void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); 447 void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
446 void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); 448 void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
449 void FastCopySurface(const Surface& src_surface, const Surface& dst_surface);
450 void CopySurface(const Surface& src_surface, const Surface& dst_surface,
451 const GLuint copy_pbo_handle, const GLenum src_attachment = 0,
452 const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0);
447 453
448 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 454 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
449 /// previously been used. This is to prevent surfaces from being constantly created and 455 /// previously been used. This is to prevent surfaces from being constantly created and