mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-26 09:29:45 +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?)
|
||||
}
|
||||
|
||||
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) {
|
||||
// Bind the buffer and map it into CPU space.
|
||||
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));
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
||||
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;
|
||||
|
||||
// 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();
|
||||
|
||||
// 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.
|
||||
size_t new_scans = (submit_pointers.scan_buffer + scan_buffer_.size() - read_pointers.scan_buffer) % scan_buffer_.size();
|
||||
if(new_scans) {
|
||||
@ -514,30 +511,84 @@ void ScanTarget::draw(bool synchronous, int output_width, int output_height) {
|
||||
accumulation_texture_ = std::move(new_framebuffer);
|
||||
}
|
||||
|
||||
// Bind the accumulation texture.
|
||||
accumulation_texture_->bind_framebuffer();
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
// Figure out how many new spans are ostensible ready; use two less than that.
|
||||
uint16_t new_spans = (submit_pointers.line + LineBufferHeight - read_pointers.line) % LineBufferHeight;
|
||||
if(new_spans > 2) {
|
||||
new_spans -= 2;
|
||||
|
||||
// Enable stenciling and ensure spans increment the stencil buffer.
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_EQUAL, 0, GLuint(-1));
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||
// Bind the accumulation framebuffer.
|
||||
accumulation_texture_->bind_framebuffer();
|
||||
|
||||
// Output all lines except the one currently being worked on.
|
||||
glBindVertexArray(line_vertex_array_);
|
||||
output_shader_->bind();
|
||||
glEnable(GL_BLEND);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GLsizei(line_buffer_.size() - 2));
|
||||
// Enable blending and stenciling, and ensure spans increment the stencil buffer.
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_EQUAL, 0, GLuint(-1));
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||
|
||||
// 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);
|
||||
// Prepare to output lines.
|
||||
glBindVertexArray(line_vertex_array_);
|
||||
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).
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
accumulation_texture_->bind_texture();
|
||||
accumulation_texture_->draw(float(output_width) / float(output_height), 4.0f / 255.0f);
|
||||
|
@ -24,6 +24,11 @@ namespace Outputs {
|
||||
namespace Display {
|
||||
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 {
|
||||
public:
|
||||
ScanTarget();
|
||||
|
Loading…
Reference in New Issue
Block a user