1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-13 22:32:03 +00:00

Extended window for picking output frequency, attempted to consolidate CRT OpenGL timing uniforms for approprate resetting.

This commit is contained in:
Thomas Harte 2016-04-24 18:58:31 -04:00
parent 082003ed0a
commit 929cfc49cb
3 changed files with 91 additions and 87 deletions

View File

@ -29,15 +29,20 @@ struct CRTDelegate: public Outputs::CRT::Delegate {
int _frameCount; int _frameCount;
int _hitCount; int _hitCount;
BOOL _didDecideRegion; BOOL _didDecideRegion;
int _batchesReceived;
} }
- (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs { - (void)crt:(Outputs::CRT::CRT *)crt didEndBatchOfFrames:(unsigned int)numberOfFrames withUnexpectedVerticalSyncs:(unsigned int)numberOfUnexpectedSyncs {
if(!_didDecideRegion) if(!_didDecideRegion)
{ {
_didDecideRegion = YES; _batchesReceived++;
if(numberOfUnexpectedSyncs >= numberOfFrames >> 1) if(_batchesReceived == 2)
{ {
_atari2600.switch_region(); _didDecideRegion = YES;
if(numberOfUnexpectedSyncs >= numberOfFrames >> 1)
{
_atari2600.switch_region();
}
} }
} }
} }

View File

@ -185,6 +185,8 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out
prepare_rgb_output_shader(); prepare_rgb_output_shader();
prepare_output_vertex_array(); prepare_output_vertex_array();
set_timing_uniforms();
// This should return either an actual framebuffer number, if this is a target with a framebuffer intended for output, // This should return either an actual framebuffer number, if this is a target with a framebuffer intended for output,
// or 0 if no framebuffer is bound, in which case 0 is also what we want to supply to bind the implied framebuffer. So // or 0 if no framebuffer is bound, in which case 0 is also what we want to supply to bind the implied framebuffer. So
// it works either way. // it works either way.
@ -762,17 +764,11 @@ std::unique_ptr<OpenGL::Shader> OpenGLOutputBuilder::prepare_intermediate_shader
shader = std::unique_ptr<OpenGL::Shader>(new OpenGL::Shader(vertex_shader, fragment_shader, bindings)); shader = std::unique_ptr<OpenGL::Shader>(new OpenGL::Shader(vertex_shader, fragment_shader, bindings));
GLint texIDUniform = shader->get_uniform_location("texID"); GLint texIDUniform = shader->get_uniform_location("texID");
GLint phaseCyclesPerTickUniform = shader->get_uniform_location("phaseCyclesPerTick");
GLint outputTextureSizeUniform = shader->get_uniform_location("outputTextureSize"); GLint outputTextureSizeUniform = shader->get_uniform_location("outputTextureSize");
GLint extensionUniform = shader->get_uniform_location("extension");
shader->bind(); shader->bind();
glUniform1i(texIDUniform, (GLint)(texture_unit - GL_TEXTURE0)); glUniform1i(texIDUniform, (GLint)(texture_unit - GL_TEXTURE0));
glUniform2i(outputTextureSizeUniform, IntermediateBufferWidth, IntermediateBufferHeight); glUniform2i(outputTextureSizeUniform, IntermediateBufferWidth, IntermediateBufferHeight);
float phaseCyclesPerTick = (float)_colour_cycle_numerator / (float)(_colour_cycle_denominator * _cycles_per_line);
glUniform1f(phaseCyclesPerTickUniform, phaseCyclesPerTick);
glUniform1f(extensionUniform, extends ? ceilf(1.0f / phaseCyclesPerTick) : 0.0f);
} }
free(vertex_shader); free(vertex_shader);
free(fragment_shader); free(fragment_shader);
@ -784,23 +780,10 @@ void OpenGLOutputBuilder::prepare_composite_input_shader()
{ {
composite_input_shader_program = prepare_intermediate_shader("inputPosition", "uniform usampler2D texID;", get_input_fragment_shader(), source_data_texture_unit, false); composite_input_shader_program = prepare_intermediate_shader("inputPosition", "uniform usampler2D texID;", get_input_fragment_shader(), source_data_texture_unit, false);
float colour_subcarrier_frequency = (float)_colour_cycle_numerator / (float)_colour_cycle_denominator;
GLint weightsUniform;
float weights[12];
composite_y_filter_shader_program = prepare_intermediate_shader("outputPosition", "uniform sampler2D texID;", get_y_filter_fragment_shader(), composite_texture_unit, true); composite_y_filter_shader_program = prepare_intermediate_shader("outputPosition", "uniform sampler2D texID;", get_y_filter_fragment_shader(), composite_texture_unit, true);
SignalProcessing::FIRFilter luminance_filter(11, _cycles_per_line * 0.5f, 0.0f, colour_subcarrier_frequency * 0.5f, SignalProcessing::FIRFilter::DefaultAttenuation);
composite_y_filter_shader_program->bind();
weightsUniform = composite_y_filter_shader_program->get_uniform_location("weights");
luminance_filter.get_coefficients(weights);
glUniform4fv(weightsUniform, 3, weights);
composite_chrominance_filter_shader_program = prepare_intermediate_shader("outputPosition", "uniform sampler2D texID;", get_chrominance_filter_fragment_shader(), filtered_y_texture_unit, false); composite_chrominance_filter_shader_program = prepare_intermediate_shader("outputPosition", "uniform sampler2D texID;", get_chrominance_filter_fragment_shader(), filtered_y_texture_unit, true);
SignalProcessing::FIRFilter chrominance_filter(11, _cycles_per_line * 0.5f, 0.0f, colour_subcarrier_frequency * 0.5f, SignalProcessing::FIRFilter::DefaultAttenuation);
composite_chrominance_filter_shader_program->bind();
weightsUniform = composite_chrominance_filter_shader_program->get_uniform_location("weights");
chrominance_filter.get_coefficients(weights);
glUniform4fv(weightsUniform, 3, weights);
} }
void OpenGLOutputBuilder::prepare_source_vertex_array() void OpenGLOutputBuilder::prepare_source_vertex_array()
@ -851,20 +834,7 @@ std::unique_ptr<OpenGL::Shader> OpenGLOutputBuilder::prepare_output_shader(char
timestampBaseUniform = shader_program->get_uniform_location("timestampBase"); timestampBaseUniform = shader_program->get_uniform_location("timestampBase");
GLint texIDUniform = shader_program->get_uniform_location("texID"); GLint texIDUniform = shader_program->get_uniform_location("texID");
GLint ticksPerFrameUniform = shader_program->get_uniform_location("ticksPerFrame");
GLint scanNormalUniform = shader_program->get_uniform_location("scanNormal");
GLint positionConversionUniform = shader_program->get_uniform_location("positionConversion");
glUniform1i(texIDUniform, source_texture_unit - GL_TEXTURE0); glUniform1i(texIDUniform, source_texture_unit - GL_TEXTURE0);
glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display));
glUniform2f(positionConversionUniform, _horizontal_scan_period, _vertical_scan_period / (unsigned int)_vertical_period_divider);
float scan_angle = atan2f(1.0f / (float)_height_of_display, 1.0f);
float scan_normal[] = { -sinf(scan_angle), cosf(scan_angle)};
float multiplier = (float)_cycles_per_line / ((float)_height_of_display * (float)_horizontal_scan_period);
scan_normal[0] *= multiplier;
scan_normal[1] *= multiplier;
glUniform2f(scanNormalUniform, scan_normal[0], scan_normal[1]);
} }
free(vertex_shader); free(vertex_shader);
@ -908,7 +878,7 @@ void OpenGLOutputBuilder::prepare_output_vertex_array()
} }
} }
#pragma mark - Configuration #pragma mark - Public Configuration
void OpenGLOutputBuilder::set_output_device(OutputDevice output_device) void OpenGLOutputBuilder::set_output_device(OutputDevice output_device)
{ {
@ -925,50 +895,87 @@ void OpenGLOutputBuilder::set_output_device(OutputDevice output_device)
} }
} }
void OpenGLOutputBuilder::set_timing(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider)
{
_cycles_per_line = cycles_per_line;
_height_of_display = height_of_display;
_horizontal_scan_period = horizontal_scan_period;
_vertical_scan_period = vertical_scan_period;
_vertical_period_divider = vertical_period_divider;
// const char *const ntscVertexShaderGlobals = set_timing_uniforms();
// "out vec2 srcCoordinatesVarying[4];\n" }
// "out float phase;\n";
//
// const char *const ntscVertexShaderBody =
// "phase = srcCoordinates.x * 6.283185308;\n"
// "\n"
// "srcCoordinatesVarying[0] = vec2(srcCoordinates.x / textureSize.x, (srcCoordinates.y + 0.5) / textureSize.y);\n"
// "srcCoordinatesVarying[3] = srcCoordinatesVarying[0] + vec2(0.375 / textureSize.x, 0.0);\n"
// "srcCoordinatesVarying[2] = srcCoordinatesVarying[0] + vec2(0.125 / textureSize.x, 0.0);\n"
// "srcCoordinatesVarying[1] = srcCoordinatesVarying[0] - vec2(0.125 / textureSize.x, 0.0);\n"
// "srcCoordinatesVarying[0] = srcCoordinatesVarying[0] - vec2(0.325 / textureSize.x, 0.0);\n";
// assumes y = [0, 1], i and q = [-0.5, 0.5]; therefore i components are multiplied by 1.1914 versus standard matrices, q by 1.0452 #pragma mark - Internal Configuration
// const char *const yiqToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);";
// assumes y = [0,1], u and v = [-0.5, 0.5]; therefore u components are multiplied by 1.14678899082569, v by 0.8130081300813 void OpenGLOutputBuilder::set_timing_uniforms()
// const char *const yuvToRGB = "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 0.0, -0.75213899082569, 2.33040137614679, 0.92669105691057, -0.4720325203252, 0.0);"; {
OpenGL::Shader *intermediate_shaders[] = {
composite_input_shader_program.get(),
composite_y_filter_shader_program.get(),
composite_chrominance_filter_shader_program.get()
};
bool extends = false;
for(int c = 0; c < 3; c++)
{
if(intermediate_shaders[c])
{
intermediate_shaders[c]->bind();
GLint phaseCyclesPerTickUniform = intermediate_shaders[c]->get_uniform_location("phaseCyclesPerTick");
GLint extensionUniform = intermediate_shaders[c]->get_uniform_location("extension");
// const char *const ntscFragmentShaderGlobals = float phaseCyclesPerTick = (float)_colour_cycle_numerator / (float)(_colour_cycle_denominator * _cycles_per_line);
// "in vec2 srcCoordinatesVarying[4];\n" glUniform1f(phaseCyclesPerTickUniform, phaseCyclesPerTick);
// "in float phase;\n" glUniform1f(extensionUniform, extends ? ceilf(1.0f / phaseCyclesPerTick) : 0.0f);
// "\n" }
// "// for conversion from i and q are in the range [-0.5, 0.5] (so i needs to be multiplied by 1.1914 and q by 1.0452)\n" extends = true;
// "const mat3 yiqToRGB = mat3(1.0, 1.0, 1.0, 1.1389784, -0.3240608, -1.3176884, 0.6490692, -0.6762444, 1.7799756);\n"; }
// const char *const ntscFragmentShaderBody = OpenGL::Shader *output_shaders[] = {
// "vec4 angles = vec4(phase) + vec4(-2.35619449019234, -0.78539816339745, 0.78539816339745, 2.35619449019234);\n" rgb_shader_program.get(),
// "vec4 samples = vec4(" composite_output_shader_program.get()
// " sample(srcCoordinatesVarying[0], angles.x)," };
// " sample(srcCoordinatesVarying[1], angles.y)," for(int c = 0; c < 2; c++)
// " sample(srcCoordinatesVarying[2], angles.z)," {
// " sample(srcCoordinatesVarying[3], angles.w)" if(output_shaders[c])
// ");\n" {
// "\n" output_shaders[c]->bind();
// "float y = dot(vec4(0.25), samples);\n"
// "samples -= vec4(y);\n"
// "\n"
// "float i = dot(cos(angles), samples);\n"
// "float q = dot(sin(angles), samples);\n"
// "\n"
// "fragColour = 5.0 * texture(shadowMaskTexID, shadowMaskCoordinates) * vec4(yiqToRGB * vec3(y, i, q), 1.0);//sin(lateralVarying));\n";
// dot(vec3(1.0/6.0, 2.0/3.0, 1.0/6.0), vec3(sample(srcCoordinatesVarying[0]), sample(srcCoordinatesVarying[0]), sample(srcCoordinatesVarying[0])));//sin(lateralVarying));\n"; GLint ticksPerFrameUniform = output_shaders[c]->get_uniform_location("ticksPerFrame");
//} GLint scanNormalUniform = output_shaders[c]->get_uniform_location("scanNormal");
GLint positionConversionUniform = output_shaders[c]->get_uniform_location("positionConversion");
glUniform1f(ticksPerFrameUniform, (GLfloat)(_cycles_per_line * _height_of_display));
float scan_angle = atan2f(1.0f / (float)_height_of_display, 1.0f);
float scan_normal[] = { -sinf(scan_angle), cosf(scan_angle)};
float multiplier = (float)_cycles_per_line / ((float)_height_of_display * (float)_horizontal_scan_period);
scan_normal[0] *= multiplier;
scan_normal[1] *= multiplier;
glUniform2f(scanNormalUniform, scan_normal[0], scan_normal[1]);
glUniform2f(positionConversionUniform, _horizontal_scan_period, _vertical_scan_period / (unsigned int)_vertical_period_divider);
}
}
float colour_subcarrier_frequency = (float)_colour_cycle_numerator / (float)_colour_cycle_denominator;
GLint weightsUniform;
float weights[12];
if(composite_y_filter_shader_program)
{
SignalProcessing::FIRFilter luminance_filter(11, _cycles_per_line * 0.5f, 0.0f, colour_subcarrier_frequency * 0.5f, SignalProcessing::FIRFilter::DefaultAttenuation);
composite_y_filter_shader_program->bind();
weightsUniform = composite_y_filter_shader_program->get_uniform_location("weights");
luminance_filter.get_coefficients(weights);
glUniform4fv(weightsUniform, 3, weights);
}
if(composite_chrominance_filter_shader_program)
{
SignalProcessing::FIRFilter chrominance_filter(11, _cycles_per_line * 0.5f, 0.0f, colour_subcarrier_frequency * 0.5f, SignalProcessing::FIRFilter::DefaultAttenuation);
composite_chrominance_filter_shader_program->bind();
weightsUniform = composite_chrominance_filter_shader_program->get_uniform_location("weights");
chrominance_filter.get_coefficients(weights);
glUniform4fv(weightsUniform, 3, weights);
}
}

View File

@ -97,6 +97,7 @@ class OpenGLOutputBuilder {
std::unique_ptr<OpenGL::TextureTarget> filteredTexture; // receives filtered YIQ or YUV std::unique_ptr<OpenGL::TextureTarget> filteredTexture; // receives filtered YIQ or YUV
void perform_output_stage(unsigned int output_width, unsigned int output_height, OpenGL::Shader *const shader); void perform_output_stage(unsigned int output_width, unsigned int output_height, OpenGL::Shader *const shader);
void set_timing_uniforms();
public: public:
OpenGLOutputBuilder(unsigned int buffer_depth); OpenGLOutputBuilder(unsigned int buffer_depth);
@ -207,16 +208,7 @@ class OpenGLOutputBuilder {
void set_composite_sampling_function(const char *shader); void set_composite_sampling_function(const char *shader);
void set_rgb_sampling_function(const char *shader); void set_rgb_sampling_function(const char *shader);
void set_output_device(OutputDevice output_device); void set_output_device(OutputDevice output_device);
inline void set_timing(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider) void set_timing(unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider);
{
_cycles_per_line = cycles_per_line;
_height_of_display = height_of_display;
_horizontal_scan_period = horizontal_scan_period;
_vertical_scan_period = vertical_scan_period;
_vertical_period_divider = vertical_period_divider;
// TODO: update related uniforms
}
uint8_t *_input_texture_data; uint8_t *_input_texture_data;
GLuint _input_texture_array; GLuint _input_texture_array;