diff options
Diffstat (limited to 'db')
-rw-r--r-- | db/CMakeLists.txt | 6 | ||||
-rw-r--r-- | db/db.cpp | 309 |
2 files changed, 315 insertions, 0 deletions
diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt new file mode 100644 index 0000000..91ab888 --- /dev/null +++ b/db/CMakeLists.txt @@ -0,0 +1,6 @@ +include_directories(${LIBDRM_INCLUDE_DIRS}) +link_directories(${LIBDRM_LIBRARY_DIRS}) + +add_executable (db db.cpp) + +target_link_libraries(db kms++ ${LIBDRM_LIBRARIES}) diff --git a/db/db.cpp b/db/db.cpp new file mode 100644 index 0000000..d119078 --- /dev/null +++ b/db/db.cpp @@ -0,0 +1,309 @@ +#include <cstdio> +#include <algorithm> + +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <drm_fourcc.h> + +#include "kms++.h" +#include "utils/color.h" + +#include "../test.h" + +using namespace std; +using namespace kms; + +static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width); + +static void main_loop(Card& card); + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct Output +{ + Connector* connector; + Crtc* crtc; + Framebuffer* fbs[2]; + + int front_buf; + int bar_xpos; +}; + +static void do_flip(Output* out); + +int main() +{ + Card card; + + if (card.master() == false) + printf("Not DRM master, modeset may fail\n"); + + //card.print_short(); + + vector<Output> outputs; + + for (auto conn : card.get_connectors()) + { + if (conn->connected() == false) + continue; + + auto mode = conn->get_default_mode(); + + Crtc* crtc = conn->get_current_crtc(); + if (!crtc) { + for (auto c : conn->get_possible_crtcs()) { + if (find_if(outputs.begin(), outputs.end(), [c](Output o) { return o.crtc == c; }) == outputs.end()) { + crtc = c; + break; + } + } + } + + if (!crtc) { + printf("failed to find crtc\n"); + return -1; + } + + auto fb1 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24"); + auto fb2 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24"); + + printf("conn %u, crtc %u, fb1 %u, fb2 %u\n", conn->id(), crtc->id(), fb1->id(), fb2->id()); + + Output output = { }; + output.connector = conn; + output.crtc = crtc; + output.fbs[0] = fb1; + output.fbs[1] = fb2; + outputs.push_back(output); + } + + for(auto& out : outputs) { + auto conn = out.connector; + auto crtc = out.crtc; + + auto mode = conn->get_default_mode(); + int r = crtc->set_mode(conn, *out.fbs[0], mode); + ASSERT(r == 0); + } + + for(auto& out : outputs) + do_flip(&out); + + main_loop(card); + + for(auto& out : outputs) { + delete out.fbs[0]; + delete out.fbs[1]; + } +} + +static void do_flip(Output* out) +{ + const int bar_width = 20; + const int bar_speed = 8; + + auto crtc = out->crtc; + auto fb = out->fbs[(out->front_buf + 1) % 2]; + + ASSERT(crtc); + ASSERT(fb); + + int current_xpos = out->bar_xpos; + int old_xpos = (current_xpos + (fb->width() - bar_width - bar_speed)) % (fb->width() - bar_width); + int new_xpos = (current_xpos + bar_speed) % (fb->width() - bar_width); + + draw_color_bar(*fb, old_xpos, new_xpos, bar_width); + + out->bar_xpos = new_xpos; + + auto& card = crtc->card(); + + if (card.has_atomic()) { + int r; + + AtomicReq ctx(card); + + // XXX + //ctx.add(plane, card.get_prop("CRTC_X"), 50); + //ctx.add(plane, card.get_prop("CRTC_Y"), 50); + + r = ctx.test(); + ASSERT(r == 0); + + r = ctx.commit(); + ASSERT(r == 0); + } else { + int r = drmModePageFlip(card.fd(), crtc->id(), fb->id(), DRM_MODE_PAGE_FLIP_EVENT, out); + ASSERT(r == 0); + } +} + +static void page_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, + void *data) +{ + //printf("flip event %d, %d, %u, %u, %p\n", fd, frame, sec, usec, data); + + auto out = (Output*)data; + + out->front_buf = (out->front_buf + 1) % 2; + + do_flip(out); +} + + +static void main_loop(Card& card) +{ + drmEventContext ev = { + .version = DRM_EVENT_CONTEXT_VERSION, + .vblank_handler = 0, + .page_flip_handler = page_flip_handler, + }; + + fd_set fds; + + FD_ZERO(&fds); + + int fd = card.fd(); + + printf("press enter to exit\n"); + + while (true) { + int r; + + FD_SET(0, &fds); + FD_SET(fd, &fds); + + r = select(fd + 1, &fds, NULL, NULL, NULL); + if (r < 0) { + fprintf(stderr, "select() failed with %d: %m\n", errno); + break; + } else if (FD_ISSET(0, &fds)) { + fprintf(stderr, "exit due to user-input\n"); + break; + } else if (FD_ISSET(fd, &fds)) { + drmHandleEvent(fd, &ev); + } + } +} + + +static const RGB colors32[] = { + RGB(255, 255, 255), + RGB(255, 0, 0), + RGB(255, 255, 255), + RGB(0, 255, 0), + RGB(255, 255, 255), + RGB(0, 0, 255), + RGB(255, 255, 255), + RGB(200, 200, 200), + RGB(255, 255, 255), + RGB(100, 100, 100), + RGB(255, 255, 255), + RGB(50, 50, 50), +}; + +static const uint16_t colors16[] = { + colors32[0].rgb565(), + colors32[1].rgb565(), + colors32[2].rgb565(), + colors32[3].rgb565(), + colors32[4].rgb565(), + colors32[5].rgb565(), + colors32[6].rgb565(), + colors32[7].rgb565(), + colors32[8].rgb565(), + colors32[9].rgb565(), + colors32[10].rgb565(), + colors32[11].rgb565(), +}; + +static void drm_draw_color_bar_rgb888(Framebuffer& buf, int old_xpos, int xpos, int width) +{ + for (unsigned y = 0; y < buf.height(); ++y) { + RGB bcol = colors32[y * ARRAY_SIZE(colors32) / buf.height()]; + uint32_t *line = (uint32_t*)(buf.map(0) + buf.stride(0) * y); + + if (old_xpos >= 0) { + for (int x = old_xpos; x < old_xpos + width; ++x) + line[x] = 0; + } + + for (int x = xpos; x < xpos + width; ++x) + line[x] = bcol.raw; + } +} + +static void drm_draw_color_bar_rgb565(Framebuffer& buf, int old_xpos, int xpos, int width) +{ + static_assert(ARRAY_SIZE(colors32) == ARRAY_SIZE(colors16), "bad colors arrays"); + + for (unsigned y = 0; y < buf.height(); ++y) { + uint16_t bcol = colors16[y * ARRAY_SIZE(colors16) / buf.height()]; + uint16_t *line = (uint16_t*)(buf.map(0) + buf.stride(0) * y); + + if (old_xpos >= 0) { + for (int x = old_xpos; x < old_xpos + width; ++x) + line[x] = 0; + } + + for (int x = xpos; x < xpos + width; ++x) + line[x] = bcol; + } +} + +static void drm_draw_color_bar_semiplanar_yuv(Framebuffer& buf, int old_xpos, int xpos, int width) +{ + const uint8_t colors[] = { + 0xff, + 0x00, + 0xff, + 0x20, + 0xff, + 0x40, + 0xff, + 0x80, + 0xff, + }; + + for (unsigned y = 0; y < buf.height(); ++y) { + unsigned int bcol = colors[y * ARRAY_SIZE(colors) / buf.height()]; + uint8_t *line = (uint8_t*)(buf.map(0) + buf.stride(0) * y); + + if (old_xpos >= 0) { + for (int x = old_xpos; x < old_xpos + width; ++x) + line[x] = 0; + } + + for (int x = xpos; x < xpos + width; ++x) + line[x] = bcol; + } +} + +static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width) +{ + switch (buf.format()) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + // XXX not right but gets something on the screen + drm_draw_color_bar_semiplanar_yuv(buf, old_xpos, xpos, width); + break; + + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + // XXX not right but gets something on the screen + drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width); + break; + + case DRM_FORMAT_RGB565: + drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width); + break; + + case DRM_FORMAT_XRGB8888: + drm_draw_color_bar_rgb888(buf, old_xpos, xpos, width); + break; + + default: + ASSERT(false); + } +} |