diff options
| author | 2021-10-13 20:41:17 -0400 | |
|---|---|---|
| committer | 2021-10-13 20:41:17 -0400 | |
| commit | 894b483a0d619c3ceaa79fa0ff4cef6d37301f9c (patch) | |
| tree | f8f7e3f32578f7090860567be355c3b822b39d9f | |
| parent | Merge pull request #7142 from german77/sdl_range (diff) | |
| parent | vic: Use the minimum of surface/frame dimensions when writing the final frame... (diff) | |
| download | yuzu-894b483a0d619c3ceaa79fa0ff4cef6d37301f9c.tar.gz yuzu-894b483a0d619c3ceaa79fa0ff4cef6d37301f9c.tar.xz yuzu-894b483a0d619c3ceaa79fa0ff4cef6d37301f9c.zip | |
Merge pull request #7157 from ameerj/vic-surface-size
vic: Use the minimum of surface/frame dimensions when writing the final frame to the GPU
| -rw-r--r-- | src/video_core/command_classes/vic.cpp | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/src/video_core/command_classes/vic.cpp b/src/video_core/command_classes/vic.cpp index dc768b952..051616124 100644 --- a/src/video_core/command_classes/vic.cpp +++ b/src/video_core/command_classes/vic.cpp | |||
| @@ -32,7 +32,7 @@ enum class VideoPixelFormat : u64_le { | |||
| 32 | RGBA8 = 0x1f, | 32 | RGBA8 = 0x1f, |
| 33 | BGRA8 = 0x20, | 33 | BGRA8 = 0x20, |
| 34 | RGBX8 = 0x23, | 34 | RGBX8 = 0x23, |
| 35 | Yuv420 = 0x44, | 35 | YUV420 = 0x44, |
| 36 | }; | 36 | }; |
| 37 | } // Anonymous namespace | 37 | } // Anonymous namespace |
| 38 | 38 | ||
| @@ -88,12 +88,10 @@ void Vic::Execute() { | |||
| 88 | const u64 surface_width = config.surface_width_minus1 + 1; | 88 | const u64 surface_width = config.surface_width_minus1 + 1; |
| 89 | const u64 surface_height = config.surface_height_minus1 + 1; | 89 | const u64 surface_height = config.surface_height_minus1 + 1; |
| 90 | if (static_cast<u64>(frame->width) != surface_width || | 90 | if (static_cast<u64>(frame->width) != surface_width || |
| 91 | static_cast<u64>(frame->height) > surface_height) { | 91 | static_cast<u64>(frame->height) != surface_height) { |
| 92 | // TODO: Properly support multiple video streams with differing frame dimensions | 92 | // TODO: Properly support multiple video streams with differing frame dimensions |
| 93 | LOG_WARNING(Debug, | 93 | LOG_WARNING(Service_NVDRV, "Frame dimensions {}x{} don't match surface dimensions {}x{}", |
| 94 | "Frame dimensions {}x{} can't be safely decoded into surface dimensions {}x{}", | ||
| 95 | frame->width, frame->height, surface_width, surface_height); | 94 | frame->width, frame->height, surface_width, surface_height); |
| 96 | return; | ||
| 97 | } | 95 | } |
| 98 | switch (config.pixel_format) { | 96 | switch (config.pixel_format) { |
| 99 | case VideoPixelFormat::RGBA8: | 97 | case VideoPixelFormat::RGBA8: |
| @@ -101,7 +99,7 @@ void Vic::Execute() { | |||
| 101 | case VideoPixelFormat::RGBX8: | 99 | case VideoPixelFormat::RGBX8: |
| 102 | WriteRGBFrame(frame, config); | 100 | WriteRGBFrame(frame, config); |
| 103 | break; | 101 | break; |
| 104 | case VideoPixelFormat::Yuv420: | 102 | case VideoPixelFormat::YUV420: |
| 105 | WriteYUVFrame(frame, config); | 103 | WriteYUVFrame(frame, config); |
| 106 | break; | 104 | break; |
| 107 | default: | 105 | default: |
| @@ -136,21 +134,20 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { | |||
| 136 | scaler_height = frame->height; | 134 | scaler_height = frame->height; |
| 137 | converted_frame_buffer.reset(); | 135 | converted_frame_buffer.reset(); |
| 138 | } | 136 | } |
| 139 | // Get Converted frame | ||
| 140 | const u32 width = static_cast<u32>(frame->width); | ||
| 141 | const u32 height = static_cast<u32>(frame->height); | ||
| 142 | const std::size_t linear_size = width * height * 4; | ||
| 143 | |||
| 144 | // Only allocate frame_buffer once per stream, as the size is not expected to change | ||
| 145 | if (!converted_frame_buffer) { | 137 | if (!converted_frame_buffer) { |
| 146 | converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(linear_size)), av_free}; | 138 | const size_t frame_size = frame->width * frame->height * 4; |
| 139 | converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(frame_size)), av_free}; | ||
| 147 | } | 140 | } |
| 148 | const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0}; | 141 | const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0}; |
| 149 | u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; | 142 | u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; |
| 150 | |||
| 151 | sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, &converted_frame_buf_addr, | 143 | sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, &converted_frame_buf_addr, |
| 152 | converted_stride.data()); | 144 | converted_stride.data()); |
| 153 | 145 | ||
| 146 | // Use the minimum of surface/frame dimensions to avoid buffer overflow. | ||
| 147 | const u32 surface_width = static_cast<u32>(config.surface_width_minus1) + 1; | ||
| 148 | const u32 surface_height = static_cast<u32>(config.surface_height_minus1) + 1; | ||
| 149 | const u32 width = std::min(surface_width, static_cast<u32>(frame->width)); | ||
| 150 | const u32 height = std::min(surface_height, static_cast<u32>(frame->height)); | ||
| 154 | const u32 blk_kind = static_cast<u32>(config.block_linear_kind); | 151 | const u32 blk_kind = static_cast<u32>(config.block_linear_kind); |
| 155 | if (blk_kind != 0) { | 152 | if (blk_kind != 0) { |
| 156 | // swizzle pitch linear to block linear | 153 | // swizzle pitch linear to block linear |
| @@ -158,11 +155,12 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { | |||
| 158 | const auto size = Texture::CalculateSize(true, 4, width, height, 1, block_height, 0); | 155 | const auto size = Texture::CalculateSize(true, 4, width, height, 1, block_height, 0); |
| 159 | luma_buffer.resize(size); | 156 | luma_buffer.resize(size); |
| 160 | Texture::SwizzleSubrect(width, height, width * 4, width, 4, luma_buffer.data(), | 157 | Texture::SwizzleSubrect(width, height, width * 4, width, 4, luma_buffer.data(), |
| 161 | converted_frame_buffer.get(), block_height, 0, 0); | 158 | converted_frame_buf_addr, block_height, 0, 0); |
| 162 | 159 | ||
| 163 | gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size); | 160 | gpu.MemoryManager().WriteBlock(output_surface_luma_address, luma_buffer.data(), size); |
| 164 | } else { | 161 | } else { |
| 165 | // send pitch linear frame | 162 | // send pitch linear frame |
| 163 | const size_t linear_size = width * height * 4; | ||
| 166 | gpu.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr, | 164 | gpu.MemoryManager().WriteBlock(output_surface_luma_address, converted_frame_buf_addr, |
| 167 | linear_size); | 165 | linear_size); |
| 168 | } | 166 | } |
| @@ -173,9 +171,10 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { | |||
| 173 | 171 | ||
| 174 | const std::size_t surface_width = config.surface_width_minus1 + 1; | 172 | const std::size_t surface_width = config.surface_width_minus1 + 1; |
| 175 | const std::size_t surface_height = config.surface_height_minus1 + 1; | 173 | const std::size_t surface_height = config.surface_height_minus1 + 1; |
| 174 | const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL; | ||
| 175 | // Use the minimum of surface/frame dimensions to avoid buffer overflow. | ||
| 176 | const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width)); | 176 | const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width)); |
| 177 | const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height)); | 177 | const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height)); |
| 178 | const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL; | ||
| 179 | 178 | ||
| 180 | const auto stride = static_cast<size_t>(frame->linesize[0]); | 179 | const auto stride = static_cast<size_t>(frame->linesize[0]); |
| 181 | 180 | ||