mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	Merge pull request #593 from Vort/atv_double_buffering
ATV Demodulator: implement double buffering
This commit is contained in:
		
						commit
						aa8f9f6805
					
				@ -484,7 +484,7 @@ void ATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque
 | 
				
			|||||||
            m_samplesPerLine - m_numberSamplesPerLineSignals,
 | 
					            m_samplesPerLine - m_numberSamplesPerLineSignals,
 | 
				
			||||||
            m_settings.m_nbLines - m_numberOfBlackLines
 | 
					            m_settings.m_nbLines - m_numberOfBlackLines
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
		m_tvScreenData = m_registeredTVScreen->getData();
 | 
							m_tvScreenBuffer = m_registeredTVScreen->getBackBuffer();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    m_fieldIndex = 0;
 | 
					    m_fieldIndex = 0;
 | 
				
			||||||
@ -576,7 +576,7 @@ void ATVDemodSink::applySettings(const ATVDemodSettings& settings, bool force)
 | 
				
			|||||||
                m_samplesPerLine - m_numberSamplesPerLineSignals,
 | 
					                m_samplesPerLine - m_numberSamplesPerLineSignals,
 | 
				
			||||||
                m_settings.m_nbLines - m_numberOfBlackLines
 | 
					                m_settings.m_nbLines - m_numberOfBlackLines
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
			m_tvScreenData = m_registeredTVScreen->getData();
 | 
								m_tvScreenBuffer = m_registeredTVScreen->getBackBuffer();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        m_fieldIndex = 0;
 | 
					        m_fieldIndex = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -109,7 +109,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    //*************** ATV PARAMETERS  ***************
 | 
					    //*************** ATV PARAMETERS  ***************
 | 
				
			||||||
    TVScreenAnalog *m_registeredTVScreen;
 | 
					    TVScreenAnalog *m_registeredTVScreen;
 | 
				
			||||||
	std::shared_ptr<TVScreenAnalogData> m_tvScreenData;
 | 
						std::shared_ptr<TVScreenAnalogBuffer> m_tvScreenBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //int m_intNumberSamplePerLine;
 | 
					    //int m_intNumberSamplePerLine;
 | 
				
			||||||
    int m_numberSamplesPerHTopNom;     //!< number of samples per horizontal synchronization pulse (pulse in ultra-black) - nominal value
 | 
					    int m_numberSamplesPerHTopNom;     //!< number of samples per horizontal synchronization pulse (pulse in ultra-black) - nominal value
 | 
				
			||||||
@ -199,7 +199,7 @@ private:
 | 
				
			|||||||
    inline void processSample(float& sample, int& sampleVideo)
 | 
					    inline void processSample(float& sample, int& sampleVideo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // Filling pixel on the current line - reference index 0 at start of sync pulse
 | 
					        // Filling pixel on the current line - reference index 0 at start of sync pulse
 | 
				
			||||||
		m_tvScreenData->setSampleValue(m_sampleOffset - m_numberSamplesPerHSync, sampleVideo);
 | 
							m_tvScreenBuffer->setSampleValue(m_sampleOffset - m_numberSamplesPerHSync, sampleVideo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (m_settings.m_hSync)
 | 
					        if (m_settings.m_hSync)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -278,7 +278,7 @@ private:
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        if (m_lineIndex == m_numberOfVSyncLines + 3 && m_fieldIndex == 0)
 | 
					        if (m_lineIndex == m_numberOfVSyncLines + 3 && m_fieldIndex == 0)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
			m_registeredTVScreen->renderImage();
 | 
								m_tvScreenBuffer = m_registeredTVScreen->swapBuffers();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (m_vSyncDetectSampleCount > m_vSyncDetectThreshold &&
 | 
					        if (m_vSyncDetectSampleCount > m_vSyncDetectThreshold &&
 | 
				
			||||||
@ -311,7 +311,7 @@ private:
 | 
				
			|||||||
        if (m_interleaved)
 | 
					        if (m_interleaved)
 | 
				
			||||||
            rowIndex = rowIndex * 2 - m_fieldIndex;
 | 
					            rowIndex = rowIndex * 2 - m_fieldIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m_tvScreenData->selectRow(rowIndex, m_sampleOffsetFrac);
 | 
							m_tvScreenBuffer->selectRow(rowIndex, m_sampleOffsetFrac);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Vertical sync is obtained by skipping horizontal sync on the line that triggers vertical sync (new frame)
 | 
					    // Vertical sync is obtained by skipping horizontal sync on the line that triggers vertical sync (new frame)
 | 
				
			||||||
@ -320,11 +320,11 @@ private:
 | 
				
			|||||||
		if ((m_sampleOffsetDetected > (3 * m_samplesPerLine) / 2) // Vertical sync is first horizontal sync after skip (count at least 1.5 line length)
 | 
							if ((m_sampleOffsetDetected > (3 * m_samplesPerLine) / 2) // Vertical sync is first horizontal sync after skip (count at least 1.5 line length)
 | 
				
			||||||
            || (!m_settings.m_vSync && (m_lineIndex >= m_settings.m_nbLines))) // Vsync ignored and reached nominal number of lines per frame
 | 
					            || (!m_settings.m_vSync && (m_lineIndex >= m_settings.m_nbLines))) // Vsync ignored and reached nominal number of lines per frame
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
			m_registeredTVScreen->renderImage();
 | 
								m_tvScreenBuffer = m_registeredTVScreen->swapBuffers();
 | 
				
			||||||
			m_lineIndex = 0;
 | 
								m_lineIndex = 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m_tvScreenData->selectRow(m_lineIndex, m_sampleOffsetFrac);
 | 
							m_tvScreenBuffer->selectRow(m_lineIndex, m_sampleOffsetFrac);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -68,10 +68,11 @@ TVScreenAnalog::TVScreenAnalog(QWidget *parent)
 | 
				
			|||||||
	: QGLWidget(parent)
 | 
						: QGLWidget(parent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_isDataChanged = false;
 | 
						m_isDataChanged = false;
 | 
				
			||||||
	m_data = std::make_shared<TVScreenAnalogData>(5, 1);
 | 
						m_frontBuffer = std::make_shared<TVScreenAnalogBuffer>(5, 1);
 | 
				
			||||||
 | 
						m_backBuffer = std::make_shared<TVScreenAnalogBuffer>(5, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	connect(&m_objTimer, SIGNAL(timeout()), this, SLOT(tick()));
 | 
						connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(tick()));
 | 
				
			||||||
	m_objTimer.start(40); // capped at 25 FPS
 | 
						m_updateTimer.start(40); // capped at 25 FPS
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::cleanup()
 | 
					void TVScreenAnalog::cleanup()
 | 
				
			||||||
@ -81,9 +82,9 @@ void TVScreenAnalog::cleanup()
 | 
				
			|||||||
	m_lineShiftsTexture = nullptr;
 | 
						m_lineShiftsTexture = nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::shared_ptr<TVScreenAnalogData> TVScreenAnalog::getData()
 | 
					std::shared_ptr<TVScreenAnalogBuffer> TVScreenAnalog::getBackBuffer()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return m_data;
 | 
						return m_backBuffer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::resizeTVScreen(int intCols, int intRows)
 | 
					void TVScreenAnalog::resizeTVScreen(int intCols, int intRows)
 | 
				
			||||||
@ -91,8 +92,12 @@ void TVScreenAnalog::resizeTVScreen(int intCols, int intRows)
 | 
				
			|||||||
	qDebug("TVScreen::resizeTVScreen: cols: %d, rows: %d", intCols, intRows);
 | 
						qDebug("TVScreen::resizeTVScreen: cols: %d, rows: %d", intCols, intRows);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int colsAdj = intCols + 4;
 | 
						int colsAdj = intCols + 4;
 | 
				
			||||||
	if (m_data->getWidth() != colsAdj || m_data->getHeight() != intRows)
 | 
						QMutexLocker lock(&m_buffersMutex);
 | 
				
			||||||
		m_data = std::make_shared<TVScreenAnalogData>(colsAdj, intRows);
 | 
						if (m_frontBuffer->getWidth() != colsAdj || m_frontBuffer->getHeight() != intRows)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_frontBuffer = std::make_shared<TVScreenAnalogBuffer>(colsAdj, intRows);
 | 
				
			||||||
 | 
							m_backBuffer = std::make_shared<TVScreenAnalogBuffer>(colsAdj, intRows);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::resizeGL(int intWidth, int intHeight)
 | 
					void TVScreenAnalog::resizeGL(int intWidth, int intHeight)
 | 
				
			||||||
@ -143,12 +148,12 @@ void TVScreenAnalog::initializeGL()
 | 
				
			|||||||
	m_texelHeightLoc = m_shader->uniformLocation("tlh");
 | 
						m_texelHeightLoc = m_shader->uniformLocation("tlh");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::initializeTextures()
 | 
					void TVScreenAnalog::initializeTextures(std::shared_ptr<TVScreenAnalogBuffer> buffer)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_imageTexture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target2D);
 | 
						m_imageTexture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target2D);
 | 
				
			||||||
	m_lineShiftsTexture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target2D);
 | 
						m_lineShiftsTexture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target2D);
 | 
				
			||||||
	m_imageTexture->setSize(m_data->getWidth(), m_data->getHeight());
 | 
						m_imageTexture->setSize(buffer->getWidth(), buffer->getHeight());
 | 
				
			||||||
	m_lineShiftsTexture->setSize(1, m_data->getHeight());
 | 
						m_lineShiftsTexture->setSize(1, buffer->getHeight());
 | 
				
			||||||
	m_imageTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
 | 
						m_imageTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
 | 
				
			||||||
	m_lineShiftsTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
 | 
						m_lineShiftsTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
 | 
				
			||||||
	m_imageTexture->setAutoMipMapGenerationEnabled(false);
 | 
						m_imageTexture->setAutoMipMapGenerationEnabled(false);
 | 
				
			||||||
@ -166,9 +171,12 @@ void TVScreenAnalog::initializeTextures()
 | 
				
			|||||||
	m_lineShiftsTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
 | 
						m_lineShiftsTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::renderImage()
 | 
					std::shared_ptr<TVScreenAnalogBuffer> TVScreenAnalog::swapBuffers()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						QMutexLocker lock(&m_buffersMutex);
 | 
				
			||||||
 | 
						std::swap(m_frontBuffer, m_backBuffer);
 | 
				
			||||||
	m_isDataChanged = true;
 | 
						m_isDataChanged = true;
 | 
				
			||||||
 | 
						return m_backBuffer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void TVScreenAnalog::tick()
 | 
					void TVScreenAnalog::tick()
 | 
				
			||||||
@ -190,15 +198,17 @@ void TVScreenAnalog::paintGL()
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::shared_ptr<TVScreenAnalogBuffer> buffer = m_frontBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!m_imageTexture ||
 | 
						if (!m_imageTexture ||
 | 
				
			||||||
		m_imageTexture->width() != m_data->getWidth() ||
 | 
							m_imageTexture->width() != buffer->getWidth() ||
 | 
				
			||||||
		m_imageTexture->height() != m_data->getHeight())
 | 
							m_imageTexture->height() != buffer->getHeight())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		initializeTextures();
 | 
							initializeTextures(buffer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float imageWidth = m_data->getWidth();
 | 
						float imageWidth = buffer->getWidth();
 | 
				
			||||||
	float imageHeight = m_data->getHeight();
 | 
						float imageHeight = buffer->getHeight();
 | 
				
			||||||
	float texelWidth = 1.0f / imageWidth;
 | 
						float texelWidth = 1.0f / imageWidth;
 | 
				
			||||||
	float texelHeight = 1.0f / imageHeight;
 | 
						float texelHeight = 1.0f / imageHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -213,12 +223,12 @@ void TVScreenAnalog::paintGL()
 | 
				
			|||||||
	glActiveTexture(GL_TEXTURE0);
 | 
						glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
	m_imageTexture->bind();
 | 
						m_imageTexture->bind();
 | 
				
			||||||
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
 | 
						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
 | 
				
			||||||
		m_data->getWidth(), m_data->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_data->getImageData());
 | 
							buffer->getWidth(), buffer->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, buffer->getImageData());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glActiveTexture(GL_TEXTURE1);
 | 
						glActiveTexture(GL_TEXTURE1);
 | 
				
			||||||
	m_lineShiftsTexture->bind();
 | 
						m_lineShiftsTexture->bind();
 | 
				
			||||||
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
 | 
						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
 | 
				
			||||||
		1, m_data->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, m_data->getLineShiftData());
 | 
							1, buffer->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, buffer->getLineShiftData());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float rectHalfWidth = 1.0f + 4.0f / (imageWidth - 4.0f);
 | 
						float rectHalfWidth = 1.0f + 4.0f / (imageWidth - 4.0f);
 | 
				
			||||||
	GLfloat vertices[] =
 | 
						GLfloat vertices[] =
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,6 @@
 | 
				
			|||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <QImage>
 | 
					 | 
				
			||||||
#include <QMutex>
 | 
					#include <QMutex>
 | 
				
			||||||
#include <QTimer>
 | 
					#include <QTimer>
 | 
				
			||||||
#include <QGLWidget>
 | 
					#include <QGLWidget>
 | 
				
			||||||
@ -36,10 +35,10 @@
 | 
				
			|||||||
#include <QOpenGLFunctions>
 | 
					#include <QOpenGLFunctions>
 | 
				
			||||||
#include <QOpenGLShaderProgram>
 | 
					#include <QOpenGLShaderProgram>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TVScreenAnalogData
 | 
					class TVScreenAnalogBuffer
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	TVScreenAnalogData(int width, int height)
 | 
						TVScreenAnalogBuffer(int width, int height)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_width = width;
 | 
							m_width = width;
 | 
				
			||||||
		m_height = height;
 | 
							m_height = height;
 | 
				
			||||||
@ -53,7 +52,7 @@ public:
 | 
				
			|||||||
		std::fill(m_lineShiftData, m_lineShiftData + height, 127);
 | 
							std::fill(m_lineShiftData, m_lineShiftData + height, 127);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~TVScreenAnalogData()
 | 
						~TVScreenAnalogBuffer()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		delete[] m_imageData;
 | 
							delete[] m_imageData;
 | 
				
			||||||
		delete[] m_lineShiftData;
 | 
							delete[] m_lineShiftData;
 | 
				
			||||||
@ -116,7 +115,7 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	Q_OBJECT
 | 
						Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QTimer m_objTimer;
 | 
						QTimer m_updateTimer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool m_isDataChanged;
 | 
						bool m_isDataChanged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -129,7 +128,9 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
 | 
				
			|||||||
	int m_vertexAttribIndex;
 | 
						int m_vertexAttribIndex;
 | 
				
			||||||
	int m_texCoordAttribIndex;
 | 
						int m_texCoordAttribIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::shared_ptr<TVScreenAnalogData> m_data;
 | 
						QMutex m_buffersMutex;
 | 
				
			||||||
 | 
						std::shared_ptr<TVScreenAnalogBuffer> m_frontBuffer;
 | 
				
			||||||
 | 
						std::shared_ptr<TVScreenAnalogBuffer> m_backBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::shared_ptr<QOpenGLShaderProgram> m_shader;
 | 
						std::shared_ptr<QOpenGLShaderProgram> m_shader;
 | 
				
			||||||
	std::shared_ptr<QOpenGLTexture> m_imageTexture;
 | 
						std::shared_ptr<QOpenGLTexture> m_imageTexture;
 | 
				
			||||||
@ -138,12 +139,12 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	TVScreenAnalog(QWidget *parent);
 | 
						TVScreenAnalog(QWidget *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::shared_ptr<TVScreenAnalogData> getData();
 | 
						std::shared_ptr<TVScreenAnalogBuffer> getBackBuffer();
 | 
				
			||||||
 | 
						std::shared_ptr<TVScreenAnalogBuffer> swapBuffers();
 | 
				
			||||||
	void resizeTVScreen(int intCols, int intRows);
 | 
						void resizeTVScreen(int intCols, int intRows);
 | 
				
			||||||
	void renderImage();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void initializeTextures();
 | 
						void initializeTextures(std::shared_ptr<TVScreenAnalogBuffer> buffer);
 | 
				
			||||||
	void initializeGL() override;
 | 
						void initializeGL() override;
 | 
				
			||||||
	void paintGL() override;
 | 
						void paintGL() override;
 | 
				
			||||||
	void resizeGL(int width, int height);
 | 
						void resizeGL(int width, int height);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user