2018-11-07 03:23:38 +00:00
|
|
|
//
|
|
|
|
// ScanTarget.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 05/11/2018.
|
|
|
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "ScanTarget.hpp"
|
2018-11-08 03:53:46 +00:00
|
|
|
#include "Primitives/Rectangle.hpp"
|
2018-11-07 03:23:38 +00:00
|
|
|
|
|
|
|
using namespace Outputs::Display::OpenGL;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
constexpr int WriteAreaWidth = 2048;
|
|
|
|
constexpr int WriteAreaHeight = 2048;
|
|
|
|
|
|
|
|
#define TextureAddress(x, y) (((x) << 11) | (y))
|
|
|
|
#define TextureAddressGetX(v) ((v) >> 11)
|
|
|
|
#define TextureAddressGetY(v) ((v) & 0x7ff)
|
|
|
|
#define TextureSub(x, y) (((x) - (y)) & 0x7ff)
|
2018-11-07 03:23:38 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-08 03:53:46 +00:00
|
|
|
ScanTarget::ScanTarget() {
|
|
|
|
// Allocate space for the spans.
|
|
|
|
glGenBuffers(1, &scan_buffer_name_);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, scan_buffer_name_);
|
|
|
|
const auto buffer_size = scan_buffer_.size() * sizeof(Scan);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(buffer_size), NULL, GL_STREAM_DRAW);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScanTarget::~ScanTarget() {
|
|
|
|
// Release span space.
|
|
|
|
glDeleteBuffers(1, &scan_buffer_name_);
|
|
|
|
}
|
|
|
|
|
2018-11-07 03:23:38 +00:00
|
|
|
void ScanTarget::set_modals(Modals modals) {
|
|
|
|
// TODO: consider resizing the write_area_texture_, and setting
|
|
|
|
// write_area_texture_line_length_ appropriately.
|
|
|
|
modals_ = modals;
|
|
|
|
|
|
|
|
const auto data_type_size = Outputs::Display::size_for_data_type(modals.input_data_type);
|
|
|
|
if(data_type_size != data_type_size_) {
|
|
|
|
// TODO: flush output.
|
|
|
|
|
|
|
|
data_type_size_ = data_type_size;
|
|
|
|
write_area_texture_.resize(2048*2048*data_type_size_);
|
2018-11-09 02:57:28 +00:00
|
|
|
|
|
|
|
write_pointers_.scan_buffer = 0;
|
|
|
|
write_pointers_.write_area = 0;
|
2018-11-07 03:23:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Outputs::Display::ScanTarget::Scan *ScanTarget::get_scan() {
|
|
|
|
if(allocation_has_failed_) return nullptr;
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
const auto result = &scan_buffer_[write_pointers_.scan_buffer];
|
|
|
|
const auto read_pointers = read_pointers_.load();
|
2018-11-07 03:23:38 +00:00
|
|
|
|
|
|
|
// Advance the pointer.
|
2018-11-09 02:57:28 +00:00
|
|
|
const auto next_write_pointer = decltype(write_pointers_.scan_buffer)((write_pointers_.scan_buffer + 1) % scan_buffer_.size());
|
2018-11-07 03:23:38 +00:00
|
|
|
|
|
|
|
// Check whether that's too many.
|
2018-11-09 02:57:28 +00:00
|
|
|
if(next_write_pointer == read_pointers.scan_buffer) {
|
2018-11-07 03:23:38 +00:00
|
|
|
allocation_has_failed_ = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-11-09 02:57:28 +00:00
|
|
|
write_pointers_.scan_buffer = next_write_pointer;
|
2018-11-07 03:23:38 +00:00
|
|
|
|
|
|
|
// Fill in extra OpenGL-specific details.
|
2018-11-09 02:57:28 +00:00
|
|
|
// result->data_y = write_pointers_.write_area;
|
2018-11-07 03:23:38 +00:00
|
|
|
result->composite_y = 0;
|
|
|
|
|
|
|
|
return static_cast<Outputs::Display::ScanTarget::Scan *>(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *ScanTarget::allocate_write_area(size_t required_length, size_t required_alignment) {
|
|
|
|
if(allocation_has_failed_) return nullptr;
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
// Determine where the proposed write area would start and end.
|
|
|
|
uint16_t output_y = TextureAddressGetY(write_pointers_.write_area);
|
|
|
|
|
|
|
|
uint16_t aligned_start_x = TextureAddressGetX(write_pointers_.write_area & 0xffff) + 1;
|
|
|
|
aligned_start_x += uint16_t((required_alignment - aligned_start_x%required_alignment)%required_alignment);
|
|
|
|
|
|
|
|
uint16_t end_x = aligned_start_x + uint16_t(1 + required_length);
|
|
|
|
|
|
|
|
if(end_x > WriteAreaWidth) {
|
|
|
|
output_y = (output_y + 1) % WriteAreaHeight;
|
|
|
|
aligned_start_x = uint16_t(required_alignment);
|
|
|
|
end_x = aligned_start_x + uint16_t(1 + required_length);
|
2018-11-07 03:23:38 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
// Check whether that steps over the read pointer.
|
|
|
|
const auto new_address = TextureAddress(end_x, output_y);
|
|
|
|
const auto read_pointers = read_pointers_.load();
|
|
|
|
|
|
|
|
const auto new_distance = TextureSub(read_pointers.write_area, new_address);
|
|
|
|
const auto previous_distance = TextureSub(read_pointers.write_area, write_pointers_.write_area);
|
|
|
|
|
|
|
|
// If allocating this would somehow make the write pointer further away from the read pointer,
|
|
|
|
// there must not be enough space left.
|
|
|
|
if(new_distance > previous_distance) {
|
2018-11-07 03:23:38 +00:00
|
|
|
allocation_has_failed_ = true;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
// Everything checks out, return the pointer.
|
|
|
|
last_supplied_x_ = aligned_start_x;
|
|
|
|
return &write_area_texture_[size_t(new_address) * data_type_size_];
|
2018-11-07 03:23:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScanTarget::reduce_previous_allocation_to(size_t actual_length) {
|
|
|
|
if(allocation_has_failed_) return;
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
// The span was allocated in the knowledge that there's sufficient distance
|
|
|
|
// left on the current line, so there's no need to worry about carry.
|
|
|
|
write_pointers_.write_area += actual_length + 1;
|
2018-11-07 03:23:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScanTarget::submit() {
|
2018-11-08 03:53:46 +00:00
|
|
|
if(allocation_has_failed_) {
|
|
|
|
// Reset all pointers to where they were.
|
2018-11-09 02:57:28 +00:00
|
|
|
write_pointers_ = submit_pointers_.load();
|
2018-11-08 03:53:46 +00:00
|
|
|
} else {
|
|
|
|
// Advance submit pointer.
|
2018-11-09 02:57:28 +00:00
|
|
|
submit_pointers_.store(write_pointers_);
|
2018-11-08 03:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
allocation_has_failed_ = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScanTarget::draw() {
|
2018-11-09 02:57:28 +00:00
|
|
|
// Grab the current read and submit pointers.
|
|
|
|
const auto submit_pointers = submit_pointers_.load();
|
|
|
|
const auto read_pointers = read_pointers_.load();
|
|
|
|
|
2018-11-08 03:53:46 +00:00
|
|
|
// Submit spans.
|
2018-11-09 02:57:28 +00:00
|
|
|
if(submit_pointers.scan_buffer != read_pointers.scan_buffer) {
|
|
|
|
|
|
|
|
// uint8_t *destination = static_cast<uint8_t *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
|
|
|
|
// if(!glGetError() && destination) {
|
|
|
|
// }
|
|
|
|
|
2018-11-08 03:53:46 +00:00
|
|
|
// TODO: submit all scans from scan_buffer_pointers_.read_pointer to scan_buffer_pointers_.submit_pointer.
|
2018-11-09 02:57:28 +00:00
|
|
|
// read_pointers_.scan_buffer = submit_pointers.scan_buffer;
|
2018-11-08 03:53:46 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 02:57:28 +00:00
|
|
|
// All data now having been spooled to the GPU, update the read pointers to
|
|
|
|
// the submit pointer location.
|
|
|
|
read_pointers_.store(submit_pointers);
|
|
|
|
|
2018-11-08 03:53:46 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
2018-11-09 02:57:28 +00:00
|
|
|
// ::OpenGL::Rectangle rect(-0.8f, -0.8f, 1.6f, 1.6f);
|
|
|
|
// rect.draw(1, 1, 0);
|
2018-11-07 03:23:38 +00:00
|
|
|
}
|