From 9dcc9d98ac014e164073e0f4457d73c177a4fdcc Mon Sep 17 00:00:00 2001 From: Jesse Barker Date: Thu, 6 Dec 2012 13:29:19 -0800 Subject: Rebranch of lp:~glmark2-dev/glmark2/canvas-drm Adds CanvasDRM to support rendering to gbm managed surfaces and flipping to DRM-managed framebuffers. --- INSTALL | 2 +- src/canvas-drm.cpp | 580 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/canvas-drm.h | 132 ++++++++++++ src/main.cpp | 8 +- src/wscript_build | 43 ++++ wscript | 36 +++- 6 files changed, 790 insertions(+), 11 deletions(-) create mode 100644 src/canvas-drm.cpp create mode 100644 src/canvas-drm.h diff --git a/INSTALL b/INSTALL index 550631a..4f65d23 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ glmark2 uses the WAF build system. To configure glmark2 use: -$ ./waf configure [--enable-gl --enable-glesv2 --data-path=DATA_PATH --prefix=PREFIX] +$ ./waf configure [--enable-gl --enable-glesv2 --enable-gl-drm --enable-glesv2-drm --data-path=DATA_PATH --prefix=PREFIX] To build use: diff --git a/src/canvas-drm.cpp b/src/canvas-drm.cpp new file mode 100644 index 0000000..0c26909 --- /dev/null +++ b/src/canvas-drm.cpp @@ -0,0 +1,580 @@ +// +// Copyright © 2012 Linaro Limited +// +// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. +// +// glmark2 is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or (at your option) any later +// version. +// +// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// glmark2. If not, see . +// +// Authors: +// Simon Que +// Jesse Barker +// +#include "canvas-drm.h" +#include "log.h" +#include "options.h" +#include "util.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +/****************** + * Public methods * + ******************/ + +bool +CanvasDRM::reset() +{ + if (!reset_context()) + return false; + + if (!make_current()) + return false; + + if (!supports_gl2()) { + Log::error("Glmark2 needs OpenGL(ES) version >= 2.0 to run" + " (but version string is: '%s')!\n", + glGetString(GL_VERSION)); + return false; + } + + glViewport(0, 0, width_, height_); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + clear(); + egl_.swap(); + + if (!drm_.reset()) { + return false; + } + + return true; +} + +void +DRMState::fb_destroy_callback(gbm_bo* bo, void* data) +{ + DRMFBState* fb = reinterpret_cast(data); + if (fb && fb->fb_id) { + drmModeRmFB(fb->fd, fb->fb_id); + } + delete fb; + gbm_device* dev = gbm_bo_get_device(bo); + Log::debug("Got GBM device handle %p from buffer object\n", dev); +} + +DRMFBState* +DRMState::fb_get_from_bo(gbm_bo* bo) +{ + DRMFBState* fb = reinterpret_cast(gbm_bo_get_user_data(bo)); + if (fb) { + return fb; + } + + unsigned int width = gbm_bo_get_width(bo); + unsigned int height = gbm_bo_get_height(bo); + unsigned int stride = gbm_bo_get_stride(bo); + unsigned int handle = gbm_bo_get_handle(bo).u32; + unsigned int fb_id(0); + int status = drmModeAddFB(fd_, width, height, 24, 32, stride, handle, &fb_id); + if (status < 0) { + Log::error("Failed to create FB: %d\n", status); + return 0; + } + + fb = new DRMFBState(); + fb->fd = fd_; + fb->bo = bo; + fb->fb_id = fb_id; + + gbm_bo_set_user_data(bo, fb, fb_destroy_callback); + return fb; +} + +bool +DRMState::init_gbm() +{ + dev_ = gbm_create_device(fd_); + if (!dev_) { + Log::error("Failed to create GBM device\n"); + return false; + } + + surface_ = gbm_surface_create(dev_, mode_->hdisplay, mode_->vdisplay, + GBM_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + if (!surface_) { + Log::error("Failed to create GBM surface\n"); + return false; + } + + return true; +} + +bool +DRMState::init() +{ + // TODO: Replace this with something that explicitly probes for the loaded + // driver (udev?). + static const char* drm_modules[] = { + "i915", + "nouveau", + "radeon", + "vmgfx", + "omapdrm", + "exynos" + }; + + unsigned int num_modules(sizeof(drm_modules)/sizeof(drm_modules[0])); + for (unsigned int m = 0; m < num_modules; m++) { + fd_ = drmOpen(drm_modules[m], 0); + if (fd_ < 0) { + Log::debug("Failed to open DRM module '%s'\n", drm_modules[m]); + continue; + } + Log::debug("Opened DRM module '%s'\n", drm_modules[m]); + break; + } + + if (fd_ < 0) { + Log::error("Failed to find a suitable DRM device\n"); + return false; + } + + resources_ = drmModeGetResources(fd_); + if (!resources_) { + Log::error("drmModeGetResources failed\n"); + return false; + } + + // Find a connected connector + for (int c = 0; c < resources_->count_connectors; c++) { + connector_ = drmModeGetConnector(fd_, resources_->connectors[c]); + if (DRM_MODE_CONNECTED == connector_->connection) { + break; + } + drmModeFreeConnector(connector_); + connector_ = 0; + } + + if (!connector_) { + Log::error("Failed to find a suitable connector\n"); + return false; + } + + // Find the best resolution (we will always operate full-screen). + unsigned int bestArea(0); + for (int m = 0; m < connector_->count_modes; m++) { + drmModeModeInfo* curMode = &connector_->modes[m]; + unsigned int curArea = curMode->hdisplay * curMode->vdisplay; + if (curArea > bestArea) { + mode_ = curMode; + bestArea = curArea; + } + } + + if (!mode_) { + Log::error("Failed to find a suitable mode\n"); + return false; + } + + // Find a suitable encoder + for (int e = 0; e < resources_->count_encoders; e++) { + encoder_ = drmModeGetEncoder(fd_, resources_->encoders[e]); + if (encoder_ && encoder_->encoder_id == connector_->encoder_id) { + break; + } + drmModeFreeEncoder(encoder_); + encoder_ = 0; + } + + if (!encoder_) { + Log::error("Failed to find a suitable encoder\n"); + return false; + } + + if (!init_gbm()) { + return false; + } + + crtc_ = drmModeGetCrtc(fd_, encoder_->crtc_id); + if (!crtc_) { + Log::error("Failed to get current CRTC\n"); + return false; + } + + return true; +} + +bool +DRMState::reset() +{ + if (bo_) { + gbm_surface_release_buffer(surface_, bo_); + } + + bo_ = gbm_surface_lock_front_buffer(surface_); + fb_ = fb_get_from_bo(bo_); + + int status = drmModeSetCrtc(fd_, encoder_->crtc_id, fb_->fb_id, 0, 0, + &connector_->connector_id, 1, mode_); + if (status < 0) { + Log::error("Failed to set CRTC: %d\n", status); + return false; + } + + return true; +} + +void +DRMState::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) +{ + Log::debug("page_flip_handler called on fd %d for frame %u at %u sec, %u usec\n", + fd, frame, sec, usec); + unsigned int* waiting = reinterpret_cast(data); + *waiting = 0; +} + +void +DRMState::do_flip() +{ + gbm_bo* next = gbm_surface_lock_front_buffer(surface_); + fb_ = fb_get_from_bo(next); + unsigned int waiting(1); + int status = drmModePageFlip(fd_, encoder_->crtc_id, fb_->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, &waiting); + if (status < 0) { + Log::error("Failed to enqueue page flip: %d\n", status); + return; + } + + fd_set fds; + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd_, &fds); + drmEventContext evCtx; + evCtx.version = DRM_EVENT_CONTEXT_VERSION; + evCtx.page_flip_handler = page_flip_handler; + + while (waiting) { + status = select(fd_ + 1, &fds, 0, 0, 0); + if (status < 0) { + Log::error("Error in select: %d\n", status); + return; + } + else if (status == 0) { + Log::info("Timeout in select\n"); + return; + } + else if (FD_ISSET(0, &fds)) { + Log::info("User interrupt received\n"); + return; + } + drmHandleEvent(fd_, &evCtx); + } + + gbm_surface_release_buffer(surface_, bo_); + bo_ = next; +} + +void +DRMState::cleanup() +{ + // Restore CRTC state if necessary + if (crtc_) { + int status = drmModeSetCrtc(fd_, crtc_->crtc_id, crtc_->buffer_id, + crtc_->x, crtc_->y, &connector_->connector_id, + 1, &crtc_->mode); + if (status < 0) { + Log::error("Failed to restore original CRTC: %d\n", status); + } + drmModeFreeCrtc(crtc_); + crtc_ = 0; + } + if (surface_) { + gbm_surface_destroy(surface_); + surface_ = 0; + } + if (dev_) { + gbm_device_destroy(dev_); + dev_ = 0; + } + if (connector_) { + drmModeFreeConnector(connector_); + connector_ = 0; + } + if (encoder_) { + drmModeFreeEncoder(encoder_); + encoder_ = 0; + } + if (resources_) { + drmModeFreeResources(resources_); + resources_ = 0; + } + if (fd_ > 0) { + drmClose(fd_); + } + fd_ = 0; + mode_ = 0; +} + +bool +CanvasDRM::init() +{ + signal(SIGINT, &CanvasDRM::quit_handler); + + if (!drm_.init()) { + Log::error("Failed to initialize the DRM canvas\n"); + drm_.cleanup(); + return false; + } + + width_ = drm_.mode_width(); + height_ = drm_.mode_height(); + resize_no_viewport(width_, height_); + + if (!egl_.init_display(drm_.device(), visual_config_)) { + return false; + } + if (!egl_.init_surface(drm_.surface())) { + return false; + } + if (!egl_.valid()) { + return false; + } + + return reset(); +} + + +CanvasDRM::~CanvasDRM() +{ + drm_.cleanup(); +} + +void +CanvasDRM::visible(bool /* visible */) +{ +} + +void +CanvasDRM::clear() +{ + glClearColor(0.0f, 0.0f, 0.0f, 0.5f); +#if USE_GL + glClearDepth(1.0f); +#elif USE_GLESv2 + glClearDepthf(1.0f); +#endif + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void +CanvasDRM::update() +{ + Options::FrameEnd m = Options::frame_end; + + if (m == Options::FrameEndDefault) { + if (offscreen_) + m = Options::FrameEndFinish; + else + m = Options::FrameEndSwap; + } + + switch(m) { + case Options::FrameEndSwap: + swap_buffers(); + break; + case Options::FrameEndFinish: + glFinish(); + break; + case Options::FrameEndReadPixels: + read_pixel(width_ / 2, height_ / 2); + break; + case Options::FrameEndNone: + default: + break; + } +} + +void +CanvasDRM::print_info() +{ + make_current(); + + std::stringstream ss; + ss << " OpenGL Information" << std::endl; + ss << " GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; + ss << " GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; + ss << " GL_VERSION: " << glGetString(GL_VERSION) << std::endl; + Log::info("%s", ss.str().c_str()); +} + +Canvas::Pixel +CanvasDRM::read_pixel(int x, int y) +{ + uint8_t pixel[4]; + glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); + return Canvas::Pixel(pixel[0], pixel[1], pixel[2], pixel[3]); +} + +void +CanvasDRM::write_to_file(std::string &filename) +{ + char *pixels = new char[width_ * height_ * 4]; + + for (int i = 0; i < height_; i++) { + glReadPixels(0, i, width_, 1, GL_RGBA, GL_UNSIGNED_BYTE, + &pixels[(height_ - i - 1) * width_ * 4]); + } + + std::ofstream output (filename.c_str(), std::ios::out | std::ios::binary); + output.write(pixels, 4 * width_ * height_); + + delete [] pixels; +} + +bool +CanvasDRM::should_quit() +{ + return should_quit_; +} + +void +CanvasDRM::resize(int width, int height) +{ + resize_no_viewport(width, height); + glViewport(0, 0, width_, height_); +} + +/********************* + * Protected methods * + *********************/ + +bool +CanvasDRM::supports_gl2() +{ + std::string gl_version_str( + reinterpret_cast(glGetString(GL_VERSION))); + int gl_major = 0; + + size_t point_pos(gl_version_str.find('.')); + + if (point_pos != std::string::npos) { + point_pos--; + + size_t start_pos(gl_version_str.rfind(' ', point_pos)); + if (start_pos == std::string::npos) + start_pos = 0; + else + start_pos++; + + gl_major = Util::fromString( + gl_version_str.substr(start_pos, point_pos - start_pos + 1) + ); + } + + return gl_major >= 2; +} + +bool +CanvasDRM::make_current() +{ + if (!egl_.valid()) { + Log::error("CanvasDRM: Invalid EGL state\n"); + return false; + } + + init_gl_extensions(); + + return true; +} + +bool +CanvasDRM::reset_context() +{ + return egl_.reset(); +} + +void +CanvasDRM::swap_buffers() +{ + egl_.swap(); + drm_.do_flip(); +} + +void +CanvasDRM::init_gl_extensions() +{ +#if USE_GLESv2 + /* + * Parse the extensions we care about from the extension string. + * Don't even bother to get function pointers until we know the + * extension is present. + */ + std::string extString; + const char* exts = + reinterpret_cast(glGetString(GL_EXTENSIONS)); + if (exts) + extString = exts; + + if (extString.find("GL_OES_mapbuffer") != std::string::npos) { + GLExtensions::MapBuffer = reinterpret_cast( + eglGetProcAddress("glMapBufferOES")); + GLExtensions::UnmapBuffer = reinterpret_cast( + eglGetProcAddress("glUnmapBufferOES")); + } +#elif USE_GL + GLExtensions::MapBuffer = glMapBuffer; + GLExtensions::UnmapBuffer = glUnmapBuffer; +#endif +} + + +/******************* + * Private methods * + *******************/ + +void +CanvasDRM::resize_no_viewport(int width, int height) +{ + width_ = drm_.mode_width(); + height_ = drm_.mode_height(); + + if (!width_) + width_ = width; + if (!height_) + height_ = height; + + projection_ = + LibMatrix::Mat4::perspective(60.0, width_ / static_cast(height_), + 1.0, 1024.0); +} + +bool CanvasDRM::should_quit_ = false; + +void +CanvasDRM::quit_handler(int /* signum */) +{ + should_quit_ = true; +} diff --git a/src/canvas-drm.h b/src/canvas-drm.h new file mode 100644 index 0000000..e5dde15 --- /dev/null +++ b/src/canvas-drm.h @@ -0,0 +1,132 @@ +// +// Copyright © 2012 Linaro Limited +// +// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. +// +// glmark2 is free software: you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the Free Software +// Foundation, either version 3 of the License, or (at your option) any later +// version. +// +// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// glmark2. If not, see . +// +// Authors: +// Simon Que +// Jesse Barker +// +#ifndef GLMARK2_CANVAS_DRM_H_ +#define GLMARK2_CANVAS_DRM_H_ + +#include +#include +#include +#include +#include + +#include "canvas.h" +#include "egl-state.h" + +struct DRMFBState +{ + int fd; + gbm_bo* bo; + uint32_t fb_id; +}; + +class DRMState +{ + static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void* data); + static void fb_destroy_callback(gbm_bo* bo, void* data); + DRMFBState* fb_get_from_bo(gbm_bo* bo); + bool init_gbm(); + int fd_; + drmModeRes* resources_; + drmModeConnector* connector_; + drmModeEncoder* encoder_; + drmModeCrtcPtr crtc_; + drmModeModeInfo* mode_; + gbm_device* dev_; + gbm_surface* surface_; + gbm_bo* bo_; + DRMFBState* fb_; + +public: + DRMState() : + fd_(0), + resources_(0), + connector_(0), + encoder_(0), + mode_(0), + dev_(0), + surface_(0), + bo_(0), + fb_(0) {} + ~DRMState() { cleanup(); } + void cleanup(); + bool init(); + bool reset(); + void do_flip(); + gbm_device* device() const { return dev_; } + gbm_surface* surface() const { return surface_; } + unsigned int mode_width() const + { + if (mode_) { + return mode_->hdisplay; + } + return 0; + } + unsigned int mode_height() const + { + if (mode_) { + return mode_->vdisplay; + } + return 0; + } +}; + +/** + * Canvas for direct rendering with EGL. + */ +class CanvasDRM: public Canvas +{ +public: + CanvasDRM(int width, int height) : + Canvas(width, height) {} + ~CanvasDRM(); + + virtual bool init(); + virtual bool reset(); + virtual void visible(bool visible); + virtual void clear(); + virtual void update(); + virtual void print_info(); + virtual Pixel read_pixel(int x, int y); + virtual void write_to_file(std::string &filename); + virtual bool should_quit(); + virtual void resize(int width, int height); + +protected: + virtual bool make_current(); + virtual bool reset_context(); + virtual void swap_buffers(); + virtual bool supports_gl2(); + +private: + DRMState drm_; + EGLState egl_; + + void resize_no_viewport(int width, int height); + void init_gl_extensions(); + + static void quit_handler(int signum); + static bool should_quit_; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index d310a51..8340f1e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,7 +35,9 @@ #include #include -#if USE_GL +#if USE_DRM +#include "canvas-drm.h" +#elif USE_GL #include "canvas-x11-glx.h" #elif USE_GLESv2 #include "canvas-x11-egl.h" @@ -179,7 +181,9 @@ main(int argc, char *argv[]) } // Create the canvas -#if USE_GL +#if USE_DRM + CanvasDRM canvas(Options::size.first, Options::size.second); +#elif USE_GL CanvasX11GLX canvas(Options::size.first, Options::size.second); #elif USE_GLESv2 CanvasX11EGL canvas(Options::size.first, Options::size.second); diff --git a/src/wscript_build b/src/wscript_build index f0c233f..b742b48 100644 --- a/src/wscript_build +++ b/src/wscript_build @@ -4,6 +4,8 @@ common_sources = [f for f in all_sources if f.name.find('canvas-') == -1 and f.name.find('egl-') == -1] gl_sources = ['canvas-x11.cpp', 'canvas-x11-glx.cpp'] glesv2_sources = ['canvas-x11.cpp', 'canvas-x11-egl.cpp', 'egl-state.cpp'] +gl_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp'] +glesv2_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp'] libmatrix_sources = [f for f in bld.path.ant_glob('libmatrix/*.cc') if not f.name.endswith('test.cc')] includes = ['.', 'scene-ideas', 'scene-terrain'] @@ -47,3 +49,44 @@ if bld.env.USE_GLESv2: includes = includes, defines = ['USE_GLESv2', 'USE_EXCEPTIONS'] ) + +if bld.env.USE_GL_DRM: + bld( + features = ['cxx', 'cxxstlib'], + source = libmatrix_sources, + target = 'matrix-drm', + lib = ['m'], + includes = ['.'], + export_includes = 'libmatrix', + defines = ['USE_DRM', '__GBM__', 'USE_GL', 'USE_EXCEPTIONS'] + ) + bld( + features = ['cxx', 'cprogram'], + source = common_sources + gl_drm_sources, + target = 'glmark2-drm', + use = ['egl', 'gl', 'matrix-drm', 'libpng12', 'drm', 'gbm'], + lib = ['m', 'jpeg', 'dl'], + includes = includes, + defines = ['USE_DRM', '__GBM__', 'USE_GL'] + ) + +if bld.env.USE_GLESv2_DRM: + bld( + features = ['cxx', 'cxxstlib'], + source = libmatrix_sources, + target = 'matrix-es2-drm', + lib = ['m'], + includes = ['.'], + export_includes = 'libmatrix', + defines = ['USE_DRM', '__GBM__', 'USE_GLESv2', 'USE_EXCEPTIONS'] + ) + bld( + features = ['cxx', 'cprogram'], + source = common_sources + glesv2_drm_sources, + target = 'glmark2-es2-drm', + use = ['egl', 'glesv2', 'matrix-es2-drm', 'libpng12', 'drm', + 'gbm'], + lib = ['m', 'jpeg', 'dl'], + includes = includes, + defines = ['USE_DRM', '__GBM__', 'USE_GLESv2'] + ) diff --git a/wscript b/wscript index 007eb0a..18cca76 100644 --- a/wscript +++ b/wscript @@ -20,6 +20,11 @@ def options(opt): default = False, help='build using OpenGL 2.0') opt.add_option('--enable-glesv2', action='store_true', dest = 'glesv2', default = False, help='build using OpenGL ES 2.0') + opt.add_option('--enable-gl-drm', action='store_true', dest = 'gl_drm', + default = False, help='build using OpenGL 2.0 without X') + opt.add_option('--enable-glesv2-drm', action='store_true', + dest = 'glesv2_drm', + default = False, help='build using OpenGL ES 2.0 without X') opt.add_option('--no-debug', action='store_false', dest = 'debug', default = True, help='disable compiler debug information') opt.add_option('--no-opt', action='store_false', dest = 'opt', @@ -30,8 +35,10 @@ def options(opt): help='path to additional data (models, shaders, textures)') def configure(ctx): - if not Options.options.gl and not Options.options.glesv2: - ctx.fatal("You must configure using at least one of --enable-gl, --enable-glesv2") + if not Options.options.gl and not Options.options.glesv2 and \ + not Options.options.gl_drm and not Options.options.glesv2_drm: + ctx.fatal("You must configure using at least one of --enable-gl, " + + "--enable-glesv2, --enable-gl-drm, --enable-glesv2-drm") ctx.check_tool('gnu_dirs') ctx.check_tool('compiler_cc') @@ -54,15 +61,22 @@ def configure(ctx): uselib = uselib, mandatory = True) # Check required packages - req_pkgs = [('x11', 'x11'), ('libpng12', 'libpng12')] + req_pkgs = [('libpng12', 'libpng12')] for (pkg, uselib) in req_pkgs: ctx.check_cfg(package = pkg, uselib_store = uselib, args = '--cflags --libs', mandatory = True) # Check optional packages - opt_pkgs = [('gl', 'gl', Options.options.gl), - ('egl', 'egl', Options.options.glesv2), - ('glesv2', 'glesv2', Options.options.glesv2)] + opt_pkgs = [('x11', 'x11', Options.options.gl or Options.options.glesv2), + ('gl', 'gl', Options.options.gl or Options.options.gl_drm), + ('egl', 'egl', Options.options.glesv2 or + Options.options.glesv2_drm), + ('glesv2', 'glesv2', Options.options.glesv2 or + Options.options.glesv2_drm), + ('libdrm','drm', Options.options.gl_drm or + Options.options.glesv2_drm), + ('gbm','gbm', Options.options.gl_drm or + Options.options.glesv2_drm)] for (pkg, uselib, mandatory) in opt_pkgs: ctx.check_cfg(package = pkg, uselib_store = uselib, args = '--cflags --libs', mandatory = mandatory) @@ -94,6 +108,8 @@ def configure(ctx): ctx.env.USE_GL = Options.options.gl ctx.env.USE_GLESv2 = Options.options.glesv2 + ctx.env.USE_GL_DRM = Options.options.gl_drm + ctx.env.USE_GLESv2_DRM = Options.options.glesv2_drm ctx.msg("Prefix", ctx.env.PREFIX, color = 'PINK') ctx.msg("Data path", data_path, color = 'PINK') @@ -101,9 +117,13 @@ def configure(ctx): color = 'PINK'); if ctx.env.HAVE_EXTRAS: ctx.msg("Extras path", Options.options.extras_path, color = 'PINK') - ctx.msg("Building GL2 version", "Yes" if ctx.env.USE_GL else "No", + ctx.msg("Building X11 GL2 version", "Yes" if ctx.env.USE_GL else "No", color = 'PINK') - ctx.msg("Building GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No", + ctx.msg("Building X11 GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No", + color = 'PINK') + ctx.msg("Building DRM GL2 version", "Yes" if ctx.env.USE_GL_DRM else "No", + color = 'PINK') + ctx.msg("Building DRM GLESv2 version", "Yes" if ctx.env.USE_GLESv2_DRM else "No", color = 'PINK') def build(ctx): -- cgit v1.2.3 From fadb8f7d792d49b900b0397903ab67140e72f209 Mon Sep 17 00:00:00 2001 From: Jesse Barker Date: Thu, 6 Dec 2012 14:47:53 -0800 Subject: CanvasDRM: Remove the debug statement from the page flip handler based upon review comments. Can always be re-inserted if an actual page flip issue is encountered. --- src/canvas-drm.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/canvas-drm.cpp b/src/canvas-drm.cpp index 0c26909..f24d315 100644 --- a/src/canvas-drm.cpp +++ b/src/canvas-drm.cpp @@ -249,10 +249,13 @@ DRMState::reset() void DRMState::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) { - Log::debug("page_flip_handler called on fd %d for frame %u at %u sec, %u usec\n", - fd, frame, sec, usec); unsigned int* waiting = reinterpret_cast(data); *waiting = 0; + // Deal with unused parameters + static_cast(fd); + static_cast(frame); + static_cast(sec); + static_cast(usec); } void -- cgit v1.2.3 From 002f81e3db992c8edd41436cc7010e1c58abc0ef Mon Sep 17 00:00:00 2001 From: Jesse Barker Date: Mon, 17 Dec 2012 11:11:54 -0800 Subject: CanvasDRM: Fix handling of Ctrl-C. Because the Ctrl-C was being handled by CanvasDRM directly, DRMState had no knowledge of the event, and wasn't able to detect it properly when select() came back with an error. Move the quit handler into DRMState, and give it a public should_quit() method that CanvasDRM can call. This is better encapsulation, and allows DRMState to properly detect the user interrupt and release the GBM resources so the console isn't hung when the application exits. --- src/canvas-drm.cpp | 35 ++++++++++++++++++++++++----------- src/canvas-drm.h | 6 +++--- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/canvas-drm.cpp b/src/canvas-drm.cpp index f24d315..e3a81f7 100644 --- a/src/canvas-drm.cpp +++ b/src/canvas-drm.cpp @@ -223,6 +223,8 @@ DRMState::init() return false; } + signal(SIGINT, &DRMState::quit_handler); + return true; } @@ -246,6 +248,15 @@ DRMState::reset() return true; } + +bool DRMState::should_quit_ = false; + +void +DRMState::quit_handler(int signo) +{ + Log::debug("Got SIGINT (%d).\n", signo); + should_quit_ = true; +} void DRMState::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) { @@ -282,7 +293,15 @@ DRMState::do_flip() while (waiting) { status = select(fd_ + 1, &fds, 0, 0, 0); if (status < 0) { - Log::error("Error in select: %d\n", status); + // Most of the time, select() will return an error because the + // user pressed Ctrl-C. So, only print out a message in debug + // mode, and just check for the likely condition and release + // the current buffer object before getting out. + Log::debug("Error in select\n"); + if (should_quit()) { + gbm_surface_release_buffer(surface_, bo_); + bo_ = next; + } return; } else if (status == 0) { @@ -344,7 +363,9 @@ DRMState::cleanup() bool CanvasDRM::init() { - signal(SIGINT, &CanvasDRM::quit_handler); + Log::info("NOTE: The DRM canvas is still experimental and its behavior\n"); + Log::info(" is subject to change as GBM and modesetting behavior\n"); + Log::info(" evolves\n"); if (!drm_.init()) { Log::error("Failed to initialize the DRM canvas\n"); @@ -460,7 +481,7 @@ CanvasDRM::write_to_file(std::string &filename) bool CanvasDRM::should_quit() { - return should_quit_; + return drm_.should_quit(); } void @@ -573,11 +594,3 @@ CanvasDRM::resize_no_viewport(int width, int height) LibMatrix::Mat4::perspective(60.0, width_ / static_cast(height_), 1.0, 1024.0); } - -bool CanvasDRM::should_quit_ = false; - -void -CanvasDRM::quit_handler(int /* signum */) -{ - should_quit_ = true; -} diff --git a/src/canvas-drm.h b/src/canvas-drm.h index e5dde15..e355131 100644 --- a/src/canvas-drm.h +++ b/src/canvas-drm.h @@ -44,6 +44,8 @@ class DRMState static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data); static void fb_destroy_callback(gbm_bo* bo, void* data); + static void quit_handler(int signum); + static bool should_quit_; DRMFBState* fb_get_from_bo(gbm_bo* bo); bool init_gbm(); int fd_; @@ -73,6 +75,7 @@ public: bool init(); bool reset(); void do_flip(); + bool should_quit() const { return should_quit_; } gbm_device* device() const { return dev_; } gbm_surface* surface() const { return surface_; } unsigned int mode_width() const @@ -124,9 +127,6 @@ private: void resize_no_viewport(int width, int height); void init_gl_extensions(); - - static void quit_handler(int signum); - static bool should_quit_; }; #endif -- cgit v1.2.3 From 4be027a005d8d6dec3b4ce2317527fab424e08ac Mon Sep 17 00:00:00 2001 From: Jesse Barker Date: Mon, 17 Dec 2012 14:48:52 -0800 Subject: CanvasDRM: Further simplify the select() logic. Firstly, as we have a NULL pointer for the timeout parameter, select() won't time out and we don't need to handle that return value. Secondly, unless we have a really great idea for handling user input (apart from Ctrl-C), we don't need to listen on stdin. --- src/canvas-drm.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/canvas-drm.cpp b/src/canvas-drm.cpp index e3a81f7..7d11e85 100644 --- a/src/canvas-drm.cpp +++ b/src/canvas-drm.cpp @@ -284,7 +284,6 @@ DRMState::do_flip() fd_set fds; FD_ZERO(&fds); - FD_SET(0, &fds); FD_SET(fd_, &fds); drmEventContext evCtx; evCtx.version = DRM_EVENT_CONTEXT_VERSION; @@ -304,14 +303,6 @@ DRMState::do_flip() } return; } - else if (status == 0) { - Log::info("Timeout in select\n"); - return; - } - else if (FD_ISSET(0, &fds)) { - Log::info("User interrupt received\n"); - return; - } drmHandleEvent(fd_, &evCtx); } -- cgit v1.2.3