1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Makes first attempt to draw only new lines.

This commit is contained in:
Thomas Harte 2018-11-19 23:25:26 -05:00
parent 26219213d7
commit 4c00456166
2 changed files with 78 additions and 22 deletions

View File

@ -336,7 +336,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::patch_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);
@ -361,7 +361,7 @@ template <typename T> void ScanTarget::patch_buffer(const T &array, GLuint targe
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size)); glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size));
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
} }
} }*/
void ScanTarget::draw(bool synchronous, int output_width, int output_height) { void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
if(fence_ != nullptr) { if(fence_ != nullptr) {
@ -375,12 +375,9 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
if(is_drawing_.test_and_set()) return; if(is_drawing_.test_and_set()) return;
// Grab the current read and submit pointers. // Grab the current read and submit pointers.
const auto submit_pointers = submit_pointers_.load(); auto submit_pointers = submit_pointers_.load();
const auto read_pointers = read_pointers_.load(); const auto read_pointers = read_pointers_.load();
// Submit scans and lines; TODO: for lines, rotate in.
patch_buffer(line_buffer_, line_buffer_name_, submit_pointers.line, read_pointers.line);
// Submit scans; only the new ones need to be communicated. // Submit scans; only the new ones need to be communicated.
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size(); size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
if(new_scans) { if(new_scans) {
@ -514,30 +511,84 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
accumulation_texture_ = std::move(new_framebuffer); accumulation_texture_ = std::move(new_framebuffer);
} }
// Bind the accumulation texture. // Figure out how many new spans are ostensible ready; use two less than that.
accumulation_texture_->bind_framebuffer(); uint16_t new_spans = (submit_pointers.line + LineBufferHeight - read_pointers.line) % LineBufferHeight;
glClear(GL_STENCIL_BUFFER_BIT); if(new_spans > 2) {
new_spans -= 2;
// Enable stenciling and ensure spans increment the stencil buffer. // Bind the accumulation framebuffer.
glEnable(GL_STENCIL_TEST); accumulation_texture_->bind_framebuffer();
glStencilFunc(GL_EQUAL, 0, GLuint(-1));
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
// Output all lines except the one currently being worked on. // Enable blending and stenciling, and ensure spans increment the stencil buffer.
glBindVertexArray(line_vertex_array_); glEnable(GL_BLEND);
output_shader_->bind(); glEnable(GL_STENCIL_TEST);
glEnable(GL_BLEND); glStencilFunc(GL_EQUAL, 0, GLuint(-1));
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(line_buffer_.size() - 2)); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
// Clear untouched parts of the display. (TODO: at vertical sync, probably) // Prepare to output lines.
full_display_rectangle_.draw(0.0, 0.0, 0.0); glBindVertexArray(line_vertex_array_);
glDisable(GL_STENCIL_TEST); output_shader_->bind();
// Prepare to upload data that will consitute lines.
glBindBuffer(GL_ARRAY_BUFFER, line_buffer_name_);
// Divide spans by which frame they're in.
uint16_t start_line = read_pointers.line;
submit_pointers.line = (read_pointers.line + new_spans) % LineBufferHeight;
while(new_spans) {
uint16_t end_line = start_line+1;
// Find the limit of spans to draw in this cycle.
size_t spans = 1;
while(end_line != submit_pointers.line && !line_metadata_buffer_[end_line].is_first_in_frame) {
end_line = (end_line + 1) % LineBufferHeight;
++spans;
}
// Upload and draw.
const auto buffer_size = spans * sizeof(Line);
if(!end_line || end_line > start_line) {
glBufferSubData(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), &line_buffer_[start_line]);
} else {
uint8_t *destination = static_cast<uint8_t *>(
glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size), GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)
);
assert(destination);
const size_t buffer_length = line_buffer_.size() * sizeof(Line);
const size_t start_position = start_line * sizeof(Line);
memcpy(&destination[0], &line_buffer_[start_line], buffer_length - start_position);
memcpy(&destination[buffer_length - start_position], &line_buffer_[0], end_line * sizeof(Line));
glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(buffer_size));
glUnmapBuffer(GL_ARRAY_BUFFER);
}
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(spans));
// If this is end-of-frame, clear any untouched pixels and flush the stencil buffer
if(line_metadata_buffer_[end_line].is_first_in_frame) {
full_display_rectangle_.draw(0.0, 0.0, 0.0);
glClear(GL_STENCIL_BUFFER_BIT);
// Rebind the program for span output.
glBindVertexArray(line_vertex_array_);
output_shader_->bind();
}
start_line = end_line;
new_spans -= spans;
}
// Clear untouched parts of the display. (TODO: at vertical sync, probably)
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
}
// Copy the accumulatiion texture to the target (TODO: don't assume framebuffer 0). // Copy the accumulatiion texture to the target (TODO: don't assume framebuffer 0).
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height); glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height);
glDisable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
accumulation_texture_->bind_texture(); accumulation_texture_->bind_texture();
accumulation_texture_->draw(float(output_width) / float(output_height), 4.0f / 255.0f); accumulation_texture_->draw(float(output_width) / float(output_height), 4.0f / 255.0f);

View File

@ -24,6 +24,11 @@ namespace Outputs {
namespace Display { namespace Display {
namespace OpenGL { namespace OpenGL {
/*!
Provides a ScanTarget that uses OpenGL to render its output;
this uses various internal buffers so that the only geometry
drawn to the target framebuffer is a quad.
*/
class ScanTarget: public Outputs::Display::ScanTarget { class ScanTarget: public Outputs::Display::ScanTarget {
public: public:
ScanTarget(); ScanTarget();