1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-26 09:29:45 +00:00

Possibly adds enough for the Electron and ZX80 to start outputting dummy lines.

Let's see!
This commit is contained in:
Thomas Harte 2018-11-03 23:40:39 -04:00
parent b40211d2c0
commit f6562de325
16 changed files with 97 additions and 64 deletions

View File

@ -64,7 +64,7 @@ template <class BusHandler> class MOS6560 {
public:
MOS6560(BusHandler &bus_handler) :
bus_handler_(bus_handler),
crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::Display::Type::NTSC60, 2)),
// crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::Display::Type::NTSC60, 2)),
audio_generator_(audio_queue_),
speaker_(audio_generator_)
{

View File

@ -49,8 +49,9 @@ struct ReverseTable {
}
Base::Base(Personality p) :
personality_(p),
crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4)) {
personality_(p)//,
// crt_(new Outputs::CRT::CRT(CRTCyclesPerLine, CRTCyclesDivider, Outputs::Display::Type::NTSC60, 4))
{
switch(p) {
case TI::TMS::TMS9918A:

View File

@ -326,7 +326,7 @@ class CRTCBusHandler {
/// Constructs an appropriate CRT for video output.
void setup_output(Outputs::Display::ScanTarget *scan_target) {
crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::Display::Type::PAL50, 1));
// crt_.reset(new Outputs::CRT::CRT(1024, 16, Outputs::Display::Type::PAL50, 1));
// crt_->set_rgb_sampling_function(
// "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
// "{"

View File

@ -11,7 +11,7 @@
using namespace AppleII::Video;
VideoBase::VideoBase(bool is_iie, std::function<void(Cycles)> &&target) :
crt_(new Outputs::CRT::CRT(910, 1, Outputs::Display::Type::NTSC60, 1)),
// crt_(new Outputs::CRT::CRT(910, 1, Outputs::Display::Type::NTSC60, 1)),
is_iie_(is_iie),
deferrer_(std::move(target)) {

View File

@ -24,7 +24,7 @@ namespace {
TIA::TIA(bool create_crt) {
if(create_crt) {
crt_.reset(new Outputs::CRT::CRT(cycles_per_line * 2 - 1, 1, Outputs::Display::Type::NTSC60, 1));
// crt_.reset(new Outputs::CRT::CRT(cycles_per_line * 2 - 1, 1, Outputs::Display::Type::NTSC60, 1));
// crt_->set_video_signal(Outputs::Display::VideoSignal::Composite);
set_output_mode(OutputMode::NTSC);
}

View File

@ -374,17 +374,9 @@ class ConcreteMachine:
}
void setup_output(Outputs::Display::ScanTarget *scan_target) override final {
video_output_.reset(new VideoOutput(ram_));
video_output_.reset(new VideoOutput(ram_, scan_target));
}
// void close_output() override final {
// video_output_.reset();
// }
//
// Outputs::CRT::CRT *get_crt() override final {
// return video_output_->get_crt();
// }
Outputs::Speaker::Speaker *get_speaker() override final {
return &speaker_;
}

View File

@ -38,12 +38,18 @@ namespace {
// MARK: - Lifecycle
VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory) {
VideoOutput::VideoOutput(uint8_t *memory, Outputs::Display::ScanTarget *scan_target) : ram_(memory) {
memset(palette_, 0xf, sizeof(palette_));
setup_screen_map();
setup_base_address();
crt_.reset(new Outputs::CRT::CRT(crt_cycles_per_line, 8, Outputs::Display::Type::PAL50, 1));
crt_.reset(new Outputs::CRT::CRT(
crt_cycles_per_line,
1024,
Outputs::Display::Type::PAL50,
Outputs::Display::ScanTarget::Modals::DataType::Red1Green1Blue1,
scan_target));
// crt_->set_rgb_sampling_function(
// "vec3 rgb_sample(usampler2D sampler, vec2 coordinate)"
// "{"

View File

@ -27,10 +27,12 @@ namespace Electron {
class VideoOutput {
public:
/*!
Instantiates a VideoOutput that will read its pixels from @c memory. The pointer supplied
should be to address 0 in the unexpanded Electron's memory map.
Instantiates a VideoOutput that will read its pixels from @c memory and output video
to @c scan_target.
The pointer supplied should be to address 0 in the unexpanded Electron's memory map.
*/
VideoOutput(uint8_t *memory);
VideoOutput(uint8_t *memory, Outputs::Display::ScanTarget *scan_target);
/// @returns the CRT to which output is being painted.
Outputs::CRT::CRT *get_crt();

View File

@ -23,7 +23,7 @@ namespace {
VideoOutput::VideoOutput(uint8_t *memory) :
ram_(memory),
crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::Display::Type::PAL50, 2)),
// crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::Display::Type::PAL50, 2)),
v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition),
counter_period_(PAL50Period) {
// crt_->set_rgb_sampling_function(

View File

@ -22,8 +22,9 @@ const std::size_t StandardAllocationSize = 320;
}
Video::Video() :
crt_(new Outputs::CRT::CRT(207 * 2, 1, Outputs::Display::Type::PAL50, 1)) {
Video::Video(Outputs::Display::ScanTarget *scan_target) :
crt_(new Outputs::CRT::CRT(207 * 2, 414, Outputs::Display::Type::PAL50, Outputs::Display::ScanTarget::Modals::DataType::Luminance1, scan_target))
{
// 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.

View File

@ -27,7 +27,7 @@ namespace ZX8081 {
class Video {
public:
/// Constructs an instance of the video feed; a CRT is also created.
Video();
Video(Outputs::Display::ScanTarget *scan_target);
/// @returns The CRT this video feed is feeding.
Outputs::CRT::CRT *get_crt();

View File

@ -311,7 +311,7 @@ template<bool is_zx81> class ConcreteMachine:
}
void setup_output(Outputs::Display::ScanTarget *scan_target) override final {
video_.reset(new Video);
video_.reset(new Video(scan_target));
}
Outputs::Speaker::Speaker *get_speaker() override final {

View File

@ -29,6 +29,8 @@
#import <OpenGL/OpenGL.h>
#include <OpenGL/gl3.h>
#include "ScanTarget.hpp"
@interface CSMachine() <CSFastLoading>
- (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
- (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker;
@ -71,6 +73,27 @@ struct ActivityObserver: public Activity::Observer {
__unsafe_unretained CSMachine *machine;
};
class ScanTarget: public Outputs::Display::ScanTarget {
public:
void set_modals(Modals) {}
Scan *get_scan() {
return &scan_;
}
uint8_t *allocate_write_area(size_t required_length, size_t required_alignment) {
write_area_.resize(required_length);
return write_area_.data();
}
void submit(bool only_if_no_allocation_failures) {
}
private:
Scan scan_;
std::vector<uint8_t> write_area_;
};
@implementation CSMachine {
SpeakerDelegate _speakerDelegate;
ActivityObserver _activityObserver;
@ -83,6 +106,8 @@ struct ActivityObserver: public Activity::Observer {
CSJoystickManager *_joystickManager;
std::bitset<65536> _depressedKeys;
NSMutableArray<NSString *> *_leds;
ScanTarget _scanTarget;
}
- (instancetype)initWithAnalyser:(CSStaticAnalyser *)result {
@ -231,7 +256,7 @@ struct ActivityObserver: public Activity::Observer {
}
- (void)setupOutputWithAspectRatio:(float)aspectRatio {
// _machine->crt_machine()->setup_output(aspectRatio);
_machine->crt_machine()->setup_output(&_scanTarget);
// Since OS X v10.6, Macs have had a gamma of 2.2.
// _machine->crt_machine()->get_crt()->set_output_gamma(2.2f);

View File

@ -56,12 +56,14 @@ void CRT::set_new_timing(int cycles_per_line, int height_of_display, Outputs::Di
vertical_flywheel_.reset(new Flywheel(multiplied_cycles_per_line * height_of_display, scanlinesVerticalRetraceTime * multiplied_cycles_per_line, (multiplied_cycles_per_line * height_of_display) >> 3));
// figure out the divisor necessary to get the horizontal flywheel into a 16-bit range
const int real_clock_scan_period = (multiplied_cycles_per_line * height_of_display) / (time_multiplier_ * common_output_divisor_);
vertical_flywheel_output_divider_ = static_cast<uint16_t>(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_ * common_output_divisor_));
// const int real_clock_scan_period = (multiplied_cycles_per_line * height_of_display) / (time_multiplier_);
// vertical_flywheel_output_divider_ = static_cast<uint16_t>(ceilf(real_clock_scan_period / 65536.0f) * (time_multiplier_));
// openGL_output_builder_.set_timing(cycles_per_line, multiplied_cycles_per_line, height_of_display, horizontal_flywheel_->get_scan_period(), vertical_flywheel_->get_scan_period(), vertical_flywheel_output_divider_);
// TODO: set scan_target modals.
scan_target_modals_.expected_vertical_lines = height_of_display;
scan_target_modals_.composite_colour_space = colour_space;
scan_target_->set_modals(scan_target_modals_);
}
void CRT::set_new_display_type(int cycles_per_line, Outputs::Display::Type displayType) {
@ -91,24 +93,30 @@ void CRT::set_input_gamma(float gamma) {
// update_gamma();
}
CRT::CRT(int common_output_divisor, int buffer_depth) :
common_output_divisor_(common_output_divisor) {}
CRT::CRT( int cycles_per_line,
int common_output_divisor,
int pixel_clock_least_common_multiple,
int height_of_display,
Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator, int colour_cycle_denominator,
int vertical_sync_half_lines,
bool should_alternate,
int buffer_depth) :
CRT(common_output_divisor, buffer_depth) {
Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target;
scan_target_modals_.source_data_type = data_type;
scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple;
set_new_timing(cycles_per_line, height_of_display, colour_space, colour_cycle_numerator, colour_cycle_denominator, vertical_sync_half_lines, should_alternate);
}
CRT::CRT(int cycles_per_line, int common_output_divisor, Outputs::Display::Type displayType, int buffer_depth) :
CRT(common_output_divisor, buffer_depth) {
set_new_display_type(cycles_per_line, displayType);
CRT::CRT( int cycles_per_line,
int pixel_clock_least_common_multiple,
Outputs::Display::Type display_type,
Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target) {
scan_target_ = scan_target;
scan_target_modals_.source_data_type = data_type;
scan_target_modals_.pixel_clock_least_common_multiple = pixel_clock_least_common_multiple;
set_new_display_type(cycles_per_line, display_type);
}
// MARK: - Sync loop
@ -193,6 +201,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, bool vsync_
}
}
}
scan_target_->submit();
}
// MARK: - stream feeding methods

View File

@ -27,12 +27,9 @@ class Delegate {
class CRT {
private:
CRT(int common_output_divisor, int buffer_depth);
// the incoming clock lengths will be multiplied by something to give at least 1000
// sample points per line
int time_multiplier_ = 1;
const int common_output_divisor_ = 1;
// the two flywheels regulating scanning
std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_;
@ -82,6 +79,7 @@ class CRT {
int cycles_per_line_ = 1;
Outputs::Display::ScanTarget *scan_target_ = nullptr;
Outputs::Display::ScanTarget::Modals scan_target_modals_;
public:
/*! Constructs the CRT with a specified clock rate, height and colour subcarrier frequency.
@ -91,10 +89,7 @@ class CRT {
@param cycles_per_line The clock rate at which this CRT will be driven, specified as the number
of cycles expected to take up one whole scanline of the display.
@param common_output_divisor The greatest a priori common divisor of all cycle counts that will be
supplied to @c output_sync, @c output_data, etc; supply 1 if no greater divisor is known. For many
machines output will run at a fixed multiple of the clock rate; knowing this divisor can improve
internal precision.
@param pixel_clock_least_common_multiple TODO.
@param height_of_display The number of lines that nominally form one field of the display, rounded
up to the next whole integer.
@ -107,22 +102,22 @@ class CRT {
@param vertical_sync_half_lines The expected length of vertical synchronisation (equalisation pulses aside),
in multiples of half a line.
@param buffer_depth The depth per pixel of source data buffers to create for this machine. Machines
may provide per-clock-cycle data in the depth that they consider convenient, supplying a sampling
function to convert between their data format and either a composite or RGB signal, allowing that
work to be offloaded onto the GPU and allowing the output signal to be sampled at a rate appropriate
to the display size.
@param data_type TODO.
@param scan_target TODO.
@see @c set_rgb_sampling_function , @c set_composite_sampling_function
*/
CRT(int cycles_per_line,
int common_output_divisor,
int pixel_clock_least_common_multiple,
int height_of_display,
Outputs::Display::ColourSpace colour_space,
int colour_cycle_numerator, int colour_cycle_denominator,
int colour_cycle_numerator,
int colour_cycle_denominator,
int vertical_sync_half_lines,
bool should_alternate,
int buffer_depth);
Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target);
/*! Constructs the CRT with the specified clock rate, with the display height and colour
subcarrier frequency dictated by a standard display type and with the requested number of
@ -132,9 +127,10 @@ class CRT {
looked up by display type.
*/
CRT(int cycles_per_line,
int common_output_divisor,
int pixel_clock_least_common_multiple,
Outputs::Display::Type display_type,
int buffer_depth);
Outputs::Display::ScanTarget::Modals::DataType data_type,
Outputs::Display::ScanTarget *scan_target);
/*! Resets the CRT with new timing information. The CRT then continues as though the new timing had
been provided at construction. */
@ -149,7 +145,12 @@ class CRT {
/*! Resets the CRT with new timing information derived from a new display type. The CRT then continues
as though the new timing had been provided at construction. */
void set_new_display_type(int cycles_per_line, Outputs::Display::Type display_type);
void set_new_display_type(
int cycles_per_line,
Outputs::Display::Type display_type);
// TODO.
void set_new_data_type(Outputs::Display::ScanTarget::Modals::DataType data_type);
/*! Output at the sync level.

View File

@ -34,7 +34,7 @@ struct Rect {
float width, height;
} size;
Rect() {}
Rect() : origin({0.0f, 0.0f}), size({1.0f, 1.0f}) {}
Rect(float x, float y, float width, float height) :
origin({x, y}), size({width, height}) {}
};
@ -178,7 +178,7 @@ struct ScanTarget {
/// Announces that the owner is finished with the region created by the most recent @c allocate_write_area
/// and indicates that its actual final size was @c actual_length.
virtual void reduce_previous_allocation_to(size_t actual_length) = 0;
virtual void reduce_previous_allocation_to(size_t actual_length) {};
/// Announces that all endpoint pairs and write areas obtained since the last @c submit have now been
/// populated with appropriate data.
@ -187,15 +187,10 @@ struct ScanTarget {
/// as long as it feels is appropriate subject to an @c flush.
virtual void submit(bool only_if_no_allocation_failures = true) = 0;
/// Discards all data and endpoints supplied since the last @c submit. This is generally used when
/// failures in either get_endpoing_pair of allocate_write_area mean that proceeding would produce
/// a faulty total output.
virtual void reset() = 0;
/// Announces that any submitted data not yet output should be output now, but needn't block while
/// doing so. This generally communicates that processing is now otherwise 'up to date', so no
/// further delay should be allowed.
virtual void flush() = 0;
// virtual void flush() = 0;
/*