ATV Demodulator: implement double buffering

This commit is contained in:
Vort 2020-08-10 15:54:34 +03:00
parent e704689be1
commit f08ed0ff7d
4 changed files with 46 additions and 35 deletions

View File

@ -484,7 +484,7 @@ void ATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque
m_samplesPerLine - m_numberSamplesPerLineSignals,
m_settings.m_nbLines - m_numberOfBlackLines
);
m_tvScreenData = m_registeredTVScreen->getData();
m_tvScreenBuffer = m_registeredTVScreen->getBackBuffer();
}
m_fieldIndex = 0;
@ -576,7 +576,7 @@ void ATVDemodSink::applySettings(const ATVDemodSettings& settings, bool force)
m_samplesPerLine - m_numberSamplesPerLineSignals,
m_settings.m_nbLines - m_numberOfBlackLines
);
m_tvScreenData = m_registeredTVScreen->getData();
m_tvScreenBuffer = m_registeredTVScreen->getBackBuffer();
}
m_fieldIndex = 0;

View File

@ -109,7 +109,7 @@ private:
//*************** ATV PARAMETERS ***************
TVScreenAnalog *m_registeredTVScreen;
std::shared_ptr<TVScreenAnalogData> m_tvScreenData;
std::shared_ptr<TVScreenAnalogBuffer> m_tvScreenBuffer;
//int m_intNumberSamplePerLine;
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)
{
// 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)
{
@ -278,7 +278,7 @@ private:
{
if (m_lineIndex == m_numberOfVSyncLines + 3 && m_fieldIndex == 0)
{
m_registeredTVScreen->renderImage();
m_tvScreenBuffer = m_registeredTVScreen->swapBuffers();
}
if (m_vSyncDetectSampleCount > m_vSyncDetectThreshold &&
@ -311,7 +311,7 @@ private:
if (m_interleaved)
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)
@ -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)
|| (!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_tvScreenData->selectRow(m_lineIndex, m_sampleOffsetFrac);
m_tvScreenBuffer->selectRow(m_lineIndex, m_sampleOffsetFrac);
}
};

View File

@ -68,10 +68,11 @@ TVScreenAnalog::TVScreenAnalog(QWidget *parent)
: QGLWidget(parent)
{
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()));
m_objTimer.start(40); // capped at 25 FPS
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(tick()));
m_updateTimer.start(40); // capped at 25 FPS
}
void TVScreenAnalog::cleanup()
@ -81,9 +82,9 @@ void TVScreenAnalog::cleanup()
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)
@ -91,8 +92,12 @@ void TVScreenAnalog::resizeTVScreen(int intCols, int intRows)
qDebug("TVScreen::resizeTVScreen: cols: %d, rows: %d", intCols, intRows);
int colsAdj = intCols + 4;
if (m_data->getWidth() != colsAdj || m_data->getHeight() != intRows)
m_data = std::make_shared<TVScreenAnalogData>(colsAdj, intRows);
QMutexLocker lock(&m_buffersMutex);
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)
@ -143,12 +148,12 @@ void TVScreenAnalog::initializeGL()
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_lineShiftsTexture = std::make_shared<QOpenGLTexture>(QOpenGLTexture::Target2D);
m_imageTexture->setSize(m_data->getWidth(), m_data->getHeight());
m_lineShiftsTexture->setSize(1, m_data->getHeight());
m_imageTexture->setSize(buffer->getWidth(), buffer->getHeight());
m_lineShiftsTexture->setSize(1, buffer->getHeight());
m_imageTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
m_lineShiftsTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
m_imageTexture->setAutoMipMapGenerationEnabled(false);
@ -166,9 +171,12 @@ void TVScreenAnalog::initializeTextures()
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;
return m_backBuffer;
}
void TVScreenAnalog::tick()
@ -190,15 +198,17 @@ void TVScreenAnalog::paintGL()
return;
}
std::shared_ptr<TVScreenAnalogBuffer> buffer = m_frontBuffer;
if (!m_imageTexture ||
m_imageTexture->width() != m_data->getWidth() ||
m_imageTexture->height() != m_data->getHeight())
m_imageTexture->width() != buffer->getWidth() ||
m_imageTexture->height() != buffer->getHeight())
{
initializeTextures();
initializeTextures(buffer);
}
float imageWidth = m_data->getWidth();
float imageHeight = m_data->getHeight();
float imageWidth = buffer->getWidth();
float imageHeight = buffer->getHeight();
float texelWidth = 1.0f / imageWidth;
float texelHeight = 1.0f / imageHeight;
@ -213,12 +223,12 @@ void TVScreenAnalog::paintGL()
glActiveTexture(GL_TEXTURE0);
m_imageTexture->bind();
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);
m_lineShiftsTexture->bind();
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);
GLfloat vertices[] =

View File

@ -28,7 +28,6 @@
#include <memory>
#include <algorithm>
#include <QImage>
#include <QMutex>
#include <QTimer>
#include <QGLWidget>
@ -36,10 +35,10 @@
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
class TVScreenAnalogData
class TVScreenAnalogBuffer
{
public:
TVScreenAnalogData(int width, int height)
TVScreenAnalogBuffer(int width, int height)
{
m_width = width;
m_height = height;
@ -53,7 +52,7 @@ public:
std::fill(m_lineShiftData, m_lineShiftData + height, 127);
}
~TVScreenAnalogData()
~TVScreenAnalogBuffer()
{
delete[] m_imageData;
delete[] m_lineShiftData;
@ -116,7 +115,7 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
QTimer m_objTimer;
QTimer m_updateTimer;
bool m_isDataChanged;
@ -129,7 +128,9 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
int m_vertexAttribIndex;
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<QOpenGLTexture> m_imageTexture;
@ -138,12 +139,12 @@ class SDRGUI_API TVScreenAnalog : public QGLWidget, protected QOpenGLFunctions
public:
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 renderImage();
private:
void initializeTextures();
void initializeTextures(std::shared_ptr<TVScreenAnalogBuffer> buffer);
void initializeGL() override;
void paintGL() override;
void resizeGL(int width, int height);