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:
parent
26219213d7
commit
4c00456166
@ -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.
|
||||||
|
accumulation_texture_->bind_framebuffer();
|
||||||
|
|
||||||
|
// Enable blending and stenciling, and ensure spans increment the stencil buffer.
|
||||||
|
glEnable(GL_BLEND);
|
||||||
glEnable(GL_STENCIL_TEST);
|
glEnable(GL_STENCIL_TEST);
|
||||||
glStencilFunc(GL_EQUAL, 0, GLuint(-1));
|
glStencilFunc(GL_EQUAL, 0, GLuint(-1));
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
|
|
||||||
// Output all lines except the one currently being worked on.
|
// Prepare to output lines.
|
||||||
glBindVertexArray(line_vertex_array_);
|
glBindVertexArray(line_vertex_array_);
|
||||||
output_shader_->bind();
|
output_shader_->bind();
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(line_buffer_.size() - 2));
|
// 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)
|
// Clear untouched parts of the display. (TODO: at vertical sync, probably)
|
||||||
full_display_rectangle_.draw(0.0, 0.0, 0.0);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
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);
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user