From f902b289c2a3956176fc328afb31ea4fc91f8984 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Sat, 16 Apr 2016 22:16:44 +0300 Subject: [PATCH] kmscube: split into parts --- kmscube/CMakeLists.txt | 9 +- kmscube/cube-egl.cpp | 95 ++++ kmscube/cube-egl.h | 34 ++ kmscube/cube-gbm.cpp | 398 +++++++++++++ kmscube/cube-gles2.cpp | 264 +++++++++ kmscube/cube-gles2.h | 22 + kmscube/cube-null.cpp | 36 ++ kmscube/cube-wl.cpp | 122 ++++ kmscube/cube-x11.cpp | 67 +++ kmscube/cube.cpp | 69 +++ kmscube/cube.h | 103 +--- kmscube/esTransform.c | 2 +- kmscube/{esUtil.h => esTransform.h} | 0 kmscube/kmscube.cpp | 830 ---------------------------- 14 files changed, 1123 insertions(+), 928 deletions(-) create mode 100644 kmscube/cube-egl.cpp create mode 100644 kmscube/cube-egl.h create mode 100644 kmscube/cube-gbm.cpp create mode 100644 kmscube/cube-gles2.cpp create mode 100644 kmscube/cube-gles2.h create mode 100644 kmscube/cube-null.cpp create mode 100644 kmscube/cube-wl.cpp create mode 100644 kmscube/cube-x11.cpp create mode 100644 kmscube/cube.cpp rename kmscube/{esUtil.h => esTransform.h} (100%) delete mode 100644 kmscube/kmscube.cpp diff --git a/kmscube/CMakeLists.txt b/kmscube/CMakeLists.txt index 9c1a9d6..15b4dbf 100644 --- a/kmscube/CMakeLists.txt +++ b/kmscube/CMakeLists.txt @@ -5,6 +5,9 @@ pkg_check_modules(GBM gbm REQUIRED) pkg_check_modules(X11 x11 REQUIRED) pkg_check_modules(XCB xcb REQUIRED) pkg_check_modules(X11XCB x11-xcb REQUIRED) +pkg_check_modules(WL wayland-client REQUIRED) +pkg_check_modules(WL_EGL wayland-egl REQUIRED) + include_directories( ${LIBDRM_INCLUDE_DIRS} @@ -26,7 +29,9 @@ link_directories( ${X11XCB_LIBRARY_DIRS} ) -add_executable (kmscube kmscube.cpp esTransform.c esUtil.h cube.h) +add_executable (kmscube cube.cpp cube.h cube-egl.cpp cube-egl.h cube-gles2.cpp cube-gles2.h + cube-null.cpp cube-gbm.cpp cube-x11.cpp cube-wl.cpp + esTransform.c esTransform.h) target_link_libraries(kmscube kms++ kmstest ${LIBDRM_LIBRARIES} ${GLESv2_LIBRARIES} @@ -35,4 +40,6 @@ target_link_libraries(kmscube kms++ kmstest ${X11_LIBRARIES} ${XCB_LIBRARIES} ${X11XCB_LIBRARIES} + ${WL_LIBRARIES} + ${WL_EGL_LIBRARIES} ) diff --git a/kmscube/cube-egl.cpp b/kmscube/cube-egl.cpp new file mode 100644 index 0000000..4213536 --- /dev/null +++ b/kmscube/cube-egl.cpp @@ -0,0 +1,95 @@ +#include "cube-egl.h" +#include "cube.h" + +#include "test.h" + +using namespace std; + +EglState::EglState(void *native_display) +{ + EGLBoolean b; + EGLint major, minor, n; + + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + static const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + m_display = eglGetDisplay((EGLNativeDisplayType)native_display); + FAIL_IF(!m_display, "failed to get egl display"); + + b = eglInitialize(m_display, &major, &minor); + FAIL_IF(!b, "failed to initialize"); + + if (s_verbose) { + printf("Using display %p with EGL version %d.%d\n", m_display, major, minor); + + printf("EGL_VENDOR: %s\n", eglQueryString(m_display, EGL_VENDOR)); + printf("EGL_VERSION: %s\n", eglQueryString(m_display, EGL_VERSION)); + printf("EGL_EXTENSIONS: %s\n", eglQueryString(m_display, EGL_EXTENSIONS)); + printf("EGL_CLIENT_APIS: %s\n", eglQueryString(m_display, EGL_CLIENT_APIS)); + } + + b = eglBindAPI(EGL_OPENGL_ES_API); + FAIL_IF(!b, "failed to bind api EGL_OPENGL_ES_API"); + + b = eglChooseConfig(m_display, config_attribs, &m_config, 1, &n); + FAIL_IF(!b || n != 1, "failed to choose config"); + + auto getconf = [this](EGLint a) { EGLint v = -1; eglGetConfigAttrib(m_display, m_config, a, &v); return v; }; + + if (s_verbose) { + printf("EGL Config %d: color buf %d/%d/%d/%d = %d, depth %d, stencil %d\n", + getconf(EGL_CONFIG_ID), + getconf(EGL_ALPHA_SIZE), + getconf(EGL_RED_SIZE), + getconf(EGL_GREEN_SIZE), + getconf(EGL_BLUE_SIZE), + getconf(EGL_BUFFER_SIZE), + getconf(EGL_DEPTH_SIZE), + getconf(EGL_STENCIL_SIZE)); + } + + m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs); + FAIL_IF(!m_context, "failed to create context"); + + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_context); +} + +EglState::~EglState() +{ + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(m_display); +} + +EglSurface::EglSurface(const EglState &egl, void *native_window) + : egl(egl) +{ + esurface = eglCreateWindowSurface(egl.display(), egl.config(), (EGLNativeWindowType)native_window, NULL); + FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface"); +} + +EglSurface::~EglSurface() +{ + eglDestroySurface(egl.display(), esurface); +} + +void EglSurface::make_current() +{ + eglMakeCurrent(egl.display(), esurface, esurface, egl.context()); +} + +void EglSurface::swap_buffers() +{ + eglSwapBuffers(egl.display(), esurface); +} diff --git a/kmscube/cube-egl.h b/kmscube/cube-egl.h new file mode 100644 index 0000000..a7de103 --- /dev/null +++ b/kmscube/cube-egl.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +class EglState +{ +public: + EglState(void *native_display); + ~EglState(); + + EGLDisplay display() const { return m_display; } + EGLConfig config() const { return m_config; } + EGLContext context() const { return m_context; } + +private: + EGLDisplay m_display; + EGLConfig m_config; + EGLContext m_context; +}; + +class EglSurface +{ +public: + EglSurface(const EglState& egl, void *native_window); + ~EglSurface(); + + void make_current(); + void swap_buffers(); + +private: + const EglState& egl; + + EGLSurface esurface; +}; diff --git a/kmscube/cube-gbm.cpp b/kmscube/cube-gbm.cpp new file mode 100644 index 0000000..a65f693 --- /dev/null +++ b/kmscube/cube-gbm.cpp @@ -0,0 +1,398 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "test.h" +#include "cube-egl.h" +#include "cube-gles2.h" + +using namespace kms; +using namespace std; + +static int s_flip_pending; +static bool s_need_exit; + +static bool s_support_planes; + +class GbmDevice +{ +public: + GbmDevice(Card& card) + { + m_dev = gbm_create_device(card.fd()); + FAIL_IF(!m_dev, "failed to create gbm device"); + } + + ~GbmDevice() + { + gbm_device_destroy(m_dev); + } + + GbmDevice(const GbmDevice& other) = delete; + GbmDevice& operator=(const GbmDevice& other) = delete; + + struct gbm_device* handle() const { return m_dev; } + +private: + struct gbm_device* m_dev; +}; + +class GbmSurface +{ +public: + GbmSurface(GbmDevice& gdev, int width, int height) + { + m_surface = gbm_surface_create(gdev.handle(), width, height, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + FAIL_IF(!m_surface, "failed to create gbm surface"); + } + + ~GbmSurface() + { + gbm_surface_destroy(m_surface); + } + + GbmSurface(const GbmSurface& other) = delete; + GbmSurface& operator=(const GbmSurface& other) = delete; + + bool has_free() + { + return gbm_surface_has_free_buffers(m_surface); + } + + gbm_bo* lock_front_buffer() + { + return gbm_surface_lock_front_buffer(m_surface); + } + + void release_buffer(gbm_bo *bo) + { + gbm_surface_release_buffer(m_surface, bo); + } + + struct gbm_surface* handle() const { return m_surface; } + +private: + struct gbm_surface* m_surface; +}; + +class GbmEglSurface +{ +public: + GbmEglSurface(Card& card, GbmDevice& gdev, const EglState& egl, int width, int height) + : card(card), gdev(gdev), egl(egl), m_width(width), m_height(height), + bo_prev(0), bo_next(0) + { + gsurface = unique_ptr(new GbmSurface(gdev, width, height)); + esurface = eglCreateWindowSurface(egl.display(), egl.config(), gsurface->handle(), NULL); + FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface"); + } + + ~GbmEglSurface() + { + if (bo_next) + gsurface->release_buffer(bo_next); + eglDestroySurface(egl.display(), esurface); + } + + void make_current() + { + FAIL_IF(!gsurface->has_free(), "No free buffers"); + + eglMakeCurrent(egl.display(), esurface, esurface, egl.context()); + } + + void swap_buffers() + { + eglSwapBuffers(egl.display(), esurface); + } + + static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) + { + auto fb = reinterpret_cast(data); + delete fb; + } + + static Framebuffer* drm_fb_get_from_bo(struct gbm_bo *bo, Card& card) + { + auto fb = reinterpret_cast(gbm_bo_get_user_data(bo)); + if (fb) + return fb; + + uint32_t width = gbm_bo_get_width(bo); + uint32_t height = gbm_bo_get_height(bo); + uint32_t stride = gbm_bo_get_stride(bo); + uint32_t handle = gbm_bo_get_handle(bo).u32; + + fb = new ExtFramebuffer(card, width, height, 24, 32, stride, handle); + + gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); + + return fb; + } + + struct Framebuffer* lock_next() + { + bo_prev = bo_next; + bo_next = gsurface->lock_front_buffer(); + FAIL_IF(!bo_next, "could not lock gbm buffer"); + return drm_fb_get_from_bo(bo_next, card); + } + + void free_prev() + { + if (bo_prev) { + gsurface->release_buffer(bo_prev); + bo_prev = 0; + } + } + + uint32_t width() const { return m_width; } + uint32_t height() const { return m_height; } + +private: + Card& card; + GbmDevice& gdev; + const EglState& egl; + + unique_ptr gsurface; + EGLSurface esurface; + + int m_width; + int m_height; + + struct gbm_bo* bo_prev; + struct gbm_bo* bo_next; +}; + +class OutputHandler : private PageFlipHandlerBase +{ +public: + OutputHandler(Card& card, GbmDevice& gdev, const EglState& egl, Connector* connector, Crtc* crtc, Videomode& mode, Plane* plane, float rotation_mult) + : m_frame_num(0), m_connector(connector), m_crtc(crtc), m_plane(plane), m_mode(mode), + m_rotation_mult(rotation_mult) + { + m_surface1 = unique_ptr(new GbmEglSurface(card, gdev, egl, mode.hdisplay, mode.vdisplay)); + m_scene1 = unique_ptr(new GlScene()); + m_scene1->set_viewport(m_surface1->width(), m_surface1->height()); + + if (m_plane) { + m_surface2 = unique_ptr(new GbmEglSurface(card, gdev, egl, 400, 400)); + m_scene2 = unique_ptr(new GlScene()); + m_scene2->set_viewport(m_surface2->width(), m_surface2->height()); + } + } + + OutputHandler(const OutputHandler& other) = delete; + OutputHandler& operator=(const OutputHandler& other) = delete; + + void setup() + { + int ret; + + m_surface1->make_current(); + m_surface1->swap_buffers(); + struct Framebuffer* fb = m_surface1->lock_next(); + + struct Framebuffer* planefb = 0; + + if (m_plane) { + m_surface2->make_current(); + m_surface2->swap_buffers(); + planefb = m_surface2->lock_next(); + } + + + ret = m_crtc->set_mode(m_connector, *fb, m_mode); + FAIL_IF(ret, "failed to set mode"); + + if (m_crtc->card().has_atomic()) { + Plane* root_plane = 0; + for (Plane* p : m_crtc->get_possible_planes()) { + if (p->crtc_id() == m_crtc->id()) { + root_plane = p; + break; + } + } + + FAIL_IF(!root_plane, "No primary plane for crtc %d", m_crtc->id()); + + m_root_plane = root_plane; + } + + if (m_plane) { + ret = m_crtc->set_plane(m_plane, *planefb, + 0, 0, planefb->width(), planefb->height(), + 0, 0, planefb->width(), planefb->height()); + FAIL_IF(ret, "failed to set plane"); + } + } + + void start_flipping() + { + m_t1 = chrono::steady_clock::now(); + queue_next(); + } + +private: + void handle_page_flip(uint32_t frame, double time) + { + ++m_frame_num; + + if (m_frame_num % 100 == 0) { + auto t2 = chrono::steady_clock::now(); + chrono::duration fsec = t2 - m_t1; + printf("fps: %f\n", 100.0 / fsec.count()); + m_t1 = t2; + } + + s_flip_pending--; + + m_surface1->free_prev(); + if (m_plane) + m_surface2->free_prev(); + + if (s_need_exit) + return; + + queue_next(); + } + + void queue_next() + { + m_surface1->make_current(); + m_scene1->draw(m_frame_num * m_rotation_mult); + m_surface1->swap_buffers(); + struct Framebuffer* fb = m_surface1->lock_next(); + + struct Framebuffer* planefb = 0; + + if (m_plane) { + m_surface2->make_current(); + m_scene2->draw(m_frame_num * m_rotation_mult * 2); + m_surface2->swap_buffers(); + planefb = m_surface2->lock_next(); + } + + if (m_crtc->card().has_atomic()) { + int r; + + AtomicReq req(m_crtc->card()); + + req.add(m_root_plane, "FB_ID", fb->id()); + if (m_plane) + req.add(m_plane, "FB_ID", planefb->id()); + + r = req.test(); + FAIL_IF(r, "atomic test failed"); + + r = req.commit(this); + FAIL_IF(r, "atomic commit failed"); + } else { + int ret; + + ret = m_crtc->page_flip(*fb, this); + FAIL_IF(ret, "failed to queue page flip"); + + if (m_plane) { + ret = m_crtc->set_plane(m_plane, *planefb, + 0, 0, planefb->width(), planefb->height(), + 0, 0, planefb->width(), planefb->height()); + FAIL_IF(ret, "failed to set plane"); + } + } + + s_flip_pending++; + } + + int m_frame_num; + chrono::steady_clock::time_point m_t1; + + Connector* m_connector; + Crtc* m_crtc; + Plane* m_plane; + Videomode m_mode; + Plane* m_root_plane; + + unique_ptr m_surface1; + unique_ptr m_surface2; + + unique_ptr m_scene1; + unique_ptr m_scene2; + + float m_rotation_mult; +}; + +void main_gbm() +{ + Card card; + + GbmDevice gdev(card); + EglState egl(gdev.handle()); + + vector> outputs; + vector used_planes; + + float rot_mult = 1; + + for (auto pipe : card.get_connected_pipelines()) { + auto connector = pipe.connector; + auto crtc = pipe.crtc; + auto mode = connector->get_default_mode(); + + Plane* plane = 0; + + if (s_support_planes) { + for (Plane* p : crtc->get_possible_planes()) { + if (find(used_planes.begin(), used_planes.end(), p) != used_planes.end()) + continue; + + if (p->plane_type() != PlaneType::Overlay) + continue; + + plane = p; + break; + } + } + + if (plane) + used_planes.push_back(plane); + + auto out = new OutputHandler(card, gdev, egl, connector, crtc, mode, plane, rot_mult); + outputs.emplace_back(out); + + rot_mult *= 1.33; + } + + for (auto& out : outputs) + out->setup(); + + for (auto& out : outputs) + out->start_flipping(); + + struct pollfd fds[2] = { 0 }; + fds[0].fd = 0; + fds[0].events = POLLIN; + fds[1].fd = card.fd(); + fds[1].events = POLLIN; + + while (!s_need_exit || s_flip_pending) { + int r = poll(fds, ARRAY_SIZE(fds), -1); + FAIL_IF(r < 0, "poll error %d", r); + + if (fds[0].revents) + s_need_exit = true; + + if (fds[1].revents) + card.call_page_flip_handlers(); + } +} diff --git a/kmscube/cube-gles2.cpp b/kmscube/cube-gles2.cpp new file mode 100644 index 0000000..68b3831 --- /dev/null +++ b/kmscube/cube-gles2.cpp @@ -0,0 +1,264 @@ +#include "esTransform.h" +#include "cube-gles2.h" +#include "cube.h" + +#include "test.h" + +using namespace std; + +GlScene::GlScene() +{ + GLuint vertex_shader, fragment_shader; + GLint ret; + + static const GLfloat vVertices[] = { + // front + -1.0f, -1.0f, +1.0f, // point blue + +1.0f, -1.0f, +1.0f, // point magenta + -1.0f, +1.0f, +1.0f, // point cyan + +1.0f, +1.0f, +1.0f, // point white + // back + +1.0f, -1.0f, -1.0f, // point red + -1.0f, -1.0f, -1.0f, // point black + +1.0f, +1.0f, -1.0f, // point yellow + -1.0f, +1.0f, -1.0f, // point green + // right + +1.0f, -1.0f, +1.0f, // point magenta + +1.0f, -1.0f, -1.0f, // point red + +1.0f, +1.0f, +1.0f, // point white + +1.0f, +1.0f, -1.0f, // point yellow + // left + -1.0f, -1.0f, -1.0f, // point black + -1.0f, -1.0f, +1.0f, // point blue + -1.0f, +1.0f, -1.0f, // point green + -1.0f, +1.0f, +1.0f, // point cyan + // top + -1.0f, +1.0f, +1.0f, // point cyan + +1.0f, +1.0f, +1.0f, // point white + -1.0f, +1.0f, -1.0f, // point green + +1.0f, +1.0f, -1.0f, // point yellow + // bottom + -1.0f, -1.0f, -1.0f, // point black + +1.0f, -1.0f, -1.0f, // point red + -1.0f, -1.0f, +1.0f, // point blue + +1.0f, -1.0f, +1.0f // point magenta + }; + + static const GLfloat vColors[] = { + // front + 0.0f, 0.0f, 1.0f, // blue + 1.0f, 0.0f, 1.0f, // magenta + 0.0f, 1.0f, 1.0f, // cyan + 1.0f, 1.0f, 1.0f, // white + // back + 1.0f, 0.0f, 0.0f, // red + 0.0f, 0.0f, 0.0f, // black + 1.0f, 1.0f, 0.0f, // yellow + 0.0f, 1.0f, 0.0f, // green + // right + 1.0f, 0.0f, 1.0f, // magenta + 1.0f, 0.0f, 0.0f, // red + 1.0f, 1.0f, 1.0f, // white + 1.0f, 1.0f, 0.0f, // yellow + // left + 0.0f, 0.0f, 0.0f, // black + 0.0f, 0.0f, 1.0f, // blue + 0.0f, 1.0f, 0.0f, // green + 0.0f, 1.0f, 1.0f, // cyan + // top + 0.0f, 1.0f, 1.0f, // cyan + 1.0f, 1.0f, 1.0f, // white + 0.0f, 1.0f, 0.0f, // green + 1.0f, 1.0f, 0.0f, // yellow + // bottom + 0.0f, 0.0f, 0.0f, // black + 1.0f, 0.0f, 0.0f, // red + 0.0f, 0.0f, 1.0f, // blue + 1.0f, 0.0f, 1.0f // magenta + }; + + static const GLfloat vNormals[] = { + // front + +0.0f, +0.0f, +1.0f, // forward + +0.0f, +0.0f, +1.0f, // forward + +0.0f, +0.0f, +1.0f, // forward + +0.0f, +0.0f, +1.0f, // forward + // back + +0.0f, +0.0f, -1.0f, // backbard + +0.0f, +0.0f, -1.0f, // backbard + +0.0f, +0.0f, -1.0f, // backbard + +0.0f, +0.0f, -1.0f, // backbard + // right + +1.0f, +0.0f, +0.0f, // right + +1.0f, +0.0f, +0.0f, // right + +1.0f, +0.0f, +0.0f, // right + +1.0f, +0.0f, +0.0f, // right + // left + -1.0f, +0.0f, +0.0f, // left + -1.0f, +0.0f, +0.0f, // left + -1.0f, +0.0f, +0.0f, // left + -1.0f, +0.0f, +0.0f, // left + // top + +0.0f, +1.0f, +0.0f, // up + +0.0f, +1.0f, +0.0f, // up + +0.0f, +1.0f, +0.0f, // up + +0.0f, +1.0f, +0.0f, // up + // bottom + +0.0f, -1.0f, +0.0f, // down + +0.0f, -1.0f, +0.0f, // down + +0.0f, -1.0f, +0.0f, // down + +0.0f, -1.0f, +0.0f // down + }; + + static const char *vertex_shader_source = + "uniform mat4 modelviewMatrix; \n" + "uniform mat4 modelviewprojectionMatrix;\n" + "uniform mat3 normalMatrix; \n" + " \n" + "attribute vec4 in_position; \n" + "attribute vec3 in_normal; \n" + "attribute vec4 in_color; \n" + "\n" + "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n" + " \n" + "varying vec4 vVaryingColor; \n" + " \n" + "void main() \n" + "{ \n" + " gl_Position = modelviewprojectionMatrix * in_position;\n" + " vec3 vEyeNormal = normalMatrix * in_normal;\n" + " vec4 vPosition4 = modelviewMatrix * in_position;\n" + " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n" + " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n" + " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n" + " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n" + "} \n"; + + static const char *fragment_shader_source = + "precision mediump float; \n" + " \n" + "varying vec4 vVaryingColor; \n" + " \n" + "void main() \n" + "{ \n" + " gl_FragColor = vVaryingColor; \n" + "} \n"; + + + if (s_verbose) { + printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); + printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); + printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); + printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); + } + + vertex_shader = glCreateShader(GL_VERTEX_SHADER); + + glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); + glCompileShader(vertex_shader); + + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret); + FAIL_IF(!ret, "vertex shader compilation failed!"); + + fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); + glCompileShader(fragment_shader); + + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret); + FAIL_IF(!ret, "fragment shader compilation failed!"); + + GLuint program = glCreateProgram(); + + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + + glBindAttribLocation(program, 0, "in_position"); + glBindAttribLocation(program, 1, "in_normal"); + glBindAttribLocation(program, 2, "in_color"); + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &ret); + FAIL_IF(!ret, "program linking failed!"); + + glUseProgram(program); + + m_modelviewmatrix = glGetUniformLocation(program, "modelviewMatrix"); + m_modelviewprojectionmatrix = glGetUniformLocation(program, "modelviewprojectionMatrix"); + m_normalmatrix = glGetUniformLocation(program, "normalMatrix"); + + glEnable(GL_CULL_FACE); + + GLintptr positionsoffset = 0; + GLintptr colorsoffset = sizeof(vVertices); + GLintptr normalsoffset = sizeof(vVertices) + sizeof(vColors); + GLuint vbo; + + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, positionsoffset, sizeof(vVertices), &vVertices[0]); + glBufferSubData(GL_ARRAY_BUFFER, colorsoffset, sizeof(vColors), &vColors[0]); + glBufferSubData(GL_ARRAY_BUFFER, normalsoffset, sizeof(vNormals), &vNormals[0]); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)positionsoffset); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)normalsoffset); + glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)colorsoffset); + glEnableVertexAttribArray(2); +} + +void GlScene::set_viewport(uint32_t width, uint32_t height) +{ + m_width = width; + m_height = height; +} + +void GlScene::draw(uint32_t framenum) +{ + glViewport(0, 0, m_width, m_height); + + glClearColor(0.5, 0.5, 0.5, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + ESMatrix modelview; + + esMatrixLoadIdentity(&modelview); + esTranslate(&modelview, 0.0f, 0.0f, -8.0f); + esRotate(&modelview, 45.0f + (0.75f * framenum), 1.0f, 0.0f, 0.0f); + esRotate(&modelview, 45.0f - (0.5f * framenum), 0.0f, 1.0f, 0.0f); + esRotate(&modelview, 10.0f + (0.45f * framenum), 0.0f, 0.0f, 1.0f); + + GLfloat aspect = (float)m_height / m_width; + + ESMatrix projection; + esMatrixLoadIdentity(&projection); + esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f); + + ESMatrix modelviewprojection; + esMatrixLoadIdentity(&modelviewprojection); + esMatrixMultiply(&modelviewprojection, &modelview, &projection); + + float normal[9]; + normal[0] = modelview.m[0][0]; + normal[1] = modelview.m[0][1]; + normal[2] = modelview.m[0][2]; + normal[3] = modelview.m[1][0]; + normal[4] = modelview.m[1][1]; + normal[5] = modelview.m[1][2]; + normal[6] = modelview.m[2][0]; + normal[7] = modelview.m[2][1]; + normal[8] = modelview.m[2][2]; + + glUniformMatrix4fv(m_modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]); + glUniformMatrix4fv(m_modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]); + glUniformMatrix3fv(m_normalmatrix, 1, GL_FALSE, normal); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); + glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); +} diff --git a/kmscube/cube-gles2.h b/kmscube/cube-gles2.h new file mode 100644 index 0000000..983c133 --- /dev/null +++ b/kmscube/cube-gles2.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +class GlScene +{ +public: + GlScene(); + + GlScene(const GlScene& other) = delete; + GlScene& operator=(const GlScene& other) = delete; + + void set_viewport(uint32_t width, uint32_t height); + + void draw(uint32_t framenum); + +private: + GLint m_modelviewmatrix, m_modelviewprojectionmatrix, m_normalmatrix; + + uint32_t m_width; + uint32_t m_height; +}; diff --git a/kmscube/cube-null.cpp b/kmscube/cube-null.cpp new file mode 100644 index 0000000..42f2ac2 --- /dev/null +++ b/kmscube/cube-null.cpp @@ -0,0 +1,36 @@ +#include + +#include "cube-egl.h" +#include "cube-gles2.h" +#include "cube.h" + +#include "test.h" + +using namespace std; + +void main_null() +{ + EglState egl(EGL_DEFAULT_DISPLAY); + EglSurface surface(egl, 0); + GlScene scene; + + scene.set_viewport(600, 600); + + int framenum = 0; + + struct pollfd fds[1] = { 0 }; + fds[0].fd = 0; + fds[0].events = POLLIN; + + while (true) { + int r = poll(fds, ARRAY_SIZE(fds), 0); + ASSERT(r >= 0); + + if (fds[0].revents) + break; + + surface.make_current(); + scene.draw(framenum++); + surface.swap_buffers(); + } +} diff --git a/kmscube/cube-wl.cpp b/kmscube/cube-wl.cpp new file mode 100644 index 0000000..c8dfa56 --- /dev/null +++ b/kmscube/cube-wl.cpp @@ -0,0 +1,122 @@ + +#include +#include + +#include +#include + +#include + +static struct wl_compositor *s_compositor = NULL; +static struct wl_shell *s_shell = NULL; +static EGLDisplay s_egl_display; +static char s_running = 1; + +struct window { + EGLContext egl_context; + struct wl_surface *surface; + struct wl_shell_surface *shell_surface; + struct wl_egl_window *egl_window; + EGLSurface egl_surface; +}; + +// listeners +static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) +{ + if (!strcmp(interface, "wl_compositor")) + s_compositor = (struct wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 0); + else if (!strcmp(interface, "wl_shell")) + s_shell = (struct wl_shell*)wl_registry_bind(registry, name, &wl_shell_interface, 0); +} + +static void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name) +{ + +} + +static struct wl_registry_listener registry_listener = { ®istry_add_object, ®istry_remove_object }; + +static void shell_surface_ping(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void shell_surface_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) +{ + struct window *window = (struct window*)data; + + wl_egl_window_resize(window->egl_window, width, height, 0, 0); +} + +static void shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface) +{ + +} + +static struct wl_shell_surface_listener shell_surface_listener = { &shell_surface_ping, &shell_surface_configure, &shell_surface_popup_done }; + +static void create_window(struct window *window, int32_t width, int32_t height) +{ + eglBindAPI(EGL_OPENGL_API); + EGLint attributes[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_NONE + }; + EGLConfig config; + EGLint num_config; + eglChooseConfig(s_egl_display, attributes, &config, 1, &num_config); + window->egl_context = eglCreateContext(s_egl_display, config, EGL_NO_CONTEXT, NULL); + + window->surface = wl_compositor_create_surface(s_compositor); + window->shell_surface = wl_shell_get_shell_surface(s_shell, window->surface); + wl_shell_surface_add_listener(window->shell_surface, &shell_surface_listener, window); + wl_shell_surface_set_toplevel(window->shell_surface); + window->egl_window = wl_egl_window_create(window->surface, width, height); + window->egl_surface = eglCreateWindowSurface(s_egl_display, config, window->egl_window, NULL); + eglMakeCurrent(s_egl_display, window->egl_surface, window->egl_surface, window->egl_context); +} + +static void delete_window(struct window *window) +{ + eglDestroySurface(s_egl_display, window->egl_surface); + wl_egl_window_destroy(window->egl_window); + wl_shell_surface_destroy(window->shell_surface); + wl_surface_destroy(window->surface); + eglDestroyContext(s_egl_display, window->egl_context); +} + +static void draw_window(struct window *window) +{ + glClearColor(0.0, 1.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + eglSwapBuffers(s_egl_display, window->egl_surface); +} + +int main_wl() +{ + struct wl_display *display = wl_display_connect(NULL); + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_roundtrip(display); + + s_egl_display = eglGetDisplay(display); + eglInitialize(s_egl_display, NULL, NULL); + + uint32_t width = 600; + uint32_t height = 600; + + struct window window; + create_window(&window, width, height); + + while (s_running) { + wl_display_dispatch_pending(display); + draw_window(&window); + } + + delete_window(&window); + eglTerminate(s_egl_display); + wl_display_disconnect(display); + return 0; +} diff --git a/kmscube/cube-x11.cpp b/kmscube/cube-x11.cpp new file mode 100644 index 0000000..7f01ae8 --- /dev/null +++ b/kmscube/cube-x11.cpp @@ -0,0 +1,67 @@ + +#include + +#include "cube-egl.h" +#include "cube-gles2.h" + +#include "test.h" + +using namespace std; + +void main_x11() +{ + Display* display = XOpenDisplay(NULL); + + xcb_connection_t *connection = XGetXCBConnection(display); + + /* Get the first screen */ + const xcb_setup_t *setup = xcb_get_setup (connection); + xcb_screen_t *screen = xcb_setup_roots_iterator (setup).data; + + /* Create the window */ + + uint32_t width = 600; + uint32_t height = 600; + + const uint32_t xcb_window_attrib_mask = XCB_CW_EVENT_MASK; + const uint32_t xcb_window_attrib_list[] = { + XCB_EVENT_MASK_EXPOSURE, + }; + + xcb_window_t window = xcb_generate_id (connection); + xcb_create_window (connection, /* Connection */ + XCB_COPY_FROM_PARENT, /* depth (same as root)*/ + window, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + width, height, /* width, height */ + 0, /* border_width */ + XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ + screen->root_visual, /* visual */ + xcb_window_attrib_mask, + xcb_window_attrib_list); + + xcb_map_window (connection, window); + xcb_flush (connection); + + EglState egl(display); + EglSurface surface(egl, (void*)(uintptr_t)window); + GlScene scene; + + scene.set_viewport(width, height); + + int framenum = 0; + + surface.make_current(); + surface.swap_buffers(); + + xcb_generic_event_t *event; + while ( (event = xcb_poll_for_event (connection)) ) { + + surface.make_current(); + scene.draw(framenum++); + surface.swap_buffers(); + } + + xcb_disconnect (connection); +} diff --git a/kmscube/cube.cpp b/kmscube/cube.cpp new file mode 100644 index 0000000..14c340a --- /dev/null +++ b/kmscube/cube.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 Arvin Schnell + * Copyright (c) 2012 Rob Clark + * Copyright (c) 2015 Tomi Valkeinen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Based on a egl cube test app originally written by Arvin Schnell */ + +#include "cube.h" +#include "opts.h" +#include "test.h" + +using namespace std; + +bool s_verbose; + +int main(int argc, char *argv[]) +{ + OptionSet optionset = { + Option("v|verbose", + [&]() + { + s_verbose = true; + }), + }; + + optionset.parse(argc, argv); + + string m; + + if (optionset.params().size() == 0) + m = "gbm"; + else + m = optionset.params().front(); + + if (m == "gbm") + main_gbm(); + else if (m == "null") + main_null(); + else if (m == "x") + main_x11(); + else if (m == "wl") + main_wl(); + else { + printf("Unknown mode %s\n", m.c_str()); + return -1; + } + + return 0; +} diff --git a/kmscube/cube.h b/kmscube/cube.h index 9616c74..8245f0b 100644 --- a/kmscube/cube.h +++ b/kmscube/cube.h @@ -1,98 +1,9 @@ -static const GLfloat vVertices[] = { - // front - -1.0f, -1.0f, +1.0f, // point blue - +1.0f, -1.0f, +1.0f, // point magenta - -1.0f, +1.0f, +1.0f, // point cyan - +1.0f, +1.0f, +1.0f, // point white - // back - +1.0f, -1.0f, -1.0f, // point red - -1.0f, -1.0f, -1.0f, // point black - +1.0f, +1.0f, -1.0f, // point yellow - -1.0f, +1.0f, -1.0f, // point green - // right - +1.0f, -1.0f, +1.0f, // point magenta - +1.0f, -1.0f, -1.0f, // point red - +1.0f, +1.0f, +1.0f, // point white - +1.0f, +1.0f, -1.0f, // point yellow - // left - -1.0f, -1.0f, -1.0f, // point black - -1.0f, -1.0f, +1.0f, // point blue - -1.0f, +1.0f, -1.0f, // point green - -1.0f, +1.0f, +1.0f, // point cyan - // top - -1.0f, +1.0f, +1.0f, // point cyan - +1.0f, +1.0f, +1.0f, // point white - -1.0f, +1.0f, -1.0f, // point green - +1.0f, +1.0f, -1.0f, // point yellow - // bottom - -1.0f, -1.0f, -1.0f, // point black - +1.0f, -1.0f, -1.0f, // point red - -1.0f, -1.0f, +1.0f, // point blue - +1.0f, -1.0f, +1.0f // point magenta -}; +#pragma once -static const GLfloat vColors[] = { - // front - 0.0f, 0.0f, 1.0f, // blue - 1.0f, 0.0f, 1.0f, // magenta - 0.0f, 1.0f, 1.0f, // cyan - 1.0f, 1.0f, 1.0f, // white - // back - 1.0f, 0.0f, 0.0f, // red - 0.0f, 0.0f, 0.0f, // black - 1.0f, 1.0f, 0.0f, // yellow - 0.0f, 1.0f, 0.0f, // green - // right - 1.0f, 0.0f, 1.0f, // magenta - 1.0f, 0.0f, 0.0f, // red - 1.0f, 1.0f, 1.0f, // white - 1.0f, 1.0f, 0.0f, // yellow - // left - 0.0f, 0.0f, 0.0f, // black - 0.0f, 0.0f, 1.0f, // blue - 0.0f, 1.0f, 0.0f, // green - 0.0f, 1.0f, 1.0f, // cyan - // top - 0.0f, 1.0f, 1.0f, // cyan - 1.0f, 1.0f, 1.0f, // white - 0.0f, 1.0f, 0.0f, // green - 1.0f, 1.0f, 0.0f, // yellow - // bottom - 0.0f, 0.0f, 0.0f, // black - 1.0f, 0.0f, 0.0f, // red - 0.0f, 0.0f, 1.0f, // blue - 1.0f, 0.0f, 1.0f // magenta -}; +extern bool s_verbose; + +void main_null(); +void main_gbm(); +void main_x11(); +void main_wl(); -static const GLfloat vNormals[] = { - // front - +0.0f, +0.0f, +1.0f, // forward - +0.0f, +0.0f, +1.0f, // forward - +0.0f, +0.0f, +1.0f, // forward - +0.0f, +0.0f, +1.0f, // forward - // back - +0.0f, +0.0f, -1.0f, // backbard - +0.0f, +0.0f, -1.0f, // backbard - +0.0f, +0.0f, -1.0f, // backbard - +0.0f, +0.0f, -1.0f, // backbard - // right - +1.0f, +0.0f, +0.0f, // right - +1.0f, +0.0f, +0.0f, // right - +1.0f, +0.0f, +0.0f, // right - +1.0f, +0.0f, +0.0f, // right - // left - -1.0f, +0.0f, +0.0f, // left - -1.0f, +0.0f, +0.0f, // left - -1.0f, +0.0f, +0.0f, // left - -1.0f, +0.0f, +0.0f, // left - // top - +0.0f, +1.0f, +0.0f, // up - +0.0f, +1.0f, +0.0f, // up - +0.0f, +1.0f, +0.0f, // up - +0.0f, +1.0f, +0.0f, // up - // bottom - +0.0f, -1.0f, +0.0f, // down - +0.0f, -1.0f, +0.0f, // down - +0.0f, -1.0f, +0.0f, // down - +0.0f, -1.0f, +0.0f // down -}; diff --git a/kmscube/esTransform.c b/kmscube/esTransform.c index e3e30e4..899c038 100644 --- a/kmscube/esTransform.c +++ b/kmscube/esTransform.c @@ -40,7 +40,7 @@ /// // Includes // -#include "esUtil.h" +#include "esTransform.h" #include #include diff --git a/kmscube/esUtil.h b/kmscube/esTransform.h similarity index 100% rename from kmscube/esUtil.h rename to kmscube/esTransform.h diff --git a/kmscube/kmscube.cpp b/kmscube/kmscube.cpp deleted file mode 100644 index e9145c9..0000000 --- a/kmscube/kmscube.cpp +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Copyright (c) 2012 Arvin Schnell - * Copyright (c) 2012 Rob Clark - * Copyright (c) 2015 Tomi Valkeinen - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* Based on a egl cube test app originally written by Arvin Schnell */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "esUtil.h" - -#include -#include "test.h" -#include "opts.h" - -using namespace kms; -using namespace std; - -static bool s_verbose; -static int s_flip_pending; -static bool s_need_exit; - -static bool s_support_planes; - -class GbmDevice -{ -public: - GbmDevice(Card& card) - { - m_dev = gbm_create_device(card.fd()); - FAIL_IF(!m_dev, "failed to create gbm device"); - } - - ~GbmDevice() - { - gbm_device_destroy(m_dev); - } - - GbmDevice(const GbmDevice& other) = delete; - GbmDevice& operator=(const GbmDevice& other) = delete; - - struct gbm_device* handle() const { return m_dev; } - -private: - struct gbm_device* m_dev; -}; - -class GbmSurface -{ -public: - GbmSurface(GbmDevice& gdev, int width, int height) - { - m_surface = gbm_surface_create(gdev.handle(), width, height, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - FAIL_IF(!m_surface, "failed to create gbm surface"); - } - - ~GbmSurface() - { - gbm_surface_destroy(m_surface); - } - - GbmSurface(const GbmSurface& other) = delete; - GbmSurface& operator=(const GbmSurface& other) = delete; - - bool has_free() - { - return gbm_surface_has_free_buffers(m_surface); - } - - gbm_bo* lock_front_buffer() - { - return gbm_surface_lock_front_buffer(m_surface); - } - - void release_buffer(gbm_bo *bo) - { - gbm_surface_release_buffer(m_surface, bo); - } - - struct gbm_surface* handle() const { return m_surface; } - -private: - struct gbm_surface* m_surface; -}; - -class EglState -{ -public: - EglState(EGLNativeDisplayType display_id) - { - EGLBoolean b; - EGLint major, minor, n; - - static const EGLint context_attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - static const EGLint config_attribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 0, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE - }; - - m_display = eglGetDisplay(display_id); - FAIL_IF(!m_display, "failed to get egl display"); - - b = eglInitialize(m_display, &major, &minor); - FAIL_IF(!b, "failed to initialize"); - - if (s_verbose) { - printf("Using display %p with EGL version %d.%d\n", m_display, major, minor); - - printf("EGL_VENDOR: %s\n", eglQueryString(m_display, EGL_VENDOR)); - printf("EGL_VERSION: %s\n", eglQueryString(m_display, EGL_VERSION)); - printf("EGL_EXTENSIONS: %s\n", eglQueryString(m_display, EGL_EXTENSIONS)); - printf("EGL_CLIENT_APIS: %s\n", eglQueryString(m_display, EGL_CLIENT_APIS)); - } - - b = eglBindAPI(EGL_OPENGL_ES_API); - FAIL_IF(!b, "failed to bind api EGL_OPENGL_ES_API"); - - b = eglChooseConfig(m_display, config_attribs, &m_config, 1, &n); - FAIL_IF(!b || n != 1, "failed to choose config"); - - auto getconf = [this](EGLint a) { EGLint v = -1; eglGetConfigAttrib(m_display, m_config, a, &v); return v; }; - - if (s_verbose) { - printf("EGL Config %d: color buf %d/%d/%d/%d = %d, depth %d, stencil %d\n", - getconf(EGL_CONFIG_ID), - getconf(EGL_ALPHA_SIZE), - getconf(EGL_RED_SIZE), - getconf(EGL_GREEN_SIZE), - getconf(EGL_BLUE_SIZE), - getconf(EGL_BUFFER_SIZE), - getconf(EGL_DEPTH_SIZE), - getconf(EGL_STENCIL_SIZE)); - } - - m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs); - FAIL_IF(!m_context, "failed to create context"); - - eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_context); - } - - ~EglState() - { - eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(m_display); - } - - EGLDisplay display() const { return m_display; } - EGLConfig config() const { return m_config; } - EGLContext context() const { return m_context; } - -private: - EGLDisplay m_display; - EGLConfig m_config; - EGLContext m_context; -}; - -class GlScene -{ -public: - GlScene() - { - GLuint vertex_shader, fragment_shader; - GLint ret; - -#include "cube.h" - - static const char *vertex_shader_source = - "uniform mat4 modelviewMatrix; \n" - "uniform mat4 modelviewprojectionMatrix;\n" - "uniform mat3 normalMatrix; \n" - " \n" - "attribute vec4 in_position; \n" - "attribute vec3 in_normal; \n" - "attribute vec4 in_color; \n" - "\n" - "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n" - " \n" - "varying vec4 vVaryingColor; \n" - " \n" - "void main() \n" - "{ \n" - " gl_Position = modelviewprojectionMatrix * in_position;\n" - " vec3 vEyeNormal = normalMatrix * in_normal;\n" - " vec4 vPosition4 = modelviewMatrix * in_position;\n" - " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n" - " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n" - " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n" - " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n" - "} \n"; - - static const char *fragment_shader_source = - "precision mediump float; \n" - " \n" - "varying vec4 vVaryingColor; \n" - " \n" - "void main() \n" - "{ \n" - " gl_FragColor = vVaryingColor; \n" - "} \n"; - - - if (s_verbose) { - printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); - printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); - printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); - printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); - } - - vertex_shader = glCreateShader(GL_VERTEX_SHADER); - - glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); - glCompileShader(vertex_shader); - - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret); - FAIL_IF(!ret, "vertex shader compilation failed!"); - - fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - - glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); - glCompileShader(fragment_shader); - - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret); - FAIL_IF(!ret, "fragment shader compilation failed!"); - - GLuint program = glCreateProgram(); - - glAttachShader(program, vertex_shader); - glAttachShader(program, fragment_shader); - - glBindAttribLocation(program, 0, "in_position"); - glBindAttribLocation(program, 1, "in_normal"); - glBindAttribLocation(program, 2, "in_color"); - - glLinkProgram(program); - - glGetProgramiv(program, GL_LINK_STATUS, &ret); - FAIL_IF(!ret, "program linking failed!"); - - glUseProgram(program); - - m_modelviewmatrix = glGetUniformLocation(program, "modelviewMatrix"); - m_modelviewprojectionmatrix = glGetUniformLocation(program, "modelviewprojectionMatrix"); - m_normalmatrix = glGetUniformLocation(program, "normalMatrix"); - - glEnable(GL_CULL_FACE); - - GLintptr positionsoffset = 0; - GLintptr colorsoffset = sizeof(vVertices); - GLintptr normalsoffset = sizeof(vVertices) + sizeof(vColors); - GLuint vbo; - - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, positionsoffset, sizeof(vVertices), &vVertices[0]); - glBufferSubData(GL_ARRAY_BUFFER, colorsoffset, sizeof(vColors), &vColors[0]); - glBufferSubData(GL_ARRAY_BUFFER, normalsoffset, sizeof(vNormals), &vNormals[0]); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)positionsoffset); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)normalsoffset); - glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)colorsoffset); - glEnableVertexAttribArray(2); - } - - GlScene(const GlScene& other) = delete; - GlScene& operator=(const GlScene& other) = delete; - - void set_viewport(uint32_t width, uint32_t height) - { - m_width = width; - m_height = height; - } - - void draw(uint32_t framenum) - { - glViewport(0, 0, m_width, m_height); - - glClearColor(0.5, 0.5, 0.5, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - - ESMatrix modelview; - - esMatrixLoadIdentity(&modelview); - esTranslate(&modelview, 0.0f, 0.0f, -8.0f); - esRotate(&modelview, 45.0f + (0.75f * framenum), 1.0f, 0.0f, 0.0f); - esRotate(&modelview, 45.0f - (0.5f * framenum), 0.0f, 1.0f, 0.0f); - esRotate(&modelview, 10.0f + (0.45f * framenum), 0.0f, 0.0f, 1.0f); - - GLfloat aspect = (float)m_height / m_width; - - ESMatrix projection; - esMatrixLoadIdentity(&projection); - esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f); - - ESMatrix modelviewprojection; - esMatrixLoadIdentity(&modelviewprojection); - esMatrixMultiply(&modelviewprojection, &modelview, &projection); - - float normal[9]; - normal[0] = modelview.m[0][0]; - normal[1] = modelview.m[0][1]; - normal[2] = modelview.m[0][2]; - normal[3] = modelview.m[1][0]; - normal[4] = modelview.m[1][1]; - normal[5] = modelview.m[1][2]; - normal[6] = modelview.m[2][0]; - normal[7] = modelview.m[2][1]; - normal[8] = modelview.m[2][2]; - - glUniformMatrix4fv(m_modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]); - glUniformMatrix4fv(m_modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]); - glUniformMatrix3fv(m_normalmatrix, 1, GL_FALSE, normal); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 12, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 16, 4); - glDrawArrays(GL_TRIANGLE_STRIP, 20, 4); - } - -private: - GLint m_modelviewmatrix, m_modelviewprojectionmatrix, m_normalmatrix; - - uint32_t m_width; - uint32_t m_height; -}; - -class GbmEglSurface -{ -public: - GbmEglSurface(Card& card, GbmDevice& gdev, const EglState& egl, int width, int height) - : card(card), gdev(gdev), egl(egl), m_width(width), m_height(height), - bo_prev(0), bo_next(0) - { - gsurface = unique_ptr(new GbmSurface(gdev, width, height)); - esurface = eglCreateWindowSurface(egl.display(), egl.config(), gsurface->handle(), NULL); - FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface"); - } - - ~GbmEglSurface() - { - if (bo_next) - gsurface->release_buffer(bo_next); - eglDestroySurface(egl.display(), esurface); - } - - void make_current() - { - FAIL_IF(!gsurface->has_free(), "No free buffers"); - - eglMakeCurrent(egl.display(), esurface, esurface, egl.context()); - } - - void swap_buffers() - { - eglSwapBuffers(egl.display(), esurface); - } - - static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) - { - auto fb = reinterpret_cast(data); - delete fb; - } - - static Framebuffer* drm_fb_get_from_bo(struct gbm_bo *bo, Card& card) - { - auto fb = reinterpret_cast(gbm_bo_get_user_data(bo)); - if (fb) - return fb; - - uint32_t width = gbm_bo_get_width(bo); - uint32_t height = gbm_bo_get_height(bo); - uint32_t stride = gbm_bo_get_stride(bo); - uint32_t handle = gbm_bo_get_handle(bo).u32; - - fb = new ExtFramebuffer(card, width, height, 24, 32, stride, handle); - - gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback); - - return fb; - } - - struct Framebuffer* lock_next() - { - bo_prev = bo_next; - bo_next = gsurface->lock_front_buffer(); - FAIL_IF(!bo_next, "could not lock gbm buffer"); - return drm_fb_get_from_bo(bo_next, card); - } - - void free_prev() - { - if (bo_prev) { - gsurface->release_buffer(bo_prev); - bo_prev = 0; - } - } - - uint32_t width() const { return m_width; } - uint32_t height() const { return m_height; } - -private: - Card& card; - GbmDevice& gdev; - const EglState& egl; - - unique_ptr gsurface; - EGLSurface esurface; - - int m_width; - int m_height; - - struct gbm_bo* bo_prev; - struct gbm_bo* bo_next; -}; - -class EglSurface -{ -public: - EglSurface(const EglState& egl, EGLNativeWindowType wnd) - : egl(egl) - { - esurface = eglCreateWindowSurface(egl.display(), egl.config(), wnd, NULL); - FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface"); - } - - ~EglSurface() - { - eglDestroySurface(egl.display(), esurface); - } - - void make_current() - { - eglMakeCurrent(egl.display(), esurface, esurface, egl.context()); - } - - void swap_buffers() - { - eglSwapBuffers(egl.display(), esurface); - } - -private: - const EglState& egl; - - EGLSurface esurface; -}; - -class OutputHandler : private PageFlipHandlerBase -{ -public: - OutputHandler(Card& card, GbmDevice& gdev, const EglState& egl, Connector* connector, Crtc* crtc, Videomode& mode, Plane* plane, float rotation_mult) - : m_frame_num(0), m_connector(connector), m_crtc(crtc), m_plane(plane), m_mode(mode), - m_rotation_mult(rotation_mult) - { - m_surface1 = unique_ptr(new GbmEglSurface(card, gdev, egl, mode.hdisplay, mode.vdisplay)); - m_scene1 = unique_ptr(new GlScene()); - m_scene1->set_viewport(m_surface1->width(), m_surface1->height()); - - if (m_plane) { - m_surface2 = unique_ptr(new GbmEglSurface(card, gdev, egl, 400, 400)); - m_scene2 = unique_ptr(new GlScene()); - m_scene2->set_viewport(m_surface2->width(), m_surface2->height()); - } - } - - OutputHandler(const OutputHandler& other) = delete; - OutputHandler& operator=(const OutputHandler& other) = delete; - - void setup() - { - int ret; - - m_surface1->make_current(); - m_surface1->swap_buffers(); - struct Framebuffer* fb = m_surface1->lock_next(); - - struct Framebuffer* planefb = 0; - - if (m_plane) { - m_surface2->make_current(); - m_surface2->swap_buffers(); - planefb = m_surface2->lock_next(); - } - - - ret = m_crtc->set_mode(m_connector, *fb, m_mode); - FAIL_IF(ret, "failed to set mode"); - - if (m_crtc->card().has_atomic()) { - Plane* root_plane = 0; - for (Plane* p : m_crtc->get_possible_planes()) { - if (p->crtc_id() == m_crtc->id()) { - root_plane = p; - break; - } - } - - FAIL_IF(!root_plane, "No primary plane for crtc %d", m_crtc->id()); - - m_root_plane = root_plane; - } - - if (m_plane) { - ret = m_crtc->set_plane(m_plane, *planefb, - 0, 0, planefb->width(), planefb->height(), - 0, 0, planefb->width(), planefb->height()); - FAIL_IF(ret, "failed to set plane"); - } - } - - void start_flipping() - { - m_t1 = chrono::steady_clock::now(); - queue_next(); - } - -private: - void handle_page_flip(uint32_t frame, double time) - { - ++m_frame_num; - - if (m_frame_num % 100 == 0) { - auto t2 = chrono::steady_clock::now(); - chrono::duration fsec = t2 - m_t1; - printf("fps: %f\n", 100.0 / fsec.count()); - m_t1 = t2; - } - - s_flip_pending--; - - m_surface1->free_prev(); - if (m_plane) - m_surface2->free_prev(); - - if (s_need_exit) - return; - - queue_next(); - } - - void queue_next() - { - m_surface1->make_current(); - m_scene1->draw(m_frame_num * m_rotation_mult); - m_surface1->swap_buffers(); - struct Framebuffer* fb = m_surface1->lock_next(); - - struct Framebuffer* planefb = 0; - - if (m_plane) { - m_surface2->make_current(); - m_scene2->draw(m_frame_num * m_rotation_mult * 2); - m_surface2->swap_buffers(); - planefb = m_surface2->lock_next(); - } - - if (m_crtc->card().has_atomic()) { - int r; - - AtomicReq req(m_crtc->card()); - - req.add(m_root_plane, "FB_ID", fb->id()); - if (m_plane) - req.add(m_plane, "FB_ID", planefb->id()); - - r = req.test(); - FAIL_IF(r, "atomic test failed"); - - r = req.commit(this); - FAIL_IF(r, "atomic commit failed"); - } else { - int ret; - - ret = m_crtc->page_flip(*fb, this); - FAIL_IF(ret, "failed to queue page flip"); - - if (m_plane) { - ret = m_crtc->set_plane(m_plane, *planefb, - 0, 0, planefb->width(), planefb->height(), - 0, 0, planefb->width(), planefb->height()); - FAIL_IF(ret, "failed to set plane"); - } - } - - s_flip_pending++; - } - - int m_frame_num; - chrono::steady_clock::time_point m_t1; - - Connector* m_connector; - Crtc* m_crtc; - Plane* m_plane; - Videomode m_mode; - Plane* m_root_plane; - - unique_ptr m_surface1; - unique_ptr m_surface2; - - unique_ptr m_scene1; - unique_ptr m_scene2; - - float m_rotation_mult; -}; - -static void main_gbm() -{ - Card card; - - GbmDevice gdev(card); - EglState egl(gdev.handle()); - - vector> outputs; - vector used_planes; - - float rot_mult = 1; - - for (auto pipe : card.get_connected_pipelines()) { - auto connector = pipe.connector; - auto crtc = pipe.crtc; - auto mode = connector->get_default_mode(); - - Plane* plane = 0; - - if (s_support_planes) { - for (Plane* p : crtc->get_possible_planes()) { - if (find(used_planes.begin(), used_planes.end(), p) != used_planes.end()) - continue; - - if (p->plane_type() != PlaneType::Overlay) - continue; - - plane = p; - break; - } - } - - if (plane) - used_planes.push_back(plane); - - auto out = new OutputHandler(card, gdev, egl, connector, crtc, mode, plane, rot_mult); - outputs.emplace_back(out); - - rot_mult *= 1.33; - } - - for (auto& out : outputs) - out->setup(); - - for (auto& out : outputs) - out->start_flipping(); - - struct pollfd fds[2] = { 0 }; - fds[0].fd = 0; - fds[0].events = POLLIN; - fds[1].fd = card.fd(); - fds[1].events = POLLIN; - - while (!s_need_exit || s_flip_pending) { - int r = poll(fds, ARRAY_SIZE(fds), -1); - FAIL_IF(r < 0, "poll error %d", r); - - if (fds[0].revents) - s_need_exit = true; - - if (fds[1].revents) - card.call_page_flip_handlers(); - } -} - -static void main_x() -{ - Display* display = XOpenDisplay(NULL); - - xcb_connection_t *connection = XGetXCBConnection(display); - - /* Get the first screen */ - const xcb_setup_t *setup = xcb_get_setup (connection); - xcb_screen_t *screen = xcb_setup_roots_iterator (setup).data; - - /* Create the window */ - - uint32_t width = 600; - uint32_t height = 600; - - const uint32_t xcb_window_attrib_mask = XCB_CW_EVENT_MASK; - const uint32_t xcb_window_attrib_list[] = { - XCB_EVENT_MASK_EXPOSURE, - }; - - xcb_window_t window = xcb_generate_id (connection); - xcb_create_window (connection, /* Connection */ - XCB_COPY_FROM_PARENT, /* depth (same as root)*/ - window, /* window Id */ - screen->root, /* parent window */ - 0, 0, /* x, y */ - width, height, /* width, height */ - 0, /* border_width */ - XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ - screen->root_visual, /* visual */ - xcb_window_attrib_mask, - xcb_window_attrib_list); - - xcb_map_window (connection, window); - xcb_flush (connection); - - EglState egl(reinterpret_cast(display)); - EglSurface surface(egl, reinterpret_cast(window)); - GlScene scene; - - scene.set_viewport(width, height); - - int framenum = 0; - - surface.make_current(); - surface.swap_buffers(); - - xcb_generic_event_t *event; - while ( (event = xcb_poll_for_event (connection)) ) { - - surface.make_current(); - scene.draw(framenum++); - surface.swap_buffers(); - } - - xcb_disconnect (connection); -} - -static void main_null() -{ - EglState egl(EGL_DEFAULT_DISPLAY); - EglSurface surface(egl, 0); - GlScene scene; - - scene.set_viewport(600, 600); - - int framenum = 0; - - struct pollfd fds[1] = { 0 }; - fds[0].fd = 0; - fds[0].events = POLLIN; - - while (true) { - int r = poll(fds, ARRAY_SIZE(fds), 0); - ASSERT(r >= 0); - - if (fds[0].revents) - break; - - surface.make_current(); - scene.draw(framenum++); - surface.swap_buffers(); - } -} - -int main(int argc, char *argv[]) -{ - OptionSet optionset = { - Option("v|verbose", - [&]() - { - s_verbose = true; - }), - }; - - optionset.parse(argc, argv); - - string m; - - if (optionset.params().size() == 0) - m = "gbm"; - else - m = optionset.params().front(); - - if (m == "gbm") - main_gbm(); - else if (m == "null") - main_null(); - else if (m == "x") - main_x(); - else { - printf("Unknown mode %s\n", m.c_str()); - return -1; - } - - return 0; -} -- 2.39.2