mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Proceeds as drawing to the unprocessed line buffer and drawing from it.
Very, very slowly, and without yet clearing.
This commit is contained in:
parent
02f9cada43
commit
bf3ab4e260
@ -244,7 +244,7 @@ struct ActivityObserver: public Activity::Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty {
|
- (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty {
|
||||||
_scanTarget->draw(onlyIfDirty ? false : true);
|
_scanTarget->draw(onlyIfDirty ? false : true, (int)pixelSize.width, (int)pixelSize.height);
|
||||||
// _machine->crt_machine()->get_crt()->draw_frame((unsigned int)pixelSize.width, (unsigned int)pixelSize.height, onlyIfDirty ? true : false);
|
// _machine->crt_machine()->get_crt()->draw_frame((unsigned int)pixelSize.width, (unsigned int)pixelSize.height, onlyIfDirty ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ ScanTarget::ScanTarget() :
|
|||||||
|
|
||||||
glGenTextures(1, &write_area_texture_name_);
|
glGenTextures(1, &write_area_texture_name_);
|
||||||
|
|
||||||
test_shader_.reset(new Shader(
|
input_shader_.reset(new Shader(
|
||||||
glsl_globals(ShaderType::Scan) + glsl_default_vertex_shader(ShaderType::Scan),
|
glsl_globals(ShaderType::Scan) + glsl_default_vertex_shader(ShaderType::Scan),
|
||||||
"#version 150\n"
|
"#version 150\n"
|
||||||
|
|
||||||
@ -103,9 +103,28 @@ ScanTarget::ScanTarget() :
|
|||||||
"fragColour = vec4(float(texture(textureName, textureCoordinate).r), 0.0, 0.0, 1.0);"
|
"fragColour = vec4(float(texture(textureName, textureCoordinate).r), 0.0, 0.0, 1.0);"
|
||||||
"}"
|
"}"
|
||||||
));
|
));
|
||||||
|
|
||||||
glBindVertexArray(scan_vertex_array_);
|
glBindVertexArray(scan_vertex_array_);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
||||||
enable_vertex_attributes(ShaderType::Scan, *test_shader_);
|
enable_vertex_attributes(ShaderType::Scan, *input_shader_);
|
||||||
|
|
||||||
|
output_shader_.reset(new Shader(
|
||||||
|
glsl_globals(ShaderType::Line) + glsl_default_vertex_shader(ShaderType::Line),
|
||||||
|
"#version 150\n"
|
||||||
|
|
||||||
|
"out vec4 fragColour;"
|
||||||
|
"in vec2 textureCoordinate;"
|
||||||
|
|
||||||
|
"uniform sampler2D textureName;"
|
||||||
|
|
||||||
|
"void main(void) {"
|
||||||
|
"fragColour = texture(textureName, textureCoordinate);"
|
||||||
|
"}"
|
||||||
|
));
|
||||||
|
|
||||||
|
glBindVertexArray(line_vertex_array_);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, line_buffer_name_);
|
||||||
|
enable_vertex_attributes(ShaderType::Line, *output_shader_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanTarget::~ScanTarget() {
|
ScanTarget::~ScanTarget() {
|
||||||
@ -140,10 +159,17 @@ void ScanTarget::set_modals(Modals modals) {
|
|||||||
processing_width_ = colour_cycle_width + (overflow ? dot_clock - overflow : 0);
|
processing_width_ = colour_cycle_width + (overflow ? dot_clock - overflow : 0);
|
||||||
processing_width_ = std::min(processing_width_, 2048);
|
processing_width_ = std::min(processing_width_, 2048);
|
||||||
|
|
||||||
// TODO: this, but not to the test shader.
|
set_uniforms(Outputs::Display::OpenGL::ScanTarget::ShaderType::Scan, *output_shader_);
|
||||||
test_shader_->set_uniform("scale", GLfloat(modals.output_scale.x), GLfloat(modals.output_scale.y));
|
set_uniforms(Outputs::Display::OpenGL::ScanTarget::ShaderType::Line, *input_shader_);
|
||||||
test_shader_->set_uniform("rowHeight", GLfloat(1.0f / modals.expected_vertical_lines));
|
|
||||||
test_shader_->set_uniform("textureName", GLint(SourceData1BppTextureUnit - GL_TEXTURE0));
|
input_shader_->set_uniform("textureName", GLint(SourceData1BppTextureUnit - GL_TEXTURE0));
|
||||||
|
output_shader_->set_uniform("textureName", GLint(UnprocessedLineBufferTextureUnit - GL_TEXTURE0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Outputs::Display::OpenGL::ScanTarget::set_uniforms(ShaderType type, Shader &target) {
|
||||||
|
target.set_uniform("scale", GLfloat(modals_.output_scale.x), GLfloat(modals_.output_scale.y));
|
||||||
|
target.set_uniform("rowHeight", GLfloat(1.0f / modals_.expected_vertical_lines));
|
||||||
|
target.set_uniform("processingWidth", GLfloat(processing_width_) / 2048.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Outputs::Display::ScanTarget::Scan *ScanTarget::begin_scan() {
|
Outputs::Display::ScanTarget::Scan *ScanTarget::begin_scan() {
|
||||||
@ -273,7 +299,7 @@ void ScanTarget::announce(Event event, uint16_t x, uint16_t y) {
|
|||||||
// (maybe set a flag and zero out the line coordinates?)
|
// (maybe set a flag and zero out the line coordinates?)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void ScanTarget::submit_buffer(const T &array, GLuint target, uint16_t submit_pointer, uint16_t read_pointer) {
|
template <typename T> void ScanTarget::patch_buffer(const T &array, GLuint target, uint16_t submit_pointer, uint16_t read_pointer) {
|
||||||
if(submit_pointer != read_pointer) {
|
if(submit_pointer != read_pointer) {
|
||||||
// Bind the buffer and map it into CPU space.
|
// Bind the buffer and map it into CPU space.
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, target);
|
glBindBuffer(GL_ARRAY_BUFFER, target);
|
||||||
@ -283,7 +309,7 @@ template <typename T> void ScanTarget::submit_buffer(const T &array, GLuint targ
|
|||||||
);
|
);
|
||||||
assert(destination);
|
assert(destination);
|
||||||
|
|
||||||
if(submit_pointer > read_pointer) {
|
if(read_pointer < submit_pointer) {
|
||||||
// Submit the direct region from the submit pointer to the read pointer.
|
// Submit the direct region from the submit pointer to the read pointer.
|
||||||
const size_t offset = read_pointer * sizeof(array[0]);
|
const size_t offset = read_pointer * sizeof(array[0]);
|
||||||
const size_t length = (submit_pointer - read_pointer) * sizeof(array[0]);
|
const size_t length = (submit_pointer - read_pointer) * sizeof(array[0]);
|
||||||
@ -309,7 +335,7 @@ template <typename T> void ScanTarget::submit_buffer(const T &array, GLuint targ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScanTarget::draw(bool synchronous) {
|
void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
||||||
if(fence_ != nullptr) {
|
if(fence_ != nullptr) {
|
||||||
// if the GPU is still busy, don't wait; we'll catch it next time
|
// if the GPU is still busy, don't wait; we'll catch it next time
|
||||||
if(glClientWaitSync(fence_, GL_SYNC_FLUSH_COMMANDS_BIT, synchronous ? GL_TIMEOUT_IGNORED : 0) == GL_TIMEOUT_EXPIRED) {
|
if(glClientWaitSync(fence_, GL_SYNC_FLUSH_COMMANDS_BIT, synchronous ? GL_TIMEOUT_IGNORED : 0) == GL_TIMEOUT_EXPIRED) {
|
||||||
@ -324,9 +350,31 @@ void ScanTarget::draw(bool synchronous) {
|
|||||||
const auto submit_pointers = submit_pointers_.load();
|
const auto submit_pointers = submit_pointers_.load();
|
||||||
const auto read_pointers = read_pointers_.load();
|
const auto read_pointers = read_pointers_.load();
|
||||||
|
|
||||||
// Submit scans and lines.
|
// Submit scans and lines; TODO: for lines, rotate in.
|
||||||
submit_buffer(scan_buffer_, scan_buffer_name_, submit_pointers.scan_buffer, read_pointers.scan_buffer);
|
patch_buffer(line_buffer_, line_buffer_name_, submit_pointers.line, read_pointers.line);
|
||||||
submit_buffer(line_buffer_, line_buffer_name_, submit_pointers.line, read_pointers.line);
|
|
||||||
|
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
||||||
|
if(new_scans) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
||||||
|
|
||||||
|
// Map only the required portion of the buffer.
|
||||||
|
const size_t new_scans_size = new_scans * sizeof(Scan);
|
||||||
|
uint8_t *const destination = static_cast<uint8_t *>(
|
||||||
|
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(new_scans_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(read_pointers.scan_buffer < submit_pointers.scan_buffer) {
|
||||||
|
memcpy(destination, &scan_buffer_[read_pointers.scan_buffer], new_scans_size);
|
||||||
|
} else {
|
||||||
|
const size_t first_portion_length = (scan_buffer_.size() - read_pointers.scan_buffer) * sizeof(Scan);
|
||||||
|
memcpy(destination, &scan_buffer_[read_pointers.scan_buffer], first_portion_length);
|
||||||
|
memcpy(&destination[first_portion_length], &scan_buffer_[0], new_scans_size - first_portion_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmap the buffer.
|
||||||
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||||
|
}
|
||||||
|
// patch_buffer(scan_buffer_, scan_buffer_name_, submit_pointers.scan_buffer, read_pointers.scan_buffer);
|
||||||
|
|
||||||
// Submit texture.
|
// Submit texture.
|
||||||
if(submit_pointers.write_area != read_pointers.write_area) {
|
if(submit_pointers.write_area != read_pointers.write_area) {
|
||||||
@ -384,22 +432,32 @@ void ScanTarget::draw(bool synchronous) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: clear composite buffer (if needed).
|
// Push new input to the unprocessed line buffer.
|
||||||
// TODO: drawing (!)
|
if(new_scans) {
|
||||||
|
unprocessed_line_texture_.bind_framebuffer();
|
||||||
|
glBindVertexArray(scan_vertex_array_);
|
||||||
|
input_shader_->bind();
|
||||||
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(new_scans));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the target framebuffer (TODO: don't assume 0).
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// unprocessed_line_texture_.draw(1.0f);
|
||||||
|
|
||||||
|
// Output all lines.
|
||||||
|
glBindVertexArray(line_vertex_array_);
|
||||||
|
output_shader_->bind();
|
||||||
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(line_buffer_.size()));
|
||||||
|
|
||||||
// All data now having been spooled to the GPU, update the read pointers to
|
// All data now having been spooled to the GPU, update the read pointers to
|
||||||
// the submit pointer location.
|
// the submit pointer location.
|
||||||
read_pointers_.store(submit_pointers);
|
read_pointers_.store(submit_pointers);
|
||||||
|
|
||||||
// TEST: draw all lines.
|
// Grab a fence sync object to avoid busy waiting upon the next extry into this
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
// function, and reset the is_drawing_ flag.
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
glBindVertexArray(scan_vertex_array_);
|
|
||||||
test_shader_->bind();
|
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(scan_buffer_.size()));
|
|
||||||
|
|
||||||
fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
fence_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
is_drawing_.clear();
|
is_drawing_.clear();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class ScanTarget: public Outputs::Display::ScanTarget {
|
|||||||
public:
|
public:
|
||||||
ScanTarget();
|
ScanTarget();
|
||||||
~ScanTarget();
|
~ScanTarget();
|
||||||
void draw(bool synchronous);
|
void draw(bool synchronous, int output_width, int output_height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Outputs::Display::ScanTarget overrides.
|
// Outputs::Display::ScanTarget overrides.
|
||||||
@ -87,7 +87,7 @@ class ScanTarget: public Outputs::Display::ScanTarget {
|
|||||||
GLuint line_buffer_name_ = 0, line_vertex_array_ = 0;
|
GLuint line_buffer_name_ = 0, line_vertex_array_ = 0;
|
||||||
|
|
||||||
template <typename T> void allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name);
|
template <typename T> void allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name);
|
||||||
template <typename T> void submit_buffer(const T &array, GLuint target, uint16_t submit_pointer, uint16_t read_pointer);
|
template <typename T> void patch_buffer(const T &array, GLuint target, uint16_t submit_pointer, uint16_t read_pointer);
|
||||||
|
|
||||||
// Uses a texture to vend write areas.
|
// Uses a texture to vend write areas.
|
||||||
std::vector<uint8_t> write_area_texture_;
|
std::vector<uint8_t> write_area_texture_;
|
||||||
@ -128,12 +128,14 @@ class ScanTarget: public Outputs::Display::ScanTarget {
|
|||||||
globals for shaders of @c type to @c target.
|
globals for shaders of @c type to @c target.
|
||||||
*/
|
*/
|
||||||
void enable_vertex_attributes(ShaderType type, Shader &target);
|
void enable_vertex_attributes(ShaderType type, Shader &target);
|
||||||
|
void set_uniforms(ShaderType type, Shader &target);
|
||||||
|
|
||||||
GLsync fence_ = nullptr;
|
GLsync fence_ = nullptr;
|
||||||
std::atomic_flag is_drawing_;
|
std::atomic_flag is_drawing_;
|
||||||
|
|
||||||
int processing_width_ = 0;
|
int processing_width_ = 0;
|
||||||
std::unique_ptr<Shader> test_shader_;
|
std::unique_ptr<Shader> input_shader_;
|
||||||
|
std::unique_ptr<Shader> output_shader_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ std::string ScanTarget::glsl_globals(ShaderType type) {
|
|||||||
"uniform float rowHeight;"
|
"uniform float rowHeight;"
|
||||||
"uniform mat3 lumaChromaToRGB;"
|
"uniform mat3 lumaChromaToRGB;"
|
||||||
"uniform mat3 rgbToLumaChroma;"
|
"uniform mat3 rgbToLumaChroma;"
|
||||||
|
"uniform float processingWidth;"
|
||||||
|
|
||||||
"in vec2 startPoint;"
|
"in vec2 startPoint;"
|
||||||
"in float startDataX;"
|
"in float startDataX;"
|
||||||
@ -38,9 +39,12 @@ std::string ScanTarget::glsl_globals(ShaderType type) {
|
|||||||
|
|
||||||
"uniform vec2 scale;"
|
"uniform vec2 scale;"
|
||||||
"uniform float rowHeight;"
|
"uniform float rowHeight;"
|
||||||
|
"uniform float processingWidth;"
|
||||||
|
|
||||||
"in vec2 startPoint;"
|
"in vec2 startPoint;"
|
||||||
"in vec2 endPoint;";
|
"in vec2 endPoint;"
|
||||||
|
|
||||||
|
"in float lineY;";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,16 +61,21 @@ std::string ScanTarget::glsl_default_vertex_shader(ShaderType type) {
|
|||||||
|
|
||||||
"textureCoordinate = vec2(mix(startDataX, endDataX, lateral), dataY) / textureSize(textureName, 0);"
|
"textureCoordinate = vec2(mix(startDataX, endDataX, lateral), dataY) / textureSize(textureName, 0);"
|
||||||
|
|
||||||
"vec2 eyePosition = vec2(mix(startPoint.x, endPoint.x, lateral), lineY + longitudinal) / vec2(scale.x, 2048.0);"
|
"vec2 eyePosition = vec2(mix(startPoint.x, endPoint.x, lateral) * processingWidth, lineY + longitudinal) / vec2(scale.x, 2048.0);"
|
||||||
"gl_Position = vec4(eyePosition*2 - vec2(1.0), 0.0, 1.0);"
|
"gl_Position = vec4(eyePosition*2 - vec2(1.0), 0.0, 1.0);"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
case ShaderType::Line:
|
case ShaderType::Line:
|
||||||
return
|
return
|
||||||
|
"out vec2 textureCoordinate;"
|
||||||
|
"uniform sampler2D textureName;"
|
||||||
|
|
||||||
"void main(void) {"
|
"void main(void) {"
|
||||||
"float lateral = float(gl_VertexID & 1);"
|
"float lateral = float(gl_VertexID & 1);"
|
||||||
"float longitudinal = float((gl_VertexID & 2) >> 1);"
|
"float longitudinal = float((gl_VertexID & 2) >> 1);"
|
||||||
|
|
||||||
|
"textureCoordinate = vec2(lateral * processingWidth, lineY) / vec2(1.0, textureSize(textureName, 0).y);"
|
||||||
|
|
||||||
"vec2 centrePoint = mix(startPoint, endPoint, lateral) / scale;"
|
"vec2 centrePoint = mix(startPoint, endPoint, lateral) / scale;"
|
||||||
"vec2 height = normalize(endPoint - startPoint).yx * (longitudinal - 0.5) * rowHeight;"
|
"vec2 height = normalize(endPoint - startPoint).yx * (longitudinal - 0.5) * rowHeight;"
|
||||||
"vec2 eyePosition = vec2(-0.9, 0.9) + vec2(1.8, -1.8) * (centrePoint + height);"
|
"vec2 eyePosition = vec2(-0.9, 0.9) + vec2(1.8, -1.8) * (centrePoint + height);"
|
||||||
@ -126,6 +135,13 @@ void ScanTarget::enable_vertex_attributes(ShaderType type, Shader &target) {
|
|||||||
reinterpret_cast<void *>(offsetof(Line, end_points[c].x)),
|
reinterpret_cast<void *>(offsetof(Line, end_points[c].x)),
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target.enable_vertex_attribute_with_pointer(
|
||||||
|
"lineY",
|
||||||
|
1, GL_UNSIGNED_SHORT, GL_FALSE,
|
||||||
|
sizeof(Line),
|
||||||
|
reinterpret_cast<void *>(offsetof(Line, line)),
|
||||||
|
1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user