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:
parent
b40211d2c0
commit
f6562de325
@ -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_)
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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)"
|
||||
// "{"
|
||||
|
@ -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)) {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_;
|
||||
}
|
||||
|
@ -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)"
|
||||
// "{"
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user