#include "dev/arm/hdlcd.hh"
+#include "base/compiler.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "base/vnc/vncinput.hh"
}
}
+size_t
+HDLcd::lineNext(std::vector<Pixel>::iterator pixel_it, size_t line_length)
+{
+ const size_t byte_count = line_length * conv.length;
+
+ lineBuffer.resize(byte_count);
+ dmaRead(bypassLineAddress, byte_count, nullptr, lineBuffer.data());
+
+ bypassLineAddress += fb_line_pitch;
+
+ uint8_t *bufPtr = lineBuffer.data();
+ for (size_t i = 0; i < line_length; i++) {
+ *pixel_it++ = conv.toPixel(bufPtr);
+ bufPtr += conv.length;
+ }
+
+ return line_length;
+}
+
void
HDLcd::pxlVSyncBegin()
{
HDLcd::pxlVSyncEnd()
{
DPRINTF(HDLcd, "End of VSYNC, starting DMA engine\n");
- dmaEngine->startFrame(fb_base);
+ if (sys->bypassCaches()) {
+ bypassLineAddress = fb_base;
+ } else {
+ dmaEngine->startFrame(fb_base);
+ }
}
void
#include <fstream>
#include <memory>
+#include <vector>
#include "base/framebuffer.hh"
#include "base/imgwriter.hh"
ColorSelectReg blue_select = 0; /**< Blue color select register */
/** @} */
+ std::vector<uint8_t> lineBuffer;
+
uint32_t readReg(Addr offset);
void writeReg(Addr offset, uint32_t value);
public: // Pixel pump callbacks
bool pxlNext(Pixel &p);
+ size_t lineNext(std::vector<Pixel>::iterator pixel_it, size_t line_length);
void pxlVSyncBegin();
void pxlVSyncEnd();
void pxlUnderrun();
{
public:
PixelPump(HDLcd &p, ClockDomain &pxl_clk, unsigned pixel_chunk)
- : BasePixelPump(p, pxl_clk, pixel_chunk), parent(p) {}
+ : BasePixelPump(p, pxl_clk, pixel_chunk), parent(p)
+ {}
void dumpSettings();
protected:
bool nextPixel(Pixel &p) override { return parent.pxlNext(p); }
+ size_t
+ nextLine(std::vector<Pixel>::iterator pixel_it,
+ size_t line_length) override
+ {
+ return parent.lineNext(pixel_it, line_length);
+ }
void onVSyncBegin() override { return parent.pxlVSyncBegin(); }
void onVSyncEnd() override { return parent.pxlVSyncEnd(); }
HDLcd &parent;
};
+ Addr bypassLineAddress = 0;
+
/** Handler for fast frame refresh in KVM-mode */
void virtRefresh();
EventFunctionWrapper virtRefreshEvent;
#include "dev/pixelpump.hh"
+#include "base/logging.hh"
+
const DisplayTimings DisplayTimings::vga(
640, 480,
48, 96, 16,
void
BasePixelPump::renderLine()
{
- const unsigned pos_y(posY());
+ const unsigned pos_y = posY();
+ const size_t _width = fb.width();
- Pixel pixel(0, 0, 0);
- for (_posX = 0; _posX < _timings.width; ++_posX) {
- if (!nextPixel(pixel)) {
- panic("Unexpected underrun in BasePixelPump (%u, %u)\n",
- _posX, pos_y);
- }
- fb.pixel(_posX, pos_y) = pixel;
- }
+ auto pixel_it = fb.pixels.begin() + _width * pos_y;
+ panic_if(nextLine(pixel_it, _width) != _width,
+ "Unexpected underrun in BasePixelPump (%u, %u)", _width, pos_y);
}
#ifndef __DEV_PIXELPUMP_HH__
#define __DEV_PIXELPUMP_HH__
+#include <vector>
+
#include "base/framebuffer.hh"
#include "sim/clocked_object.hh"
/** Update frame size using display timing */
void updateTimings(const DisplayTimings &timings);
- /** Render an entire frame in KVM execution mode */
+ /** Render an entire frame in non-caching mode */
void renderFrame();
/** Starting pushing pixels in timing mode */
*/
virtual bool nextPixel(Pixel &p) = 0;
+ /**
+ * Get the next line of pixels directly from memory. This is for use from
+ * the renderFrame which is called in non-caching mode.
+ *
+ * The default implementation falls back to calling nextPixel over and
+ * over, but a more efficient implementation could retrieve the entire line
+ * of pixels all at once using fewer access to memory which bypass any
+ * intermediate structures like an incoming FIFO.
+ *
+ * @param ps A vector iterator to store retrieved pixels into.
+ * @param line_length The number of pixels being requested.
+ * @return The number of pixels actually retrieved.
+ */
+ virtual size_t
+ nextLine(std::vector<Pixel>::iterator ps, size_t line_length)
+ {
+ size_t count = 0;
+ while (count < line_length && nextPixel(*ps++))
+ count++;
+ return count;
+ }
+
/** First pixel clock of the first VSync line. */
virtual void onVSyncBegin() {};