2015-07-23 23:16:31 -04:00
|
|
|
#include "stdafx.h"
|
2015-08-30 21:04:21 -04:00
|
|
|
#include "IRenderingDevice.h"
|
2015-07-23 23:16:31 -04:00
|
|
|
#include "VideoDecoder.h"
|
|
|
|
#include "EmulationSettings.h"
|
2016-01-05 21:28:38 -05:00
|
|
|
#include "DefaultVideoFilter.h"
|
|
|
|
#include "NtscFilter.h"
|
|
|
|
#include "HdVideoFilter.h"
|
2016-01-31 00:41:33 -05:00
|
|
|
#include "VideoRenderer.h"
|
2015-07-23 23:16:31 -04:00
|
|
|
|
|
|
|
unique_ptr<VideoDecoder> VideoDecoder::Instance;
|
|
|
|
|
|
|
|
VideoDecoder* VideoDecoder::GetInstance()
|
|
|
|
{
|
|
|
|
if(!Instance) {
|
|
|
|
Instance.reset(new VideoDecoder());
|
|
|
|
}
|
|
|
|
return Instance.get();
|
|
|
|
}
|
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
VideoDecoder::VideoDecoder()
|
|
|
|
{
|
2016-01-05 21:28:38 -05:00
|
|
|
UpdateVideoFilter();
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
|
2015-07-23 23:16:31 -04:00
|
|
|
VideoDecoder::~VideoDecoder()
|
|
|
|
{
|
2015-08-30 21:04:21 -04:00
|
|
|
StopThread();
|
2015-07-23 23:16:31 -04:00
|
|
|
}
|
|
|
|
|
2016-01-05 21:28:38 -05:00
|
|
|
void VideoDecoder::GetScreenSize(ScreenSize &size)
|
2015-07-23 23:16:31 -04:00
|
|
|
{
|
2016-01-05 21:28:38 -05:00
|
|
|
if(_videoFilter) {
|
|
|
|
size.Width = _videoFilter->GetFrameInfo().Width * EmulationSettings::GetVideoScale();
|
|
|
|
size.Height = _videoFilter->GetFrameInfo().Height * EmulationSettings::GetVideoScale();
|
2015-07-23 23:16:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-05 21:28:38 -05:00
|
|
|
void VideoDecoder::UpdateVideoFilter()
|
2015-07-23 23:16:31 -04:00
|
|
|
{
|
2016-01-05 21:28:38 -05:00
|
|
|
VideoFilterType newFilter = EmulationSettings::GetVideoFilterType();
|
|
|
|
if(_hdScreenTiles) {
|
|
|
|
newFilter = VideoFilterType::HdPack;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_videoFilterType != newFilter || _videoFilter == nullptr) {
|
|
|
|
_videoFilterType = newFilter;
|
2015-07-23 23:16:31 -04:00
|
|
|
|
2016-01-05 21:28:38 -05:00
|
|
|
switch(_videoFilterType) {
|
|
|
|
case VideoFilterType::None: _videoFilter.reset(new DefaultVideoFilter()); break;
|
|
|
|
case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter()); break;
|
|
|
|
case VideoFilterType::HdPack: _videoFilter.reset(new HdVideoFilter()); break;
|
2015-07-23 23:16:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
void VideoDecoder::DecodeFrame()
|
2015-08-14 21:50:14 -04:00
|
|
|
{
|
2016-01-05 21:28:38 -05:00
|
|
|
UpdateVideoFilter();
|
2015-08-30 21:04:21 -04:00
|
|
|
|
2016-01-05 21:28:38 -05:00
|
|
|
if(_videoFilterType == VideoFilterType::HdPack) {
|
|
|
|
((HdVideoFilter*)_videoFilter.get())->SetHdScreenTiles(_hdScreenTiles);
|
2015-08-14 21:50:14 -04:00
|
|
|
}
|
2016-01-05 21:28:38 -05:00
|
|
|
_videoFilter->SendFrame(_ppuOutputBuffer);
|
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
_frameChanged = false;
|
2015-08-14 21:50:14 -04:00
|
|
|
|
2016-01-31 00:41:33 -05:00
|
|
|
VideoRenderer::GetInstance()->UpdateFrame(_videoFilter->GetOutputBuffer(), _videoFilter->GetFrameInfo().Width, _videoFilter->GetFrameInfo().Height);
|
2015-08-14 21:50:14 -04:00
|
|
|
}
|
|
|
|
|
2015-08-08 22:36:39 -04:00
|
|
|
void VideoDecoder::DebugDecodeFrame(uint16_t* inputBuffer, uint32_t* outputBuffer, uint32_t length)
|
|
|
|
{
|
|
|
|
for(uint32_t i = 0; i < length; i++) {
|
2016-01-17 14:21:31 -05:00
|
|
|
outputBuffer[i] = EmulationSettings::GetRgbPalette()[inputBuffer[i] & 0x3F];
|
2015-08-08 22:36:39 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-30 21:04:21 -04:00
|
|
|
void VideoDecoder::DecodeThread()
|
|
|
|
{
|
|
|
|
//This thread will decode the PPU's output (color ID to RGB, intensify r/g/b and produce a HD version of the frame if needed)
|
|
|
|
while(!_stopFlag.load()) {
|
|
|
|
//DecodeFrame returns the final ARGB frame we want to display in the emulator window
|
|
|
|
if(!_frameChanged) {
|
|
|
|
_waitForFrame.Wait();
|
|
|
|
if(_stopFlag.load()) {
|
2016-01-12 19:42:28 -05:00
|
|
|
return;
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DecodeFrame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t VideoDecoder::GetFrameCount()
|
|
|
|
{
|
|
|
|
return _frameCount;
|
|
|
|
}
|
|
|
|
|
2016-01-12 19:42:28 -05:00
|
|
|
void VideoDecoder::UpdateFrame(void *ppuOutputBuffer, HdPpuPixelInfo *hdPixelInfo)
|
2015-08-30 21:04:21 -04:00
|
|
|
{
|
2016-01-12 19:42:28 -05:00
|
|
|
if(_frameChanged) {
|
|
|
|
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
|
|
|
|
while(_frameChanged) {
|
|
|
|
//Spin until decode is done
|
|
|
|
}
|
|
|
|
//At this point, we are sure that the decode thread is no longer busy
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
|
2016-01-12 19:42:28 -05:00
|
|
|
_hdScreenTiles = hdPixelInfo;
|
|
|
|
_ppuOutputBuffer = (uint16_t*)ppuOutputBuffer;
|
|
|
|
_frameChanged = true;
|
|
|
|
_waitForFrame.Signal();
|
|
|
|
|
|
|
|
_frameCount++;
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDecoder::StartThread()
|
|
|
|
{
|
2016-01-16 12:29:17 -05:00
|
|
|
if(!_decodeThread) {
|
2015-08-30 21:04:21 -04:00
|
|
|
_stopFlag = false;
|
2015-12-26 17:11:00 -05:00
|
|
|
_frameChanged = false;
|
|
|
|
_frameCount = 0;
|
2016-01-06 20:37:52 -05:00
|
|
|
_waitForFrame.Reset();
|
2016-01-16 12:29:17 -05:00
|
|
|
|
|
|
|
_decodeThread.reset(new thread(&VideoDecoder::DecodeThread, this));
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDecoder::StopThread()
|
|
|
|
{
|
|
|
|
_stopFlag = true;
|
|
|
|
if(_decodeThread) {
|
|
|
|
_waitForFrame.Signal();
|
|
|
|
_decodeThread->join();
|
2015-12-26 17:11:00 -05:00
|
|
|
|
2016-01-31 00:41:33 -05:00
|
|
|
_decodeThread.release();
|
2015-08-30 21:04:21 -04:00
|
|
|
|
2016-01-31 00:41:33 -05:00
|
|
|
if(_ppuOutputBuffer != nullptr) {
|
|
|
|
//Clear whole screen
|
|
|
|
for(int i = 0; i < PPU::PixelCount; i++) {
|
|
|
|
_ppuOutputBuffer[i] = 14; //Black
|
|
|
|
}
|
|
|
|
DecodeFrame();
|
2015-08-30 21:04:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-31 00:41:33 -05:00
|
|
|
bool VideoDecoder::IsRunning()
|
2015-08-30 21:04:21 -04:00
|
|
|
{
|
2016-01-31 00:41:33 -05:00
|
|
|
return _decodeThread != nullptr;
|
2016-01-05 21:28:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDecoder::TakeScreenshot(string romFilename)
|
|
|
|
{
|
|
|
|
if(_videoFilter) {
|
|
|
|
_videoFilter->TakeScreenshot(romFilename);
|
|
|
|
}
|
2015-07-23 23:16:31 -04:00
|
|
|
}
|