mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Started taking steps towards using a texture barrier where possible to reduce all of my framebuffer binds. Some output appears, but it's not correct.
This commit is contained in:
parent
0487b8c178
commit
be48c950b4
@ -6,8 +6,10 @@
|
||||
//
|
||||
|
||||
#include "CRT.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "CRTOpenGL.hpp"
|
||||
#include "../../../SignalProcessing/FIRFilter.hpp"
|
||||
@ -21,6 +23,8 @@ namespace {
|
||||
static const GLenum filtered_texture_unit = GL_TEXTURE2;
|
||||
static const GLenum source_data_texture_unit = GL_TEXTURE3;
|
||||
static const GLenum pixel_accumulation_texture_unit = GL_TEXTURE4;
|
||||
|
||||
static const GLenum work_texture_unit = GL_TEXTURE0;
|
||||
}
|
||||
|
||||
OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) :
|
||||
@ -32,10 +36,7 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) :
|
||||
last_output_height_(0),
|
||||
fence_(nullptr),
|
||||
texture_builder(bytes_per_pixel, source_data_texture_unit),
|
||||
array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize),
|
||||
composite_texture_(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit),
|
||||
separated_texture_(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit),
|
||||
filtered_texture_(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit)
|
||||
array_builder(SourceVertexBufferDataSize, OutputVertexBufferDataSize)
|
||||
{
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_COLOR);
|
||||
glBlendColor(0.6f, 0.6f, 0.6f, 1.0f);
|
||||
@ -45,6 +46,32 @@ OpenGLOutputBuilder::OpenGLOutputBuilder(size_t bytes_per_pixel) :
|
||||
|
||||
// create the source vertex array
|
||||
glGenVertexArrays(1, &source_vertex_array_);
|
||||
|
||||
bool supports_texture_barrier = false;
|
||||
#ifdef GL_NV_texture_barrier
|
||||
GLint number_of_extensions;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &number_of_extensions);
|
||||
|
||||
for(GLuint c = 0; c < (GLuint)number_of_extensions; c++)
|
||||
{
|
||||
const char *extension_name = (const char *)glGetStringi(GL_EXTENSIONS, c);
|
||||
if(!strcmp(extension_name, "GL_NV_texture_barrier"))
|
||||
{
|
||||
supports_texture_barrier = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(supports_texture_barrier)
|
||||
{
|
||||
work_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight*2, work_texture_unit));
|
||||
}
|
||||
else
|
||||
{
|
||||
composite_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, composite_texture_unit));
|
||||
separated_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, separated_texture_unit));
|
||||
filtered_texture_.reset(new OpenGL::TextureTarget(IntermediateBufferWidth, IntermediateBufferHeight, filtered_texture_unit));
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLOutputBuilder::~OpenGLOutputBuilder()
|
||||
@ -121,26 +148,25 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
|
||||
output_mutex_.unlock();
|
||||
|
||||
struct RenderStage {
|
||||
OpenGL::TextureTarget *const target;
|
||||
OpenGL::Shader *const shader;
|
||||
OpenGL::TextureTarget *const target;
|
||||
float clear_colour[3];
|
||||
};
|
||||
|
||||
// for composite video, go through four steps to get to something that can be painted to the output
|
||||
RenderStage composite_render_stages[] =
|
||||
{
|
||||
{&composite_texture_, composite_input_shader_program_.get(), {0.0, 0.0, 0.0}},
|
||||
{&separated_texture_, composite_separation_filter_program_.get(), {0.0, 0.5, 0.5}},
|
||||
// {&filtered_y_texture_, composite_y_filter_shader_program_.get(), {0.0, 0.5, 0.5}},
|
||||
{&filtered_texture_, composite_chrominance_filter_shader_program_.get(), {0.0, 0.0, 0.0}},
|
||||
{composite_input_shader_program_.get(), composite_texture_.get(), {0.0, 0.0, 0.0}},
|
||||
{composite_separation_filter_program_.get(), separated_texture_.get(), {0.0, 0.5, 0.5}},
|
||||
{composite_chrominance_filter_shader_program_.get(), filtered_texture_.get(), {0.0, 0.0, 0.0}},
|
||||
{nullptr}
|
||||
};
|
||||
|
||||
// for RGB video, there's only two steps
|
||||
RenderStage rgb_render_stages[] =
|
||||
{
|
||||
{&composite_texture_, rgb_input_shader_program_.get(), {0.0, 0.0, 0.0}},
|
||||
{&filtered_texture_, rgb_filter_shader_program_.get(), {0.0, 0.0, 0.0}},
|
||||
{rgb_input_shader_program_.get(), composite_texture_.get(), {0.0, 0.0, 0.0}},
|
||||
{rgb_filter_shader_program_.get(), filtered_texture_.get(), {0.0, 0.0, 0.0}},
|
||||
{nullptr}
|
||||
};
|
||||
|
||||
@ -152,24 +178,39 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
|
||||
glBindVertexArray(source_vertex_array_);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
while(active_pipeline->target)
|
||||
#ifdef GL_NV_texture_barrier
|
||||
if(work_texture_)
|
||||
{
|
||||
work_texture_->bind_framebuffer();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
while(active_pipeline->shader)
|
||||
{
|
||||
// switch to the framebuffer and shader associated with this stage
|
||||
active_pipeline->shader->bind();
|
||||
active_pipeline->target->bind_framebuffer();
|
||||
|
||||
// if this is the final stage before painting to the CRT, clear the framebuffer before drawing in order to blank out
|
||||
// those portions for which no input was provided
|
||||
if(!active_pipeline[1].target)
|
||||
if(!work_texture_)
|
||||
{
|
||||
glClearColor(active_pipeline->clear_colour[0], active_pipeline->clear_colour[1], active_pipeline->clear_colour[2], 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
active_pipeline->target->bind_framebuffer();
|
||||
|
||||
// if this is the final stage before painting to the CRT, clear the framebuffer before drawing in order to blank out
|
||||
// those portions for which no input was provided
|
||||
if(!active_pipeline[1].shader)
|
||||
{
|
||||
glClearColor(active_pipeline->clear_colour[0], active_pipeline->clear_colour[1], active_pipeline->clear_colour[2], 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
// draw
|
||||
glDrawArraysInstanced(GL_LINES, 0, 2, (GLsizei)array_submission.input_size / SourceVertexSize);
|
||||
|
||||
active_pipeline++;
|
||||
#ifdef GL_NV_texture_barrier
|
||||
glTextureBarrierNV();
|
||||
#endif
|
||||
}
|
||||
|
||||
// prepare to transfer to framebuffer
|
||||
@ -192,6 +233,10 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize);
|
||||
}
|
||||
|
||||
#ifdef GL_NV_texture_barrier
|
||||
glTextureBarrierNV();
|
||||
#endif
|
||||
|
||||
// copy framebuffer to the intended place
|
||||
glDisable(GL_BLEND);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
@ -247,18 +292,17 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders()
|
||||
composite_input_shader_program_ = OpenGL::IntermediateShader::make_source_conversion_shader(composite_shader_, rgb_shader_);
|
||||
composite_input_shader_program_->set_source_texture_unit(source_data_texture_unit);
|
||||
composite_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||
composite_input_shader_program_->set_vertical_offsets(0.0f, 0.0f);
|
||||
|
||||
composite_separation_filter_program_ = OpenGL::IntermediateShader::make_chroma_luma_separation_shader();
|
||||
composite_separation_filter_program_->set_source_texture_unit(composite_texture_unit);
|
||||
composite_separation_filter_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : composite_texture_unit);
|
||||
composite_separation_filter_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||
|
||||
// composite_y_filter_shader_program_ = OpenGL::IntermediateShader::make_luma_filter_shader();
|
||||
// composite_y_filter_shader_program_->set_source_texture_unit(separated_texture_unit);
|
||||
// composite_y_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||
composite_separation_filter_program_->set_vertical_offsets(0.0f, work_texture_ ? 0.5f : 0.0f);
|
||||
|
||||
composite_chrominance_filter_shader_program_ = OpenGL::IntermediateShader::make_chroma_filter_shader();
|
||||
composite_chrominance_filter_shader_program_->set_source_texture_unit(separated_texture_unit);
|
||||
composite_chrominance_filter_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : separated_texture_unit);
|
||||
composite_chrominance_filter_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||
composite_chrominance_filter_shader_program_->set_vertical_offsets(work_texture_ ? 0.5f : 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void OpenGLOutputBuilder::prepare_rgb_input_shaders()
|
||||
@ -292,7 +336,7 @@ void OpenGLOutputBuilder::prepare_source_vertex_array()
|
||||
void OpenGLOutputBuilder::prepare_output_shader()
|
||||
{
|
||||
output_shader_program_ = OpenGL::OutputShader::make_shader("", "texture(texID, srcCoordinatesVarying).rgb", false);
|
||||
output_shader_program_->set_source_texture_unit(filtered_texture_unit);
|
||||
output_shader_program_->set_source_texture_unit(work_texture_ ? work_texture_unit : filtered_texture_unit);
|
||||
}
|
||||
|
||||
void OpenGLOutputBuilder::prepare_output_vertex_array()
|
||||
|
@ -66,12 +66,19 @@ class OpenGLOutputBuilder {
|
||||
GLsizei composite_src_output_y_;
|
||||
|
||||
std::unique_ptr<OpenGL::OutputShader> output_shader_program_;
|
||||
std::unique_ptr<OpenGL::IntermediateShader> composite_input_shader_program_, composite_separation_filter_program_, composite_chrominance_filter_shader_program_;
|
||||
std::unique_ptr<OpenGL::IntermediateShader> rgb_input_shader_program_, rgb_filter_shader_program_;
|
||||
|
||||
OpenGL::TextureTarget composite_texture_; // receives raw composite levels
|
||||
OpenGL::TextureTarget separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B
|
||||
OpenGL::TextureTarget filtered_texture_; // receives filtered YIQ or YUV
|
||||
std::unique_ptr<OpenGL::IntermediateShader> composite_input_shader_program_;
|
||||
std::unique_ptr<OpenGL::IntermediateShader> composite_separation_filter_program_;
|
||||
std::unique_ptr<OpenGL::IntermediateShader> composite_chrominance_filter_shader_program_;
|
||||
|
||||
std::unique_ptr<OpenGL::IntermediateShader> rgb_input_shader_program_;
|
||||
std::unique_ptr<OpenGL::IntermediateShader> rgb_filter_shader_program_;
|
||||
|
||||
std::unique_ptr<OpenGL::TextureTarget> composite_texture_; // receives raw composite levels
|
||||
std::unique_ptr<OpenGL::TextureTarget> separated_texture_; // receives filtered Y in the R channel plus unfiltered but demodulated chrominance in G and B
|
||||
std::unique_ptr<OpenGL::TextureTarget> filtered_texture_; // receives filtered YIQ or YUV
|
||||
|
||||
std::unique_ptr<OpenGL::TextureTarget> work_texture_; // used for all intermediate rendering if texture fences are supported
|
||||
|
||||
std::unique_ptr<OpenGL::TextureTarget> framebuffer_; // the current pixel output
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#else
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/gl3.h>
|
||||
#include <OpenGL/gl3ext.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -46,6 +46,8 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const char *
|
||||
"uniform %s texID;"
|
||||
"uniform float offsets[5];"
|
||||
"uniform vec2 widthScalers;"
|
||||
"uniform float inputVerticalOffset;"
|
||||
"uniform float outputVerticalOffset;"
|
||||
|
||||
"out vec2 phaseAndAmplitudeVarying;"
|
||||
"out vec2 inputPositionsVarying[11];"
|
||||
@ -60,8 +62,8 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const char *
|
||||
// inputPosition.x is either inputStart.x or ends.x, depending on whether it is on the left or the right;
|
||||
// outputPosition.x is either outputStart.x or ends.y;
|
||||
// .ys are inputStart.y and outputStart.y respectively
|
||||
"vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y);"
|
||||
"vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y);"
|
||||
"vec2 inputPosition = vec2(mix(inputStart.x, ends.x, extent)*widthScalers[0], inputStart.y + inputVerticalOffset);"
|
||||
"vec2 outputPosition = vec2(mix(outputStart.x, ends.y, extent)*widthScalers[1], outputStart.y + outputVerticalOffset);"
|
||||
|
||||
// extension is the amount to extend both the input and output by to add a full colour cycle at each end
|
||||
"vec2 extensionVector = vec2(extension, 0.0) * 2.0 * (extent - 0.5);"
|
||||
@ -76,17 +78,17 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const char *
|
||||
"vec2 mappedInputPosition = (extendedInputPosition + vec2(0.0, 0.5)) / textureSize;"
|
||||
|
||||
// setup input positions spaced as per the supplied offsets; these are for filtering where required
|
||||
"inputPositionsVarying[0] = mappedInputPosition - (vec2(offsets[0], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[1] = mappedInputPosition - (vec2(offsets[1], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[2] = mappedInputPosition - (vec2(offsets[2], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[3] = mappedInputPosition - (vec2(offsets[3], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[4] = mappedInputPosition - (vec2(offsets[4], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[1] = mappedInputPosition - (vec2(4.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[2] = mappedInputPosition - (vec2(3.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[3] = mappedInputPosition - (vec2(2.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[4] = mappedInputPosition - (vec2(1.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[5] = mappedInputPosition;"
|
||||
"inputPositionsVarying[6] = mappedInputPosition + (vec2(offsets[4], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[7] = mappedInputPosition + (vec2(offsets[3], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[8] = mappedInputPosition + (vec2(offsets[2], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[9] = mappedInputPosition + (vec2(offsets[1], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[10] = mappedInputPosition + (vec2(offsets[0], 0.0) / textureSize);"
|
||||
"inputPositionsVarying[6] = mappedInputPosition + (vec2(1.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[7] = mappedInputPosition + (vec2(2.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[8] = mappedInputPosition + (vec2(3.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[9] = mappedInputPosition + (vec2(4.0, 0.0) / textureSize);"
|
||||
"inputPositionsVarying[10] = mappedInputPosition + (vec2(5.0, 0.0) / textureSize);"
|
||||
"delayLinePositionVarying = mappedInputPosition - vec2(0.0, 1.0);"
|
||||
|
||||
// setup phaseAndAmplitudeVarying.x as colour burst subcarrier phase, in radians;
|
||||
@ -474,3 +476,9 @@ void IntermediateShader::set_width_scalers(float input_scaler, float output_scal
|
||||
{
|
||||
set_uniform("widthScalers", input_scaler, output_scaler);
|
||||
}
|
||||
|
||||
void IntermediateShader::set_vertical_offsets(float input, float output)
|
||||
{
|
||||
set_uniform("inputVerticalOffset", input);
|
||||
set_uniform("outputVerticalOffset", output);
|
||||
}
|
||||
|
@ -89,6 +89,11 @@ public:
|
||||
*/
|
||||
void set_width_scalers(float input_scaler, float output_scaler);
|
||||
|
||||
/*!
|
||||
Sets source and target vertical offsets.
|
||||
*/
|
||||
void set_vertical_offsets(float input, float output);
|
||||
|
||||
private:
|
||||
static std::unique_ptr<IntermediateShader> make_shader(const char *fragment_shader, bool use_usampler, bool input_is_inputPosition);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user