1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Gives the CRT the ability to move iCoordinate multiplication outside of the fragment loop.

That resolves precision issues, as were plaguing the Apple II.
This commit is contained in:
Thomas Harte 2018-04-18 19:29:03 -04:00
parent a167e3849b
commit 6547560e52
8 changed files with 47 additions and 9 deletions

View File

@ -28,11 +28,10 @@ VideoBase::VideoBase() :
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)"
"{"
"uint texValue = texture(sampler, coordinate).r;"
"texValue <<= uint(icoordinate.x * 7.0) % 7u;"
"texValue <<= int(icoordinate.x) % 7;"
"return float(texValue & 64u);"
"}");
// TODO: the above has precision issues. Fix!
crt_->set_integer_coordinate_multiplier(7.0f);
// Show only the centre 75% of the TV frame.
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);

View File

@ -55,9 +55,10 @@ VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory) {
"vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)"
"{"
"uint texValue = texture(sampler, coordinate).r;"
"texValue >>= 4 - (int(icoordinate.x * 8) & 4);"
"texValue >>= 4 - (int(icoordinate.x) & 4);"
"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);
crt_->set_bookender(std::move(bookender));
// TODO: as implied below, I've introduced a clock's latency into the graphics pipeline somehow. Investigate.

View File

@ -31,9 +31,10 @@ Video::Video() :
"float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)"
"{"
"uint texValue = texture(sampler, coordinate).r;"
"texValue <<= int(icoordinate.x * 8) & 7;"
"texValue <<= int(icoordinate.x) & 7;"
"return float(texValue & 128u);"
"}");
crt_->set_integer_coordinate_multiplier(8.0f);
// Show only the centre 80% of the TV frame.
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);

View File

@ -290,6 +290,22 @@ 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 {
/// The composite function provides continuous output.
Continuous,
@ -333,12 +349,12 @@ class CRT {
output mode will be applied.
@param shader A GLSL fragent including a function with the signature
`vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)` that evaluates to an RGB colour
`vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 iCoordinate)` that evaluates to an RGB colour
as a function of:
* `usampler2D sampler` representing the source buffer;
* `vec2 coordinate` representing the source buffer location to sample from in the range [0, 1); and
* `vec2 icoordinate` representing the source buffer location to sample from as a pixel count, for easier multiple-pixels-per-byte unpacking.
* `vec2 iCoordinate` representing the source buffer location to sample from as a pixel count, for easier multiple-pixels-per-byte unpacking.
*/
inline void set_rgb_sampling_function(const std::string &shader) {
enqueue_openGL_function([shader, this] {

View File

@ -514,4 +514,12 @@ void OpenGLOutputBuilder::set_timing_uniforms() {
if(rgb_input_shader_program_) {
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

@ -104,6 +104,8 @@ class OpenGLOutputBuilder {
float get_composite_output_width() const;
void set_output_shader_width();
float integer_coordinate_multiplier_ = 1.0f;
public:
// These two are protected by output_mutex_.
TextureBuilder texture_builder;
@ -158,6 +160,7 @@ class OpenGLOutputBuilder {
void set_rgb_sampling_function(const std::string &);
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_integer_coordinate_multiplier(float multiplier);
};
}

View File

@ -46,6 +46,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::s
"uniform float inputVerticalOffset;"
"uniform float outputVerticalOffset;"
"uniform float textureHeightDivisor;"
"uniform float iCoordinateMultiplier;"
"out vec3 phaseAndAmplitudeVarying;"
"out vec2 inputPositionsVarying[11];"
@ -76,8 +77,8 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::s
// keep iInputPositionVarying in whole source pixels, scale mappedInputPosition to the ordinary normalised range
"vec2 textureSize = vec2(textureSize(texID, 0));"
"iInputPositionVarying = extendedInputPosition;"
"vec2 mappedInputPosition = extendedInputPosition / textureSize;" // + vec2(0.0, 0.5)
"iInputPositionVarying = extendedInputPosition * iCoordinateMultiplier;"
"vec2 mappedInputPosition = extendedInputPosition / textureSize;"
// setup input positions spaced as per the supplied offsets; these are for filtering where required
"inputPositionsVarying[0] = mappedInputPosition - (vec2(5.0, 0.0) / textureSize);"
@ -434,3 +435,7 @@ void IntermediateShader::set_is_double_height(bool is_double_height, float input
set_uniform("inputVerticalOffset", input_offset);
set_uniform("outputVerticalOffset", output_offset);
}
void IntermediateShader::set_integer_coordinate_multiplier(float multiplier) {
set_uniform("iCoordinateMultiplier", multiplier);
}

View File

@ -135,6 +135,11 @@ public:
*/
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:
static std::unique_ptr<IntermediateShader> make_shader(const std::string &fragment_shader, bool use_usampler, bool input_is_inputPosition);
};