1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-29 12:50:28 +00:00

Hides the modals.

This commit is contained in:
Thomas Harte 2020-07-27 23:33:39 -04:00
parent 62be2a2eec
commit 2470055d90
4 changed files with 65 additions and 37 deletions

View File

@ -114,7 +114,8 @@ void ScanTarget::set_target_framebuffer(GLuint target_framebuffer) {
} }
void ScanTarget::setup_pipeline() { void ScanTarget::setup_pipeline() {
const auto data_type_size = Outputs::Display::size_for_data_type(modals_.input_data_type); auto modals = BufferingScanTarget::modals();
const auto data_type_size = Outputs::Display::size_for_data_type(modals.input_data_type);
// Resize the texture only if required. // Resize the texture only if required.
if(data_type_size != write_area_data_size()) { if(data_type_size != write_area_data_size()) {
@ -127,7 +128,7 @@ void ScanTarget::setup_pipeline() {
test_gl(glBindBuffer, GL_ARRAY_BUFFER, line_buffer_name_); test_gl(glBindBuffer, GL_ARRAY_BUFFER, line_buffer_name_);
// Destroy or create a QAM buffer and shader, if appropriate. // Destroy or create a QAM buffer and shader, if appropriate.
const bool needs_qam_buffer = (modals_.display_type == DisplayType::CompositeColour || modals_.display_type == DisplayType::SVideo); const bool needs_qam_buffer = (modals.display_type == DisplayType::CompositeColour || modals.display_type == DisplayType::SVideo);
if(needs_qam_buffer) { if(needs_qam_buffer) {
if(!qam_chroma_texture_) { if(!qam_chroma_texture_) {
qam_chroma_texture_ = std::make_unique<TextureTarget>(LineBufferWidth, LineBufferHeight, QAMChromaTextureUnit, GL_NEAREST, false); qam_chroma_texture_ = std::make_unique<TextureTarget>(LineBufferWidth, LineBufferHeight, QAMChromaTextureUnit, GL_NEAREST, false);
@ -146,8 +147,8 @@ void ScanTarget::setup_pipeline() {
output_shader_ = conversion_shader(); output_shader_ = conversion_shader();
enable_vertex_attributes(ShaderType::Conversion, *output_shader_); enable_vertex_attributes(ShaderType::Conversion, *output_shader_);
set_uniforms(ShaderType::Conversion, *output_shader_); set_uniforms(ShaderType::Conversion, *output_shader_);
output_shader_->set_uniform("origin", modals_.visible_area.origin.x, modals_.visible_area.origin.y); output_shader_->set_uniform("origin", modals.visible_area.origin.x, modals.visible_area.origin.y);
output_shader_->set_uniform("size", modals_.visible_area.size.width, modals_.visible_area.size.height); output_shader_->set_uniform("size", modals.visible_area.size.width, modals.visible_area.size.height);
output_shader_->set_uniform("textureName", GLint(UnprocessedLineBufferTextureUnit - GL_TEXTURE0)); output_shader_->set_uniform("textureName", GLint(UnprocessedLineBufferTextureUnit - GL_TEXTURE0));
output_shader_->set_uniform("qamTextureName", GLint(QAMChromaTextureUnit - GL_TEXTURE0)); output_shader_->set_uniform("qamTextureName", GLint(QAMChromaTextureUnit - GL_TEXTURE0));
@ -161,7 +162,8 @@ void ScanTarget::setup_pipeline() {
} }
bool ScanTarget::is_soft_display_type() { bool ScanTarget::is_soft_display_type() {
return modals_.display_type == DisplayType::CompositeColour || modals_.display_type == DisplayType::CompositeMonochrome; const auto display_type = modals().display_type;
return display_type == DisplayType::CompositeColour || display_type == DisplayType::CompositeMonochrome;
} }
void ScanTarget::update(int, int output_height) { void ScanTarget::update(int, int output_height) {
@ -186,10 +188,10 @@ void ScanTarget::update(int, int output_height) {
// Grab the new output list. // Grab the new output list.
perform([=] (const OutputArea &area) { perform([=] (const OutputArea &area) {
// Establish the pipeline if necessary. // Establish the pipeline if necessary.
const bool did_setup_pipeline = modals_are_dirty_; const auto new_modals = BufferingScanTarget::new_modals();
if(modals_are_dirty_) { const bool did_setup_pipeline = bool(new_modals);
if(did_setup_pipeline) {
setup_pipeline(); setup_pipeline();
modals_are_dirty_ = false;
} }
// Determine the start time of this submission group and the number of lines it will contain. // Determine the start time of this submission group and the number of lines it will contain.
@ -291,7 +293,7 @@ void ScanTarget::update(int, int output_height) {
// Determine the proper clear colour — this needs to be anything that describes black // Determine the proper clear colour — this needs to be anything that describes black
// in the input colour encoding at use. // in the input colour encoding at use.
if(modals_.input_data_type == InputDataType::Luminance8Phase8) { if(modals().input_data_type == InputDataType::Luminance8Phase8) {
// Supply both a zero luminance and a colour-subcarrier-disengaging phase. // Supply both a zero luminance and a colour-subcarrier-disengaging phase.
test_gl(glClearColor, 0.0f, 1.0f, 0.0f, 0.0f); test_gl(glClearColor, 0.0f, 1.0f, 0.0f, 0.0f);
} else { } else {

View File

@ -23,14 +23,15 @@ void ScanTarget::set_uniforms(ShaderType type, Shader &target) const {
// converge even allowing for the fact that they may not be spaced by exactly // converge even allowing for the fact that they may not be spaced by exactly
// the expected distance. Cf. the stencil-powered logic for making sure all // the expected distance. Cf. the stencil-powered logic for making sure all
// pixels are painted only exactly once per field. // pixels are painted only exactly once per field.
const auto modals = BufferingScanTarget::modals();
switch(type) { switch(type) {
case ShaderType::Composition: break; case ShaderType::Composition: break;
default: default:
target.set_uniform("rowHeight", GLfloat(1.05f / modals_.expected_vertical_lines)); target.set_uniform("rowHeight", GLfloat(1.05f / modals.expected_vertical_lines));
target.set_uniform("scale", GLfloat(modals_.output_scale.x), GLfloat(modals_.output_scale.y) * modals_.aspect_ratio * (3.0f / 4.0f)); target.set_uniform("scale", GLfloat(modals.output_scale.x), GLfloat(modals.output_scale.y) * modals.aspect_ratio * (3.0f / 4.0f));
target.set_uniform("phaseOffset", GLfloat(modals_.input_data_tweaks.phase_linked_luminance_offset)); target.set_uniform("phaseOffset", GLfloat(modals.input_data_tweaks.phase_linked_luminance_offset));
const float clocks_per_angle = float(modals_.cycles_per_line) * float(modals_.colour_cycle_denominator) / float(modals_.colour_cycle_numerator); const float clocks_per_angle = float(modals.cycles_per_line) * float(modals.colour_cycle_denominator) / float(modals.colour_cycle_numerator);
GLfloat texture_offsets[4]; GLfloat texture_offsets[4];
GLfloat angles[4]; GLfloat angles[4];
for(int c = 0; c < 4; ++c) { for(int c = 0; c < 4; ++c) {
@ -41,7 +42,7 @@ void ScanTarget::set_uniforms(ShaderType type, Shader &target) const {
target.set_uniform("textureCoordinateOffsets", 1, 4, texture_offsets); target.set_uniform("textureCoordinateOffsets", 1, 4, texture_offsets);
target.set_uniform("compositeAngleOffsets", 4, 1, angles); target.set_uniform("compositeAngleOffsets", 4, 1, angles);
switch(modals_.composite_colour_space) { switch(modals.composite_colour_space) {
case ColourSpace::YIQ: { case ColourSpace::YIQ: {
const GLfloat rgbToYIQ[] = {0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f}; const GLfloat rgbToYIQ[] = {0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f};
const GLfloat yiqToRGB[] = {1.0f, 1.0f, 1.0f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f}; const GLfloat yiqToRGB[] = {1.0f, 1.0f, 1.0f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f};
@ -61,9 +62,10 @@ void ScanTarget::set_uniforms(ShaderType type, Shader &target) const {
} }
void ScanTarget::set_sampling_window(int output_width, int, Shader &target) { void ScanTarget::set_sampling_window(int output_width, int, Shader &target) {
if(modals_.display_type != DisplayType::CompositeColour) { const auto modals = BufferingScanTarget::modals();
const float one_pixel_width = float(modals_.cycles_per_line) * modals_.visible_area.size.width / float(output_width); if(modals.display_type != DisplayType::CompositeColour) {
const float clocks_per_angle = float(modals_.cycles_per_line) * float(modals_.colour_cycle_denominator) / float(modals_.colour_cycle_numerator); const float one_pixel_width = float(modals.cycles_per_line) * modals.visible_area.size.width / float(output_width);
const float clocks_per_angle = float(modals.cycles_per_line) * float(modals.colour_cycle_denominator) / float(modals.colour_cycle_numerator);
GLfloat texture_offsets[4]; GLfloat texture_offsets[4];
GLfloat angles[4]; GLfloat angles[4];
for(int c = 0; c < 4; ++c) { for(int c = 0; c < 4; ++c) {
@ -191,8 +193,9 @@ std::vector<std::string> ScanTarget::bindings(ShaderType type) const {
std::string ScanTarget::sampling_function() const { std::string ScanTarget::sampling_function() const {
std::string fragment_shader; std::string fragment_shader;
const auto modals = BufferingScanTarget::modals();
if(modals_.display_type == DisplayType::SVideo) { if(modals.display_type == DisplayType::SVideo) {
fragment_shader += fragment_shader +=
"vec2 svideo_sample(vec2 coordinate, float angle) {"; "vec2 svideo_sample(vec2 coordinate, float angle) {";
} else { } else {
@ -200,8 +203,8 @@ std::string ScanTarget::sampling_function() const {
"float composite_sample(vec2 coordinate, float angle) {"; "float composite_sample(vec2 coordinate, float angle) {";
} }
const bool is_svideo = modals_.display_type == DisplayType::SVideo; const bool is_svideo = modals.display_type == DisplayType::SVideo;
switch(modals_.input_data_type) { switch(modals.input_data_type) {
case InputDataType::Luminance1: case InputDataType::Luminance1:
case InputDataType::Luminance8: case InputDataType::Luminance8:
// Easy, just copy across. // Easy, just copy across.
@ -255,6 +258,8 @@ std::string ScanTarget::sampling_function() const {
} }
std::unique_ptr<Shader> ScanTarget::conversion_shader() const { std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
const auto modals = BufferingScanTarget::modals();
// Compose a vertex shader. If the display type is RGB, generate just the proper // Compose a vertex shader. If the display type is RGB, generate just the proper
// geometry position, plus a solitary textureCoordinate. // geometry position, plus a solitary textureCoordinate.
// //
@ -301,7 +306,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
"out vec4 fragColour;"; "out vec4 fragColour;";
if(modals_.display_type != DisplayType::RGB) { if(modals.display_type != DisplayType::RGB) {
vertex_shader += vertex_shader +=
"out float compositeAngle;" "out float compositeAngle;"
"out float compositeAmplitude;" "out float compositeAmplitude;"
@ -316,7 +321,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
"uniform vec4 compositeAngleOffsets;"; "uniform vec4 compositeAngleOffsets;";
} }
if(modals_.display_type == DisplayType::SVideo || modals_.display_type == DisplayType::CompositeColour) { if(modals.display_type == DisplayType::SVideo || modals.display_type == DisplayType::CompositeColour) {
vertex_shader += "out vec2 qamTextureCoordinates[4];"; vertex_shader += "out vec2 qamTextureCoordinates[4];";
fragment_shader += "in vec2 qamTextureCoordinates[4];"; fragment_shader += "in vec2 qamTextureCoordinates[4];";
} }
@ -332,7 +337,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
"gl_Position = vec4(eyePosition, 0.0, 1.0);"; "gl_Position = vec4(eyePosition, 0.0, 1.0);";
// For everything other than RGB, calculate the two composite outputs. // For everything other than RGB, calculate the two composite outputs.
if(modals_.display_type != DisplayType::RGB) { if(modals.display_type != DisplayType::RGB) {
vertex_shader += vertex_shader +=
"compositeAngle = (mix(startCompositeAngle, endCompositeAngle, lateral) / 32.0) * 3.141592654;" "compositeAngle = (mix(startCompositeAngle, endCompositeAngle, lateral) / 32.0) * 3.141592654;"
"compositeAmplitude = lineCompositeAmplitude / 255.0;" "compositeAmplitude = lineCompositeAmplitude / 255.0;"
@ -346,7 +351,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
"textureCoordinates[2] = vec2(centreClock + textureCoordinateOffsets[2], lineY + 0.5) / textureSize(textureName, 0);" "textureCoordinates[2] = vec2(centreClock + textureCoordinateOffsets[2], lineY + 0.5) / textureSize(textureName, 0);"
"textureCoordinates[3] = vec2(centreClock + textureCoordinateOffsets[3], lineY + 0.5) / textureSize(textureName, 0);"; "textureCoordinates[3] = vec2(centreClock + textureCoordinateOffsets[3], lineY + 0.5) / textureSize(textureName, 0);";
if((modals_.display_type == DisplayType::SVideo) || (modals_.display_type == DisplayType::CompositeColour)) { if((modals.display_type == DisplayType::SVideo) || (modals.display_type == DisplayType::CompositeColour)) {
vertex_shader += vertex_shader +=
"float centreCompositeAngle = abs(mix(startCompositeAngle, endCompositeAngle, lateral)) * 4.0 / 64.0;" "float centreCompositeAngle = abs(mix(startCompositeAngle, endCompositeAngle, lateral)) * 4.0 / 64.0;"
"centreCompositeAngle = floor(centreCompositeAngle);" "centreCompositeAngle = floor(centreCompositeAngle);"
@ -360,7 +365,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
// Compose a fragment shader. // Compose a fragment shader.
if(modals_.display_type != DisplayType::RGB) { if(modals.display_type != DisplayType::RGB) {
fragment_shader += fragment_shader +=
"uniform mat3 lumaChromaToRGB;" "uniform mat3 lumaChromaToRGB;"
"uniform mat3 rgbToLumaChroma;"; "uniform mat3 rgbToLumaChroma;";
@ -372,7 +377,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
"void main(void) {" "void main(void) {"
"vec3 fragColour3;"; "vec3 fragColour3;";
switch(modals_.display_type) { switch(modals.display_type) {
case DisplayType::CompositeColour: case DisplayType::CompositeColour:
fragment_shader += fragment_shader +=
"vec4 angles = compositeAngle + compositeAngleOffsets;" "vec4 angles = compositeAngle + compositeAngleOffsets;"
@ -460,13 +465,13 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
} }
// Apply a brightness adjustment if requested. // Apply a brightness adjustment if requested.
if(fabs(modals_.brightness - 1.0f) > 0.05f) { if(fabs(modals.brightness - 1.0f) > 0.05f) {
fragment_shader += "fragColour3 = fragColour3 * " + std::to_string(modals_.brightness) + ";"; fragment_shader += "fragColour3 = fragColour3 * " + std::to_string(modals.brightness) + ";";
} }
// Apply a gamma correction if required. // Apply a gamma correction if required.
if(fabs(output_gamma_ - modals_.intended_gamma) > 0.05f) { if(fabs(output_gamma_ - modals.intended_gamma) > 0.05f) {
const float gamma_ratio = output_gamma_ / modals_.intended_gamma; const float gamma_ratio = output_gamma_ / modals.intended_gamma;
fragment_shader += "fragColour3 = pow(fragColour3, vec3(" + std::to_string(gamma_ratio) + "));"; fragment_shader += "fragColour3 = pow(fragColour3, vec3(" + std::to_string(gamma_ratio) + "));";
} }
@ -482,6 +487,7 @@ std::unique_ptr<Shader> ScanTarget::conversion_shader() const {
} }
std::unique_ptr<Shader> ScanTarget::composition_shader() const { std::unique_ptr<Shader> ScanTarget::composition_shader() const {
const auto modals = BufferingScanTarget::modals();
const std::string vertex_shader = const std::string vertex_shader =
"#version 150\n" "#version 150\n"
@ -516,7 +522,7 @@ std::unique_ptr<Shader> ScanTarget::composition_shader() const {
"void main(void) {"; "void main(void) {";
switch(modals_.input_data_type) { switch(modals.input_data_type) {
case InputDataType::Luminance1: case InputDataType::Luminance1:
fragment_shader += "fragColour = textureLod(textureName, textureCoordinate, 0).rrrr;"; fragment_shader += "fragColour = textureLod(textureName, textureCoordinate, 0).rrrr;";
break; break;
@ -556,7 +562,8 @@ std::unique_ptr<Shader> ScanTarget::composition_shader() const {
} }
std::unique_ptr<Shader> ScanTarget::qam_separation_shader() const { std::unique_ptr<Shader> ScanTarget::qam_separation_shader() const {
const bool is_svideo = modals_.display_type == DisplayType::SVideo; const auto modals = BufferingScanTarget::modals();
const bool is_svideo = modals.display_type == DisplayType::SVideo;
// Sets up texture coordinates to run between startClock and endClock, mapping to // Sets up texture coordinates to run between startClock and endClock, mapping to
// coordinates that correlate with four times the absolute value of the composite angle. // coordinates that correlate with four times the absolute value of the composite angle.
@ -632,7 +639,7 @@ std::unique_ptr<Shader> ScanTarget::qam_separation_shader() const {
sampling_function() + sampling_function() +
"void main(void) {"; "void main(void) {";
if(modals_.display_type == DisplayType::SVideo) { if(modals.display_type == DisplayType::SVideo) {
fragment_shader += fragment_shader +=
"fragColour = vec4(svideo_sample(textureCoordinate, compositeAngle).rgg * vec3(1.0, cos(compositeAngle), sin(compositeAngle)), 1.0);"; "fragColour = vec4(svideo_sample(textureCoordinate, compositeAngle).rgg * vec3(1.0, cos(compositeAngle), sin(compositeAngle)), 1.0);";
} else { } else {

View File

@ -310,3 +310,15 @@ void BufferingScanTarget::set_line_buffer(Line *line_buffer, LineMetadata *metad
line_metadata_buffer_ = metadata_buffer; line_metadata_buffer_ = metadata_buffer;
line_buffer_size_ = size; line_buffer_size_ = size;
} }
const Outputs::Display::ScanTarget::Modals *BufferingScanTarget::new_modals() {
if(!modals_are_dirty_) {
return nullptr;
}
modals_are_dirty_ = false;
return &modals_;
}
const Outputs::Display::ScanTarget::Modals &BufferingScanTarget::modals() const {
return modals_;
}

View File

@ -94,10 +94,12 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget {
/// Sets the area of memory to use as line and line metadata buffers. /// Sets the area of memory to use as line and line metadata buffers.
void set_line_buffer(Line *line_buffer, LineMetadata *metadata_buffer, size_t size); void set_line_buffer(Line *line_buffer, LineMetadata *metadata_buffer, size_t size);
// These are safe to read only within a `perform` block. /// @returns new Modals if any have been set since the last call to get_new_modals().
// TODO: can I do better than that? /// The caller must be within a @c perform block.
Modals modals_; const Modals *new_modals();
bool modals_are_dirty_ = false;
/// @returns the current @c Modals.
const Modals &modals() const;
/// Sets a new base address for the texture. /// Sets a new base address for the texture.
/// When called this will flush all existing data and load up the /// When called this will flush all existing data and load up the
@ -213,6 +215,11 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget {
Line *line_buffer_ = nullptr; Line *line_buffer_ = nullptr;
LineMetadata *line_metadata_buffer_ = nullptr; LineMetadata *line_metadata_buffer_ = nullptr;
size_t line_buffer_size_ = 0; size_t line_buffer_size_ = 0;
// Current modals and whether they've yet been returned
// from a call to @c get_new_modals.
Modals modals_;
bool modals_are_dirty_ = false;
}; };