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:
parent
a167e3849b
commit
6547560e52
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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] {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user