1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 18:30:21 +00:00

Eliminates the concept of an iCoordinate.

Real-life precision appears not to support the idea of sub-sample pixel storage.
This commit is contained in:
Thomas Harte 2018-09-12 20:05:39 -04:00
parent c6e94bc2a6
commit a38639d099
13 changed files with 21 additions and 65 deletions

View File

@ -69,7 +69,7 @@ template <class BusHandler> class MOS6560 {
speaker_(audio_generator_) speaker_(audio_generator_)
{ {
crt_->set_svideo_sampling_function( crt_->set_svideo_sampling_function(
"vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"vec2 yc = texture(texID, coordinate).rg / vec2(255.0);" "vec2 yc = texture(texID, coordinate).rg / vec2(255.0);"

View File

@ -92,7 +92,7 @@ TMS9918::TMS9918(Personality p) {
// Unimaginatively, this class just passes RGB through to the shader. Investigation is needed // Unimaginatively, this class just passes RGB through to the shader. Investigation is needed
// into whether there's a more natural form. // into whether there's a more natural form.
crt_->set_rgb_sampling_function( crt_->set_rgb_sampling_function(
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
"{" "{"
"return texture(sampler, coordinate).rgb / vec3(255.0);" "return texture(sampler, coordinate).rgb / vec3(255.0);"
"}"); "}");

View File

@ -327,7 +327,7 @@ class CRTCBusHandler {
void setup_output(float aspect_ratio) { void setup_output(float aspect_ratio) {
crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::CRT::DisplayType::PAL50, 1)); crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::CRT::DisplayType::PAL50, 1));
crt_->set_rgb_sampling_function( crt_->set_rgb_sampling_function(
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
"{" "{"
"uint sample = texture(texID, coordinate).r;" "uint sample = texture(texID, coordinate).r;"
"return vec3(float((sample >> 4) & 3u), float((sample >> 2) & 3u), float(sample & 3u)) / 2.0;" "return vec3(float((sample >> 4) & 3u), float((sample >> 2) & 3u), float(sample & 3u)) / 2.0;"

View File

@ -18,7 +18,7 @@ VideoBase::VideoBase(bool is_iie, std::function<void(Cycles)> &&target) :
// Set a composite sampling function that assumes one byte per pixel input, and // Set a composite sampling function that assumes one byte per pixel input, and
// accepts any non-zero value as being fully on, zero being fully off. // accepts any non-zero value as being fully on, zero being fully off.
crt_->set_composite_sampling_function( crt_->set_composite_sampling_function(
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"return clamp(texture(sampler, coordinate).r, 0.0, 1.0);" "return clamp(texture(sampler, coordinate).r, 0.0, 1.0);"
"}"); "}");

View File

@ -124,7 +124,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) {
if(output_mode == OutputMode::NTSC) { if(output_mode == OutputMode::NTSC) {
crt_->set_svideo_sampling_function( crt_->set_svideo_sampling_function(
"vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"uint c = texture(texID, coordinate).r;" "uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;" "uint y = c & 14u;"
@ -136,7 +136,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) {
display_type = Outputs::CRT::DisplayType::NTSC60; display_type = Outputs::CRT::DisplayType::NTSC60;
} else { } else {
crt_->set_svideo_sampling_function( crt_->set_svideo_sampling_function(
"vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"uint c = texture(texID, coordinate).r;" "uint c = texture(texID, coordinate).r;"
"uint y = c & 14u;" "uint y = c & 14u;"

View File

@ -52,13 +52,11 @@ VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory) {
crt_.reset(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1)); crt_.reset(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::CRT::DisplayType::PAL50, 1));
crt_->set_rgb_sampling_function( crt_->set_rgb_sampling_function(
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
"{" "{"
"uint texValue = texture(sampler, coordinate).r;" "uint texValue = texture(sampler, coordinate).r;"
"texValue >>= 4 - (int(icoordinate.x) & 4);"
"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
"}"); "}");
crt_->set_integer_coordinate_multiplier(8.0f);
std::unique_ptr<Outputs::CRT::TextureBuilder::Bookender> bookender(new FourBPPBookender); std::unique_ptr<Outputs::CRT::TextureBuilder::Bookender> bookender(new FourBPPBookender);
crt_->set_bookender(std::move(bookender)); crt_->set_bookender(std::move(bookender));
// TODO: as implied below, I've introduced a clock's latency into the graphics pipeline somehow. Investigate. // TODO: as implied below, I've introduced a clock's latency into the graphics pipeline somehow. Investigate.

View File

@ -25,13 +25,13 @@ VideoOutput::VideoOutput(uint8_t *memory) :
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition), v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
counter_period_(PAL50Period) { counter_period_(PAL50Period) {
crt_->set_rgb_sampling_function( crt_->set_rgb_sampling_function(
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
"{" "{"
"uint texValue = texture(sampler, coordinate).r;" "uint texValue = texture(sampler, coordinate).r;"
"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
"}"); "}");
crt_->set_composite_sampling_function( crt_->set_composite_sampling_function(
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"uint texValue = uint(dot(texture(sampler, coordinate).rg, uvec2(1, 256)));" "uint texValue = uint(dot(texture(sampler, coordinate).rg, uvec2(1, 256)));"
"uint iPhase = uint((phase + 3.141592654 + 0.39269908175) * 2.0 / 3.141592654) & 3u;" "uint iPhase = uint((phase + 3.141592654 + 0.39269908175) * 2.0 / 3.141592654) & 3u;"

View File

@ -26,7 +26,7 @@ Video::Video() :
// Set a composite sampling function that assumes two-level input; either a byte is 0, which is black, // Set a composite sampling function that assumes two-level input; either a byte is 0, which is black,
// or it is non-zero, which is white. // or it is non-zero, which is white.
crt_->set_composite_sampling_function( crt_->set_composite_sampling_function(
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" "float composite_sample(usampler2D sampler, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"return texture(sampler, coordinate).r;" "return texture(sampler, coordinate).r;"
"}"); "}");

View File

@ -280,7 +280,7 @@ class CRT {
/*! Sets a function that will map from whatever data the machine provided to a composite signal. /*! Sets a function that will map from whatever data the machine provided to a composite signal.
@param shader A GLSL fragment including a function with the signature @param shader A GLSL fragment including a function with the signature
`float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)` `float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)`
that evaluates to the composite signal level as a function of a source buffer, sampling location, colour that evaluates to the composite signal level as a function of a source buffer, sampling location, colour
carrier phase and amplitude. carrier phase and amplitude.
*/ */
@ -290,22 +290,6 @@ class CRT {
}); });
} }
/*!
Sets a multiplier applied to iCoordinate values prior to their passing to the various sampling functions.
This multiplier is applied outside of the interpolation loop, making for a more precise interpolation
than if it were applied within the sampling function.
Idiomatically, this is likely to be the number of output pixels packed into each input sample where
packing is in use.
The default value is 1.0.
*/
inline void set_integer_coordinate_multiplier(float multiplier) {
enqueue_openGL_function([=] {
openGL_output_builder_.set_integer_coordinate_multiplier(multiplier);
});
}
enum CompositeSourceType { enum CompositeSourceType {
/// The composite function provides continuous output. /// The composite function provides continuous output.
Continuous, Continuous,

View File

@ -524,12 +524,4 @@ void OpenGLOutputBuilder::set_timing_uniforms() {
if(rgb_input_shader_program_) { if(rgb_input_shader_program_) {
rgb_input_shader_program_->set_width_scalers(1.0f, 1.0f); rgb_input_shader_program_->set_width_scalers(1.0f, 1.0f);
} }
set_integer_coordinate_multiplier(integer_coordinate_multiplier_);
}
void OpenGLOutputBuilder::set_integer_coordinate_multiplier(float multiplier) {
integer_coordinate_multiplier_ = multiplier;
if(composite_input_shader_program_) composite_input_shader_program_->set_integer_coordinate_multiplier(multiplier);
if(svideo_input_shader_program_) svideo_input_shader_program_->set_integer_coordinate_multiplier(multiplier);
if(rgb_input_shader_program_) rgb_input_shader_program_->set_integer_coordinate_multiplier(multiplier);
} }

View File

@ -105,8 +105,6 @@ class OpenGLOutputBuilder {
float get_composite_output_width() const; float get_composite_output_width() const;
void set_output_shader_width(); void set_output_shader_width();
float integer_coordinate_multiplier_ = 1.0f;
// Maintain a couple of rectangles for masking off the extreme edge of the display; // Maintain a couple of rectangles for masking off the extreme edge of the display;
// this is a bit of a cheat: there's some tolerance in when a sync pulse will be // this is a bit of a cheat: there's some tolerance in when a sync pulse will be
// generated. So it might be slightly later than expected. Which might cause a scan // generated. So it might be slightly later than expected. Which might cause a scan
@ -174,7 +172,6 @@ class OpenGLOutputBuilder {
void set_rgb_sampling_function(const std::string &); void set_rgb_sampling_function(const std::string &);
void set_video_signal(VideoSignal); void set_video_signal(VideoSignal);
void set_timing(unsigned int input_frequency, 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 input_frequency, 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_integer_coordinate_multiplier(float multiplier);
}; };
} }

View File

@ -46,11 +46,9 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::s
"uniform float inputVerticalOffset;" "uniform float inputVerticalOffset;"
"uniform float outputVerticalOffset;" "uniform float outputVerticalOffset;"
"uniform float textureHeightDivisor;" "uniform float textureHeightDivisor;"
"uniform float iCoordinateMultiplier;"
"out vec3 phaseAndAmplitudeVarying;" "out vec3 phaseAndAmplitudeVarying;"
"out vec2 inputPositionsVarying[11];" "out vec2 inputPositionsVarying[11];"
"out vec2 iInputPositionVarying;"
"out vec2 delayLinePositionVarying;" "out vec2 delayLinePositionVarying;"
"void main(void)" "void main(void)"
@ -75,9 +73,8 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::s
"vec2 extendedInputPosition = " << (input_is_inputPosition ? "inputPosition" : "outputPosition") << " + extensionVector;" "vec2 extendedInputPosition = " << (input_is_inputPosition ? "inputPosition" : "outputPosition") << " + extensionVector;"
"vec2 extendedOutputPosition = outputPosition + extensionVector;" "vec2 extendedOutputPosition = outputPosition + extensionVector;"
// keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range // scale mappedInputPosition to the ordinary normalised range
"vec2 textureSize = vec2(textureSize(texID, 0));" "vec2 textureSize = vec2(textureSize(texID, 0));"
"iInputPositionVarying = extendedInputPosition * iCoordinateMultiplier;"
"vec2 mappedInputPosition = extendedInputPosition / textureSize;" "vec2 mappedInputPosition = extendedInputPosition / textureSize;"
// setup input positions spaced as per the supplied offsets; these are for filtering where required // setup input positions spaced as per the supplied offsets; these are for filtering where required
@ -120,7 +117,6 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_sh
"#version 150\n" "#version 150\n"
"in vec2 inputPositionsVarying[11];" "in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;" "in vec3 phaseAndAmplitudeVarying;"
"out vec4 fragColour;" "out vec4 fragColour;"
@ -132,18 +128,18 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_sh
if(!svideo_shader.empty()) { if(!svideo_shader.empty()) {
fragment_shader << fragment_shader <<
svideo_shader << svideo_shader <<
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"vec2 svideoColour = svideo_sample(texID, coordinate, iCoordinate, phase, amplitude);" "vec2 svideoColour = svideo_sample(texID, coordinate, phase, amplitude);"
"return mix(svideoColour.x, svideoColour.y, abs(amplitude));" "return mix(svideoColour.x, svideoColour.y, abs(amplitude));"
"}"; "}";
} else { } else {
fragment_shader << fragment_shader <<
rgb_shader << rgb_shader <<
"uniform mat3 rgbToLumaChroma;" "uniform mat3 rgbToLumaChroma;"
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "float composite_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"vec3 rgbColour = clamp(rgb_sample(texID, coordinate, iCoordinate), vec3(0.0), vec3(1.0));" "vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));"
"vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;" "vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;"
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(abs(amplitude), amplitude);" "vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(abs(amplitude), amplitude);"
"return dot(lumaChromaColour, vec3(1.0 - abs(amplitude), quadrature));" "return dot(lumaChromaColour, vec3(1.0 - abs(amplitude), quadrature));"
@ -154,7 +150,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_sh
fragment_shader << fragment_shader <<
"void main(void)" "void main(void)"
"{" "{"
"fragColour = vec4(composite_sample(texID, inputPositionsVarying[5], iInputPositionVarying, phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y));" "fragColour = vec4(composite_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y));"
"}"; "}";
return make_shader(fragment_shader.str(), true, true); return make_shader(fragment_shader.str(), true, true);
@ -166,7 +162,6 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shade
"#version 150\n" "#version 150\n"
"in vec2 inputPositionsVarying[11];" "in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;" "in vec3 phaseAndAmplitudeVarying;"
"out vec3 fragColour;" "out vec3 fragColour;"
@ -178,9 +173,9 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shade
fragment_shader fragment_shader
<< rgb_shader << << rgb_shader <<
"uniform mat3 rgbToLumaChroma;" "uniform mat3 rgbToLumaChroma;"
"vec2 svideo_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "vec2 svideo_sample(usampler2D texID, vec2 coordinate, float phase, float amplitude)"
"{" "{"
"vec3 rgbColour = clamp(rgb_sample(texID, coordinate, iCoordinate), vec3(0.0), vec3(1.0));" "vec3 rgbColour = clamp(rgb_sample(texID, coordinate), vec3(0.0), vec3(1.0));"
"vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;" "vec3 lumaChromaColour = rgbToLumaChroma * rgbColour;"
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(1.0, sign(amplitude));" "vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(1.0, sign(amplitude));"
"return vec2(lumaChromaColour.x, 0.5 + dot(quadrature, lumaChromaColour.yz) * 0.5);" "return vec2(lumaChromaColour.x, 0.5 + dot(quadrature, lumaChromaColour.yz) * 0.5);"
@ -190,7 +185,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shade
fragment_shader << fragment_shader <<
"void main(void)" "void main(void)"
"{" "{"
"vec2 sample = svideo_sample(texID, inputPositionsVarying[5], iInputPositionVarying, phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y);" "vec2 sample = svideo_sample(texID, inputPositionsVarying[5], phaseAndAmplitudeVarying.x, phaseAndAmplitudeVarying.y);"
"vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), sin(phaseAndAmplitudeVarying.x)) * vec2(1.0, sign(phaseAndAmplitudeVarying.y)) * 0.5 * phaseAndAmplitudeVarying.z;" "vec2 quadrature = vec2(cos(phaseAndAmplitudeVarying.x), sin(phaseAndAmplitudeVarying.x)) * vec2(1.0, sign(phaseAndAmplitudeVarying.y)) * 0.5 * phaseAndAmplitudeVarying.z;"
"fragColour = vec3(sample.x, vec2(0.5) + (sample.y * quadrature));" "fragColour = vec3(sample.x, vec2(0.5) + (sample.y * quadrature));"
"}"; "}";
@ -204,7 +199,6 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_rgb_source_shader(c
"#version 150\n" "#version 150\n"
"in vec2 inputPositionsVarying[11];" "in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;" "in vec3 phaseAndAmplitudeVarying;"
"out vec3 fragColour;" "out vec3 fragColour;"
@ -215,7 +209,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_rgb_source_shader(c
"void main(void)" "void main(void)"
"{" "{"
"fragColour = rgb_sample(texID, inputPositionsVarying[5], iInputPositionVarying);" "fragColour = rgb_sample(texID, inputPositionsVarying[5]);"
"}"; "}";
return make_shader(fragment_shader.str(), true, true); return make_shader(fragment_shader.str(), true, true);
@ -439,7 +433,3 @@ void IntermediateShader::set_is_double_height(bool is_double_height, float input
set_uniform("inputVerticalOffset", input_offset); set_uniform("inputVerticalOffset", input_offset);
set_uniform("outputVerticalOffset", output_offset); set_uniform("outputVerticalOffset", output_offset);
} }
void IntermediateShader::set_integer_coordinate_multiplier(float multiplier) {
set_uniform("iCoordinateMultiplier", multiplier);
}

View File

@ -135,11 +135,6 @@ public:
*/ */
void set_is_double_height(bool is_double_height, float input_offset = 0.0f, float output_offset = 0.0f); void set_is_double_height(bool is_double_height, float input_offset = 0.0f, float output_offset = 0.0f);
/*!
Sets the multiplier applied in the vertex shader to iCoordinates.
*/
void set_integer_coordinate_multiplier(float);
private: private:
static std::unique_ptr<IntermediateShader> make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition); static std::unique_ptr<IntermediateShader> make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition);
}; };