diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/fermi_2d.cpp | 62 | ||||
| -rw-r--r-- | src/video_core/engines/fermi_2d.h | 29 | ||||
| -rw-r--r-- | src/video_core/rasterizer_interface.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 159 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 8 |
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: | |||
| 122 | ASSERT_REG_POSITION(dst, 0x80); | 132 | ASSERT_REG_POSITION(dst, 0x80); |
| 123 | ASSERT_REG_POSITION(src, 0x8C); | 133 | ASSERT_REG_POSITION(src, 0x8C); |
| 124 | ASSERT_REG_POSITION(operation, 0xAB); | 134 | ASSERT_REG_POSITION(operation, 0xAB); |
| 125 | ASSERT_REG_POSITION(trigger, 0xB5); | 135 | ASSERT_REG_POSITION(blit_control, 0x223); |
| 136 | ASSERT_REG_POSITION(blit_dst_x, 0x22c); | ||
| 137 | ASSERT_REG_POSITION(blit_dst_y, 0x22d); | ||
| 138 | ASSERT_REG_POSITION(blit_dst_width, 0x22e); | ||
| 139 | ASSERT_REG_POSITION(blit_dst_height, 0x22f); | ||
| 140 | ASSERT_REG_POSITION(blit_du_dx, 0x230); | ||
| 141 | ASSERT_REG_POSITION(blit_dv_dy, 0x232); | ||
| 142 | ASSERT_REG_POSITION(blit_src_x, 0x234); | ||
| 143 | ASSERT_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 | ||
| 780 | bool RasterizerOpenGL::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Regs::Surface& src, | 780 | bool 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 | ||
| 440 | static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { | 440 | void 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 | ||
| 452 | MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); | 455 | MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); |
| 453 | static void CopySurface(const Surface& src_surface, const Surface& dst_surface, | 456 | void 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 | ||
| 537 | CachedSurface::CachedSurface(const SurfaceParams& params) | 543 | CachedSurface::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 | |||
| 1064 | static 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 | ||
| 1056 | void RasterizerCacheOpenGL::FermiCopySurface( | 1193 | void 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 | ||
| 1076 | void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface, | 1217 | void 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 | ||
| 428 | private: | 430 | private: |
| 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 |