From patchwork Thu Mar 22 10:40:18 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alexandros.frantzis@linaro.org X-Patchwork-Id: 7406 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 7325A23E2F for ; Thu, 22 Mar 2012 10:40:23 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 19ED3A18405 for ; Thu, 22 Mar 2012 10:40:23 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id e36so3877920iag.11 for ; Thu, 22 Mar 2012 03:40:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :content-type:mime-version:x-launchpad-project:x-launchpad-branch :x-launchpad-message-rationale:x-launchpad-branch-revision-number :x-launchpad-notification-type:to:from:subject:message-id:date :reply-to:sender:errors-to:precedence:x-generated-by :x-launchpad-hash:x-gm-message-state; bh=jVSpXQfUuT0jQudxqPomQDxEaPd2tw33AqTqY1wz/F0=; b=l22sNmiUBAfHnZki9mexNmqfH/H7uIJchjCT/fSWNnxCdJTYKhaZL0J6mfCORxe0Y6 zjLz/U4bhYUJjqnEUnY7IF0ERayfzT7V957Pk0SjQU4geVp2FjjPA1V9F/V0B470aD/N Y9oyaAfyLFaQmY2mZRBL88p+Pflb+fuuvqH4iuxRR7FzMSEVVa8HLM/Fl4GiyE0nb2fA 7y6zYbEpeQSpWGaOOyOgkhgHNxh8iyTFBv9+8hpFw7V7Chs0lIk2dGNQEIrOZFm83aIf 73aq0THQ5pETCd3gStIMzTWvLOi71Jhi/z42lzkRBA0apMK/rwKsNTGMRayQWnzX5CDg w8uw== Received: by 10.50.183.163 with SMTP id en3mr1035945igc.12.1332412822841; Thu, 22 Mar 2012 03:40:22 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.203.79 with SMTP id fh15csp44368ibb; Thu, 22 Mar 2012 03:40:20 -0700 (PDT) Received: by 10.180.107.162 with SMTP id hd2mr3795403wib.8.1332412819957; Thu, 22 Mar 2012 03:40:19 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id j10si4642272wed.143.2012.03.22.03.40.19 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 22 Mar 2012 03:40:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1SAfRL-0004Bt-1f for ; Thu, 22 Mar 2012 10:40:19 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id F3654E0118 for ; Thu, 22 Mar 2012 10:40:18 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: glmark2 X-Launchpad-Branch: ~glmark2-dev/glmark2/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 202 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~glmark2-dev/glmark2/trunk] Rev 202: Canvas*: Add support for rendering to an off-screen surface. Message-Id: <20120322104018.25386.9065.launchpad@ackee.canonical.com> Date: Thu, 22 Mar 2012 10:40:18 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="14981"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: 84f41fff6a5ee5e4dd87fb1eb4636400572c7a4d X-Gm-Message-State: ALoCoQntQ0rQXnj9Kxi94GvzTJaVr3nokVOzm345EwTSQJmMUxnu1FWmT3tcI/h47rTD/VAnVka1 Merge authors: Alexandros Frantzis (afrantzis) ------------------------------------------------------------ revno: 202 [merge] committer: Alexandros Frantzis branch nick: trunk timestamp: Thu 2012-03-22 12:37:04 +0200 message: Canvas*: Add support for rendering to an off-screen surface. modified: doc/glmark2.1.in src/canvas-x11-egl.cpp src/canvas-x11-egl.h src/canvas-x11-glx.cpp src/canvas-x11-glx.h src/canvas-x11.cpp src/canvas-x11.h src/canvas.h src/gl-headers.cpp src/gl-headers.h src/main.cpp src/options.cpp src/options.h src/scene-desktop.cpp --- lp:glmark2 https://code.launchpad.net/~glmark2-dev/glmark2/trunk You are subscribed to branch lp:glmark2. To unsubscribe from this branch go to https://code.launchpad.net/~glmark2-dev/glmark2/trunk/+edit-subscription === modified file 'doc/glmark2.1.in' --- doc/glmark2.1.in 2012-02-16 11:45:12 +0000 +++ doc/glmark2.1.in 2012-03-22 09:40:12 +0000 @@ -21,15 +21,17 @@ Run a quick output validation test instead of running the benchmarks .TP -\fB\-\-no\-swap\-buffers\fR -Don't update the screen by swapping the front and -back buffer, use glFinish() instead +\fB\-\-frame-end\fR METHOD +How to end a frame [default,none,swap,finish,readpixels] +.TP +\fB\-\-off-screen\fR +Render to an off-screen surface .TP \fB\-\-reuse\-context\fR Use a single context for all scenes (by default, each scene gets its own context) .TP -\fB\-s\fR, \fB\-\-size WxH\fR +\fB\-s\fR, \fB\-\-size\fR WxH Size of the output window (default: 800x600) .TP \fB\-l\fR, \fB\-\-list\-scenes\fR === modified file 'src/canvas-x11-egl.cpp' --- src/canvas-x11-egl.cpp 2012-01-04 16:51:20 +0000 +++ src/canvas-x11-egl.cpp 2012-03-20 11:16:03 +0000 @@ -86,6 +86,20 @@ return true; } +void +CanvasX11EGL::get_glvisualinfo(GLVisualInfo &gl_visinfo) +{ + if (!ensure_egl_config()) + return; + + eglGetConfigAttrib(egl_display_, egl_config_, EGL_BUFFER_SIZE, &gl_visinfo.buffer_size); + eglGetConfigAttrib(egl_display_, egl_config_, EGL_RED_SIZE, &gl_visinfo.red_size); + eglGetConfigAttrib(egl_display_, egl_config_, EGL_GREEN_SIZE, &gl_visinfo.green_size); + eglGetConfigAttrib(egl_display_, egl_config_, EGL_BLUE_SIZE, &gl_visinfo.blue_size); + eglGetConfigAttrib(egl_display_, egl_config_, EGL_ALPHA_SIZE, &gl_visinfo.alpha_size); + eglGetConfigAttrib(egl_display_, egl_config_, EGL_DEPTH_SIZE, &gl_visinfo.depth_size); +} + /******************* * Private methods * *******************/ @@ -256,18 +270,7 @@ CanvasX11EGL::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) { + if (GLExtensions::support("GL_OES_mapbuffer")) { GLExtensions::MapBuffer = reinterpret_cast(eglGetProcAddress("glMapBufferOES")); GLExtensions::UnmapBuffer = === modified file 'src/canvas-x11-egl.h' --- src/canvas-x11-egl.h 2012-01-04 00:37:12 +0000 +++ src/canvas-x11-egl.h 2012-03-19 16:55:27 +0000 @@ -43,6 +43,7 @@ bool make_current(); bool reset_context(); void swap_buffers() { eglSwapBuffers(egl_display_, egl_surface_); } + void get_glvisualinfo(GLVisualInfo &gl_visinfo); private: bool ensure_egl_display(); === modified file 'src/canvas-x11-glx.cpp' --- src/canvas-x11-glx.cpp 2012-01-04 00:37:12 +0000 +++ src/canvas-x11-glx.cpp 2012-03-19 16:55:27 +0000 @@ -68,6 +68,19 @@ return true; } +void +CanvasX11GLX::get_glvisualinfo(GLVisualInfo &gl_visinfo) +{ + if (!ensure_glx_fbconfig()) + return; + + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BUFFER_SIZE, &gl_visinfo.buffer_size); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_RED_SIZE, &gl_visinfo.red_size); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_GREEN_SIZE, &gl_visinfo.green_size); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_BLUE_SIZE, &gl_visinfo.blue_size); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_ALPHA_SIZE, &gl_visinfo.alpha_size); + glXGetFBConfigAttrib(xdpy_, glx_fbconfig_, GLX_DEPTH_SIZE, &gl_visinfo.depth_size); +} /******************* * Private methods * === modified file 'src/canvas-x11-glx.h' --- src/canvas-x11-glx.h 2012-01-04 00:37:12 +0000 +++ src/canvas-x11-glx.h 2012-03-19 16:55:27 +0000 @@ -43,6 +43,7 @@ bool make_current(); bool reset_context(); void swap_buffers() { glXSwapBuffers(xdpy_, xwin_); } + void get_glvisualinfo(GLVisualInfo &gl_visinfo); private: bool check_glx_version(); === modified file 'src/canvas-x11.cpp' --- src/canvas-x11.cpp 2012-01-04 00:37:12 +0000 +++ src/canvas-x11.cpp 2012-03-20 12:55:49 +0000 @@ -35,10 +35,12 @@ bool CanvasX11::reset() { + release_fbo(); + if (!reset_context()) return false; - if (!make_current()) + if (!do_make_current()) return false; if (!supports_gl2()) { @@ -78,7 +80,7 @@ void CanvasX11::visible(bool visible) { - if (visible) + if (visible && !offscreen_) XMapWindow(xdpy_, xwin_); } @@ -97,16 +99,35 @@ void CanvasX11::update() { - if (Options::swap_buffers) - swap_buffers(); - else - glFinish(); + 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 CanvasX11::print_info() { - make_current(); + do_make_current(); std::stringstream ss; @@ -173,6 +194,12 @@ glViewport(0, 0, width_, height_); } +unsigned int +CanvasX11::fbo() +{ + return fbo_; +} + bool CanvasX11::supports_gl2() { @@ -285,7 +312,183 @@ if (!ensure_x_window()) Log::error("Error: Couldn't create X Window!\n"); + if (color_renderbuffer_) { + glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_); + glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_, + width_, height_); + } + + if (depth_renderbuffer_) { + glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_); + glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_, + width_, height_); + } + projection_ = LibMatrix::Mat4::perspective(60.0, width_ / static_cast(height_), 1.0, 1024.0); } +bool +CanvasX11::do_make_current() +{ + if (!make_current()) + return false; + + if (offscreen_) { + if (!ensure_fbo()) + return false; + + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + } + + return true; +} + +bool +CanvasX11::ensure_gl_formats() +{ + if (gl_color_format_ && gl_depth_format_) + return true; + + GLVisualInfo gl_visinfo; + get_glvisualinfo(gl_visinfo); + + gl_color_format_ = 0; + gl_depth_format_ = 0; + + bool supports_rgba8(false); + bool supports_rgb8(false); + bool supports_depth24(false); + bool supports_depth32(false); + +#if USE_GLESv2 + if (GLExtensions::support("GL_ARM_rgba8")) + supports_rgba8 = true; + + if (GLExtensions::support("GL_OES_rgb8_rgba8")) { + supports_rgba8 = true; + supports_rgb8 = true; + } + + if (GLExtensions::support("GL_OES_depth24")) + supports_depth24 = true; + + if (GLExtensions::support("GL_OES_depth32")) + supports_depth32 = true; +#elif USE_GL + supports_rgba8 = true; + supports_rgb8 = true; + supports_depth24 = true; + supports_depth32 = true; +#endif + + if (gl_visinfo.buffer_size == 32) { + if (supports_rgba8) + gl_color_format_ = GL_RGBA8; + else + gl_color_format_ = GL_RGBA4; + } + else if (gl_visinfo.buffer_size == 24) { + if (supports_rgb8) + gl_color_format_ = GL_RGB8; + else + gl_color_format_ = GL_RGB565; + } + else if (gl_visinfo.buffer_size == 16) { + if (gl_visinfo.red_size == 4 && gl_visinfo.green_size == 4 && + gl_visinfo.blue_size == 4 && gl_visinfo.alpha_size == 4) + { + gl_color_format_ = GL_RGBA4; + } + else if (gl_visinfo.red_size == 5 && gl_visinfo.green_size == 5 && + gl_visinfo.blue_size == 5 && gl_visinfo.alpha_size == 1) + { + gl_color_format_ = GL_RGB5_A1; + } + else if (gl_visinfo.red_size == 5 && gl_visinfo.green_size == 6 && + gl_visinfo.blue_size == 5 && gl_visinfo.alpha_size == 0) + { + gl_color_format_ = GL_RGB565; + } + } + + if (gl_visinfo.depth_size == 32 && supports_depth32) + gl_depth_format_ = GL_DEPTH_COMPONENT32; + else if (gl_visinfo.depth_size >= 24 && supports_depth24) + gl_depth_format_ = GL_DEPTH_COMPONENT24; + else if (gl_visinfo.depth_size == 16) + gl_depth_format_ = GL_DEPTH_COMPONENT16; + + Log::debug("Selected Renderbuffer ColorFormat: %s DepthFormat: %s\n", + get_gl_format_str(gl_color_format_), + get_gl_format_str(gl_depth_format_)); + + return (gl_color_format_ && gl_depth_format_); +} + +bool +CanvasX11::ensure_fbo() +{ + if (!fbo_) { + if (!ensure_gl_formats()) + return false; + + /* Create a texture for the color attachment */ + glGenRenderbuffers(1, &color_renderbuffer_); + glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer_); + glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format_, + width_, height_); + + /* Create a renderbuffer for the depth attachment */ + glGenRenderbuffers(1, &depth_renderbuffer_); + glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer_); + glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format_, + width_, height_); + + /* Create a FBO and set it up */ + glGenFramebuffers(1, &fbo_); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, color_renderbuffer_); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_renderbuffer_); + } + + return true; +} + +void +CanvasX11::release_fbo() +{ + glDeleteFramebuffers(1, &fbo_); + glDeleteRenderbuffers(1, &color_renderbuffer_); + glDeleteRenderbuffers(1, &depth_renderbuffer_); + fbo_ = 0; + color_renderbuffer_ = 0; + depth_renderbuffer_ = 0; + + gl_color_format_ = 0; + gl_depth_format_ = 0; +} + +const char * +CanvasX11::get_gl_format_str(GLenum f) +{ + const char *str; + + switch(f) { + case GL_RGBA8: str = "GL_RGBA8"; break; + case GL_RGB8: str = "GL_RGB8"; break; + case GL_RGBA4: str = "GL_RGBA4"; break; + case GL_RGB5_A1: str = "GL_RGB5_A1"; break; + case GL_RGB565: str = "GL_RGB565"; break; + case GL_DEPTH_COMPONENT16: str = "GL_DEPTH_COMPONENT16"; break; + case GL_DEPTH_COMPONENT24: str = "GL_DEPTH_COMPONENT24"; break; + case GL_DEPTH_COMPONENT32: str = "GL_DEPTH_COMPONENT32"; break; + case GL_NONE: str = "GL_NONE"; break; + default: str = "Unknown"; break; + } + + return str; +} + === modified file 'src/canvas-x11.h' --- src/canvas-x11.h 2012-01-04 00:37:12 +0000 +++ src/canvas-x11.h 2012-03-20 11:29:09 +0000 @@ -44,10 +44,25 @@ virtual void write_to_file(std::string &filename); virtual bool should_quit(); virtual void resize(int width, int height); + virtual unsigned int fbo(); protected: CanvasX11(int width, int height) : - Canvas(width, height), xwin_(0), xdpy_(0) {} + Canvas(width, height), xwin_(0), xdpy_(0), + gl_color_format_(0), gl_depth_format_(0), + color_renderbuffer_(0), depth_renderbuffer_(0), fbo_(0) {} + + /** + * Information about a GL visual. + */ + struct GLVisualInfo { + int buffer_size; + int red_size; + int green_size; + int blue_size; + int alpha_size; + int depth_size; + }; /** * Gets the XVisualInfo to use for creating the X window with. @@ -88,6 +103,13 @@ virtual void swap_buffers() = 0; /** + * Gets information about the GL visual used for this canvas. + * + * This method should be implemented in derived classes. + */ + virtual void get_glvisualinfo(GLVisualInfo &gl_visinfo) = 0; + + /** * Whether the current implementation supports GL(ES) 2.0. * * @return true if it supports GL(ES) 2.0, false otherwise @@ -103,6 +125,18 @@ private: void resize_no_viewport(int width, int height); bool ensure_x_window(); + bool do_make_current(); + bool ensure_gl_formats(); + bool ensure_fbo(); + void release_fbo(); + + const char *get_gl_format_str(GLenum f); + + GLenum gl_color_format_; + GLenum gl_depth_format_; + GLuint color_renderbuffer_; + GLuint depth_renderbuffer_; + GLuint fbo_; }; #endif === modified file 'src/canvas.h' --- src/canvas.h 2012-01-04 00:37:12 +0000 +++ src/canvas.h 2012-03-15 12:17:22 +0000 @@ -191,6 +191,13 @@ virtual void resize(int width, int height) { static_cast(width); static_cast(height); } /** + * Gets the FBO associated with the canvas. + * + * @return the FBO + */ + virtual unsigned int fbo() { return 0; } + + /** * Gets a dummy canvas object. * * @return the dummy canvas @@ -224,12 +231,21 @@ */ const LibMatrix::mat4 &projection() { return projection_; } + /** + * Sets whether the canvas should be backed by an off-screen surface. + * + * This takes effect after the next init()/reset(). + */ + void offscreen(bool offscreen) { offscreen_ = offscreen; } + protected: - Canvas(int width, int height) : width_(width), height_(height) {} + Canvas(int width, int height) : + width_(width), height_(height), offscreen_(false) {} int width_; int height_; LibMatrix::mat4 projection_; + bool offscreen_; }; #endif === modified file 'src/gl-headers.cpp' --- src/gl-headers.cpp 2011-10-10 11:00:36 +0000 +++ src/gl-headers.cpp 2012-03-20 11:15:27 +0000 @@ -24,3 +24,23 @@ void* (*GLExtensions::MapBuffer) (GLenum target, GLenum access) = 0; GLboolean (*GLExtensions::UnmapBuffer) (GLenum target) = 0; +bool +GLExtensions::support(const std::string &ext) +{ + std::string ext_string; + const char* exts = reinterpret_cast(glGetString(GL_EXTENSIONS)); + if (exts) { + ext_string = exts; + } + + const size_t ext_size = ext.size(); + size_t pos = 0; + + while ((pos = ext_string.find(ext, pos)) != std::string::npos) { + char c = ext_string[pos + ext_size]; + if (c == ' ' || c == '\0') + break; + } + + return pos != std::string::npos; +} === modified file 'src/gl-headers.h' --- src/gl-headers.h 2011-10-26 11:12:19 +0000 +++ src/gl-headers.h 2012-03-20 11:29:09 +0000 @@ -27,19 +27,43 @@ #if USE_GL #include #include +#ifndef GL_RGB565 +#define GL_RGB565 0x8D62 +#endif #elif USE_GLESv2 #include #include #ifndef GL_WRITE_ONLY #define GL_WRITE_ONLY GL_WRITE_ONLY_OES #endif -#endif +#ifndef GL_DEPTH_COMPONENT24 +#define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES +#endif +#ifndef GL_DEPTH_COMPONENT32 +#define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES +#endif +#ifndef GL_RGBA8 +#define GL_RGBA8 GL_RGBA8_OES +#endif +#ifndef GL_RGB8 +#define GL_RGB8 GL_RGB8_OES +#endif +#endif + +#include /** * Struct that holds pointers to functions that belong to extensions * in either GL2.0 or GLES2.0. */ struct GLExtensions { + /** + * Whether the current context has support for a GL extension. + * + * @return true if the extension is supported + */ + static bool support(const std::string &ext); + static void* (*MapBuffer) (GLenum target, GLenum access); static GLboolean (*UnmapBuffer) (GLenum target); }; === modified file 'src/main.cpp' --- src/main.cpp 2012-03-09 09:40:49 +0000 +++ src/main.cpp 2012-03-22 10:37:04 +0000 @@ -165,6 +165,8 @@ CanvasX11EGL canvas(Options::size.first, Options::size.second); #endif + canvas.offscreen(Options::offscreen); + vector scenes; // Register the scenes, so they can be looked up by name === modified file 'src/options.cpp' --- src/options.cpp 2012-02-16 09:03:42 +0000 +++ src/options.cpp 2012-03-20 12:55:49 +0000 @@ -33,7 +33,7 @@ std::vector Options::benchmarks; std::vector Options::benchmark_files; bool Options::validate = false; -bool Options::swap_buffers = true; +Options::FrameEnd Options::frame_end = Options::FrameEndDefault; std::pair Options::size(800, 600); bool Options::list_scenes = false; bool Options::show_all_options = false; @@ -42,13 +42,15 @@ bool Options::reuse_context = false; bool Options::run_forever = false; bool Options::annotate = false; +bool Options::offscreen = false; static struct option long_options[] = { {"annotate", 0, 0, 0}, {"benchmark", 1, 0, 0}, {"benchmark-file", 1, 0, 0}, {"validate", 0, 0, 0}, - {"no-swap-buffers", 0, 0, 0}, + {"frame-end", 1, 0, 0}, + {"off-screen", 0, 0, 0}, {"reuse-context", 0, 0, 0}, {"run-forever", 0, 0, 0}, {"size", 1, 0, 0}, @@ -83,6 +85,31 @@ size.second = size.first; } +/** + * Parses a frame-end method string + * + * @param str the string to parse + * + * @return the parsed frame end method + */ +static Options::FrameEnd +frame_end_from_str(const std::string &str) +{ + Options::FrameEnd m = Options::FrameEndDefault; + + if (str == "swap") + m = Options::FrameEndSwap; + else if (str == "finish") + m = Options::FrameEndFinish; + else if (str == "readpixels") + m = Options::FrameEndReadPixels; + else if (str == "none") + m = Options::FrameEndNone; + + return m; +} + + void Options::print_help() { @@ -96,8 +123,8 @@ " (the option can be used multiple times)\n" " --validate Run a quick output validation test instead of \n" " running the benchmarks\n" - " --no-swap-buffers Don't update the canvas by swapping the front and\n" - " back buffer, use glFinish() instead\n" + " --frame-end METHOD How to end a frame [default,none,swap,finish,readpixels]\n" + " --off-screen Render to an off-screen surface\n" " --reuse-context Use a single context for all scenes\n" " (by default, each scene gets its own context)\n" " -s, --size WxH Size of the output window (default: 800x600)\n" @@ -139,8 +166,10 @@ Options::benchmark_files.push_back(optarg); else if (!strcmp(optname, "validate")) Options::validate = true; - else if (!strcmp(optname, "no-swap-buffers")) - Options::swap_buffers = false; + else if (!strcmp(optname, "frame-end")) + Options::frame_end = frame_end_from_str(optarg); + else if (!strcmp(optname, "off-screen")) + Options::offscreen = true; else if (!strcmp(optname, "reuse-context")) Options::reuse_context = true; else if (c == 's' || !strcmp(optname, "size")) === modified file 'src/options.h' --- src/options.h 2012-02-16 09:03:42 +0000 +++ src/options.h 2012-03-20 12:55:49 +0000 @@ -28,13 +28,21 @@ #include struct Options { + enum FrameEnd { + FrameEndDefault, + FrameEndNone, + FrameEndSwap, + FrameEndFinish, + FrameEndReadPixels + }; + static bool parse_args(int argc, char **argv); static void print_help(); static std::vector benchmarks; static std::vector benchmark_files; static bool validate; - static bool swap_buffers; + static FrameEnd frame_end; static std::pair size; static bool list_scenes; static bool show_all_options; @@ -43,6 +51,7 @@ static bool reuse_context; static bool run_forever; static bool annotate; + static bool offscreen; }; #endif /* OPTIONS_H_ */ === modified file 'src/scene-desktop.cpp' --- src/scene-desktop.cpp 2012-02-13 09:43:54 +0000 +++ src/scene-desktop.cpp 2012-03-12 15:32:07 +0000 @@ -356,6 +356,7 @@ class RenderScreen : public RenderObject { public: + RenderScreen(Canvas &canvas) { fbo_ = canvas.fbo(); } virtual void init() {} virtual void release() {} }; @@ -736,8 +737,8 @@ RenderClearImage desktop; std::vector windows; - SceneDesktopPrivate() : - desktop(GLMARK_DATA_PATH"/textures/effect-2d.png") {} + SceneDesktopPrivate(Canvas &canvas) : + screen(canvas), desktop(GLMARK_DATA_PATH"/textures/effect-2d.png") {} ~SceneDesktopPrivate() { Util::dispose_pointer_vector(windows); } @@ -747,7 +748,7 @@ SceneDesktop::SceneDesktop(Canvas &canvas) : Scene(canvas, "desktop") { - priv_ = new SceneDesktopPrivate(); + priv_ = new SceneDesktopPrivate(canvas); options_["effect"] = Scene::Option("effect", "blur", "the effect to use [blur]"); options_["windows"] = Scene::Option("windows", "4",