1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-12 15:31:09 +00:00

Merge pull request #550 from TomHarte/ElectronCorruption

Resolves potential Electron output errors
This commit is contained in:
Thomas Harte 2018-09-12 21:04:20 -04:00 committed by GitHub
commit 3b70dbfebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 77 additions and 165 deletions

View File

@ -69,7 +69,7 @@ template <class BusHandler> class MOS6560 {
speaker_(audio_generator_)
{
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);"

View File

@ -92,7 +92,7 @@ TMS9918::TMS9918(Personality p) {
// Unimaginatively, this class just passes RGB through to the shader. Investigation is needed
// into whether there's a more natural form.
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);"
"}");

View File

@ -327,7 +327,7 @@ class CRTCBusHandler {
void setup_output(float aspect_ratio) {
crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::CRT::DisplayType::PAL50, 1));
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;"
"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
// accepts any non-zero value as being fully on, zero being fully off.
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);"
"}");

View File

@ -124,7 +124,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) {
if(output_mode == OutputMode::NTSC) {
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 y = c & 14u;"
@ -136,7 +136,7 @@ void TIA::set_output_mode(Atari2600::TIA::OutputMode output_mode) {
display_type = Outputs::CRT::DisplayType::NTSC60;
} else {
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 y = c & 14u;"

View File

@ -34,13 +34,6 @@ namespace {
static const int real_time_clock_interrupt_2 = 56704;
static const int display_end_interrupt_1 = (first_graphics_line + display_end_interrupt_line)*cycles_per_line;
static const int display_end_interrupt_2 = (first_graphics_line + field_divider_line + display_end_interrupt_line)*cycles_per_line;
struct FourBPPBookender: public Outputs::CRT::TextureBuilder::Bookender {
void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) {
*left_bookend = static_cast<uint8_t>(((*left_value) & 0x0f) | (((*left_value) & 0x0f) << 4));
*right_bookend = static_cast<uint8_t>(((*right_value) & 0xf0) | (((*right_value) & 0xf0) >> 4));
}
};
}
// MARK: - Lifecycle
@ -52,15 +45,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_->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;"
"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.
crt_->set_visible_area(crt_->get_rect_for_area(first_graphics_line - 1, 256, (first_graphics_cycle+1) * crt_cycles_multiplier, 80 * crt_cycles_multiplier, 4.0f / 3.0f));
}
@ -113,9 +102,9 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
} else {
unsigned int divider = 1;
switch(screen_mode_) {
case 0: case 3: divider = 2; break;
case 1: case 4: case 6: divider = 4; break;
case 2: case 5: divider = 8; break;
case 0: case 3: divider = 1; break;
case 1: case 4: case 6: divider = 2; break;
case 2: case 5: divider = 4; break;
}
if(!initial_output_target_ || divider != current_output_divider_) {
@ -124,7 +113,7 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
crt_->output_data(data_length * current_output_divider_, data_length);
}
current_output_divider_ = divider;
initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 4);
initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 8 / divider);
}
#define get_pixel() \
@ -139,8 +128,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
if(initial_output_target_) {
while(number_of_cycles--) {
get_pixel();
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.eighty1bpp[last_pixel_byte_];
current_output_target_ += 4;
*reinterpret_cast<uint64_t *>(current_output_target_) = palette_tables_.eighty1bpp[last_pixel_byte_];
current_output_target_ += 8;
current_pixel_column_++;
}
} else current_output_target_ += 4*number_of_cycles;
@ -150,8 +139,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
if(initial_output_target_) {
while(number_of_cycles--) {
get_pixel();
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.eighty2bpp[last_pixel_byte_];
current_output_target_ += 2;
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.eighty2bpp[last_pixel_byte_];
current_output_target_ += 4;
current_pixel_column_++;
}
} else current_output_target_ += 2*number_of_cycles;
@ -161,8 +150,8 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
if(initial_output_target_) {
while(number_of_cycles--) {
get_pixel();
*current_output_target_ = palette_tables_.eighty4bpp[last_pixel_byte_];
current_output_target_ += 1;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.eighty4bpp[last_pixel_byte_];
current_output_target_ += 2;
current_pixel_column_++;
}
} else current_output_target_ += number_of_cycles;
@ -172,28 +161,28 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
if(initial_output_target_) {
if(current_pixel_column_&1) {
last_pixel_byte_ <<= 4;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 2;
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 4;
number_of_cycles--;
current_pixel_column_++;
}
while(number_of_cycles > 1) {
get_pixel();
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 2;
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 4;
last_pixel_byte_ <<= 4;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 2;
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 4;
number_of_cycles -= 2;
current_pixel_column_+=2;
}
if(number_of_cycles) {
get_pixel();
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 2;
*reinterpret_cast<uint32_t *>(current_output_target_) = palette_tables_.forty1bpp[last_pixel_byte_];
current_output_target_ += 4;
current_pixel_column_++;
}
} else current_output_target_ += 2 * number_of_cycles;
@ -203,28 +192,28 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
if(initial_output_target_) {
if(current_pixel_column_&1) {
last_pixel_byte_ <<= 2;
*current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 1;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 2;
number_of_cycles--;
current_pixel_column_++;
}
while(number_of_cycles > 1) {
get_pixel();
*current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 1;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 2;
last_pixel_byte_ <<= 2;
*current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 1;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 2;
number_of_cycles -= 2;
current_pixel_column_+=2;
}
if(number_of_cycles) {
get_pixel();
*current_output_target_ = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 1;
*reinterpret_cast<uint16_t *>(current_output_target_) = palette_tables_.forty2bpp[last_pixel_byte_];
current_output_target_ += 2;
current_pixel_column_++;
}
} else current_output_target_ += number_of_cycles;
@ -310,27 +299,37 @@ void VideoOutput::set_register(int address, uint8_t value) {
}
// regenerate all palette tables for now
#define pack(a, b) static_cast<uint8_t>((a << 4) | (b))
for(int byte = 0; byte < 256; byte++) {
uint8_t *target = reinterpret_cast<uint8_t *>(&palette_tables_.forty1bpp[byte]);
target[0] = pack(palette_[(byte&0x80) >> 4], palette_[(byte&0x40) >> 3]);
target[1] = pack(palette_[(byte&0x20) >> 2], palette_[(byte&0x10) >> 1]);
target[0] = palette_[(byte&0x80) >> 4];
target[1] = palette_[(byte&0x40) >> 3];
target[2] = palette_[(byte&0x20) >> 2];
target[3] = palette_[(byte&0x10) >> 1];
target = reinterpret_cast<uint8_t *>(&palette_tables_.eighty2bpp[byte]);
target[0] = pack(palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)], palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]);
target[1] = pack(palette_[((byte&0x20) >> 2) | ((byte&0x02) >> 0)], palette_[((byte&0x10) >> 1) | ((byte&0x01) << 1)]);
target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)];
target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)];
target[2] = palette_[((byte&0x20) >> 2) | ((byte&0x02) >> 0)];
target[3] = palette_[((byte&0x10) >> 1) | ((byte&0x01) << 1)];
target = reinterpret_cast<uint8_t *>(&palette_tables_.eighty1bpp[byte]);
target[0] = pack(palette_[(byte&0x80) >> 4], palette_[(byte&0x40) >> 3]);
target[1] = pack(palette_[(byte&0x20) >> 2], palette_[(byte&0x10) >> 1]);
target[2] = pack(palette_[(byte&0x08) >> 0], palette_[(byte&0x04) << 1]);
target[3] = pack(palette_[(byte&0x02) << 2], palette_[(byte&0x01) << 3]);
target[0] = palette_[(byte&0x80) >> 4];
target[1] = palette_[(byte&0x40) >> 3];
target[2] = palette_[(byte&0x20) >> 2];
target[3] = palette_[(byte&0x10) >> 1];
target[4] = palette_[(byte&0x08) >> 0];
target[5] = palette_[(byte&0x04) << 1];
target[6] = palette_[(byte&0x02) << 2];
target[7] = palette_[(byte&0x01) << 3];
palette_tables_.forty2bpp[byte] = pack( palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)], palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)]);
palette_tables_.eighty4bpp[byte] = pack( palette_[((byte&0x80) >> 4) | ((byte&0x20) >> 3) | ((byte&0x08) >> 2) | ((byte&0x02) >> 1)],
palette_[((byte&0x40) >> 3) | ((byte&0x10) >> 2) | ((byte&0x04) >> 1) | ((byte&0x01) >> 0)]);
target = reinterpret_cast<uint8_t *>(&palette_tables_.forty2bpp[byte]);
target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x08) >> 2)];
target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x04) >> 1)];
target = reinterpret_cast<uint8_t *>(&palette_tables_.eighty4bpp[byte]);
target[0] = palette_[((byte&0x80) >> 4) | ((byte&0x20) >> 3) | ((byte&0x08) >> 2) | ((byte&0x02) >> 1)];
target[1] = palette_[((byte&0x40) >> 3) | ((byte&0x10) >> 2) | ((byte&0x04) >> 1) | ((byte&0x01) >> 0)];
}
#undef pack
}
break;
}

View File

@ -90,11 +90,11 @@ class VideoOutput {
uint8_t *ram_;
struct {
uint16_t forty1bpp[256];
uint8_t forty2bpp[256];
uint32_t eighty1bpp[256];
uint16_t eighty2bpp[256];
uint8_t eighty4bpp[256];
uint32_t forty1bpp[256];
uint16_t forty2bpp[256];
uint64_t eighty1bpp[256];
uint32_t eighty2bpp[256];
uint16_t eighty4bpp[256];
} palette_tables_;
// Display generation.

View File

@ -25,13 +25,13 @@ VideoOutput::VideoOutput(uint8_t *memory) :
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
counter_period_(PAL50Period) {
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;"
"return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));"
"}");
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 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,
// or it is non-zero, which is white.
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;"
"}");

View File

@ -280,7 +280,7 @@ class CRT {
/*! 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
`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
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 {
/// The composite function provides continuous output.
Continuous,
@ -362,10 +346,6 @@ class CRT {
});
}
inline void set_bookender(std::unique_ptr<TextureBuilder::Bookender> bookender) {
openGL_output_builder_.texture_builder.set_bookender(std::move(bookender));
}
inline void set_video_signal(VideoSignal video_signal) {
enqueue_openGL_function([video_signal, this] {
openGL_output_builder_.set_video_signal(video_signal);

View File

@ -524,12 +524,4 @@ 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

@ -105,8 +105,6 @@ class OpenGLOutputBuilder {
float get_composite_output_width() const;
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;
// 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
@ -174,7 +172,6 @@ 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,11 +46,9 @@ 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];"
"out vec2 iInputPositionVarying;"
"out vec2 delayLinePositionVarying;"
"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 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));"
"iInputPositionVarying = extendedInputPosition * iCoordinateMultiplier;"
"vec2 mappedInputPosition = extendedInputPosition / textureSize;"
// 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"
"in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;"
"out vec4 fragColour;"
@ -132,18 +128,18 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_sh
if(!svideo_shader.empty()) {
fragment_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));"
"}";
} else {
fragment_shader <<
rgb_shader <<
"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;"
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(abs(amplitude), amplitude);"
"return dot(lumaChromaColour, vec3(1.0 - abs(amplitude), quadrature));"
@ -154,7 +150,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_composite_source_sh
fragment_shader <<
"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);
@ -166,7 +162,6 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shade
"#version 150\n"
"in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;"
"out vec3 fragColour;"
@ -178,9 +173,9 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_svideo_source_shade
fragment_shader
<< rgb_shader <<
"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;"
"vec2 quadrature = vec2(cos(phase), sin(phase)) * vec2(1.0, sign(amplitude));"
"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 <<
"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;"
"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"
"in vec2 inputPositionsVarying[11];"
"in vec2 iInputPositionVarying;"
"in vec3 phaseAndAmplitudeVarying;"
"out vec3 fragColour;"
@ -215,7 +209,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_rgb_source_shader(c
"void main(void)"
"{"
"fragColour = rgb_sample(texID, inputPositionsVarying[5], iInputPositionVarying);"
"fragColour = rgb_sample(texID, inputPositionsVarying[5]);"
"}";
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("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);
/*!
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);
};

View File

@ -36,19 +36,6 @@ const GLenum formatForDepth(std::size_t depth) {
}
}
struct DefaultBookender: public TextureBuilder::Bookender {
public:
DefaultBookender(std::size_t bytes_per_pixel) : bytes_per_pixel_(bytes_per_pixel) {}
void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) {
std::memcpy(left_bookend, left_value, bytes_per_pixel_);
std::memcpy(right_bookend, right_value, bytes_per_pixel_);
}
private:
std::size_t bytes_per_pixel_;
};
}
TextureBuilder::TextureBuilder(std::size_t bytes_per_pixel, GLenum texture_unit) :
@ -58,8 +45,6 @@ TextureBuilder::TextureBuilder(std::size_t bytes_per_pixel, GLenum texture_unit)
bind();
glTexImage2D(GL_TEXTURE_2D, 0, internalFormatForDepth(bytes_per_pixel), InputBufferBuilderWidth, InputBufferBuilderHeight, 0, formatForDepth(bytes_per_pixel), GL_UNSIGNED_BYTE, nullptr);
set_bookender(nullptr);
}
TextureBuilder::~TextureBuilder() {
@ -119,17 +104,9 @@ void TextureBuilder::reduce_previous_allocation_to(std::size_t actual_length) {
// Bookend the allocation with duplicates of the first and last pixel, to protect
// against rounding errors when this run is drawn.
// TODO: allow somebody else to specify the rule for generating a left-padding value and
// a right-padding value.
uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y) - bytes_per_pixel_;
bookender_->add_bookends(&start_pointer[bytes_per_pixel_], &start_pointer[actual_length * bytes_per_pixel_], start_pointer, &start_pointer[(actual_length + 1) * bytes_per_pixel_]);
}
void TextureBuilder::set_bookender(std::unique_ptr<TextureBuilder::Bookender> bookender) {
bookender_ = std::move(bookender);
if(!bookender_) {
bookender_.reset(new DefaultBookender(bytes_per_pixel_));
}
std::memcpy(start_pointer, &start_pointer[bytes_per_pixel_], bytes_per_pixel_);
std::memcpy(&start_pointer[(actual_length + 1) * bytes_per_pixel_], &start_pointer[actual_length * bytes_per_pixel_], bytes_per_pixel_);
}
bool TextureBuilder::retain_latest() {

View File

@ -98,22 +98,6 @@ class TextureBuilder {
/// allocated, indicating their final resting locations and their lengths.
void flush(const std::function<void(const std::vector<WriteArea> &write_areas, std::size_t count)> &);
/// A Bookender helps to paper over precision errors when rendering; its job is to provide single-sample
/// extensions that duplicate the left and right edges of a written area. By default the texture builder will
/// simply copy the appropriate number of bytes per pixel, but if the client is using a packed pixel format
/// then that may be incorrect, e.g. if each sample is a byte but contains two pixels, each in a single nibble,
/// then the correct duplication might be a byte composed of copies of the two top nibbles as the left bookend,
/// and one composed of copies of the two bottom nibbles on the right.
struct Bookender {
/// Writes to left_bookend the sample that should appear as a continuation before the left_value;
/// writes to right_bookend the sample that should appear as a continuation after right_value.
virtual void add_bookends(uint8_t *const left_value, uint8_t *const right_value, uint8_t *left_bookend, uint8_t *right_bookend) = 0;
};
/// Sets the current bookender. The bookender be called synchronously within the builder-writing thread.
/// Supply nullptr to engage the default bookender.
void set_bookender(std::unique_ptr<Bookender> bookender);
/// Binds this texture to the unit supplied at instantiation.
void bind();
@ -140,8 +124,6 @@ class TextureBuilder {
// Caveat: reset to the origin upon a submit. So used in comparison by flush to
// determine whether the current batch of write areas needs to be relocated.
uint16_t write_areas_start_x_ = 0, write_areas_start_y_ = 0;
std::unique_ptr<Bookender> bookender_;
};
}